*~
*.log
-*.trs
*.exe
*.gz
*.lo
.idea/
.project
.settings/
-INSTALL
-Makefile
-Makefile.in
-TAGS
-aclocal.m4
-aminclude.am
-artifacts
-autom4te.cache
-autoscan.log
-build-aux/
-clients/memaslap
-clients/memcapable
-clients/memcat
-clients/memcp
-clients/memdump
-clients/memerror
-clients/memexist
-clients/memflush
-clients/memparse
-clients/memping
-clients/memrm
-clients/memslap
-clients/memstat
-clients/memtouch
+src/bin/memaslap
+src/bin/memcapable
+src/bin/memcat
+src/bin/memcp
+src/bin/memdump
+src/bin/memerror
+src/bin/memexist
+src/bin/memflush
+src/bin/memparse
+src/bin/memping
+src/bin/memrm
+src/bin/memslap
+src/bin/memstat
+src/bin/memtouch
cmake-build-*/
-config.cache
-config.log
-config.status
-config/compile
-config/config.guess
-config/config.sub
-config/depcomp
-config/install-sh
-config/ltmain.sh
-config/missing
-config/pandora_vc_revinfo
-config/top.h
-configure
-configure.scan
-docs/*.[13]
-docs/*.html
-docs/build
-docs/changes
-docs/source/conf.py
-docs/doctest/
-docs/doctrees/
-docs/html/
-docs/linkcheck/
-docs/text
example/memcached_light
example/t/memcached_light
-libhashkit-1.0/configure.h
-libhashkit/hashkitcon.h
-libmemcached-1.0/configure.h
-libmemcached-1.0/t/c_sasl_test
-libmemcached-1.0/t/c_test
-libmemcached-1.0/t/cc_test
-libmemcached-1.2/configure.h
-libmemcached-2.0/configure.h
-libmemcached-?.??/
-libmemcached/configure.h
-libmemcached/csl/parser.cc
-libmemcached/csl/parser.h
-libmemcached/csl/scanner.cc
-libmemcached/csl/scanner.h
-libmemcached/dtrace_probes.h
-libmemcached/generated_probes.h
-libmemcached/memcached_configure.h
-libtest/.hg/
-libtest/.hgignore
-libtest/abort
-libtest/backtrace
-libtest/core-count
-libtest/skiptest
-libtest/unittest
-libtest/version.h
-libtest/wait
-libtest/yatlcon.h
-libtool
-m4/libtool.m4
-m4/libtool.m4
-m4/ltoptions.m4
-m4/ltsugar.m4
-m4/ltversion.m4
-m4/lt~obsolete.m4
-man/*.1
-man/*.3
-man/*.8
-man/.doctrees/
-mem_config.h
-mem_config.in
-out
-patch
-patch2
-stamp-h1
-support/example.cnf
-support/Makefile
-support/Makefile.in
-support/libmemcached-fc.spec
-support/libmemcached.pc
-support/libmemcached.spec
tags
-tests/atomsmasher
-tests/c_sasl_test
-tests/c_test
-tests/cycle
-tests/failure
-tests/hash_plus
-tests/hashplus
-tests/internals
-tests/libmemcached-1.0/internals
-tests/libmemcached-1.0/sasl
-tests/libmemcached-1.0/testapp
-tests/libmemcached-1.0/testsocket
-tests/memcapable
-tests/memcat
-tests/memcp
-tests/memdump
-tests/memerror
-tests/memexist
-tests/memflush
-tests/memping
-tests/memplus
-tests/memrm
-tests/memslap
-tests/memstat
-tests/memtouch
-tests/output.cmp
-tests/parser
-tests/sasl
-tests/startservers
-tests/testapp
-tests/testhashkit
-tests/testplus
-tests/testudp
-tests/var/
-tmp_chroot
-unittests/unittests
venv/
/infer-out/
-/gh-pages/
-/gh-pages-build/
+/docs/gh-pages/source/
+/docs/gh-pages/build/
include(CMakeConfig.txt)
-include_directories(${CMAKE_BINARY_DIR})
+foreach(INCLUDE IN ITEMS ${CMAKE_BINARY_DIR} .)
+ include_directories(
+ ${INCLUDE}/
+ ${INCLUDE}/include
+ ${INCLUDE}/src
+ )
+endforeach()
set(AUTOHEADER_FILE mem_config.h)
set(CLIENTS
memtouch
)
-add_subdirectory(clients)
-add_subdirectory(libhashkit)
-add_subdirectory(libhashkit-1.0)
-add_subdirectory(libmemcached)
-add_subdirectory(libmemcached-1.0)
-add_subdirectory(libmemcachedutil)
-add_subdirectory(libmemcachedutil-1.0)
+add_subdirectory(include)
+add_subdirectory(src)
+add_subdirectory(docs)
+add_subdirectory(support)
if(BUILD_TESTING)
- add_subdirectory(libtest)
add_subdirectory(tests)
endif()
-add_subdirectory(docs)
-add_subdirectory(support)
-
# keep last
-configure_file(mem_config.h.in ${CMAKE_BINARY_DIR}/${AUTOHEADER_FILE} @ONLY)
+configure_file(src/mem_config.h.in ${AUTOHEADER_FILE} @ONLY)
-Software License Agreement (BSD License)
+Copyright (c) 2011-2013 Brian Aker, DataDifferential, https://datadifferential.com/
+Copyright (c) 2020 Michael Wallner, SmugMug Inc, https://smugmug.com/
-Copyright (c) 2012, Data Differential (http://datadifferential.com/)
All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
- * Neither the name of TangentOrg nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
+3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+++ /dev/null
-Hi!
-
-If you are getting this code from http://launchpad.net/libmemcached then
-continue reading. Otherwise these directions are not for you (well maybe...).
-
-To obtain code from http://bazaar.launchpad.net/libmemcached you will need to
-issue the following command:
-
-bzr branch lp:libmemcached
-
-Once the tree is cloned you will need to build the "configure" script. You
-can do this by running the script:
-
-./bootstrap.sh autoreconf
-
-It will set up all of the files you need to build libmemcached. At that
-point it is just the typical "./configure; make; make test; make install"
-
-For a tarball release do a "make dist" and for an RPM type "make rpm".
-
-For patches, we prefer you push a branch to launchpad and then submit that
-branch to be merged. For more information, see:
-
-https://help.launchpad.net/Code/UploadingABranch
-https://help.launchpad.net/Code/Review
-
-Thanks and keep hacking!
-
-Cheers,
- -Brian
- Seattle, WA.
+++ /dev/null
-
-add_library(libclient_utilities STATIC utilities.cc generator.cc execute.cc)
-add_library(client_utilities ALIAS libclient_utilities)
-target_include_directories(libclient_utilities PRIVATE ..)
-target_link_libraries(libclient_utilities libmemcachedinternal)
-
-foreach(CLIENT IN LISTS CLIENTS)
- add_executable(${CLIENT} ${CLIENT}.cc)
- target_include_directories(${CLIENT} PRIVATE ..)
- target_link_libraries(${CLIENT} libclient_utilities)
- install(TARGETS ${CLIENT}
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
-endforeach()
-
-# extra sources
-
-target_sources(memcapable PRIVATE ../libmemcached/byteorder.cc)
-
-# extra libs
-
-target_link_libraries(memcapable Threads::Threads)
-target_link_libraries(memping libmemcachedutil)
-target_link_libraries(memslap Threads::Threads)
-
-# memaslap is special
-
-if(ENABLE_MEMASLAP)
- if(LIBEVENT AND HAVE_C_STDATOMIC)
- add_executable(memaslap memaslap.c
- ms_conn.c ms_setting.c ms_sigsegv.c ms_stats.c ms_task.c ms_thread.c)
- target_include_directories(memaslap PRIVATE .. ${LIBEVENT_INCLUDEDIR})
- target_link_libraries(memaslap libclient_utilities ${LIBEVENT_LIBRARIES} Threads::Threads)
- install(TARGETS memaslap
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
- endif()
-endif()
+++ /dev/null
-/* 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:
- *
- */
-
-#pragma once
-
-typedef struct memcached_help_text_st memcached_help_text_st;
-
-enum memcached_options {
- OPT_SERVERS= 's',
- OPT_VERSION= 'V',
- OPT_HELP= 'h',
- OPT_VERBOSE= 'v',
- OPT_DEBUG= 'd',
- OPT_ANALYZE= 'a',
- OPT_FLAG= 257,
- OPT_EXPIRE,
- OPT_SET,
- OPT_REPLACE,
- OPT_ADD,
- OPT_SLAP_EXECUTE_NUMBER,
- OPT_SLAP_INITIAL_LOAD,
- OPT_SLAP_TEST,
- OPT_SLAP_CONCURRENCY,
- OPT_SLAP_NON_BLOCK,
- OPT_SLAP_TCP_NODELAY,
- OPT_FLUSH,
- OPT_HASH,
- OPT_BINARY,
- OPT_UDP,
- OPT_BUFFER,
- OPT_USERNAME,
- OPT_PASSWD,
- OPT_STAT_ARGS,
- OPT_SERVER_VERSION,
- OPT_QUIET,
- OPT_FILE= 'f'
-};
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-/*
- Execute a memcached_set() a set of pairs.
- Return the number of rows set.
-*/
-
-#include <mem_config.h>
-#include "clients/execute.h"
-
-unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
-{
- uint32_t count= 0;
- for (; count < number_of; ++count)
- {
- memcached_return_t rc= memcached_set(memc, pairs[count].key, pairs[count].key_length,
- pairs[count].value, pairs[count].value_length,
- 0, 0);
- if (memcached_failed(rc))
- {
- fprintf(stderr, "%s:%d Failure on %u insert (%s) of %.*s\n",
- __FILE__, __LINE__, count,
- memcached_last_error_message(memc),
- (unsigned int)pairs[count].key_length, pairs[count].key);
-
- // We will try to reconnect and see if that fixes the issue
- memcached_quit(memc);
-
- return count;
- }
- }
-
- return count;
-}
-
-/*
- Execute a memcached_get() on a set of pairs.
- Return the number of rows retrieved.
-*/
-unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
-{
- unsigned int x;
- unsigned int retrieved;
-
-
- for (retrieved= 0,x= 0; x < number_of; x++)
- {
- size_t value_length;
- uint32_t flags;
-
- unsigned int fetch_key= (unsigned int)((unsigned int)random() % number_of);
-
- memcached_return_t rc;
- char *value= memcached_get(memc, pairs[fetch_key].key, pairs[fetch_key].key_length,
- &value_length, &flags, &rc);
-
- if (memcached_failed(rc))
- {
- fprintf(stderr, "%s:%d Failure on read(%s) of %.*s\n",
- __FILE__, __LINE__,
- memcached_last_error_message(memc),
- (unsigned int)pairs[fetch_key].key_length, pairs[fetch_key].key);
- }
- else
- {
- retrieved++;
- }
-
- ::free(value);
- }
-
- return retrieved;
-}
-
-/**
- * Callback function to count the number of results
- */
-static memcached_return_t callback_counter(const memcached_st *ptr,
- memcached_result_st *result,
- void *context)
-{
- (void)ptr;
- (void)result;
- unsigned int *counter= (unsigned int *)context;
- *counter= *counter + 1;
-
- return MEMCACHED_SUCCESS;
-}
-
-/**
- * Try to run a large mget to get all of the keys
- * @param memc memcached handle
- * @param keys the keys to get
- * @param key_length the length of the keys
- * @param number_of the number of keys to try to get
- * @return the number of keys received
- */
-unsigned int execute_mget(memcached_st *memc,
- const char * const *keys,
- size_t *key_length,
- unsigned int number_of)
-{
- unsigned int retrieved= 0;
- memcached_execute_fn callbacks[]= { callback_counter };
- memcached_return_t rc;
- rc= memcached_mget_execute(memc, keys, key_length,
- (size_t)number_of, callbacks, &retrieved, 1);
-
- if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_NOTFOUND ||
- rc == MEMCACHED_BUFFERED || rc == MEMCACHED_END)
- {
- rc= memcached_fetch_execute(memc, callbacks, (void *)&retrieved, 1);
- if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_END)
- {
- fprintf(stderr, "%s:%d Failed to execute mget: %s\n",
- __FILE__, __LINE__,
- memcached_strerror(memc, rc));
- memcached_quit(memc);
- return 0;
- }
- }
- else
- {
- fprintf(stderr, "%s:%d Failed to execute mget: %s\n",
- __FILE__, __LINE__,
- memcached_strerror(memc, rc));
- memcached_quit(memc);
- return 0;
- }
-
- return retrieved;
-}
+++ /dev/null
-/* 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:
- *
- */
-
-#pragma once
-
-#include <stdio.h>
-
-#include <libmemcached-1.0/memcached.h>
-#include "clients/generator.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of);
-unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of);
-unsigned int execute_mget(memcached_st *memc, const char * const *keys, size_t *key_length,
- unsigned int number_of);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 <mem_config.h>
-
-#include <stdint.h>
-
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-#include <unistd.h>
-
-#include "clients/generator.h"
-
-#define KEY_BYTES 20
-
-/* Use this for string generation */
-static const char ALPHANUMERICS[]=
- "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
-
-#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
-
-static size_t get_alpha_num(void)
-{
- return (size_t)random() % ALPHANUMERICS_SIZE;
-}
-
-void get_random_string(char *buffer, size_t size)
-{
- char *buffer_ptr= buffer;
-
- while (--size)
- {
- *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
- }
- *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
-}
-
-void pairs_free(pairs_st *pairs)
-{
- if (pairs == NULL)
- {
- return;
- }
-
- /* We free until we hit the null pair we stores during creation */
- for (uint32_t x= 0; pairs[x].key; x++)
- {
- free(pairs[x].key);
- if (pairs[x].value)
- {
- free(pairs[x].value);
- }
- }
-
- free(pairs);
-}
-
-pairs_st *pairs_generate(uint64_t number_of, size_t value_length)
-{
- pairs_st *pairs= (pairs_st*)calloc((size_t)number_of + 1, sizeof(pairs_st));
-
- if (pairs == NULL)
- {
- goto error;
- }
-
- for (uint64_t x= 0; x < number_of; x++)
- {
- pairs[x].key= (char *)calloc(KEY_BYTES, sizeof(char));
-
- if (pairs[x].key == NULL)
- goto error;
-
- get_random_string(pairs[x].key, KEY_BYTES);
- pairs[x].key_length= KEY_BYTES;
-
- if (value_length)
- {
- pairs[x].value= (char *)calloc(value_length, sizeof(char));
-
- if (pairs[x].value == NULL)
- goto error;
-
- get_random_string(pairs[x].value, value_length);
- pairs[x].value_length= value_length;
- }
- else
- {
- pairs[x].value= NULL;
- pairs[x].value_length= 0;
- }
- }
-
- return pairs;
-error:
- std::cerr << "Memory Allocation failure in pairs_generate." << std::endl;
- exit(EXIT_SUCCESS);
-}
+++ /dev/null
-/* 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
-*/
-
-#pragma once
-
-typedef struct pairs_st pairs_st;
-
-struct pairs_st {
- char *key;
- size_t key_length;
- char *value;
- size_t value_length;
-};
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-pairs_st *pairs_generate(uint64_t number_of, size_t value_length);
-void pairs_free(pairs_st *pairs);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
+++ /dev/null
-/*
- * 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 "mem_config.h"
-
-#include <stdlib.h>
-#include <getopt.h>
-#include <limits.h>
-
-#if defined(HAVE_SYS_TIME_H)
-# include <sys/time.h>
-#endif
-
-#if defined(HAVE_TIME_H)
-# include <time.h>
-#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
-
-/* 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 */
-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 in_time);
-static void ms_print_memslap_stats(struct timeval *start_time,
- struct timeval *end_time);
-static void ms_monitor_slap_mode(void);
-
-/**
- * output the help information
- *
- * @param command_name, the string of this process
- * @param description, description of this process
- * @param long_options, global options array
- */
-static __attribute__((noreturn)) 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++)
- {
- 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)
- {
- printf(" %s\n", help_message);
- }
- }
-
- 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");
-
- exit(0);
-} /* ms_help_command */
-
-
-/* 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);
-
- ms_global.warmup_lock.count = 0;
- pthread_mutex_init(&ms_global.warmup_lock.lock, NULL);
- pthread_cond_init(&ms_global.warmup_lock.cond, NULL);
-
- 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()
-{
- pthread_mutex_destroy(&ms_global.init_lock.lock);
- pthread_cond_destroy(&ms_global.init_lock.cond);
-
- pthread_mutex_destroy(&ms_global.warmup_lock.lock);
- pthread_cond_destroy(&ms_global.warmup_lock.cond);
-
- pthread_mutex_destroy(&ms_global.run_lock.lock);
- pthread_cond_destroy(&ms_global.run_lock.cond);
-
- pthread_mutex_destroy(&ms_global.quit_mutex);
- pthread_mutex_destroy(&ms_global.seq_mutex);
-
- if (ms_setting.stat_freq > 0)
- {
- pthread_mutex_destroy(&ms_statistic.stat_mutex);
- }
-} /* ms_sync_lock_destroy */
-
-
-/* initialize the global structure */
-static void ms_global_struct_init()
-{
- ms_sync_lock_init();
- ms_global.finish_warmup= false;
- ms_global.time_out= false;
-}
-
-
-/* destroy the global structure */
-static void ms_global_struct_destroy()
-{
- ms_sync_lock_destroy();
-}
-
-
-/**
- * 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);
-}
-
-
-/**
- * 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)
-{
- 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";
-
- case OPT_VERSION:
- return "Display the version of the application and then exit.";
-
- case OPT_HELP:
- return "Display this message and then exit.";
-
- case OPT_EXECUTE_NUMBER:
- return "Number of operations(get and set) to execute for the\n"
- " given test. Default 1000000.";
-
- 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.";
-
- case OPT_RECONNECT:
- return
- "Reconnect support, when connection is closed it will be reconnected.";
-
- case OPT_VERBOSE:
- return
- "Whether it outputs detailed information when verification fails.";
-
- case OPT_FACEBOOK_TEST:
- return
- "Whether it enables facebook test feature, set with TCP and multi-get with UDP.";
-
- 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 */
-
-
-/* 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)
- {
- case 'd':
- case 'D':
- ret*= 24;
- /* fall through */
- case 'h':
- case 'H':
- ret*= 60;
- /* fall through */
- case 'm':
- case 'M':
- ret*= 60;
- /* fall through */
- case 's':
- case 'S':
- break;
-
- default:
- ret= -1;
- break;
- } /* switch */
-
- return ret;
-} /* ms_parse_time */
-
-
-/* used to parse the size string */
-static int64_t ms_parse_size()
-{
- int64_t ret= -1;
- char unit= optarg[strlen(optarg) - 1];
-
- optarg[strlen(optarg) - 1]= '\0';
- errno= 0;
- ret= strtoll(optarg, (char **)NULL, 10);
- if (errno != 0)
- {
- fprintf(stderr, "strtoll(optarg,..): %s\n", strerror(errno));
- exit(1);
- }
-
- switch (unit)
- {
- case 'k':
- case 'K':
- ret*= 1024;
- break;
-
- 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 ((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)
- {
- switch (option_rv)
- {
- case 0:
- break;
-
- 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 */
- errno= 0;
- ms_setting.nconns= (uint32_t)strtoul(optarg, (char **) NULL, 10);
- if (ms_setting.nconns <= 0 || errno != 0)
- {
- fprintf(stderr, "Concurrency must be greater than 0.:-)\n");
- exit(1);
- }
- break;
-
- case OPT_EXECUTE_NUMBER: /* --execute_number or -x */
- errno= 0;
- ms_setting.exec_num= (int)strtol(optarg, (char **) NULL, 10);
- if (ms_setting.exec_num <= 0 || errno != 0)
- {
- fprintf(stderr, "Execute number must be greater than 0.:-)\n");
- exit(1);
- }
- break;
-
- case OPT_THREAD_NUMBER: /* --threads or -T */
- errno= 0;
- ms_setting.nthreads= (uint32_t)strtoul(optarg, (char **) NULL, 10);
- if (ms_setting.nthreads <= 0 || errno != 0)
- {
- fprintf(stderr, "Threads number must be greater than 0.:-)\n");
- exit(1);
- }
- break;
-
- case OPT_FIXED_LTH: /* --fixed_size or -X */
- errno= 0;
- ms_setting.fixed_value_size= (size_t)strtoull(optarg, (char **) NULL, 10);
- if ((ms_setting.fixed_value_size <= 0 || errno != 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_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_GETS_DIVISION: /* --division or -d */
- errno= 0;
- ms_setting.mult_key_num= (int)strtol(optarg, (char **) NULL, 10);
- if (ms_setting.mult_key_num <= 0 || errno != 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_CONFIG_CMD: /* --cfg_cmd or -F */
- ms_setting.cfg_file= strdup(optarg);
- break;
-
- 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)
- {
- 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);
- }
-
- if (ms_setting.stat_freq == 0)
- {
- fprintf(stderr, "The frequency of dumping statistic information "
- "can not be 0. :-)\n");
- exit(1);
- }
- break;
-
- case OPT_SOCK_PER_CONN: /* --conn_sock or -n */
- errno= 0;
- ms_setting.sock_per_conn= (uint32_t)strtoul(optarg, (char **) NULL, 10);
- if (ms_setting.sock_per_conn <= 0 || errno != 0)
- {
- fprintf(stderr, "Number of socks of each concurrency "
- "must be greater than 0.:-)\n");
- exit(1);
- }
- break;
-
- case OPT_RECONNECT: /* --reconnect or -R */
- ms_setting.reconnect= true;
- break;
-
- case OPT_VERBOSE: /* --verbose or -b */
- ms_setting.verbose= true;
- break;
-
- 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 */
- errno= 0;
- ms_setting.rep_write_srv= (uint32_t)strtoul(optarg, (char **) NULL, 10);
- if (ms_setting.rep_write_srv <= 0 || errno != 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 (ms_setting.nconns % (uint32_t)ms_setting.nthreads != 0)
- {
- fprintf(stderr, "Concurrency must be the multiples of threads count.\n");
- return -1;
- }
-
- if (ms_setting.win_size % UNIT_ITEMS_COUNT != 0)
- {
- fprintf(stderr, "Window size must be the multiples of 1024.\n\n");
- return -1;
- }
-
- return EXIT_SUCCESS;
-} /* ms_check_para */
-
-
-/* initialize the statistic structure */
-static void ms_statistic_init()
-{
- 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 */
-
-
-/* initialize the global state structure */
-static void ms_stats_init()
-{
- memset(&ms_stats, 0, sizeof(ms_stats_t));
- if (ms_setting.stat_freq > 0)
- {
- ms_statistic_init();
- }
-} /* ms_stats_init */
-
-
-/* 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+= snprintf(pos,
- sizeof(buf), "cmd_get: %lu\n",
- (unsigned long) ms_stats.cmd_get);
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "cmd_set: %lu\n",
- (unsigned long) ms_stats.cmd_set);
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "get_misses: %lu\n",
- (unsigned long) ms_stats.get_misses);
-
- if (ms_setting.verify_percent > 0)
- {
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "verify_misses: %lu\n",
- (unsigned long) ms_stats.vef_miss);
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "verify_failed: %lu\n",
- (unsigned long) ms_stats.vef_failed);
- }
-
- if (ms_setting.exp_ver_per > 0)
- {
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "expired_get: %lu\n",
- (unsigned long) ms_stats.exp_get);
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "unexpired_unget: %lu\n",
- (unsigned long) ms_stats.unexp_unget);
- }
-
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "written_bytes: %lu\n",
- (unsigned long) ms_stats.bytes_written);
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "read_bytes: %lu\n",
- (unsigned long) ms_stats.bytes_read);
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "object_bytes: %lu\n",
- (unsigned long) ms_stats.obj_bytes);
-
- if (ms_setting.udp || ms_setting.facebook_test)
- {
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "packet_disorder: %lu\n",
- (unsigned long) ms_stats.pkt_disorder);
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "packet_drop: %lu\n",
- (unsigned long)ms_stats.pkt_drop);
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "udp_timeout: %lu\n",
- (unsigned long)ms_stats.udp_timeout);
- }
-
- 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);
- }
-
- int64_t time_diff= ms_time_diff(start_time, end_time);
- pos+= snprintf(pos,
- sizeof(buf) - (size_t)(pos -buf),
- "\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));
- assert(pos <= buf);
-
- 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()
-{
- struct timeval start_time, end_time;
-
- /* Wait all the threads complete initialization. */
- pthread_mutex_lock(&ms_global.init_lock.lock);
- while (ms_global.init_lock.count < ms_setting.nthreads)
- {
- pthread_cond_wait(&ms_global.init_lock.cond,
- &ms_global.init_lock.lock);
- }
- pthread_mutex_unlock(&ms_global.init_lock.lock);
-
- /* 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.warmup_lock.lock);
- while (ms_global.warmup_lock.count < ms_setting.nconns)
- {
- pthread_cond_wait(&ms_global.warmup_lock.cond, &ms_global.warmup_lock.lock);
- }
- pthread_mutex_unlock(&ms_global.warmup_lock.lock);
- }
- ms_global.finish_warmup= true;
-
- /* running in "run time" mode, user specify run time */
- if (ms_setting.run_time > 0)
- {
- int second= 0;
- gettimeofday(&start_time, NULL);
- while (1)
- {
- sleep(1);
- second++;
-
- 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 < 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[])
-{
- srandom((unsigned int)time(NULL));
- ms_global_struct_init();
-
- /* 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();
-
- /* waiting work thread complete its task */
- ms_monitor_slap_mode();
-
- /* clean up */
- ms_thread_cleanup();
- ms_global_struct_destroy();
- ms_setting_cleanup();
-
- return EXIT_SUCCESS;
-} /* main */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 <mem_config.h>
-
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#else
-#include "poll/poll.h"
-#endif
-
-#include <cassert>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <ctype.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <libmemcached-1.0/memcached.h>
-
-#include "libmemcached/socket.hpp"
-#include "libmemcachedprotocol-0.0/binary.h"
-#include "libmemcached/byteorder.h"
-#include "clients/utilities.h"
-
-#include <vector>
-
-#ifdef linux
-/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
- * optimize the conversion functions, but the prototypes generate warnings
- * from gcc. The conversion methods isn't the bottleneck for my app, so
- * just remove the warnings by undef'ing the optimization ..
- */
-#undef ntohs
-#undef ntohl
-#endif
-
-/* Should we generate coredumps when we enounter an error (-c) */
-static bool do_core= false;
-/* connection to the server */
-static memcached_socket_t sock;
-/* Should the output from test failures be verbose or quiet? */
-static bool verbose= false;
-
-/* The number of seconds to wait for an IO-operation */
-static int timeout= 2;
-
-/*
- * Instead of having to cast between the different datatypes we create
- * a union of all of the different types of pacages we want to send.
- * A lot of the different commands use the same packet layout, so I'll
- * just define the different types I need. The typedefs only contain
- * the header of the message, so we need some space for keys and body
- * To avoid to have to do multiple writes, lets add a chunk of memory
- * to use. 1k should be more than enough for header, key and body.
- */
-typedef union
-{
- protocol_binary_request_no_extras plain;
- protocol_binary_request_flush flush;
- protocol_binary_request_incr incr;
- protocol_binary_request_set set;
- char bytes[1024];
-} command;
-
-typedef union
-{
- protocol_binary_response_no_extras plain;
- protocol_binary_response_incr incr;
- protocol_binary_response_decr decr;
- char bytes[1024];
-} response;
-
-enum test_return
-{
- TEST_SKIP, TEST_PASS, TEST_PASS_RECONNECT, TEST_FAIL
-};
-
-/**
- * Try to get an addrinfo struct for a given port on a given host
- */
-static struct addrinfo *lookuphost(const char *hostname, const char *port)
-{
- struct addrinfo *ai= 0;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family=AF_UNSPEC;
- hints.ai_protocol=IPPROTO_TCP;
- hints.ai_socktype=SOCK_STREAM;
-
- int error= getaddrinfo(hostname, port, &hints, &ai);
- if (error != 0)
- {
- if (error != EAI_SYSTEM)
- {
- fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
- }
- else
- {
- perror("getaddrinfo()");
- }
- }
-
- return ai;
-}
-
-/**
- * Set the socket in nonblocking mode
- * @return -1 if failure, the socket otherwise
- */
-static memcached_socket_t set_noblock(void)
-{
-#if defined(_WIN32)
- u_long arg = 1;
- if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
- {
- perror("Failed to set nonblocking io");
- closesocket(sock);
- return INVALID_SOCKET;
- }
-#else
- int flags= fcntl(sock, F_GETFL, 0);
- if (flags == -1)
- {
- perror("Failed to get socket flags");
- memcached_close_socket(sock);
- return INVALID_SOCKET;
- }
-
- if ((flags & O_NONBLOCK) != O_NONBLOCK)
- {
- if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
- {
- perror("Failed to set socket to nonblocking mode");
- memcached_close_socket(sock);
- return INVALID_SOCKET;
- }
- }
-#endif
- return sock;
-}
-
-/**
- * Try to open a connection to the server
- * @param hostname the name of the server to connect to
- * @param port the port number (or service) to connect to
- * @return positive integer if success, -1 otherwise
- */
-static memcached_socket_t connect_server(const char *hostname, const char *port)
-{
- struct addrinfo *ai= lookuphost(hostname, port);
- sock= INVALID_SOCKET;
- if (ai != NULL)
- {
- if ((sock= socket(ai->ai_family, ai->ai_socktype,
- ai->ai_protocol)) != INVALID_SOCKET)
- {
- if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR)
- {
- fprintf(stderr, "Failed to connect socket: %s\n",
- strerror(get_socket_errno()));
- closesocket(sock);
- sock= INVALID_SOCKET;
- }
- else
- {
- sock= set_noblock();
- }
- }
- else
- {
- fprintf(stderr, "Failed to create socket: %s\n", strerror(get_socket_errno()));
- }
-
- freeaddrinfo(ai);
- }
-
- return sock;
-}
-
-static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len)
-{
- ssize_t ret;
-
- if (direction == POLLOUT)
- {
- ret= send(fd, buf, len, 0);
- }
- else
- {
- ret= recv(fd, buf, len, 0);
- }
-
- if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK)
- {
- struct pollfd fds;
- memset(&fds, 0, sizeof(struct pollfd));
- fds.events= direction;
- fds.fd= fd;
-
- int err= poll(&fds, 1, timeout * 1000);
- if (err == 1)
- {
- if (direction == POLLOUT)
- {
- ret= send(fd, buf, len, 0);
- }
- else
- {
- ret= recv(fd, buf, len, 0);
- }
- }
- else if (err == 0)
- {
- errno= ETIMEDOUT;
- }
- else
- {
- perror("Failed to poll");
- return -1;
- }
- }
-
- return ret;
-}
-
-/**
- * Ensure that an expression is true. If it isn't print out a message similar
- * to assert() and create a coredump if the user wants that. If not an error
- * message is returned.
- *
- */
-static enum test_return ensure(bool val, const char *expression, const char *file, int line)
-{
- if (!val)
- {
- if (verbose)
- {
- fprintf(stdout, "\n%s:%d: %s", file, line, expression);
- }
-
- if (do_core)
- {
- abort();
- }
-
- return TEST_FAIL;
- }
-
- return TEST_PASS;
-}
-
-#define verify(expression) do { if (ensure(expression, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
-#define execute(expression) do { if (ensure(expression == TEST_PASS, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
-
-/**
- * Send a chunk of memory over the socket (retry if the call is iterrupted
- */
-static enum test_return retry_write(const void* buf, size_t len)
-{
- size_t offset= 0;
- const char* ptr= static_cast<const char *>(buf);
-
- do
- {
- size_t num_bytes= len - offset;
- ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes);
- if (nw == -1)
- {
- verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
- }
- else
- {
- offset+= (size_t)nw;
- }
-
- } while (offset < len);
-
- return TEST_PASS;
-}
-
-/**
- * Resend a packet to the server (All fields in the command header should
- * be in network byte order)
- */
-static enum test_return resend_packet(command *cmd)
-{
- size_t length= sizeof (protocol_binary_request_no_extras) +
- ntohl(cmd->plain.message.header.request.bodylen);
-
- execute(retry_write(cmd, length));
- return TEST_PASS;
-}
-
-/**
- * Send a command to the server. The command header needs to be updated
- * to network byte order
- */
-static enum test_return send_packet(command *cmd)
-{
- /* Fix the byteorder of the header */
- cmd->plain.message.header.request.keylen=
- ntohs(cmd->plain.message.header.request.keylen);
- cmd->plain.message.header.request.bodylen=
- ntohl(cmd->plain.message.header.request.bodylen);
- cmd->plain.message.header.request.cas=
- memcached_ntohll(cmd->plain.message.header.request.cas);
-
- execute(resend_packet(cmd));
- return TEST_PASS;
-}
-
-/**
- * Read a fixed length chunk of data from the server
- */
-static enum test_return retry_read(void *buf, size_t len)
-{
- size_t offset= 0;
- do
- {
- ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset);
- switch (nr) {
- case -1 :
- fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno));
- verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
- break;
-
- case 0:
- return TEST_FAIL;
-
- default:
- offset+= (size_t)nr;
- }
- } while (offset < len);
-
- return TEST_PASS;
-}
-
-/**
- * Receive a response from the server and conver the fields in the header
- * to local byte order
- */
-static enum test_return recv_packet(response *rsp)
-{
- execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras)));
-
- /* Fix the byte order in the packet header */
- rsp->plain.message.header.response.keylen=
- ntohs(rsp->plain.message.header.response.keylen);
- rsp->plain.message.header.response.status=
- ntohs(rsp->plain.message.header.response.status);
- rsp->plain.message.header.response.bodylen=
- ntohl(rsp->plain.message.header.response.bodylen);
- rsp->plain.message.header.response.cas=
- memcached_ntohll(rsp->plain.message.header.response.cas);
-
- size_t bodysz= rsp->plain.message.header.response.bodylen;
- if (bodysz > 0)
- execute(retry_read(rsp->bytes + sizeof (protocol_binary_response_no_extras), bodysz));
-
- return TEST_PASS;
-}
-
-/**
- * Create a storage command (add, set, replace etc)
- *
- * @param cmd destination buffer
- * @param cc the storage command to create
- * @param key the key to store
- * @param keylen the length of the key
- * @param dta the data to store with the key
- * @param dtalen the length of the data to store with the key
- * @param flags the flags to store along with the key
- * @param exptime the expiry time for the key
- */
-static void storage_command(command *cmd,
- uint8_t cc,
- const void* key,
- size_t keylen,
- const void* dta,
- size_t dtalen,
- uint32_t flags,
- uint32_t exptime)
-{
- /* all of the storage commands use the same command layout */
- protocol_binary_request_set *request= &cmd->set;
-
- memset(request, 0, sizeof (*request));
- request->message.header.request.magic= PROTOCOL_BINARY_REQ;
- request->message.header.request.opcode= cc;
- request->message.header.request.keylen= (uint16_t)keylen;
- request->message.header.request.extlen= 8;
- request->message.header.request.bodylen= (uint32_t)(keylen + 8 + dtalen);
- request->message.header.request.opaque= 0xdeadbeef;
- request->message.body.flags= flags;
- request->message.body.expiration= exptime;
-
- off_t key_offset= sizeof (protocol_binary_request_no_extras) + 8;
- memcpy(cmd->bytes + key_offset, key, keylen);
- if (dta != NULL)
- memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
-}
-
-/**
- * Create a basic command to send to the server
- * @param cmd destination buffer
- * @param cc the command to create
- * @param key the key to store
- * @param keylen the length of the key
- * @param dta the data to store with the key
- * @param dtalen the length of the data to store with the key
- */
-static void raw_command(command *cmd,
- uint8_t cc,
- const void* key,
- size_t keylen,
- const void* dta,
- size_t dtalen)
-{
- /* all of the storage commands use the same command layout */
- memset(cmd, 0, sizeof (*cmd));
- cmd->plain.message.header.request.magic= PROTOCOL_BINARY_REQ;
- cmd->plain.message.header.request.opcode= cc;
- cmd->plain.message.header.request.keylen= (uint16_t)keylen;
- cmd->plain.message.header.request.bodylen= (uint32_t)(keylen + dtalen);
- cmd->plain.message.header.request.opaque= 0xdeadbeef;
-
- off_t key_offset= sizeof (protocol_binary_request_no_extras);
-
- if (key != NULL)
- memcpy(cmd->bytes + key_offset, key, keylen);
-
- if (dta != NULL)
- memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
-}
-
-/**
- * Create the flush command
- * @param cmd destination buffer
- * @param cc the command to create (FLUSH/FLUSHQ)
- * @param exptime when to flush
- * @param use_extra to force using of the extra field?
- */
-static void flush_command(command *cmd,
- uint8_t cc, uint32_t exptime, bool use_extra)
-{
- memset(cmd, 0, sizeof (cmd->flush));
- cmd->flush.message.header.request.magic= PROTOCOL_BINARY_REQ;
- cmd->flush.message.header.request.opcode= cc;
- cmd->flush.message.header.request.opaque= 0xdeadbeef;
-
- if (exptime != 0 || use_extra)
- {
- cmd->flush.message.header.request.extlen= 4;
- cmd->flush.message.body.expiration= htonl(exptime);
- cmd->flush.message.header.request.bodylen= 4;
- }
-}
-
-/**
- * Create a incr/decr command
- * @param cc the cmd to create (FLUSH/FLUSHQ)
- * @param key the key to operate on
- * @param keylen the number of bytes in the key
- * @param delta the number to add/subtract
- * @param initial the initial value if the key doesn't exist
- * @param exptime when the key should expire if it isn't set
- */
-static void arithmetic_command(command *cmd,
- uint8_t cc,
- const void* key,
- size_t keylen,
- uint64_t delta,
- uint64_t initial,
- uint32_t exptime)
-{
- memset(cmd, 0, sizeof (cmd->incr));
- cmd->incr.message.header.request.magic= PROTOCOL_BINARY_REQ;
- cmd->incr.message.header.request.opcode= cc;
- cmd->incr.message.header.request.keylen= (uint16_t)keylen;
- cmd->incr.message.header.request.extlen= 20;
- cmd->incr.message.header.request.bodylen= (uint32_t)(keylen + 20);
- cmd->incr.message.header.request.opaque= 0xdeadbeef;
- cmd->incr.message.body.delta= memcached_htonll(delta);
- cmd->incr.message.body.initial= memcached_htonll(initial);
- cmd->incr.message.body.expiration= htonl(exptime);
-
- off_t key_offset= sizeof (protocol_binary_request_no_extras) + 20;
- memcpy(cmd->bytes + key_offset, key, keylen);
-}
-
-/**
- * Validate the response header from the server
- * @param rsp the response to check
- * @param cc the expected command
- * @param status the expected status
- */
-static enum test_return do_validate_response_header(response *rsp,
- uint8_t cc, uint16_t status)
-{
- verify(rsp->plain.message.header.response.magic == PROTOCOL_BINARY_RES);
- verify(rsp->plain.message.header.response.opcode == cc);
- verify(rsp->plain.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
- verify(rsp->plain.message.header.response.status == status);
- verify(rsp->plain.message.header.response.opaque == 0xdeadbeef);
-
- if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS)
- {
- switch (cc) {
- case PROTOCOL_BINARY_CMD_ADDQ:
- case PROTOCOL_BINARY_CMD_APPENDQ:
- case PROTOCOL_BINARY_CMD_DECREMENTQ:
- case PROTOCOL_BINARY_CMD_DELETEQ:
- case PROTOCOL_BINARY_CMD_FLUSHQ:
- case PROTOCOL_BINARY_CMD_INCREMENTQ:
- case PROTOCOL_BINARY_CMD_PREPENDQ:
- case PROTOCOL_BINARY_CMD_QUITQ:
- case PROTOCOL_BINARY_CMD_REPLACEQ:
- case PROTOCOL_BINARY_CMD_SETQ:
- verify("Quiet command shouldn't return on success" == NULL);
- /* fall through */
- default:
- break;
- }
-
- switch (cc) {
- case PROTOCOL_BINARY_CMD_ADD:
- case PROTOCOL_BINARY_CMD_REPLACE:
- case PROTOCOL_BINARY_CMD_SET:
- case PROTOCOL_BINARY_CMD_APPEND:
- case PROTOCOL_BINARY_CMD_PREPEND:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- verify(rsp->plain.message.header.response.bodylen == 0);
- verify(rsp->plain.message.header.response.cas != 0);
- break;
- case PROTOCOL_BINARY_CMD_FLUSH:
- case PROTOCOL_BINARY_CMD_NOOP:
- case PROTOCOL_BINARY_CMD_QUIT:
- case PROTOCOL_BINARY_CMD_DELETE:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- verify(rsp->plain.message.header.response.bodylen == 0);
- verify(rsp->plain.message.header.response.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_DECREMENT:
- case PROTOCOL_BINARY_CMD_INCREMENT:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- verify(rsp->plain.message.header.response.bodylen == 8);
- verify(rsp->plain.message.header.response.cas != 0);
- break;
-
- case PROTOCOL_BINARY_CMD_STAT:
- verify(rsp->plain.message.header.response.extlen == 0);
- /* key and value exists in all packets except in the terminating */
- verify(rsp->plain.message.header.response.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_VERSION:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- verify(rsp->plain.message.header.response.bodylen != 0);
- verify(rsp->plain.message.header.response.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_GET:
- case PROTOCOL_BINARY_CMD_GETQ:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 4);
- verify(rsp->plain.message.header.response.cas != 0);
- break;
-
- case PROTOCOL_BINARY_CMD_GETK:
- case PROTOCOL_BINARY_CMD_GETKQ:
- verify(rsp->plain.message.header.response.keylen != 0);
- verify(rsp->plain.message.header.response.extlen == 4);
- verify(rsp->plain.message.header.response.cas != 0);
- break;
-
- default:
- /* Undefined command code */
- break;
- }
- }
- else
- {
- verify(rsp->plain.message.header.response.cas == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- if (cc != PROTOCOL_BINARY_CMD_GETK)
- {
- verify(rsp->plain.message.header.response.keylen == 0);
- }
- }
-
- return TEST_PASS;
-}
-
-/* We call verify(validate_response_header), but that macro
- * expects a boolean expression, and the function returns
- * an enum.... Let's just create a macro to avoid cluttering
- * the code with all of the == TEST_PASS ;-)
- */
-#define validate_response_header(a,b,c) \
- do_validate_response_header(a,b,c) == TEST_PASS
-
-
-static enum test_return send_binary_noop(void)
-{
- command cmd;
- raw_command(&cmd, PROTOCOL_BINARY_CMD_NOOP, NULL, 0, NULL, 0);
- execute(send_packet(&cmd));
- return TEST_PASS;
-}
-
-static enum test_return receive_binary_noop(void)
-{
- response rsp;
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_NOOP,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- return TEST_PASS;
-}
-
-static enum test_return test_binary_noop(void)
-{
- execute(send_binary_noop());
- execute(receive_binary_noop());
- return TEST_PASS;
-}
-
-static enum test_return test_binary_quit_impl(uint8_t cc)
-{
- command cmd;
- response rsp;
- raw_command(&cmd, cc, NULL, 0, NULL, 0);
-
- execute(send_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_QUIT)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_QUIT,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
-
- /* Socket should be closed now, read should return EXIT_SUCCESS */
- verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0);
-
- return TEST_PASS_RECONNECT;
-}
-
-static enum test_return test_binary_quit(void)
-{
- return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
-}
-
-static enum test_return test_binary_quitq(void)
-{
- return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
-}
-
-static enum test_return test_binary_set_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
-
- uint64_t value= 0xdeadbeefdeadcafeULL;
- storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
-
- /* set should always work */
- for (int ii= 0; ii < 10; ii++)
- {
- if (ii == 0)
- {
- execute(send_packet(&cmd));
- }
- else
- {
- execute(resend_packet(&cmd));
- }
-
- if (cc == PROTOCOL_BINARY_CMD_SET)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- execute(test_binary_noop());
- }
-
- /*
- * We need to get the current CAS id, and at this time we haven't
- * verified that we have a working get
- */
- if (cc == PROTOCOL_BINARY_CMD_SETQ)
- {
- cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET;
- execute(resend_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
- }
-
- /* try to set with the correct CAS value */
- cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas);
- execute(resend_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_SET)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- execute(test_binary_noop());
-
- /* try to set with an incorrect CAS value */
- cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas - 1);
- execute(resend_packet(&cmd));
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
- execute(receive_binary_noop());
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_set(void)
-{
- return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
-}
-
-static enum test_return test_binary_setq(void)
-{
- return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
-}
-
-static enum test_return test_binary_add_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
- uint64_t value= 0xdeadbeefdeadcafeULL;
- storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
-
- /* first add should work, rest of them should fail (even with cas
- as wildcard */
- for (int ii=0; ii < 10; ii++)
- {
- if (ii == 0)
- execute(send_packet(&cmd));
- else
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_ADD || ii > 0)
- {
- uint16_t expected_result;
- if (ii == 0)
- expected_result= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- else
- expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
-
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- execute(receive_binary_noop());
- verify(validate_response_header(&rsp, cc, expected_result));
- }
- else
- execute(test_binary_noop());
- }
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_add(void)
-{
- return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
-}
-
-static enum test_return test_binary_addq(void)
-{
- return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
-}
-
-static enum test_return binary_set_item(const char *key, const char *value)
-{
- command cmd;
- response rsp;
- storage_command(&cmd, PROTOCOL_BINARY_CMD_SET, key, strlen(key),
- value, strlen(value), 0, 0);
- execute(send_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- return TEST_PASS;
-}
-
-static enum test_return test_binary_replace_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
- uint64_t value= 0xdeadbeefdeadcafeULL;
- storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
-
- /* first replace should fail, successive should succeed (when the
- item is added! */
- for (int ii= 0; ii < 10; ii++)
- {
- if (ii == 0)
- {
- execute(send_packet(&cmd));
- }
- else
- {
- execute(resend_packet(&cmd));
- }
-
- if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0)
- {
- uint16_t expected_result;
- if (ii == 0)
- {
- expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
- }
- else
- {
- expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS;
- }
-
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- execute(receive_binary_noop());
- verify(validate_response_header(&rsp, cc, expected_result));
-
- if (ii == 0)
- execute(binary_set_item(key, key));
- }
- else
- {
- execute(test_binary_noop());
- }
- }
-
- /* verify that replace with CAS value works! */
- cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas);
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_REPLACE)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- execute(test_binary_noop());
-
- /* try to set with an incorrect CAS value */
- cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas - 1);
- execute(resend_packet(&cmd));
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- execute(receive_binary_noop());
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_replace(void)
-{
- return test_binary_replace_impl("test_binary_replace", PROTOCOL_BINARY_CMD_REPLACE);
-}
-
-static enum test_return test_binary_replaceq(void)
-{
- return test_binary_replace_impl("test_binary_replaceq", PROTOCOL_BINARY_CMD_REPLACEQ);
-}
-
-static enum test_return test_binary_delete_impl(const char *key, uint8_t cc)
-{
- command cmd;
- response rsp;
- raw_command(&cmd, cc, key, strlen(key), NULL, 0);
-
- /* The delete shouldn't work the first time, because the item isn't there */
- execute(send_packet(&cmd));
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
- execute(receive_binary_noop());
- execute(binary_set_item(key, key));
-
- /* The item should be present now, resend*/
- execute(resend_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_DELETE)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
-
- execute(test_binary_noop());
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_delete(void)
-{
- return test_binary_delete_impl("test_binary_delete", PROTOCOL_BINARY_CMD_DELETE);
-}
-
-static enum test_return test_binary_deleteq(void)
-{
- return test_binary_delete_impl("test_binary_deleteq", PROTOCOL_BINARY_CMD_DELETEQ);
-}
-
-static enum test_return test_binary_get_impl(const char *key, uint8_t cc)
-{
- command cmd;
- response rsp;
-
- raw_command(&cmd, cc, key, strlen(key), NULL, 0);
- execute(send_packet(&cmd));
- execute(send_binary_noop());
-
- if (cc == PROTOCOL_BINARY_CMD_GET || cc == PROTOCOL_BINARY_CMD_GETK)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
- }
-
- execute(receive_binary_noop());
-
- execute(binary_set_item(key, key));
- execute(resend_packet(&cmd));
- execute(send_binary_noop());
-
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- execute(receive_binary_noop());
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_get(void)
-{
- return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
-}
-
-static enum test_return test_binary_getk(void)
-{
- return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
-}
-
-static enum test_return test_binary_getq(void)
-{
- return test_binary_get_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
-}
-
-static enum test_return test_binary_getkq(void)
-{
- return test_binary_get_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
-}
-
-static enum test_return test_binary_incr_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
- arithmetic_command(&cmd, cc, key, strlen(key), 1, 0, 0);
-
- uint64_t ii;
- for (ii= 0; ii < 10; ++ii)
- {
- if (ii == 0)
- execute(send_packet(&cmd));
- else
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_INCREMENT)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- verify(memcached_ntohll(rsp.incr.message.body.value) == ii);
- }
- else
- execute(test_binary_noop());
- }
-
- /* @todo add incorrect CAS */
- return TEST_PASS;
-}
-
-static enum test_return test_binary_incr(void)
-{
- return test_binary_incr_impl("test_binary_incr", PROTOCOL_BINARY_CMD_INCREMENT);
-}
-
-static enum test_return test_binary_incrq(void)
-{
- return test_binary_incr_impl("test_binary_incrq", PROTOCOL_BINARY_CMD_INCREMENTQ);
-}
-
-static enum test_return test_binary_decr_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
- arithmetic_command(&cmd, cc, key, strlen(key), 1, 9, 0);
-
- int ii;
- for (ii= 9; ii > -1; --ii)
- {
- if (ii == 9)
- execute(send_packet(&cmd));
- else
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- verify(memcached_ntohll(rsp.decr.message.body.value) == (uint64_t)ii);
- }
- else
- execute(test_binary_noop());
- }
-
- /* decr 0 should not wrap */
- execute(resend_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- verify(memcached_ntohll(rsp.decr.message.body.value) == 0);
- }
- else
- {
- /* @todo get the value and verify! */
-
- }
-
- /* @todo add incorrect cas */
- execute(test_binary_noop());
- return TEST_PASS;
-}
-
-static enum test_return test_binary_decr(void)
-{
- return test_binary_decr_impl("test_binary_decr",
- PROTOCOL_BINARY_CMD_DECREMENT);
-}
-
-static enum test_return test_binary_decrq(void)
-{
- return test_binary_decr_impl("test_binary_decrq",
- PROTOCOL_BINARY_CMD_DECREMENTQ);
-}
-
-static enum test_return test_binary_version(void)
-{
- command cmd;
- response rsp;
- raw_command(&cmd, PROTOCOL_BINARY_CMD_VERSION, NULL, 0, NULL, 0);
-
- execute(send_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_VERSION,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_flush_impl(const char *key, uint8_t cc)
-{
- command cmd;
- response rsp;
-
- for (int ii= 0; ii < 2; ++ii)
- {
- execute(binary_set_item(key, key));
- flush_command(&cmd, cc, 0, ii == 0);
- execute(send_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_FLUSH)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- execute(test_binary_noop());
-
- raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
- execute(send_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
- PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
- }
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_flush(void)
-{
- return test_binary_flush_impl("test_binary_flush", PROTOCOL_BINARY_CMD_FLUSH);
-}
-
-static enum test_return test_binary_flushq(void)
-{
- return test_binary_flush_impl("test_binary_flushq", PROTOCOL_BINARY_CMD_FLUSHQ);
-}
-
-static enum test_return test_binary_concat_impl(const char *key, uint8_t cc)
-{
- command cmd;
- response rsp;
- const char *value;
-
- if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
- {
- value="hello";
- }
- else
- {
- value=" world";
- }
-
- execute(binary_set_item(key, value));
-
- if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
- {
- value=" world";
- }
- else
- {
- value="hello";
- }
-
- raw_command(&cmd, cc, key, strlen(key), value, strlen(value));
- execute(send_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_PREPEND)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- {
- execute(test_binary_noop());
- }
-
- raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
- execute(send_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- verify(rsp.plain.message.header.response.bodylen - 4 == 11);
- verify(memcmp(rsp.bytes + 28, "hello world", 11) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_append(void)
-{
- return test_binary_concat_impl("test_binary_append", PROTOCOL_BINARY_CMD_APPEND);
-}
-
-static enum test_return test_binary_prepend(void)
-{
- return test_binary_concat_impl("test_binary_prepend", PROTOCOL_BINARY_CMD_PREPEND);
-}
-
-static enum test_return test_binary_appendq(void)
-{
- return test_binary_concat_impl("test_binary_appendq", PROTOCOL_BINARY_CMD_APPENDQ);
-}
-
-static enum test_return test_binary_prependq(void)
-{
- return test_binary_concat_impl("test_binary_prependq", PROTOCOL_BINARY_CMD_PREPENDQ);
-}
-
-static enum test_return test_binary_stat(void)
-{
- command cmd;
- response rsp;
-
- raw_command(&cmd, PROTOCOL_BINARY_CMD_STAT, NULL, 0, NULL, 0);
- execute(send_packet(&cmd));
-
- do
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_STAT,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- } while (rsp.plain.message.header.response.keylen != 0);
-
- return TEST_PASS;
-}
-
-static enum test_return send_string(const char *cmd)
-{
- execute(retry_write(cmd, strlen(cmd)));
- return TEST_PASS;
-}
-
-static enum test_return receive_line(char *buffer, size_t size)
-{
- size_t offset= 0;
- while (offset < size)
- {
- execute(retry_read(buffer + offset, 1));
- if (buffer[offset] == '\n')
- {
- if (offset + 1 < size)
- {
- buffer[offset + 1]= '\0';
- return TEST_PASS;
- }
- else
- return TEST_FAIL;
- }
- ++offset;
- }
-
- return TEST_FAIL;
-}
-
-static enum test_return receive_response(const char *msg) {
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- if (strcmp(msg, buffer) != 0) {
- fprintf(stderr, "[%s]\n", buffer);
- }
- verify(strcmp(msg, buffer) == 0);
- return TEST_PASS;
-}
-
-static enum test_return receive_error_response(void)
-{
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "ERROR", 5) == 0 ||
- strncmp(buffer, "CLIENT_ERROR", 12) == 0 ||
- strncmp(buffer, "SERVER_ERROR", 12) == 0);
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_quit(void)
-{
- /* Verify that quit handles unknown options */
- execute(send_string("quit foo bar\r\n"));
- execute(receive_error_response());
-
- /* quit doesn't support noreply */
- execute(send_string("quit noreply\r\n"));
- execute(receive_error_response());
-
- /* Verify that quit works */
- execute(send_string("quit\r\n"));
-
- /* Socket should be closed now, read should return EXIT_SUCCESS */
- char buffer[80];
- verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0);
- return TEST_PASS_RECONNECT;
-
-}
-
-static enum test_return test_ascii_version(void)
-{
- /* Verify that version command handles unknown options */
- execute(send_string("version foo bar\r\n"));
- execute(receive_error_response());
-
- /* version doesn't support noreply */
- execute(send_string("version noreply\r\n"));
- execute(receive_error_response());
-
- /* Verify that verify works */
- execute(send_string("version\r\n"));
- char buffer[256];
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "VERSION ", 8) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_verbosity(void)
-{
- /* This command does not adhere to the spec! */
- execute(send_string("verbosity foo bar my\r\n"));
- execute(receive_error_response());
-
- execute(send_string("verbosity noreply\r\n"));
- execute(test_ascii_version());
-
- execute(send_string("verbosity 0 noreply\r\n"));
- execute(test_ascii_version());
-
- execute(send_string("verbosity\r\n"));
- execute(receive_error_response());
-
- execute(send_string("verbosity 1\r\n"));
- execute(receive_response("OK\r\n"));
-
- execute(send_string("verbosity 0\r\n"));
- execute(receive_response("OK\r\n"));
-
- return TEST_PASS;
-}
-
-
-
-static enum test_return test_ascii_set_impl(const char* key, bool noreply)
-{
- /* @todo add tests for bogus format! */
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (!noreply)
- {
- execute(receive_response("STORED\r\n"));
- }
-
- return test_ascii_version();
-}
-
-static enum test_return test_ascii_set(void)
-{
- return test_ascii_set_impl("test_ascii_set", false);
-}
-
-static enum test_return test_ascii_set_noreply(void)
-{
- return test_ascii_set_impl("test_ascii_set_noreply", true);
-}
-
-static enum test_return test_ascii_add_impl(const char* key, bool noreply)
-{
- /* @todo add tests for bogus format! */
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (!noreply)
- {
- execute(receive_response("STORED\r\n"));
- }
-
- execute(send_string(buffer));
-
- if (!noreply)
- {
- execute(receive_response("NOT_STORED\r\n"));
- }
-
- return test_ascii_version();
-}
-
-static enum test_return test_ascii_add(void)
-{
- return test_ascii_add_impl("test_ascii_add", false);
-}
-
-static enum test_return test_ascii_add_noreply(void)
-{
- return test_ascii_add_impl("test_ascii_add_noreply", true);
-}
-
-static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata)
-{
- char buffer[1024];
-
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "VALUE ", 6) == 0);
- char *end= strchr(buffer + 6, ' ');
- verify(end != NULL);
- if (end)
- {
- *end= '\0';
- }
- *key= strdup(buffer + 6);
- verify(*key != NULL);
- char *ptr= end + 1;
-
- errno= 0;
- unsigned long val= strtoul(ptr, &end, 10); /* flags */
- verify(errno == 0);
- verify(ptr != end);
- verify(val == 0);
- verify(end != NULL);
- errno= 0;
- *ndata = (ssize_t)strtoul(end, &end, 10); /* size */
- verify(errno == 0);
- verify(ptr != end);
- verify(end != NULL);
- while (end and *end != '\n' and isspace(*end))
- ++end;
- verify(end and *end == '\n');
-
- *value= static_cast<char*>(malloc((size_t)*ndata));
- verify(*value != NULL);
-
- execute(retry_read(*value, (size_t)*ndata));
-
- execute(retry_read(buffer, 2));
- verify(memcmp(buffer, "\r\n", 2) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_get_value(const char *key, const char *value)
-{
-
- char buffer[1024];
- size_t datasize= strlen(value);
-
- verify(datasize < sizeof(buffer));
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "VALUE ", 6) == 0);
- verify(strncmp(buffer + 6, key, strlen(key)) == 0);
- char *ptr= buffer + 6 + strlen(key) + 1;
- char *end;
-
- errno= 0;
- unsigned long val= strtoul(ptr, &end, 10); /* flags */
- verify(errno == 0);
- verify(ptr != end);
- verify(val == 0);
- verify(end != NULL);
-
- errno= 0;
- val= strtoul(end, &end, 10); /* size */
- verify(errno == 0);
- verify(ptr != end);
- verify(val == datasize);
- verify(end != NULL);
- while (end and *end != '\n' and isspace(*end))
- {
- ++end;
- }
- verify(end and *end == '\n');
-
- execute(retry_read(buffer, datasize));
- verify(memcmp(buffer, value, datasize) == 0);
-
- execute(retry_read(buffer, 2));
- verify(memcmp(buffer, "\r\n", 2) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_get_item(const char *key, const char *value,
- bool exist)
-{
- char buffer[1024];
- size_t datasize= 0;
- if (value != NULL)
- {
- datasize= strlen(value);
- }
-
- verify(datasize < sizeof(buffer));
- snprintf(buffer, sizeof(buffer), "get %s\r\n", key);
- execute(send_string(buffer));
-
- if (exist)
- {
- execute(ascii_get_value(key, value));
- }
-
- execute(retry_read(buffer, 5));
- verify(memcmp(buffer, "END\r\n", 5) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_gets_value(const char *key, const char *value,
- unsigned long *cas)
-{
-
- char buffer[1024];
- size_t datasize= strlen(value);
-
- verify(datasize < sizeof(buffer));
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "VALUE ", 6) == 0);
- verify(strncmp(buffer + 6, key, strlen(key)) == 0);
- char *ptr= buffer + 6 + strlen(key) + 1;
- char *end;
-
- errno= 0;
- unsigned long val= strtoul(ptr, &end, 10); /* flags */
- verify(errno == 0);
- verify(ptr != end);
- verify(val == 0);
- verify(end != NULL);
-
- errno= 0;
- val= strtoul(end, &end, 10); /* size */
- verify(errno == 0);
- verify(ptr != end);
- verify(val == datasize);
- verify(end != NULL);
-
- errno= 0;
- *cas= strtoul(end, &end, 10); /* cas */
- verify(errno == 0);
- verify(ptr != end);
- verify(val == datasize);
- verify(end != NULL);
-
- while (end and *end != '\n' and isspace(*end))
- {
- ++end;
- }
- verify(end and *end == '\n');
-
- execute(retry_read(buffer, datasize));
- verify(memcmp(buffer, value, datasize) == 0);
-
- execute(retry_read(buffer, 2));
- verify(memcmp(buffer, "\r\n", 2) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_gets_item(const char *key, const char *value,
- bool exist, unsigned long *cas)
-{
- char buffer[1024];
- size_t datasize= 0;
- if (value != NULL)
- {
- datasize= strlen(value);
- }
-
- verify(datasize < sizeof(buffer));
- snprintf(buffer, sizeof(buffer), "gets %s\r\n", key);
- execute(send_string(buffer));
-
- if (exist)
- execute(ascii_gets_value(key, value, cas));
-
- execute(retry_read(buffer, 5));
- verify(memcmp(buffer, "END\r\n", 5) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_set_item(const char *key, const char *value)
-{
- char buffer[300];
- size_t len= strlen(value);
- snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len);
- execute(send_string(buffer));
- execute(retry_write(value, len));
- execute(send_string("\r\n"));
- execute(receive_response("STORED\r\n"));
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_replace_impl(const char* key, bool noreply)
-{
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (noreply)
- {
- execute(test_ascii_version());
- }
- else
- {
- execute(receive_response("NOT_STORED\r\n"));
- }
-
- execute(ascii_set_item(key, "value"));
- execute(ascii_get_item(key, "value", true));
-
-
- execute(send_string(buffer));
-
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("STORED\r\n"));
-
- return test_ascii_version();
-}
-
-static enum test_return test_ascii_replace(void)
-{
- return test_ascii_replace_impl("test_ascii_replace", false);
-}
-
-static enum test_return test_ascii_replace_noreply(void)
-{
- return test_ascii_replace_impl("test_ascii_replace_noreply", true);
-}
-
-static enum test_return test_ascii_cas_impl(const char* key, bool noreply)
-{
- char buffer[1024];
- unsigned long cas;
-
- execute(ascii_set_item(key, "value"));
- execute(ascii_gets_item(key, "value", true, &cas));
-
- snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (noreply)
- {
- execute(test_ascii_version());
- }
- else
- {
- execute(receive_response("STORED\r\n"));
- }
-
- /* reexecute the same command should fail due to illegal cas */
- execute(send_string(buffer));
-
- if (noreply)
- {
- execute(test_ascii_version());
- }
- else
- {
- execute(receive_response("EXISTS\r\n"));
- }
-
- return test_ascii_version();
-}
-
-static enum test_return test_ascii_cas(void)
-{
- return test_ascii_cas_impl("test_ascii_cas", false);
-}
-
-static enum test_return test_ascii_cas_noreply(void)
-{
- return test_ascii_cas_impl("test_ascii_cas_noreply", true);
-}
-
-static enum test_return test_ascii_delete_impl(const char *key, bool noreply)
-{
- execute(ascii_set_item(key, "value"));
-
- execute(send_string("delete\r\n"));
- execute(receive_error_response());
- /* BUG: the server accepts delete a b */
- execute(send_string("delete a b c d e\r\n"));
- execute(receive_error_response());
-
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("DELETED\r\n"));
-
- execute(ascii_get_item(key, "value", false));
- execute(send_string(buffer));
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("NOT_FOUND\r\n"));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_delete(void)
-{
- return test_ascii_delete_impl("test_ascii_delete", false);
-}
-
-static enum test_return test_ascii_delete_noreply(void)
-{
- return test_ascii_delete_impl("test_ascii_delete_noreply", true);
-}
-
-static enum test_return test_ascii_get(void)
-{
- execute(ascii_set_item("test_ascii_get", "value"));
-
- execute(send_string("get\r\n"));
- execute(receive_error_response());
- execute(ascii_get_item("test_ascii_get", "value", true));
- execute(ascii_get_item("test_ascii_get_notfound", "value", false));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_gets(void)
-{
- execute(ascii_set_item("test_ascii_gets", "value"));
-
- execute(send_string("gets\r\n"));
- execute(receive_error_response());
- unsigned long cas;
- execute(ascii_gets_item("test_ascii_gets", "value", true, &cas));
- execute(ascii_gets_item("test_ascii_gets_notfound", "value", false, &cas));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_mget(void)
-{
- const uint32_t nkeys= 5;
- const char * const keys[]= {
- "test_ascii_mget1",
- "test_ascii_mget2",
- /* test_ascii_mget_3 does not exist :) */
- "test_ascii_mget4",
- "test_ascii_mget5",
- "test_ascii_mget6"
- };
-
- for (uint32_t x= 0; x < nkeys; ++x)
- {
- execute(ascii_set_item(keys[x], "value"));
- }
-
- /* Ask for a key that doesn't exist as well */
- execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 "
- "test_ascii_mget4 test_ascii_mget5 "
- "test_ascii_mget6\r\n"));
-
- std::vector<char *> returned;
- returned.resize(nkeys);
-
- for (uint32_t x= 0; x < nkeys; ++x)
- {
- ssize_t nbytes = 0;
- char *v= NULL;
- execute(ascii_get_unknown_value(&returned[x], &v, &nbytes));
- verify(nbytes == 5);
- verify(memcmp(v, "value", 5) == 0);
- free(v);
- }
-
- char buffer[5];
- execute(retry_read(buffer, 5));
- verify(memcmp(buffer, "END\r\n", 5) == 0);
-
- /* verify that we got all the keys we expected */
- for (uint32_t x= 0; x < nkeys; ++x)
- {
- bool found= false;
- for (uint32_t y= 0; y < nkeys; ++y)
- {
- if (strcmp(keys[x], returned[y]) == 0)
- {
- found = true;
- break;
- }
- }
- verify(found);
- }
-
- for (uint32_t x= 0; x < nkeys; ++x)
- {
- free(returned[x]);
- }
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_incr_impl(const char* key, bool noreply)
-{
- char cmd[300];
- snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : "");
-
- execute(ascii_set_item(key, "0"));
- for (int x= 1; x < 11; ++x)
- {
- execute(send_string(cmd));
-
- if (noreply)
- execute(test_ascii_version());
- else
- {
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- int val= atoi(buffer);
- verify(val == x);
- }
- }
-
- execute(ascii_get_item(key, "10", true));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_incr(void)
-{
- return test_ascii_incr_impl("test_ascii_incr", false);
-}
-
-static enum test_return test_ascii_incr_noreply(void)
-{
- return test_ascii_incr_impl("test_ascii_incr_noreply", true);
-}
-
-static enum test_return test_ascii_decr_impl(const char* key, bool noreply)
-{
- char cmd[300];
- snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : "");
-
- execute(ascii_set_item(key, "9"));
- for (int x= 8; x > -1; --x)
- {
- execute(send_string(cmd));
-
- if (noreply)
- {
- execute(test_ascii_version());
- }
- else
- {
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- int val= atoi(buffer);
- verify(val == x);
- }
- }
-
- execute(ascii_get_item(key, "0", true));
-
- /* verify that it doesn't wrap */
- execute(send_string(cmd));
- if (noreply)
- {
- execute(test_ascii_version());
- }
- else
- {
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- }
- execute(ascii_get_item(key, "0", true));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_decr(void)
-{
- return test_ascii_decr_impl("test_ascii_decr", false);
-}
-
-static enum test_return test_ascii_decr_noreply(void)
-{
- return test_ascii_decr_impl("test_ascii_decr_noreply", true);
-}
-
-
-static enum test_return test_ascii_flush_impl(const char *key, bool noreply)
-{
-#if 0
- /* Verify that the flush_all command handles unknown options */
- /* Bug in the current memcached server! */
- execute(send_string("flush_all foo bar\r\n"));
- execute(receive_error_response());
-#endif
-
- execute(ascii_set_item(key, key));
- execute(ascii_get_item(key, key, true));
-
- if (noreply)
- {
- execute(send_string("flush_all noreply\r\n"));
- execute(test_ascii_version());
- }
- else
- {
- execute(send_string("flush_all\r\n"));
- execute(receive_response("OK\r\n"));
- }
-
- execute(ascii_get_item(key, key, false));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_flush(void)
-{
- return test_ascii_flush_impl("test_ascii_flush", false);
-}
-
-static enum test_return test_ascii_flush_noreply(void)
-{
- return test_ascii_flush_impl("test_ascii_flush_noreply", true);
-}
-
-static enum test_return test_ascii_concat_impl(const char *key,
- bool append,
- bool noreply)
-{
- const char *value;
-
- if (append)
- value="hello";
- else
- value=" world";
-
- execute(ascii_set_item(key, value));
-
- if (append)
- {
- value=" world";
- }
- else
- {
- value="hello";
- }
-
- char cmd[400];
- snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n",
- append ? "append" : "prepend",
- key, (unsigned int)strlen(value), noreply ? " noreply" : "",
- value);
- execute(send_string(cmd));
-
- if (noreply)
- {
- execute(test_ascii_version());
- }
- else
- {
- execute(receive_response("STORED\r\n"));
- }
-
- execute(ascii_get_item(key, "hello world", true));
-
- snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n",
- append ? "append" : "prepend",
- key, (unsigned int)strlen(value), noreply ? " noreply" : "",
- value);
- execute(send_string(cmd));
-
- if (noreply)
- {
- execute(test_ascii_version());
- }
- else
- {
- execute(receive_response("NOT_STORED\r\n"));
- }
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_append(void)
-{
- return test_ascii_concat_impl("test_ascii_append", true, false);
-}
-
-static enum test_return test_ascii_prepend(void)
-{
- return test_ascii_concat_impl("test_ascii_prepend", false, false);
-}
-
-static enum test_return test_ascii_append_noreply(void)
-{
- return test_ascii_concat_impl("test_ascii_append_noreply", true, true);
-}
-
-static enum test_return test_ascii_prepend_noreply(void)
-{
- return test_ascii_concat_impl("test_ascii_prepend_noreply", false, true);
-}
-
-static enum test_return test_ascii_stat(void)
-{
- execute(send_string("stats noreply\r\n"));
- execute(receive_error_response());
- execute(send_string("stats\r\n"));
- char buffer[1024];
- do {
- execute(receive_line(buffer, sizeof(buffer)));
- } while (strcmp(buffer, "END\r\n") != 0);
-
- return TEST_PASS_RECONNECT;
-}
-
-typedef enum test_return(*TEST_FUNC)(void);
-
-struct testcase
-{
- const char *description;
- TEST_FUNC function;
-};
-
-struct testcase testcases[]= {
- { "ascii quit", test_ascii_quit },
- { "ascii version", test_ascii_version },
- { "ascii verbosity", test_ascii_verbosity },
- { "ascii set", test_ascii_set },
- { "ascii set noreply", test_ascii_set_noreply },
- { "ascii get", test_ascii_get },
- { "ascii gets", test_ascii_gets },
- { "ascii mget", test_ascii_mget },
- { "ascii flush", test_ascii_flush },
- { "ascii flush noreply", test_ascii_flush_noreply },
- { "ascii add", test_ascii_add },
- { "ascii add noreply", test_ascii_add_noreply },
- { "ascii replace", test_ascii_replace },
- { "ascii replace noreply", test_ascii_replace_noreply },
- { "ascii cas", test_ascii_cas },
- { "ascii cas noreply", test_ascii_cas_noreply },
- { "ascii delete", test_ascii_delete },
- { "ascii delete noreply", test_ascii_delete_noreply },
- { "ascii incr", test_ascii_incr },
- { "ascii incr noreply", test_ascii_incr_noreply },
- { "ascii decr", test_ascii_decr },
- { "ascii decr noreply", test_ascii_decr_noreply },
- { "ascii append", test_ascii_append },
- { "ascii append noreply", test_ascii_append_noreply },
- { "ascii prepend", test_ascii_prepend },
- { "ascii prepend noreply", test_ascii_prepend_noreply },
- { "ascii stat", test_ascii_stat },
- { "binary noop", test_binary_noop },
- { "binary quit", test_binary_quit },
- { "binary quitq", test_binary_quitq },
- { "binary set", test_binary_set },
- { "binary setq", test_binary_setq },
- { "binary flush", test_binary_flush },
- { "binary flushq", test_binary_flushq },
- { "binary add", test_binary_add },
- { "binary addq", test_binary_addq },
- { "binary replace", test_binary_replace },
- { "binary replaceq", test_binary_replaceq },
- { "binary delete", test_binary_delete },
- { "binary deleteq", test_binary_deleteq },
- { "binary get", test_binary_get },
- { "binary getq", test_binary_getq },
- { "binary getk", test_binary_getk },
- { "binary getkq", test_binary_getkq },
- { "binary incr", test_binary_incr },
- { "binary incrq", test_binary_incrq },
- { "binary decr", test_binary_decr },
- { "binary decrq", test_binary_decrq },
- { "binary version", test_binary_version },
- { "binary append", test_binary_append },
- { "binary appendq", test_binary_appendq },
- { "binary prepend", test_binary_prepend },
- { "binary prependq", test_binary_prependq },
- { "binary stat", test_binary_stat },
- { NULL, NULL}
-};
-
-const int ascii_tests = 1;
-const int binary_tests = 2;
-
-struct test_type_st
-{
- bool ascii;
- bool binary;
-};
-
-int main(int argc, char **argv)
-{
- static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"};
- struct test_type_st tests= { true, true };
- int total= 0;
- int failed= 0;
- const char *hostname= NULL;
- const char *port= MEMCACHED_DEFAULT_PORT_STRING;
- int cmd;
- bool prompt= false;
- const char *testname= NULL;
-
-
-
- while ((cmd= getopt(argc, argv, "qt:vch:p:PT:?ab")) != EOF)
- {
- switch (cmd) {
- case 'a':
- tests.ascii= true;
- tests.binary= false;
- break;
-
- case 'b':
- tests.ascii= false;
- tests.binary= true;
- break;
-
- case 't':
- timeout= atoi(optarg);
- if (timeout == 0)
- {
- fprintf(stderr, "Invalid timeout. Please specify a number for -t\n");
- return EXIT_FAILURE;
- }
- break;
-
- case 'v': verbose= true;
- break;
-
- case 'c': do_core= true;
- break;
-
- case 'h': hostname= optarg;
- break;
-
- case 'p': port= optarg;
- break;
-
- case 'q':
- close_stdio();
- break;
-
- case 'P': prompt= true;
- break;
-
- case 'T': testname= optarg;
- break;
-
- default:
- fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n"
- "\t-c\tGenerate coredump if a test fails\n"
- "\t-v\tVerbose test output (print out the assertion)\n"
- "\t-t n\tSet the timeout for io-operations to n seconds\n"
- "\t-P\tPrompt the user before starting a test.\n"
- "\t\t\t\"skip\" will skip the test\n"
- "\t\t\t\"quit\" will terminate memcapable\n"
- "\t\t\tEverything else will start the test\n"
- "\t-T n\tJust run the test named n\n"
- "\t-a\tOnly test the ascii protocol\n"
- "\t-b\tOnly test the binary protocol\n",
- argv[0]);
- return EXIT_SUCCESS;
- }
- }
-
- if (!hostname)
- {
- fprintf(stderr, "No hostname was provided.\n");
- return EXIT_FAILURE;
- }
-
- initialize_sockets();
- sock= connect_server(hostname, port);
- if (sock == INVALID_SOCKET)
- {
- fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
- hostname?:"(null)", port?:"(null)", strerror(get_socket_errno()));
- return EXIT_FAILURE;
- }
-
- for (int ii= 0; testcases[ii].description != NULL; ++ii)
- {
- if (testname != NULL && strcmp(testcases[ii].description, testname) != 0)
- {
- continue;
- }
-
- if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) ||
- (testcases[ii].description[0] == 'b' && (tests.binary) == 0))
- {
- continue;
- }
- ++total;
- fprintf(stdout, "%-40s", testcases[ii].description);
- fflush(stdout);
-
- if (prompt)
- {
- fprintf(stdout, "\nPress <return> when you are ready? ");
- char buffer[80] = {0};
- if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
- if (strncmp(buffer, "skip", 4) == 0)
- {
- fprintf(stdout, "%-40s%s\n", testcases[ii].description,
- status_msg[TEST_SKIP]);
- fflush(stdout);
- continue;
- }
- if (strncmp(buffer, "quit", 4) == 0)
- {
- exit(EXIT_SUCCESS);
- }
- }
-
- fprintf(stdout, "%-40s", testcases[ii].description);
- fflush(stdout);
- }
-
- bool reconnect= false;
- enum test_return ret= testcases[ii].function();
- if (ret == TEST_FAIL)
- {
- reconnect= true;
- ++failed;
- if (verbose)
- {
- fprintf(stderr, "\n");
- }
- }
- else if (ret == TEST_PASS_RECONNECT)
- {
- reconnect= true;
- }
-
- if (ret == TEST_FAIL)
- {
- fprintf(stderr, "%s\n", status_msg[ret]);
- }
- else
- {
- fprintf(stdout, "%s\n", status_msg[ret]);
- }
-
- if (reconnect)
- {
- closesocket(sock);
- if ((sock= connect_server(hostname, port)) == INVALID_SOCKET)
- {
- fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", hostname?:"(null)", port?:"(null)", strerror(get_socket_errno()));
- fprintf(stderr, "%d of %d tests failed\n", failed, total);
- return EXIT_FAILURE;
- }
- }
- }
-
- closesocket(sock);
- if (failed == 0)
- {
- fprintf(stdout, "All tests passed\n");
- }
- else
- {
- fprintf(stderr, "%d of %d tests failed\n", failed, total);
- }
-
- return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-}
+++ /dev/null
-#!/bin/sh
-clients/memcapable -vh localhost
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 <mem_config.h>
-
-#include <cstdio>
-#include <cstring>
-#include <getopt.h>
-#include <iostream>
-#include <unistd.h>
-#include <libmemcached-1.0/memcached.h>
-
-#include "utilities.h"
-
-#define PROGRAM_NAME "memcat"
-#define PROGRAM_DESCRIPTION "Cat a set of key values to stdout."
-
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static int opt_displayflag= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-static char *opt_file;
-
-int main(int argc, char *argv[])
-{
- char *string;
- size_t string_length;
- uint32_t flags;
- memcached_return_t rc;
-
- int return_code= EXIT_SUCCESS;
-
- options_parse(argc, argv);
- initialize_sockets();
-
- if (opt_servers == NULL)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
-
- if (opt_servers == NULL)
- {
- std::cerr << "No servers provided" << std::endl;
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_server_st* servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- return EXIT_FAILURE;
- }
-
- memcached_st* memc= memcached_create(NULL);
- process_hash_option(memc, opt_hash);
-
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t)opt_binary);
-
- if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- memcached_free(memc);
- std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
- return EXIT_FAILURE;
- }
-
- if (opt_username)
- {
- memcached_return_t ret;
- if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
- {
- std::cerr << memcached_last_error_message(memc) << std::endl;
- memcached_free(memc);
- return EXIT_FAILURE;
- }
- }
-
- while (optind < argc)
- {
- string= memcached_get(memc, argv[optind], strlen(argv[optind]),
- &string_length, &flags, &rc);
- if (rc == MEMCACHED_SUCCESS)
- {
- if (opt_displayflag)
- {
- if (opt_verbose)
- {
- std::cout << "key: " << argv[optind] << std::endl << "flags: " << flags << std::endl;
- }
- }
- else
- {
- if (opt_verbose)
- {
- std::cout << "key: " << argv[optind] << std::endl << "flags: " << flags << std::endl << "length: " << string_length << std::endl << "value: ";
- }
-
- if (opt_file)
- {
- FILE *fp= fopen(opt_file, "w");
- if (fp == NULL)
- {
- perror("fopen");
- return_code= EXIT_FAILURE;
- break;
- }
-
- size_t written= fwrite(string, 1, string_length, fp);
- if (written != string_length)
- {
- std::cerr << "error writing file to file " << opt_file << " wrote " << written << ", should have written" << string_length << std::endl;
- return_code= EXIT_FAILURE;
- break;
- }
-
- if (fclose(fp))
- {
- std::cerr << "error closing " << opt_file << std::endl;
- return_code= EXIT_FAILURE;
- break;
- }
- }
- else
- {
- std::cout.write(string, string_length);
- std::cout << std::endl;
- }
- free(string);
- }
- }
- else if (rc != MEMCACHED_NOTFOUND)
- {
- std::cerr << "error on " << argv[optind] << "(" << memcached_strerror(memc, rc) << ")";
- if (memcached_last_error_errno(memc))
- {
- std::cerr << " system error (" << strerror(memcached_last_error_errno(memc)) << ")" << std::endl;
- }
- std::cerr << std::endl;
-
- return_code= EXIT_FAILURE;
- break;
- }
- else // Unknown Issue
- {
- std::cerr << "error on " << argv[optind] << "("<< memcached_strerror(NULL, rc) << ")" << std::endl;
- return_code= EXIT_FAILURE;
- }
- optind++;
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- {
- free(opt_servers);
- }
- if (opt_hash)
- {
- free(opt_hash);
- }
-
- return return_code;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
- int option_index= 0;
-
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {(OPTIONSTRING)"file", required_argument, NULL, OPT_FILE},
- {0, 0, 0, 0},
- };
-
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1) break;
- switch (option_rv)
- {
- case 0:
- break;
- case OPT_BINARY:
- opt_binary = 1;
- break;
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- break;
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
- case OPT_USERNAME:
- opt_username= optarg;
- break;
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
- case OPT_FILE:
- opt_file= optarg;
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(EXIT_FAILURE);
- default:
- abort();
- }
- }
-}
+++ /dev/null
-#!/bin/sh
-clients/memcp.sh
-clients/memcat --servers=localhost -v mem.testdata
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- * 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 "mem_config.h"
-
-#include <cerrno>
-#include <climits>
-#include <cstdio>
-#include <cstdlib>
-#include <cstdlib>
-#include <cstring>
-#include <fcntl.h>
-#include <getopt.h>
-#include <iostream>
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-
-#include <libmemcached-1.0/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-
-#define PROGRAM_NAME "memcp"
-#define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-static bool opt_binary= false;
-static bool opt_udp= false;
-static bool opt_buffer= false;
-static int opt_verbose= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static int opt_method= OPT_SET;
-static uint32_t opt_flags= 0;
-static time_t opt_expires= 0;
-static char *opt_username;
-static char *opt_passwd;
-
-static long strtol_wrapper(const char *nptr, int base, bool *error)
-{
- long val;
- char *endptr;
-
- errno= 0; /* To distinguish success/failure after call */
- val= strtol(nptr, &endptr, base);
-
- /* Check for various possible errors */
-
- if ((errno == ERANGE and (val == LONG_MAX or val == LONG_MIN))
- or (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[])
-{
-
- options_parse(argc, argv);
-
- if (optind >= argc)
- {
- fprintf(stderr, "Expected argument after options\n");
- exit(EXIT_FAILURE);
- }
-
- initialize_sockets();
-
- memcached_st *memc= memcached_create(NULL);
-
- if (opt_udp)
- {
- if (opt_verbose)
- {
- std::cout << "Enabling UDP" << std::endl;
- }
-
- if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, opt_udp)))
- {
- memcached_free(memc);
- std::cerr << "Could not enable UDP protocol." << std::endl;
- return EXIT_FAILURE;
- }
- }
-
- if (opt_buffer)
- {
- if (opt_verbose)
- {
- std::cout << "Enabling MEMCACHED_BEHAVIOR_BUFFER_REQUESTS" << std::endl;
- }
-
- if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, opt_buffer)))
- {
- memcached_free(memc);
- std::cerr << "Could not enable MEMCACHED_BEHAVIOR_BUFFER_REQUESTS." << std::endl;
- return EXIT_FAILURE;
- }
- }
-
- process_hash_option(memc, opt_hash);
-
- if (opt_servers == NULL)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
-#if 0
- else if (argc >= 1 and argv[--argc])
- {
- opt_servers= strdup(argv[argc]);
- }
-#endif
-
- if (opt_servers == NULL)
- {
- std::cerr << "No Servers provided" << std::endl;
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_server_st* servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- return EXIT_FAILURE;
- }
-
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, opt_binary);
- if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- memcached_free(memc);
- std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
- return EXIT_FAILURE;
- }
-
- if (opt_username)
- {
- memcached_return_t ret;
- if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
- {
- std::cerr << memcached_last_error_message(memc) << std::endl;
- memcached_free(memc);
- return EXIT_FAILURE;
- }
- }
-
- int exit_code= EXIT_SUCCESS;
- while (optind < argc)
- {
- int fd= open(argv[optind], O_RDONLY);
- if (fd < 0)
- {
- std::cerr << "memcp " << argv[optind] << " " << strerror(errno) << std::endl;
- optind++;
- exit_code= EXIT_FAILURE;
- continue;
- }
-
- struct stat sbuf;
- if (fstat(fd, &sbuf) == -1)
- {
- std::cerr << "memcp " << argv[optind] << " " << strerror(errno) << std::endl;
- optind++;
- exit_code= EXIT_FAILURE;
- continue;
- }
-
- char *ptr= rindex(argv[optind], '/');
- if (ptr)
- {
- ptr++;
- }
- else
- {
- ptr= argv[optind];
- }
-
- if (opt_verbose)
- {
- static const char *opstr[] = { "set", "add", "replace" };
- printf("op: %s\nsource file: %s\nlength: %lu\n"
- "key: %s\nflags: %x\nexpires: %lu\n",
- opstr[opt_method - OPT_SET], argv[optind], (unsigned long)sbuf.st_size,
- ptr, opt_flags, (unsigned long)opt_expires);
- }
-
- // The file may be empty
- char *file_buffer_ptr= NULL;
- if (sbuf.st_size > 0)
- {
- if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL)
- {
- std::cerr << "Error allocating file buffer(" << strerror(errno) << ")" << std::endl;
- close(fd);
- exit(EXIT_FAILURE);
- }
-
- ssize_t read_length;
- if ((read_length= ::read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1)
- {
- std::cerr << "Error while reading file " << file_buffer_ptr << " (" << strerror(errno) << ")" << std::endl;
- close(fd);
- free(file_buffer_ptr);
- exit(EXIT_FAILURE);
- }
-
- if (read_length != sbuf.st_size)
- {
- std::cerr << "Failure while reading file. Read length was not equal to stat() length" << std::endl;
- close(fd);
- free(file_buffer_ptr);
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_return_t rc;
- if (opt_method == OPT_ADD)
- {
- rc= memcached_add(memc, ptr, strlen(ptr),
- file_buffer_ptr, (size_t)sbuf.st_size,
- opt_expires, opt_flags);
- }
- else if (opt_method == OPT_REPLACE)
- {
- rc= memcached_replace(memc, ptr, strlen(ptr),
- file_buffer_ptr, (size_t)sbuf.st_size,
- opt_expires, opt_flags);
- }
- else
- {
- rc= memcached_set(memc, ptr, strlen(ptr),
- file_buffer_ptr, (size_t)sbuf.st_size,
- opt_expires, opt_flags);
- }
-
- if (memcached_failed(rc))
- {
- std::cerr << "Error occrrured during memcached_set(): " << memcached_last_error_message(memc) << std::endl;
- exit_code= EXIT_FAILURE;
- }
-
- ::free(file_buffer_ptr);
- ::close(fd);
- optind++;
- }
-
- if (opt_verbose)
- {
- std::cout << "Calling memcached_free()" << std::endl;
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- {
- free(opt_servers);
- }
-
- if (opt_hash)
- {
- free(opt_hash);
- }
-
- return exit_code;
-}
-
-static void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP},
- {(OPTIONSTRING)"buffer", no_argument, NULL, OPT_BUFFER},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG},
- {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
- {(OPTIONSTRING)"set", no_argument, NULL, OPT_SET},
- {(OPTIONSTRING)"add", no_argument, NULL, OPT_ADD},
- {(OPTIONSTRING)"replace", no_argument, NULL, OPT_REPLACE},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0},
- };
-
- bool opt_version= false;
- bool opt_help= false;
- int option_index= 0;
-
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-
- if (option_rv == -1)
- break;
-
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_BINARY:
- opt_binary= true;
- break;
-
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose= OPT_VERBOSE;
- break;
-
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose= OPT_DEBUG;
- break;
-
- case OPT_VERSION: /* --version or -V */
- opt_version= true;
- break;
-
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
-
- case OPT_FLAG: /* --flag */
- {
- bool strtol_error;
- opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error);
- if (strtol_error == true)
- {
- fprintf(stderr, "Bad value passed via --flag\n");
- exit(1);
- }
- }
- break;
-
- case OPT_EXPIRE: /* --expire */
- {
- bool strtol_error;
- opt_expires= (time_t)strtol_wrapper(optarg, 10, &strtol_error);
- if (strtol_error == true)
- {
- fprintf(stderr, "Bad value passed via --expire\n");
- exit(1);
- }
- }
- break;
-
- case OPT_SET:
- opt_method= OPT_SET;
- break;
-
- case OPT_REPLACE:
- opt_method= OPT_REPLACE;
- break;
-
- case OPT_ADD:
- opt_method= OPT_ADD;
- break;
-
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
-
- case OPT_USERNAME:
- opt_username= optarg;
- break;
-
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
- case OPT_UDP:
- opt_udp= true;
- break;
-
- case OPT_BUFFER:
- opt_buffer= true;
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- exit(EXIT_SUCCESS);
- }
-}
+++ /dev/null
-#!/bin/sh
-clients/memcp -v --servers localhost mem.testdata
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 "mem_config.h"
-
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <fcntl.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <iostream>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <libmemcached-1.0/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-
-#define PROGRAM_NAME "memdump"
-#define PROGRAM_DESCRIPTION "Dump all values from one or many servers."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-static bool opt_binary=0;
-static int opt_verbose= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-/* Print the keys and counter how many were found */
-static memcached_return_t key_printer(const memcached_st *,
- const char *key, size_t key_length,
- void *)
-{
- std::cout.write(key, key_length);
- std::cout << std::endl;
-
- return MEMCACHED_SUCCESS;
-}
-
-int main(int argc, char *argv[])
-{
- memcached_dump_fn callbacks[1];
-
- callbacks[0]= &key_printer;
-
- options_parse(argc, argv);
-
- if (opt_servers == NULL)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
- else if (argc >= 1 and argv[--argc])
- {
- opt_servers= strdup(argv[argc]);
- }
-
- if (opt_servers == NULL)
- {
- std::cerr << "No Servers provided" << std::endl;
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_server_st* servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- return EXIT_FAILURE;
- }
-
- memcached_st *memc= memcached_create(NULL);
- if (memc == NULL)
- {
- std::cerr << "Could not allocate a memcached_st structure.\n" << std::endl;
- return EXIT_FAILURE;
- }
- process_hash_option(memc, opt_hash);
-
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t)opt_binary);
-
- if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- memcached_free(memc);
- std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
- return EXIT_FAILURE;
- }
-
- if (opt_username)
- {
- memcached_return_t ret;
- if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
- {
- std::cerr << memcached_last_error_message(memc) << std::endl;
- memcached_free(memc);
- return EXIT_FAILURE;
- }
- }
-
- memcached_return_t rc= memcached_dump(memc, callbacks, NULL, 1);
-
- int exit_code= EXIT_SUCCESS;
- if (memcached_failed(rc))
- {
- if (opt_verbose)
- {
- std::cerr << "Failed to dump keys: " << memcached_last_error_message(memc) << std::endl;
- }
- exit_code= EXIT_FAILURE;
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- {
- free(opt_servers);
- }
- if (opt_hash)
- {
- free(opt_hash);
- }
-
- return exit_code;
-}
-
-static void options_parse(int argc, char *argv[])
-{
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0}
- };
-
- int option_index= 0;
- bool opt_version= false;
- bool opt_help= false;
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-
- if (option_rv == -1) break;
-
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_BINARY:
- opt_binary= true;
- break;
-
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose= OPT_VERBOSE;
- break;
-
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose= OPT_DEBUG;
- break;
-
- case OPT_VERSION: /* --version or -V */
- opt_verbose= true;
- break;
-
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
-
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
-
- case OPT_USERNAME:
- opt_username= optarg;
- break;
-
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
- exit(EXIT_SUCCESS);
- }
-}
+++ /dev/null
-#!/bin/bash
-clients/memdump -v --servers localhost
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 "mem_config.h"
-
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <climits>
-
-#include <getopt.h>
-#include <iostream>
-#include <unistd.h>
-
-#include <libmemcached-1.0/memcached.h>
-
-#include "utilities.h"
-
-#define PROGRAM_NAME "memerror"
-#define PROGRAM_DESCRIPTION "Translate a memcached errror code into a string."
-
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
- options_parse(argc, argv);
-
- if (argc < 2)
- {
- return EXIT_FAILURE;
- }
-
- while (optind < argc)
- {
- errno= 0;
- char *nptr;
- unsigned long value= strtoul(argv[optind], &nptr, 10);
-
- if ((errno != 0) or
- (nptr == argv[optind] and value == 0) or
- (value == ULONG_MAX and errno == ERANGE) or
- (value == 0 and errno == EINVAL))
- {
- std::cerr << "strtoul() was unable to parse given value" << std::endl;
- return EXIT_FAILURE;
- }
-
- if (value < MEMCACHED_MAXIMUM_RETURN)
- {
- std::cout << memcached_strerror(NULL, (memcached_return_t)value) << std::endl;
- }
- else
- {
- std::cerr << memcached_strerror(NULL, MEMCACHED_MAXIMUM_RETURN) << std::endl;
- return EXIT_FAILURE;
- }
-
- optind++;
- }
-
- return EXIT_SUCCESS;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {0, 0, 0, 0},
- };
-
- bool opt_version= false;
- bool opt_help= false;
- int option_index= 0;
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1)
- {
- break;
- }
-
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_VERSION: /* --version or -V */
- opt_version= true;
- break;
-
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(EXIT_FAILURE);
-
- default:
- exit(EXIT_FAILURE);
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
- exit(EXIT_SUCCESS);
- }
-}
+++ /dev/null
-#!/bin/sh
-clients/memerror 0 1 2 3
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 "mem_config.h"
-
-#include <cstdio>
-#include <cstring>
-#include <getopt.h>
-#include <iostream>
-#include <unistd.h>
-
-#include <libmemcached-1.0/memcached.h>
-#include "client_options.h"
-#include "utilities.h"
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-#define PROGRAM_NAME "memexist"
-#define PROGRAM_DESCRIPTION "Check for the existance of a key within a cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
- options_parse(argc, argv);
- initialize_sockets();
-
- if (opt_servers == NULL)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
-
- if (opt_servers == NULL)
- {
- std::cerr << "No Servers provided" << std::endl;
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_server_st* servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- return EXIT_FAILURE;
- }
-
- memcached_st* memc= memcached_create(NULL);
- process_hash_option(memc, opt_hash);
-
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t) opt_binary);
-
- if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- memcached_free(memc);
- std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
- return EXIT_FAILURE;
- }
-
- if (opt_username)
- {
- memcached_return_t ret;
- if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
- {
- std::cerr << memcached_last_error_message(memc) << std::endl;
- memcached_free(memc);
- return EXIT_FAILURE;
- }
- }
-
- int return_code= EXIT_SUCCESS;
-
- while (optind < argc)
- {
- memcached_return_t rc= memcached_exist(memc, argv[optind], strlen(argv[optind]));
-
- if (rc == MEMCACHED_NOTFOUND)
- {
- if (opt_verbose)
- {
- std::cout << "Could not find key \"" << argv[optind] << "\"" << std::endl;
- }
-
- return_code= EXIT_FAILURE;
- }
- else if (memcached_failed(rc))
- {
- if (opt_verbose)
- {
- std::cerr << "Fatal error for key \"" << argv[optind] << "\" :" << memcached_last_error_message(memc) << std::endl;
- }
-
- return_code= EXIT_FAILURE;
- }
- else // success
- {
- if (opt_verbose)
- {
- std::cout << "Found key " << argv[optind] << std::endl;
- }
- }
-
- optind++;
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- {
- free(opt_servers);
- }
-
- if (opt_hash)
- {
- free(opt_hash);
- }
-
- return return_code;
-}
-
-
-static void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0},
- };
-
- bool opt_version= false;
- bool opt_help= false;
- int option_index= 0;
-
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1)
- {
- break;
- }
-
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_BINARY:
- opt_binary = 1;
- break;
-
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
-
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
-
- case OPT_VERSION: /* --version or -V */
- opt_version= true;
- break;
-
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
-
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
-
- case OPT_USERNAME:
- opt_username= optarg;
- break;
-
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(EXIT_SUCCESS);
-
- default:
- abort();
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- exit(EXIT_SUCCESS);
- }
-}
+++ /dev/null
-#!/bin/bash
-clients/memcp.sh
-clients/memexist -v --servers localhost mem.testdata
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 "mem_config.h"
-
-#include <cerrno>
-#include <cstdio>
-#include <cstring>
-#include <getopt.h>
-#include <iostream>
-#include <unistd.h>
-
-#include <libmemcached-1.0/memcached.h>
-#include "client_options.h"
-#include "utilities.h"
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static time_t opt_expire= 0;
-static char *opt_servers= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-#define PROGRAM_NAME "memflush"
-#define PROGRAM_DESCRIPTION "Erase all data in a server of memcached servers."
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
- options_parse(argc, argv);
-
- if (opt_servers == NULL)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
-
- if (opt_servers == NULL)
- {
- std::cerr << "No Servers provided" << std::endl;
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_server_st* servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- return EXIT_FAILURE;
- }
-
- memcached_st *memc= memcached_create(NULL);
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t) opt_binary);
-
- if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- memcached_free(memc);
- std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
- return EXIT_FAILURE;
- }
-
- if (opt_username)
- {
- memcached_return_t ret;
- if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
- {
- std::cerr << memcached_last_error_message(memc) << std::endl;
- memcached_free(memc);
- return EXIT_FAILURE;
- }
- }
-
- memcached_return_t rc = memcached_flush(memc, opt_expire);
- if (rc != MEMCACHED_SUCCESS)
- {
- std::cerr << memcached_last_error_message(memc) << std::endl;
- }
-
- memcached_free(memc);
-
- free(opt_servers);
-
- return EXIT_SUCCESS;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0},
- };
-
- bool opt_version= false;
- bool opt_help= false;
- int option_index= 0;
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1) break;
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_BINARY:
- opt_binary= true;
- break;
-
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose= OPT_VERBOSE;
- break;
-
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose= OPT_DEBUG;
- break;
-
- case OPT_VERSION: /* --version or -V */
- opt_version= true;
- break;
-
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
-
- case OPT_EXPIRE: /* --expire */
- errno= 0;
- opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
- if (errno != 0)
- {
- std::cerr << "Incorrect value passed to --expire: `" << optarg << "`" << std::endl;
- exit(EXIT_FAILURE);
- }
- break;
-
- case OPT_USERNAME:
- opt_username= optarg;
- break;
-
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(EXIT_FAILURE);
-
- default:
- abort();
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
- exit(EXIT_SUCCESS);
- }
-}
+++ /dev/null
-#!/bin/sh
-clients/memflush -v --servers localhost
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <mem_config.h>
-
-#include <cstdio>
-#include <cstring>
-#include <iostream>
-
-#include <libmemcached-1.0/memcached.h>
-
-int main(int argc, char *argv[])
-{
-
- if (argc < 2)
- {
- std::cerr << "No arguments provided." << std::endl;
- return EXIT_FAILURE;
- }
-
- for (int x= 1; x < argc; x++)
- {
- char buffer[BUFSIZ];
- memcached_return_t rc;
- rc= libmemcached_check_configuration(argv[x], strlen(argv[x]), buffer, sizeof(buffer));
-
- if (rc != MEMCACHED_SUCCESS)
- {
- std::cerr << "Failed to parse argument #" << x << " " << argv[x] << std::endl;
- std::cerr << buffer << std::endl;
- return EXIT_FAILURE;
- }
- }
-
- return EXIT_SUCCESS;
-}
+++ /dev/null
-#!/bin/sh
-clients/memparse --server=localhost:11211/?1 --server=127.0.0.1:11211/?2
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 "mem_config.h"
-
-#include <cerrno>
-#include <cstdio>
-#include <cstring>
-#include <getopt.h>
-#include <unistd.h>
-
-#include <libmemcached-1.0/memcached.h>
-#include <libmemcachedutil-1.0/util.h>
-#include "client_options.h"
-#include "utilities.h"
-
-#include <iostream>
-
-static bool opt_binary= false;
-static int opt_verbose= 0;
-static time_t opt_expire= 0;
-static char *opt_servers= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-#define PROGRAM_NAME "memping"
-#define PROGRAM_DESCRIPTION "Ping a server to see if it is alive"
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
- options_parse(argc, argv);
-
- if (opt_servers == NULL)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
-
- if (opt_servers == NULL)
- {
- std::cerr << "No Servers provided" << std::endl;
- exit(EXIT_FAILURE);
- }
- }
-
- int exit_code= EXIT_SUCCESS;
- memcached_server_st *servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- exit_code= EXIT_FAILURE;
- }
- else
- {
- for (uint32_t x= 0; x < memcached_server_list_count(servers); x++)
- {
- memcached_return_t instance_rc;
- const char *hostname= servers[x].hostname;
- in_port_t port= servers[x].port;
-
- if (opt_verbose)
- {
- std::cout << "Trying to ping " << hostname << ":" << port << std::endl;
- }
-
- if (libmemcached_util_ping2(hostname, port, opt_username, opt_passwd, &instance_rc) == false)
- {
- std::cerr << "Failed to ping " << hostname << ":" << port << " " << memcached_strerror(NULL, instance_rc) << std::endl;
- exit_code= EXIT_FAILURE;
- }
- }
- }
- memcached_server_list_free(servers);
-
- free(opt_servers);
-
- return exit_code;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0},
- };
-
- bool opt_version= false;
- bool opt_help= false;
- int option_index= 0;
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-
- if (option_rv == -1) break;
-
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_BINARY:
- opt_binary= true;
- break;
-
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
-
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
-
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
-
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- break;
-
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
-
- case OPT_EXPIRE: /* --expire */
- errno= 0;
- opt_expire= time_t(strtoll(optarg, (char **)NULL, 10));
- if (errno != 0)
- {
- std::cerr << "Incorrect value passed to --expire: `" << optarg << "`" << std::endl;
- exit(EXIT_FAILURE);
- }
- break;
-
- case OPT_USERNAME:
- opt_username= optarg;
- opt_binary= true;
- break;
-
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- exit(EXIT_SUCCESS);
- }
-}
+++ /dev/null
-#!/bin/sh
-clients/memping -v --servers localhost
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 "mem_config.h"
-
-#include <cerrno>
-#include <cstdio>
-#include <cstring>
-#include <getopt.h>
-#include <iostream>
-#include <unistd.h>
-
-#include <libmemcached-1.0/memcached.h>
-#include "client_options.h"
-#include "utilities.h"
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static time_t opt_expire= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-#define PROGRAM_NAME "memrm"
-#define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
- options_parse(argc, argv);
- initialize_sockets();
-
- if (opt_servers == NULL)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
-
- if (opt_servers == NULL)
- {
- std::cerr << "No Servers provided" << std::endl;
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_server_st* servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- return EXIT_FAILURE;
- }
-
- memcached_st* memc= memcached_create(NULL);
- process_hash_option(memc, opt_hash);
-
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t) opt_binary);
-
- if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- memcached_free(memc);
- std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
- return EXIT_FAILURE;
- }
-
- if (opt_username)
- {
- memcached_return_t ret;
- if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
- {
- std::cerr << memcached_last_error_message(memc) << std::endl;
- memcached_free(memc);
- return EXIT_FAILURE;
- }
- }
-
- int return_code= EXIT_SUCCESS;
-
- while (optind < argc)
- {
- memcached_return_t rc= memcached_delete(memc, argv[optind], strlen(argv[optind]), opt_expire);
-
- if (rc == MEMCACHED_NOTFOUND)
- {
- if (opt_verbose)
- {
- std::cerr << "Could not find key \"" << argv[optind] << "\"" << std::endl;
- }
- }
- else if (memcached_fatal(rc))
- {
- if (opt_verbose)
- {
- std::cerr << "Failed to delete key \"" << argv[optind] << "\" :" << memcached_last_error_message(memc) << std::endl;
- }
-
- return_code= EXIT_FAILURE;
- }
- else // success
- {
- if (opt_verbose)
- {
- std::cout << "Deleted key " << argv[optind];
- if (opt_expire)
- {
- std::cout << " expires: " << opt_expire << std::endl;
- }
- std::cout << std::endl;
- }
- }
-
- optind++;
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- {
- free(opt_servers);
- }
-
- if (opt_hash)
- {
- free(opt_hash);
- }
-
- return return_code;
-}
-
-
-static void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0},
- };
-
- bool opt_version= false;
- bool opt_help= false;
- int option_index= 0;
-
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1)
- {
- break;
- }
-
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_BINARY:
- opt_binary = 1;
- break;
-
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
-
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
-
- case OPT_VERSION: /* --version or -V */
- opt_version= true;
- break;
-
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
-
- case OPT_EXPIRE: /* --expire */
- errno= 0;
- opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
- if (errno != 0)
- {
- std::cerr << "Incorrect value passed to --expire: `" << optarg << "`" << std::endl;
- exit(EXIT_FAILURE);
- }
- break;
-
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
-
- case OPT_USERNAME:
- opt_username= optarg;
- break;
-
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(EXIT_SUCCESS);
-
- default:
- abort();
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- exit(EXIT_SUCCESS);
- }
-}
+++ /dev/null
-#!/bin/sh
-clients/memcp.sh
-clients/memrm -v --servers localhost mem.testdata
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <mem_config.h>
-
-#include <cassert>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <fcntl.h>
-#include <getopt.h>
-#include <memory>
-#include <pthread.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <iostream>
-
-#include <libmemcached-1.0/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 VALUE_BYTES 4096
-
-#define PROGRAM_NAME "memslap"
-#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
-
-/* Global Thread counter */
-volatile unsigned int master_wakeup;
-pthread_mutex_t sleeper_mutex;
-pthread_cond_t sleep_threshhold;
-
-/* Types */
-enum test_t {
- SET_TEST,
- GET_TEST,
- MGET_TEST
-};
-
-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_t test;
- memcached_st *memc;
- const memcached_st* root;
-
- thread_context_st(const memcached_st* memc_arg, test_t test_arg) :
- key_count(0),
- initial_pairs(NULL),
- initial_number(0),
- execute_pairs(NULL),
- execute_number(0),
- keys(0),
- key_lengths(NULL),
- test(test_arg),
- memc(NULL),
- root(memc_arg)
- {
- }
-
- void init()
- {
- memc= memcached_clone(NULL, root);
- }
-
- ~thread_context_st()
- {
- if (execute_pairs)
- {
- pairs_free(execute_pairs);
- }
- memcached_free(memc);
- }
-};
-
-struct conclusions_st {
- long int load_time;
- long int read_time;
- unsigned int rows_loaded;
- unsigned int rows_read;
-
- conclusions_st() :
- load_time(0),
- read_time(0),
- rows_loaded(0),
- rows_read()
- { }
-};
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-void conclusions_print(conclusions_st *conclusion);
-void scheduler(memcached_server_st *servers, conclusions_st *conclusion);
-pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
- unsigned int *actual_loaded);
-void flush_all(memcached_st *memc);
-
-static bool 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 bool opt_udp_io= false;
-test_t opt_test= SET_TEST;
-
-extern "C" {
-
-static __attribute__((noreturn)) void *run_task(void *p)
-{
- thread_context_st *context= (thread_context_st *)p;
-
- context->init();
-
- pthread_mutex_lock(&sleeper_mutex);
- while (master_wakeup)
- {
- pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
- }
- pthread_mutex_unlock(&sleeper_mutex);
-
- /* Do Stuff */
- switch (context->test)
- {
- case SET_TEST:
- assert(context->execute_pairs);
- execute_set(context->memc, context->execute_pairs, context->execute_number);
- break;
-
- case GET_TEST:
- execute_get(context->memc, context->initial_pairs, context->initial_number);
- break;
-
- case MGET_TEST:
- execute_mget(context->memc, (const char*const*)context->keys, context->key_lengths, context->initial_number);
- break;
- }
-
- delete context;
-
- pthread_exit(0);
-}
-
-}
-
-
-int main(int argc, char *argv[])
-{
- conclusions_st conclusion;
-
- srandom((unsigned int)time(NULL));
- options_parse(argc, argv);
-
- if (opt_servers == NULL)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
-
- if (opt_servers == NULL)
- {
- std::cerr << "No Servers provided" << std::endl;
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_server_st *servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- return EXIT_FAILURE;
- }
-
- pthread_mutex_init(&sleeper_mutex, NULL);
- pthread_cond_init(&sleep_threshhold, NULL);
-
- int error_code= EXIT_SUCCESS;
- try {
- scheduler(servers, &conclusion);
- }
- catch(std::exception& e)
- {
- std::cerr << "Died with exception: " << e.what() << std::endl;
- error_code= EXIT_FAILURE;
- }
-
- free(opt_servers);
-
- (void)pthread_mutex_destroy(&sleeper_mutex);
- (void)pthread_cond_destroy(&sleep_threshhold);
- conclusions_print(&conclusion);
- memcached_server_list_free(servers);
-
- return error_code;
-}
-
-void scheduler(memcached_server_st *servers, conclusions_st *conclusion)
-{
- unsigned int actual_loaded= 0; /* Fix warning */
-
- struct timeval start_time, end_time;
- pairs_st *pairs= NULL;
-
- memcached_st *memc= memcached_create(NULL);
-
- memcached_server_push(memc, servers);
-
- /* We need to set udp behavior before adding servers to the client */
- if (opt_udp_io)
- {
- if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, opt_udp_io)))
- {
- std::cerr << "Failed to enable UDP." << std::endl;
- memcached_free(memc);
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t)opt_binary);
-
- if (opt_flush)
- {
- flush_all(memc);
- }
-
- if (opt_createial_load)
- {
- pairs= load_create_data(memc, opt_createial_load, &actual_loaded);
- }
-
- char **keys= static_cast<char **>(calloc(actual_loaded, sizeof(char*)));
- size_t *key_lengths= static_cast<size_t *>(calloc(actual_loaded, sizeof(size_t)));
-
- if (keys == NULL or key_lengths == NULL)
- {
- free(keys);
- free(key_lengths);
- keys= NULL;
- key_lengths= NULL;
- }
- else
- {
- for (uint32_t x= 0; x < actual_loaded; ++x)
- {
- keys[x]= pairs[x].key;
- key_lengths[x]= pairs[x].key_length;
- }
- }
-
- /* We set this after we have loaded */
- {
- if (opt_non_blocking_io)
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
-
- if (opt_tcp_nodelay)
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
- }
-
- pthread_mutex_lock(&sleeper_mutex);
- master_wakeup= 1;
- pthread_mutex_unlock(&sleeper_mutex);
-
- pthread_t *threads= new (std::nothrow) pthread_t[opt_concurrency];
-
- if (threads == NULL)
- {
- exit(EXIT_FAILURE);
- }
-
- for (uint32_t x= 0; x < opt_concurrency; x++)
- {
- thread_context_st *context= new thread_context_st(memc, opt_test);
- context->test= opt_test;
-
- context->initial_pairs= pairs;
- context->initial_number= actual_loaded;
- context->keys= keys;
- context->key_lengths= key_lengths;
-
- if (opt_test == SET_TEST)
- {
- context->execute_pairs= pairs_generate(opt_execute_number, VALUE_BYTES);
- context->execute_number= opt_execute_number;
- }
-
- /* now you create the thread */
- if (pthread_create(threads +x, NULL, run_task, (void *)context) != 0)
- {
- fprintf(stderr,"Could not create thread\n");
- exit(1);
- }
- }
-
- pthread_mutex_lock(&sleeper_mutex);
- master_wakeup= 0;
- pthread_mutex_unlock(&sleeper_mutex);
- pthread_cond_broadcast(&sleep_threshhold);
- gettimeofday(&start_time, NULL);
-
- for (uint32_t x= 0; x < opt_concurrency; x++)
- {
- void *retval;
- pthread_join(threads[x], &retval);
- }
- delete [] threads;
-
- gettimeofday(&end_time, NULL);
-
- conclusion->load_time= timedif(end_time, start_time);
- conclusion->read_time= timedif(end_time, start_time);
- free(keys);
- free(key_lengths);
- pairs_free(pairs);
- memcached_free(memc);
-}
-
-void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(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},
- };
-
- bool opt_help= false;
- bool opt_version= false;
- int option_index= 0;
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-
- if (option_rv == -1) break;
-
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_UDP:
- if (opt_test == GET_TEST)
- {
- fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
- "does not currently support get ops.\n");
- exit(1);
- }
- opt_udp_io= true;
- break;
-
- case OPT_BINARY:
- opt_binary= true;
- break;
-
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose= OPT_VERBOSE;
- break;
-
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose= OPT_DEBUG;
- break;
-
- case OPT_VERSION: /* --version or -V */
- opt_version= true;
- break;
-
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
-
- case OPT_SLAP_TEST:
- if (strcmp(optarg, "get") == 0)
- {
- 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(EXIT_FAILURE);
- }
- opt_test= GET_TEST ;
- }
- else if (strcmp(optarg, "set") == 0)
- {
- opt_test= SET_TEST;
- }
- else if (strcmp(optarg, "mget") == 0)
- {
- opt_test= MGET_TEST;
- }
- else
- {
- fprintf(stderr, "Your test, %s, is not a known test\n", optarg);
- exit(EXIT_FAILURE);
- }
- break;
-
- case OPT_SLAP_CONCURRENCY:
- errno= 0;
- opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10);
- if (errno != 0)
- {
- fprintf(stderr, "Invalid value for concurrency: %s\n", optarg);
- exit(EXIT_FAILURE);
- }
- break;
-
- case OPT_SLAP_EXECUTE_NUMBER:
- errno= 0;
- opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10);
- if (errno != 0)
- {
- fprintf(stderr, "Invalid value for execute: %s\n", optarg);
- exit(EXIT_FAILURE);
- }
- break;
-
- case OPT_SLAP_INITIAL_LOAD:
- errno= 0;
- opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10);
- if (errno != 0)
- {
- fprintf(stderr, "Invalid value for initial load: %s\n", optarg);
- exit(EXIT_FAILURE);
- }
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(EXIT_FAILURE);
-
- default:
- abort();
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- exit(EXIT_SUCCESS);
- }
-
- if ((opt_test == GET_TEST or opt_test == MGET_TEST) and opt_createial_load == 0)
- opt_createial_load= DEFAULT_INITIAL_LOAD;
-
- if (opt_execute_number == 0)
- opt_execute_number= DEFAULT_EXECUTE_NUMBER;
-
- if (opt_concurrency == 0)
- opt_concurrency= DEFAULT_CONCURRENCY;
-}
-
-void conclusions_print(conclusions_st *conclusion)
-{
- printf("\tThreads connecting to servers %u\n", opt_concurrency);
-#ifdef NOT_FINISHED
- printf("\tLoaded %u rows\n", conclusion->rows_loaded);
- printf("\tRead %u rows\n", conclusion->rows_read);
-#endif
- if (opt_test == SET_TEST)
- printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000,
- conclusion->load_time % 1000);
- else
- printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000,
- conclusion->read_time % 1000);
-}
-
-void flush_all(memcached_st *memc)
-{
- memcached_flush(memc, 0);
-}
-
-pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
- unsigned int *actual_loaded)
-{
- memcached_st *memc_clone= memcached_clone(NULL, memc);
- /* We always used non-blocking IO for load since it is faster */
- memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
-
- pairs_st *pairs= pairs_generate(number_of, VALUE_BYTES);
- *actual_loaded= execute_set(memc_clone, pairs, number_of);
-
- memcached_free(memc_clone);
-
- return pairs;
-}
+++ /dev/null
-#!/bin/sh
-clients/memslap -v --servers localhost
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 <mem_config.h>
-
-#include <cstdio>
-#include <cstring>
-#include <ctime>
-#include <iostream>
-#include <fcntl.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/types.h>
-
-#include <libmemcached-1.0/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-
-#define PROGRAM_NAME "memstat"
-#define PROGRAM_DESCRIPTION "Output the state of a memcached cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat);
-static void print_analysis_report(memcached_st *memc,
- memcached_analysis_st *report);
-
-static bool opt_binary= false;
-static bool opt_verbose= false;
-static bool opt_server_version= false;
-static bool opt_analyze= false;
-static char *opt_servers= NULL;
-static char *stat_args= NULL;
-static char *analyze_mode= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-static struct option long_options[]=
-{
- {(OPTIONSTRING)"args", required_argument, NULL, OPT_STAT_ARGS},
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(OPTIONSTRING)"verbose", no_argument, NULL, OPT_VERBOSE},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"debug", no_argument, NULL, OPT_DEBUG},
- {(OPTIONSTRING)"server-version", no_argument, NULL, OPT_SERVER_VERSION},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0},
-};
-
-
-static memcached_return_t stat_printer(const memcached_instance_st * instance,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- void *context)
-{
- static const memcached_instance_st * last= NULL;
- (void)context;
-
- if (last != instance)
- {
- printf("Server: %s (%u)\n", memcached_server_name(instance),
- (uint32_t)memcached_server_port(instance));
- last= instance;
- }
-
- printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value);
-
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t server_print_callback(const memcached_st *,
- const memcached_instance_st * instance,
- void *)
-{
- std::cerr << memcached_server_name(instance) << ":" << memcached_server_port(instance) <<
- " " << int(memcached_server_major_version(instance)) <<
- "." << int(memcached_server_minor_version(instance)) <<
- "." << int(memcached_server_micro_version(instance)) << std::endl;
-
- return MEMCACHED_SUCCESS;
-}
-
-int main(int argc, char *argv[])
-{
- options_parse(argc, argv);
- initialize_sockets();
-
- if (opt_servers == NULL)
- {
- char *temp;
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
-
- if (opt_servers == NULL)
- {
- std::cerr << "No Servers provided" << std::endl;
- return EXIT_FAILURE;
- }
- }
-
- memcached_server_st* servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- return EXIT_FAILURE;
- }
-
- if (opt_servers)
- {
- free(opt_servers);
- }
-
- memcached_st *memc= memcached_create(NULL);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, opt_binary);
-
- memcached_return_t rc= memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
-
- if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- memcached_free(memc);
- std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
- return EXIT_FAILURE;
- }
-
- if (opt_username)
- {
- memcached_return_t ret;
- if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
- {
- std::cerr << memcached_last_error_message(memc) << std::endl;
- memcached_free(memc);
- return EXIT_FAILURE;
- }
- }
-
- if (rc != MEMCACHED_SUCCESS and rc != MEMCACHED_SOME_ERRORS)
- {
- printf("Failure to communicate with servers (%s)\n",
- memcached_strerror(memc, rc));
- exit(EXIT_FAILURE);
- }
-
- if (opt_server_version)
- {
- if (memcached_failed(memcached_version(memc)))
- {
- std::cerr << "Unable to obtain server version";
- exit(EXIT_FAILURE);
- }
-
- memcached_server_fn callbacks[1];
- callbacks[0]= server_print_callback;
- memcached_server_cursor(memc, callbacks, NULL, 1);
- }
- else if (opt_analyze)
- {
- memcached_stat_st *memc_stat= memcached_stat(memc, NULL, &rc);
-
- if (memc_stat == NULL)
- {
- exit(EXIT_FAILURE);
- }
-
- run_analyzer(memc, memc_stat);
-
- memcached_stat_free(memc, memc_stat);
- }
- else
- {
- rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL);
- }
-
- memcached_free(memc);
-
- return rc == MEMCACHED_SUCCESS ? EXIT_SUCCESS: EXIT_FAILURE;
-}
-
-static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat)
-{
- memcached_return_t rc;
-
- if (analyze_mode == NULL)
- {
- memcached_analysis_st *report;
- report= memcached_analyze(memc, memc_stat, &rc);
- if (rc != MEMCACHED_SUCCESS || report == NULL)
- {
- printf("Failure to analyze servers (%s)\n",
- memcached_strerror(memc, rc));
- exit(1);
- }
- print_analysis_report(memc, report);
- free(report);
- }
- else if (strcmp(analyze_mode, "latency") == 0)
- {
- uint32_t flags, server_count= memcached_server_count(memc);
- uint32_t num_of_tests= 32;
- const char *test_key= "libmemcached_test_key";
-
- memcached_st **servers= static_cast<memcached_st**>(malloc(sizeof(memcached_st*) * server_count));
- if (servers == NULL)
- {
- fprintf(stderr, "Failed to allocate memory\n");
- return;
- }
-
- for (uint32_t x= 0; x < server_count; x++)
- {
- const memcached_instance_st * instance=
- memcached_server_instance_by_position(memc, x);
-
- if ((servers[x]= memcached_create(NULL)) == NULL)
- {
- fprintf(stderr, "Failed to memcached_create()\n");
- if (x > 0)
- {
- memcached_free(servers[0]);
- }
- x--;
-
- for (; x > 0; x--)
- {
- memcached_free(servers[x]);
- }
-
- free(servers);
-
- return;
- }
- memcached_server_add(servers[x],
- memcached_server_name(instance),
- memcached_server_port(instance));
- }
-
- printf("Network Latency Test:\n\n");
- struct timeval start_time, end_time;
- uint32_t slowest_server= 0;
- long elapsed_time, slowest_time= 0;
-
- for (uint32_t x= 0; x < server_count; x++)
- {
- const memcached_instance_st * instance=
- memcached_server_instance_by_position(memc, x);
- gettimeofday(&start_time, NULL);
-
- for (uint32_t y= 0; y < num_of_tests; y++)
- {
- size_t vlen;
- char *val= memcached_get(servers[x], test_key, strlen(test_key),
- &vlen, &flags, &rc);
- if (rc != MEMCACHED_NOTFOUND and rc != MEMCACHED_SUCCESS)
- {
- break;
- }
- free(val);
- }
- gettimeofday(&end_time, NULL);
-
- elapsed_time= (long) timedif(end_time, start_time);
- elapsed_time /= (long) num_of_tests;
-
- if (elapsed_time > slowest_time)
- {
- slowest_server= x;
- slowest_time= elapsed_time;
- }
-
- if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
- {
- printf("\t %s (%d) => failed to reach the server\n",
- memcached_server_name(instance),
- memcached_server_port(instance));
- }
- else
- {
- printf("\t %s (%d) => %ld.%ld seconds\n",
- memcached_server_name(instance),
- memcached_server_port(instance),
- elapsed_time / 1000, elapsed_time % 1000);
- }
- }
-
- if (server_count > 1 && slowest_time > 0)
- {
- const memcached_instance_st * slowest=
- memcached_server_instance_by_position(memc, slowest_server);
-
- printf("---\n");
- printf("Slowest Server: %s (%d) => %ld.%ld seconds\n",
- memcached_server_name(slowest),
- memcached_server_port(slowest),
- slowest_time / 1000, slowest_time % 1000);
- }
- printf("\n");
-
- for (uint32_t x= 0; x < server_count; x++)
- {
- memcached_free(servers[x]);
- }
-
- free(servers);
- free(analyze_mode);
- }
- else
- {
- fprintf(stderr, "Invalid Analyzer Option provided\n");
- free(analyze_mode);
- }
-}
-
-static void print_analysis_report(memcached_st *memc,
- memcached_analysis_st *report)
-
-{
- uint32_t server_count= memcached_server_count(memc);
- const memcached_instance_st * most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server);
- const memcached_instance_st * least_free_server= memcached_server_instance_by_position(memc, report->least_free_server);
- const memcached_instance_st * oldest_server= memcached_server_instance_by_position(memc, report->oldest_server);
-
- printf("Memcached Cluster Analysis Report\n\n");
-
- printf("\tNumber of Servers Analyzed : %u\n", server_count);
- printf("\tAverage Item Size (incl/overhead) : %u bytes\n",
- report->average_item_size);
-
- if (server_count == 1)
- {
- printf("\nFor a detailed report, you must supply multiple servers.\n");
- return;
- }
-
- printf("\n");
- printf("\tNode with most memory consumption : %s:%u (%llu bytes)\n",
- memcached_server_name(most_consumed_server),
- (uint32_t)memcached_server_port(most_consumed_server),
- (unsigned long long)report->most_used_bytes);
- printf("\tNode with least free space : %s:%u (%llu bytes remaining)\n",
- memcached_server_name(least_free_server),
- (uint32_t)memcached_server_port(least_free_server),
- (unsigned long long)report->least_remaining_bytes);
- printf("\tNode with longest uptime : %s:%u (%us)\n",
- memcached_server_name(oldest_server),
- (uint32_t)memcached_server_port(oldest_server),
- report->longest_uptime);
- printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio);
- printf("\n");
-}
-
-static void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- int option_index= 0;
-
- bool opt_version= false;
- bool opt_help= false;
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index);
-
- if (option_rv == -1)
- break;
-
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose= true;
- break;
-
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose= true;
- break;
-
- case OPT_BINARY:
- opt_binary= true;
- break;
-
- case OPT_SERVER_VERSION:
- opt_server_version= true;
- break;
-
- case OPT_VERSION: /* --version or -V */
- opt_version= true;
- break;
-
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
-
- case OPT_STAT_ARGS:
- stat_args= strdup(optarg);
- break;
-
- case OPT_ANALYZE: /* --analyze or -a */
- opt_analyze= true;
- analyze_mode= (optarg) ? strdup(optarg) : NULL;
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
- case OPT_USERNAME:
- opt_username= optarg;
- opt_binary= true;
- break;
-
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- exit(EXIT_SUCCESS);
- }
-}
+++ /dev/null
-#!/bin/bash
-clients/memstat -v --servers localhost
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 <mem_config.h>
-
-#include <cerrno>
-#include <cstdio>
-#include <cstring>
-#include <getopt.h>
-#include <iostream>
-#include <unistd.h>
-
-#include <libmemcached-1.0/memcached.h>
-
-#include "utilities.h"
-
-#define PROGRAM_NAME "memtouch"
-#define PROGRAM_DESCRIPTION "Update the expiration value of an already existing value in the server"
-
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-time_t expiration= 0;
-
-int main(int argc, char *argv[])
-{
- int return_code= EXIT_SUCCESS;
-
- options_parse(argc, argv);
- initialize_sockets();
-
- if (opt_servers == NULL)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
-
- if (opt_servers == NULL)
- {
- std::cerr << "No Servers provided" << std::endl;
- exit(EXIT_FAILURE);
- }
- }
-
- memcached_server_st* servers= memcached_servers_parse(opt_servers);
- if (servers == NULL or memcached_server_list_count(servers) == 0)
- {
- std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
- return EXIT_FAILURE;
- }
-
- memcached_st *memc= memcached_create(NULL);
- process_hash_option(memc, opt_hash);
-
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t)opt_binary);
-
- if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- memcached_free(memc);
- std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
- return EXIT_FAILURE;
- }
-
- if (opt_username)
- {
- memcached_return_t ret;
- if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
- {
- std::cerr << memcached_last_error_message(memc) << std::endl;
- memcached_free(memc);
- return EXIT_FAILURE;
- }
- }
-
- while (optind < argc)
- {
- memcached_return_t rc= memcached_touch(memc, argv[optind], strlen(argv[optind]), expiration);
- if (rc == MEMCACHED_NOTFOUND)
- {
- if (opt_verbose)
- {
- std::cout << "Could not find key \"" << argv[optind] << "\"" << std::endl;
- }
-
- return_code= EXIT_FAILURE;
- }
- else if (memcached_failed(rc))
- {
- if (opt_verbose)
- {
- std::cerr << "Fatal error for key \"" << argv[optind] << "\" :" << memcached_last_error_message(memc) << std::endl;
- }
-
- return_code= EXIT_FAILURE;
- }
- else // success
- {
- if (opt_verbose)
- {
- std::cout << "Found key " << argv[optind] << std::endl;
- }
- }
-
- optind++;
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- {
- free(opt_servers);
- }
-
- if (opt_hash)
- {
- free(opt_hash);
- }
-
- return return_code;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
- {0, 0, 0, 0},
- };
-
- bool opt_version= false;
- bool opt_help= false;
- int option_index= 0;
-
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1)
- {
- break;
- }
-
- switch (option_rv)
- {
- case 0:
- break;
-
- case OPT_BINARY:
- opt_binary = true;
- break;
-
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
-
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
-
- case OPT_VERSION: /* --version or -V */
- opt_version= true;
- break;
-
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
-
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
-
- case OPT_USERNAME:
- opt_username= optarg;
- break;
-
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
-
- case OPT_EXPIRE:
- errno= 0;
- expiration= time_t(strtoul(optarg, (char **)NULL, 10));
- if (errno != 0)
- {
- fprintf(stderr, "Invalid value for --expire: %s\n", optarg);
- exit(EXIT_FAILURE);
- }
- break;
-
- case OPT_QUIET:
- close_stdio();
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(EXIT_FAILURE);
-
- default:
- abort();
- }
- }
-
- if (opt_version)
- {
- version_command(PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- exit(EXIT_SUCCESS);
- }
-}
+++ /dev/null
-#!/bin/sh
-clients/memcp.sh
-clients/memtouch -v --servers localhost mem.testdata
+++ /dev/null
-/* 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 HAVE_C_STDATOMIC
-# define ATOMIC _Atomic
-#else
-# define ATOMIC volatile
-#endif
-
-#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
-#elif HAVE_GCC_ATOMIC_BUILTINS
-# 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)
-#elif HAVE_C_STDATOMIC
-# include <stdatomic.h>
-# define atomic_add_8(X, Y) atomic_fetch_add(X, Y)
-# define atomic_add_16(X, Y) atomic_fetch_add(X, Y)
-# define atomic_add_32(X, Y) atomic_fetch_add(X, Y)
-# define atomic_add_size(X, Y) atomic_fetch_add(X, Y)
-# define atomic_dec_8(X) atomic_fetch_sub(X, 1)
-# define atomic_dec_16(X) atomic_fetch_sub(X, 1)
-# define atomic_dec_32(X) atomic_fetch_sub(X, 1)
-# define atomic_dec_size(X) atomic_fetch_sub(X, 1)
-/* The same as above, but these return the new value instead of void */
-# define ATOMIC_ADD_FETCH_DECL(T) \
-static inline T atomic_add_fetch_##T(ATOMIC T *ptr, T add) { \
- T des, cur = atomic_load(ptr); \
- do { \
- des = cur + add; \
- } while(!atomic_compare_exchange_weak(ptr, &cur, des)); \
- return des; \
-}
-# define ATOMIC_SUB_FETCH_DECL(T) \
-T atomic_sub_fetch_##T(ATOMIC T *ptr) { \
- T des, cur = atomic_load(ptr); \
- do { \
- des = cur - 1; \
- } while(!atomic_compare_exchange_weak(ptr, &cur, des)); \
- return des; \
-}
-ATOMIC_ADD_FETCH_DECL(uint8_t)
-# define atomic_add_8_nv(X, Y) atomic_add_fetch_uint8_t(X, Y)
-ATOMIC_ADD_FETCH_DECL(uint16_t)
-# define atomic_add_16_nv(X, Y) atomic_add_fetch_uint16_t(X, Y)
-ATOMIC_ADD_FETCH_DECL(uint32_t)
-# define atomic_add_32_nv(X, Y) atomic_add_fetch_uint32_t(X, Y)
-ATOMIC_ADD_FETCH_DECL(size_t)
-# define atomic_add_size_nv(X, Y) atomic_add_fetch_size_t(X, Y)
-# define atomic_dec_8_nv(X) atomic_sub_fetch<uint8_t>(X, Y)
-# define atomic_dec_16_nv(X) atomic_sub_fetch<uint16_t>(X, Y)
-# define atomic_dec_32_nv(X) atomic_sub_fetch<uint32_t>(X, Y)
-# define atomic_dec_size_nv(X) atomic_sub_fetch<size_t>(X, Y)
-#else
-#warning "Atomic operators not found so memslap will not work correctly"
-# define atomic_add_8(X, Y) 0
-# define atomic_add_16(X, Y) 0
-# define atomic_add_32(X, Y) 0
-# define atomic_add_size(X, Y) 0
-# define atomic_dec_8(X) 0
-# define atomic_dec_16(X) 0
-# define atomic_dec_32(X) 0
-# define atomic_dec_size(X) 0
-/* The same as above, but these return the new value instead of void */
-# define atomic_add_8_nv(X, Y) 0
-# define atomic_add_16_nv(X, Y) 0
-# define atomic_add_32_nv(X, Y) 0
-# define atomic_add_size_nv(X, Y) 0
-# define atomic_dec_8_nv(X) 0
-# define atomic_dec_16_nv(X) 0
-# define atomic_dec_32_nv(X) 0
-# define atomic_dec_size_nv(X) 0
-#endif /* defined(__SUNPRO_C) */
-
-#endif /* CLIENTS_MS_ATOMIC_H */
+++ /dev/null
-/*
- * File: ms_conn.c
- * Author: Mingqiang Zhuang
- *
- * Created on February 10, 2009
- *
- * (c) Copyright 2009, Schooner Information Technology, Inc.
- * http://www.schoonerinfotech.com/
- *
- */
-
-#include "mem_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 <netinet/in.h>
-
-#if defined(HAVE_ARPA_INET_H)
-# include <arpa/inet.h>
-#endif
-
-#if defined(HAVE_SYS_TIME_H)
-# include <sys/time.h>
-#endif
-
-#if defined(HAVE_TIME_H)
-# include <time.h>
-#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 ATOMIC 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 uint32_t ms_get_rep_sock_index(ms_conn_t *c, int cmd);
-static uint32_t 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 * ms_setting.sock_per_conn;
- }
- 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
- {
- 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, else return -1
- */
-static int ms_conn_sock_init(ms_conn_t *c)
-{
- ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
- uint32_t i;
- int ret_sfd;
- uint32_t 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 % ms_setting.srv_cnt;
- }
- 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 (uint32_t j= 0; j < i; j++)
- {
- close(c->tcpsfd[j]);
- }
- }
-
- if (c->udpsfd != 0)
- {
- close(c->udpsfd);
- }
-
- return -1;
- }
-
- return EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, else return -1
- */
-static int ms_conn_event_init(ms_conn_t *c)
-{
- ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
- 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 (event_add(&c->event, NULL) == -1)
- {
- return -1;
- }
-
- return EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 (uint32_t 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 EXIT_SUCCESS, 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;
- }
- }
- (void)last_good;
-} /* 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 EXIT_SUCCESS, 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));
-#ifdef AI_ADDRCONFIG
- hints.ai_flags= AI_PASSIVE | AI_ADDRCONFIG;
-#else
- hints.ai_flags= AI_PASSIVE;
-#endif /* 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 EXIT_SUCCESS, else return -1
- */
-static int ms_reconn(ms_conn_t *c)
-{
- ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
- uint32_t srv_idx= 0;
- uint32_t srv_conn_cnt= 0;
-
- if (ms_setting.rep_write_srv > 0)
- {
- srv_idx= c->cur_idx % ms_setting.srv_cnt;
- srv_conn_cnt= ms_setting.sock_per_conn * ms_setting.nconns;
- }
- else
- {
- srv_idx= ms_thread->thread_ctx->srv_idx;
- srv_conn_cnt= 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)
- % 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)
- {
- uint32_t 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 (ms_setting.rep_write_srv == 0 && c->total_sfds > 0)
- {
- /* wait a second and reconnect */
- sleep(1);
- }
- }
- while (ms_setting.rep_write_srv == 0 && c->total_sfds > 0);
- }
-
- if ((c->total_sfds > 1) && (c->tcpsfd[c->cur_idx] == 0))
- {
- c->sfd= 0;
- c->alive_sfds--;
- }
-
- return EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, else return -1
- */
-int ms_reconn_socks(ms_conn_t *c)
-{
- ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
- uint32_t srv_idx= 0;
- int ret_sfd= 0;
- uint32_t srv_conn_cnt= 0;
- struct timeval cur_time;
-
- assert(c != NULL);
-
- if ((c->total_sfds == 1) || (c->total_sfds == c->alive_sfds))
- {
- return EXIT_SUCCESS;
- }
-
- for (uint32_t 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 % ms_setting.srv_cnt;
- srv_conn_cnt= ms_setting.sock_per_conn * ms_setting.nconns;
- }
- else
- {
- srv_idx= ms_thread->thread_ctx->srv_idx;
- srv_conn_cnt= 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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);
- errno= 0;
- value_len= strtol(tokens[VALUELEN_TOKEN].value, NULL, 10);
- if (errno != 0)
- {
- printf("<%d ERROR %s\n", c->sfd, strerror(errno));
- }
- 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;
- break;
-
- 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;
- c->msgcurr = 0;
- c->msgused = 0;
- c->iovused = 0;
- 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
- }
- 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 EXIT_SUCCESS;
- }
-
- /* 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 EXIT_SUCCESS;
-
- el= memchr(c->rcurr, '\n', (size_t)c->rbytes);
- if (! el)
- return EXIT_SUCCESS;
-
- 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;
- }
- }
- (void)packets;
-
- 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 EXIT_SUCCESS 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 EXIT_SUCCESS if there's nothing to read on the first read.
- * return EXIT_FAILURE 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_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_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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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;
-
-#ifdef IOV_MAX
- /* 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];
- }
-#endif
-
- 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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)
-{
- 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 (event_add(&c->event, NULL) == -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);
-
- 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 EXIT_SUCCESS
- */
-static uint32_t ms_get_rep_sock_index(ms_conn_t *c, int cmd)
-{
- uint32_t sock_index= 0;
- uint32_t i= 0;
-
- if (c->total_sfds == 1)
- {
- return EXIT_SUCCESS;
- }
-
- 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= (uint32_t)random() % c->total_sfds;
- }
- else
- {
- /* random get one replication writing server to write */
- sock_index= (uint32_t)random() % ms_setting.rep_write_srv;
- }
- }
- else if (cmd == CMD_GET)
- {
- /* random get one replication server to read */
- sock_index= (uint32_t)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 uint32_t ms_get_next_sock_index(ms_conn_t *c)
-{
- uint32_t 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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= snprintf(buffer,
- c->wsize,
- " %u %d %d\r\n",
- 0,
- item->exp_time,
- item->value_size);
-
- if (write_len > c->wsize || write_len < 0)
- {
- /* 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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
- *
- * @return int, if success, return EXIT_SUCCESS, else return -1
- */
-int ms_mcd_get(ms_conn_t *c, ms_task_item_t *item)
-{
- 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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);
- }
-
- (void)item;
-
- return EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_FAILURE;
- }
- 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 EXIT_SUCCESS;
-} /* 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.vbucket= 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* ms_build_bin_write_buf_mlget */
+++ /dev/null
-/*
- * 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 <libmemcachedprotocol-0.0/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 30 /* maximum waiting time of UDP, 30s */
-#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 */
- 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
-{
- uint32_t 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 */
- uint32_t total_sfds; /* how many socks in the tcpsfd array */
- uint32_t alive_sfds; /* alive socks */
- uint32_t 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 */
- bool 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);
-
-
-/* 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 */
+++ /dev/null
-/*
- * 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"
-#include "ms_atomic.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
-{
- ATOMIC uint32_t active_conns; /* active connections */
- ATOMIC size_t bytes_read; /* read bytes */
- ATOMIC size_t bytes_written; /* written bytes */
- ATOMIC size_t obj_bytes; /* object bytes */
- ATOMIC size_t pre_cmd_get; /* previous total get command count */
- ATOMIC size_t pre_cmd_set; /* previous total set command count */
- ATOMIC size_t cmd_get; /* current total get command count */
- ATOMIC size_t cmd_set; /* current total set command count */
- ATOMIC size_t get_misses; /* total objects of get miss */
- ATOMIC size_t vef_miss; /* total objects of verification miss */
- ATOMIC size_t vef_failed; /* total objects of verification failed */
- ATOMIC size_t unexp_unget; /* total objects which is unexpired but not get */
- ATOMIC size_t exp_get; /* total objects which is expired but get */
- ATOMIC size_t pkt_disorder; /* disorder packages of UDP */
- ATOMIC size_t pkt_drop; /* packages dropped of UDP */
- ATOMIC size_t udp_timeout; /* how many times timeout of UDP happens */
-} ms_stats_t;
-
-/* lock adapter */
-typedef struct sync_lock
-{
- uint32_t 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 warmup_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 */
+++ /dev/null
-/*
- * File: ms_setting.c
- * Author: Mingqiang Zhuang
- *
- * Created on February 10, 2009
- *
- * (c) Copyright 2009, Schooner Information Technology, Inc.
- * http://www.schoonerinfotech.com/
- *
- */
-
-#include "mem_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 <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 uint32_t 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 EXIT_FAILURE
- */
-static uint32_t 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 EXIT_FAILURE;
-} /* 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 EXIT_FAILURE, else return EXIT_SUCCESS
- */
-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 EXIT_SUCCESS;
-
- return EXIT_FAILURE;
-} /* 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 EXIT_SUCCESS, else return EXIT_FAILURE
- */
-static int ms_read_is_data(char *line, ssize_t nread)
-{
- if ((nread == EOF) || ! ms_is_line_data(line))
- return EXIT_SUCCESS;
-
- return EXIT_FAILURE;
-} /* 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;
- 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", &start_len, &end_len,
- &proportion) != 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", &cmd_type, &proportion) != 2)
- {
- conf_type= ms_get_conf_type(line);
- break;
- }
- if (cmd_type >= CMD_NULL)
- {
- continue;
- }
- 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 EXIT_SUCCESS
- */
-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 EXIT_SUCCESS;
-} /* 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.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.facebook_test && (ms_setting.rep_write_srv > 0))
- {
- fprintf(stderr, "facebook test couldn't work with replication.\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 */
+++ /dev/null
-/*
- * 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_server
-{
- char srv_host_name[MCD_HOST_LENGTH]; /* host name of server */
- int srv_port; /* server port */
-
- /* for calculating how long the server disconnects */
- ATOMIC uint32_t disconn_cnt; /* number of disconnections count */
- ATOMIC 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
-{
- uint32_t ncpu; /* cpu count of this system */
- uint32_t 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 */
- uint32_t total_srv_cnt; /* total servers count of the servers array */
- uint32_t 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 */
- uint32_t sock_per_conn; /* number of socks per connection structure */
- bool binary_prot_; /* whether it use binary protocol */
- int expected_tps; /* expected throughput */
- uint32_t 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 */
+++ /dev/null
-/*
- * 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 "mem_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");
-#if 0
- pandora_print_callstack(stderr);
-#endif
- fprintf(stderr, "End of stack trace\n");
- pthread_mutex_unlock(&ms_global.quit_mutex);
- abort();
-}
-
-/* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
- }
-
- return -1;
-} /* ms_setup_sigsegv */
-
-
-/**
- * redirect signal pipe
- *
- * @return if success, return EXIT_SUCCESS, else return -1
- */
-int ms_setup_sigpipe(void)
-{
- /* ignore the SIGPIPE signal */
- signal(SIGPIPE, SIG_IGN);
-
- return -1;
-} /* ms_setup_sigpipe */
-
-
-/**
- * redirect signal int
- *
- * @return if success, return EXIT_SUCCESS, 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 EXIT_SUCCESS;
- }
-
- 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
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * File: ms_stats.h
- * Author: Mingqiang Zhuang
- *
- * Created on March 25, 2009
- *
- * (c) Copyright 2009, Schooner Information Technology, Inc.
- * http://www.schoonerinfotech.com/
- *
- */
-
-#include "mem_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;
-
- 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);
-
- uint64_t diff_time= stat->total_time - stat->pre_total_time;
- uint64_t 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;
- double 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));
- double 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 */
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * File: ms_task.c
- * Author: Mingqiang Zhuang
- *
- * Created on February 10, 2009
- *
- * (c) Copyright 2009, Schooner Information Technology, Inc.
- * http://www.schoonerinfotech.com/
- *
- */
-
-#include "mem_config.h"
-
-#if defined(HAVE_SYS_TIME_H)
-# include <sys/time.h>
-#endif
-
-#if defined(HAVE_TIME_H)
-# include <time.h>
-#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_random_overwrite_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_overwrite_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_random_overwrite_item(ms_conn_t *c)
-{
- return ms_get_next_get_item(c);
-} /* ms_get_random_overwrite_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_overwrite_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_overwrite_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_overwrite_item(task))
- {
- /**
- * overwrite not use the item with current set cursor, revert
- * set cursor.
- */
- c->set_cursor--;
-
- item= ms_get_random_overwrite_item(c);
- if (item->value_offset != INVALID_OFFSET)
- {
- task->item= item;
- task->overwrite_set++;
- }
- else /* item is a new item */
- {
- /* select the 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.warmup_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);
- }
- }
-} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* ms_run_getset_task */
-
-
-/**
- * the state machine call the function to execute task.
- *
- * @param c, pointer of the concurrency
- *
- * @return int, if success, return EXIT_SUCCESS, 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 EXIT_SUCCESS;
-} /* ms_exec_task */
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * File: ms_thread.c
- * Author: Mingqiang Zhuang
- *
- * Created on February 10, 2009
- *
- * (c) Copyright 2009, Schooner Information Technology, Inc.
- * http://www.schoonerinfotech.com/
- *
- */
-
-#include "mem_config.h"
-
-#if defined(HAVE_SYS_TIME_H)
-# include <sys/time.h>
-#endif
-
-#if defined(HAVE_TIME_H)
-# include <time.h>
-#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 uint32_t ms_set_thread_cpu_affinity(uint32_t 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 (uint32_t 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 (uint32_t 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 EXIT_SUCCESS, else return -1
- */
-static uint32_t ms_set_thread_cpu_affinity(uint32_t cpu)
-{
- uint32_t 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 EXIT_SUCCESS, 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 ATOMIC 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 (uint32_t 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 EXIT_SUCCESS;
-} /* 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= NULL;
- 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);
-
- pthread_mutex_lock(&ms_global.init_lock.lock);
- ms_global.init_lock.count++;
- pthread_cond_signal(&ms_global.init_lock.cond);
- pthread_mutex_unlock(&ms_global.init_lock.lock);
-
- ms_thread= pthread_getspecific(ms_thread_key);
- 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 (uint32_t i= 0; i < ms_setting.nthreads; i++)
- {
- ms_thread_ctx[i].thd_idx= i;
- ms_thread_ctx[i].nconns= 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 (uint32_t 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 */
+++ /dev/null
-/*
- * 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
-{
- uint32_t thd_idx; /* the thread index */
- uint32_t nconns; /* how many connections included by the thread */
- uint32_t 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 */
- uint32_t 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 */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * 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 <mem_config.h>
-
-#include <clients/utilities.h>
-
-#include <cstdio>
-#include <cassert>
-#include <cstdlib>
-#include <cstring>
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-
-long int timedif(struct timeval a, struct timeval b)
-{
- long us, s;
-
- us = (int)(a.tv_usec - b.tv_usec);
- us /= 1000;
- s = (int)(a.tv_sec - b.tv_sec);
- s *= 1000;
- return s + us;
-}
-
-void version_command(const char *command_name)
-{
- printf("%s v%u.%u\n", command_name, 1U, 0U);
- exit(EXIT_SUCCESS);
-}
-
-void close_stdio(void)
-{
- int fd;
- if ((fd = open("/dev/null", O_RDWR, 0)) < 0)
- {
- return;
- }
- else
- {
- if (dup2(fd, STDIN_FILENO) < 0)
- {
- return;
- }
-
- if (dup2(fd, STDOUT_FILENO) < 0)
- {
- return;
- }
-
- if (dup2(fd, STDERR_FILENO) < 0)
- {
- return;
- }
-
- if (fd > STDERR_FILENO)
- {
- close(fd);
- }
- }
-}
-
-
-static const char *lookup_help(memcached_options option)
-{
- switch (option)
- {
- case OPT_SERVERS: return("List which servers you wish to connect to.");
- case OPT_VERSION: return("Display the version of the application and then exit.");
- case OPT_HELP: return("Display this message and then exit.");
- case OPT_VERBOSE: return("Give more details on the progression of the application.");
- case OPT_QUIET: return("stderr and stdin will be closed at application startup.");
- case OPT_DEBUG: return("Provide output only useful for debugging.");
- case OPT_FLAG: return("Provide flag information for storage operation.");
- case OPT_EXPIRE: return("Set the expire option for the object.");
- case OPT_SET: return("Use set command with memcached when storing.");
- case OPT_REPLACE: return("Use replace command with memcached when storing.");
- case OPT_ADD: return("Use add command with memcached when storing.");
- case OPT_SLAP_EXECUTE_NUMBER: return("Number of times to execute the given test.");
- case OPT_SLAP_INITIAL_LOAD: return("Number of key pairs to load before executing tests.");
- case OPT_SLAP_TEST: return("Test to run (currently \"get\" or \"set\").");
- case OPT_SLAP_CONCURRENCY: return("Number of users to simulate with load.");
- case OPT_SLAP_NON_BLOCK: return("Set TCP up to use non-blocking IO.");
- case OPT_SLAP_TCP_NODELAY: return("Set TCP socket up to use nodelay.");
- case OPT_FLUSH: return("Flush servers before running tests.");
- case OPT_HASH: return("Select hash type.");
- case OPT_BINARY: return("Switch to binary protocol.");
- case OPT_ANALYZE: return("Analyze the provided servers.");
- case OPT_UDP: return("Use UDP protocol when communicating with server.");
- case OPT_BUFFER: return("Enable request buffering.");
- case OPT_USERNAME: return "Username to use for SASL authentication";
- case OPT_PASSWD: return "Password to use for SASL authentication";
- case OPT_FILE: return "Path to file in which to save result";
- case OPT_STAT_ARGS: return "Argument for statistics";
- case OPT_SERVER_VERSION: return "Memcached daemon software version";
- default:
- break;
- };
-
- assert(0);
- return "forgot to document this function :)";
-}
-
-void help_command(const char *command_name, const char *description,
- const struct option *long_options,
- memcached_programs_help_st *options)
-{
- unsigned int x;
- (void)options;
-
- printf("%s v%u.%u\n\n", command_name, 1U, 0U);
- printf("\t%s\n\n", description);
- printf("Current options. A '=' means the option takes a value.\n\n");
-
- for (x= 0; long_options[x].name; x++)
- {
- const char *help_message;
-
- printf("\t --%s%c\n", long_options[x].name,
- long_options[x].has_arg ? '=' : ' ');
- if ((help_message= lookup_help(memcached_options(long_options[x].val))))
- printf("\t\t%s\n", help_message);
- }
-
- printf("\n");
- exit(EXIT_SUCCESS);
-}
-
-void process_hash_option(memcached_st *memc, char *opt_hash)
-{
- uint64_t set;
- memcached_return_t rc;
-
- if (opt_hash == NULL)
- {
- return;
- }
-
- set= MEMCACHED_HASH_DEFAULT; /* Just here to solve warning */
- if (!strcasecmp(opt_hash, "CRC"))
- {
- set= MEMCACHED_HASH_CRC;
- }
- else if (!strcasecmp(opt_hash, "FNV1_64"))
- {
- set= MEMCACHED_HASH_FNV1_64;
- }
- else if (!strcasecmp(opt_hash, "FNV1A_64"))
- {
- set= MEMCACHED_HASH_FNV1A_64;
- }
- else if (!strcasecmp(opt_hash, "FNV1_32"))
- {
- set= MEMCACHED_HASH_FNV1_32;
- }
- else if (!strcasecmp(opt_hash, "FNV1A_32"))
- {
- set= MEMCACHED_HASH_FNV1A_32;
- }
- else
- {
- fprintf(stderr, "hash: type not recognized %s\n", opt_hash);
- exit(EXIT_FAILURE);
- }
-
- rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
- if (rc != MEMCACHED_SUCCESS)
- {
- fprintf(stderr, "hash: memcache error %s\n", memcached_strerror(memc, rc));
- exit(EXIT_FAILURE);
- }
-}
-
-void initialize_sockets(void)
-{
- /* Define the function for all platforms to avoid #ifdefs in each program */
-#if defined(_WIN32)
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0)
- {
- fprintf(stderr, "Socket Initialization Error. Program aborted\n");
- exit(EXIT_FAILURE);
- }
-#endif // #if defined(_WIN32)
-}
+++ /dev/null
-/* 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:
- *
- */
-
-#pragma once
-
-#include <getopt.h>
-#include <libmemcached-1.0/memcached.h>
-#include "clients/client_options.h"
-
-#if defined(HAVE_SYS_TIME_H)
-# include <sys/time.h>
-#endif
-
-#if defined(HAVE_TIME_H)
-# include <time.h>
-#endif
-
-
-#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
-
-typedef struct memcached_programs_help_st memcached_programs_help_st;
-
-struct memcached_programs_help_st
-{
- char *not_used_yet;
-};
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-char *strdup_cleanup(const char *str);
-void cleanup(void);
-long int timedif(struct timeval a, struct timeval b);
-void version_command(const char *command_name) __attribute__ ((noreturn));
-void help_command(const char *command_name, const char *description,
- const struct option *long_options,
- memcached_programs_help_st *options) __attribute__ ((noreturn));
-void process_hash_option(memcached_st *memc, char *opt_hash);
-bool initialize_sasl(memcached_st *memc, char *user, char *password);
-void shutdown_sasl(void);
-void initialize_sockets(void);
-void close_stdio(void);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
--- /dev/null
+#!/bin/bash
+
+set -eu
+cd "$(dirname $0)"
+
+if test -d source/.git
+then
+ cd source
+ git pull -r
+ cd ..
+else
+ git clone -b gh-pages github.com:m6w6/libmemcached source
+fi
+
+mkdir -p build
+cd build
+cmake ../..
+make html
+rsync -va --delete --exclude=.git/ docs/html/ ../source/
+
+cd ../source
+touch .nojekyll
+git add -A
+git ci -m "update docs"
+git push
+
+++ /dev/null
-#!/bin/bash
-
-set -eu
-cd "$(dirname $0)"
-
-if test -d gh-pages/.git
-then
- cd gh-pages
- git pull -r
- cd ..
-else
- git clone -b gh-pages github.com:m6w6/libmemcached gh-pages
-fi
-
-mkdir -p gh-pages-build
-cd gh-pages-build
-cmake ..
-make html
-rsync -va --delete --exclude=.git/ docs/html/ ../gh-pages/
-
-cd ../gh-pages
-touch .nojekyll
-git add -A
-git ci -m "update docs"
-git push
-
--- /dev/null
+
+add_subdirectory(libhashkit-1.0)
+add_subdirectory(libmemcached-1.0)
+add_subdirectory(libmemcachedutil-1.0)
--- /dev/null
+
+configure_file(configure.h.in configure.h @ONLY)
+
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ FILES_MATCHING REGEX "\\.h(pp)?$"
+ )
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/**
+ * @file
+ * @brief HashKit Header
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HASHKIT_API
+uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_fnv1_64(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_fnv1_32(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_crc32(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_hsieh(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_murmur(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_murmur3(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_jenkins(const char *key, size_t key_length);
+
+HASHKIT_API
+uint32_t libhashkit_md5(const char *key, size_t key_length);
+
+HASHKIT_API
+void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+#pragma once
+
+// No assumptions of NULL should be made
+
+#define hashkit_size(X) (X).size;
+#define hashkit_c_str(X) (X).c_str;
+#define hashkit_string_param(X) (X).c_str, (X).size
+
+#ifdef __cplusplus
+#define hashkit_string_printf(X) int((X).size), (X).c_str
+#else
+#define hashkit_string_printf(X) (int)((X).size), (X).c_str
+#endif
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+
+
+/**
+ * @file
+ * @brief HashKit Header
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+
+
+#pragma once
+
+#define LIBHASHKIT_VERSION_STRING "@LIBHASHKIT_VERSION@"
+#define LIBHASHKIT_VERSION_HEX @LIBHASHKIT_VERSION_HEX@
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HASHKIT_API
+uint32_t hashkit_digest(const hashkit_st *self, const char *key, size_t key_length);
+
+/**
+ This is a utilitly function provided so that you can directly access hashes with a hashkit_st.
+*/
+
+HASHKIT_API
+uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ This sets/gets the default function we will be using.
+*/
+HASHKIT_API
+hashkit_return_t hashkit_set_function(hashkit_st *hash, hashkit_hash_algorithm_t hash_algorithm);
+
+HASHKIT_API
+hashkit_return_t hashkit_set_custom_function(hashkit_st *hash, hashkit_hash_fn function, void *context);
+
+HASHKIT_API
+hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *hash);
+
+/**
+ This sets/gets the function we use for distribution.
+*/
+HASHKIT_API
+hashkit_return_t hashkit_set_distribution_function(hashkit_st *hash, hashkit_hash_algorithm_t hash_algorithm);
+
+HASHKIT_API
+hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context);
+
+HASHKIT_API
+hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HASHKIT_API
+bool libhashkit_has_algorithm(const hashkit_hash_algorithm_t);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+
+
+#pragma once
+
+
+#if !defined(__cplusplus)
+# include <stdbool.h>
+#endif
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include <libhashkit-1.0/visibility.h>
+#include <libhashkit-1.0/configure.h>
+#include <libhashkit-1.0/types.h>
+#include <libhashkit-1.0/has.h>
+#include <libhashkit-1.0/algorithm.h>
+#include <libhashkit-1.0/behavior.h>
+#include <libhashkit-1.0/digest.h>
+#include <libhashkit-1.0/function.h>
+#include <libhashkit-1.0/str_algorithm.h>
+#include <libhashkit-1.0/strerror.h>
+#include <libhashkit-1.0/string.h>
+
+struct hashkit_st
+{
+ struct hashkit_function_st {
+ hashkit_hash_fn function;
+ void *context;
+ } base_hash, distribution_hash;
+
+ struct {
+ bool is_base_same_distributed:1;
+ } flags;
+
+ struct {
+ bool is_allocated:1;
+ } options;
+
+ void *_key;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HASHKIT_API
+ hashkit_st *hashkit_create(hashkit_st *hash);
+
+HASHKIT_API
+ hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
+
+HASHKIT_API
+ bool hashkit_compare(const hashkit_st *first, const hashkit_st *second);
+
+HASHKIT_API
+ void hashkit_free(hashkit_st *hash);
+
+HASHKIT_API
+ hashkit_string_st *hashkit_encrypt(hashkit_st *,
+ const char* source, size_t source_length);
+
+HASHKIT_API
+ hashkit_string_st *hashkit_decrypt(hashkit_st *,
+ const char* source, size_t source_length);
+
+HASHKIT_API
+ bool hashkit_key(hashkit_st *, const char *key, const size_t key_length);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#include <libhashkit-1.0/hashkit.h>
+#include <string>
+
+class Hashkit {
+
+public:
+
+ Hashkit()
+ {
+ hashkit_create(&self);
+ }
+
+ Hashkit(const Hashkit& source)
+ {
+ hashkit_clone(&self, &source.self);
+ }
+
+ Hashkit& operator=(const Hashkit& source)
+ {
+ hashkit_free(&self);
+ hashkit_clone(&self, &source.self);
+
+ return *this;
+ }
+
+ friend bool operator==(const Hashkit &left, const Hashkit &right)
+ {
+ return hashkit_compare(&left.self, &right.self);
+ }
+
+ uint32_t digest(std::string& str)
+ {
+ return hashkit_digest(&self, str.c_str(), str.length());
+ }
+
+ uint32_t digest(const char *key, size_t key_length)
+ {
+ return hashkit_digest(&self, key, key_length);
+ }
+
+ hashkit_return_t set_function(hashkit_hash_algorithm_t hash_algorithm)
+ {
+ return hashkit_set_function(&self, hash_algorithm);
+ }
+
+ hashkit_return_t set_distribution_function(hashkit_hash_algorithm_t hash_algorithm)
+ {
+ return hashkit_set_function(&self, hash_algorithm);
+ }
+
+ ~Hashkit()
+ {
+ hashkit_free(&self);
+ }
+private:
+
+ hashkit_st self;
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HASHKIT_API
+const char *libhashkit_string_hash(hashkit_hash_algorithm_t type);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HASHKIT_API
+ const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+struct hashkit_string_st;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HASHKIT_API
+void hashkit_string_free(hashkit_string_st *ptr);
+
+
+HASHKIT_API
+size_t hashkit_string_length(const hashkit_string_st *self);
+
+HASHKIT_API
+const char *hashkit_string_c_str(const hashkit_string_st* self);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+typedef enum {
+ HASHKIT_SUCCESS,
+ HASHKIT_FAILURE,
+ HASHKIT_MEMORY_ALLOCATION_FAILURE,
+ HASHKIT_INVALID_HASH,
+ HASHKIT_INVALID_ARGUMENT,
+ HASHKIT_MAXIMUM_RETURN /* Always add new error code before */
+} hashkit_return_t;
+
+static inline bool hashkit_success(const hashkit_return_t rc)
+{
+ return (rc == HASHKIT_SUCCESS);
+}
+
+static inline bool hashkit_failed(const hashkit_return_t rc)
+{
+ return (rc != HASHKIT_SUCCESS);
+}
+
+typedef enum {
+ HASHKIT_HASH_DEFAULT= 0, // hashkit_one_at_a_time()
+ 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_MURMUR3,
+ HASHKIT_HASH_CUSTOM,
+ 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;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct hashkit_st hashkit_st;
+typedef struct hashkit_string_st hashkit_string_st;
+
+typedef uint32_t (*hashkit_hash_fn)(const char *key, size_t key_length, void *context);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/*
+ * 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
+ */
+
+#pragma once
+
+/**
+ *
+ * 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) */
--- /dev/null
+
+configure_file(configure.h.in configure.h @ONLY)
+
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ FILES_MATCHING REGEX "\\.h(pp)?$"
+ PATTERN t EXCLUDE
+ )
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Memory allocation functions.
+*/
+typedef void (*memcached_free_fn)(const memcached_st *ptr, void *mem, void *context);
+typedef void *(*memcached_malloc_fn)(const memcached_st *ptr, const size_t size, void *context);
+typedef void *(*memcached_realloc_fn)(const memcached_st *ptr, void *mem, const size_t size, void *context);
+typedef void *(*memcached_calloc_fn)(const memcached_st *ptr, size_t nelem, const size_t elsize, void *context);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_set_memory_allocators(memcached_st *ptr,
+ memcached_malloc_fn mem_malloc,
+ memcached_free_fn mem_free,
+ memcached_realloc_fn mem_realloc,
+ memcached_calloc_fn mem_calloc,
+ void *context);
+
+LIBMEMCACHED_API
+void memcached_get_memory_allocators(const memcached_st *ptr,
+ memcached_malloc_fn *mem_malloc,
+ memcached_free_fn *mem_free,
+ memcached_realloc_fn *mem_realloc,
+ memcached_calloc_fn *mem_calloc);
+
+LIBMEMCACHED_API
+void *memcached_get_memory_allocators_context(const memcached_st *ptr);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached-1.0/struct/analysis.h>
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#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 *group_key, size_t group_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 *group_key, size_t group_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 *group_key,
+ size_t group_key_length,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+// No assumptions of NULL should be made
+
+struct memcached_string_t {
+ const char *c_str;
+ size_t size;
+};
+
+#define memcached_size(X) (X).size;
+#define memcached_c_str(X) (X).c_str;
+#define memcached_string_param(X) (X).c_str, (X).size
+
+#ifdef __cplusplus
+#define memcached_string_printf(X) int((X).size), (X).c_str
+#else
+#define memcached_string_printf(X) (int)((X).size), (X).c_str
+#endif
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#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);
+
+LIBMEMCACHED_API
+ const char *libmemcached_string_behavior(const memcached_behavior_t flag);
+
+LIBMEMCACHED_API
+ const char *libmemcached_string_distribution(const memcached_server_distribution_t flag);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_bucket_set(memcached_st *self,
+ const uint32_t *host_map,
+ const uint32_t *forward_map,
+ const uint32_t buckets,
+ const uint32_t replicas);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_callback_set(memcached_st *ptr,
+ const memcached_callback_t flag,
+ const void *data);
+LIBMEMCACHED_API
+void *memcached_callback_get(memcached_st *ptr,
+ const memcached_callback_t flag,
+ memcached_return_t *error);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef memcached_return_t (*memcached_execute_fn)(const memcached_st *ptr, memcached_result_st *result, void *context);
+typedef memcached_return_t (*memcached_server_fn)(const memcached_st *ptr, const memcached_instance_st * server, void *context);
+typedef memcached_return_t (*memcached_stat_fn)(const memcached_instance_st * server,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ void *context);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker, Trond Norbye All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#cmakedefine01 LIBMEMCACHED_ENABLE_DEPRECATED
+#cmakedefine01 LIBMEMCACHED_WITH_SASL_SUPPORT
+
+#define LIBMEMCACHED_VERSION_STRING "@LIBMEMCACHED_VERSION@"
+#define LIBMEMCACHED_VERSION_HEX @LIBMEMCACHED_VERSION_HEX@
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+/* Public defines */
+#define MEMCACHED_DEFAULT_PORT 11211
+#define MEMCACHED_DEFAULT_PORT_STRING "11211"
+#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 5000
+#define MEMCACHED_DEFAULT_CONNECT_TIMEOUT 4000
+#define MEMCACHED_CONTINUUM_ADDITION 10 /* How many extra slots we should build for in the continuum */
+#define MEMCACHED_EXPIRATION_NOT_ADD 0xffffffffU
+#define MEMCACHED_SERVER_FAILURE_LIMIT 5
+#define MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT 2
+#define MEMCACHED_SERVER_FAILURE_DEAD_TIMEOUT 0
+#define MEMCACHED_SERVER_TIMEOUT_LIMIT 0
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
+ time_t expiration);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_delete_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ time_t expiration);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Warning, none of these should ever be used.
+ */
+
+#pragma once
+
+/**
+ @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_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;
+typedef memcached_instance_st *memcached_server_instance_st;
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+#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
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_set_encoding_key(memcached_st*, const char *str, size_t length);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+ const char *memcached_error(const memcached_st *);
+
+LIBMEMCACHED_API
+ const char *memcached_last_error_message(const memcached_st *);
+
+LIBMEMCACHED_API
+ void memcached_error_print(const memcached_st *);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_last_error(const memcached_st *);
+
+LIBMEMCACHED_API
+ int memcached_last_error_errno(const memcached_st *);
+
+LIBMEMCACHED_API
+ const char *memcached_server_error(const memcached_instance_st * ptr);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_server_error_return(const memcached_instance_st * ptr);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/*
+ * Summary: Exceptions for the C++ interface
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ */
+
+/**
+ * @file
+ * @brief Exception declarations
+ */
+
+#pragma once
+
+#include <stdexcept>
+#include <string>
+
+namespace memcache
+{
+ class Exception : public std::runtime_error
+ {
+ public:
+ Exception(const std::string& msg, int in_errno)
+ :
+ std::runtime_error(msg),
+ _errno(in_errno)
+ {}
+
+ Exception(const char *msg, int in_errno)
+ :
+ std::runtime_error(std::string(msg)),
+ _errno(in_errno) {}
+
+ virtual ~Exception() throw() {}
+
+ int getErrno() const
+ {
+ return _errno;
+ }
+
+ private:
+ int _errno;
+ };
+
+ class Warning : public Exception
+ {
+ public:
+ Warning(const std::string& msg, int in_errno) : Exception(msg, in_errno) {}
+ Warning(const char *msg, int in_errno) : Exception(msg, in_errno) {}
+ };
+
+ class Error : public Exception
+ {
+ public:
+ Error(const std::string& msg, int in_errno) : Exception(msg, in_errno) {}
+ Error(const char *msg, int in_errno) : Exception(msg, in_errno) {}
+ virtual ~Error() throw() {}
+ };
+
+} /* namespace libmemcached */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_exist(memcached_st *memc, const char *key, size_t key_length);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_exist_by_key(memcached_st *memc,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length);
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_fetch_execute(memcached_st *ptr,
+ memcached_execute_fn *callback,
+ void *context,
+ uint32_t number_of_callbacks);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_flush_buffers(memcached_st *mem);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+#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 *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ size_t *value_length,
+ uint32_t *flags,
+ memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_mget_by_key(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ 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 *group_key,
+ size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ memcached_execute_fn *callback,
+ void *context,
+ const uint32_t number_of_callbacks);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The two public hash bits */
+LIBMEMCACHED_API
+uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm);
+
+LIBMEMCACHED_API
+const hashkit_st *memcached_get_hashkit(const memcached_st *ptr);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_set_hashkit(memcached_st *ptr, hashkit_st *hashk);
+
+LIBMEMCACHED_API
+uint32_t memcached_generate_hash(const memcached_st *ptr, const char *key, size_t key_length);
+
+LIBMEMCACHED_API
+void memcached_autoeject(memcached_st *ptr);
+
+LIBMEMCACHED_API
+ const char * libmemcached_string_hash(memcached_hash_t type);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#define MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH 20
+#define MEMCACHED_MAX_BUFFER 8196
+#define MEMCACHED_MAX_HOST_SORT_LENGTH 86 /* Used for Ketama */
+#define MEMCACHED_MAX_KEY 251 /* We add one to have it null terminated */
+#define MEMCACHED_PREFIX_KEY_MAX_SIZE 128
+#define MEMCACHED_VERSION_STRING_LENGTH 24
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+/* This seems to be required for older compilers @note http://stackoverflow.com/questions/8132399/how-to-printf-uint64-t */
+#ifndef __STDC_FORMAT_MACROS
+# define __STDC_FORMAT_MACROS
+#endif
+
+#ifdef __cplusplus
+# if __cplusplus >= 201103L
+# include <cinttypes>
+# else
+# include <inttypes.h>
+# endif
+# include <cstddef>
+# include <cstdlib>
+#else
+# include <inttypes.h>
+# include <stddef.h>
+# include <stdlib.h>
+# include <stdbool.h>
+#endif
+
+#include <sys/types.h>
+
+#include <libmemcached-1.0/visibility.h>
+#include <libmemcached-1.0/configure.h>
+#include <libmemcached-1.0/platform.h>
+
+#include <libmemcached-1.0/limits.h>
+#include <libmemcached-1.0/defaults.h>
+
+#include <libmemcached-1.0/types/behavior.h>
+#include <libmemcached-1.0/types/callback.h>
+#include <libmemcached-1.0/types/connection.h>
+#include <libmemcached-1.0/types/hash.h>
+#include <libmemcached-1.0/types/return.h>
+#include <libmemcached-1.0/types/server_distribution.h>
+
+#include <libmemcached-1.0/return.h>
+
+#include <libmemcached-1.0/types.h>
+#include <libmemcached-1.0/callbacks.h>
+#include <libmemcached-1.0/alloc.h>
+#include <libmemcached-1.0/triggers.h>
+
+#include <libhashkit-1.0/hashkit.h>
+
+#include <libmemcached-1.0/struct/callback.h>
+#include <libmemcached-1.0/struct/string.h>
+#include <libmemcached-1.0/struct/result.h>
+#include <libmemcached-1.0/struct/allocator.h>
+#include <libmemcached-1.0/struct/sasl.h>
+#include <libmemcached-1.0/struct/memcached.h>
+#include <libmemcached-1.0/struct/server.h>
+#include <libmemcached-1.0/struct/stat.h>
+
+#include <libmemcached-1.0/basic_string.h>
+#include <libmemcached-1.0/error.h>
+#include <libmemcached-1.0/stats.h>
+
+// Everything above this line must be in the order specified.
+#include <libmemcached-1.0/allocators.h>
+#include <libmemcached-1.0/analyze.h>
+#include <libmemcached-1.0/auto.h>
+#include <libmemcached-1.0/behavior.h>
+#include <libmemcached-1.0/callback.h>
+#include <libmemcached-1.0/delete.h>
+#include <libmemcached-1.0/dump.h>
+#include <libmemcached-1.0/encoding_key.h>
+#include <libmemcached-1.0/exist.h>
+#include <libmemcached-1.0/fetch.h>
+#include <libmemcached-1.0/flush.h>
+#include <libmemcached-1.0/flush_buffers.h>
+#include <libmemcached-1.0/get.h>
+#include <libmemcached-1.0/hash.h>
+#include <libmemcached-1.0/options.h>
+#include <libmemcached-1.0/parse.h>
+#include <libmemcached-1.0/quit.h>
+#include <libmemcached-1.0/result.h>
+#include <libmemcached-1.0/server.h>
+#include <libmemcached-1.0/server_list.h>
+#include <libmemcached-1.0/storage.h>
+#include <libmemcached-1.0/strerror.h>
+#include <libmemcached-1.0/touch.h>
+#include <libmemcached-1.0/verbosity.h>
+#include <libmemcached-1.0/version.h>
+#include <libmemcached-1.0/sasl.h>
+
+#include <libmemcached-1.0/deprecated_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+void memcached_servers_reset(memcached_st *ptr);
+
+LIBMEMCACHED_API
+memcached_st *memcached_create(memcached_st *ptr);
+
+LIBMEMCACHED_API
+memcached_st *memcached(const char *string, size_t string_length);
+
+LIBMEMCACHED_API
+void memcached_free(memcached_st *ptr);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_reset(memcached_st *ptr);
+
+LIBMEMCACHED_API
+void memcached_reset_last_disconnected_server(memcached_st *ptr);
+
+LIBMEMCACHED_API
+memcached_st *memcached_clone(memcached_st *clone, const memcached_st *ptr);
+
+LIBMEMCACHED_API
+void *memcached_get_user_data(const memcached_st *ptr);
+
+LIBMEMCACHED_API
+void *memcached_set_user_data(memcached_st *ptr, void *data);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source);
+
+LIBMEMCACHED_API
+const memcached_instance_st * memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key);
+
+LIBMEMCACHED_API
+uint32_t memcached_server_count(const memcached_st *);
+
+LIBMEMCACHED_API
+uint64_t memcached_query_id(const memcached_st *);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Summary: C++ interface for memcached server
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Authors: Padraig O'Sullivan <osullivan.padraig@gmail.com>
+ * Patrick Galbraith <patg@patg.net>
+ */
+
+/**
+ * @file memcached.hpp
+ * @brief Libmemcached C++ interface
+ */
+
+#pragma once
+
+#include <libmemcached-1.0/memcached.h>
+#if 0
+#include <libmemcached/exception.hpp>
+#endif
+
+#include <string.h>
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <map>
+
+namespace memcache
+{
+
+/**
+ * This is the core memcached library (if later, other objects
+ * are needed, they will be created from this class).
+ */
+class Memcache
+{
+public:
+
+ Memcache()
+ {
+ memc_= memcached(NULL, 0);
+ }
+
+ Memcache(const std::string &config)
+ {
+ memc_= memcached(config.c_str(), config.size());
+ }
+
+ Memcache(const std::string &hostname, in_port_t port)
+ {
+ memc_= memcached(NULL, 0);
+ if (memc_)
+ {
+ memcached_server_add(memc_, hostname.c_str(), port);
+ }
+ }
+
+ Memcache(memcached_st *clone)
+ {
+ memc_= memcached_clone(NULL, clone);
+ }
+
+ Memcache(const Memcache &rhs)
+ {
+ memc_= memcached_clone(NULL, rhs.getImpl());
+ }
+
+ Memcache &operator=(const Memcache &rhs)
+ {
+ if (this != &rhs)
+ {
+ memcached_free(memc_);
+ memc_= memcached_clone(NULL, rhs.getImpl());
+ }
+
+ return *this;
+ }
+
+ ~Memcache()
+ {
+ memcached_free(memc_);
+ }
+
+ /**
+ * Get the internal memcached_st *
+ */
+ const memcached_st *getImpl() const
+ {
+ return memc_;
+ }
+
+ /**
+ * Return an error string for the given 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_t rc) const
+ {
+ /* first parameter to strerror is unused */
+ return memcached_strerror(NULL, rc);
+ }
+
+ bool error(std::string& error_message) const
+ {
+ if (memcached_failed(memcached_last_error(memc_)))
+ {
+ error_message+= memcached_last_error_message(memc_);
+ return true;
+ }
+
+ return false;
+ }
+
+ bool error() const
+ {
+ if (memcached_failed(memcached_last_error(memc_)))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ bool error(memcached_return_t& arg) const
+ {
+ arg= memcached_last_error(memc_);
+ return memcached_failed(arg);
+ }
+
+ bool setBehavior(memcached_behavior_t flag, uint64_t data)
+ {
+ return (memcached_success(memcached_behavior_set(memc_, flag, data)));
+ }
+
+ uint64_t getBehavior(memcached_behavior_t flag)
+ {
+ return memcached_behavior_get(memc_, flag);
+ }
+
+ /**
+ * Configure the memcache object
+ *
+ * @param[in] in_config configuration
+ * @return true on success; false otherwise
+ */
+ bool configure(const std::string &configuration)
+ {
+ memcached_st *new_memc= memcached(configuration.c_str(), configuration.size());
+
+ if (new_memc)
+ {
+ memcached_free(memc_);
+ memc_= new_memc;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Add a server to the list of memcached servers to use.
+ *
+ * @param[in] server_name name of the server to add
+ * @param[in] port port number of server to add
+ * @return true on success; false otherwise
+ */
+ bool addServer(const std::string &server_name, in_port_t port)
+ {
+ return memcached_success(memcached_server_add(memc_, server_name.c_str(), port));
+ }
+
+ /**
+ * Remove a server from the list of memcached servers to use.
+ *
+ * @param[in] server_name name of the server to remove
+ * @param[in] port port number of server to remove
+ * @return true on success; false otherwise
+ */
+ bool removeServer(const std::string &server_name, in_port_t port)
+ {
+ std::string tmp_str;
+ std::ostringstream strstm;
+ tmp_str.append(",");
+ tmp_str.append(server_name);
+ tmp_str.append(":");
+ strstm << port;
+ tmp_str.append(strstm.str());
+
+ //memcached_return_t rc= memcached_server_remove(server);
+
+ return false;
+ }
+
+ /**
+ * Fetches an individual value from the server. mget() must always
+ * be called before using this method.
+ *
+ * @param[in] key key of object to fetch
+ * @param[out] ret_val store returned object in this vector
+ * @return a memcached return structure
+ */
+ memcached_return_t fetch(std::string &key,
+ std::vector<char> &ret_val,
+ uint32_t &flags,
+ uint64_t &cas_value)
+ {
+ memcached_return_t rc;
+
+ memcached_result_st *result;
+ if ((result= memcached_fetch_result(memc_, NULL, &rc)))
+ {
+ // Key
+ key.assign(memcached_result_key_value(result), memcached_result_key_length(result));
+
+ // Actual value, null terminated
+ ret_val.reserve(memcached_result_length(result) +1);
+ ret_val.assign(memcached_result_value(result),
+ memcached_result_value(result) +memcached_result_length(result) +1);
+ ret_val.resize(memcached_result_length(result));
+
+ // Misc
+ flags= memcached_result_flags(result);
+ cas_value= memcached_result_cas(result);
+ }
+ memcached_result_free(result);
+
+ return rc;
+ }
+
+ memcached_return_t fetch(std::string &key,
+ std::vector<char> &ret_val)
+ {
+ uint32_t flags= 0;
+ uint64_t cas_value= 0;
+
+ return fetch(key, ret_val, flags, cas_value);
+ }
+
+ /**
+ * Fetches an individual value from the server.
+ *
+ * @param[in] key key of object whose value to get
+ * @param[out] ret_val object that is retrieved is stored in
+ * this vector
+ * @return true on success; false otherwise
+ */
+ bool get(const std::string &key, std::vector<char> &ret_val)
+ {
+ uint32_t flags= 0;
+ memcached_return_t rc;
+ size_t value_length= 0;
+
+ char *value= memcached_get(memc_, key.c_str(), key.length(),
+ &value_length, &flags, &rc);
+ if (value != NULL && ret_val.empty())
+ {
+ ret_val.reserve(value_length +1); // Always provide null
+ ret_val.assign(value, value +value_length +1);
+ ret_val.resize(value_length);
+ free(value);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * 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
+ * used for storage.
+ *
+ * @param[in] master_key key that specifies server object is stored on
+ * @param[in] key key of object whose value to get
+ * @param[out] ret_val object that is retrieved is stored in
+ * this vector
+ * @return true on success; false otherwise
+ */
+ bool getByKey(const std::string &master_key,
+ const std::string &key,
+ std::vector<char> &ret_val)
+ {
+ uint32_t flags= 0;
+ memcached_return_t rc;
+ size_t value_length= 0;
+
+ char *value= memcached_get_by_key(memc_,
+ master_key.c_str(), master_key.length(),
+ key.c_str(), key.length(),
+ &value_length, &flags, &rc);
+ if (value)
+ {
+ ret_val.reserve(value_length +1); // Always provide null
+ ret_val.assign(value, value +value_length +1);
+ ret_val.resize(value_length);
+ free(value);
+
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Selects multiple keys at once. This method always
+ * works asynchronously.
+ *
+ * @param[in] keys vector of keys to select
+ * @return true if all keys are found
+ */
+ bool mget(const std::vector<std::string>& keys)
+ {
+ std::vector<const char *> real_keys;
+ std::vector<size_t> key_len;
+ /*
+ * Construct an array which will contain the length
+ * of each of the strings in the input vector. Also, to
+ * interface with the memcached C API, we need to convert
+ * the vector of std::string's to a vector of char *.
+ */
+ real_keys.reserve(keys.size());
+ key_len.reserve(keys.size());
+
+ std::vector<std::string>::const_iterator it= keys.begin();
+
+ while (it != keys.end())
+ {
+ real_keys.push_back(const_cast<char *>((*it).c_str()));
+ key_len.push_back((*it).length());
+ ++it;
+ }
+
+ /*
+ * If the std::vector of keys is empty then we cannot
+ * call memcached_mget as we will get undefined behavior.
+ */
+ if (not real_keys.empty())
+ {
+ return memcached_success(memcached_mget(memc_, &real_keys[0], &key_len[0], real_keys.size()));
+ }
+
+ return false;
+ }
+
+ /**
+ * Writes an object to the server. If the object already exists, it will
+ * overwrite the existing object. This method always returns true
+ * when using non-blocking mode unless a network error occurs.
+ *
+ * @param[in] key key of object to write to server
+ * @param[in] value value of object to write to server
+ * @param[in] expiration time to keep the object stored in the server for
+ * @param[in] flags flags to store with the object
+ * @return true on succcess; false otherwise
+ */
+ bool set(const std::string &key,
+ const std::vector<char> &value,
+ time_t expiration,
+ uint32_t flags)
+ {
+ memcached_return_t rc= memcached_set(memc_,
+ key.c_str(), key.length(),
+ value.data(), value.size(),
+ expiration, flags);
+ return memcached_success(rc);
+ }
+
+ bool set(const std::string &key,
+ const char* value, const size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+ {
+ memcached_return_t rc= memcached_set(memc_,
+ key.c_str(), key.length(),
+ value, value_length,
+ expiration, flags);
+ return memcached_success(rc);
+ }
+
+ /**
+ * Writes an object to a server specified by the master_key parameter.
+ * If the object already exists, it will overwrite the existing object.
+ *
+ * @param[in] master_key key that specifies server to write to
+ * @param[in] key key of object to write to server
+ * @param[in] value value of object to write to server
+ * @param[in] expiration time to keep the object stored in the server for
+ * @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,
+ const std::vector<char> &value,
+ time_t expiration,
+ uint32_t flags)
+ {
+ return memcached_success(memcached_set_by_key(memc_, master_key.c_str(),
+ master_key.length(),
+ key.c_str(), key.length(),
+ &value[0], value.size(),
+ expiration,
+ flags));
+ }
+
+ /**
+ * Writes a list of objects to the server. Objects are specified by
+ * 2 vectors - 1 vector of keys and 1 vector of values.
+ *
+ * @param[in] keys vector of keys of objects to write to server
+ * @param[in] values vector of values of objects to write to server
+ * @param[in] expiration time to keep the objects stored in server for
+ * @param[in] flags flags to store with the objects
+ * @return true on success; false otherwise
+ */
+ bool setAll(const std::vector<std::string>& keys,
+ const std::vector< std::vector<char> *>& values,
+ time_t expiration,
+ uint32_t flags)
+ {
+ bool retval= true;
+ std::vector<std::string>::const_iterator key_it= keys.begin();
+ std::vector< std::vector<char> *>::const_iterator val_it= values.begin();
+ while (key_it != keys.end())
+ {
+ retval= set((*key_it), *(*val_it), expiration, flags);
+ if (retval == false)
+ {
+ return retval;
+ }
+ ++key_it;
+ ++val_it;
+ }
+ return retval;
+ }
+
+ /**
+ * Writes a list of objects to the server. Objects are specified by
+ * a map of keys to values.
+ *
+ * @param[in] key_value_map map of keys and values to store in server
+ * @param[in] expiration time to keep the objects stored in server for
+ * @param[in] flags flags to store with the objects
+ * @return true on success; false otherwise
+ */
+ bool setAll(const std::map<const std::string, std::vector<char> >& key_value_map,
+ time_t expiration,
+ uint32_t flags)
+ {
+ std::map<const std::string, std::vector<char> >::const_iterator it= key_value_map.begin();
+
+ while (it != key_value_map.end())
+ {
+ if (!set(it->first, it->second, expiration, flags))
+ {
+ // We should tell the user what the key that failed was
+ return false;
+ }
+ ++it;
+ }
+
+ return true;
+ }
+
+ /**
+ * Increment the value of the object associated with the specified
+ * key by the offset given. The resulting value is saved in the value
+ * parameter.
+ *
+ * @param[in] key key of object in server whose value to increment
+ * @param[in] offset amount to increment object's value by
+ * @param[out] value store the result of the increment here
+ * @return true on success; false otherwise
+ */
+ bool increment(const std::string& key, uint32_t offset, uint64_t *value)
+ {
+ return memcached_success(memcached_increment(memc_, key.c_str(), key.length(), offset, value));
+ }
+
+ /**
+ * Decrement the value of the object associated with the specified
+ * key by the offset given. The resulting value is saved in the value
+ * parameter.
+ *
+ * @param[in] key key of object in server whose value to decrement
+ * @param[in] offset amount to increment object's value by
+ * @param[out] value store the result of the decrement here
+ * @return true on success; false otherwise
+ */
+ bool decrement(const std::string& key, uint32_t offset, uint64_t *value)
+ {
+ return memcached_success(memcached_decrement(memc_, key.c_str(),
+ key.length(),
+ offset, value));
+ }
+
+
+ /**
+ * Add an object with the specified key and value to the server. This
+ * function returns false if the object already exists on the server.
+ *
+ * @param[in] key key of object to add
+ * @param[in] value of object to add
+ * @return true on success; false otherwise
+ */
+ bool add(const std::string& key, const std::vector<char>& value)
+ {
+ return memcached_success(memcached_add(memc_, key.c_str(), key.length(),
+ &value[0], value.size(), 0, 0));
+ }
+
+ /**
+ * Add an object with the specified key and value to the server. This
+ * function returns false if the object already exists on the server. The
+ * server to add the object to is specified by the master_key parameter.
+ *
+ * @param[in[ master_key key of server to add object to
+ * @param[in] key key of object to add
+ * @param[in] value of object to add
+ * @return true on success; false otherwise
+ */
+ bool addByKey(const std::string& master_key,
+ const std::string& key,
+ const std::vector<char>& value)
+ {
+ return memcached_success(memcached_add_by_key(memc_,
+ master_key.c_str(),
+ master_key.length(),
+ key.c_str(),
+ key.length(),
+ &value[0],
+ value.size(),
+ 0, 0));
+ }
+
+ /**
+ * Replaces an object on the server. This method only succeeds
+ * if the object is already present on the server.
+ *
+ * @param[in] key key of object to replace
+ * @param[in[ value value to replace object with
+ * @return true on success; false otherwise
+ */
+ bool replace(const std::string& key, const std::vector<char>& value)
+ {
+ return memcached_success(memcached_replace(memc_, key.c_str(), key.length(),
+ &value[0], value.size(),
+ 0, 0));
+ }
+
+ /**
+ * Replaces an object on the server. This method only succeeds
+ * if the object is already present on the server. The server
+ * to replace the object on is specified by the master_key param.
+ *
+ * @param[in] master_key key of server to replace object on
+ * @param[in] key key of object to replace
+ * @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,
+ const std::vector<char>& value)
+ {
+ return memcached_success(memcached_replace_by_key(memc_,
+ master_key.c_str(),
+ master_key.length(),
+ key.c_str(),
+ key.length(),
+ &value[0],
+ value.size(),
+ 0, 0));
+ }
+
+ /**
+ * Places a segment of data before the last piece of data stored.
+ *
+ * @param[in] key key of object whose value we will prepend data to
+ * @param[in] value data to prepend to object's value
+ * @return true on success; false otherwise
+ */
+ bool prepend(const std::string& key, const std::vector<char>& value)
+ {
+ return memcached_success(memcached_prepend(memc_, key.c_str(), key.length(),
+ &value[0], value.size(), 0, 0));
+ }
+
+ /**
+ * Places a segment of data before the last piece of data stored. The
+ * server on which the object where we will be prepending data is stored
+ * on is specified by the master_key parameter.
+ *
+ * @param[in] master_key key of server where object is stored
+ * @param[in] key key of object whose value we will prepend data to
+ * @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,
+ const std::vector<char>& value)
+ {
+ return memcached_success(memcached_prepend_by_key(memc_,
+ master_key.c_str(),
+ master_key.length(),
+ key.c_str(),
+ key.length(),
+ &value[0],
+ value.size(),
+ 0,
+ 0));
+ }
+
+ /**
+ * Places a segment of data at the end of the last piece of data stored.
+ *
+ * @param[in] key key of object whose value we will append data to
+ * @param[in] value data to append to object's value
+ * @return true on success; false otherwise
+ */
+ bool append(const std::string& key, const std::vector<char>& value)
+ {
+ return memcached_success(memcached_append(memc_,
+ key.c_str(),
+ key.length(),
+ &value[0],
+ value.size(),
+ 0, 0));
+ }
+
+ /**
+ * Places a segment of data at the end of the last piece of data stored. The
+ * server on which the object where we will be appending data is stored
+ * on is specified by the master_key parameter.
+ *
+ * @param[in] master_key key of server where object is stored
+ * @param[in] key key of object whose value we will append data to
+ * @param[in] value data to append to object's value
+ * @return true on success; false otherwise
+ */
+ bool appendByKey(const std::string& master_key,
+ const std::string& key,
+ const std::vector<char> &value)
+ {
+ return memcached_success(memcached_append_by_key(memc_,
+ master_key.c_str(),
+ master_key.length(),
+ key.c_str(),
+ key.length(),
+ &value[0],
+ value.size(),
+ 0, 0));
+ }
+
+ /**
+ * Overwrite data in the server as long as the cas_arg value
+ * is still the same in the server.
+ *
+ * @param[in] key key of object in server
+ * @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,
+ uint64_t cas_arg)
+ {
+ return memcached_success(memcached_cas(memc_, key.c_str(), key.length(),
+ &value[0], value.size(),
+ 0, 0, cas_arg));
+ }
+
+ /**
+ * Overwrite data in the server as long as the cas_arg value
+ * is still the same in the server. The server to use is
+ * specified by the master_key parameter.
+ *
+ * @param[in] master_key specifies server to operate on
+ * @param[in] key key of object in server
+ * @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,
+ uint64_t cas_arg)
+ {
+ return memcached_success(memcached_cas_by_key(memc_,
+ master_key.c_str(),
+ master_key.length(),
+ key.c_str(),
+ key.length(),
+ &value[0],
+ value.size(),
+ 0, 0, cas_arg));
+ }
+
+ /**
+ * Delete an object from the server specified by the key given.
+ *
+ * @param[in] key key of object to delete
+ * @return true on success; false otherwise
+ */
+ bool remove(const std::string& key)
+ {
+ return memcached_success(memcached_delete(memc_, key.c_str(), key.length(), 0));
+ }
+
+ /**
+ * Delete an object from the server specified by the key given.
+ *
+ * @param[in] key key of object to delete
+ * @param[in] expiration time to delete the object after
+ * @return true on success; false otherwise
+ */
+ bool remove(const std::string& key, time_t expiration)
+ {
+ return memcached_success(memcached_delete(memc_,
+ key.c_str(),
+ key.length(),
+ expiration));
+ }
+
+ /**
+ * 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
+ * @return true on success; false otherwise
+ */
+ bool removeByKey(const std::string& master_key,
+ const std::string& key)
+ {
+ return memcached_success(memcached_delete_by_key(memc_,
+ master_key.c_str(),
+ master_key.length(),
+ key.c_str(),
+ key.length(),
+ 0));
+ }
+
+ /**
+ * 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,
+ const std::string& key,
+ time_t expiration)
+ {
+ return memcached_success(memcached_delete_by_key(memc_,
+ master_key.c_str(),
+ master_key.length(),
+ key.c_str(),
+ key.length(),
+ expiration));
+ }
+
+ /**
+ * Wipe the contents of memcached servers.
+ *
+ * @param[in] expiration time to wait until wiping contents of
+ * memcached servers
+ * @return true on success; false otherwise
+ */
+ bool flush(time_t expiration= 0)
+ {
+ return memcached_success(memcached_flush(memc_, expiration));
+ }
+
+ /**
+ * Get the library version string.
+ * @return std::string containing a copy of the library version string.
+ */
+ const std::string libVersion() const
+ {
+ const char *ver= memcached_lib_version();
+ const std::string version(ver);
+ return version;
+ }
+
+ /**
+ * Retrieve memcached statistics. Populate a std::map with the retrieved
+ * stats. Each server will map to another std::map of the key:value stats.
+ *
+ * @param[out] stats_map a std::map to be populated with the memcached
+ * stats
+ * @return true on success; false otherwise
+ */
+ bool getStats(std::map< std::string, std::map<std::string, std::string> >& stats_map)
+ {
+ memcached_return_t rc;
+ memcached_stat_st *stats= memcached_stat(memc_, NULL, &rc);
+
+ if (rc != MEMCACHED_SUCCESS &&
+ rc != MEMCACHED_SOME_ERRORS)
+ {
+ return false;
+ }
+
+ uint32_t server_count= memcached_server_count(memc_);
+
+ /*
+ * For each memcached server, construct a std::map for its stats and add
+ * it to the std::map of overall stats.
+ */
+ for (uint32_t x= 0; x < server_count; x++)
+ {
+ const memcached_instance_st * instance= memcached_server_instance_by_position(memc_, x);
+ std::ostringstream strstm;
+ std::string server_name(memcached_server_name(instance));
+ server_name.append(":");
+ strstm << memcached_server_port(instance);
+ server_name.append(strstm.str());
+
+ std::map<std::string, std::string> server_stats;
+ char **list= memcached_stat_get_keys(memc_, &stats[x], &rc);
+ for (char** ptr= list; *ptr; ptr++)
+ {
+ char *value= memcached_stat_get_value(memc_, &stats[x], *ptr, &rc);
+ server_stats[*ptr]= value;
+ free(value);
+ }
+
+ stats_map[server_name]= server_stats;
+ free(list);
+ }
+
+ memcached_stat_free(memc_, stats);
+ return true;
+ }
+
+private:
+ memcached_st *memc_;
+};
+
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+ memcached_return_t libmemcached_check_configuration(const char *option_string, size_t length, char *error_buffer, size_t error_buffer_size);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* 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: Work with fetching results
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_server_list_st memcached_servers_parse(const char *server_strings);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+#if defined(_WIN32)
+# include <winsock2.h>
+# include <ws2tcpip.h>
+
+#ifndef HAVE_IN_PORT_T
+typedef int in_port_t;
+# define HAVE_IN_PORT_T 1
+#endif
+
+typedef SOCKET memcached_socket_t;
+
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# include <sys/un.h>
+# include <netinet/tcp.h>
+
+typedef int memcached_socket_t;
+
+#endif /* _WIN32 */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+void memcached_quit(memcached_st *ptr);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached-1.0/struct/result.h>
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 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(const memcached_st *ptr,
+ memcached_result_st *result);
+
+LIBMEMCACHED_API
+const char *memcached_result_key_value(const memcached_result_st *self);
+
+LIBMEMCACHED_API
+size_t memcached_result_key_length(const memcached_result_st *self);
+
+LIBMEMCACHED_API
+const char *memcached_result_value(const memcached_result_st *self);
+
+LIBMEMCACHED_API
+char *memcached_result_take_value(memcached_result_st *self);
+
+LIBMEMCACHED_API
+size_t memcached_result_length(const memcached_result_st *self);
+
+LIBMEMCACHED_API
+uint32_t memcached_result_flags(const memcached_result_st *self);
+
+LIBMEMCACHED_API
+uint64_t memcached_result_cas(const memcached_result_st *self);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length);
+
+LIBMEMCACHED_API
+void memcached_result_set_flags(memcached_result_st *self, uint32_t flags);
+
+LIBMEMCACHED_API
+void memcached_result_set_expiration(memcached_result_st *self, time_t expiration);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+static inline bool memcached_success(memcached_return_t rc)
+{
+ return (rc == MEMCACHED_BUFFERED ||
+ rc == MEMCACHED_DELETED ||
+ rc == MEMCACHED_END ||
+ rc == MEMCACHED_ITEM ||
+ rc == MEMCACHED_STAT ||
+ rc == MEMCACHED_STORED ||
+ rc == MEMCACHED_SUCCESS ||
+ rc == MEMCACHED_VALUE);
+}
+
+static inline bool memcached_failed(memcached_return_t rc)
+{
+ return (rc != MEMCACHED_AUTH_CONTINUE &&
+ rc != MEMCACHED_BUFFERED &&
+ rc != MEMCACHED_DELETED &&
+ rc != MEMCACHED_END &&
+ rc != MEMCACHED_ITEM &&
+ rc != MEMCACHED_STAT &&
+ rc != MEMCACHED_STORED &&
+ rc != MEMCACHED_SUCCESS &&
+ rc != MEMCACHED_VALUE);
+}
+
+static inline bool memcached_fatal(memcached_return_t rc)
+{
+ return (rc != MEMCACHED_AUTH_CONTINUE &&
+ rc != MEMCACHED_BUFFERED &&
+ rc != MEMCACHED_CLIENT_ERROR &&
+ rc != MEMCACHED_DATA_EXISTS &&
+ rc != MEMCACHED_DELETED &&
+ rc != MEMCACHED_E2BIG &&
+ rc != MEMCACHED_END &&
+ rc != MEMCACHED_ITEM &&
+ rc != MEMCACHED_ERROR &&
+ rc != MEMCACHED_NOTFOUND &&
+ rc != MEMCACHED_NOTSTORED &&
+ rc != MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE &&
+ rc != MEMCACHED_STAT &&
+ rc != MEMCACHED_STORED &&
+ rc != MEMCACHED_SUCCESS &&
+ rc != MEMCACHED_VALUE);
+}
+
+#define memcached_continue(__memcached_return_t) ((__memcached_return_t) == MEMCACHED_IN_PROGRESS)
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#if defined(LIBMEMCACHED_WITH_SASL_SUPPORT) && LIBMEMCACHED_WITH_SASL_SUPPORT
+#include <sasl/sasl.h>
+#else
+#define sasl_callback_t void
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+void memcached_set_sasl_callbacks(memcached_st *ptr,
+ const sasl_callback_t *callbacks);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_set_sasl_auth_data(memcached_st *ptr,
+ const char *username,
+ const char *password);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_destroy_sasl_auth_data(memcached_st *ptr);
+
+
+LIBMEMCACHED_API
+sasl_callback_t *memcached_get_sasl_callbacks(memcached_st *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <libmemcached-1.0/struct/sasl.h>
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#include <libmemcached-1.0/struct/server.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_server_cursor(const memcached_st *ptr,
+ const memcached_server_fn *callback,
+ void *context,
+ uint32_t number_of_callbacks);
+
+LIBMEMCACHED_API
+ const memcached_instance_st * memcached_server_by_key(memcached_st *ptr,
+ const char *key,
+ size_t key_length,
+ memcached_return_t *error);
+
+LIBMEMCACHED_API
+void memcached_server_error_reset(memcached_server_st *ptr);
+
+LIBMEMCACHED_API
+void memcached_server_free(memcached_server_st *ptr);
+
+LIBMEMCACHED_API
+const memcached_instance_st * memcached_server_get_last_disconnect(const memcached_st *ptr);
+
+
+LIBMEMCACHED_API
+memcached_return_t memcached_server_add_udp(memcached_st *ptr,
+ const char *hostname,
+ in_port_t port);
+LIBMEMCACHED_API
+memcached_return_t memcached_server_add_unix_socket(memcached_st *ptr,
+ const char *filename);
+LIBMEMCACHED_API
+memcached_return_t memcached_server_add(memcached_st *ptr,
+ const char *hostname, in_port_t port);
+
+LIBMEMCACHED_API
+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_t memcached_server_add_unix_socket_with_weight(memcached_st *ptr,
+ const char *filename,
+ uint32_t weight);
+LIBMEMCACHED_API
+memcached_return_t memcached_server_add_with_weight(memcached_st *ptr, const char *hostname,
+ in_port_t port,
+ uint32_t weight);
+
+/**
+ Operations on Single Servers.
+*/
+LIBMEMCACHED_API
+uint32_t memcached_server_response_count(const memcached_instance_st * self);
+
+LIBMEMCACHED_API
+const char *memcached_server_name(const memcached_instance_st * self);
+
+LIBMEMCACHED_API
+in_port_t memcached_server_port(const memcached_instance_st * self);
+
+LIBMEMCACHED_API
+in_port_t memcached_server_srcport(const memcached_instance_st * self);
+
+LIBMEMCACHED_API
+void memcached_instance_next_retry(const memcached_instance_st * self, const time_t absolute_time);
+
+LIBMEMCACHED_API
+const char *memcached_server_type(const memcached_instance_st * ptr);
+
+LIBMEMCACHED_API
+uint8_t memcached_server_major_version(const memcached_instance_st * ptr);
+
+LIBMEMCACHED_API
+uint8_t memcached_server_minor_version(const memcached_instance_st * ptr);
+
+LIBMEMCACHED_API
+uint8_t memcached_server_micro_version(const memcached_instance_st * ptr);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Server List Public functions */
+LIBMEMCACHED_API
+ void memcached_server_list_free(memcached_server_list_st ptr);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list);
+
+LIBMEMCACHED_API
+ memcached_server_list_st memcached_server_list_append(memcached_server_list_st ptr,
+ const char *hostname,
+ in_port_t port,
+ memcached_return_t *error);
+LIBMEMCACHED_API
+ memcached_server_list_st memcached_server_list_append_with_weight(memcached_server_list_st ptr,
+ const char *hostname,
+ in_port_t port,
+ uint32_t weight,
+ memcached_return_t *error);
+LIBMEMCACHED_API
+ uint32_t memcached_server_list_count(const memcached_server_list_st ptr);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached-1.0/struct/stat.h>
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+void memcached_stat_free(const 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);
+
+LIBMEMCACHED_API
+char *memcached_stat_get_value(const memcached_st *ptr, memcached_stat_st *memc_stat,
+ const char *key, memcached_return_t *error);
+
+LIBMEMCACHED_API
+char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *memc_stat,
+ memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_stat_execute(memcached_st *memc, const char *args, memcached_stat_fn func, void *context);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#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 *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_add_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_replace_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_append_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_cas_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+const char *memcached_strerror(const memcached_st *ptr, memcached_return_t rc);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+struct memcached_allocator_t {
+ memcached_calloc_fn calloc;
+ memcached_free_fn free;
+ memcached_malloc_fn malloc;
+ memcached_realloc_fn realloc;
+ void *context;
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+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;
+};
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+struct memcached_callback_st {
+ memcached_execute_fn *callback;
+ void *context;
+ uint32_t number_of_callback;
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+struct memcached_st {
+ /**
+ @note these are static and should not change without a call to behavior.
+ */
+ struct {
+ bool is_purging:1;
+ bool is_processing_input:1;
+ bool is_time_for_rebuild:1;
+ bool is_parsing:1;
+ } state;
+
+ struct {
+ // Everything below here is pretty static.
+ bool auto_eject_hosts:1;
+ bool binary_protocol:1;
+ bool buffer_requests:1;
+ bool hash_with_namespace:1;
+ bool no_block:1; // Don't block
+ bool reply:1;
+ bool randomize_replica_read:1;
+ bool support_cas:1;
+ bool tcp_nodelay:1;
+ bool use_sort_hosts:1;
+ bool use_udp:1;
+ bool verify_key:1;
+ bool tcp_keepalive:1;
+ bool is_aes:1;
+ bool is_fetching_version:1;
+ bool not_used:1;
+ } flags;
+
+ memcached_server_distribution_t distribution;
+ hashkit_st hashkit;
+ struct {
+ unsigned int version;
+ } server_info;
+ uint32_t number_of_hosts;
+ memcached_instance_st *servers;
+ memcached_instance_st *last_disconnected_server;
+ int32_t snd_timeout;
+ int32_t rcv_timeout;
+ uint32_t server_failure_limit;
+ uint32_t server_timeout_limit;
+ uint32_t io_msg_watermark;
+ uint32_t io_bytes_watermark;
+ uint32_t io_key_prefetch;
+ uint32_t tcp_keepidle;
+ int32_t poll_timeout;
+ int32_t connect_timeout; // How long we will wait on connect() before we will timeout
+ int32_t retry_timeout;
+ int32_t dead_timeout;
+ int send_size;
+ int recv_size;
+ void *user_data;
+ uint64_t query_id;
+ uint32_t number_of_replicas;
+ memcached_result_st result;
+
+ struct {
+ bool weighted_;
+ uint32_t continuum_count; // Ketama
+ uint32_t continuum_points_counter; // Ketama
+ time_t next_distribution_rebuild; // Ketama
+ struct memcached_continuum_item_st *continuum; // Ketama
+ } ketama;
+
+ struct memcached_virtual_bucket_t *virtual_bucket;
+
+ struct memcached_allocator_t allocators;
+
+ memcached_clone_fn on_clone;
+ memcached_cleanup_fn on_cleanup;
+ memcached_trigger_key_fn get_key_failure;
+ memcached_trigger_delete_key_fn delete_trigger;
+ memcached_callback_st *callbacks;
+ struct memcached_sasl_st sasl;
+ struct memcached_error_t *error_messages;
+ struct memcached_array_st *_namespace;
+ struct {
+ uint32_t initial_pool_size;
+ uint32_t max_pool_size;
+ int32_t version; // This is used by pool and others to determine if the memcached_st is out of date.
+ struct memcached_array_st *filename;
+ } configure;
+ struct {
+ bool is_allocated:1;
+ } options;
+
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+struct memcached_result_st {
+ uint32_t item_flags;
+ time_t item_expiration;
+ size_t key_length;
+ uint64_t item_cas;
+ struct memcached_st *root;
+ memcached_string_st value;
+ uint64_t numeric_value;
+ uint64_t count;
+ char item_key[MEMCACHED_MAX_KEY];
+ struct {
+ bool is_allocated:1;
+ bool is_initialized:1;
+ } options;
+ /* Add result callback function */
+};
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#if defined(LIBMEMCACHED_WITH_SASL_SUPPORT) && LIBMEMCACHED_WITH_SASL_SUPPORT
+#include <sasl/sasl.h>
+#else
+#define sasl_callback_t void
+#endif
+
+#pragma once
+
+struct memcached_sasl_st {
+ sasl_callback_t *callbacks;
+ /*
+ ** Did we allocate data inside the callbacks, or did the user
+ ** supply that.
+ */
+ bool is_allocated;
+};
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+
+#ifdef NI_MAXHOST
+# define MEMCACHED_NI_MAXHOST NI_MAXHOST
+#else
+# define MEMCACHED_NI_MAXHOST 1025
+#endif
+
+#ifdef NI_MAXSERV
+# define MEMCACHED_NI_MAXSERV NI_MAXSERV
+#else
+# define MEMCACHED_NI_MAXSERV 32
+#endif
+
+enum memcached_server_state_t {
+ MEMCACHED_SERVER_STATE_NEW, // fd == -1, no address lookup has been done
+ MEMCACHED_SERVER_STATE_ADDRINFO, // ADDRRESS information has been gathered
+ MEMCACHED_SERVER_STATE_IN_PROGRESS,
+ MEMCACHED_SERVER_STATE_CONNECTED,
+ MEMCACHED_SERVER_STATE_IN_TIMEOUT,
+ MEMCACHED_SERVER_STATE_DISABLED
+};
+
+struct memcached_server_st {
+ struct {
+ bool is_allocated:1;
+ bool is_initialized:1;
+ bool is_shutting_down:1;
+ bool is_dead:1;
+ } options;
+ uint32_t number_of_hosts;
+ uint32_t cursor_active;
+ in_port_t port;
+ uint32_t io_bytes_sent; /* # bytes sent since last read */
+ uint32_t request_id;
+ uint32_t server_failure_counter;
+ uint64_t server_failure_counter_query_id;
+ uint32_t server_timeout_counter;
+ uint64_t server_timeout_counter_query_id;
+ uint32_t weight;
+ uint32_t version;
+ enum memcached_server_state_t state;
+ struct {
+ uint32_t read;
+ uint32_t write;
+ uint32_t timeouts;
+ size_t _bytes_read;
+ } io_wait_count;
+ uint8_t major_version; // Default definition of UINT8_MAX means that it has not been set.
+ uint8_t micro_version; // ditto, and note that this is the third, not second version bit
+ uint8_t minor_version; // ditto
+ memcached_connection_t type;
+ time_t next_retry;
+ struct memcached_st *root;
+ uint64_t limit_maxbytes;
+ struct memcached_error_t *error_messages;
+ char hostname[MEMCACHED_NI_MAXHOST];
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+struct memcached_stat_st {
+ unsigned long connection_structures;
+ unsigned long curr_connections;
+ unsigned long curr_items;
+ pid_t pid;
+ unsigned long pointer_size;
+ unsigned long rusage_system_microseconds;
+ unsigned long rusage_system_seconds;
+ unsigned long rusage_user_microseconds;
+ unsigned long rusage_user_seconds;
+ unsigned long threads;
+ unsigned long time;
+ unsigned long total_connections;
+ unsigned long total_items;
+ unsigned long uptime;
+ unsigned long long bytes;
+ unsigned long long bytes_read;
+ unsigned long long bytes_written;
+ unsigned long long cmd_get;
+ unsigned long long cmd_set;
+ unsigned long long evictions;
+ unsigned long long get_hits;
+ unsigned long long get_misses;
+ unsigned long long limit_maxbytes;
+ char version[MEMCACHED_VERSION_STRING_LENGTH];
+ void *__future; // @todo create a new structure to place here for future usage
+ memcached_st *root;
+};
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+/**
+ Strings are always under our control so we make some assumptions
+ about them.
+
+ 1) is_initialized is always valid.
+ 2) A string once intialized will always be, until free where we
+ unset this flag.
+ 3) A string always has a root.
+*/
+
+struct memcached_string_st {
+ char *end;
+ char *string;
+ size_t current_size;
+ struct memcached_st *root;
+ struct {
+ bool is_allocated:1;
+ bool is_initialized:1;
+ } options;
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached C sasl test app
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * @file @brief C dummy test, aka testing C linking, etc
+ */
+
+#include <stdlib.h>
+
+#ifdef HAVE_SASL_SASL_H
+#include <sasl/sasl.h>
+#endif
+
+#include <libmemcached-1.0/memcached.h>
+
+int main(void)
+{
+ memcached_st *memc= memcached_create(NULL);
+
+ if (memc == NULL)
+ {
+ return EXIT_FAILURE;
+ }
+ memcached_free(memc);
+
+ return EXIT_SUCCESS;
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached C test app
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * @file @brief C dummy test, aka testing C linking, etc
+ */
+
+#include <stdlib.h>
+
+#include <libmemcached-1.0/memcached.h>
+
+int main(void)
+{
+ (void)memcached_success(MEMCACHED_SUCCESS);
+ (void)memcached_failed(MEMCACHED_SUCCESS);
+ (void)memcached_continue(MEMCACHED_SUCCESS);
+
+ memcached_st *memc= memcached_create(NULL);
+
+ if (memc == NULL)
+ {
+ return EXIT_FAILURE;
+ }
+ memcached_free(memc);
+
+ return EXIT_SUCCESS;
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached C++ test app
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * @file @brief C dummy test, aka testing C linking, etc
+ */
+
+#include <cstdlib>
+
+#include <libmemcached-1.0/memcached.h>
+
+int main(void)
+{
+ (void)memcached_success(MEMCACHED_SUCCESS);
+ (void)memcached_failed(MEMCACHED_SUCCESS);
+ (void)memcached_continue(MEMCACHED_SUCCESS);
+
+ memcached_st *memc= memcached_create(NULL);
+
+ if (memc == NULL)
+ {
+ return EXIT_FAILURE;
+ }
+
+ memcached_free(memc);
+
+ return EXIT_SUCCESS;
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+LIBMEMCACHED_API
+memcached_return_t memcached_touch(memcached_st *ptr,
+ const char *key, size_t key_length,
+ time_t expiration);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_touch_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ time_t expiration);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef memcached_return_t (*memcached_clone_fn)(memcached_st *destination, const memcached_st *source);
+typedef memcached_return_t (*memcached_cleanup_fn)(const memcached_st *ptr);
+
+/**
+ Trigger functions.
+*/
+typedef memcached_return_t (*memcached_trigger_key_fn)(const memcached_st *ptr,
+ const char *key, size_t key_length,
+ memcached_result_st *result);
+typedef memcached_return_t (*memcached_trigger_delete_key_fn)(const memcached_st *ptr,
+ const char *key, size_t key_length);
+
+typedef memcached_return_t (*memcached_dump_fn)(const memcached_st *ptr,
+ const char *key,
+ size_t key_length,
+ void *context);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifdef __cplusplus
+
+struct memcached_st;
+struct memcached_stat_st;
+struct memcached_analysis_st;
+struct memcached_result_st;
+struct memcached_array_st;
+struct memcached_error_t;
+
+// All of the flavors of memcache_server_st
+struct memcached_server_st;
+struct memcached_instance_st;
+typedef struct memcached_instance_st memcached_instance_st;
+typedef struct memcached_server_st *memcached_server_list_st;
+
+struct memcached_callback_st;
+
+// The following two structures are internal, and never exposed to users.
+struct memcached_string_st;
+struct memcached_string_t;
+struct memcached_continuum_item_st;
+
+#else
+
+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_array_st memcached_array_st;
+typedef struct memcached_error_t memcached_error_t;
+
+// All of the flavors of memcache_server_st
+typedef struct memcached_server_st memcached_server_st;
+typedef struct memcached_instance_st memcached_instance_st;
+typedef struct memcached_server_st *memcached_server_list_st;
+
+typedef struct memcached_callback_st memcached_callback_st;
+
+// The following two structures are internal, and never exposed to users.
+typedef struct memcached_string_st memcached_string_st;
+typedef struct memcached_string_t memcached_string_t;
+
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+enum memcached_behavior_t {
+ 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_TCP_KEEPALIVE,
+ MEMCACHED_BEHAVIOR_TCP_KEEPIDLE,
+ MEMCACHED_BEHAVIOR_LOAD_FROM_FILE,
+ MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS,
+ MEMCACHED_BEHAVIOR_DEAD_TIMEOUT,
+ MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT,
+ MEMCACHED_BEHAVIOR_MAX
+};
+
+#ifndef __cplusplus
+typedef enum memcached_behavior_t memcached_behavior_t;
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+enum memcached_callback_t {
+ MEMCACHED_CALLBACK_PREFIX_KEY = 0,
+ MEMCACHED_CALLBACK_USER_DATA = 1,
+ MEMCACHED_CALLBACK_CLEANUP_FUNCTION = 2,
+ MEMCACHED_CALLBACK_CLONE_FUNCTION = 3,
+ MEMCACHED_CALLBACK_GET_FAILURE = 7,
+ MEMCACHED_CALLBACK_DELETE_TRIGGER = 8,
+ MEMCACHED_CALLBACK_MAX,
+ MEMCACHED_CALLBACK_NAMESPACE= MEMCACHED_CALLBACK_PREFIX_KEY
+};
+
+#ifndef __cplusplus
+typedef enum memcached_callback_t memcached_callback_t;
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+enum memcached_connection_t {
+ MEMCACHED_CONNECTION_TCP,
+ MEMCACHED_CONNECTION_UDP,
+ MEMCACHED_CONNECTION_UNIX_SOCKET
+};
+
+#ifndef __cplusplus
+typedef enum memcached_connection_t memcached_connection_t;
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+enum memcached_hash_t {
+ 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_MURMUR3,
+ MEMCACHED_HASH_CUSTOM,
+ MEMCACHED_HASH_MAX
+};
+
+#ifndef __cplusplus
+typedef enum memcached_hash_t memcached_hash_t;
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+enum memcached_return_t {
+ MEMCACHED_SUCCESS,
+ MEMCACHED_FAILURE,
+ MEMCACHED_HOST_LOOKUP_FAILURE, // getaddrinfo() and getnameinfo() only
+ MEMCACHED_CONNECTION_FAILURE,
+ MEMCACHED_CONNECTION_BIND_FAILURE, // DEPRECATED, see MEMCACHED_HOST_LOOKUP_FAILURE
+ MEMCACHED_WRITE_FAILURE,
+ MEMCACHED_READ_FAILURE,
+ MEMCACHED_UNKNOWN_READ_FAILURE,
+ MEMCACHED_PROTOCOL_ERROR,
+ MEMCACHED_CLIENT_ERROR,
+ MEMCACHED_SERVER_ERROR, // Server returns "SERVER_ERROR"
+ MEMCACHED_ERROR, // Server returns "ERROR"
+ 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, // DEPRECATED
+ MEMCACHED_NOT_SUPPORTED,
+ MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */
+ MEMCACHED_FETCH_NOTFINISHED,
+ MEMCACHED_TIMEOUT,
+ MEMCACHED_BUFFERED,
+ MEMCACHED_BAD_KEY_PROVIDED,
+ MEMCACHED_INVALID_HOST_PROTOCOL,
+ MEMCACHED_SERVER_MARKED_DEAD,
+ MEMCACHED_UNKNOWN_STAT_KEY,
+ MEMCACHED_E2BIG,
+ MEMCACHED_INVALID_ARGUMENTS,
+ MEMCACHED_KEY_TOO_BIG,
+ MEMCACHED_AUTH_PROBLEM,
+ MEMCACHED_AUTH_FAILURE,
+ MEMCACHED_AUTH_CONTINUE,
+ MEMCACHED_PARSE_ERROR,
+ MEMCACHED_PARSE_USER_ERROR,
+ MEMCACHED_DEPRECATED,
+ MEMCACHED_IN_PROGRESS,
+ MEMCACHED_SERVER_TEMPORARILY_DISABLED,
+ MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE,
+ MEMCACHED_UNIX_SOCKET_PATH_TOO_BIG,
+ MEMCACHED_MAXIMUM_RETURN, /* Always add new error code before */
+ MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE= MEMCACHED_ERROR
+};
+
+#ifndef __cplusplus
+typedef enum memcached_return_t memcached_return_t;
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+enum memcached_server_distribution_t {
+ MEMCACHED_DISTRIBUTION_MODULA,
+ MEMCACHED_DISTRIBUTION_CONSISTENT,
+ MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA,
+ MEMCACHED_DISTRIBUTION_RANDOM,
+ MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY,
+ MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED,
+ MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET,
+ MEMCACHED_DISTRIBUTION_CONSISTENT_MAX
+};
+
+#ifndef __cplusplus
+typedef enum memcached_server_distribution_t memcached_server_distribution_t;
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_verbosity(memcached_st *ptr, uint32_t verbosity);
+
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_version(memcached_st *ptr);
+
+LIBMEMCACHED_API
+const char * memcached_lib_version(void);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* 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.
+ *
+ * Author: Trond Norbye
+ *
+ */
+
+/**
+ * @file
+ * @brief Visibility control macros
+ */
+
+#pragma once
+
+/**
+ *
+ * LIBMEMCACHED_API is used for the public API symbols. It either DLL imports or
+ * DLL exports (or does nothing for static build).
+ *
+ * LIBMEMCACHED_LOCAL is used for non-api symbols.
+ */
+
+#if defined(BUILDING_LIBMEMCACHEDINTERNAL)
+# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
+# define LIBMEMCACHED_API __attribute__ ((visibility("default")))
+# define LIBMEMCACHED_LOCAL __attribute__ ((visibility("default")))
+# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+# define LIBMEMCACHED_API __global
+# define LIBMEMCACHED_LOCAL __global
+# elif defined(_MSC_VER)
+# define LIBMEMCACHED_API extern __declspec(dllexport)
+# define LIBMEMCACHED_LOCAL extern __declspec(dllexport)
+# else
+# define LIBMEMCACHED_API
+# define LIBMEMCACHED_LOCAL
+# endif
+#else
+# if defined(BUILDING_LIBMEMCACHED)
+# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
+# define LIBMEMCACHED_API __attribute__ ((visibility("default")))
+# define LIBMEMCACHED_LOCAL __attribute__ ((visibility("hidden")))
+# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+# define LIBMEMCACHED_API __global
+# define LIBMEMCACHED_LOCAL __hidden
+# elif defined(_MSC_VER)
+# define LIBMEMCACHED_API extern __declspec(dllexport)
+# define LIBMEMCACHED_LOCAL
+# else
+# define LIBMEMCACHED_API
+# define LIBMEMCACHED_LOCAL
+# endif /* defined(HAVE_VISIBILITY) */
+# else /* defined(BUILDING_LIBMEMCACHED) */
+# if defined(_MSC_VER)
+# define LIBMEMCACHED_API extern __declspec(dllimport)
+# define LIBMEMCACHED_LOCAL
+# else
+# define LIBMEMCACHED_API
+# define LIBMEMCACHED_LOCAL
+# endif /* defined(_MSC_VER) */
+# endif /* defined(BUILDING_LIBMEMCACHED) */
+#endif /* defined(BUILDING_LIBMEMCACHEDINTERNAL) */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) <2008>, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Summary: Constants used by to implement the binary protocol.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Trond Norbye <trond.norbye@sun.com>
+ */
+
+#ifndef PROTOCOL_BINARY_H
+#define PROTOCOL_BINARY_H
+
+#include <libmemcachedprotocol-0.0/vbucket.h>
+
+/**
+ * \addtogroup Protocol
+ * @{
+ */
+
+/**
+ * This file contains definitions of the constants and packet formats
+ * defined in the binary specification. Please note that you _MUST_ remember
+ * to convert each multibyte field to / from network byte order to / from
+ * host order.
+ */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /**
+ * Definition of the legal "magic" values used in a packet.
+ * See section 3.1 Magic byte
+ */
+ typedef enum {
+ PROTOCOL_BINARY_REQ = 0x80,
+ PROTOCOL_BINARY_RES = 0x81
+ } protocol_binary_magic;
+
+ /**
+ * Definition of the valid response status numbers.
+ * See section 3.2 Response Status
+ */
+ typedef enum {
+ PROTOCOL_BINARY_RESPONSE_SUCCESS = 0x00,
+ PROTOCOL_BINARY_RESPONSE_KEY_ENOENT = 0x01,
+ PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS = 0x02,
+ PROTOCOL_BINARY_RESPONSE_E2BIG = 0x03,
+ PROTOCOL_BINARY_RESPONSE_EINVAL = 0x04,
+ PROTOCOL_BINARY_RESPONSE_NOT_STORED = 0x05,
+ PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL = 0x06,
+ PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET = 0x07,
+ PROTOCOL_BINARY_RESPONSE_AUTH_ERROR = 0x20,
+ PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE = 0x21,
+ PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND = 0x81,
+ PROTOCOL_BINARY_RESPONSE_ENOMEM = 0x82,
+ PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED = 0x83,
+ PROTOCOL_BINARY_RESPONSE_EINTERNAL = 0x84,
+ PROTOCOL_BINARY_RESPONSE_EBUSY = 0x85,
+ PROTOCOL_BINARY_RESPONSE_ETMPFAIL = 0x86
+ } protocol_binary_response_status;
+
+ /**
+ * Defintion of the different command opcodes.
+ * See section 3.3 Command Opcodes
+ */
+ typedef enum {
+ PROTOCOL_BINARY_CMD_GET = 0x00,
+ PROTOCOL_BINARY_CMD_SET = 0x01,
+ PROTOCOL_BINARY_CMD_ADD = 0x02,
+ PROTOCOL_BINARY_CMD_REPLACE = 0x03,
+ PROTOCOL_BINARY_CMD_DELETE = 0x04,
+ PROTOCOL_BINARY_CMD_INCREMENT = 0x05,
+ PROTOCOL_BINARY_CMD_DECREMENT = 0x06,
+ PROTOCOL_BINARY_CMD_QUIT = 0x07,
+ PROTOCOL_BINARY_CMD_FLUSH = 0x08,
+ PROTOCOL_BINARY_CMD_GETQ = 0x09,
+ PROTOCOL_BINARY_CMD_NOOP = 0x0a,
+ PROTOCOL_BINARY_CMD_VERSION = 0x0b,
+ PROTOCOL_BINARY_CMD_GETK = 0x0c,
+ PROTOCOL_BINARY_CMD_GETKQ = 0x0d,
+ PROTOCOL_BINARY_CMD_APPEND = 0x0e,
+ PROTOCOL_BINARY_CMD_PREPEND = 0x0f,
+ PROTOCOL_BINARY_CMD_STAT = 0x10,
+ PROTOCOL_BINARY_CMD_SETQ = 0x11,
+ PROTOCOL_BINARY_CMD_ADDQ = 0x12,
+ PROTOCOL_BINARY_CMD_REPLACEQ = 0x13,
+ PROTOCOL_BINARY_CMD_DELETEQ = 0x14,
+ PROTOCOL_BINARY_CMD_INCREMENTQ = 0x15,
+ PROTOCOL_BINARY_CMD_DECREMENTQ = 0x16,
+ PROTOCOL_BINARY_CMD_QUITQ = 0x17,
+ PROTOCOL_BINARY_CMD_FLUSHQ = 0x18,
+ PROTOCOL_BINARY_CMD_APPENDQ = 0x19,
+ PROTOCOL_BINARY_CMD_PREPENDQ = 0x1a,
+ PROTOCOL_BINARY_CMD_VERBOSITY = 0x1b,
+ PROTOCOL_BINARY_CMD_TOUCH = 0x1c,
+ PROTOCOL_BINARY_CMD_GAT = 0x1d,
+ PROTOCOL_BINARY_CMD_GATQ = 0x1e,
+ PROTOCOL_BINARY_CMD_GATK = 0x23,
+ PROTOCOL_BINARY_CMD_GATKQ = 0x24,
+
+ PROTOCOL_BINARY_CMD_SASL_LIST_MECHS = 0x20,
+ PROTOCOL_BINARY_CMD_SASL_AUTH = 0x21,
+ PROTOCOL_BINARY_CMD_SASL_STEP = 0x22,
+
+ /* These commands are used for range operations and exist within
+ * this header for use in other projects. Range operations are
+ * not expected to be implemented in the memcached server itself.
+ */
+ PROTOCOL_BINARY_CMD_RGET = 0x30,
+ PROTOCOL_BINARY_CMD_RSET = 0x31,
+ PROTOCOL_BINARY_CMD_RSETQ = 0x32,
+ PROTOCOL_BINARY_CMD_RAPPEND = 0x33,
+ PROTOCOL_BINARY_CMD_RAPPENDQ = 0x34,
+ PROTOCOL_BINARY_CMD_RPREPEND = 0x35,
+ PROTOCOL_BINARY_CMD_RPREPENDQ = 0x36,
+ PROTOCOL_BINARY_CMD_RDELETE = 0x37,
+ PROTOCOL_BINARY_CMD_RDELETEQ = 0x38,
+ PROTOCOL_BINARY_CMD_RINCR = 0x39,
+ PROTOCOL_BINARY_CMD_RINCRQ = 0x3a,
+ PROTOCOL_BINARY_CMD_RDECR = 0x3b,
+ PROTOCOL_BINARY_CMD_RDECRQ = 0x3c,
+ /* End Range operations */
+
+ /* VBucket commands */
+ PROTOCOL_BINARY_CMD_SET_VBUCKET = 0x3d,
+ PROTOCOL_BINARY_CMD_GET_VBUCKET = 0x3e,
+ PROTOCOL_BINARY_CMD_DEL_VBUCKET = 0x3f,
+ /* End VBucket commands */
+
+ /* TAP commands */
+ PROTOCOL_BINARY_CMD_TAP_CONNECT = 0x40,
+ PROTOCOL_BINARY_CMD_TAP_MUTATION = 0x41,
+ PROTOCOL_BINARY_CMD_TAP_DELETE = 0x42,
+ PROTOCOL_BINARY_CMD_TAP_FLUSH = 0x43,
+ PROTOCOL_BINARY_CMD_TAP_OPAQUE = 0x44,
+ PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET = 0x45,
+ PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START = 0x46,
+ PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END = 0x47,
+ /* End TAP */
+
+ PROTOCOL_BINARY_CMD_LAST_RESERVED = 0xef,
+
+ /* Scrub the data */
+ PROTOCOL_BINARY_CMD_SCRUB = 0xf0
+ } protocol_binary_command;
+
+ /**
+ * Definition of the data types in the packet
+ * See section 3.4 Data Types
+ */
+ typedef enum {
+ PROTOCOL_BINARY_RAW_BYTES = 0x00
+ } protocol_binary_datatypes;
+
+ /**
+ * Definition of the header structure for a request packet.
+ * See section 2
+ */
+ typedef union {
+ struct {
+ uint8_t magic;
+ uint8_t opcode;
+ uint16_t keylen;
+ uint8_t extlen;
+ uint8_t datatype;
+ uint16_t vbucket;
+ uint32_t bodylen;
+ uint32_t opaque;
+ uint64_t cas;
+ } request;
+ uint8_t bytes[24];
+ } protocol_binary_request_header;
+
+ /**
+ * Definition of the header structure for a response packet.
+ * See section 2
+ */
+ typedef union {
+ struct {
+ uint8_t magic;
+ uint8_t opcode;
+ uint16_t keylen;
+ uint8_t extlen;
+ uint8_t datatype;
+ uint16_t status;
+ uint32_t bodylen;
+ uint32_t opaque;
+ uint64_t cas;
+ } response;
+ uint8_t bytes[24];
+ } protocol_binary_response_header;
+
+ /**
+ * Definition of a request-packet containing no extras
+ */
+ union protocol_binary_request_no_extras {
+ struct {
+ protocol_binary_request_header header;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header)];
+ };
+ typedef union protocol_binary_request_no_extras protocol_binary_request_no_extras;
+
+ /**
+ * Definition of a response-packet containing no extras
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_response_header)];
+ } protocol_binary_response_no_extras;
+
+ /**
+ * Definition of the packet used by the get, getq, getk and getkq command.
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_get;
+ typedef protocol_binary_request_no_extras protocol_binary_request_getq;
+ typedef protocol_binary_request_no_extras protocol_binary_request_getk;
+ typedef protocol_binary_request_no_extras protocol_binary_request_getkq;
+
+ /**
+ * Definition of the packet returned from a successful get, getq, getk and
+ * getkq.
+ * See section 4
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ struct {
+ uint32_t flags;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_response_header) + 4];
+ } protocol_binary_response_get;
+
+ typedef protocol_binary_response_get protocol_binary_response_getq;
+ typedef protocol_binary_response_get protocol_binary_response_getk;
+ typedef protocol_binary_response_get protocol_binary_response_getkq;
+
+ /**
+ * Definition of the packet used by the delete command
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_delete;
+
+ /**
+ * Definition of the packet returned by the delete command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_delete;
+
+ /**
+ * Definition of the packet used by the flush command
+ * See section 4
+ * Please note that the expiration field is optional, so remember to see
+ * check the header.bodysize to see if it is present.
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_flush;
+
+ /**
+ * Definition of the packet returned by the flush command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_flush;
+
+ /**
+ * Definition of the packet used by set, add and replace
+ * See section 4
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t flags;
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 8];
+ } protocol_binary_request_set;
+ typedef protocol_binary_request_set protocol_binary_request_add;
+ typedef protocol_binary_request_set protocol_binary_request_replace;
+
+ /**
+ * Definition of the packet returned by set, add and replace
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_set;
+ typedef protocol_binary_response_no_extras protocol_binary_response_add;
+ typedef protocol_binary_response_no_extras protocol_binary_response_replace;
+
+ /**
+ * Definition of the noop packet
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_noop;
+
+ /**
+ * Definition of the packet returned by the noop command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_noop;
+
+ /**
+ * Definition of the structure used by the increment and decrement
+ * command.
+ * See section 4
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint64_t delta;
+ uint64_t initial;
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 20];
+ } protocol_binary_request_incr;
+ typedef protocol_binary_request_incr protocol_binary_request_decr;
+
+ /**
+ * Definition of the response from an incr or decr command
+ * command.
+ * See section 4
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ struct {
+ uint64_t value;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_response_header) + 8];
+ } protocol_binary_response_incr;
+ typedef protocol_binary_response_incr protocol_binary_response_decr;
+
+ /**
+ * Definition of the quit
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_quit;
+
+ /**
+ * Definition of the packet returned by the quit command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_quit;
+
+ /**
+ * Definition of the packet used by append and prepend command
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_append;
+ typedef protocol_binary_request_no_extras protocol_binary_request_prepend;
+
+ /**
+ * Definition of the packet returned from a successful append or prepend
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_append;
+ typedef protocol_binary_response_no_extras protocol_binary_response_prepend;
+
+ /**
+ * Definition of the packet used by the version command
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_version;
+
+ /**
+ * Definition of the packet returned from a successful version command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_version;
+
+
+ /**
+ * Definition of the packet used by the stats command.
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_stats;
+
+ /**
+ * Definition of the packet returned from a successful stats command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_stats;
+
+ /**
+ * Definition of the packet used by the verbosity command
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t level;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_verbosity;
+
+ /**
+ * Definition of the packet returned from the verbosity command
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_verbosity;
+
+ /**
+ * Definition of the packet used by the touch command.
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_touch;
+
+ /**
+ * Definition of the packet returned from the touch command
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_touch;
+
+ /**
+ * Definition of the packet used by the GAT(Q) command.
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_gat;
+
+ typedef protocol_binary_request_gat protocol_binary_request_gatq;
+
+ /**
+ * Definition of the packet returned from the GAT(Q)
+ */
+ typedef protocol_binary_response_get protocol_binary_response_gat;
+ typedef protocol_binary_response_get protocol_binary_response_gatq;
+
+
+ /**
+ * Definition of a request for a range operation.
+ * See http://code.google.com/p/memcached/wiki/RangeOps
+ *
+ * These types are used for range operations and exist within
+ * this header for use in other projects. Range operations are
+ * not expected to be implemented in the memcached server itself.
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ struct {
+ uint16_t size;
+ uint8_t reserved;
+ uint8_t flags;
+ uint32_t max_results;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_rangeop;
+
+ typedef protocol_binary_request_rangeop protocol_binary_request_rget;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rset;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rsetq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rappend;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rappendq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rprepend;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rprependq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rdelete;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rdeleteq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rincr;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rincrq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rdecr;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rdecrq;
+
+
+ /**
+ * Definition of tap commands
+ * See To be written
+ *
+ */
+
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ /**
+ * flags is a bitmask used to set properties for the
+ * the connection. Please In order to be forward compatible
+ * you should set all undefined bits to 0.
+ *
+ * If the bit require extra userdata, it will be stored
+ * in the user-data field of the body (passed to the engine
+ * as enginespeciffic). That means that when you parse the
+ * flags and the engine-specific data, you have to work your
+ * way from bit 0 and upwards to find the correct offset for
+ * the data.
+ *
+ */
+ uint32_t flags;
+
+ /**
+ * Backfill age
+ *
+ * By using this flag you can limit the amount of data being
+ * transmitted. If you don't specify a backfill age, the
+ * server will transmit everything it contains.
+ *
+ * The first 8 bytes in the engine specific data contains
+ * the oldest entry (from epoc) you're interested in.
+ * Specifying a time in the future (for the server you are
+ * connecting to), will cause it to start streaming current
+ * changes.
+ */
+#define TAP_CONNECT_FLAG_BACKFILL 0x01
+ /**
+ * Dump will cause the server to send the data stored on the
+ * server, but disconnect when the keys stored in the server
+ * are transmitted.
+ */
+#define TAP_CONNECT_FLAG_DUMP 0x02
+ /**
+ * The body contains a list of 16 bits words in network byte
+ * order specifying the vbucket ids to monitor. The first 16
+ * bit word contains the number of buckets. The number of 0
+ * means "all buckets"
+ */
+#define TAP_CONNECT_FLAG_LIST_VBUCKETS 0x04
+ /**
+ * The responsibility of the vbuckets is to be transferred
+ * over to the caller when all items are transferred.
+ */
+#define TAP_CONNECT_FLAG_TAKEOVER_VBUCKETS 0x08
+ /**
+ * The tap consumer supports ack'ing of tap messages
+ */
+#define TAP_CONNECT_SUPPORT_ACK 0x10
+ /**
+ * The tap consumer would prefer to just get the keys
+ * back. If the engine supports this it will set
+ * the TAP_FLAG_NO_VALUE flag in each of the
+ * tap packets returned.
+ */
+#define TAP_CONNECT_REQUEST_KEYS_ONLY 0x20
+ /**
+ * The body contains a list of (vbucket_id, last_checkpoint_id)
+ * pairs. This provides the checkpoint support in TAP streams.
+ * The last checkpoint id represents the last checkpoint that
+ * was successfully persisted.
+ */
+#define TAP_CONNECT_CHECKPOINT 0x40
+ /**
+ * The tap consumer is a registered tap client, which means that
+ * the tap server will maintain its checkpoint cursor permanently.
+ */
+#define TAP_CONNECT_REGISTERED_CLIENT 0x80
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_tap_connect;
+
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ struct {
+ uint16_t enginespecific_length;
+ /*
+ * The flag section support the following flags
+ */
+ /**
+ * Request that the consumer send a response packet
+ * for this packet. The opaque field must be preserved
+ * in the response.
+ */
+#define TAP_FLAG_ACK 0x01
+ /**
+ * The value for the key is not included in the packet
+ */
+#define TAP_FLAG_NO_VALUE 0x02
+ uint16_t flags;
+ uint8_t ttl;
+ uint8_t res1;
+ uint8_t res2;
+ uint8_t res3;
+ } tap;
+ struct {
+ uint32_t flags;
+ uint32_t expiration;
+ } item;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 16];
+ } protocol_binary_request_tap_mutation;
+
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ struct {
+ uint16_t enginespecific_length;
+ /**
+ * See the definition of the flags for
+ * protocol_binary_request_tap_mutation for a description
+ * of the available flags.
+ */
+ uint16_t flags;
+ uint8_t ttl;
+ uint8_t res1;
+ uint8_t res2;
+ uint8_t res3;
+ } tap;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 8];
+ } protocol_binary_request_tap_no_extras;
+
+ typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_delete;
+ typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_flush;
+ typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_opaque;
+ typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_vbucket_set;
+
+
+ /**
+ * Definition of the packet used by the scrub.
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_scrub;
+
+ /**
+ * Definition of the packet returned from scrub.
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_scrub;
+
+
+ /**
+ * Definition of the packet used by set vbucket
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ vbucket_state_t state;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + sizeof(vbucket_state_t)];
+ } protocol_binary_request_set_vbucket;
+ /**
+ * Definition of the packet returned from set vbucket
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_set_vbucket;
+ /**
+ * Definition of the packet used by del vbucket
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_del_vbucket;
+ /**
+ * Definition of the packet returned from del vbucket
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_del_vbucket;
+
+ /**
+ * Definition of the packet used by get vbucket
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_get_vbucket;
+
+ /**
+ * Definition of the packet returned from get vbucket
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ struct {
+ vbucket_state_t state;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_response_header) + sizeof(vbucket_state_t)];
+ } protocol_binary_response_get_vbucket;
+
+
+ /**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* PROTOCOL_BINARY_H */
--- /dev/null
+/*
+ * Summary: Definition of the callback interface
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Trond Norbye
+ */
+
+#pragma once
+
+/**
+ * Callback to send data back from a successful GET/GETQ/GETK/GETKQ command
+ *
+ * @param cookie Just pass along the cookie supplied in the callback
+ * @param key What to insert as key in the reply
+ * @param keylen The length of the key
+ * @param body What to store in the body of the package
+ * @param bodylen The number of bytes of the body
+ * @param flags The flags stored with the item
+ * @param cas The CAS value to insert into the response (should be 0
+ * if you don't care)
+ */
+typedef protocol_binary_response_status
+(*memcached_binary_protocol_get_response_handler)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void *body,
+ uint32_t bodylen,
+ uint32_t flags,
+ uint64_t cas);
+/**
+ * Callback to send data back from a STAT command
+ *
+ * @param cookie Just pass along the cookie supplied in the callback
+ * @param key What to insert as key in the reply
+ * @param keylen The length of the key
+ * @param body What to store in the body of the package
+ * @param bodylen The number of bytes of the body
+ */
+typedef protocol_binary_response_status
+(*memcached_binary_protocol_stat_response_handler)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void *body,
+ uint32_t bodylen);
+/**
+ * Callback to send data back from a VERSION command
+ *
+ * @param cookie Just pass along the cookie supplied in the callback
+ * @param text The version string
+ * @param length The number of bytes in the version string
+ */
+typedef protocol_binary_response_status
+(*memcached_binary_protocol_version_response_handler)(const void *cookie,
+ const void *text,
+ uint32_t length);
+
+
+/**
+ * In the low level interface you need to format the response
+ * packet yourself (giving you complete freedom :-)
+ *
+ * @param cookie Just pass along the cookie supplied in the callback
+ * @param request Pointer to the request packet you are sending a reply to
+ * @param response Pointer to the response packet to send
+ *
+ */
+typedef protocol_binary_response_status (*memcached_binary_protocol_raw_response_handler)(const void *cookie,
+ protocol_binary_request_header *request,
+ protocol_binary_response_header *response);
+
+/**
+ * In the low lever interface you have to do most of the work by
+ * yourself, but it also gives you a lot of freedom :-)
+ * @param cookie identification for this connection, just pass it along to
+ * the response handler
+ * @param header the command received over the wire. Never try to access
+ * <u>anything</u> outside the command.
+ * @param resonse_handler call this function to send data back to the client
+ */
+typedef protocol_binary_response_status (*memcached_binary_protocol_command_handler)(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler);
+
+/**
+ * The raw interface to the packets is implemented in version 0. It contains
+ * just an array with command handlers. The inxed in the array is the
+ * com code.
+ */
+typedef struct {
+ memcached_binary_protocol_command_handler comcode[256];
+} memcached_binary_protocol_callback_v0_st;
+
+
+/**
+ * The first version of the callback struct containing all of the
+ * documented commands in the initial release of the binary protocol
+ * (aka. memcached 1.4.0).
+ *
+ * You might miss the Q commands (addq etc) but the response function
+ * knows how to deal with them so you don't need to worry about that :-)
+ */
+typedef struct {
+ /**
+ * Add an item to the cache
+ * @param cookie id of the client receiving the command
+ * @param key the key to add
+ * @param len the length of the key
+ * @param val the value to store for the key (may be NIL)
+ * @param vallen the length of the data
+ * @param flags the flags to store with the key
+ * @param exptime the expiry time for the key-value pair
+ * @param cas the resulting cas for the add operation (if success)
+ */
+ protocol_binary_response_status (*add)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* val,
+ uint32_t vallen,
+ uint32_t flags,
+ uint32_t exptime,
+ uint64_t *cas);
+
+ /**
+ * Append data to an <b>existing</b> key-value pair.
+ *
+ * @param cookie id of the client receiving the command
+ * @param key the key to add data to
+ * @param len the length of the key
+ * @param val the value to append to the value
+ * @param vallen the length of the data
+ * @param cas the CAS in the request
+ * @param result_cas the resulting cas for the append operation
+ *
+ */
+ protocol_binary_response_status (*append)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* val,
+ uint32_t vallen,
+ uint64_t cas,
+ uint64_t *result_cas);
+
+ /**
+ * Decrement the value for a key
+ *
+ * @param cookie id of the client receiving the command
+ * @param key the key to decrement the value for
+ * @param len the length of the key
+ * @param delta the amount to decrement
+ * @param initial initial value to store (if the key doesn't exist)
+ * @param expiration expiration time for the object (if the key doesn't exist)
+ * @param cas the CAS in the request
+ * @param result the result from the decrement
+ * @param result_cas the cas of the item
+ *
+ */
+ protocol_binary_response_status (*decrement)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ uint64_t delta,
+ uint64_t initial,
+ uint32_t expiration,
+ uint64_t *result,
+ uint64_t *result_cas);
+
+ /**
+ * Delete an existing key
+ *
+ * @param cookie id of the client receiving the command
+ * @param key the key to delete_object
+ * @param len the length of the key
+ * @param cas the CAS in the request
+ */
+ protocol_binary_response_status (*delete_object)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ uint64_t cas);
+
+
+ /**
+ * Flush the cache
+ *
+ * @param cookie id of the client receiving the command
+ * @param when when the cache should be flushed (0 == immediately)
+ */
+ protocol_binary_response_status (*flush_object)(const void *cookie,
+ uint32_t when);
+
+
+
+ /**
+ * Get a key-value pair
+ *
+ * @param cookie id of the client receiving the command
+ * @param key the key to get
+ * @param len the length of the key
+ * @param response_handler to send the result back to the client
+ */
+ protocol_binary_response_status (*get)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ memcached_binary_protocol_get_response_handler response_handler);
+
+ /**
+ * Increment the value for a key
+ *
+ * @param cookie id of the client receiving the command
+ * @param key the key to increment the value on
+ * @param len the length of the key
+ * @param delta the amount to increment
+ * @param initial initial value to store (if the key doesn't exist)
+ * @param expiration expiration time for the object (if the key doesn't exist)
+ * @param cas the CAS in the request
+ * @param result the result from the decrement
+ * @param result_cas the cas of the item
+ *
+ */
+ protocol_binary_response_status (*increment)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ uint64_t delta,
+ uint64_t initial,
+ uint32_t expiration,
+ uint64_t *result,
+ uint64_t *result_cas);
+
+ /**
+ * The noop command was received. This is just a notification callback (the
+ * response is automatically created).
+ *
+ * @param cookie id of the client receiving the command
+ */
+ protocol_binary_response_status (*noop)(const void *cookie);
+
+ /**
+ * Prepend data to an <b>existing</b> key-value pair.
+ *
+ * @param cookie id of the client receiving the command
+ * @param key the key to prepend data to
+ * @param len the length of the key
+ * @param val the value to prepend to the value
+ * @param vallen the length of the data
+ * @param cas the CAS in the request
+ * @param result-cas the cas id of the item
+ *
+ */
+ protocol_binary_response_status (*prepend)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* val,
+ uint32_t vallen,
+ uint64_t cas,
+ uint64_t *result_cas);
+
+ /**
+ * The quit command was received. This is just a notification callback (the
+ * response is automatically created).
+ *
+ * @param cookie id of the client receiving the command
+ */
+ protocol_binary_response_status (*quit)(const void *cookie);
+
+
+ /**
+ * Replace an <b>existing</b> item to the cache
+ *
+ * @param cookie id of the client receiving the command
+ * @param key the key to replace the content for
+ * @param len the length of the key
+ * @param val the value to store for the key (may be NIL)
+ * @param vallen the length of the data
+ * @param flags the flags to store with the key
+ * @param exptime the expiry time for the key-value pair
+ * @param cas the cas id in the request
+ * @param result_cas the cas id of the item
+ */
+ protocol_binary_response_status (*replace)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* val,
+ uint32_t vallen,
+ uint32_t flags,
+ uint32_t exptime,
+ uint64_t cas,
+ uint64_t *result_cas);
+
+
+ /**
+ * Set a key-value pair in the cache
+ *
+ * @param cookie id of the client receiving the command
+ * @param key the key to insert
+ * @param len the length of the key
+ * @param val the value to store for the key (may be NIL)
+ * @param vallen the length of the data
+ * @param flags the flags to store with the key
+ * @param exptime the expiry time for the key-value pair
+ * @param cas the cas id in the request
+ * @param result_cas the cas id of the new item
+ */
+ protocol_binary_response_status (*set)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* val,
+ uint32_t vallen,
+ uint32_t flags,
+ uint32_t exptime,
+ uint64_t cas,
+ uint64_t *result_cas);
+
+ /**
+ * Get status information
+ *
+ * @param cookie id of the client receiving the command
+ * @param key the key to get status for (or NIL to request all status).
+ * Remember to insert the terminating packet if multiple
+ * packets should be returned.
+ * @param keylen the length of the key
+ * @param response_handler to send the result back to the client, but
+ * don't send reply on success!
+ *
+ */
+ protocol_binary_response_status (*stat)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ memcached_binary_protocol_stat_response_handler response_handler);
+
+ /**
+ * Get the version information
+ *
+ * @param cookie id of the client receiving the command
+ * @param response_handler to send the result back to the client, but
+ * don't send reply on success!
+ *
+ */
+ protocol_binary_response_status (*version)(const void *cookie,
+ memcached_binary_protocol_version_response_handler response_handler);
+} memcached_binary_protocol_callback_v1_st;
+
+
+/**
+ * The version numbers for the different callback structures.
+ */
+typedef enum {
+ /** Version 0 is a lowlevel interface that tries to maximize your freedom */
+ MEMCACHED_PROTOCOL_HANDLER_V0= 0,
+ /**
+ * Version 1 abstracts more of the protocol details, and let you work at
+ * a logical level
+ */
+ MEMCACHED_PROTOCOL_HANDLER_V1= 1
+} memcached_protocol_interface_version_t;
+
+/**
+ * Definition of the protocol callback structure.
+ */
+typedef struct {
+ /**
+ * The interface version you provide callbacks for.
+ */
+ memcached_protocol_interface_version_t interface_version;
+
+ /**
+ * Callback fired just before the command will be executed.
+ *
+ * @param cookie id of the client receiving the command
+ * @param header the command header as received on the wire. If you look
+ * at the content you <b>must</b> ensure that you don't
+ * try to access beyond the end of the message.
+ */
+ void (*pre_execute)(const void *cookie,
+ protocol_binary_request_header *header);
+ /**
+ * Callback fired just after the command was exected (please note
+ * that the data transfer back to the client is not finished at this
+ * time).
+ *
+ * @param cookie id of the client receiving the command
+ * @param header the command header as received on the wire. If you look
+ * at the content you <b>must</b> ensure that you don't
+ * try to access beyond the end of the message.
+ */
+ void (*post_execute)(const void *cookie,
+ protocol_binary_request_header *header);
+
+ /**
+ * Callback fired if no specialized callback is registered for this
+ * specific command code.
+ *
+ * @param cookie id of the client receiving the command
+ * @param header the command header as received on the wire. You <b>must</b>
+ * ensure that you don't try to access beyond the end of the
+ * message.
+ * @param response_handler The response handler to send data back.
+ */
+ protocol_binary_response_status (*unknown)(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler);
+
+ /**
+ * The different interface levels we support. A pointer is used so the
+ * size of the structure is fixed. You must ensure that the memory area
+ * passed as the pointer is valid as long as you use the protocol handler.
+ */
+ union {
+ memcached_binary_protocol_callback_v0_st v0;
+
+ /**
+ * The first version of the callback struct containing all of the
+ * documented commands in the initial release of the binary protocol
+ * (aka. memcached 1.4.0).
+ */
+ memcached_binary_protocol_callback_v1_st v1;
+ } interface;
+} memcached_binary_protocol_callback_st;
--- /dev/null
+/* 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: Definition of the callback interface to the protocol handler
+ *
+ * Author: Trond Norbye
+ *
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#if !defined(__cplusplus)
+# include <stdbool.h>
+#endif
+
+#include <libmemcached-1.0/visibility.h>
+#include <libmemcached-1.0/platform.h>
+#include <libmemcachedprotocol-0.0/binary.h>
+#include <libmemcachedprotocol-0.0/callback.h>
+
+/* Forward declarations */
+/*
+ * You should only access memcached_protocol_st from one thread!,
+ * and never assume anything about the internal layout / sizes of the
+ * structures.
+ */
+typedef struct memcached_protocol_st memcached_protocol_st;
+typedef struct memcached_protocol_client_st memcached_protocol_client_st;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Function the protocol handler should call to receive data.
+ * This function should behave exactly like read(2)
+ *
+ * @param cookie a cookie used to represent a given client
+ * @param fd the filedescriptor associated with the client
+ * @param buf destination buffer
+ * @param nbuf number of bytes to receive
+ * @return the number of bytes copied into buf
+ * or -1 upon error (errno should contain more information)
+ */
+typedef ssize_t (*memcached_protocol_recv_func)(const void *cookie,
+ memcached_socket_t fd,
+ void *buf,
+ size_t nbuf);
+
+/**
+ * Function the protocol handler should call to send data.
+ * This function should behave exactly like write(2)
+ *
+ * @param cookie a cookie used to represent a given client
+ * @param fd the filedescriptor associated with the client
+ * @param buf the source buffer
+ * @param nbuf number of bytes to send
+ * @return the number of bytes sent
+ * or -1 upon error (errno should contain more information)
+ */
+typedef ssize_t (*memcached_protocol_send_func)(const void *cookie,
+ memcached_socket_t fd,
+ const void *buf,
+ size_t nbuf);
+
+/**
+ * Create an instance of the protocol handler
+ *
+ * @return NULL if allocation of an instance fails
+ */
+LIBMEMCACHED_API
+memcached_protocol_st *memcached_protocol_create_instance(void);
+
+/**
+ * Get the callbacks associated with a protocol handler instance
+ * @return the callbacks currently used
+ */
+LIBMEMCACHED_API
+memcached_binary_protocol_callback_st *memcached_binary_protocol_get_callbacks(memcached_protocol_st *instance);
+
+/**
+ * Set the callbacks to be used by the given protocol handler instance
+ * @param instance the instance to update
+ * @param callback the callbacks to use
+ */
+LIBMEMCACHED_API
+void memcached_binary_protocol_set_callbacks(memcached_protocol_st *instance, memcached_binary_protocol_callback_st *callback);
+
+/**
+ * Should the library inspect the packages being sent and received and verify
+ * that they are according to the specification? If it encounters an invalid
+ * packet, it will return an EINVAL packet.
+ *
+ * @param instance the instance to update
+ * @param enable true if you want the library to check packages, false otherwise
+ */
+LIBMEMCACHED_API
+void memcached_binary_protocol_set_pedantic(memcached_protocol_st *instance, bool enable);
+
+/**
+ * Is the library inpecting each package?
+ * @param instance the instance to check
+ * @return true it the library is inspecting each package, false otherwise
+ */
+LIBMEMCACHED_API
+bool memcached_binary_protocol_get_pedantic(memcached_protocol_st *instance);
+
+/**
+ * Destroy an instance of the protocol handler
+ *
+ * @param instance The instance to destroy
+ */
+LIBMEMCACHED_API
+void memcached_protocol_destroy_instance(memcached_protocol_st *instance);
+
+/**
+ * Set the IO functions used by the instance to send and receive data. The
+ * functions should behave like recv(3socket) and send(3socket).
+ *
+ * @param instance the instance to specify the IO functions for
+ * @param recv the function to call for reciving data
+ * @param send the function to call for sending data
+ */
+LIBMEMCACHED_API
+void memached_protocol_set_io_functions(memcached_protocol_st *instance,
+ memcached_protocol_recv_func recv,
+ memcached_protocol_send_func send);
+
+
+/**
+ * Create a new client instance and associate it with a socket
+ * @param instance the protocol instance to bind the client to
+ * @param sock the client socket
+ * @return NULL if allocation fails, otherwise an instance
+ */
+LIBMEMCACHED_API
+memcached_protocol_client_st *memcached_protocol_create_client(memcached_protocol_st *instance, memcached_socket_t sock);
+
+/**
+ * Destroy a client handle.
+ * The caller needs to close the socket accociated with the client
+ * <b>before</b> calling this function. This function invalidates the
+ * client memory area.
+ *
+ * @param client the client to destroy
+ */
+LIBMEMCACHED_API
+void memcached_protocol_client_destroy(memcached_protocol_client_st *client);
+
+LIBMEMCACHED_API
+void memcached_protocol_client_set_verbose(struct memcached_protocol_client_st *client, bool arg);
+
+/**
+ * Error event means that the client encountered an error with the
+ * connection so you should shut it down
+ */
+#define MEMCACHED_PROTOCOL_ERROR_EVENT 1
+/**
+ * Please notify when there is more data available to read
+ */
+#define MEMCACHED_PROTOCOL_READ_EVENT 2
+/**
+ * Please notify when it is possible to send more data
+ */
+#define MEMCACHED_PROTOCOL_WRITE_EVENT 4
+/**
+ * Backed paused the execution for this client
+ */
+#define MEMCACHED_PROTOCOL_PAUSE_EVENT 8
+
+/**
+ * The different events the client is interested in. This is a bitmask of
+ * the constants defined above.
+ */
+typedef uint32_t memcached_protocol_event_t;
+
+/**
+ * Let the client do some work. This might involve reading / sending data
+ * to/from the client, or perform callbacks to execute a command.
+ * @param client the client structure to work on
+ * @return The next event the protocol handler will be notified for
+ */
+LIBMEMCACHED_API
+memcached_protocol_event_t memcached_protocol_client_work(memcached_protocol_client_st *client);
+
+/**
+ * Get the socket attached to a client handle
+ * @param client the client to query
+ * @return the socket handle
+ */
+LIBMEMCACHED_API
+memcached_socket_t memcached_protocol_client_get_socket(memcached_protocol_client_st *client);
+
+/**
+ * Get the error id socket attached to a client handle
+ * @param client the client to query for an error code
+ * @return the OS error code from the client
+ */
+LIBMEMCACHED_API
+int memcached_protocol_client_get_errno(memcached_protocol_client_st *client);
+
+/**
+ * Get a raw response handler for the given cookie
+ * @param cookie the cookie passed along into the callback
+ * @return the raw reponse handler you may use if you find
+ * the generic callback too limiting
+ */
+LIBMEMCACHED_API
+memcached_binary_protocol_raw_response_handler memcached_binary_protocol_get_raw_response_handler(const void *cookie);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef enum {
+ vbucket_state_active = 1, /**< Actively servicing a vbucket. */
+ vbucket_state_replica, /**< Servicing a vbucket as a replica only. */
+ vbucket_state_pending, /**< Pending active. */
+ vbucket_state_dead /**< Not in use, pending deletion. */
+} vbucket_state_t;
+
+#define is_valid_vbucket_state_t(state) \
+ (state == vbucket_state_active || \
+ state == vbucket_state_replica || \
+ state == vbucket_state_pending || \
+ state == vbucket_state_dead)
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ FILES_MATCHING REGEX "\\.h(pp)?$"
+ )
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+bool libmemcached_util_flush(const char *hostname, in_port_t port, memcached_return_t *ret);
+
+#ifdef __cplusplus
+}
+#endif
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+static inline std::ostream& operator<<(std::ostream& output, const enum memcached_return_t &arg)
+{
+ output << memcached_strerror(NULL, arg);
+ return output;
+}
+
+static inline std::ostream& operator<<(std::ostream& output, const memcached_st &arg)
+{
+ output << " query_id: " << memcached_query_id(&arg);
+ output << " error: " << memcached_last_error_message(&arg);
+ return output;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifndef _WIN32
+# include <netdb.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+pid_t libmemcached_util_getpid(const char *hostname, in_port_t port, memcached_return_t *ret);
+
+LIBMEMCACHED_API
+pid_t libmemcached_util_getpid2(const char *hostname, in_port_t port, const char *username, const char *password, memcached_return_t *ret);
+
+#ifdef __cplusplus
+}
+#endif
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret);
+
+LIBMEMCACHED_API
+bool libmemcached_util_ping2(const char *hostname, in_port_t port, const char *username, const char *password, memcached_return_t *ret);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+#include <libmemcached-1.0/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_pool_st *memcached_pool(const char *option_string, size_t option_string_length);
+
+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_release(memcached_pool_st* pool, memcached_st* mmc);
+
+LIBMEMCACHED_API
+memcached_st* memcached_pool_fetch(memcached_pool_st*, struct timespec* relative_time, memcached_return_t* rc);
+
+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
+} // extern "C"
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libmemcached-1.0/memcached.h>
+
+#include <libmemcachedutil-1.0/pid.h>
+#include <libmemcachedutil-1.0/flush.h>
+#include <libmemcachedutil-1.0/ping.h>
+#include <libmemcachedutil-1.0/pool.h>
+#include <libmemcachedutil-1.0/version.h>
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+ bool libmemcached_util_version_check(memcached_st *memc,
+ uint8_t major_version,
+ uint8_t minor_version,
+ uint8_t micro_version);
+
+#ifdef __cplusplus
+}
+#endif
+++ /dev/null
-
-configure_file(configure.h.in configure.h @ONLY)
-
-install(DIRECTORY ../libhashkit-1.0
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
- FILES_MATCHING REGEX "\\.h(pp)?$"
- )
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-/**
- * @file
- * @brief HashKit Header
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HASHKIT_API
-uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_fnv1_64(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_fnv1_32(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_crc32(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_hsieh(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_murmur(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_murmur3(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_jenkins(const char *key, size_t key_length);
-
-HASHKIT_API
-uint32_t libhashkit_md5(const char *key, size_t key_length);
-
-HASHKIT_API
-void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-#pragma once
-
-// No assumptions of NULL should be made
-
-#define hashkit_size(X) (X).size;
-#define hashkit_c_str(X) (X).c_str;
-#define hashkit_string_param(X) (X).c_str, (X).size
-
-#ifdef __cplusplus
-#define hashkit_string_printf(X) int((X).size), (X).c_str
-#else
-#define hashkit_string_printf(X) (int)((X).size), (X).c_str
-#endif
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-
-
-/**
- * @file
- * @brief HashKit Header
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-
-
-#pragma once
-
-#define LIBHASHKIT_VERSION_STRING "@LIBHASHKIT_VERSION@"
-#define LIBHASHKIT_VERSION_HEX @LIBHASHKIT_VERSION_HEX@
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HASHKIT_API
-uint32_t hashkit_digest(const hashkit_st *self, const char *key, size_t key_length);
-
-/**
- This is a utilitly function provided so that you can directly access hashes with a hashkit_st.
-*/
-
-HASHKIT_API
-uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- This sets/gets the default function we will be using.
-*/
-HASHKIT_API
-hashkit_return_t hashkit_set_function(hashkit_st *hash, hashkit_hash_algorithm_t hash_algorithm);
-
-HASHKIT_API
-hashkit_return_t hashkit_set_custom_function(hashkit_st *hash, hashkit_hash_fn function, void *context);
-
-HASHKIT_API
-hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *hash);
-
-/**
- This sets/gets the function we use for distribution.
-*/
-HASHKIT_API
-hashkit_return_t hashkit_set_distribution_function(hashkit_st *hash, hashkit_hash_algorithm_t hash_algorithm);
-
-HASHKIT_API
-hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context);
-
-HASHKIT_API
-hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HASHKIT_API
-bool libhashkit_has_algorithm(const hashkit_hash_algorithm_t);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-
-
-#pragma once
-
-
-#if !defined(__cplusplus)
-# include <stdbool.h>
-#endif
-#include <inttypes.h>
-#include <sys/types.h>
-
-#include <libhashkit-1.0/visibility.h>
-#include <libhashkit-1.0/configure.h>
-#include <libhashkit-1.0/types.h>
-#include <libhashkit-1.0/has.h>
-#include <libhashkit-1.0/algorithm.h>
-#include <libhashkit-1.0/behavior.h>
-#include <libhashkit-1.0/digest.h>
-#include <libhashkit-1.0/function.h>
-#include <libhashkit-1.0/str_algorithm.h>
-#include <libhashkit-1.0/strerror.h>
-#include <libhashkit-1.0/string.h>
-
-struct hashkit_st
-{
- struct hashkit_function_st {
- hashkit_hash_fn function;
- void *context;
- } base_hash, distribution_hash;
-
- struct {
- bool is_base_same_distributed:1;
- } flags;
-
- struct {
- bool is_allocated:1;
- } options;
-
- void *_key;
-};
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HASHKIT_API
- hashkit_st *hashkit_create(hashkit_st *hash);
-
-HASHKIT_API
- hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
-
-HASHKIT_API
- bool hashkit_compare(const hashkit_st *first, const hashkit_st *second);
-
-HASHKIT_API
- void hashkit_free(hashkit_st *hash);
-
-HASHKIT_API
- hashkit_string_st *hashkit_encrypt(hashkit_st *,
- const char* source, size_t source_length);
-
-HASHKIT_API
- hashkit_string_st *hashkit_decrypt(hashkit_st *,
- const char* source, size_t source_length);
-
-HASHKIT_API
- bool hashkit_key(hashkit_st *, const char *key, const size_t key_length);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#include <libhashkit-1.0/hashkit.h>
-#include <string>
-
-class Hashkit {
-
-public:
-
- Hashkit()
- {
- hashkit_create(&self);
- }
-
- Hashkit(const Hashkit& source)
- {
- hashkit_clone(&self, &source.self);
- }
-
- Hashkit& operator=(const Hashkit& source)
- {
- hashkit_free(&self);
- hashkit_clone(&self, &source.self);
-
- return *this;
- }
-
- friend bool operator==(const Hashkit &left, const Hashkit &right)
- {
- return hashkit_compare(&left.self, &right.self);
- }
-
- uint32_t digest(std::string& str)
- {
- return hashkit_digest(&self, str.c_str(), str.length());
- }
-
- uint32_t digest(const char *key, size_t key_length)
- {
- return hashkit_digest(&self, key, key_length);
- }
-
- hashkit_return_t set_function(hashkit_hash_algorithm_t hash_algorithm)
- {
- return hashkit_set_function(&self, hash_algorithm);
- }
-
- hashkit_return_t set_distribution_function(hashkit_hash_algorithm_t hash_algorithm)
- {
- return hashkit_set_function(&self, hash_algorithm);
- }
-
- ~Hashkit()
- {
- hashkit_free(&self);
- }
-private:
-
- hashkit_st self;
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HASHKIT_API
-const char *libhashkit_string_hash(hashkit_hash_algorithm_t type);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HASHKIT_API
- const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifdef __cplusplus
-struct hashkit_string_st;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HASHKIT_API
-void hashkit_string_free(hashkit_string_st *ptr);
-
-
-HASHKIT_API
-size_t hashkit_string_length(const hashkit_string_st *self);
-
-HASHKIT_API
-const char *hashkit_string_c_str(const hashkit_string_st* self);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-typedef enum {
- HASHKIT_SUCCESS,
- HASHKIT_FAILURE,
- HASHKIT_MEMORY_ALLOCATION_FAILURE,
- HASHKIT_INVALID_HASH,
- HASHKIT_INVALID_ARGUMENT,
- HASHKIT_MAXIMUM_RETURN /* Always add new error code before */
-} hashkit_return_t;
-
-static inline bool hashkit_success(const hashkit_return_t rc)
-{
- return (rc == HASHKIT_SUCCESS);
-}
-
-static inline bool hashkit_failed(const hashkit_return_t rc)
-{
- return (rc != HASHKIT_SUCCESS);
-}
-
-typedef enum {
- HASHKIT_HASH_DEFAULT= 0, // hashkit_one_at_a_time()
- 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_MURMUR3,
- HASHKIT_HASH_CUSTOM,
- 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;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct hashkit_st hashkit_st;
-typedef struct hashkit_string_st hashkit_string_st;
-
-typedef uint32_t (*hashkit_hash_fn)(const char *key, size_t key_length, void *context);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/*
- * 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
- */
-
-#pragma once
-
-/**
- *
- * 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) */
+++ /dev/null
-if(HAVE_HSIEH_HASH)
- set(HSIEH_CC hsieh.cc)
-else()
- set(HSIEH_CC nohsieh.cc)
-endif()
-
-add_library(libhashkit SHARED
- aes.cc
- algorithm.cc
- behavior.cc
- crc32.cc
- digest.cc
- encrypt.cc
- fnv_32.cc
- fnv_64.cc
- function.cc
- has.cc
- hashkit.cc
- ${HSIEH_CC}
- jenkins.cc
- ketama.cc
- md5.cc
- murmur.cc
- murmur3.cc
- murmur3_api.cc
- nohsieh.cc
- one_at_a_time.cc
- rijndael.cc
- str_algorithm.cc
- strerror.cc
- string.cc
- )
-add_library(hashkit ALIAS libhashkit)
-set_target_properties(libhashkit PROPERTIES LIBRARY_OUTPUT_NAME hashkit)
-target_include_directories(libhashkit PRIVATE ..)
-target_compile_options(libhashkit PRIVATE -DBUILDING_HASHKIT)
-
-configure_file(hashkitcon.h.in hashkitcon.h @ONLY)
-
-set_target_properties(libhashkit PROPERTIES SOVERSION ${LIBHASHKIT_SO_VERSION})
-install(TARGETS libhashkit EXPORT libhashkit
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
-export(EXPORT libhashkit)
-install(EXPORT libhashkit DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake)
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
- FILES_MATCHING PATTERN hashkit.h
- )
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libhashkit library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include "libhashkit/common.h"
-
-#include "libhashkit/rijndael.hpp"
-
-#include <cstring>
-
-#define AES_KEY_LENGTH 256 /* 128, 192, 256 */
-#define AES_BLOCK_SIZE 16
-
-enum encrypt_t
-{
- AES_ENCRYPT,
- AES_DECRYPT
-};
-
-struct _key_t {
- int nr;
- uint32_t rk[4*(AES_MAXNR +1)];
-};
-
-struct aes_key_t {
- _key_t encode_key;
- _key_t decode_key;
-};
-
-aes_key_t* aes_create_key(const char *key, const size_t key_length)
-{
- aes_key_t* _aes_key= (aes_key_t*)(calloc(1, sizeof(aes_key_t)));
- if (_aes_key)
- {
- uint8_t rkey[AES_KEY_LENGTH/8];
- uint8_t *rkey_end= rkey +AES_KEY_LENGTH/8;
- const char *key_end= key +key_length;
-
- memset(rkey, 0, sizeof(rkey)); /* Set initial key */
-
- uint8_t *ptr= rkey;
- const char* sptr= key;
- for (; sptr < key_end; ptr++,sptr++)
- {
- if (ptr == rkey_end)
- {
- ptr= rkey; /* Just loop over tmp_key until we used all key */
- }
- *ptr^= (uint8_t)(*sptr);
- }
-
- _aes_key->decode_key.nr= rijndaelKeySetupDec(_aes_key->decode_key.rk, rkey, AES_KEY_LENGTH);
- _aes_key->encode_key.nr= rijndaelKeySetupEnc(_aes_key->encode_key.rk, rkey, AES_KEY_LENGTH);
- }
-
- return _aes_key;
-}
-
-aes_key_t* aes_clone_key(aes_key_t *_aes_key)
-{
- if (_aes_key == NULL)
- {
- return NULL;
- }
-
- aes_key_t* _aes_clone_key= (aes_key_t*)(calloc(1, sizeof(aes_key_t)));
- if (_aes_clone_key)
- {
- memcpy(_aes_clone_key, _aes_key, sizeof(aes_key_t));
- }
-
- return _aes_clone_key;
-}
-
-hashkit_string_st* aes_encrypt(aes_key_t *_aes_key,
- const char* source, size_t source_length)
-{
- if (_aes_key == NULL)
- {
- return NULL;
- }
-
- size_t num_blocks= source_length/AES_BLOCK_SIZE;
-
- hashkit_string_st* destination= hashkit_string_create(source_length);
- if (destination)
- {
- char *dest= hashkit_string_c_str_mutable(destination);
-
- for (size_t x= num_blocks; x > 0; x--) /* Encode complete blocks */
- {
- rijndaelEncrypt(_aes_key->encode_key.rk, _aes_key->encode_key.nr, (const uint8_t*)(source),
- (uint8_t*) (dest));
- source+= AES_BLOCK_SIZE;
- dest+= AES_BLOCK_SIZE;
- }
-
- uint8_t block[AES_BLOCK_SIZE];
- char pad_len= AES_BLOCK_SIZE - (source_length - AES_BLOCK_SIZE*num_blocks);
- memcpy(block, source, 16 -pad_len);
- memset(block + AES_BLOCK_SIZE -pad_len, pad_len, pad_len);
- rijndaelEncrypt(_aes_key->encode_key.rk, _aes_key->encode_key.nr, block, (uint8_t*) (dest));
- hashkit_string_set_length(destination, AES_BLOCK_SIZE*(num_blocks + 1));
- }
-
- return destination;
-}
-
-hashkit_string_st* aes_decrypt(aes_key_t *_aes_key,
- const char* source, size_t source_length)
-{
- if (_aes_key == NULL)
- {
- return NULL;
- }
-
- size_t num_blocks= source_length/AES_BLOCK_SIZE;
- if ((source_length != num_blocks*AES_BLOCK_SIZE) or num_blocks ==0 )
- {
- return NULL;
- }
-
- hashkit_string_st* destination= hashkit_string_create(source_length);
- if (destination)
- {
- char *dest= hashkit_string_c_str_mutable(destination);
-
- for (size_t x = num_blocks-1; x > 0; x--)
- {
- rijndaelDecrypt(_aes_key->decode_key.rk, _aes_key->decode_key.nr, (const uint8_t*) (source), (uint8_t*)(dest));
- source+= AES_BLOCK_SIZE;
- dest+= AES_BLOCK_SIZE;
- }
-
- uint8_t block[AES_BLOCK_SIZE];
- rijndaelDecrypt(_aes_key->decode_key.rk, _aes_key->decode_key.nr, (const uint8_t*)(source), block);
- /* Use last char in the block as size */
- unsigned int pad_len= (unsigned int) (unsigned char)(block[AES_BLOCK_SIZE-1]);
- if (pad_len > AES_BLOCK_SIZE)
- {
- hashkit_string_free(destination);
- return NULL;
- }
-
- /* We could also check whole padding but we do not really need this */
-
- memcpy(dest, block, AES_BLOCK_SIZE - pad_len);
- hashkit_string_set_length(destination, AES_BLOCK_SIZE*num_blocks - pad_len);
- }
-
- return destination;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-struct aes_key_t;
-
-hashkit_string_st* aes_encrypt(aes_key_t* _aes_key,
- const char* source, size_t source_length);
-
-hashkit_string_st* aes_decrypt(aes_key_t* _aes_key,
- const char* source, size_t source_length);
-
-aes_key_t* aes_create_key(const char *key, const size_t key_length);
-
-aes_key_t* aes_clone_key(aes_key_t* _aes_key);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2006-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libhashkit/common.h"
-
-uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length)
-{
- return hashkit_one_at_a_time(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1_64(const char *key, size_t key_length)
-{
- return hashkit_fnv1_64(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length)
-{
- return hashkit_fnv1a_64(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1_32(const char *key, size_t key_length)
-{
- return hashkit_fnv1_32(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length)
-{
- return hashkit_fnv1a_32(key, key_length, NULL);
-}
-
-uint32_t libhashkit_crc32(const char *key, size_t key_length)
-{
- return hashkit_crc32(key, key_length, NULL);
-}
-
-uint32_t libhashkit_hsieh(const char *key, size_t key_length)
-{
- return hashkit_hsieh(key, key_length, NULL);
-}
-
-uint32_t libhashkit_murmur3(const char *key, size_t key_length)
-{
- return hashkit_murmur3(key, key_length, NULL);
-}
-
-uint32_t libhashkit_murmur(const char *key, size_t key_length)
-{
- return hashkit_murmur(key, key_length, NULL);
-}
-
-uint32_t libhashkit_jenkins(const char *key, size_t key_length)
-{
- return hashkit_jenkins(key, key_length, NULL);
-}
-
-uint32_t libhashkit_md5(const char *key, size_t key_length)
-{
- return hashkit_md5(key, key_length, NULL);
-}
-
-void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result)
-{
- md5_signature(key, (uint32_t)length, result);
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-/**
- * @file
- * @brief HashKit Header
- */
-
-#pragma once
-
-uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_crc32(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_hsieh(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_murmur(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_murmur3(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_jenkins(const char *key, size_t key_length, void *context);
-
-uint32_t hashkit_md5(const char *key, size_t key_length, void *context);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2009-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libhashkit/common.h>
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#include "libhashkit/hashkitcon.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#ifndef __WORDSIZE
-# ifdef __MINGW32__
-# define __WORDSIZE 32
-# endif
-#endif
-
-#include <libhashkit-1.0/hashkit.h>
-#include "libhashkit/algorithm.h"
-#include "libhashkit/is.h"
-#include "libhashkit/string.h"
-#include "libhashkit/aes.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result);
-
-int update_continuum(hashkit_st *hashkit);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2009-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* The crc32 functions and data was originally written by Spencer
- * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source
- * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at
- * src/usr.bin/cksum/crc32.c.
- */
-
-#include <libhashkit/common.h>
-
-static const uint32_t crc32tab[256] = {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
- 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
- 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
- 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
- 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
- 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
- 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
- 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
- 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
- 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
- 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
- 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
- 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
- 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
- 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
- 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
- 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
- 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
- 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
- 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
- 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
- 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
- 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
- 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
- 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
- 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
- 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
- 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
- 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
- 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
- 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
-};
-
-uint32_t hashkit_crc32(const char *key, size_t key_length, void *context)
-{
- uint64_t x;
- uint32_t crc= UINT32_MAX;
- (void)context;
-
- for (x= 0; x < key_length; x++)
- crc= (crc >> 8) ^ crc32tab[(crc ^ (uint64_t)key[x]) & 0xff];
-
- return ((~crc) >> 16) & 0x7fff;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2010-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libhashkit/common.h>
-
-uint32_t hashkit_digest(const hashkit_st *self, const char *key, size_t key_length)
-{
- return self->base_hash.function(key, key_length, self->base_hash.context);
-}
-
-uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm)
-{
- switch (hash_algorithm)
- {
- case HASHKIT_HASH_DEFAULT:
- return libhashkit_one_at_a_time(key, key_length);
- case HASHKIT_HASH_MD5:
- return libhashkit_md5(key, key_length);
- case HASHKIT_HASH_CRC:
- return libhashkit_crc32(key, key_length);
- case HASHKIT_HASH_FNV1_64:
- return libhashkit_fnv1_64(key, key_length);
- case HASHKIT_HASH_FNV1A_64:
- return libhashkit_fnv1a_64(key, key_length);
- case HASHKIT_HASH_FNV1_32:
- return libhashkit_fnv1_32(key, key_length);
- case HASHKIT_HASH_FNV1A_32:
- return libhashkit_fnv1a_32(key, key_length);
- case HASHKIT_HASH_HSIEH:
-#ifdef HAVE_HSIEH_HASH
- return libhashkit_hsieh(key, key_length);
-#else
- return 1;
-#endif
- case HASHKIT_HASH_MURMUR3:
- return libhashkit_murmur3(key, key_length);
-
- case HASHKIT_HASH_MURMUR:
-#ifdef HAVE_MURMUR_HASH
- return libhashkit_murmur(key, key_length);
-#else
- return 1;
-#endif
- case HASHKIT_HASH_JENKINS:
- return libhashkit_jenkins(key, key_length);
- case HASHKIT_HASH_CUSTOM:
- case HASHKIT_HASH_MAX:
- default:
- if (DEBUG)
- {
- fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n");
- fflush(stderr);
- assert(0);
- }
- break;
- }
-
- return 1;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libhashkit library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libhashkit/common.h>
-
-hashkit_string_st *hashkit_encrypt(hashkit_st *kit,
- const char* source, size_t source_length)
-{
- return aes_encrypt(static_cast<aes_key_t*>(kit->_key), source, source_length);
-}
-
-hashkit_string_st *hashkit_decrypt(hashkit_st *kit,
- const char* source, size_t source_length)
-{
- return aes_decrypt(static_cast<aes_key_t*>(kit->_key), source, source_length);
-}
-
-bool hashkit_key(hashkit_st *kit, const char *key, const size_t key_length)
-{
- if (kit->_key)
- {
- free(kit->_key);
- }
-
- kit->_key= aes_create_key(key, key_length);
-
- return bool(kit->_key);
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libhashkit/common.h>
-
-/* FNV hash'es lifted from Dustin Sallings work */
-static uint32_t FNV_32_INIT= 2166136261UL;
-static uint32_t FNV_32_PRIME= 16777619;
-
-uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context)
-{
- uint32_t hash= FNV_32_INIT;
- (void)context;
-
- for (size_t x= 0; x < key_length; x++)
- {
- uint32_t val= (uint32_t)key[x];
- hash *= FNV_32_PRIME;
- hash ^= val;
- }
-
- return hash;
-}
-
-uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context)
-{
- uint32_t hash= FNV_32_INIT;
- (void)context;
-
- for (size_t x= 0; x < key_length; x++)
- {
- uint32_t val= (uint32_t)key[x];
- hash ^= val;
- hash *= FNV_32_PRIME;
- }
-
- return hash;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libhashkit/common.h>
-
-#if __WORDSIZE == 64 && defined(HAVE_FNV64_HASH)
-
-/* FNV hash'es lifted from Dustin Sallings work */
-static uint64_t FNV_64_INIT= 0xcbf29ce484222325;
-static uint64_t FNV_64_PRIME= 0x100000001b3;
-
-uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *)
-{
- /* Thanks to pierre@demartines.com for the pointer */
- uint64_t hash= FNV_64_INIT;
-
- for (size_t x= 0; x < key_length; x++)
- {
- hash *= FNV_64_PRIME;
- hash ^= (uint64_t)key[x];
- }
-
- return (uint32_t)hash;
-}
-
-uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *)
-{
- uint32_t hash= (uint32_t) FNV_64_INIT;
-
- for (size_t x= 0; x < key_length; x++)
- {
- uint32_t val= (uint32_t)key[x];
- hash ^= val;
- hash *= (uint32_t) FNV_64_PRIME;
- }
-
- return hash;
-}
-
-#else
-uint32_t hashkit_fnv1_64(const char *, size_t, void *)
-{
- return 0;
-}
-
-uint32_t hashkit_fnv1a_64(const char *, size_t, void *)
-{
- return 0;
-}
-#endif
+++ /dev/null
-/* HashKit
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-static hashkit_return_t _set_function(struct hashkit_st::hashkit_function_st *self, hashkit_hash_algorithm_t hash_algorithm)
-{
- if (self == NULL)
- {
- return HASHKIT_INVALID_ARGUMENT;
- }
-
- switch (hash_algorithm)
- {
- case HASHKIT_HASH_MD5:
- self->function= hashkit_md5;
- break;
-
- case HASHKIT_HASH_CRC:
- self->function= hashkit_crc32;
- break;
-
- case HASHKIT_HASH_FNV1_64:
- if (libhashkit_has_algorithm(HASHKIT_HASH_FNV1_64))
- {
- self->function= hashkit_fnv1_64;
- break;
- }
- return HASHKIT_INVALID_ARGUMENT;
-
- case HASHKIT_HASH_FNV1A_64:
- if (libhashkit_has_algorithm(HASHKIT_HASH_FNV1_64))
- {
- self->function= hashkit_fnv1a_64;
- break;
- }
- return HASHKIT_INVALID_ARGUMENT;
-
- case HASHKIT_HASH_FNV1_32:
- self->function= hashkit_fnv1_32;
- break;
-
- case HASHKIT_HASH_FNV1A_32:
- self->function= hashkit_fnv1a_32;
- break;
-
- case HASHKIT_HASH_HSIEH:
- if (libhashkit_has_algorithm(HASHKIT_HASH_HSIEH))
- {
- self->function= hashkit_hsieh;
- break;
- }
- return HASHKIT_INVALID_ARGUMENT;
-
- case HASHKIT_HASH_MURMUR3:
- if (libhashkit_has_algorithm(HASHKIT_HASH_MURMUR3))
- {
- self->function= hashkit_murmur3;
- break;
- }
- return HASHKIT_INVALID_ARGUMENT;
- case HASHKIT_HASH_MURMUR:
- if (libhashkit_has_algorithm(HASHKIT_HASH_MURMUR))
- {
- self->function= hashkit_murmur;
- break;
- }
- return HASHKIT_INVALID_ARGUMENT;
-
- case HASHKIT_HASH_JENKINS:
- self->function= hashkit_jenkins;
- break;
-
- case HASHKIT_HASH_CUSTOM:
- return HASHKIT_INVALID_ARGUMENT;
-
- case HASHKIT_HASH_DEFAULT:
- self->function= hashkit_one_at_a_time;
- break;
-
- case HASHKIT_HASH_MAX:
- self->function= hashkit_one_at_a_time;
- return HASHKIT_INVALID_HASH;
- }
-
- self->context= NULL;
-
- return HASHKIT_SUCCESS;
-}
-
-hashkit_return_t hashkit_set_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm)
-{
- return _set_function(&self->base_hash, hash_algorithm);
-}
-
-hashkit_return_t hashkit_set_distribution_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm)
-{
- return _set_function(&self->distribution_hash, hash_algorithm);
-}
-
-static hashkit_return_t _set_custom_function(struct hashkit_st::hashkit_function_st *self, hashkit_hash_fn function, void *context)
-{
- if (self == NULL)
- {
- return HASHKIT_INVALID_ARGUMENT;
- }
-
- if (function)
- {
- self->function= function;
- self->context= context;
-
- return HASHKIT_SUCCESS;
- }
-
- return HASHKIT_FAILURE;
-}
-
-hashkit_return_t hashkit_set_custom_function(hashkit_st *self, hashkit_hash_fn function, void *context)
-{
- if (self == NULL)
- {
- return HASHKIT_INVALID_ARGUMENT;
- }
-
-
- return _set_custom_function(&self->base_hash, function, context);
-}
-
-hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context)
-{
- if (self == NULL)
- {
- return HASHKIT_INVALID_ARGUMENT;
- }
-
- return _set_custom_function(&self->distribution_hash, function, context);
-}
-
-static hashkit_hash_algorithm_t get_function_type(const hashkit_hash_fn function)
-{
- if (function == hashkit_one_at_a_time)
- {
- return HASHKIT_HASH_DEFAULT;
- }
- else if (function == hashkit_md5)
- {
- return HASHKIT_HASH_MD5;
- }
- else if (function == hashkit_crc32)
- {
- return HASHKIT_HASH_CRC;
- }
- else if (function == hashkit_fnv1_64)
- {
- return HASHKIT_HASH_FNV1_64;
- }
- else if (function == hashkit_fnv1a_64)
- {
- return HASHKIT_HASH_FNV1A_64;
- }
- else if (function == hashkit_fnv1_32)
- {
- return HASHKIT_HASH_FNV1_32;
- }
- else if (function == hashkit_fnv1a_32)
- {
- return HASHKIT_HASH_FNV1A_32;
- }
- else if (function == hashkit_hsieh)
- {
- return HASHKIT_HASH_HSIEH;
- }
- else if (function == hashkit_murmur)
- {
- return HASHKIT_HASH_MURMUR;
- }
- else if (function == hashkit_murmur3)
- {
- return HASHKIT_HASH_MURMUR3;
- }
- else if (function == hashkit_jenkins)
- {
- return HASHKIT_HASH_JENKINS;
- }
-
- return HASHKIT_HASH_CUSTOM;
-}
-
-hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *self)
-{
- if (self == NULL)
- {
- return HASHKIT_HASH_DEFAULT;
- }
-
- return get_function_type(self->base_hash.function);
-}
-
-hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self)
-{
- if (self == NULL)
- {
- return HASHKIT_HASH_DEFAULT;
- }
-
- return get_function_type(self->distribution_hash.function);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libhashkit/common.h>
-
-bool libhashkit_has_algorithm(const hashkit_hash_algorithm_t algo)
-{
- switch (algo)
- {
- case HASHKIT_HASH_FNV1_64:
- case HASHKIT_HASH_FNV1A_64:
-#if __WORDSIZE == 64 && defined(HAVE_FNV64_HASH)
- return true;
-#else
- return false;
-#endif
-
- case HASHKIT_HASH_HSIEH:
-#ifdef HAVE_HSIEH_HASH
- return true;
-#else
- return false;
-#endif
-
- case HASHKIT_HASH_MURMUR3:
- case HASHKIT_HASH_MURMUR:
-#ifdef HAVE_MURMUR_HASH
- return true;
-#else
- return false;
-#endif
-
- case HASHKIT_HASH_FNV1_32:
- case HASHKIT_HASH_FNV1A_32:
- case HASHKIT_HASH_DEFAULT:
- case HASHKIT_HASH_MD5:
- case HASHKIT_HASH_CRC:
- case HASHKIT_HASH_JENKINS:
- case HASHKIT_HASH_CUSTOM:
- return true;
-
- case HASHKIT_HASH_MAX:
- break;
- }
-
- return false;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libhashkit/common.h>
-
-static inline void _hashkit_init(hashkit_st *self)
-{
- self->base_hash.function= hashkit_one_at_a_time;
- self->base_hash.context= NULL;
-
- self->distribution_hash.function= hashkit_one_at_a_time;
- self->distribution_hash.context= NULL;
-
- self->flags.is_base_same_distributed= true;
- self->_key= NULL;
-}
-
-static inline hashkit_st *_hashkit_create(hashkit_st *self)
-{
- if (self)
- {
- self->options.is_allocated= false;
- }
- else
- {
- self= (hashkit_st*)calloc(1, sizeof(hashkit_st));
- if (self == NULL)
- {
- return NULL;
- }
-
- self->options.is_allocated= true;
- }
-
- return self;
-}
-
-hashkit_st *hashkit_create(hashkit_st *self)
-{
- self= _hashkit_create(self);
- if (self == NULL)
- {
- return NULL;
- }
-
- _hashkit_init(self);
-
- return self;
-}
-
-
-void hashkit_free(hashkit_st *self)
-{
- if (self and self->_key)
- {
- free(self->_key);
- self->_key= NULL;
- }
-
- if (hashkit_is_allocated(self))
- {
- free(self);
- }
-}
-
-hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source)
-{
- if (source == NULL)
- {
- return hashkit_create(destination);
- }
-
- /* new_clone will be a pointer to destination */
- destination= _hashkit_create(destination);
-
- // Should only happen on allocation failure.
- if (destination == NULL)
- {
- return NULL;
- }
-
- destination->base_hash= source->base_hash;
- destination->distribution_hash= source->distribution_hash;
- destination->flags= source->flags;
- destination->_key= aes_clone_key(static_cast<aes_key_t*>(source->_key));
-
- return destination;
-}
-
-bool hashkit_compare(const hashkit_st *first, const hashkit_st *second)
-{
- if (not first or not second)
- return false;
-
- if (first->base_hash.function == second->base_hash.function and
- first->base_hash.context == second->base_hash.context and
- first->distribution_hash.function == second->distribution_hash.function and
- first->distribution_hash.context == second->distribution_hash.context and
- first->flags.is_base_same_distributed == second->flags.is_base_same_distributed)
- {
- return true;
- }
-
- return false;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#include <libhashkit-1.0/hashkit.h>
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#include "@AUTOHEADER_FILE@"
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* By Paul Hsieh (C) 2004, 2005. Covered under the Paul Hsieh
- * derivative license.
- * See: http://www.azillionmonkeys.com/qed/weblicense.html for license
- * details.
- * http://www.azillionmonkeys.com/qed/hash.html
-*/
-
-#include <libhashkit/common.h>
-
-#undef get16bits
-#if (defined(__GNUC__) && defined(__i386__))
-#define get16bits(d) (*((const uint16_t *) (d)))
-#endif
-
-#if !defined (get16bits)
-#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
- +(uint32_t)(((const uint8_t *)(d))[0]) )
-#endif
-
-#ifdef HAVE_HSIEH_HASH
-uint32_t hashkit_hsieh(const char *key, size_t key_length, void *)
-{
- uint32_t hash = 0, tmp;
- int rem;
-
- if (key_length <= 0 || key == NULL)
- return 0;
-
- rem = key_length & 3;
- key_length >>= 2;
-
- /* Main loop */
- for (;key_length > 0; key_length--)
- {
- hash += get16bits (key);
- tmp = (get16bits (key+2) << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- key += 2*sizeof (uint16_t);
- hash += hash >> 11;
- }
-
- /* Handle end cases */
- switch (rem)
- {
- case 3: hash += get16bits (key);
- hash ^= hash << 16;
- hash ^= (uint32_t)key[sizeof (uint16_t)] << 18;
- hash += hash >> 11;
- break;
- case 2: hash += get16bits (key);
- hash ^= hash << 11;
- hash += hash >> 17;
- break;
- case 1: hash += (unsigned char)(*key);
- hash ^= hash << 10;
- hash += hash >> 1;
- default:
- break;
- }
-
- /* Force "avalanching" of final 127 bits */
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 4;
- hash += hash >> 17;
- hash ^= hash << 25;
- hash += hash >> 6;
-
- return hash;
-}
-#else
-uint32_t hashkit_hsieh(const char *, size_t , void *)
-{
- return 0;
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-#pragma once
-
-#define hashkit_is_allocated(__object) ((__object)->options.is_allocated)
-#define hashkit_is_initialized(__object) ((__object)->options.is_initialized)
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
-*
-* By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
-* code any way you wish, private, educational, or commercial. It's free.
-* Use for hash table lookup, or anything where one collision in 2^^32 is
-* acceptable. Do NOT use for cryptographic purposes.
-* http://burtleburtle.net/bob/hash/index.html
-*
-* Modified by Brian Pontz for libmemcached
-* TODO:
-* Add big endian support
-*/
-
-#include <libhashkit/common.h>
-
-#define hashsize(n) ((uint32_t)1<<(n))
-#define hashmask(n) (hashsize(n)-1)
-#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
-
-#define mix(a,b,c) \
-{ \
- a -= c; a ^= rot(c, 4); c += b; \
- b -= a; b ^= rot(a, 6); a += c; \
- c -= b; c ^= rot(b, 8); b += a; \
- a -= c; a ^= rot(c,16); c += b; \
- b -= a; b ^= rot(a,19); a += c; \
- c -= b; c ^= rot(b, 4); b += a; \
-}
-
-#define final(a,b,c) \
-{ \
- c ^= b; c -= rot(b,14); \
- a ^= c; a -= rot(c,11); \
- b ^= a; b -= rot(a,25); \
- c ^= b; c -= rot(b,16); \
- a ^= c; a -= rot(c,4); \
- b ^= a; b -= rot(a,14); \
- c ^= b; c -= rot(b,24); \
-}
-
-#define JENKINS_INITVAL 13
-
-/*
-jenkins_hash() -- hash a variable-length key into a 32-bit value
- k : the key (the unaligned variable-length array of bytes)
- length : the length of the key, counting by bytes
- initval : can be any 4-byte value
-Returns a 32-bit value. Every bit of the key affects every bit of
-the return value. Two keys differing by one or two bits will have
-totally different hash values.
-
-The best hash table sizes are powers of 2. There is no need to do
-mod a prime (mod is sooo slow!). If you need less than 32 bits,
-use a bitmask. For example, if you need only 10 bits, do
- h = (h & hashmask(10));
-In which case, the hash table should have hashsize(10) elements.
-*/
-
-uint32_t hashkit_jenkins(const char *key, size_t length, void *)
-{
- uint32_t a,b,c; /* internal state */
-#ifndef WORDS_BIGENDIAN
- union { const void *ptr; size_t i; } u;
- u.ptr = key;
-#endif
-
- /* Set up the internal state */
- a = b = c = 0xdeadbeef + ((uint32_t)length) + JENKINS_INITVAL;
-
-#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;
- /* fall through */
- case 11: c+=((uint32_t)k[10])<<16;
- /* fall through */
- case 10: c+=((uint32_t)k[9])<<8;
- /* fall through */
- case 9 : c+=k[8];
- /* fall through */
- case 8 : b+=((uint32_t)k[7])<<24;
- /* fall through */
- case 7 : b+=((uint32_t)k[6])<<16;
- /* fall through */
- case 6 : b+=((uint32_t)k[5])<<8;
- /* fall through */
- case 5 : b+=k[4];
- /* fall through */
- case 4 : a+=((uint32_t)k[3])<<24;
- /* fall through */
- case 3 : a+=((uint32_t)k[2])<<16;
- /* fall through */
- case 2 : a+=((uint32_t)k[1])<<8;
- /* fall through */
- case 1 : a+=k[0];
- break;
- case 0 : return c;
- default : return c;
- }
-#ifndef WORDS_BIGENDIAN
- }
-#endif
-
- final(a,b,c);
- return c;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libhashkit/common.h>
-#include <math.h>
-
-#if 0
-static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment)
-{
- unsigned char results[16];
-
- md5_signature((unsigned char*)key, key_length, results);
- return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
- | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
- | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
- | (results[0 + alignment * 4] & 0xFF);
-}
-
-static int continuum_points_cmp(const void *t1, const void *t2)
-{
- hashkit_continuum_point_st *ct1= (hashkit_continuum_point_st *)t1;
- hashkit_continuum_point_st *ct2= (hashkit_continuum_point_st *)t2;
-
- if (ct1->value == ct2->value)
- return 0;
- else if (ct1->value > ct2->value)
- return 1;
- else
- return -1;
-}
-
-int update_continuum(hashkit_st *hashkit)
-{
- uint32_t count;
- uint32_t continuum_index= 0;
- uint32_t value;
- uint32_t points_index;
- uint32_t points_count= 0;
- uint32_t points_per_server;
- uint32_t points_per_hash;
- uint64_t total_weight= 0;
- uint32_t live_servers;
- uint8_t *context;
-
- if (hashkit->active_fn != NULL || hashkit->weight_fn != NULL)
- {
- live_servers= 0;
-
- for (count= 0, context= hashkit->list; count < hashkit->list_size;
- count++, context+= hashkit->context_size)
- {
- if (hashkit->active_fn != NULL)
- {
- if (hashkit->active_fn(context))
- live_servers++;
- else
- continue;
- }
-
- if (hashkit->weight_fn != NULL)
- total_weight+= hashkit->weight_fn(context);
- }
- }
-
- if (hashkit->active_fn == NULL)
- live_servers= (uint32_t)hashkit->list_size;
-
- if (live_servers == 0)
- return 0;
-
- if (hashkit->weight_fn == NULL)
- {
- points_per_server= HASHKIT_POINTS_PER_NODE;
- points_per_hash= 1;
- }
- else
- {
- points_per_server= HASHKIT_POINTS_PER_NODE_WEIGHTED;
- points_per_hash= 4;
- }
-
- if (live_servers > hashkit->continuum_count)
- {
- hashkit_continuum_point_st *new_continuum;
-
- new_continuum= realloc(hashkit->continuum,
- sizeof(hashkit_continuum_point_st) *
- (live_servers + HASHKIT_CONTINUUM_ADDITION) *
- points_per_server);
-
- if (new_continuum == NULL)
- return ENOMEM;
-
- hashkit->continuum= new_continuum;
- hashkit->continuum_count= live_servers + HASHKIT_CONTINUUM_ADDITION;
- }
-
- for (count= 0, context= hashkit->list; count < hashkit->list_size;
- count++, context+= hashkit->context_size)
- {
- if (hashkit->active_fn != NULL && hashkit->active_fn(context) == false)
- continue;
-
- if (hashkit->weight_fn != NULL)
- {
- float pct = (float)hashkit->weight_fn(context) / (float)total_weight;
- points_per_server= (uint32_t) ((floorf((float) (pct * HASHKIT_POINTS_PER_NODE_WEIGHTED / 4 * (float)live_servers + 0.0000000001))) * 4);
- }
-
- for (points_index= 0;
- points_index < points_per_server / points_per_hash;
- points_index++)
- {
- char sort_host[HASHKIT_CONTINUUM_KEY_SIZE]= "";
- size_t sort_host_length;
-
- if (hashkit->continuum_key_fn == NULL)
- {
- sort_host_length= (size_t) snprintf(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, "%u",
- points_index);
- }
- else
- {
- sort_host_length= hashkit->continuum_key_fn(sort_host, HASHKIT_CONTINUUM_KEY_SIZE,
- points_index, context);
- }
-
- if (hashkit->weight_fn == NULL)
- {
- if (hashkit->continuum_hash_fn == NULL)
- value= hashkit_default(sort_host, sort_host_length);
- else
- value= hashkit->continuum_hash_fn(sort_host, sort_host_length);
-
- hashkit->continuum[continuum_index].index= count;
- hashkit->continuum[continuum_index++].value= value;
- }
- else
- {
- unsigned int i;
- for (i = 0; i < points_per_hash; i++)
- {
- value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
- hashkit->continuum[continuum_index].index= count;
- hashkit->continuum[continuum_index++].value= value;
- }
- }
- }
-
- points_count+= points_per_server;
- }
-
- hashkit->continuum_points_count= points_count;
- qsort(hashkit->continuum, hashkit->continuum_points_count, sizeof(hashkit_continuum_point_st),
- continuum_points_cmp);
-
- return 0;
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- This Library has been modified from its original form by
- Brian Aker (brian@tangent.org)
-
- See below for original Copyright.
-*/
-/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
- */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
-*/
-
-#include <libhashkit/common.h>
-
-#include <string.h>
-#include <sys/types.h>
-
-#define GCC_VERSION (__GNUC__ * 10000 \
- + __GNUC_MINOR__ * 100 \
- + __GNUC_PATCHLEVEL__)
-
-#if GCC_VERSION > 40600
-# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
-#endif
-
-/* POINTER defines a generic pointer type */
-typedef unsigned char *POINTER;
-typedef const unsigned char *CONST_POINTER;
-
-
-/* UINT4 defines a four byte word */
-typedef unsigned int UINT4;
-
-
-/* MD5 context. */
-typedef struct {
- UINT4 state[4]; /* state (ABCD) */
- UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
- unsigned char buffer[64]; /* input buffer */
-} MD5_CTX;
-
-static void MD5Init (MD5_CTX *context); /* context */
-static void MD5Update ( MD5_CTX *context, /* context */
- const unsigned char *input, /* input block */
- unsigned int inputLen); /* length of input block */
-static void MD5Final ( unsigned char digest[16], /* message digest */
- MD5_CTX *context); /* context */
-
-/* Constants for MD5Transform routine. */
-
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-
-
-static void MD5Transform (UINT4 state[4],
- const unsigned char block[64]);
-static void Encode (unsigned char *output,
- UINT4 *input,
- unsigned int len);
-static void Decode(UINT4 *output, const unsigned char *input, unsigned int len);
-
-static unsigned char PADDING[64] = {
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G, H and I are basic MD5 functions.
- */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE_LEFT rotates x left n bits.
- */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-Rotation is separate from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-
-
-/*
- Just a simple method for getting the signature
- result must be == 16
-*/
-void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result)
-{
- MD5_CTX my_md5;
-
- MD5Init(&my_md5);
- (void)MD5Update(&my_md5, key, length);
- MD5Final(result, &my_md5);
-}
-
-/* MD5 initialization. Begins an MD5 operation, writing a new context.
- */
-static void MD5Init (MD5_CTX *context) /* context */
-{
- context->count[0] = context->count[1] = 0;
- /* Load magic initialization constants.
-*/
- context->state[0] = 0x67452301;
- context->state[1] = 0xefcdab89;
- context->state[2] = 0x98badcfe;
- context->state[3] = 0x10325476;
-}
-
-/* MD5 block update operation. Continues an MD5 message-digest
- operation, processing another message block, and updating the
- context.
- */
-
-static void MD5Update (
- MD5_CTX *context, /* context */
- const unsigned char *input, /* input block */
- unsigned int inputLen) /* length of input block */
-{
- unsigned int i, idx, partLen;
-
- /* Compute number of bytes mod 64 */
- idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
-
-
- /* Update number of bits */
- if ((context->count[0] += ((UINT4)inputLen << 3))
- < ((UINT4)inputLen << 3))
- context->count[1]++;
- context->count[1] += ((UINT4)inputLen >> 29);
-
- partLen = 64 - idx;
-
- /* Transform as many times as possible.
-*/
- if (inputLen >= partLen) {
- memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)input, partLen);
- MD5Transform(context->state, context->buffer);
-
- for (i = partLen; i + 63 < inputLen; i += 64)
- MD5Transform (context->state, (CONST_POINTER)&input[i]);
-
- idx = 0;
- }
- else
- i = 0;
-
- /* Buffer remaining input */
- memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)&input[i],
- inputLen-i);
-}
-
-/* MD5 finalization. Ends an MD5 message-digest operation, writing the
- the message digest and zeroizing the context.
- */
-
-static void MD5Final (
- unsigned char digest[16], /* message digest */
- MD5_CTX *context) /* context */
-{
- unsigned char bits[8];
- unsigned int idx, padLen;
-
- /* Save number of bits */
- Encode (bits, context->count, 8);
-
- /* Pad out to 56 mod 64.
-*/
- idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
- padLen = (idx < 56) ? (56 - idx) : (120 - idx);
- MD5Update (context, PADDING, padLen);
-
- /* Append length (before padding) */
- MD5Update (context, bits, 8);
-
- /* Store state in digest */
- Encode (digest, context->state, 16);
-
- /* Zeroize sensitive information.
-*/
- memset((POINTER)context, 0, sizeof (*context));
-}
-
-/* MD5 basic transformation. Transforms state based on block.
- */
-static void MD5Transform (
- UINT4 state[4],
- const unsigned char block[64])
-{
- UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
-
- Decode (x, block, 64);
-
- /* Round 1 */
- FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
- FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
- FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
- FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
- FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
- FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
- FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
- FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
- FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
- FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
- FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
- FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
- FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
- FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
- FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
- FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
- /* Round 2 */
- GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
- GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
- GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
- GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
- GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
- GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
- GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
- GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
- GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
- GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
- GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
- GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
- GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
- GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
- GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
- GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
- /* Round 3 */
- HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
- HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
- HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
- HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
- HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
- HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
- HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
- HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
- HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
- HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
- HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
- HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
- HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
- HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
- HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
- HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
-
- /* Round 4 */
- II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
- II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
- II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
- II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
- II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
- II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
- II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
- II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
- II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
- II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
- II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
- II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
- II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
- II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
- II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
- II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
-
-
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
-
- /* Zeroize sensitive information.
-*/
- memset((POINTER)x, 0, sizeof (x));
-}
-
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is
- a multiple of 4.
- */
-static void Encode (
-unsigned char *output,
-UINT4 *input,
-unsigned int len)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
- }
-}
-
-
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is
- a multiple of 4.
- */
-static void Decode (
- UINT4 *output,
- const unsigned char *input,
- unsigned int len)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4)
- output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
- (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
-}
-
-uint32_t hashkit_md5(const char *key, size_t key_length, void *context)
-{
- unsigned char results[16];
- (void)context;
-
- md5_signature((unsigned char*)key, (unsigned int)key_length, results);
-
- return ((uint32_t) (results[3] & 0xFF) << 24)
- | ((uint32_t) (results[2] & 0xFF) << 16)
- | ((uint32_t) (results[1] & 0xFF) << 8)
- | (results[0] & 0xFF);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- "Murmur" hash provided by Austin, tanjent@gmail.com
- http://murmurhash.googlepages.com/
-
- Note - This code makes a few assumptions about how your machine behaves -
-
- 1. We can read a 4-byte value from any address without crashing
- 2. sizeof(int) == 4
-
- And it has a few limitations -
- 1. It will not work incrementally.
- 2. It will not produce the same results on little-endian and big-endian
- machines.
-
- Updated to murmur2 hash - BP
-*/
-
-#include <libhashkit/common.h>
-
-#ifdef HAVE_MURMUR_HASH
-
-#include <cstring>
-
-uint32_t hashkit_murmur(const char *key, size_t length, void *context)
-{
- /*
- 'm' and 'r' are mixing constants generated offline. They're not
- really 'magic', they just happen to work well.
- */
-
- const unsigned int m= 0x5bd1e995;
- const uint32_t seed= (0xdeadbeef * (uint32_t)length);
- const int r= 24;
-
-
- // Initialize the hash to a 'random' value
-
- uint32_t h= seed ^ (uint32_t)length;
-
- // Mix 4 bytes at a time into the hash
-
- const unsigned char * data= (const unsigned char *)key;
- (void)context;
-
- while(length >= 4)
- {
- unsigned int k;
- memcpy(&k, data, sizeof(unsigned int));
-
- 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; /* fall through */
- case 2: h ^= ((uint32_t)data[1]) << 8; /* fall through */
- 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;
-}
-
-#else
-uint32_t hashkit_murmur(const char *, size_t , void *)
-{
- return 0;
-}
-#endif
+++ /dev/null
-//-----------------------------------------------------------------------------
-//MurmurHash3 was written by Austin Appleby, and is placed in the public
-//domain. The author hereby disclaims copyright to this source code.
-
-// Note - The x86 and x64 versions do _not_ produce the same results, as the
-// algorithms are optimized for their respective platforms. You can still
-// compile and run any of them on any platform, but your performance with the
-// non-native version will be less than optimal.
-
-#include "libhashkit/hashkitcon.h"
-
-#include "libhashkit/murmur3.h"
-
-//-----------------------------------------------------------------------------
-// Platform-specific functions and macros
-
-#ifdef __GNUC__
-#define FORCE_INLINE __attribute__((always_inline)) inline
-#else
-#define FORCE_INLINE inline
-#endif
-
-static FORCE_INLINE uint32_t rotl32 ( uint32_t x, int8_t r )
-{
- return (x << r) | (x >> (32 - r));
-}
-
-static FORCE_INLINE uint64_t rotl64 ( uint64_t x, int8_t r )
-{
- return (x << r) | (x >> (64 - r));
-}
-
-#define ROTL32(x,y) rotl32(x,y)
-#define ROTL64(x,y) rotl64(x,y)
-
-#define BIG_CONSTANT(x) (x##LLU)
-
-//-----------------------------------------------------------------------------
-// Block read - if your platform needs to do endian-swapping or can only
-// handle aligned reads, do the conversion here
-
-#include <cstring>
-template <typename T>
-static inline T getblock(const T *blocks, int i) {
- T b;
- memcpy(&b, ((const uint8_t *) blocks) + i * sizeof(T), sizeof(T));
- return b;
-}
-
-//-----------------------------------------------------------------------------
-// Finalization mix - force all bits of a hash block to avalanche
-
-static FORCE_INLINE uint32_t fmix32 ( uint32_t h )
-{
- h ^= h >> 16;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
-
- return h;
-}
-
-//----------
-
-static FORCE_INLINE uint64_t fmix64 ( uint64_t k )
-{
- k ^= k >> 33;
- k *= BIG_CONSTANT(0xff51afd7ed558ccd);
- k ^= k >> 33;
- k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
- k ^= k >> 33;
-
- return k;
-}
-
-//-----------------------------------------------------------------------------
-
-void MurmurHash3_x86_32 ( const void * key, int len,
- uint32_t seed, void * out )
-{
- const uint8_t * data = (const uint8_t*)key;
- const int nblocks = len / 4;
- int i;
-
- uint32_t h1 = seed;
-
- uint32_t c1 = 0xcc9e2d51;
- uint32_t c2 = 0x1b873593;
-
- //----------
- // body
-
- const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
-
- for(i = -nblocks; i; i++)
- {
- uint32_t k1 = getblock(blocks,i);
-
- k1 *= c1;
- k1 = ROTL32(k1,15);
- k1 *= c2;
-
- h1 ^= k1;
- h1 = ROTL32(h1,13);
- h1 = h1*5+0xe6546b64;
- }
-
- //----------
- // tail
-
- const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
-
- uint32_t k1 = 0;
-
- switch(len & 3)
- {
- case 3: k1 ^= tail[2] << 16;
- /* fall through */
- case 2: k1 ^= tail[1] << 8;
- /* fall through */
- case 1: k1 ^= tail[0];
- k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
- };
-
- //----------
- // finalization
-
- h1 ^= len;
-
- h1 = fmix32(h1);
-
- *(uint32_t*)out = h1;
-}
-
-//-----------------------------------------------------------------------------
-
-void MurmurHash3_x86_128 ( const void * key, const int len,
- uint32_t seed, void * out )
-{
- const uint8_t * data = (const uint8_t*)key;
- const int nblocks = len / 16;
- int i;
-
- uint32_t h1 = seed;
- uint32_t h2 = seed;
- uint32_t h3 = seed;
- uint32_t h4 = seed;
-
- uint32_t c1 = 0x239b961b;
- uint32_t c2 = 0xab0e9789;
- uint32_t c3 = 0x38b34ae5;
- uint32_t c4 = 0xa1e38b93;
-
- //----------
- // body
-
- const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
-
- for(i = -nblocks; i; i++)
- {
- uint32_t k1 = getblock(blocks,i*4+0);
- uint32_t k2 = getblock(blocks,i*4+1);
- uint32_t k3 = getblock(blocks,i*4+2);
- uint32_t k4 = getblock(blocks,i*4+3);
-
- k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
-
- h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
-
- k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
-
- h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
-
- k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
-
- h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
-
- k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
-
- h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
- }
-
- //----------
- // tail
-
- const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
-
- uint32_t k1 = 0;
- uint32_t k2 = 0;
- uint32_t k3 = 0;
- uint32_t k4 = 0;
-
- switch(len & 15)
- {
- case 15: k4 ^= tail[14] << 16;
- /* fall through */
- case 14: k4 ^= tail[13] << 8;
- /* fall through */
- case 13: k4 ^= tail[12] << 0;
- k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
- /* fall through */
- case 12: k3 ^= tail[11] << 24;
- /* fall through */
- case 11: k3 ^= tail[10] << 16;
- /* fall through */
- case 10: k3 ^= tail[ 9] << 8;
- /* fall through */
- case 9: k3 ^= tail[ 8] << 0;
- k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
- /* fall through */
- case 8: k2 ^= tail[ 7] << 24;
- /* fall through */
- case 7: k2 ^= tail[ 6] << 16;
- /* fall through */
- case 6: k2 ^= tail[ 5] << 8;
- /* fall through */
- case 5: k2 ^= tail[ 4] << 0;
- k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
- /* fall through */
- case 4: k1 ^= tail[ 3] << 24;
- /* fall through */
- case 3: k1 ^= tail[ 2] << 16;
- /* fall through */
- case 2: k1 ^= tail[ 1] << 8;
- /* fall through */
- case 1: k1 ^= tail[ 0] << 0;
- k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
- };
-
- //----------
- // finalization
-
- h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
-
- h1 += h2; h1 += h3; h1 += h4;
- h2 += h1; h3 += h1; h4 += h1;
-
- h1 = fmix32(h1);
- h2 = fmix32(h2);
- h3 = fmix32(h3);
- h4 = fmix32(h4);
-
- h1 += h2; h1 += h3; h1 += h4;
- h2 += h1; h3 += h1; h4 += h1;
-
- ((uint32_t*)out)[0] = h1;
- ((uint32_t*)out)[1] = h2;
- ((uint32_t*)out)[2] = h3;
- ((uint32_t*)out)[3] = h4;
-}
-
-//-----------------------------------------------------------------------------
-
-void MurmurHash3_x64_128 ( const void * key, const int len,
- const uint32_t seed, void * out )
-{
- const uint8_t * data = (const uint8_t*)key;
- const int nblocks = len / 16;
- int i;
-
- uint64_t h1 = seed;
- uint64_t h2 = seed;
-
- uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
- uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
-
- //----------
- // body
-
- const uint64_t * blocks = (const uint64_t *)(data);
-
- for(i = 0; i < nblocks; i++)
- {
- uint64_t k1 = getblock(blocks,i*2+0);
- uint64_t k2 = getblock(blocks,i*2+1);
-
- k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
-
- h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
-
- k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
-
- h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
- }
-
- //----------
- // tail
-
- const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
-
- uint64_t k1 = 0;
- uint64_t k2 = 0;
-
- switch(len & 15)
- {
- case 15: k2 ^= (uint64_t)(tail[14]) << 48;
- /* fall through */
- case 14: k2 ^= (uint64_t)(tail[13]) << 40;
- /* fall through */
- case 13: k2 ^= (uint64_t)(tail[12]) << 32;
- /* fall through */
- case 12: k2 ^= (uint64_t)(tail[11]) << 24;
- /* fall through */
- case 11: k2 ^= (uint64_t)(tail[10]) << 16;
- /* fall through */
- case 10: k2 ^= (uint64_t)(tail[ 9]) << 8;
- /* fall through */
- case 9: k2 ^= (uint64_t)(tail[ 8]) << 0;
- k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
- /* fall through */
- case 8: k1 ^= (uint64_t)(tail[ 7]) << 56;
- /* fall through */
- case 7: k1 ^= (uint64_t)(tail[ 6]) << 48;
- /* fall through */
- case 6: k1 ^= (uint64_t)(tail[ 5]) << 40;
- /* fall through */
- case 5: k1 ^= (uint64_t)(tail[ 4]) << 32;
- /* fall through */
- case 4: k1 ^= (uint64_t)(tail[ 3]) << 24;
- /* fall through */
- case 3: k1 ^= (uint64_t)(tail[ 2]) << 16;
- /* fall through */
- case 2: k1 ^= (uint64_t)(tail[ 1]) << 8;
- /* fall through */
- case 1: k1 ^= (uint64_t)(tail[ 0]) << 0;
- k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
- };
-
- //----------
- // finalization
-
- h1 ^= len; h2 ^= len;
-
- h1 += h2;
- h2 += h1;
-
- h1 = fmix64(h1);
- h2 = fmix64(h2);
-
- h1 += h2;
- h2 += h1;
-
- ((uint64_t*)out)[0] = h1;
- ((uint64_t*)out)[1] = h2;
-}
-
-//-----------------------------------------------------------------------------
-
+++ /dev/null
-//-----------------------------------------------------------------------------
-// MurmurHash3 was written by Austin Appleby, and is placed in the
-// public domain. The author hereby disclaims copyright to this source
-// code.
-
-#pragma once
-
-//-----------------------------------------------------------------------------
-
-void MurmurHash3_x86_32 (const void *key, int len, uint32_t seed, void *out);
-
-void MurmurHash3_x86_128(const void *key, int len, uint32_t seed, void *out);
-
-void MurmurHash3_x64_128(const void *key, int len, uint32_t seed, void *out);
-
-//-----------------------------------------------------------------------------
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libhashkit/common.h"
-#include "libhashkit/murmur3.h"
-
-uint32_t hashkit_murmur3(const char *key, size_t length, void *)
-{
- const uint32_t seed= (0xdeadbeef * (uint32_t)length);
-
- uint32_t ret;
- MurmurHash3_x86_32(key, int(length), seed, &ret);
-
- return ret;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libhashkit/common.h>
-
-#ifdef HAVE_HSIEH_HASH
-#error "not supported"
-#else
-uint32_t hashkit_hsieh(const char *, size_t , void *)
-{
- return 0;
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-/*
- This has is Jenkin's "One at A time Hash".
-http://en.wikipedia.org/wiki/Jenkins_hash_function
-*/
-
-#include <libhashkit/common.h>
-
-uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context)
-{
- const char *ptr= key;
- uint32_t value= 0;
- (void)context;
-
- while (key_length--)
- {
- uint32_t val= (uint32_t) *ptr++;
- value += val;
- value += (value << 10);
- value ^= (value >> 6);
- }
- value += (value << 3);
- value ^= (value >> 11);
- value += (value << 15);
-
- return value;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-/**
- * rijndael-alg-fst.c
- *
- * @version 3.0 (December 2000)
- *
- * Optimised ANSI C code for the Rijndael cipher (now AES)
- *
- * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
- * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
- * @author Paulo Barreto <paulo.barreto@terra.com.br>
- *
- * This code is hereby placed in the public domain.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include <assert.h>
-#include <stdlib.h>
-
-#include "libhashkit/rijndael.hpp"
-
-/*
-Te0[x] = S [x].[02, 01, 01, 03];
-Te1[x] = S [x].[03, 02, 01, 01];
-Te2[x] = S [x].[01, 03, 02, 01];
-Te3[x] = S [x].[01, 01, 03, 02];
-Te4[x] = S [x].[01, 01, 01, 01];
-
-Td0[x] = Si[x].[0e, 09, 0d, 0b];
-Td1[x] = Si[x].[0b, 0e, 09, 0d];
-Td2[x] = Si[x].[0d, 0b, 0e, 09];
-Td3[x] = Si[x].[09, 0d, 0b, 0e];
-Td4[x] = Si[x].[01, 01, 01, 01];
-*/
-
-static const u32 Te0[256] = {
- 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
- 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
- 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
- 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
- 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
- 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
- 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
- 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
- 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
- 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
- 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
- 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
- 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
- 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
- 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
- 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
- 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
- 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
- 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
- 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
- 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
- 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
- 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
- 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
- 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
- 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
- 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
- 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
- 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
- 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
- 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
- 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
- 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
- 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
- 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
- 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
- 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
- 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
- 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
- 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
- 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
- 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
- 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
- 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
- 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
- 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
- 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
- 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
- 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
- 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
- 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
- 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
- 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
- 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
- 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
- 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
- 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
- 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
- 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
- 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
- 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
- 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
- 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
- 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
-};
-static const u32 Te1[256] = {
- 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
- 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
- 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
- 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
- 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
- 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
- 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
- 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
- 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
- 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
- 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
- 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
- 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
- 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
- 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
- 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
- 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
- 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
- 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
- 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
- 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
- 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
- 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
- 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
- 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
- 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
- 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
- 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
- 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
- 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
- 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
- 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
- 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
- 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
- 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
- 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
- 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
- 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
- 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
- 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
- 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
- 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
- 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
- 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
- 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
- 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
- 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
- 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
- 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
- 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
- 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
- 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
- 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
- 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
- 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
- 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
- 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
- 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
- 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
- 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
- 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
- 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
- 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
- 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
-};
-static const u32 Te2[256] = {
- 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
- 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
- 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
- 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
- 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
- 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
- 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
- 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
- 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
- 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
- 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
- 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
- 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
- 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
- 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
- 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
- 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
- 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
- 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
- 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
- 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
- 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
- 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
- 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
- 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
- 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
- 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
- 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
- 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
- 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
- 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
- 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
- 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
- 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
- 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
- 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
- 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
- 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
- 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
- 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
- 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
- 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
- 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
- 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
- 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
- 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
- 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
- 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
- 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
- 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
- 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
- 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
- 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
- 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
- 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
- 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
- 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
- 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
- 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
- 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
- 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
- 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
- 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
- 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
-};
-static const u32 Te3[256] = {
-
- 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
- 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
- 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
- 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
- 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
- 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
- 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
- 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
- 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
- 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
- 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
- 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
- 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
- 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
- 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
- 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
- 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
- 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
- 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
- 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
- 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
- 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
- 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
- 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
- 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
- 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
- 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
- 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
- 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
- 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
- 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
- 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
- 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
- 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
- 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
- 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
- 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
- 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
- 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
- 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
- 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
- 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
- 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
- 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
- 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
- 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
- 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
- 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
- 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
- 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
- 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
- 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
- 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
- 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
- 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
- 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
- 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
- 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
- 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
- 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
- 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
- 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
- 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
- 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
-};
-static const u32 Te4[256] = {
- 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
- 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
- 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
- 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
- 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
- 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
- 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
- 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
- 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
- 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
- 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
- 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
- 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
- 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
- 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
- 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
- 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
- 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
- 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
- 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
- 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
- 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
- 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
- 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
- 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
- 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
- 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
- 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
- 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
- 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
- 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
- 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
- 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
- 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
- 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
- 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
- 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
- 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
- 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
- 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
- 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
- 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
- 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
- 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
- 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
- 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
- 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
- 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
- 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
- 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
- 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
- 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
- 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
- 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
- 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
- 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
- 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
- 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
- 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
- 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
- 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
- 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
- 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
- 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
-};
-static const u32 Td0[256] = {
- 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
- 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
- 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
- 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
- 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
- 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
- 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
- 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
- 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
- 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
- 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
- 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
- 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
- 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
- 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
- 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
- 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
- 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
- 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
- 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
- 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
- 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
- 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
- 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
- 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
- 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
- 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
- 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
- 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
- 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
- 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
- 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
- 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
- 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
- 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
- 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
- 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
- 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
- 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
- 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
- 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
- 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
- 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
- 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
- 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
- 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
- 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
- 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
- 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
- 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
- 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
- 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
- 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
- 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
- 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
- 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
- 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
- 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
- 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
- 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
- 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
- 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
- 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
- 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
-};
-static const u32 Td1[256] = {
- 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
- 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
- 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
- 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
- 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
- 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
- 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
- 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
- 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
- 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
- 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
- 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
- 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
- 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
- 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
- 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
- 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
- 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
- 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
- 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
- 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
- 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
- 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
- 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
- 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
- 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
- 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
- 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
- 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
- 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
- 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
- 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
- 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
- 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
- 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
- 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
- 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
- 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
- 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
- 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
- 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
- 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
- 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
- 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
- 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
- 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
- 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
- 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
- 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
- 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
- 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
- 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
- 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
- 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
- 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
- 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
- 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
- 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
- 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
- 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
- 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
- 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
- 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
- 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
-};
-static const u32 Td2[256] = {
- 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
- 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
- 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
- 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
- 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
- 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
- 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
- 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
- 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
- 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
- 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
- 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
- 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
- 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
- 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
- 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
- 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
- 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
- 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
- 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
-
- 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
- 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
- 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
- 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
- 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
- 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
- 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
- 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
- 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
- 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
- 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
- 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
- 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
- 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
- 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
- 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
- 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
- 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
- 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
- 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
- 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
- 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
- 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
- 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
- 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
- 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
- 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
- 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
- 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
- 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
- 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
- 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
- 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
- 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
- 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
- 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
- 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
- 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
- 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
- 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
- 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
- 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
- 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
- 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
-};
-static const u32 Td3[256] = {
- 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
- 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
- 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
- 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
- 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
- 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
- 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
- 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
- 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
- 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
- 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
- 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
- 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
- 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
- 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
- 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
- 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
- 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
- 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
- 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
- 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
- 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
- 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
- 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
- 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
- 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
- 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
- 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
- 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
- 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
- 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
- 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
- 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
- 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
- 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
- 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
- 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
- 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
- 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
- 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
- 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
- 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
- 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
- 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
- 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
- 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
- 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
- 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
- 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
- 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
- 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
- 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
- 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
- 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
- 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
- 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
- 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
- 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
- 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
- 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
- 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
- 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
- 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
- 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
-};
-static const u32 Td4[256] = {
- 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
- 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
- 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
- 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
- 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
- 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
- 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
- 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
- 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
- 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
- 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
- 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
- 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
- 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
- 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
- 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
- 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
- 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
- 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
- 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
- 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
- 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
- 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
- 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
- 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
- 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
- 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
- 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
- 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
- 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
- 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
- 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
- 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
- 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
- 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
- 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
- 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
- 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
- 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
- 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
- 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
- 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
- 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
- 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
- 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
- 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
- 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
- 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
- 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
- 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
- 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
- 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
- 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
- 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
- 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
- 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
- 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
- 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
- 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
- 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
- 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
- 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
- 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
- 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
-};
-static const u32 rcon[] = {
- 0x01000000, 0x02000000, 0x04000000, 0x08000000,
- 0x10000000, 0x20000000, 0x40000000, 0x80000000,
- 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
-};
-
-#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
-
-#ifdef _MSC_VER
-#define GETU32(p) SWAP(*((u32 *)(p)))
-#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
-#else
-#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
-#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
-#endif
-
-/**
- * Expand the cipher key into the encryption key schedule.
- *
- * @return the number of rounds for the given cipher key size.
- */
-int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
- int i = 0;
- u32 temp;
-
- rk[0] = GETU32(cipherKey );
- rk[1] = GETU32(cipherKey + 4);
- rk[2] = GETU32(cipherKey + 8);
- rk[3] = GETU32(cipherKey + 12);
- if (keyBits == 128) {
- for (;;) {
- temp = rk[3];
- rk[4] = rk[0] ^
- (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
- (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
- (Te4[(temp ) & 0xff] & 0x0000ff00) ^
- (Te4[(temp >> 24) ] & 0x000000ff) ^
- rcon[i];
- rk[5] = rk[1] ^ rk[4];
- rk[6] = rk[2] ^ rk[5];
- rk[7] = rk[3] ^ rk[6];
- if (++i == 10) {
- return 10;
- }
- rk += 4;
- }
- }
- rk[4] = GETU32(cipherKey + 16);
- rk[5] = GETU32(cipherKey + 20);
- if (keyBits == 192) {
- for (;;) {
- temp = rk[ 5];
- rk[ 6] = rk[ 0] ^
- (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
- (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
- (Te4[(temp ) & 0xff] & 0x0000ff00) ^
- (Te4[(temp >> 24) ] & 0x000000ff) ^
- rcon[i];
- rk[ 7] = rk[ 1] ^ rk[ 6];
- rk[ 8] = rk[ 2] ^ rk[ 7];
- rk[ 9] = rk[ 3] ^ rk[ 8];
- if (++i == 8) {
- return 12;
- }
- rk[10] = rk[ 4] ^ rk[ 9];
- rk[11] = rk[ 5] ^ rk[10];
- rk += 6;
- }
- }
- rk[6] = GETU32(cipherKey + 24);
- rk[7] = GETU32(cipherKey + 28);
- if (keyBits == 256) {
- for (;;) {
- temp = rk[ 7];
- rk[ 8] = rk[ 0] ^
- (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
- (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
- (Te4[(temp ) & 0xff] & 0x0000ff00) ^
- (Te4[(temp >> 24) ] & 0x000000ff) ^
- rcon[i];
- rk[ 9] = rk[ 1] ^ rk[ 8];
- rk[10] = rk[ 2] ^ rk[ 9];
- rk[11] = rk[ 3] ^ rk[10];
- if (++i == 7) {
- return 14;
- }
- temp = rk[11];
- rk[12] = rk[ 4] ^
- (Te4[(temp >> 24) ] & 0xff000000) ^
- (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(temp ) & 0xff] & 0x000000ff);
- rk[13] = rk[ 5] ^ rk[12];
- rk[14] = rk[ 6] ^ rk[13];
- rk[15] = rk[ 7] ^ rk[14];
-
- rk += 8;
- }
- }
- return 0;
-}
-
-/**
- * Expand the cipher key into the decryption key schedule.
- *
- * @return the number of rounds for the given cipher key size.
- */
-int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
- int Nr, i, j;
- u32 temp;
-
- /* expand the cipher key: */
- Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
- /* invert the order of the round keys: */
- for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
- temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
- temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
- temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
- temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
- }
- /* apply the inverse MixColumn transform to all round keys but the first and the last: */
- for (i = 1; i < Nr; i++) {
- rk += 4;
- rk[0] =
- Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
- Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
- Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
- Td3[Te4[(rk[0] ) & 0xff] & 0xff];
- rk[1] =
- Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
- Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
- Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
- Td3[Te4[(rk[1] ) & 0xff] & 0xff];
- rk[2] =
- Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
- Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
- Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
- Td3[Te4[(rk[2] ) & 0xff] & 0xff];
- rk[3] =
- Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
- Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
- Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
- Td3[Te4[(rk[3] ) & 0xff] & 0xff];
- }
- return Nr;
-}
-
-void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
- u32 s0, s1, s2, s3, t0, t1, t2, t3;
-#ifndef FULL_UNROLL
- int r;
-#endif /* ?FULL_UNROLL */
-
- /*
- * map byte array block to cipher state
- * and add initial round key:
- */
- s0 = GETU32(pt ) ^ rk[0];
- s1 = GETU32(pt + 4) ^ rk[1];
- s2 = GETU32(pt + 8) ^ rk[2];
- s3 = GETU32(pt + 12) ^ rk[3];
-#ifdef FULL_UNROLL
- /* round 1: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
- /* round 2: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
- /* round 3: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
- /* round 4: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
- /* round 5: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
- /* round 6: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
- /* round 7: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
- /* round 8: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
- /* round 9: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
- if (Nr > 10) {
- /* round 10: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
- /* round 11: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
- if (Nr > 12) {
- /* round 12: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
- /* round 13: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
- }
- }
- rk += Nr << 2;
-#else /* !FULL_UNROLL */
- /*
- * Nr - 1 full rounds:
- */
- r = Nr >> 1;
- for (;;) {
- t0 =
- Te0[(s0 >> 24) ] ^
- Te1[(s1 >> 16) & 0xff] ^
- Te2[(s2 >> 8) & 0xff] ^
- Te3[(s3 ) & 0xff] ^
- rk[4];
- t1 =
- Te0[(s1 >> 24) ] ^
- Te1[(s2 >> 16) & 0xff] ^
- Te2[(s3 >> 8) & 0xff] ^
- Te3[(s0 ) & 0xff] ^
- rk[5];
- t2 =
- Te0[(s2 >> 24) ] ^
- Te1[(s3 >> 16) & 0xff] ^
- Te2[(s0 >> 8) & 0xff] ^
- Te3[(s1 ) & 0xff] ^
- rk[6];
- t3 =
- Te0[(s3 >> 24) ] ^
- Te1[(s0 >> 16) & 0xff] ^
- Te2[(s1 >> 8) & 0xff] ^
- Te3[(s2 ) & 0xff] ^
- rk[7];
-
- rk += 8;
- if (--r == 0) {
- break;
- }
-
- s0 =
- Te0[(t0 >> 24) ] ^
- Te1[(t1 >> 16) & 0xff] ^
- Te2[(t2 >> 8) & 0xff] ^
- Te3[(t3 ) & 0xff] ^
- rk[0];
- s1 =
- Te0[(t1 >> 24) ] ^
- Te1[(t2 >> 16) & 0xff] ^
- Te2[(t3 >> 8) & 0xff] ^
- Te3[(t0 ) & 0xff] ^
- rk[1];
- s2 =
- Te0[(t2 >> 24) ] ^
- Te1[(t3 >> 16) & 0xff] ^
- Te2[(t0 >> 8) & 0xff] ^
- Te3[(t1 ) & 0xff] ^
- rk[2];
- s3 =
- Te0[(t3 >> 24) ] ^
- Te1[(t0 >> 16) & 0xff] ^
- Te2[(t1 >> 8) & 0xff] ^
- Te3[(t2 ) & 0xff] ^
- rk[3];
- }
-#endif /* ?FULL_UNROLL */
- /*
- * apply last round and
- * map cipher state to byte array block:
- */
- s0 =
- (Te4[(t0 >> 24) ] & 0xff000000) ^
- (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t3 ) & 0xff] & 0x000000ff) ^
- rk[0];
- PUTU32(ct , s0);
- s1 =
- (Te4[(t1 >> 24) ] & 0xff000000) ^
- (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t0 ) & 0xff] & 0x000000ff) ^
- rk[1];
- PUTU32(ct + 4, s1);
- s2 =
- (Te4[(t2 >> 24) ] & 0xff000000) ^
- (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t1 ) & 0xff] & 0x000000ff) ^
- rk[2];
- PUTU32(ct + 8, s2);
- s3 =
- (Te4[(t3 >> 24) ] & 0xff000000) ^
- (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t2 ) & 0xff] & 0x000000ff) ^
- rk[3];
- PUTU32(ct + 12, s3);
-}
-
-void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) {
- u32 s0, s1, s2, s3, t0, t1, t2, t3;
-#ifndef FULL_UNROLL
- int r;
-#endif /* ?FULL_UNROLL */
-
- /*
- * map byte array block to cipher state
- * and add initial round key:
- */
- s0 = GETU32(ct ) ^ rk[0];
- s1 = GETU32(ct + 4) ^ rk[1];
- s2 = GETU32(ct + 8) ^ rk[2];
- s3 = GETU32(ct + 12) ^ rk[3];
-#ifdef FULL_UNROLL
- /* round 1: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
- /* round 2: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
- /* round 3: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
- /* round 4: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
- /* round 5: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
- /* round 6: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
- /* round 7: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
- /* round 8: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
- /* round 9: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
- if (Nr > 10) {
- /* round 10: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
- /* round 11: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
- if (Nr > 12) {
- /* round 12: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
- /* round 13: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
- }
- }
- rk += Nr << 2;
-#else /* !FULL_UNROLL */
- /*
- * Nr - 1 full rounds:
- */
- r = Nr >> 1;
- for (;;) {
- t0 =
- Td0[(s0 >> 24) ] ^
- Td1[(s3 >> 16) & 0xff] ^
- Td2[(s2 >> 8) & 0xff] ^
- Td3[(s1 ) & 0xff] ^
- rk[4];
- t1 =
- Td0[(s1 >> 24) ] ^
- Td1[(s0 >> 16) & 0xff] ^
- Td2[(s3 >> 8) & 0xff] ^
- Td3[(s2 ) & 0xff] ^
- rk[5];
- t2 =
- Td0[(s2 >> 24) ] ^
- Td1[(s1 >> 16) & 0xff] ^
- Td2[(s0 >> 8) & 0xff] ^
- Td3[(s3 ) & 0xff] ^
- rk[6];
- t3 =
- Td0[(s3 >> 24) ] ^
- Td1[(s2 >> 16) & 0xff] ^
- Td2[(s1 >> 8) & 0xff] ^
- Td3[(s0 ) & 0xff] ^
- rk[7];
-
- rk += 8;
- if (--r == 0) {
- break;
- }
-
- s0 =
- Td0[(t0 >> 24) ] ^
- Td1[(t3 >> 16) & 0xff] ^
- Td2[(t2 >> 8) & 0xff] ^
- Td3[(t1 ) & 0xff] ^
- rk[0];
- s1 =
- Td0[(t1 >> 24) ] ^
- Td1[(t0 >> 16) & 0xff] ^
- Td2[(t3 >> 8) & 0xff] ^
- Td3[(t2 ) & 0xff] ^
- rk[1];
- s2 =
- Td0[(t2 >> 24) ] ^
- Td1[(t1 >> 16) & 0xff] ^
- Td2[(t0 >> 8) & 0xff] ^
- Td3[(t3 ) & 0xff] ^
- rk[2];
- s3 =
- Td0[(t3 >> 24) ] ^
- Td1[(t2 >> 16) & 0xff] ^
- Td2[(t1 >> 8) & 0xff] ^
- Td3[(t0 ) & 0xff] ^
- rk[3];
- }
-#endif /* ?FULL_UNROLL */
- /*
- * apply last round and
- * map cipher state to byte array block:
- */
- s0 =
- (Td4[(t0 >> 24) ] & 0xff000000) ^
- (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(t1 ) & 0xff] & 0x000000ff) ^
- rk[0];
- PUTU32(pt , s0);
- s1 =
- (Td4[(t1 >> 24) ] & 0xff000000) ^
- (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(t2 ) & 0xff] & 0x000000ff) ^
- rk[1];
- PUTU32(pt + 4, s1);
- s2 =
- (Td4[(t2 >> 24) ] & 0xff000000) ^
- (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(t3 ) & 0xff] & 0x000000ff) ^
- rk[2];
- PUTU32(pt + 8, s2);
- s3 =
- (Td4[(t3 >> 24) ] & 0xff000000) ^
- (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(t0 ) & 0xff] & 0x000000ff) ^
- rk[3];
- PUTU32(pt + 12, s3);
-}
-
-#ifdef INTERMEDIATE_VALUE_KAT
-
-void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) {
- int r;
- u32 s0, s1, s2, s3, t0, t1, t2, t3;
-
- /*
- * map byte array block to cipher state
- * and add initial round key:
- */
- s0 = GETU32(block ) ^ rk[0];
- s1 = GETU32(block + 4) ^ rk[1];
- s2 = GETU32(block + 8) ^ rk[2];
- s3 = GETU32(block + 12) ^ rk[3];
- rk += 4;
-
- /*
- * Nr - 1 full rounds:
- */
- for (r = (rounds < Nr ? rounds : Nr - 1); r > 0; r--) {
- t0 =
- Te0[(s0 >> 24) ] ^
- Te1[(s1 >> 16) & 0xff] ^
- Te2[(s2 >> 8) & 0xff] ^
- Te3[(s3 ) & 0xff] ^
- rk[0];
- t1 =
- Te0[(s1 >> 24) ] ^
- Te1[(s2 >> 16) & 0xff] ^
- Te2[(s3 >> 8) & 0xff] ^
- Te3[(s0 ) & 0xff] ^
- rk[1];
- t2 =
- Te0[(s2 >> 24) ] ^
- Te1[(s3 >> 16) & 0xff] ^
- Te2[(s0 >> 8) & 0xff] ^
- Te3[(s1 ) & 0xff] ^
- rk[2];
- t3 =
- Te0[(s3 >> 24) ] ^
- Te1[(s0 >> 16) & 0xff] ^
- Te2[(s1 >> 8) & 0xff] ^
- Te3[(s2 ) & 0xff] ^
- rk[3];
-
- s0 = t0;
- s1 = t1;
- s2 = t2;
- s3 = t3;
- rk += 4;
-
- }
-
- /*
- * apply last round and
- * map cipher state to byte array block:
- */
- if (rounds == Nr) {
- t0 =
- (Te4[(s0 >> 24) ] & 0xff000000) ^
- (Te4[(s1 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(s2 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(s3 ) & 0xff] & 0x000000ff) ^
- rk[0];
- t1 =
- (Te4[(s1 >> 24) ] & 0xff000000) ^
- (Te4[(s2 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(s3 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(s0 ) & 0xff] & 0x000000ff) ^
- rk[1];
- t2 =
- (Te4[(s2 >> 24) ] & 0xff000000) ^
- (Te4[(s3 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(s0 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(s1 ) & 0xff] & 0x000000ff) ^
- rk[2];
- t3 =
- (Te4[(s3 >> 24) ] & 0xff000000) ^
- (Te4[(s0 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(s1 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(s2 ) & 0xff] & 0x000000ff) ^
- rk[3];
-
- s0 = t0;
- s1 = t1;
- s2 = t2;
- s3 = t3;
- }
-
- PUTU32(block , s0);
- PUTU32(block + 4, s1);
- PUTU32(block + 8, s2);
- PUTU32(block + 12, s3);
-}
-
-void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) {
- int r;
- u32 s0, s1, s2, s3, t0, t1, t2, t3;
-
- /*
- * map byte array block to cipher state
- * and add initial round key:
- */
- s0 = GETU32(block ) ^ rk[0];
- s1 = GETU32(block + 4) ^ rk[1];
- s2 = GETU32(block + 8) ^ rk[2];
- s3 = GETU32(block + 12) ^ rk[3];
- rk += 4;
-
- /*
- * Nr - 1 full rounds:
- */
- for (r = (rounds < Nr ? rounds : Nr) - 1; r > 0; r--) {
- t0 =
- Td0[(s0 >> 24) ] ^
- Td1[(s3 >> 16) & 0xff] ^
- Td2[(s2 >> 8) & 0xff] ^
- Td3[(s1 ) & 0xff] ^
- rk[0];
- t1 =
- Td0[(s1 >> 24) ] ^
- Td1[(s0 >> 16) & 0xff] ^
- Td2[(s3 >> 8) & 0xff] ^
- Td3[(s2 ) & 0xff] ^
- rk[1];
- t2 =
- Td0[(s2 >> 24) ] ^
- Td1[(s1 >> 16) & 0xff] ^
- Td2[(s0 >> 8) & 0xff] ^
- Td3[(s3 ) & 0xff] ^
- rk[2];
- t3 =
- Td0[(s3 >> 24) ] ^
- Td1[(s2 >> 16) & 0xff] ^
- Td2[(s1 >> 8) & 0xff] ^
- Td3[(s0 ) & 0xff] ^
- rk[3];
-
- s0 = t0;
- s1 = t1;
- s2 = t2;
- s3 = t3;
- rk += 4;
-
- }
-
- /*
- * complete the last round and
- * map cipher state to byte array block:
- */
- t0 =
- (Td4[(s0 >> 24) ] & 0xff000000) ^
- (Td4[(s3 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(s2 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(s1 ) & 0xff] & 0x000000ff);
- t1 =
- (Td4[(s1 >> 24) ] & 0xff000000) ^
- (Td4[(s0 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(s3 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(s2 ) & 0xff] & 0x000000ff);
- t2 =
- (Td4[(s2 >> 24) ] & 0xff000000) ^
- (Td4[(s1 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(s0 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(s3 ) & 0xff] & 0x000000ff);
- t3 =
- (Td4[(s3 >> 24) ] & 0xff000000) ^
- (Td4[(s2 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(s1 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(s0 ) & 0xff] & 0x000000ff);
-
- if (rounds == Nr) {
- t0 ^= rk[0];
- t1 ^= rk[1];
- t2 ^= rk[2];
- t3 ^= rk[3];
- }
-
- PUTU32(block , t0);
- PUTU32(block + 4, t1);
- PUTU32(block + 8, t2);
- PUTU32(block + 12, t3);
-}
-
-#endif /* INTERMEDIATE_VALUE_KAT */
+++ /dev/null
-/**
- * rijndael-alg-fst.h
- *
- * @version 3.0 (December 2000)
- *
- * Optimised ANSI C code for the Rijndael cipher (now AES)
- *
- * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
- * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
- * @author Paulo Barreto <paulo.barreto@terra.com.br>
- *
- * This code is hereby placed in the public domain.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#define MAXKC (256/32)
-#define MAXKB (256/8)
-#define MAXNR 14
-
-#define AES_MAXKC MAXKC
-#define AES_MAXKB MAXKB
-#define AES_MAXNR MAXNR
-
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-
-int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
-int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
-void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]);
-void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]);
-
-#ifdef INTERMEDIATE_VALUE_KAT
-void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds);
-void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds);
-#endif /* INTERMEDIATE_VALUE_KAT */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libhashkit/common.h>
-
-const char * libhashkit_string_hash(hashkit_hash_algorithm_t type)
-{
- switch(type)
- {
- case HASHKIT_HASH_DEFAULT: return "DEFAULT";
- case HASHKIT_HASH_MD5: return "MD5";
- case HASHKIT_HASH_CRC: return "CRC";
- case HASHKIT_HASH_FNV1_64: return "FNV1_64";
- case HASHKIT_HASH_FNV1A_64: return "FNV1A_64";
- case HASHKIT_HASH_FNV1_32: return "FNV1_32";
- case HASHKIT_HASH_FNV1A_32: return "FNV1A_32";
- case HASHKIT_HASH_HSIEH: return "HSIEH";
- case HASHKIT_HASH_MURMUR: return "MURMUR";
- case HASHKIT_HASH_MURMUR3: return "MURMUR3";
- case HASHKIT_HASH_JENKINS: return "JENKINS";
- case HASHKIT_HASH_CUSTOM: return "CUSTOM";
- default:
- case HASHKIT_HASH_MAX: return "INVALID";
- }
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2009 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-#include <libhashkit/common.h>
-
-const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc)
-{
- (void)ptr;
- switch (rc)
- {
- case HASHKIT_SUCCESS: return "SUCCESS";
- case HASHKIT_FAILURE: return "FAILURE";
- case HASHKIT_MEMORY_ALLOCATION_FAILURE: return "MEMORY ALLOCATION FAILURE";
- case HASHKIT_INVALID_ARGUMENT: return "INVALID ARGUMENT";
- case HASHKIT_INVALID_HASH: return "INVALID hashkit_hash_algorithm_t";
- case HASHKIT_MAXIMUM_RETURN:
- default:
- return "INVALID hashkit_return_t";
- }
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libhashkit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libhashkit/common.h>
-
-#include <cassert>
-#include <cstring>
-
-#define HASHKIT_BLOCK_SIZE 1024
-
-struct hashkit_string_st {
- char *end;
- size_t current_size;
- char *string;
-};
-
-inline static bool _string_check(hashkit_string_st *string, size_t need)
-{
- if (need and need > (size_t)(string->current_size - (size_t)(string->end - string->string)))
- {
- size_t current_offset= (size_t) (string->end - string->string);
-
- /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
- size_t adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / HASHKIT_BLOCK_SIZE;
- adjust++;
-
- size_t new_size= sizeof(char) * (size_t)((adjust * HASHKIT_BLOCK_SIZE) + string->current_size);
- /* Test for overflow */
- if (new_size < need)
- {
- return false;
- }
-
- char *new_value= (char*)realloc(string->string, new_size);
-
- if (new_value == NULL)
- {
- return false;
- }
-
- string->string= new_value;
- string->end= string->string + current_offset;
-
- string->current_size+= (HASHKIT_BLOCK_SIZE * adjust);
- }
-
- return true;
-}
-
-static inline void _init_string(hashkit_string_st *self)
-{
- self->current_size= 0;
- self->end= self->string= NULL;
-}
-
-hashkit_string_st *hashkit_string_create(size_t initial_size)
-{
- hashkit_string_st* self= (hashkit_string_st*)calloc(1, sizeof(hashkit_string_st));
-
- if (self)
- {
- if (_string_check(self, initial_size) == false)
- {
- free(self);
-
- return NULL;
- }
- }
-
- return self;
-}
-
-#if 0
-static bool hashkit_string_append_null(hashkit_string_st *string)
-{
- if (_string_check(string, 1) == false)
- {
- return false;
- }
-
- *string->end= 0;
-
- return true;
-}
-#endif
-
-bool hashkit_string_append_character(hashkit_string_st *string,
- char character)
-{
- if (_string_check(string, 1) == false)
- {
- return false;
- }
-
- *string->end= character;
- string->end++;
-
- return true;
-}
-
-bool hashkit_string_append(hashkit_string_st *string,
- const char *value, size_t length)
-{
- if (_string_check(string, length) == false)
- {
- return false;
- }
-
- assert(length <= string->current_size);
- assert(string->string);
- assert(string->end >= string->string);
-
- memcpy(string->end, value, length);
- string->end+= length;
-
- return true;
-}
-
-char *hashkit_string_c_copy(hashkit_string_st *string)
-{
- if (hashkit_string_length(string) == 0)
- {
- return NULL;
- }
-
- char *c_ptr= static_cast<char *>(malloc((hashkit_string_length(string)+1) * sizeof(char)));
- if (c_ptr == NULL)
- {
- return NULL;
- }
-
- memcpy(c_ptr, hashkit_string_c_str(string), hashkit_string_length(string));
- c_ptr[hashkit_string_length(string)]= 0;
-
- return c_ptr;
-}
-
-void hashkit_string_reset(hashkit_string_st *string)
-{
- string->end= string->string;
-}
-
-void hashkit_string_free(hashkit_string_st *ptr)
-{
- if (ptr == NULL)
- {
- return;
- }
-
- if (ptr->string)
- {
- free(ptr->string);
- }
- free(ptr);
-}
-
-bool hashkit_string_resize(hashkit_string_st& string, const size_t need)
-{
- return _string_check(&string, need);
-}
-
-size_t hashkit_string_length(const hashkit_string_st *self)
-{
- return size_t(self->end -self->string);
-}
-
-size_t hashkit_string_max_size(const hashkit_string_st *self)
-{
- return self->current_size;
-}
-
-char *hashkit_string_take(hashkit_string_st *self)
-{
- assert(self);
- if (self == NULL)
- {
- return NULL;
- }
- char *value= self->string;
-
- _init_string(self);
-
- return value;
-}
-
-char *hashkit_string_c_str_mutable(hashkit_string_st *self)
-{
- assert(self);
- if (self == NULL)
- {
- return NULL;
- }
- return self->string;
-}
-
-const char *hashkit_string_c_str(const hashkit_string_st* self)
-{
- assert(self);
- if (self == NULL)
- {
- return NULL;
- }
- return self->string;
-}
-
-void hashkit_string_set_length(hashkit_string_st *self, size_t length)
-{
- assert(self);
- if (self and _string_check(self, length))
- {
- self->end= self->string +length;
- }
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Hashkit library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-hashkit_string_st *hashkit_string_create(size_t initial_size);
-
-bool hashkit_string_append_character(hashkit_string_st *string, char character);
-
-bool hashkit_string_append(hashkit_string_st *string, const char *value, size_t length);
-
-char *hashkit_string_c_copy(hashkit_string_st *string);
-
-void hashkit_string_reset(hashkit_string_st *string);
-
-bool hashkit_string_resize(hashkit_string_st& string, const size_t need);
-
-size_t hashkit_string_max_size(const hashkit_string_st *self);
-
-char *hashkit_string_take(hashkit_string_st *self);
-
-char *hashkit_string_c_str_mutable(hashkit_string_st *self);
-
-void hashkit_string_set_length(hashkit_string_st *self, size_t length);
+++ /dev/null
-
-configure_file(configure.h.in configure.h @ONLY)
-
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
- FILES_MATCHING REGEX "\\.h(pp)?$"
- PATTERN t EXCLUDE
- )
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- Memory allocation functions.
-*/
-typedef void (*memcached_free_fn)(const memcached_st *ptr, void *mem, void *context);
-typedef void *(*memcached_malloc_fn)(const memcached_st *ptr, const size_t size, void *context);
-typedef void *(*memcached_realloc_fn)(const memcached_st *ptr, void *mem, const size_t size, void *context);
-typedef void *(*memcached_calloc_fn)(const memcached_st *ptr, size_t nelem, const size_t elsize, void *context);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_set_memory_allocators(memcached_st *ptr,
- memcached_malloc_fn mem_malloc,
- memcached_free_fn mem_free,
- memcached_realloc_fn mem_realloc,
- memcached_calloc_fn mem_calloc,
- void *context);
-
-LIBMEMCACHED_API
-void memcached_get_memory_allocators(const memcached_st *ptr,
- memcached_malloc_fn *mem_malloc,
- memcached_free_fn *mem_free,
- memcached_realloc_fn *mem_realloc,
- memcached_calloc_fn *mem_calloc);
-
-LIBMEMCACHED_API
-void *memcached_get_memory_allocators_context(const memcached_st *ptr);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached-1.0/struct/analysis.h>
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-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
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#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 *group_key, size_t group_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 *group_key, size_t group_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 *group_key,
- size_t group_key_length,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value);
-
-LIBMEMCACHED_API
- memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
- const char *group_key,
- size_t group_key_length,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-// No assumptions of NULL should be made
-
-struct memcached_string_t {
- const char *c_str;
- size_t size;
-};
-
-#define memcached_size(X) (X).size;
-#define memcached_c_str(X) (X).c_str;
-#define memcached_string_param(X) (X).c_str, (X).size
-
-#ifdef __cplusplus
-#define memcached_string_printf(X) int((X).size), (X).c_str
-#else
-#define memcached_string_printf(X) (int)((X).size), (X).c_str
-#endif
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#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);
-
-LIBMEMCACHED_API
- const char *libmemcached_string_behavior(const memcached_behavior_t flag);
-
-LIBMEMCACHED_API
- const char *libmemcached_string_distribution(const memcached_server_distribution_t flag);
-
-LIBMEMCACHED_API
- memcached_return_t memcached_bucket_set(memcached_st *self,
- const uint32_t *host_map,
- const uint32_t *forward_map,
- const uint32_t buckets,
- const uint32_t replicas);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_callback_set(memcached_st *ptr,
- const memcached_callback_t flag,
- const void *data);
-LIBMEMCACHED_API
-void *memcached_callback_get(memcached_st *ptr,
- const memcached_callback_t flag,
- memcached_return_t *error);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef memcached_return_t (*memcached_execute_fn)(const memcached_st *ptr, memcached_result_st *result, void *context);
-typedef memcached_return_t (*memcached_server_fn)(const memcached_st *ptr, const memcached_instance_st * server, void *context);
-typedef memcached_return_t (*memcached_stat_fn)(const memcached_instance_st * server,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- void *context);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker, Trond Norbye All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#cmakedefine01 LIBMEMCACHED_ENABLE_DEPRECATED
-#cmakedefine01 LIBMEMCACHED_WITH_SASL_SUPPORT
-
-#define LIBMEMCACHED_VERSION_STRING "@LIBMEMCACHED_VERSION@"
-#define LIBMEMCACHED_VERSION_HEX @LIBMEMCACHED_VERSION_HEX@
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-/* Public defines */
-#define MEMCACHED_DEFAULT_PORT 11211
-#define MEMCACHED_DEFAULT_PORT_STRING "11211"
-#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 5000
-#define MEMCACHED_DEFAULT_CONNECT_TIMEOUT 4000
-#define MEMCACHED_CONTINUUM_ADDITION 10 /* How many extra slots we should build for in the continuum */
-#define MEMCACHED_EXPIRATION_NOT_ADD 0xffffffffU
-#define MEMCACHED_SERVER_FAILURE_LIMIT 5
-#define MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT 2
-#define MEMCACHED_SERVER_FAILURE_DEAD_TIMEOUT 0
-#define MEMCACHED_SERVER_TIMEOUT_LIMIT 0
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
- time_t expiration);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_delete_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- time_t expiration);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- * Warning, none of these should ever be used.
- */
-
-#pragma once
-
-/**
- @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_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;
-typedef memcached_instance_st *memcached_server_instance_st;
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-#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
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
- memcached_return_t memcached_set_encoding_key(memcached_st*, const char *str, size_t length);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
- const char *memcached_error(const memcached_st *);
-
-LIBMEMCACHED_API
- const char *memcached_last_error_message(const memcached_st *);
-
-LIBMEMCACHED_API
- void memcached_error_print(const memcached_st *);
-
-LIBMEMCACHED_API
- memcached_return_t memcached_last_error(const memcached_st *);
-
-LIBMEMCACHED_API
- int memcached_last_error_errno(const memcached_st *);
-
-LIBMEMCACHED_API
- const char *memcached_server_error(const memcached_instance_st * ptr);
-
-LIBMEMCACHED_API
- memcached_return_t memcached_server_error_return(const memcached_instance_st * ptr);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
+++ /dev/null
-/*
- * Summary: Exceptions for the C++ interface
- *
- * Copy: See Copyright for the status of this software.
- *
- */
-
-/**
- * @file
- * @brief Exception declarations
- */
-
-#pragma once
-
-#include <stdexcept>
-#include <string>
-
-namespace memcache
-{
- class Exception : public std::runtime_error
- {
- public:
- Exception(const std::string& msg, int in_errno)
- :
- std::runtime_error(msg),
- _errno(in_errno)
- {}
-
- Exception(const char *msg, int in_errno)
- :
- std::runtime_error(std::string(msg)),
- _errno(in_errno) {}
-
- virtual ~Exception() throw() {}
-
- int getErrno() const
- {
- return _errno;
- }
-
- private:
- int _errno;
- };
-
- class Warning : public Exception
- {
- public:
- Warning(const std::string& msg, int in_errno) : Exception(msg, in_errno) {}
- Warning(const char *msg, int in_errno) : Exception(msg, in_errno) {}
- };
-
- class Error : public Exception
- {
- public:
- Error(const std::string& msg, int in_errno) : Exception(msg, in_errno) {}
- Error(const char *msg, int in_errno) : Exception(msg, in_errno) {}
- virtual ~Error() throw() {}
- };
-
-} /* namespace libmemcached */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_exist(memcached_st *memc, const char *key, size_t key_length);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_exist_by_key(memcached_st *memc,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length);
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_fetch_execute(memcached_st *ptr,
- memcached_execute_fn *callback,
- void *context,
- uint32_t number_of_callbacks);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_flush_buffers(memcached_st *mem);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-#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 *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- size_t *value_length,
- uint32_t *flags,
- memcached_return_t *error);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_mget_by_key(memcached_st *ptr,
- const char *group_key,
- size_t group_key_length,
- const char * const *keys,
- const size_t *key_length,
- 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 *group_key,
- size_t group_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- memcached_execute_fn *callback,
- void *context,
- const uint32_t number_of_callbacks);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The two public hash bits */
-LIBMEMCACHED_API
-uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm);
-
-LIBMEMCACHED_API
-const hashkit_st *memcached_get_hashkit(const memcached_st *ptr);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_set_hashkit(memcached_st *ptr, hashkit_st *hashk);
-
-LIBMEMCACHED_API
-uint32_t memcached_generate_hash(const memcached_st *ptr, const char *key, size_t key_length);
-
-LIBMEMCACHED_API
-void memcached_autoeject(memcached_st *ptr);
-
-LIBMEMCACHED_API
- const char * libmemcached_string_hash(memcached_hash_t type);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#define MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH 20
-#define MEMCACHED_MAX_BUFFER 8196
-#define MEMCACHED_MAX_HOST_SORT_LENGTH 86 /* Used for Ketama */
-#define MEMCACHED_MAX_KEY 251 /* We add one to have it null terminated */
-#define MEMCACHED_PREFIX_KEY_MAX_SIZE 128
-#define MEMCACHED_VERSION_STRING_LENGTH 24
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-/* This seems to be required for older compilers @note http://stackoverflow.com/questions/8132399/how-to-printf-uint64-t */
-#ifndef __STDC_FORMAT_MACROS
-# define __STDC_FORMAT_MACROS
-#endif
-
-#ifdef __cplusplus
-# if __cplusplus >= 201103L
-# include <cinttypes>
-# else
-# include <inttypes.h>
-# endif
-# include <cstddef>
-# include <cstdlib>
-#else
-# include <inttypes.h>
-# include <stddef.h>
-# include <stdlib.h>
-# include <stdbool.h>
-#endif
-
-#include <sys/types.h>
-
-#include <libmemcached-1.0/visibility.h>
-#include <libmemcached-1.0/configure.h>
-#include <libmemcached-1.0/platform.h>
-
-#include <libmemcached-1.0/limits.h>
-#include <libmemcached-1.0/defaults.h>
-
-#include <libmemcached-1.0/types/behavior.h>
-#include <libmemcached-1.0/types/callback.h>
-#include <libmemcached-1.0/types/connection.h>
-#include <libmemcached-1.0/types/hash.h>
-#include <libmemcached-1.0/types/return.h>
-#include <libmemcached-1.0/types/server_distribution.h>
-
-#include <libmemcached-1.0/return.h>
-
-#include <libmemcached-1.0/types.h>
-#include <libmemcached-1.0/callbacks.h>
-#include <libmemcached-1.0/alloc.h>
-#include <libmemcached-1.0/triggers.h>
-
-#include <libhashkit-1.0/hashkit.h>
-
-#include <libmemcached-1.0/struct/callback.h>
-#include <libmemcached-1.0/struct/string.h>
-#include <libmemcached-1.0/struct/result.h>
-#include <libmemcached-1.0/struct/allocator.h>
-#include <libmemcached-1.0/struct/sasl.h>
-#include <libmemcached-1.0/struct/memcached.h>
-#include <libmemcached-1.0/struct/server.h>
-#include <libmemcached-1.0/struct/stat.h>
-
-#include <libmemcached-1.0/basic_string.h>
-#include <libmemcached-1.0/error.h>
-#include <libmemcached-1.0/stats.h>
-
-// Everything above this line must be in the order specified.
-#include <libmemcached-1.0/allocators.h>
-#include <libmemcached-1.0/analyze.h>
-#include <libmemcached-1.0/auto.h>
-#include <libmemcached-1.0/behavior.h>
-#include <libmemcached-1.0/callback.h>
-#include <libmemcached-1.0/delete.h>
-#include <libmemcached-1.0/dump.h>
-#include <libmemcached-1.0/encoding_key.h>
-#include <libmemcached-1.0/exist.h>
-#include <libmemcached-1.0/fetch.h>
-#include <libmemcached-1.0/flush.h>
-#include <libmemcached-1.0/flush_buffers.h>
-#include <libmemcached-1.0/get.h>
-#include <libmemcached-1.0/hash.h>
-#include <libmemcached-1.0/options.h>
-#include <libmemcached-1.0/parse.h>
-#include <libmemcached-1.0/quit.h>
-#include <libmemcached-1.0/result.h>
-#include <libmemcached-1.0/server.h>
-#include <libmemcached-1.0/server_list.h>
-#include <libmemcached-1.0/storage.h>
-#include <libmemcached-1.0/strerror.h>
-#include <libmemcached-1.0/touch.h>
-#include <libmemcached-1.0/verbosity.h>
-#include <libmemcached-1.0/version.h>
-#include <libmemcached-1.0/sasl.h>
-
-#include <libmemcached-1.0/deprecated_types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-void memcached_servers_reset(memcached_st *ptr);
-
-LIBMEMCACHED_API
-memcached_st *memcached_create(memcached_st *ptr);
-
-LIBMEMCACHED_API
-memcached_st *memcached(const char *string, size_t string_length);
-
-LIBMEMCACHED_API
-void memcached_free(memcached_st *ptr);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_reset(memcached_st *ptr);
-
-LIBMEMCACHED_API
-void memcached_reset_last_disconnected_server(memcached_st *ptr);
-
-LIBMEMCACHED_API
-memcached_st *memcached_clone(memcached_st *clone, const memcached_st *ptr);
-
-LIBMEMCACHED_API
-void *memcached_get_user_data(const memcached_st *ptr);
-
-LIBMEMCACHED_API
-void *memcached_set_user_data(memcached_st *ptr, void *data);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source);
-
-LIBMEMCACHED_API
-const memcached_instance_st * memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key);
-
-LIBMEMCACHED_API
-uint32_t memcached_server_count(const memcached_st *);
-
-LIBMEMCACHED_API
-uint64_t memcached_query_id(const memcached_st *);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- * Summary: C++ interface for memcached server
- *
- * Copy: See Copyright for the status of this software.
- *
- * Authors: Padraig O'Sullivan <osullivan.padraig@gmail.com>
- * Patrick Galbraith <patg@patg.net>
- */
-
-/**
- * @file memcached.hpp
- * @brief Libmemcached C++ interface
- */
-
-#pragma once
-
-#include <libmemcached-1.0/memcached.h>
-#if 0
-#include <libmemcached/exception.hpp>
-#endif
-
-#include <string.h>
-
-#include <sstream>
-#include <string>
-#include <vector>
-#include <map>
-
-namespace memcache
-{
-
-/**
- * This is the core memcached library (if later, other objects
- * are needed, they will be created from this class).
- */
-class Memcache
-{
-public:
-
- Memcache()
- {
- memc_= memcached(NULL, 0);
- }
-
- Memcache(const std::string &config)
- {
- memc_= memcached(config.c_str(), config.size());
- }
-
- Memcache(const std::string &hostname, in_port_t port)
- {
- memc_= memcached(NULL, 0);
- if (memc_)
- {
- memcached_server_add(memc_, hostname.c_str(), port);
- }
- }
-
- Memcache(memcached_st *clone)
- {
- memc_= memcached_clone(NULL, clone);
- }
-
- Memcache(const Memcache &rhs)
- {
- memc_= memcached_clone(NULL, rhs.getImpl());
- }
-
- Memcache &operator=(const Memcache &rhs)
- {
- if (this != &rhs)
- {
- memcached_free(memc_);
- memc_= memcached_clone(NULL, rhs.getImpl());
- }
-
- return *this;
- }
-
- ~Memcache()
- {
- memcached_free(memc_);
- }
-
- /**
- * Get the internal memcached_st *
- */
- const memcached_st *getImpl() const
- {
- return memc_;
- }
-
- /**
- * Return an error string for the given 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_t rc) const
- {
- /* first parameter to strerror is unused */
- return memcached_strerror(NULL, rc);
- }
-
- bool error(std::string& error_message) const
- {
- if (memcached_failed(memcached_last_error(memc_)))
- {
- error_message+= memcached_last_error_message(memc_);
- return true;
- }
-
- return false;
- }
-
- bool error() const
- {
- if (memcached_failed(memcached_last_error(memc_)))
- {
- return true;
- }
-
- return false;
- }
-
- bool error(memcached_return_t& arg) const
- {
- arg= memcached_last_error(memc_);
- return memcached_failed(arg);
- }
-
- bool setBehavior(memcached_behavior_t flag, uint64_t data)
- {
- return (memcached_success(memcached_behavior_set(memc_, flag, data)));
- }
-
- uint64_t getBehavior(memcached_behavior_t flag)
- {
- return memcached_behavior_get(memc_, flag);
- }
-
- /**
- * Configure the memcache object
- *
- * @param[in] in_config configuration
- * @return true on success; false otherwise
- */
- bool configure(const std::string &configuration)
- {
- memcached_st *new_memc= memcached(configuration.c_str(), configuration.size());
-
- if (new_memc)
- {
- memcached_free(memc_);
- memc_= new_memc;
-
- return true;
- }
-
- return false;
- }
-
- /**
- * Add a server to the list of memcached servers to use.
- *
- * @param[in] server_name name of the server to add
- * @param[in] port port number of server to add
- * @return true on success; false otherwise
- */
- bool addServer(const std::string &server_name, in_port_t port)
- {
- return memcached_success(memcached_server_add(memc_, server_name.c_str(), port));
- }
-
- /**
- * Remove a server from the list of memcached servers to use.
- *
- * @param[in] server_name name of the server to remove
- * @param[in] port port number of server to remove
- * @return true on success; false otherwise
- */
- bool removeServer(const std::string &server_name, in_port_t port)
- {
- std::string tmp_str;
- std::ostringstream strstm;
- tmp_str.append(",");
- tmp_str.append(server_name);
- tmp_str.append(":");
- strstm << port;
- tmp_str.append(strstm.str());
-
- //memcached_return_t rc= memcached_server_remove(server);
-
- return false;
- }
-
- /**
- * Fetches an individual value from the server. mget() must always
- * be called before using this method.
- *
- * @param[in] key key of object to fetch
- * @param[out] ret_val store returned object in this vector
- * @return a memcached return structure
- */
- memcached_return_t fetch(std::string &key,
- std::vector<char> &ret_val,
- uint32_t &flags,
- uint64_t &cas_value)
- {
- memcached_return_t rc;
-
- memcached_result_st *result;
- if ((result= memcached_fetch_result(memc_, NULL, &rc)))
- {
- // Key
- key.assign(memcached_result_key_value(result), memcached_result_key_length(result));
-
- // Actual value, null terminated
- ret_val.reserve(memcached_result_length(result) +1);
- ret_val.assign(memcached_result_value(result),
- memcached_result_value(result) +memcached_result_length(result) +1);
- ret_val.resize(memcached_result_length(result));
-
- // Misc
- flags= memcached_result_flags(result);
- cas_value= memcached_result_cas(result);
- }
- memcached_result_free(result);
-
- return rc;
- }
-
- memcached_return_t fetch(std::string &key,
- std::vector<char> &ret_val)
- {
- uint32_t flags= 0;
- uint64_t cas_value= 0;
-
- return fetch(key, ret_val, flags, cas_value);
- }
-
- /**
- * Fetches an individual value from the server.
- *
- * @param[in] key key of object whose value to get
- * @param[out] ret_val object that is retrieved is stored in
- * this vector
- * @return true on success; false otherwise
- */
- bool get(const std::string &key, std::vector<char> &ret_val)
- {
- uint32_t flags= 0;
- memcached_return_t rc;
- size_t value_length= 0;
-
- char *value= memcached_get(memc_, key.c_str(), key.length(),
- &value_length, &flags, &rc);
- if (value != NULL && ret_val.empty())
- {
- ret_val.reserve(value_length +1); // Always provide null
- ret_val.assign(value, value +value_length +1);
- ret_val.resize(value_length);
- free(value);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * 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
- * used for storage.
- *
- * @param[in] master_key key that specifies server object is stored on
- * @param[in] key key of object whose value to get
- * @param[out] ret_val object that is retrieved is stored in
- * this vector
- * @return true on success; false otherwise
- */
- bool getByKey(const std::string &master_key,
- const std::string &key,
- std::vector<char> &ret_val)
- {
- uint32_t flags= 0;
- memcached_return_t rc;
- size_t value_length= 0;
-
- char *value= memcached_get_by_key(memc_,
- master_key.c_str(), master_key.length(),
- key.c_str(), key.length(),
- &value_length, &flags, &rc);
- if (value)
- {
- ret_val.reserve(value_length +1); // Always provide null
- ret_val.assign(value, value +value_length +1);
- ret_val.resize(value_length);
- free(value);
-
- return true;
- }
- return false;
- }
-
- /**
- * Selects multiple keys at once. This method always
- * works asynchronously.
- *
- * @param[in] keys vector of keys to select
- * @return true if all keys are found
- */
- bool mget(const std::vector<std::string>& keys)
- {
- std::vector<const char *> real_keys;
- std::vector<size_t> key_len;
- /*
- * Construct an array which will contain the length
- * of each of the strings in the input vector. Also, to
- * interface with the memcached C API, we need to convert
- * the vector of std::string's to a vector of char *.
- */
- real_keys.reserve(keys.size());
- key_len.reserve(keys.size());
-
- std::vector<std::string>::const_iterator it= keys.begin();
-
- while (it != keys.end())
- {
- real_keys.push_back(const_cast<char *>((*it).c_str()));
- key_len.push_back((*it).length());
- ++it;
- }
-
- /*
- * If the std::vector of keys is empty then we cannot
- * call memcached_mget as we will get undefined behavior.
- */
- if (not real_keys.empty())
- {
- return memcached_success(memcached_mget(memc_, &real_keys[0], &key_len[0], real_keys.size()));
- }
-
- return false;
- }
-
- /**
- * Writes an object to the server. If the object already exists, it will
- * overwrite the existing object. This method always returns true
- * when using non-blocking mode unless a network error occurs.
- *
- * @param[in] key key of object to write to server
- * @param[in] value value of object to write to server
- * @param[in] expiration time to keep the object stored in the server for
- * @param[in] flags flags to store with the object
- * @return true on succcess; false otherwise
- */
- bool set(const std::string &key,
- const std::vector<char> &value,
- time_t expiration,
- uint32_t flags)
- {
- memcached_return_t rc= memcached_set(memc_,
- key.c_str(), key.length(),
- value.data(), value.size(),
- expiration, flags);
- return memcached_success(rc);
- }
-
- bool set(const std::string &key,
- const char* value, const size_t value_length,
- time_t expiration,
- uint32_t flags)
- {
- memcached_return_t rc= memcached_set(memc_,
- key.c_str(), key.length(),
- value, value_length,
- expiration, flags);
- return memcached_success(rc);
- }
-
- /**
- * Writes an object to a server specified by the master_key parameter.
- * If the object already exists, it will overwrite the existing object.
- *
- * @param[in] master_key key that specifies server to write to
- * @param[in] key key of object to write to server
- * @param[in] value value of object to write to server
- * @param[in] expiration time to keep the object stored in the server for
- * @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,
- const std::vector<char> &value,
- time_t expiration,
- uint32_t flags)
- {
- return memcached_success(memcached_set_by_key(memc_, master_key.c_str(),
- master_key.length(),
- key.c_str(), key.length(),
- &value[0], value.size(),
- expiration,
- flags));
- }
-
- /**
- * Writes a list of objects to the server. Objects are specified by
- * 2 vectors - 1 vector of keys and 1 vector of values.
- *
- * @param[in] keys vector of keys of objects to write to server
- * @param[in] values vector of values of objects to write to server
- * @param[in] expiration time to keep the objects stored in server for
- * @param[in] flags flags to store with the objects
- * @return true on success; false otherwise
- */
- bool setAll(const std::vector<std::string>& keys,
- const std::vector< std::vector<char> *>& values,
- time_t expiration,
- uint32_t flags)
- {
- bool retval= true;
- std::vector<std::string>::const_iterator key_it= keys.begin();
- std::vector< std::vector<char> *>::const_iterator val_it= values.begin();
- while (key_it != keys.end())
- {
- retval= set((*key_it), *(*val_it), expiration, flags);
- if (retval == false)
- {
- return retval;
- }
- ++key_it;
- ++val_it;
- }
- return retval;
- }
-
- /**
- * Writes a list of objects to the server. Objects are specified by
- * a map of keys to values.
- *
- * @param[in] key_value_map map of keys and values to store in server
- * @param[in] expiration time to keep the objects stored in server for
- * @param[in] flags flags to store with the objects
- * @return true on success; false otherwise
- */
- bool setAll(const std::map<const std::string, std::vector<char> >& key_value_map,
- time_t expiration,
- uint32_t flags)
- {
- std::map<const std::string, std::vector<char> >::const_iterator it= key_value_map.begin();
-
- while (it != key_value_map.end())
- {
- if (!set(it->first, it->second, expiration, flags))
- {
- // We should tell the user what the key that failed was
- return false;
- }
- ++it;
- }
-
- return true;
- }
-
- /**
- * Increment the value of the object associated with the specified
- * key by the offset given. The resulting value is saved in the value
- * parameter.
- *
- * @param[in] key key of object in server whose value to increment
- * @param[in] offset amount to increment object's value by
- * @param[out] value store the result of the increment here
- * @return true on success; false otherwise
- */
- bool increment(const std::string& key, uint32_t offset, uint64_t *value)
- {
- return memcached_success(memcached_increment(memc_, key.c_str(), key.length(), offset, value));
- }
-
- /**
- * Decrement the value of the object associated with the specified
- * key by the offset given. The resulting value is saved in the value
- * parameter.
- *
- * @param[in] key key of object in server whose value to decrement
- * @param[in] offset amount to increment object's value by
- * @param[out] value store the result of the decrement here
- * @return true on success; false otherwise
- */
- bool decrement(const std::string& key, uint32_t offset, uint64_t *value)
- {
- return memcached_success(memcached_decrement(memc_, key.c_str(),
- key.length(),
- offset, value));
- }
-
-
- /**
- * Add an object with the specified key and value to the server. This
- * function returns false if the object already exists on the server.
- *
- * @param[in] key key of object to add
- * @param[in] value of object to add
- * @return true on success; false otherwise
- */
- bool add(const std::string& key, const std::vector<char>& value)
- {
- return memcached_success(memcached_add(memc_, key.c_str(), key.length(),
- &value[0], value.size(), 0, 0));
- }
-
- /**
- * Add an object with the specified key and value to the server. This
- * function returns false if the object already exists on the server. The
- * server to add the object to is specified by the master_key parameter.
- *
- * @param[in[ master_key key of server to add object to
- * @param[in] key key of object to add
- * @param[in] value of object to add
- * @return true on success; false otherwise
- */
- bool addByKey(const std::string& master_key,
- const std::string& key,
- const std::vector<char>& value)
- {
- return memcached_success(memcached_add_by_key(memc_,
- master_key.c_str(),
- master_key.length(),
- key.c_str(),
- key.length(),
- &value[0],
- value.size(),
- 0, 0));
- }
-
- /**
- * Replaces an object on the server. This method only succeeds
- * if the object is already present on the server.
- *
- * @param[in] key key of object to replace
- * @param[in[ value value to replace object with
- * @return true on success; false otherwise
- */
- bool replace(const std::string& key, const std::vector<char>& value)
- {
- return memcached_success(memcached_replace(memc_, key.c_str(), key.length(),
- &value[0], value.size(),
- 0, 0));
- }
-
- /**
- * Replaces an object on the server. This method only succeeds
- * if the object is already present on the server. The server
- * to replace the object on is specified by the master_key param.
- *
- * @param[in] master_key key of server to replace object on
- * @param[in] key key of object to replace
- * @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,
- const std::vector<char>& value)
- {
- return memcached_success(memcached_replace_by_key(memc_,
- master_key.c_str(),
- master_key.length(),
- key.c_str(),
- key.length(),
- &value[0],
- value.size(),
- 0, 0));
- }
-
- /**
- * Places a segment of data before the last piece of data stored.
- *
- * @param[in] key key of object whose value we will prepend data to
- * @param[in] value data to prepend to object's value
- * @return true on success; false otherwise
- */
- bool prepend(const std::string& key, const std::vector<char>& value)
- {
- return memcached_success(memcached_prepend(memc_, key.c_str(), key.length(),
- &value[0], value.size(), 0, 0));
- }
-
- /**
- * Places a segment of data before the last piece of data stored. The
- * server on which the object where we will be prepending data is stored
- * on is specified by the master_key parameter.
- *
- * @param[in] master_key key of server where object is stored
- * @param[in] key key of object whose value we will prepend data to
- * @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,
- const std::vector<char>& value)
- {
- return memcached_success(memcached_prepend_by_key(memc_,
- master_key.c_str(),
- master_key.length(),
- key.c_str(),
- key.length(),
- &value[0],
- value.size(),
- 0,
- 0));
- }
-
- /**
- * Places a segment of data at the end of the last piece of data stored.
- *
- * @param[in] key key of object whose value we will append data to
- * @param[in] value data to append to object's value
- * @return true on success; false otherwise
- */
- bool append(const std::string& key, const std::vector<char>& value)
- {
- return memcached_success(memcached_append(memc_,
- key.c_str(),
- key.length(),
- &value[0],
- value.size(),
- 0, 0));
- }
-
- /**
- * Places a segment of data at the end of the last piece of data stored. The
- * server on which the object where we will be appending data is stored
- * on is specified by the master_key parameter.
- *
- * @param[in] master_key key of server where object is stored
- * @param[in] key key of object whose value we will append data to
- * @param[in] value data to append to object's value
- * @return true on success; false otherwise
- */
- bool appendByKey(const std::string& master_key,
- const std::string& key,
- const std::vector<char> &value)
- {
- return memcached_success(memcached_append_by_key(memc_,
- master_key.c_str(),
- master_key.length(),
- key.c_str(),
- key.length(),
- &value[0],
- value.size(),
- 0, 0));
- }
-
- /**
- * Overwrite data in the server as long as the cas_arg value
- * is still the same in the server.
- *
- * @param[in] key key of object in server
- * @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,
- uint64_t cas_arg)
- {
- return memcached_success(memcached_cas(memc_, key.c_str(), key.length(),
- &value[0], value.size(),
- 0, 0, cas_arg));
- }
-
- /**
- * Overwrite data in the server as long as the cas_arg value
- * is still the same in the server. The server to use is
- * specified by the master_key parameter.
- *
- * @param[in] master_key specifies server to operate on
- * @param[in] key key of object in server
- * @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,
- uint64_t cas_arg)
- {
- return memcached_success(memcached_cas_by_key(memc_,
- master_key.c_str(),
- master_key.length(),
- key.c_str(),
- key.length(),
- &value[0],
- value.size(),
- 0, 0, cas_arg));
- }
-
- /**
- * Delete an object from the server specified by the key given.
- *
- * @param[in] key key of object to delete
- * @return true on success; false otherwise
- */
- bool remove(const std::string& key)
- {
- return memcached_success(memcached_delete(memc_, key.c_str(), key.length(), 0));
- }
-
- /**
- * Delete an object from the server specified by the key given.
- *
- * @param[in] key key of object to delete
- * @param[in] expiration time to delete the object after
- * @return true on success; false otherwise
- */
- bool remove(const std::string& key, time_t expiration)
- {
- return memcached_success(memcached_delete(memc_,
- key.c_str(),
- key.length(),
- expiration));
- }
-
- /**
- * 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
- * @return true on success; false otherwise
- */
- bool removeByKey(const std::string& master_key,
- const std::string& key)
- {
- return memcached_success(memcached_delete_by_key(memc_,
- master_key.c_str(),
- master_key.length(),
- key.c_str(),
- key.length(),
- 0));
- }
-
- /**
- * 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,
- const std::string& key,
- time_t expiration)
- {
- return memcached_success(memcached_delete_by_key(memc_,
- master_key.c_str(),
- master_key.length(),
- key.c_str(),
- key.length(),
- expiration));
- }
-
- /**
- * Wipe the contents of memcached servers.
- *
- * @param[in] expiration time to wait until wiping contents of
- * memcached servers
- * @return true on success; false otherwise
- */
- bool flush(time_t expiration= 0)
- {
- return memcached_success(memcached_flush(memc_, expiration));
- }
-
- /**
- * Get the library version string.
- * @return std::string containing a copy of the library version string.
- */
- const std::string libVersion() const
- {
- const char *ver= memcached_lib_version();
- const std::string version(ver);
- return version;
- }
-
- /**
- * Retrieve memcached statistics. Populate a std::map with the retrieved
- * stats. Each server will map to another std::map of the key:value stats.
- *
- * @param[out] stats_map a std::map to be populated with the memcached
- * stats
- * @return true on success; false otherwise
- */
- bool getStats(std::map< std::string, std::map<std::string, std::string> >& stats_map)
- {
- memcached_return_t rc;
- memcached_stat_st *stats= memcached_stat(memc_, NULL, &rc);
-
- if (rc != MEMCACHED_SUCCESS &&
- rc != MEMCACHED_SOME_ERRORS)
- {
- return false;
- }
-
- uint32_t server_count= memcached_server_count(memc_);
-
- /*
- * For each memcached server, construct a std::map for its stats and add
- * it to the std::map of overall stats.
- */
- for (uint32_t x= 0; x < server_count; x++)
- {
- const memcached_instance_st * instance= memcached_server_instance_by_position(memc_, x);
- std::ostringstream strstm;
- std::string server_name(memcached_server_name(instance));
- server_name.append(":");
- strstm << memcached_server_port(instance);
- server_name.append(strstm.str());
-
- std::map<std::string, std::string> server_stats;
- char **list= memcached_stat_get_keys(memc_, &stats[x], &rc);
- for (char** ptr= list; *ptr; ptr++)
- {
- char *value= memcached_stat_get_value(memc_, &stats[x], *ptr, &rc);
- server_stats[*ptr]= value;
- free(value);
- }
-
- stats_map[server_name]= server_stats;
- free(list);
- }
-
- memcached_stat_free(memc_, stats);
- return true;
- }
-
-private:
- memcached_st *memc_;
-};
-
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
- memcached_return_t libmemcached_check_configuration(const char *option_string, size_t length, char *error_buffer, size_t error_buffer_size);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* 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: Work with fetching results
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_server_list_st memcached_servers_parse(const char *server_strings);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-#if defined(_WIN32)
-# include <winsock2.h>
-# include <ws2tcpip.h>
-
-#ifndef HAVE_IN_PORT_T
-typedef int in_port_t;
-# define HAVE_IN_PORT_T 1
-#endif
-
-typedef SOCKET memcached_socket_t;
-
-#else
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <netdb.h>
-# include <sys/un.h>
-# include <netinet/tcp.h>
-
-typedef int memcached_socket_t;
-
-#endif /* _WIN32 */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-void memcached_quit(memcached_st *ptr);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached-1.0/struct/result.h>
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* 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(const memcached_st *ptr,
- memcached_result_st *result);
-
-LIBMEMCACHED_API
-const char *memcached_result_key_value(const memcached_result_st *self);
-
-LIBMEMCACHED_API
-size_t memcached_result_key_length(const memcached_result_st *self);
-
-LIBMEMCACHED_API
-const char *memcached_result_value(const memcached_result_st *self);
-
-LIBMEMCACHED_API
-char *memcached_result_take_value(memcached_result_st *self);
-
-LIBMEMCACHED_API
-size_t memcached_result_length(const memcached_result_st *self);
-
-LIBMEMCACHED_API
-uint32_t memcached_result_flags(const memcached_result_st *self);
-
-LIBMEMCACHED_API
-uint64_t memcached_result_cas(const memcached_result_st *self);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length);
-
-LIBMEMCACHED_API
-void memcached_result_set_flags(memcached_result_st *self, uint32_t flags);
-
-LIBMEMCACHED_API
-void memcached_result_set_expiration(memcached_result_st *self, time_t expiration);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-static inline bool memcached_success(memcached_return_t rc)
-{
- return (rc == MEMCACHED_BUFFERED ||
- rc == MEMCACHED_DELETED ||
- rc == MEMCACHED_END ||
- rc == MEMCACHED_ITEM ||
- rc == MEMCACHED_STAT ||
- rc == MEMCACHED_STORED ||
- rc == MEMCACHED_SUCCESS ||
- rc == MEMCACHED_VALUE);
-}
-
-static inline bool memcached_failed(memcached_return_t rc)
-{
- return (rc != MEMCACHED_AUTH_CONTINUE &&
- rc != MEMCACHED_BUFFERED &&
- rc != MEMCACHED_DELETED &&
- rc != MEMCACHED_END &&
- rc != MEMCACHED_ITEM &&
- rc != MEMCACHED_STAT &&
- rc != MEMCACHED_STORED &&
- rc != MEMCACHED_SUCCESS &&
- rc != MEMCACHED_VALUE);
-}
-
-static inline bool memcached_fatal(memcached_return_t rc)
-{
- return (rc != MEMCACHED_AUTH_CONTINUE &&
- rc != MEMCACHED_BUFFERED &&
- rc != MEMCACHED_CLIENT_ERROR &&
- rc != MEMCACHED_DATA_EXISTS &&
- rc != MEMCACHED_DELETED &&
- rc != MEMCACHED_E2BIG &&
- rc != MEMCACHED_END &&
- rc != MEMCACHED_ITEM &&
- rc != MEMCACHED_ERROR &&
- rc != MEMCACHED_NOTFOUND &&
- rc != MEMCACHED_NOTSTORED &&
- rc != MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE &&
- rc != MEMCACHED_STAT &&
- rc != MEMCACHED_STORED &&
- rc != MEMCACHED_SUCCESS &&
- rc != MEMCACHED_VALUE);
-}
-
-#define memcached_continue(__memcached_return_t) ((__memcached_return_t) == MEMCACHED_IN_PROGRESS)
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#if defined(LIBMEMCACHED_WITH_SASL_SUPPORT) && LIBMEMCACHED_WITH_SASL_SUPPORT
-#include <sasl/sasl.h>
-#else
-#define sasl_callback_t void
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-void memcached_set_sasl_callbacks(memcached_st *ptr,
- const sasl_callback_t *callbacks);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_set_sasl_auth_data(memcached_st *ptr,
- const char *username,
- const char *password);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_destroy_sasl_auth_data(memcached_st *ptr);
-
-
-LIBMEMCACHED_API
-sasl_callback_t *memcached_get_sasl_callbacks(memcached_st *ptr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#include <libmemcached-1.0/struct/sasl.h>
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#include <libmemcached-1.0/struct/server.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_server_cursor(const memcached_st *ptr,
- const memcached_server_fn *callback,
- void *context,
- uint32_t number_of_callbacks);
-
-LIBMEMCACHED_API
- const memcached_instance_st * memcached_server_by_key(memcached_st *ptr,
- const char *key,
- size_t key_length,
- memcached_return_t *error);
-
-LIBMEMCACHED_API
-void memcached_server_error_reset(memcached_server_st *ptr);
-
-LIBMEMCACHED_API
-void memcached_server_free(memcached_server_st *ptr);
-
-LIBMEMCACHED_API
-const memcached_instance_st * memcached_server_get_last_disconnect(const memcached_st *ptr);
-
-
-LIBMEMCACHED_API
-memcached_return_t memcached_server_add_udp(memcached_st *ptr,
- const char *hostname,
- in_port_t port);
-LIBMEMCACHED_API
-memcached_return_t memcached_server_add_unix_socket(memcached_st *ptr,
- const char *filename);
-LIBMEMCACHED_API
-memcached_return_t memcached_server_add(memcached_st *ptr,
- const char *hostname, in_port_t port);
-
-LIBMEMCACHED_API
-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_t memcached_server_add_unix_socket_with_weight(memcached_st *ptr,
- const char *filename,
- uint32_t weight);
-LIBMEMCACHED_API
-memcached_return_t memcached_server_add_with_weight(memcached_st *ptr, const char *hostname,
- in_port_t port,
- uint32_t weight);
-
-/**
- Operations on Single Servers.
-*/
-LIBMEMCACHED_API
-uint32_t memcached_server_response_count(const memcached_instance_st * self);
-
-LIBMEMCACHED_API
-const char *memcached_server_name(const memcached_instance_st * self);
-
-LIBMEMCACHED_API
-in_port_t memcached_server_port(const memcached_instance_st * self);
-
-LIBMEMCACHED_API
-in_port_t memcached_server_srcport(const memcached_instance_st * self);
-
-LIBMEMCACHED_API
-void memcached_instance_next_retry(const memcached_instance_st * self, const time_t absolute_time);
-
-LIBMEMCACHED_API
-const char *memcached_server_type(const memcached_instance_st * ptr);
-
-LIBMEMCACHED_API
-uint8_t memcached_server_major_version(const memcached_instance_st * ptr);
-
-LIBMEMCACHED_API
-uint8_t memcached_server_minor_version(const memcached_instance_st * ptr);
-
-LIBMEMCACHED_API
-uint8_t memcached_server_micro_version(const memcached_instance_st * ptr);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Server List Public functions */
-LIBMEMCACHED_API
- void memcached_server_list_free(memcached_server_list_st ptr);
-
-LIBMEMCACHED_API
- memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list);
-
-LIBMEMCACHED_API
- memcached_server_list_st memcached_server_list_append(memcached_server_list_st ptr,
- const char *hostname,
- in_port_t port,
- memcached_return_t *error);
-LIBMEMCACHED_API
- memcached_server_list_st memcached_server_list_append_with_weight(memcached_server_list_st ptr,
- const char *hostname,
- in_port_t port,
- uint32_t weight,
- memcached_return_t *error);
-LIBMEMCACHED_API
- uint32_t memcached_server_list_count(const memcached_server_list_st ptr);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached-1.0/struct/stat.h>
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-void memcached_stat_free(const 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);
-
-LIBMEMCACHED_API
-char *memcached_stat_get_value(const memcached_st *ptr, memcached_stat_st *memc_stat,
- const char *key, memcached_return_t *error);
-
-LIBMEMCACHED_API
-char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *memc_stat,
- memcached_return_t *error);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_stat_execute(memcached_st *memc, const char *args, memcached_stat_fn func, void *context);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#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 *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_add_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_replace_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_append_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_cas_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-const char *memcached_strerror(const memcached_st *ptr, memcached_return_t rc);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-struct memcached_allocator_t {
- memcached_calloc_fn calloc;
- memcached_free_fn free;
- memcached_malloc_fn malloc;
- memcached_realloc_fn realloc;
- void *context;
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-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;
-};
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-struct memcached_callback_st {
- memcached_execute_fn *callback;
- void *context;
- uint32_t number_of_callback;
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-struct memcached_st {
- /**
- @note these are static and should not change without a call to behavior.
- */
- struct {
- bool is_purging:1;
- bool is_processing_input:1;
- bool is_time_for_rebuild:1;
- bool is_parsing:1;
- } state;
-
- struct {
- // Everything below here is pretty static.
- bool auto_eject_hosts:1;
- bool binary_protocol:1;
- bool buffer_requests:1;
- bool hash_with_namespace:1;
- bool no_block:1; // Don't block
- bool reply:1;
- bool randomize_replica_read:1;
- bool support_cas:1;
- bool tcp_nodelay:1;
- bool use_sort_hosts:1;
- bool use_udp:1;
- bool verify_key:1;
- bool tcp_keepalive:1;
- bool is_aes:1;
- bool is_fetching_version:1;
- bool not_used:1;
- } flags;
-
- memcached_server_distribution_t distribution;
- hashkit_st hashkit;
- struct {
- unsigned int version;
- } server_info;
- uint32_t number_of_hosts;
- memcached_instance_st *servers;
- memcached_instance_st *last_disconnected_server;
- int32_t snd_timeout;
- int32_t rcv_timeout;
- uint32_t server_failure_limit;
- uint32_t server_timeout_limit;
- uint32_t io_msg_watermark;
- uint32_t io_bytes_watermark;
- uint32_t io_key_prefetch;
- uint32_t tcp_keepidle;
- int32_t poll_timeout;
- int32_t connect_timeout; // How long we will wait on connect() before we will timeout
- int32_t retry_timeout;
- int32_t dead_timeout;
- int send_size;
- int recv_size;
- void *user_data;
- uint64_t query_id;
- uint32_t number_of_replicas;
- memcached_result_st result;
-
- struct {
- bool weighted_;
- uint32_t continuum_count; // Ketama
- uint32_t continuum_points_counter; // Ketama
- time_t next_distribution_rebuild; // Ketama
- struct memcached_continuum_item_st *continuum; // Ketama
- } ketama;
-
- struct memcached_virtual_bucket_t *virtual_bucket;
-
- struct memcached_allocator_t allocators;
-
- memcached_clone_fn on_clone;
- memcached_cleanup_fn on_cleanup;
- memcached_trigger_key_fn get_key_failure;
- memcached_trigger_delete_key_fn delete_trigger;
- memcached_callback_st *callbacks;
- struct memcached_sasl_st sasl;
- struct memcached_error_t *error_messages;
- struct memcached_array_st *_namespace;
- struct {
- uint32_t initial_pool_size;
- uint32_t max_pool_size;
- int32_t version; // This is used by pool and others to determine if the memcached_st is out of date.
- struct memcached_array_st *filename;
- } configure;
- struct {
- bool is_allocated:1;
- } options;
-
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-struct memcached_result_st {
- uint32_t item_flags;
- time_t item_expiration;
- size_t key_length;
- uint64_t item_cas;
- struct memcached_st *root;
- memcached_string_st value;
- uint64_t numeric_value;
- uint64_t count;
- char item_key[MEMCACHED_MAX_KEY];
- struct {
- bool is_allocated:1;
- bool is_initialized:1;
- } options;
- /* Add result callback function */
-};
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#if defined(LIBMEMCACHED_WITH_SASL_SUPPORT) && LIBMEMCACHED_WITH_SASL_SUPPORT
-#include <sasl/sasl.h>
-#else
-#define sasl_callback_t void
-#endif
-
-#pragma once
-
-struct memcached_sasl_st {
- sasl_callback_t *callbacks;
- /*
- ** Did we allocate data inside the callbacks, or did the user
- ** supply that.
- */
- bool is_allocated;
-};
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifdef HAVE_NETDB_H
-# include <netdb.h>
-#endif
-
-#ifdef NI_MAXHOST
-# define MEMCACHED_NI_MAXHOST NI_MAXHOST
-#else
-# define MEMCACHED_NI_MAXHOST 1025
-#endif
-
-#ifdef NI_MAXSERV
-# define MEMCACHED_NI_MAXSERV NI_MAXSERV
-#else
-# define MEMCACHED_NI_MAXSERV 32
-#endif
-
-enum memcached_server_state_t {
- MEMCACHED_SERVER_STATE_NEW, // fd == -1, no address lookup has been done
- MEMCACHED_SERVER_STATE_ADDRINFO, // ADDRRESS information has been gathered
- MEMCACHED_SERVER_STATE_IN_PROGRESS,
- MEMCACHED_SERVER_STATE_CONNECTED,
- MEMCACHED_SERVER_STATE_IN_TIMEOUT,
- MEMCACHED_SERVER_STATE_DISABLED
-};
-
-struct memcached_server_st {
- struct {
- bool is_allocated:1;
- bool is_initialized:1;
- bool is_shutting_down:1;
- bool is_dead:1;
- } options;
- uint32_t number_of_hosts;
- uint32_t cursor_active;
- in_port_t port;
- uint32_t io_bytes_sent; /* # bytes sent since last read */
- uint32_t request_id;
- uint32_t server_failure_counter;
- uint64_t server_failure_counter_query_id;
- uint32_t server_timeout_counter;
- uint64_t server_timeout_counter_query_id;
- uint32_t weight;
- uint32_t version;
- enum memcached_server_state_t state;
- struct {
- uint32_t read;
- uint32_t write;
- uint32_t timeouts;
- size_t _bytes_read;
- } io_wait_count;
- uint8_t major_version; // Default definition of UINT8_MAX means that it has not been set.
- uint8_t micro_version; // ditto, and note that this is the third, not second version bit
- uint8_t minor_version; // ditto
- memcached_connection_t type;
- time_t next_retry;
- struct memcached_st *root;
- uint64_t limit_maxbytes;
- struct memcached_error_t *error_messages;
- char hostname[MEMCACHED_NI_MAXHOST];
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-struct memcached_stat_st {
- unsigned long connection_structures;
- unsigned long curr_connections;
- unsigned long curr_items;
- pid_t pid;
- unsigned long pointer_size;
- unsigned long rusage_system_microseconds;
- unsigned long rusage_system_seconds;
- unsigned long rusage_user_microseconds;
- unsigned long rusage_user_seconds;
- unsigned long threads;
- unsigned long time;
- unsigned long total_connections;
- unsigned long total_items;
- unsigned long uptime;
- unsigned long long bytes;
- unsigned long long bytes_read;
- unsigned long long bytes_written;
- unsigned long long cmd_get;
- unsigned long long cmd_set;
- unsigned long long evictions;
- unsigned long long get_hits;
- unsigned long long get_misses;
- unsigned long long limit_maxbytes;
- char version[MEMCACHED_VERSION_STRING_LENGTH];
- void *__future; // @todo create a new structure to place here for future usage
- memcached_st *root;
-};
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-/**
- Strings are always under our control so we make some assumptions
- about them.
-
- 1) is_initialized is always valid.
- 2) A string once intialized will always be, until free where we
- unset this flag.
- 3) A string always has a root.
-*/
-
-struct memcached_string_st {
- char *end;
- char *string;
- size_t current_size;
- struct memcached_st *root;
- struct {
- bool is_allocated:1;
- bool is_initialized:1;
- } options;
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached C sasl test app
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- * @file @brief C dummy test, aka testing C linking, etc
- */
-
-#include <stdlib.h>
-
-#ifdef HAVE_SASL_SASL_H
-#include <sasl/sasl.h>
-#endif
-
-#include <libmemcached-1.0/memcached.h>
-
-int main(void)
-{
- memcached_st *memc= memcached_create(NULL);
-
- if (memc == NULL)
- {
- return EXIT_FAILURE;
- }
- memcached_free(memc);
-
- return EXIT_SUCCESS;
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached C test app
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- * @file @brief C dummy test, aka testing C linking, etc
- */
-
-#include <stdlib.h>
-
-#include <libmemcached-1.0/memcached.h>
-
-int main(void)
-{
- (void)memcached_success(MEMCACHED_SUCCESS);
- (void)memcached_failed(MEMCACHED_SUCCESS);
- (void)memcached_continue(MEMCACHED_SUCCESS);
-
- memcached_st *memc= memcached_create(NULL);
-
- if (memc == NULL)
- {
- return EXIT_FAILURE;
- }
- memcached_free(memc);
-
- return EXIT_SUCCESS;
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached C++ test app
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- * @file @brief C dummy test, aka testing C linking, etc
- */
-
-#include <cstdlib>
-
-#include <libmemcached-1.0/memcached.h>
-
-int main(void)
-{
- (void)memcached_success(MEMCACHED_SUCCESS);
- (void)memcached_failed(MEMCACHED_SUCCESS);
- (void)memcached_continue(MEMCACHED_SUCCESS);
-
- memcached_st *memc= memcached_create(NULL);
-
- if (memc == NULL)
- {
- return EXIT_FAILURE;
- }
-
- memcached_free(memc);
-
- return EXIT_SUCCESS;
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-LIBMEMCACHED_API
-memcached_return_t memcached_touch(memcached_st *ptr,
- const char *key, size_t key_length,
- time_t expiration);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_touch_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- time_t expiration);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef memcached_return_t (*memcached_clone_fn)(memcached_st *destination, const memcached_st *source);
-typedef memcached_return_t (*memcached_cleanup_fn)(const memcached_st *ptr);
-
-/**
- Trigger functions.
-*/
-typedef memcached_return_t (*memcached_trigger_key_fn)(const memcached_st *ptr,
- const char *key, size_t key_length,
- memcached_result_st *result);
-typedef memcached_return_t (*memcached_trigger_delete_key_fn)(const memcached_st *ptr,
- const char *key, size_t key_length);
-
-typedef memcached_return_t (*memcached_dump_fn)(const memcached_st *ptr,
- const char *key,
- size_t key_length,
- void *context);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifdef __cplusplus
-
-struct memcached_st;
-struct memcached_stat_st;
-struct memcached_analysis_st;
-struct memcached_result_st;
-struct memcached_array_st;
-struct memcached_error_t;
-
-// All of the flavors of memcache_server_st
-struct memcached_server_st;
-struct memcached_instance_st;
-typedef struct memcached_instance_st memcached_instance_st;
-typedef struct memcached_server_st *memcached_server_list_st;
-
-struct memcached_callback_st;
-
-// The following two structures are internal, and never exposed to users.
-struct memcached_string_st;
-struct memcached_string_t;
-struct memcached_continuum_item_st;
-
-#else
-
-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_array_st memcached_array_st;
-typedef struct memcached_error_t memcached_error_t;
-
-// All of the flavors of memcache_server_st
-typedef struct memcached_server_st memcached_server_st;
-typedef struct memcached_instance_st memcached_instance_st;
-typedef struct memcached_server_st *memcached_server_list_st;
-
-typedef struct memcached_callback_st memcached_callback_st;
-
-// The following two structures are internal, and never exposed to users.
-typedef struct memcached_string_st memcached_string_st;
-typedef struct memcached_string_t memcached_string_t;
-
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-enum memcached_behavior_t {
- 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_TCP_KEEPALIVE,
- MEMCACHED_BEHAVIOR_TCP_KEEPIDLE,
- MEMCACHED_BEHAVIOR_LOAD_FROM_FILE,
- MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS,
- MEMCACHED_BEHAVIOR_DEAD_TIMEOUT,
- MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT,
- MEMCACHED_BEHAVIOR_MAX
-};
-
-#ifndef __cplusplus
-typedef enum memcached_behavior_t memcached_behavior_t;
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-enum memcached_callback_t {
- MEMCACHED_CALLBACK_PREFIX_KEY = 0,
- MEMCACHED_CALLBACK_USER_DATA = 1,
- MEMCACHED_CALLBACK_CLEANUP_FUNCTION = 2,
- MEMCACHED_CALLBACK_CLONE_FUNCTION = 3,
- MEMCACHED_CALLBACK_GET_FAILURE = 7,
- MEMCACHED_CALLBACK_DELETE_TRIGGER = 8,
- MEMCACHED_CALLBACK_MAX,
- MEMCACHED_CALLBACK_NAMESPACE= MEMCACHED_CALLBACK_PREFIX_KEY
-};
-
-#ifndef __cplusplus
-typedef enum memcached_callback_t memcached_callback_t;
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-enum memcached_connection_t {
- MEMCACHED_CONNECTION_TCP,
- MEMCACHED_CONNECTION_UDP,
- MEMCACHED_CONNECTION_UNIX_SOCKET
-};
-
-#ifndef __cplusplus
-typedef enum memcached_connection_t memcached_connection_t;
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-enum memcached_hash_t {
- 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_MURMUR3,
- MEMCACHED_HASH_CUSTOM,
- MEMCACHED_HASH_MAX
-};
-
-#ifndef __cplusplus
-typedef enum memcached_hash_t memcached_hash_t;
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-enum memcached_return_t {
- MEMCACHED_SUCCESS,
- MEMCACHED_FAILURE,
- MEMCACHED_HOST_LOOKUP_FAILURE, // getaddrinfo() and getnameinfo() only
- MEMCACHED_CONNECTION_FAILURE,
- MEMCACHED_CONNECTION_BIND_FAILURE, // DEPRECATED, see MEMCACHED_HOST_LOOKUP_FAILURE
- MEMCACHED_WRITE_FAILURE,
- MEMCACHED_READ_FAILURE,
- MEMCACHED_UNKNOWN_READ_FAILURE,
- MEMCACHED_PROTOCOL_ERROR,
- MEMCACHED_CLIENT_ERROR,
- MEMCACHED_SERVER_ERROR, // Server returns "SERVER_ERROR"
- MEMCACHED_ERROR, // Server returns "ERROR"
- 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, // DEPRECATED
- MEMCACHED_NOT_SUPPORTED,
- MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */
- MEMCACHED_FETCH_NOTFINISHED,
- MEMCACHED_TIMEOUT,
- MEMCACHED_BUFFERED,
- MEMCACHED_BAD_KEY_PROVIDED,
- MEMCACHED_INVALID_HOST_PROTOCOL,
- MEMCACHED_SERVER_MARKED_DEAD,
- MEMCACHED_UNKNOWN_STAT_KEY,
- MEMCACHED_E2BIG,
- MEMCACHED_INVALID_ARGUMENTS,
- MEMCACHED_KEY_TOO_BIG,
- MEMCACHED_AUTH_PROBLEM,
- MEMCACHED_AUTH_FAILURE,
- MEMCACHED_AUTH_CONTINUE,
- MEMCACHED_PARSE_ERROR,
- MEMCACHED_PARSE_USER_ERROR,
- MEMCACHED_DEPRECATED,
- MEMCACHED_IN_PROGRESS,
- MEMCACHED_SERVER_TEMPORARILY_DISABLED,
- MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE,
- MEMCACHED_UNIX_SOCKET_PATH_TOO_BIG,
- MEMCACHED_MAXIMUM_RETURN, /* Always add new error code before */
- MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE= MEMCACHED_ERROR
-};
-
-#ifndef __cplusplus
-typedef enum memcached_return_t memcached_return_t;
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-enum memcached_server_distribution_t {
- MEMCACHED_DISTRIBUTION_MODULA,
- MEMCACHED_DISTRIBUTION_CONSISTENT,
- MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA,
- MEMCACHED_DISTRIBUTION_RANDOM,
- MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY,
- MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED,
- MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET,
- MEMCACHED_DISTRIBUTION_CONSISTENT_MAX
-};
-
-#ifndef __cplusplus
-typedef enum memcached_server_distribution_t memcached_server_distribution_t;
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_verbosity(memcached_st *ptr, uint32_t verbosity);
-
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_version(memcached_st *ptr);
-
-LIBMEMCACHED_API
-const char * memcached_lib_version(void);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* 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.
- *
- * Author: Trond Norbye
- *
- */
-
-/**
- * @file
- * @brief Visibility control macros
- */
-
-#pragma once
-
-/**
- *
- * LIBMEMCACHED_API is used for the public API symbols. It either DLL imports or
- * DLL exports (or does nothing for static build).
- *
- * LIBMEMCACHED_LOCAL is used for non-api symbols.
- */
-
-#if defined(BUILDING_LIBMEMCACHEDINTERNAL)
-# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
-# define LIBMEMCACHED_API __attribute__ ((visibility("default")))
-# define LIBMEMCACHED_LOCAL __attribute__ ((visibility("default")))
-# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
-# define LIBMEMCACHED_API __global
-# define LIBMEMCACHED_LOCAL __global
-# elif defined(_MSC_VER)
-# define LIBMEMCACHED_API extern __declspec(dllexport)
-# define LIBMEMCACHED_LOCAL extern __declspec(dllexport)
-# else
-# define LIBMEMCACHED_API
-# define LIBMEMCACHED_LOCAL
-# endif
-#else
-# if defined(BUILDING_LIBMEMCACHED)
-# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
-# define LIBMEMCACHED_API __attribute__ ((visibility("default")))
-# define LIBMEMCACHED_LOCAL __attribute__ ((visibility("hidden")))
-# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
-# define LIBMEMCACHED_API __global
-# define LIBMEMCACHED_LOCAL __hidden
-# elif defined(_MSC_VER)
-# define LIBMEMCACHED_API extern __declspec(dllexport)
-# define LIBMEMCACHED_LOCAL
-# else
-# define LIBMEMCACHED_API
-# define LIBMEMCACHED_LOCAL
-# endif /* defined(HAVE_VISIBILITY) */
-# else /* defined(BUILDING_LIBMEMCACHED) */
-# if defined(_MSC_VER)
-# define LIBMEMCACHED_API extern __declspec(dllimport)
-# define LIBMEMCACHED_LOCAL
-# else
-# define LIBMEMCACHED_API
-# define LIBMEMCACHED_LOCAL
-# endif /* defined(_MSC_VER) */
-# endif /* defined(BUILDING_LIBMEMCACHED) */
-#endif /* defined(BUILDING_LIBMEMCACHEDINTERNAL) */
+++ /dev/null
-
-find_package(FLEX)
-find_package(BISON)
-
-file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/csl)
-bison_target(CSL_PARSER csl/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/csl/parser.cc
- DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/csl/parser.h
- )
-flex_target(CSL_SCANNER csl/scanner.l ${CMAKE_CURRENT_BINARY_DIR}/csl/scanner.cc
- DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/csl/scanner.h
- )
-add_flex_bison_dependency(CSL_SCANNER CSL_PARSER)
-
-set(LIBMEMCACHED_SOURCES
- csl/context.cc
- ${BISON_CSL_PARSER_OUTPUTS}
- ${FLEX_CSL_SCANNER_OUTPUTS}
- allocators.cc
- analyze.cc
- array.c
- auto.cc
- backtrace.cc
- behavior.cc
- byteorder.cc
- callback.cc
- connect.cc
- delete.cc
- do.cc
- dump.cc
- encoding_key.cc
- error.cc
- exist.cc
- fetch.cc
- flag.cc
- flush.cc
- flush_buffers.cc
- get.cc
- hash.cc
- hosts.cc
- initialize_query.cc
- instance.cc
- io.cc
- key.cc
- memcached.cc
- namespace.cc
- options.cc
- parse.cc
- poll.cc
- purge.cc
- quit.cc
- response.cc
- result.cc
- sasl.cc
- server.cc
- server_list.cc
- stats.cc
- storage.cc
- strerror.cc
- string.cc
- touch.cc
- udp.cc
- verbosity.cc
- version.cc
- virtual_bucket.c)
-
-add_library(libmemcached SHARED
- ${LIBMEMCACHED_SOURCES})
-add_library(memcached ALIAS libmemcached)
-set_target_properties(libmemcached PROPERTIES LIBRARY_OUTPUT_NAME memcached)
-target_link_libraries(libmemcached libhashkit Threads::Threads ${LIBSASL_LIBRARIES} ${CMAKE_DL_LIBS})
-target_include_directories(libmemcached PRIVATE .. ${LIBSASL_INCLUDEDIR})
-target_compile_definitions(libmemcached PRIVATE -DBUILDING_LIBMEMCACHED)
-
-set_target_properties(libmemcached PROPERTIES SOVERSION ${LIBMEMCACHED_SO_VERSION})
-install(TARGETS libmemcached EXPORT libmemcached
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
-export(EXPORT libmemcached)
-install(EXPORT libmemcached DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake)
-
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
- FILES_MATCHING REGEX "(memcached|util)\\.h(pp)?"
- PATTERN csl EXCLUDE
- PATTERN memcached EXCLUDE
- PATTERN util EXCLUDE
- )
-
-# FIXME: dtrace
-
-add_library(libmemcachedinternal STATIC
- ${LIBMEMCACHED_SOURCES})
-add_library(memcachedinternal ALIAS libmemcachedinternal)
-set_target_properties(libmemcachedinternal PROPERTIES LIBRARY_OUTPUT_NAME memcachedinternal)
-target_link_libraries(libmemcachedinternal libhashkit Threads::Threads ${LIBSASL_LIBRARIES} ${CMAKE_DL_LIBS})
-target_include_directories(libmemcachedinternal PRIVATE .. ${LIBSASL_INCLUDEDIR})
-target_compile_definitions(libmemcachedinternal PRIVATE -DBUILDING_LIBMEMCACHEDINTERNAL)
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-void _libmemcached_free(const memcached_st*, void *mem, void*)
-{
- if (mem)
- {
- std::free(mem);
- }
-}
-
-void *_libmemcached_malloc(const memcached_st *, size_t size, void *)
-{
- return std::malloc(size);
-}
-
-void *_libmemcached_realloc(const memcached_st*, void *mem, size_t size, void *)
-{
- return std::realloc(mem, size);
-}
-
-void *_libmemcached_calloc(const memcached_st *self, size_t nelem, size_t size, void *context)
-{
- if (self->allocators.malloc != _libmemcached_malloc)
- {
- void *ret= _libmemcached_malloc(self, nelem * size, context);
- if (ret)
- {
- memset(ret, 0, nelem * size);
- }
-
- return ret;
- }
-
- return std::calloc(nelem, size);
-}
-
-struct memcached_allocator_t memcached_allocators_return_default(void)
-{
- static struct memcached_allocator_t global_default_allocator= { _libmemcached_calloc, _libmemcached_free, _libmemcached_malloc, _libmemcached_realloc, 0 };
- return global_default_allocator;
-}
-
-memcached_return_t memcached_set_memory_allocators(memcached_st *shell,
- memcached_malloc_fn mem_malloc,
- memcached_free_fn mem_free,
- memcached_realloc_fn mem_realloc,
- memcached_calloc_fn mem_calloc,
- void *context)
-{
- Memcached* self= memcached2Memcached(shell);
- if (self == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- /* All should be set, or none should be set */
- if (mem_malloc == NULL and mem_free == NULL and mem_realloc == NULL and mem_calloc == NULL)
- {
- self->allocators= memcached_allocators_return_default();
- }
- else if (mem_malloc == NULL or mem_free == NULL or mem_realloc == NULL or mem_calloc == NULL)
- {
- return memcached_set_error(*self, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("NULL parameter provided for one or more allocators"));
- }
- else
- {
- self->allocators.malloc= mem_malloc;
- self->allocators.free= mem_free;
- self->allocators.realloc= mem_realloc;
- self->allocators.calloc= mem_calloc;
- self->allocators.context= context;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-void *memcached_get_memory_allocators_context(const memcached_st *shell)
-{
- const Memcached* self= memcached2Memcached(shell);
- if (self)
- {
- return self->allocators.context;
- }
-
- return NULL;
-}
-
-void memcached_get_memory_allocators(const memcached_st *shell,
- memcached_malloc_fn *mem_malloc,
- memcached_free_fn *mem_free,
- memcached_realloc_fn *mem_realloc,
- memcached_calloc_fn *mem_calloc)
-{
- const Memcached* self= memcached2Memcached(shell);
- if (self)
- {
- if (mem_malloc)
- {
- *mem_malloc= self->allocators.malloc;
- }
-
- if (mem_free)
- {
- *mem_free= self->allocators.free;
- }
-
- if (mem_realloc)
- {
- *mem_realloc= self->allocators.realloc;
- }
-
- if (mem_calloc)
- {
- *mem_calloc= self->allocators.calloc;
- }
- }
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-void _libmemcached_free(const memcached_st *ptr, void *mem, void *context);
-
-void *_libmemcached_malloc(const memcached_st *ptr, const size_t size, void *context);
-
-void *_libmemcached_realloc(const memcached_st *ptr, void *mem, const size_t size, void *context);
-
-void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context);
-
-struct memcached_allocator_t memcached_allocators_return_default(void);
+++ /dev/null
-#include <libmemcached/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 *shell,
- memcached_stat_st *memc_stat,
- memcached_return_t *error)
-{
- Memcached* memc= memcached2Memcached(shell);
- uint64_t total_items= 0, total_bytes= 0;
- uint64_t total_get_cmds= 0, total_get_hits= 0;
-
- if (memc == NULL or memc_stat == NULL)
- {
- return NULL;
- }
-
- memcached_return_t not_used;
- if (error == NULL)
- {
- error= ¬_used;
- }
-
- *error= MEMCACHED_SUCCESS;
- uint32_t server_count= memcached_server_count(memc);
- memcached_analysis_st *result= (memcached_analysis_st*)libmemcached_xcalloc(memc,
- memcached_server_count(memc),
- memcached_analysis_st);
-
- if (result == NULL)
- {
- *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return NULL;
- }
-
- result->root= memc;
-
- for (uint32_t x= 0; x < server_count; x++)
- {
- calc_largest_consumption(result, x, memc_stat[x].bytes);
- calc_oldest_node(result, x, uint32_t(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)
-{
- libmemcached_free(ptr->root, ptr);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-#include <assert.h>
-#include <iso646.h>
-
-struct memcached_array_st
-{
- Memcached *root;
- size_t size;
- char c_str[];
-};
-
-
-memcached_array_st *memcached_array_clone(Memcached *memc, const memcached_array_st *original)
-{
- if (original)
- {
- return memcached_strcpy(memc, original->c_str, original->size);
- }
-
- return NULL;
-}
-
-memcached_array_st *memcached_strcpy(Memcached *memc, const char *str, size_t str_length)
-{
- assert(memc);
- assert(str);
- assert(str_length);
-
- memcached_array_st *array= (struct memcached_array_st *)libmemcached_malloc(memc, sizeof(struct memcached_array_st) +str_length +1);
-
- if (array)
- {
- array->root= memc;
- array->size= str_length; // We don't count the NULL ending
- memcpy(array->c_str, str, str_length);
- array->c_str[str_length]= 0;
- }
-
- return array;
-}
-
-bool memcached_array_is_null(memcached_array_st *array)
-{
- if (array)
- {
- return false;
- }
-
- return true;
-}
-
-memcached_string_t memcached_array_to_string(memcached_array_st *array)
-{
- assert(array);
- assert(array->c_str);
- assert(array->size);
- memcached_string_t tmp;
- tmp.c_str= array->c_str;
- tmp.size= array->size;
-
- return tmp;
-}
-
-void memcached_array_free(memcached_array_st *array)
-{
- if (array)
- {
- WATCHPOINT_ASSERT(array->root);
- libmemcached_free(array->root, array);
- }
-}
-
-size_t memcached_array_size(memcached_array_st *array)
-{
- if (array)
- {
- return array->size;
- }
-
- return 0;
-}
-
-const char *memcached_array_string(memcached_array_st *array)
-{
- if (array)
- {
- return array->c_str;
- }
-
- return NULL;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-memcached_array_st *memcached_array_clone(Memcached* memc, const memcached_array_st *original);
-
-memcached_array_st *memcached_strcpy(Memcached* memc, const char *str, size_t str_length);
-
-void memcached_array_free(memcached_array_st *array);
-
-size_t memcached_array_size(memcached_array_st *array);
-
-const char *memcached_array_string(memcached_array_st *array);
-
-memcached_string_t memcached_array_to_string(memcached_array_st *array);
-
-bool memcached_array_is_null(memcached_array_st *array);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#ifdef __cplusplus
-#define memcached_print_array(X) static_cast<int>(memcached_array_size(X)), memcached_array_string(X)
-#define memcached_param_array(X) memcached_array_string(X), memcached_array_size(X)
-#else
-#define memcached_print_array(X) (int)memcached_array_size((X)), memcached_array_string((X))
-#define memcached_param_array(X) memcached_array_string(X), memcached_array_size(X)
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * libmcachedd client library.
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-# include <cassert>
-#else
-# include <assert.h>
-#endif // __cplusplus
-
-#ifdef NDEBUG
-# define assert_msg(__expr, __mesg) (void)(__expr); (void)(__mesg);
-# define assert_vmsg(__expr, __mesg, ...) (void)(__expr); (void)(__mesg);
-#else
-
-# ifdef _WIN32
-# include <malloc.h>
-# else
-# include <alloca.h>
-# endif
-
-#ifdef __cplusplus
-# include <cstdarg>
-# include <cstdio>
-#else
-# include <stdarg.h>
-# include <stdio.h>
-#endif
-
-# include <libmemcached/backtrace.hpp>
-
-# define assert_msg(__expr, __mesg) \
-do \
-{ \
- if (not (__expr)) \
- { \
- fprintf(stderr, "\n%s:%d Assertion \"%s\" failed for function \"%s\" likely for %s\n", __FILE__, __LINE__, #__expr, __func__, (#__mesg));\
- custom_backtrace(); \
- abort(); \
- } \
-} while (0)
-
-# define assert_vmsg(__expr, __mesg, ...) \
-do \
-{ \
- if (not (__expr)) \
- { \
- size_t ask= snprintf(0, 0, (__mesg), __VA_ARGS__); \
- ask++; \
- char *_error_message= (char*)alloca(sizeof(char) * ask); \
- size_t _error_message_size= snprintf(_error_message, ask, (__mesg), __VA_ARGS__); \
- fprintf(stderr, "\n%s:%d Assertion '%s' failed for function '%s' [ %.*s ]\n", __FILE__, __LINE__, #__expr, __func__, int(_error_message_size), _error_message);\
- custom_backtrace(); \
- abort(); \
- } \
-} while (0)
-
-#endif // NDEBUG
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-static void auto_response(memcached_instance_st* instance, const bool reply, memcached_return_t& rc, uint64_t* value)
-{
- // If the message was successfully sent, then get the response, otherwise
- // fail.
- if (memcached_success(rc))
- {
- if (reply == false)
- {
- *value= UINT64_MAX;
- return;
- }
-
- rc= memcached_response(instance, &instance->root->result);
- }
-
- if (memcached_fatal(rc))
- {
- assert(memcached_last_error(instance->root) != MEMCACHED_SUCCESS);
- *value= UINT64_MAX;
- }
- else if (memcached_failed(rc))
- {
- *value= UINT64_MAX;
- }
- else
- {
- assert(memcached_last_error(instance->root) != MEMCACHED_NOTFOUND);
- *value= instance->root->result.numeric_value;
- }
-}
-
-static memcached_return_t text_incr_decr(memcached_instance_st* instance,
- const bool is_incr,
- const char *key, size_t key_length,
- const uint64_t offset,
- const bool reply)
-{
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
- int send_length= snprintf(buffer, sizeof(buffer), " %" PRIu64, offset);
- if (size_t(send_length) >= sizeof(buffer) or send_length < 0)
- {
- return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
- }
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { memcached_literal_param("incr ") },
- { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
- { key, key_length },
- { buffer, size_t(send_length) },
- { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
- { memcached_literal_param("\r\n") }
- };
-
- if (is_incr == false)
- {
- vector[1].buffer= "decr ";
- }
-
- return memcached_vdo(instance, vector, 7, true);
-}
-
-static memcached_return_t binary_incr_decr(memcached_instance_st* instance,
- protocol_binary_command cmd,
- const char *key, const size_t key_length,
- const uint64_t offset,
- const uint64_t initial,
- const uint32_t expiration,
- const bool reply)
-{
- if (reply == false)
- {
- 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}};
-
- initialize_binary_request(instance, request.message.header);
-
- request.message.header.request.opcode= cmd;
- request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(instance->root->_namespace)));
- request.message.header.request.extlen= 20;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(instance->root->_namespace) +request.message.header.request.extlen));
- request.message.body.delta= memcached_htonll(offset);
- request.message.body.initial= memcached_htonll(initial);
- request.message.body.expiration= htonl((uint32_t) expiration);
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { request.bytes, sizeof(request.bytes) },
- { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
- { key, key_length }
- };
-
- return memcached_vdo(instance, vector, 4, true);
-}
-
-memcached_return_t memcached_increment(memcached_st *memc,
- const char *key, size_t key_length,
- uint32_t offset,
- uint64_t *value)
-{
- return memcached_increment_by_key(memc, key, key_length, key, key_length, offset, value);
-}
-
-static memcached_return_t increment_decrement_by_key(const protocol_binary_command command,
- Memcached *memc,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- uint64_t offset,
- uint64_t *value)
-{
- uint64_t local_value;
- if (value == NULL)
- {
- value= &local_value;
- }
-
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(memc, true)))
- {
- return rc;
- }
-
- if (memcached_is_encrypted(memc))
- {
- return memcached_set_error(*memc, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
- memcached_literal_param("Operation not allowed while encyrption is enabled"));
- }
-
- if (memcached_failed(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
- {
- return memcached_last_error(memc);
- }
-
- uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
- memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
-
- bool reply= memcached_is_replying(instance->root);
-
- if (memcached_is_binary(memc))
- {
- rc= binary_incr_decr(instance, command,
- key, key_length,
- uint64_t(offset), 0, MEMCACHED_EXPIRATION_NOT_ADD,
- reply);
- }
- else
- {
- rc= text_incr_decr(instance,
- command == PROTOCOL_BINARY_CMD_INCREMENT ? true : false,
- key, key_length,
- offset, reply);
- }
-
- auto_response(instance, reply, rc, value);
-
- return rc;
-}
-
-static memcached_return_t increment_decrement_with_initial_by_key(const protocol_binary_command command,
- Memcached *memc,
- const char *group_key,
- size_t group_key_length,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value)
-{
- uint64_t local_value;
- if (value == NULL)
- {
- value= &local_value;
- }
-
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(memc, true)))
- {
- return rc;
- }
-
- if (memcached_is_encrypted(memc))
- {
- return memcached_set_error(*memc, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
- memcached_literal_param("Operation not allowed while encryption is enabled"));
- }
-
- if (memcached_failed(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
- {
- return memcached_last_error(memc);
- }
-
- uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
- memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
-
- bool reply= memcached_is_replying(instance->root);
-
- if (memcached_is_binary(memc))
- {
- rc= binary_incr_decr(instance, command,
- key, key_length,
- offset, initial, uint32_t(expiration),
- reply);
-
- }
- else
- {
- rc= memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("memcached_increment_with_initial_by_key() is not supported via the ASCII protocol"));
- }
-
- auto_response(instance, reply, rc, value);
-
- return rc;
-}
-
-memcached_return_t memcached_decrement(memcached_st *memc,
- const char *key, size_t key_length,
- uint32_t offset,
- uint64_t *value)
-{
- return memcached_decrement_by_key(memc, key, key_length, key, key_length, offset, value);
-}
-
-
-memcached_return_t memcached_increment_by_key(memcached_st *shell,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- uint64_t offset,
- uint64_t *value)
-{
- Memcached* memc= memcached2Memcached(shell);
- LIBMEMCACHED_MEMCACHED_INCREMENT_START();
- memcached_return_t rc= increment_decrement_by_key(PROTOCOL_BINARY_CMD_INCREMENT,
- memc,
- group_key, group_key_length,
- key, key_length,
- offset, value);
-
- LIBMEMCACHED_MEMCACHED_INCREMENT_END();
-
- return rc;
-}
-
-memcached_return_t memcached_decrement_by_key(memcached_st *shell,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- uint64_t offset,
- uint64_t *value)
-{
- Memcached* memc= memcached2Memcached(shell);
- LIBMEMCACHED_MEMCACHED_DECREMENT_START();
- memcached_return_t rc= increment_decrement_by_key(PROTOCOL_BINARY_CMD_DECREMENT,
- memc,
- group_key, group_key_length,
- key, key_length,
- offset, value);
- LIBMEMCACHED_MEMCACHED_DECREMENT_END();
-
- return rc;
-}
-
-memcached_return_t memcached_increment_with_initial(memcached_st *memc,
- 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(memc, key, key_length,
- key, key_length,
- offset, initial, expiration, value);
-}
-
-memcached_return_t memcached_increment_with_initial_by_key(memcached_st *shell,
- const char *group_key,
- size_t group_key_length,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value)
-{
- LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
- Memcached* memc= memcached2Memcached(shell);
- memcached_return_t rc= increment_decrement_with_initial_by_key(PROTOCOL_BINARY_CMD_INCREMENT,
- memc,
- group_key, group_key_length,
- key, key_length,
- offset, initial, expiration, value);
- LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
-
- return rc;
-}
-
-memcached_return_t memcached_decrement_with_initial(memcached_st *memc,
- 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(memc, key, key_length,
- key, key_length,
- offset, initial, expiration, value);
-}
-
-memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *shell,
- const char *group_key,
- size_t group_key_length,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value)
-{
- LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
- Memcached* memc= memcached2Memcached(shell);
- memcached_return_t rc= increment_decrement_with_initial_by_key(PROTOCOL_BINARY_CMD_DECREMENT,
- memc,
- group_key, group_key_length,
- key, key_length,
- offset, initial, expiration, value);
-
- LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
-
- return rc;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached client library.
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "mem_config.h"
-
-#include "libmemcached/backtrace.hpp"
-
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-
-#if defined(HAVE_SHARED_ENABLED) && HAVE_SHARED_ENABLED
-
-#ifdef HAVE_EXECINFO_H
-#include <execinfo.h>
-#endif
-
-#ifdef HAVE_GCC_ABI_DEMANGLE
-# include <cxxabi.h>
-# define USE_DEMANGLE 1
-#else
-# define USE_DEMANGLE 0
-#endif
-
-#ifdef HAVE_DLFCN_H
-# include <dlfcn.h>
-#endif
-
-const int MAX_DEPTH= 50;
-
-void custom_backtrace(void)
-{
-#ifdef HAVE_EXECINFO_H
- void *backtrace_buffer[MAX_DEPTH +1];
-
- int stack_frames= backtrace(backtrace_buffer, MAX_DEPTH);
- if (stack_frames)
- {
- char **symbollist= backtrace_symbols(backtrace_buffer, stack_frames);
- if (symbollist)
- {
- for (int x= 0; x < stack_frames; x++)
- {
- bool was_demangled= false;
-
- if (USE_DEMANGLE)
- {
-#ifdef HAVE_DLFCN_H
- Dl_info dlinfo;
- if (dladdr(backtrace_buffer[x], &dlinfo))
- {
- char demangled_buffer[1024];
- const char *called_in= "<unresolved>";
- if (dlinfo.dli_sname)
- {
- size_t demangled_size= sizeof(demangled_buffer);
- int status;
- char* demangled;
- if ((demangled= abi::__cxa_demangle(dlinfo.dli_sname, demangled_buffer, &demangled_size, &status)))
- {
- called_in= demangled;
- fprintf(stderr, "---> demangled: %s -> %s\n", demangled_buffer, demangled);
- }
- else
- {
- called_in= dlinfo.dli_sname;
- }
-
- was_demangled= true;
- fprintf(stderr, "#%d %p in %s at %s\n",
- x, backtrace_buffer[x],
- called_in,
- dlinfo.dli_fname);
- }
- }
-#endif
- }
-
- if (was_demangled == false)
- {
- fprintf(stderr, "?%d %p in %s\n", x, backtrace_buffer[x], symbollist[x]);
- }
- }
-
- ::free(symbollist);
- }
- }
-#endif // HAVE_EXECINFO_H
-}
-
-#else // HAVE_SHARED_ENABLED
-
-void custom_backtrace(void)
-{
- fprintf(stderr, "Backtrace null function called\n");
-}
-#endif // AX_ENABLE_BACKTRACE
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * libmcachedd client library.
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void custom_backtrace(void);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-#include <libmemcached/options.hpp>
-#include <libmemcached/virtual_bucket.h>
-
-#include <ctime>
-#include <sys/types.h>
-
-bool memcached_is_consistent_distribution(const Memcached* memc)
-{
- switch (memc->distribution)
- {
- case MEMCACHED_DISTRIBUTION_CONSISTENT:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
- return true;
-
- case MEMCACHED_DISTRIBUTION_MODULA:
- case MEMCACHED_DISTRIBUTION_RANDOM:
- case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
- break;
- }
-
- return false;
-}
-
-/*
- This function is used to modify the behavior of running client.
-
- We quit all connections so we can reset the sockets.
-*/
-
-memcached_return_t memcached_behavior_set(memcached_st *shell,
- const memcached_behavior_t flag,
- uint64_t data)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- switch (flag)
- {
- case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
- ptr->number_of_replicas= (uint32_t)data;
- break;
-
- case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
- ptr->io_msg_watermark= (uint32_t) data;
- break;
-
- case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
- ptr->io_bytes_watermark= (uint32_t)data;
- break;
-
- case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
- ptr->io_key_prefetch = (uint32_t)data;
- break;
-
- case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
- ptr->snd_timeout= (int32_t)data;
- break;
-
- case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
- ptr->rcv_timeout= (int32_t)data;
- break;
-
- case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
- ptr->flags.auto_eject_hosts= bool(data);
- break;
-
- case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
- if (data == 0)
- {
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT requires a value greater then zero."));
- }
- ptr->server_failure_limit= uint32_t(data);
- break;
-
- case MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT:
- ptr->server_timeout_limit= uint32_t(data);
- break;
-
- case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
- send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
- if (data)
- {
- ptr->flags.verify_key= false;
- }
- ptr->flags.binary_protocol= bool(data);
- break;
-
- case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
- ptr->flags.support_cas= bool(data);
- break;
-
- case MEMCACHED_BEHAVIOR_NO_BLOCK:
- ptr->flags.no_block= bool(data);
- send_quit(ptr);
- break;
-
- case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
- if (memcached_is_udp(ptr))
- {
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("MEMCACHED_BEHAVIOR_BUFFER_REQUESTS cannot be set while MEMCACHED_BEHAVIOR_USE_UDP is enabled."));
- }
- ptr->flags.buffer_requests= bool(data);
- send_quit(ptr);
- break;
-
- case MEMCACHED_BEHAVIOR_USE_UDP:
- send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
- ptr->flags.use_udp= bool(data);
- if (bool(data))
- {
- ptr->flags.reply= false;
- ptr->flags.buffer_requests= false;
- }
- else
- {
- ptr->flags.reply= true;
- }
- break;
-
- case MEMCACHED_BEHAVIOR_TCP_NODELAY:
- ptr->flags.tcp_nodelay= bool(data);
- send_quit(ptr);
- break;
-
- case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
- ptr->flags.tcp_keepalive= bool(data);
- send_quit(ptr);
- break;
-
- case MEMCACHED_BEHAVIOR_DISTRIBUTION:
- return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data);
-
- case MEMCACHED_BEHAVIOR_KETAMA:
- {
- if (data) // Turn on
- {
- return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
- }
-
- return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA);
- }
-
- case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
- {
- if (bool(data) == false)
- {
- return memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_KETAMA, true);
- }
-
- (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
- (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
- /**
- @note We try to keep the same distribution going. This should be deprecated and rewritten.
- */
- return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED);
- }
-
- case MEMCACHED_BEHAVIOR_HASH:
- return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data));
-
- case MEMCACHED_BEHAVIOR_KETAMA_HASH:
- return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data));
-
- case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
- return memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
- memcached_literal_param("MEMCACHED_BEHAVIOR_CACHE_LOOKUPS has been deprecated."));
-
- case MEMCACHED_BEHAVIOR_VERIFY_KEY:
- if (ptr->flags.binary_protocol)
- {
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled."));
- }
- ptr->flags.verify_key= bool(data);
- break;
-
- case MEMCACHED_BEHAVIOR_SORT_HOSTS:
- {
- ptr->flags.use_sort_hosts= bool(data);
- return run_distribution(ptr);
- }
-
- 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_DEAD_TIMEOUT:
- ptr->dead_timeout= int32_t(data);
- break;
-
- case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
- ptr->send_size= (int32_t)data;
- send_quit(ptr);
- break;
-
- case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
- ptr->recv_size= (int32_t)data;
- send_quit(ptr);
- break;
-
- case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
- ptr->tcp_keepidle= (uint32_t)data;
- send_quit(ptr);
- break;
-
- case MEMCACHED_BEHAVIOR_USER_DATA:
- return memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
- memcached_literal_param("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
-
- case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
- ptr->flags.hash_with_namespace= bool(data);
- break;
-
- case MEMCACHED_BEHAVIOR_NOREPLY:
- if (memcached_is_udp(ptr) and bool(data) == false)
- {
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("MEMCACHED_BEHAVIOR_NOREPLY cannot be disabled while MEMCACHED_BEHAVIOR_USE_UDP is enabled."));
- }
- // We reverse the logic here to make it easier to understand throughout the
- // code.
- ptr->flags.reply= bool(data) ? false : true;
- break;
-
- case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
- ptr->flags.auto_eject_hosts= bool(data);
- break;
-
- case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
- srandom((uint32_t) time(NULL));
- ptr->flags.randomize_replica_read= bool(data);
- break;
-
- case MEMCACHED_BEHAVIOR_CORK:
- return memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
- memcached_literal_param("MEMCACHED_BEHAVIOR_CORK is now incorporated into the driver by default."));
-
- case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()"));
-
- case MEMCACHED_BEHAVIOR_MAX:
- default:
- /* Shouldn't get here */
- assert_msg(0, "Invalid behavior passed to memcached_behavior_set()");
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("Invalid behavior passed to memcached_behavior_set()"));
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-bool _is_auto_eject_host(const memcached_st *ptr)
-{
- return ptr->flags.auto_eject_hosts;
-}
-
-uint64_t memcached_behavior_get(memcached_st *shell,
- const memcached_behavior_t flag)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- switch (flag)
- {
- case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
- return ptr->number_of_replicas;
-
- case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
- return ptr->io_msg_watermark;
-
- case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
- return ptr->io_bytes_watermark;
-
- case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
- return ptr->io_key_prefetch;
-
- case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
- return ptr->flags.binary_protocol;
-
- case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
- return ptr->flags.support_cas;
-
- case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
- return true;
-
- case MEMCACHED_BEHAVIOR_NO_BLOCK:
- return ptr->flags.no_block;
-
- case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
- return ptr->flags.buffer_requests;
-
- case MEMCACHED_BEHAVIOR_USE_UDP:
- return memcached_is_udp(ptr);
-
- 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:
- if (memcached_is_consistent_distribution(ptr))
- {
- return memcached_is_weighted_ketama(ptr);
- }
- return false;
-
- case MEMCACHED_BEHAVIOR_DISTRIBUTION:
- return ptr->distribution;
-
- case MEMCACHED_BEHAVIOR_KETAMA:
- return memcached_is_consistent_distribution(ptr);
-
- case MEMCACHED_BEHAVIOR_HASH:
- return hashkit_get_function(&ptr->hashkit);
-
- case MEMCACHED_BEHAVIOR_KETAMA_HASH:
- return hashkit_get_function(&ptr->hashkit);
-
- case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
- return ptr->flags.auto_eject_hosts;
-
- case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
- return ptr->server_failure_limit;
-
- case MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT:
- return ptr->server_timeout_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_DEAD_TIMEOUT:
- return uint64_t(ptr->dead_timeout);
-
- case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
- return (uint64_t)ptr->snd_timeout;
-
- case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
- return (uint64_t)ptr->rcv_timeout;
-
- case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
- return (uint64_t)ptr->tcp_keepidle;
-
- case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
- {
- int sock_size= 0;
- socklen_t sock_length= sizeof(int);
-
- if (ptr->send_size != -1) // If value is -1 then we are using the default
- {
- return (uint64_t) ptr->send_size;
- }
-
- memcached_instance_st* instance= memcached_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_failed(memcached_connect(instance)))
- {
- return 0;
- }
-
- if (memcached_failed(memcached_io_wait_for_write(instance)))
- {
- return 0;
- }
-
- if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, (char*)&sock_size, &sock_length) < 0)
- {
- memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
- 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);
-
- if (ptr->recv_size != -1) // If value is -1 then we are using the default
- return (uint64_t) ptr->recv_size;
-
- memcached_instance_st* instance= memcached_instance_fetch(ptr, 0);
-
- /**
- @note REFACTOR
- */
- if (instance)
- {
- /* We just try the first host, and if it is down we return zero */
- if (memcached_failed(memcached_connect(instance)))
- {
- return 0;
- }
-
- if (memcached_failed(memcached_io_wait_for_write(instance)))
- {
- return 0;
- }
-
- if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, (char*)&sock_size, &sock_length) < 0)
- {
- memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
- return 0; /* Zero means error */
- }
- }
-
- return (uint64_t) sock_size;
- }
-
- case MEMCACHED_BEHAVIOR_USER_DATA:
- memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
- memcached_literal_param("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
- return 0;
-
- case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
- return ptr->flags.hash_with_namespace;
-
- case MEMCACHED_BEHAVIOR_NOREPLY:
- return ptr->flags.reply ? false : true;
-
- case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
- return ptr->flags.auto_eject_hosts;
-
- case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
- return ptr->flags.randomize_replica_read;
-
- case MEMCACHED_BEHAVIOR_CORK:
-#ifdef HAVE_MSG_MORE
- return true;
-#else
- return false;
-#endif
-
- case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
- return ptr->flags.tcp_keepalive;
-
- case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
- return bool(memcached_parse_filename(ptr));
-
- case MEMCACHED_BEHAVIOR_MAX:
- default:
- assert_msg(0, "Invalid behavior passed to memcached_behavior_get()");
- return 0;
- }
-
- /* NOTREACHED */
-}
-
-
-memcached_return_t memcached_behavior_set_distribution(memcached_st *shell, memcached_server_distribution_t type)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- switch (type)
- {
- case MEMCACHED_DISTRIBUTION_MODULA:
- break;
-
- case MEMCACHED_DISTRIBUTION_CONSISTENT:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
- memcached_set_weighted_ketama(ptr, false);
- break;
-
- case MEMCACHED_DISTRIBUTION_RANDOM:
- break;
-
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
- break;
-
- case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
- memcached_set_weighted_ketama(ptr, true);
- break;
-
- case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
- break;
-
- default:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("Invalid memcached_server_distribution_t"));
- }
- ptr->distribution= type;
-
- return run_distribution(ptr);
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
-
-
-memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *shell)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- return ptr->distribution;
- }
-
- return MEMCACHED_DISTRIBUTION_CONSISTENT_MAX;
-}
-
-memcached_return_t memcached_behavior_set_key_hash(memcached_st *shell, memcached_hash_t type)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- if (hashkit_success(hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type)))
- {
- return MEMCACHED_SUCCESS;
- }
-
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("Invalid memcached_hash_t()"));
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
-
-memcached_hash_t memcached_behavior_get_key_hash(memcached_st *shell)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
- }
-
- return MEMCACHED_HASH_MAX;
-}
-
-memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *shell, memcached_hash_t type)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- if (hashkit_success(hashkit_set_distribution_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type)))
- {
- return MEMCACHED_SUCCESS;
- }
-
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("Invalid memcached_hash_t()"));
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
-
-memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *shell)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
- }
-
- return MEMCACHED_HASH_MAX;
-}
-
-const char *libmemcached_string_behavior(const memcached_behavior_t flag)
-{
- switch (flag)
- {
- case MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT";
- case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK";
- case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY";
- case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH";
- case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA";
- case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE";
- case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE";
- case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS";
- case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS";
- case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT";
- case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION";
- case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS";
- case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA";
- case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS";
- case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY";
- case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT";
- case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT";
- case MEMCACHED_BEHAVIOR_DEAD_TIMEOUT: return "MEMCACHED_BEHAVIOR_DEAD_TIMEOUT";
- case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED";
- case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH";
- case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL";
- case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT";
- case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT";
- case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT";
- case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK";
- case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK";
- case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH";
- case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY";
- case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY";
- case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP";
- case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS";
- case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: return "MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS";
- case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS";
- case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ";
- case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK";
- case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE";
- case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE";
- case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE";
- default:
- case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t";
- }
-}
-
-const char *libmemcached_string_distribution(const memcached_server_distribution_t flag)
-{
- switch (flag)
- {
- case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA";
- case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT";
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA";
- case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM";
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY";
- case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: return "MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED";
- case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: return "MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET";
- default:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t";
- }
-}
-
-memcached_return_t memcached_bucket_set(memcached_st *shell,
- const uint32_t *host_map,
- const uint32_t *forward_map,
- const uint32_t buckets,
- const uint32_t replicas)
-{
- Memcached* self= memcached2Memcached(shell);
- memcached_return_t rc;
-
- if (self == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (host_map == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- memcached_server_distribution_t old= memcached_behavior_get_distribution(self);
-
- if (memcached_failed(rc =memcached_behavior_set_distribution(self, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET)))
- {
- return rc;
- }
-
- if (memcached_failed(rc= memcached_virtual_bucket_create(self, host_map, forward_map, buckets, replicas)))
- {
- memcached_behavior_set_distribution(self, old);
- }
-
- return rc;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-bool memcached_is_consistent_distribution(const memcached_st*);
-bool _is_auto_eject_host(const memcached_st *ptr);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "mem_config.h"
-#include "libmemcached/byteorder.h"
-
-/* Byte swap a 64-bit number. */
-#ifndef swap64
-static inline uint64_t swap64(uint64_t in)
-{
-#ifndef WORDS_BIGENDIAN
- /* Little endian, flip the bytes around until someone makes a faster/better
- * way to do this. */
- uint64_t rv= 0;
- for (uint8_t x= 0; x < 8; ++x)
- {
- rv= (rv << 8) | (in & 0xff);
- in >>= 8;
- }
- return rv;
-#else
- /* big-endian machines don't need byte swapping */
- return in;
-#endif // WORDS_BIGENDIAN
-}
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-uint64_t memcached_ntohll(uint64_t value)
-{
-#ifdef HAVE_HTONLL
- return ntohll(value);
-#else
- return swap64(value);
-#endif
-}
-
-uint64_t memcached_htonll(uint64_t value)
-{
-#ifdef HAVE_HTONLL
- return htonll(value);
-#else
- return swap64(value);
-#endif
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-uint64_t memcached_ntohll(uint64_t);
-
-uint64_t memcached_htonll(uint64_t);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: Change any of the possible callbacks.
- *
- */
-
-#include <libmemcached/common.h>
-#include <sys/types.h>
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wstrict-aliasing"
-#endif
-
-/*
- These functions provide data and function callback support
-*/
-
-memcached_return_t memcached_callback_set(memcached_st *shell,
- const memcached_callback_t flag,
- const void *data)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- switch (flag)
- {
- case MEMCACHED_CALLBACK_PREFIX_KEY:
- {
- return memcached_set_namespace(*ptr, (char*)data, data ? strlen((char*)data) : 0);
- }
-
- case MEMCACHED_CALLBACK_USER_DATA:
- {
- ptr->user_data= const_cast<void *>(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;
- }
-
- 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:
- {
- if (data) // NULL would mean we are disabling.
- {
- if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS))
- {
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Delete triggers cannot be used if buffering is enabled"));
- }
-
- if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_NOREPLY))
- {
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Delete triggers cannot be used if MEMCACHED_BEHAVIOR_NOREPLY is set"));
- }
- }
-
- memcached_trigger_delete_key_fn func= *(memcached_trigger_delete_key_fn *)&data;
- ptr->delete_trigger= func;
- break;
- }
-
- case MEMCACHED_CALLBACK_MAX:
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid callback supplied"));
- }
-
- return MEMCACHED_SUCCESS;
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
-
-void *memcached_callback_get(memcached_st *shell,
- const memcached_callback_t flag,
- memcached_return_t *error)
-{
- Memcached* ptr= memcached2Memcached(shell);
- memcached_return_t local_error;
- if (error == NULL)
- {
- error = &local_error;
- }
-
- if (ptr == NULL)
- {
- *error= MEMCACHED_INVALID_ARGUMENTS;
- return NULL;
- }
-
- switch (flag)
- {
- case MEMCACHED_CALLBACK_PREFIX_KEY:
- {
- *error= MEMCACHED_SUCCESS;
- if (ptr->_namespace)
- {
- return (void *)memcached_array_string(ptr->_namespace);
- }
- return NULL;
- }
-
- case MEMCACHED_CALLBACK_USER_DATA:
- {
- *error= ptr->user_data ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return (void *)ptr->user_data;
- }
-
- case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
- {
- *error= ptr->on_cleanup ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return *(void **)&ptr->on_cleanup;
- }
-
- case MEMCACHED_CALLBACK_CLONE_FUNCTION:
- {
- *error= ptr->on_clone ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return *(void **)&ptr->on_clone;
- }
-
- 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:
- break;
- }
-
- assert_msg(0, "Invalid callback passed to memcached_callback_get()");
- *error= MEMCACHED_FAILURE;
- return NULL;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached Client and Server
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-test_return_t test_MEMCACHED_CALLBACK_DELETE_TRIGGER(memcached_st *);
-
-test_return_t test_MEMCACHED_CALLBACK_DELETE_TRIGGER_and_MEMCACHED_BEHAVIOR_NOREPLY(memcached_st *);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- Common include file for libmemached
-*/
-
-#pragma once
-
-#include <mem_config.h>
-
-#ifdef __cplusplus
-# include <cstddef>
-# include <cstdio>
-# include <cstdlib>
-# include <cstring>
-# include <ctime>
-# include <cctype>
-# include <cerrno>
-# include <climits>
-#else
-# ifdef HAVE_STDDEF_H
-# include <stddef.h>
-# endif
-# ifdef HAVE_STDLIB_H
-# include <stdio.h>
-# endif
-# ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-# endif
-# include <string.h>
-# ifdef HAVE_TIME_H
-# include <time.h>
-# endif
-# ifdef HAVE_ERRNO_H
-# include <errno.h>
-# endif
-# ifdef HAVE_LIMITS_H
-# include <limits.h>
-# endif
-#endif
-
-#ifdef HAVE_SYS_UN_H
-# include <sys/un.h>
-#endif
-
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
-
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-
-#ifdef HAVE_DLFCN_H
-# include <dlfcn.h>
-#endif
-
-#if defined(_WIN32)
-# include "libmemcached/windows.hpp"
-#endif
-
-#include <libmemcached-1.0/memcached.h>
-#include "libmemcached/watchpoint.h"
-#include "libmemcached/is.h"
-typedef struct memcached_st Memcached;
-
-#ifdef HAVE_POLL_H
-# include <poll.h>
-#else
-# include "libmemcached/poll.h"
-#endif
-
-#ifdef __cplusplus
-memcached_instance_st* memcached_instance_fetch(memcached_st *ptr, uint32_t server_key);
-#endif
-
-/* These are private not to be installed headers */
-#include "libmemcached/error.hpp"
-#include "libmemcached/memory.h"
-#include "libmemcached/io.h"
-#ifdef __cplusplus
-# include "libmemcached/string.hpp"
-# include "libmemcachedprotocol-0.0/binary.h"
-# include "libmemcached/io.hpp"
-# include "libmemcached/udp.hpp"
-# include "libmemcached/do.hpp"
-# include "libmemcached/socket.hpp"
-# include "libmemcached/connect.hpp"
-# include "libmemcached/allocators.hpp"
-# include "libmemcached/hash.hpp"
-# include "libmemcached/quit.hpp"
-# include "libmemcached/instance.hpp"
-# include "libmemcached/server_instance.h"
-# include "libmemcached/server.hpp"
-# include "libmemcached/flag.hpp"
-# include "libmemcached/behavior.hpp"
-# include "libmemcached/sasl.hpp"
-# include "libmemcached/server_list.hpp"
-#endif
-
-#include "libmemcached/internal.h"
-#include "libmemcached/array.h"
-#include "libmemcached/libmemcached_probes.h"
-#include "libmemcached/byteorder.h"
-#include "libmemcached/initialize_query.h"
-
-#ifdef __cplusplus
-# include "libmemcached/response.h"
-# include "libmemcached/namespace.h"
-#else
-# include "libmemcached/virtual_bucket.h"
-#endif
-
-#ifdef __cplusplus
-# include "libmemcached/backtrace.hpp"
-# include "libmemcached/assert.hpp"
-# include "libmemcached/server.hpp"
-# include "libmemcached/key.hpp"
-# include "libmemcached/encoding_key.h"
-# include "libmemcached/result.h"
-# include "libmemcached/version.hpp"
-#endif
-
-#include "libmemcached/continuum.hpp"
-
-#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
-
-#define likely(x) if((x))
-#define unlikely(x) if((x))
-
-#else
-
-#define likely(x) if(__builtin_expect((x) != 0, 1))
-#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
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-memcached_return_t run_distribution(memcached_st *ptr);
-
-#ifdef __cplusplus
-static inline void memcached_server_response_increment(memcached_instance_st* instance)
-{
- instance->events(POLLIN);
- instance->cursor_active_++;
-}
-#endif
-
-#define memcached_server_response_decrement(A) (A)->cursor_active_--
-#define memcached_server_response_reset(A) (A)->cursor_active_=0
-
-#define memcached_instance_response_increment(A) (A)->cursor_active_++
-#define memcached_instance_response_decrement(A) (A)->cursor_active_--
-#define memcached_instance_response_reset(A) (A)->cursor_active_=0
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-bool memcached_purge(memcached_instance_st*);
-memcached_instance_st* memcached_instance_by_position(const memcached_st *ptr, uint32_t server_key);
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libmemcached/common.h>
-
-#include <cassert>
-
-#ifndef SOCK_CLOEXEC
-# define SOCK_CLOEXEC 0
-#endif
-
-#ifndef SOCK_NONBLOCK
-# define SOCK_NONBLOCK 0
-#endif
-
-#ifndef FD_CLOEXEC
-# define FD_CLOEXEC 0
-#endif
-
-#ifndef SO_NOSIGPIPE
-# define SO_NOSIGPIPE 0
-#endif
-
-#ifndef TCP_NODELAY
-# define TCP_NODELAY 0
-#endif
-
-#ifndef TCP_KEEPIDLE
-# define TCP_KEEPIDLE 0
-#endif
-
-static memcached_return_t connect_poll(memcached_instance_st* server, const int connection_error)
-{
- struct pollfd fds[1];
- fds[0].fd= server->fd;
- fds[0].events= server->events();
- fds[0].revents= 0;
-
- size_t loop_max= 5;
-
- if (server->root->poll_timeout == 0)
- {
- return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT,
- memcached_literal_param("The time to wait for a connection to be established was set to zero which produces a timeout to every call to poll()."));
- }
-
- while (--loop_max) // Should only loop on cases of ERESTART or EINTR
- {
- int number_of;
- if ((number_of= poll(fds, 1, server->root->connect_timeout)) == -1)
- {
- int local_errno= get_socket_errno(); // We cache in case closesocket() modifies errno
- switch (local_errno)
- {
-#ifdef __linux__
- case ERESTART:
-#endif
- case EINTR:
- continue;
-
- case EFAULT:
- case ENOMEM:
- return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
-
- case EINVAL:
- return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid"));
-
- default: // This should not happen
- break;
- }
-
- assert_msg(server->fd != INVALID_SOCKET, "poll() was passed an invalid file descriptor");
- server->reset_socket();
- server->state= MEMCACHED_SERVER_STATE_NEW;
-
- return memcached_set_errno(*server, local_errno, MEMCACHED_AT);
- }
-
- if (number_of == 0)
- {
- if (connection_error == EINPROGRESS)
- {
- int err;
- socklen_t len= sizeof(err);
- if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == -1)
- {
- return memcached_set_errno(*server, errno, MEMCACHED_AT, memcached_literal_param("getsockopt() error'ed while looking for error connect_poll(EINPROGRESS)"));
- }
-
- // If Zero, my hero, we just fail to a generic MEMCACHED_TIMEOUT error
- if (err != 0)
- {
- return memcached_set_errno(*server, err, MEMCACHED_AT, memcached_literal_param("getsockopt() found the error from poll() after connect() returned EINPROGRESS."));
- }
- }
-
- return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_literal_param("(number_of == 0)"));
- }
-
- assert (number_of == 1);
-
- if (fds[0].revents & POLLERR or
- fds[0].revents & POLLHUP or
- fds[0].revents & POLLNVAL)
- {
- int err;
- socklen_t len= sizeof (err);
- if (getsockopt(fds[0].fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == -1)
- {
- return memcached_set_errno(*server, errno, MEMCACHED_AT, memcached_literal_param("getsockopt() errored while looking up error state from poll()"));
- }
-
- // We check the value to see what happened with the socket.
- if (err == 0) // Should not happen
- {
- return MEMCACHED_SUCCESS;
- }
- errno= err;
-
- return memcached_set_errno(*server, err, MEMCACHED_AT, memcached_literal_param("getsockopt() found the error from poll() during connect."));
- }
- assert(fds[0].revents & POLLOUT);
-
- if (fds[0].revents & POLLOUT and connection_error == EINPROGRESS)
- {
- int err;
- socklen_t len= sizeof(err);
- if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == -1)
- {
- return memcached_set_errno(*server, errno, MEMCACHED_AT);
- }
-
- if (err == 0)
- {
- return MEMCACHED_SUCCESS;
- }
-
- return memcached_set_errno(*server, err, MEMCACHED_AT, memcached_literal_param("getsockopt() found the error from poll() after connect() returned EINPROGRESS."));
- }
-
- break; // We only have the loop setup for errno types that require restart
- }
-
- // This should only be possible from ERESTART or EINTR;
- return memcached_set_errno(*server, connection_error, MEMCACHED_AT, memcached_literal_param("connect_poll() was exhausted"));
-}
-
-static memcached_return_t set_hostinfo(memcached_instance_st* server)
-{
- assert(server->type != MEMCACHED_CONNECTION_UNIX_SOCKET);
- server->clear_addrinfo();
-
- char str_port[MEMCACHED_NI_MAXSERV]= { 0 };
- errno= 0;
- int length= snprintf(str_port, MEMCACHED_NI_MAXSERV, "%u", uint32_t(server->port()));
- if (length >= MEMCACHED_NI_MAXSERV or length <= 0 or errno != 0)
- {
- return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(NI_MAXSERV)"));
- }
-
- struct addrinfo hints;
- memset(&hints, 0, sizeof(struct addrinfo));
-
- hints.ai_family= AF_UNSPEC;
- if (memcached_is_udp(server->root))
- {
- hints.ai_protocol= IPPROTO_UDP;
- hints.ai_socktype= SOCK_DGRAM;
- }
- else
- {
- hints.ai_socktype= SOCK_STREAM;
- hints.ai_protocol= IPPROTO_TCP;
- }
-
- assert(server->address_info == NULL);
- assert(server->address_info_next == NULL);
- int errcode;
- assert(server->hostname());
- switch(errcode= getaddrinfo(server->hostname(), str_port, &hints, &server->address_info))
- {
- case 0:
- server->address_info_next= server->address_info;
- server->state= MEMCACHED_SERVER_STATE_ADDRINFO;
- break;
-
- case EAI_AGAIN:
- return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_string_make_from_cstr(gai_strerror(errcode)));
-
- case EAI_SYSTEM:
- server->clear_addrinfo();
- return memcached_set_errno(*server, errno, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_SYSTEM)"));
-
- case EAI_BADFLAGS:
- server->clear_addrinfo();
- return memcached_set_error(*server, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_BADFLAGS)"));
-
- case EAI_MEMORY:
- server->clear_addrinfo();
- return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_MEMORY)"));
-
- default:
- {
- server->clear_addrinfo();
- return memcached_set_error(*server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT, memcached_string_make_from_cstr(gai_strerror(errcode)));
- }
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-static inline void set_socket_nonblocking(memcached_instance_st* server)
-{
-#if defined(_WIN32)
- u_long arg= 1;
- if (ioctlsocket(server->fd, FIONBIO, &arg) == SOCKET_ERROR)
- {
- memcached_set_errno(*server, get_socket_errno(), NULL);
- }
-#else
- int flags;
-
- if (SOCK_NONBLOCK == 0)
- {
- do
- {
- flags= fcntl(server->fd, F_GETFL, 0);
- } while (flags == -1 && (errno == EINTR || errno == EAGAIN));
-
- if (flags == -1)
- {
- memcached_set_errno(*server, errno, NULL);
- }
- else if ((flags & O_NONBLOCK) == 0)
- {
- int rval;
-
- do
- {
- rval= fcntl(server->fd, F_SETFL, flags | O_NONBLOCK);
- } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
-
- if (rval == -1)
- {
- memcached_set_errno(*server, errno, NULL);
- }
- }
- }
-#endif
-}
-
-static bool set_socket_options(memcached_instance_st* server)
-{
- assert_msg(server->fd != INVALID_SOCKET, "invalid socket was passed to set_socket_options()");
-
-#ifdef HAVE_FCNTL
- // If SOCK_CLOEXEC exists then we don't need to call the following
- if (SOCK_CLOEXEC == 0)
- {
- if (FD_CLOEXEC != 0)
- {
- int flags;
- do
- {
- flags= fcntl(server->fd, F_GETFD, 0);
- } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
-
- if (flags != -1)
- {
- int rval;
- do
- {
- rval= fcntl (server->fd, F_SETFD, flags | FD_CLOEXEC);
- } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
- // we currently ignore the case where rval is -1
- }
- }
- }
-#endif
-
- if (memcached_is_udp(server->root))
- {
- return true;
- }
-
-#ifdef HAVE_SNDTIMEO
- if (server->root->snd_timeout > 0)
- {
- struct timeval waittime;
-
- waittime.tv_sec= server->root->snd_timeout / 1000000;
- waittime.tv_usec= server->root->snd_timeout % 1000000;
-
- int error= setsockopt(server->fd, SOL_SOCKET, SO_SNDTIMEO,
- (char*)&waittime, (socklen_t)sizeof(struct timeval));
- (void)error;
- assert(error == 0);
- }
-#endif
-
-#ifdef HAVE_RCVTIMEO
- if (server->root->rcv_timeout > 0)
- {
- struct timeval waittime;
-
- waittime.tv_sec= server->root->rcv_timeout / 1000000;
- waittime.tv_usec= server->root->rcv_timeout % 1000000;
-
- int error= setsockopt(server->fd, SOL_SOCKET, SO_RCVTIMEO,
- (char*)&waittime, (socklen_t)sizeof(struct timeval));
- (void)(error);
- assert(error == 0);
- }
-#endif
-
-
-#if defined(_WIN32)
-#else
-# if defined(SO_NOSIGPIPE)
- if (SO_NOSIGPIPE)
- {
- int set= 1;
- int error= setsockopt(server->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
-
- assert(error == 0);
-
- // This is not considered a fatal error
- if (error == -1)
- {
-#if 0
- perror("setsockopt(SO_NOSIGPIPE)");
-#endif
- }
- }
-# endif // SO_NOSIGPIPE
-#endif // _WIN32
-
- if (server->root->flags.no_block)
- {
- struct linger linger;
-
- linger.l_onoff= 1;
- linger.l_linger= 0; /* By default on close() just drop the socket */
- int error= setsockopt(server->fd, SOL_SOCKET, SO_LINGER,
- (char*)&linger, (socklen_t)sizeof(struct linger));
- (void)(error);
- assert(error == 0);
- }
-
- if (TCP_NODELAY)
- {
- if (server->root->flags.tcp_nodelay)
- {
- int flag= 1;
-
- int error= setsockopt(server->fd, IPPROTO_TCP, TCP_NODELAY,
- (char*)&flag, (socklen_t)sizeof(int));
- (void)(error);
- assert(error == 0);
- }
- }
-
- if (server->root->flags.tcp_keepalive)
- {
- int flag= 1;
-
- int error= setsockopt(server->fd, SOL_SOCKET, SO_KEEPALIVE,
- (char*)&flag, (socklen_t)sizeof(int));
- (void)(error);
- assert(error == 0);
- }
-
- if (TCP_KEEPIDLE)
- {
- if (server->root->tcp_keepidle > 0)
- {
- int error= setsockopt(server->fd, IPPROTO_TCP, TCP_KEEPIDLE,
- (char*)&server->root->tcp_keepidle, (socklen_t)sizeof(int));
- (void)(error);
- assert(error == 0);
- }
- }
-
- if (server->root->send_size > 0)
- {
- int error= setsockopt(server->fd, SOL_SOCKET, SO_SNDBUF,
- (char*)&server->root->send_size, (socklen_t)sizeof(int));
- (void)(error);
- assert(error == 0);
- }
-
- if (server->root->recv_size > 0)
- {
- int error= setsockopt(server->fd, SOL_SOCKET, SO_RCVBUF,
- (char*)&server->root->recv_size, (socklen_t)sizeof(int));
- (void)(error);
- assert(error == 0);
- }
-
- /* libmemcached will always use nonblocking IO to avoid write deadlocks */
- set_socket_nonblocking(server);
-
- return true;
-}
-
-static memcached_return_t unix_socket_connect(memcached_instance_st* server)
-{
-#ifndef _WIN32
- WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
-
- do {
- int type= SOCK_STREAM;
- if (SOCK_CLOEXEC != 0)
- {
- type|= SOCK_CLOEXEC;
- }
-
- if (SOCK_NONBLOCK != 0)
- {
- type|= SOCK_NONBLOCK;
- }
-
- if ((server->fd= socket(AF_UNIX, type, 0)) == -1)
- {
- return memcached_set_errno(*server, errno, NULL);
- }
-
- struct sockaddr_un servAddr;
-
- memset(&servAddr, 0, sizeof (struct sockaddr_un));
- servAddr.sun_family= AF_UNIX;
- if (strlen(server->hostname()) >= sizeof(servAddr.sun_path)) {
- return memcached_set_error(*server, MEMCACHED_UNIX_SOCKET_PATH_TOO_BIG, MEMCACHED_AT);
- }
- strncpy(servAddr.sun_path, server->hostname(), sizeof(servAddr.sun_path)-1); /* Copy filename */
-
- if (connect(server->fd, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1)
- {
- switch (errno)
- {
- case EINPROGRESS:
- case EALREADY:
- case EAGAIN:
- server->events(POLLOUT);
- break;
-
- case EINTR:
- server->reset_socket();
- continue;
-
- case EISCONN: /* We were spinning waiting on connect */
- {
- assert(0); // Programmer error
- server->reset_socket();
- continue;
- }
-
- default:
- WATCHPOINT_ERRNO(errno);
- server->reset_socket();
- return memcached_set_errno(*server, errno, MEMCACHED_AT);
- }
- }
- } while (0);
- server->state= MEMCACHED_SERVER_STATE_CONNECTED;
-
- WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
-
- return MEMCACHED_SUCCESS;
-#else
- (void)server;
- return MEMCACHED_NOT_SUPPORTED;
-#endif
-}
-
-static memcached_return_t network_connect(memcached_instance_st* server)
-{
- bool timeout_error_occured= false;
-
- WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
- WATCHPOINT_ASSERT(server->cursor_active_ == 0);
-
- /*
- We want to check both of these because if address_info_next has been fully tried, we want to do a new lookup to make sure we have picked up on any new DNS information.
- */
- if (server->address_info == NULL or server->address_info_next == NULL)
- {
- WATCHPOINT_ASSERT(server->state == MEMCACHED_SERVER_STATE_NEW);
- server->address_info_next= NULL;
- memcached_return_t rc= set_hostinfo(server);
-
- if (memcached_failed(rc))
- {
- return rc;
- }
- }
-
- assert(server->address_info_next);
- assert(server->address_info);
-
- /* Create the socket */
- while (server->address_info_next and server->fd == INVALID_SOCKET)
- {
- int type= server->address_info_next->ai_socktype;
- if (SOCK_CLOEXEC != 0)
- {
- type|= SOCK_CLOEXEC;
- }
-
- if (SOCK_NONBLOCK != 0)
- {
- type|= SOCK_NONBLOCK;
- }
-
- server->fd= socket(server->address_info_next->ai_family,
- type,
- server->address_info_next->ai_protocol);
-
- if (int(server->fd) == SOCKET_ERROR)
- {
- return memcached_set_errno(*server, get_socket_errno(), NULL);
- }
-
- if (set_socket_options(server) == false)
- {
- server->reset_socket();
- return MEMCACHED_CONNECTION_FAILURE;
- }
-
- /* connect to server */
- if ((connect(server->fd, server->address_info_next->ai_addr, server->address_info_next->ai_addrlen) != SOCKET_ERROR))
- {
- server->state= MEMCACHED_SERVER_STATE_CONNECTED;
- return MEMCACHED_SUCCESS;
- }
-
- /* An error occurred */
- int local_error= get_socket_errno();
- switch (local_error)
- {
- case ETIMEDOUT:
- timeout_error_occured= true;
- break;
-
-#if EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
-#endif
- case EINPROGRESS: // nonblocking mode - first return
- case EALREADY: // nonblocking mode - subsequent returns
- {
- server->events(POLLOUT);
- server->state= MEMCACHED_SERVER_STATE_IN_PROGRESS;
- memcached_return_t rc= connect_poll(server, local_error);
-
- if (memcached_success(rc))
- {
- server->state= MEMCACHED_SERVER_STATE_CONNECTED;
- return MEMCACHED_SUCCESS;
- }
-
- // A timeout here is treated as an error, we will not retry
- if (rc == MEMCACHED_TIMEOUT)
- {
- timeout_error_occured= true;
- }
- }
- break;
-
- case EISCONN: // we are connected :-)
- WATCHPOINT_ASSERT(0); // This is a programmer's error
- break;
-
- case EINTR: // Special case, we retry ai_addr
- WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
- server->reset_socket();
- continue;
-
- case ECONNREFUSED:
- // Probably not running service
-
- default:
- memcached_set_errno(*server, local_error, MEMCACHED_AT);
- break;
- }
-
- WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
- server->reset_socket();
- server->address_info_next= server->address_info_next->ai_next;
- }
-
- WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
-
- if (timeout_error_occured)
- {
- server->reset_socket();
- }
-
- WATCHPOINT_STRING("Never got a good file descriptor");
-
- if (memcached_has_current_error(*server))
- {
- return memcached_instance_error_return(server);
- }
-
- if (timeout_error_occured and server->state < MEMCACHED_SERVER_STATE_IN_PROGRESS)
- {
- return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT,
- memcached_literal_param("if (timeout_error_occured and server->state < MEMCACHED_SERVER_STATE_IN_PROGRESS)"));
- }
-
- return memcached_set_error(*server, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT); /* The last error should be from connect() */
-}
-
-
-/*
- backoff_handling()
-
- Based on time/failure count fail the connect without trying. This prevents waiting in a state where
- we get caught spending cycles just waiting.
-*/
-static memcached_return_t backoff_handling(memcached_instance_st* server, bool& in_timeout)
-{
- struct timeval curr_time;
- bool _gettime_success= (gettimeofday(&curr_time, NULL) == 0);
-
- /*
- If we hit server_failure_limit then something is completely wrong about the server.
-
- 1) If autoeject is enabled we do that.
- 2) If not? We go into timeout again, there is much else to do :(
- */
- if (server->server_failure_counter >= server->root->server_failure_limit)
- {
- /*
- We just auto_eject if we hit this point
- */
- if (_is_auto_eject_host(server->root))
- {
- set_last_disconnected_host(server);
-
- // Retry dead servers if requested
- if (_gettime_success and server->root->dead_timeout > 0)
- {
- server->next_retry= curr_time.tv_sec +server->root->dead_timeout;
-
- // We only retry dead servers once before assuming failure again
- server->server_failure_counter= server->root->server_failure_limit -1;
- }
-
- memcached_return_t rc;
- if (memcached_failed(rc= run_distribution((memcached_st *)server->root)))
- {
- return memcached_set_error(*server, rc, MEMCACHED_AT, memcached_literal_param("Backoff handling failed during run_distribution"));
- }
-
- return memcached_set_error(*server, MEMCACHED_SERVER_MARKED_DEAD, MEMCACHED_AT);
- }
-
- server->state= MEMCACHED_SERVER_STATE_IN_TIMEOUT;
-
- // Sanity check/setting
- if (server->next_retry == 0)
- {
- server->next_retry= 1;
- }
- }
-
- if (server->state == MEMCACHED_SERVER_STATE_IN_TIMEOUT)
- {
- /*
- If next_retry is less then our current time, then we reset and try everything again.
- */
- if (_gettime_success and server->next_retry < curr_time.tv_sec)
- {
- server->state= MEMCACHED_SERVER_STATE_NEW;
- server->server_timeout_counter= 0;
- }
- else
- {
- return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT);
- }
-
- in_timeout= true;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t _memcached_connect(memcached_instance_st* server, const bool set_last_disconnected)
-{
- assert(server);
- if (server->fd != INVALID_SOCKET)
- {
- return MEMCACHED_SUCCESS;
- }
-
- LIBMEMCACHED_MEMCACHED_CONNECT_START();
-
- bool in_timeout= false;
- memcached_return_t rc;
- if (memcached_failed(rc= backoff_handling(server, in_timeout)))
- {
- set_last_disconnected_host(server);
- return rc;
- }
-
- if (LIBMEMCACHED_WITH_SASL_SUPPORT and server->root->sasl.callbacks and memcached_is_udp(server->root))
- {
- return memcached_set_error(*server, MEMCACHED_INVALID_HOST_PROTOCOL, MEMCACHED_AT, memcached_literal_param("SASL is not supported for UDP connections"));
- }
-
- if (server->hostname()[0] == '/')
- {
- server->type= MEMCACHED_CONNECTION_UNIX_SOCKET;
- }
-
- /* We need to clean up the multi startup piece */
- switch (server->type)
- {
- case MEMCACHED_CONNECTION_UDP:
- case MEMCACHED_CONNECTION_TCP:
- rc= network_connect(server);
-
-#if defined(LIBMEMCACHED_WITH_SASL_SUPPORT)
- if (LIBMEMCACHED_WITH_SASL_SUPPORT)
- {
- if (server->fd != INVALID_SOCKET and server->root->sasl.callbacks)
- {
- rc= memcached_sasl_authenticate_connection(server);
- if (memcached_failed(rc) and server->fd != INVALID_SOCKET)
- {
- WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
- server->reset_socket();
- }
- }
- }
-#endif
- break;
-
- case MEMCACHED_CONNECTION_UNIX_SOCKET:
- rc= unix_socket_connect(server);
- break;
- }
-
- if (memcached_success(rc))
- {
- server->mark_server_as_clean();
- memcached_version_instance(server);
- return rc;
- }
- else if (set_last_disconnected)
- {
- set_last_disconnected_host(server);
- if (memcached_has_current_error(*server))
- {
- memcached_mark_server_for_timeout(server);
- assert(memcached_failed(memcached_instance_error_return(server)));
- }
- else
- {
- memcached_set_error(*server, rc, MEMCACHED_AT);
- memcached_mark_server_for_timeout(server);
- }
-
- LIBMEMCACHED_MEMCACHED_CONNECT_END();
-
- if (in_timeout)
- {
- char buffer[1024];
- int snprintf_length= snprintf(buffer, sizeof(buffer), "%s:%d", server->hostname(), int(server->port()));
- return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT, buffer, snprintf_length);
- }
- }
-
- return rc;
-}
-
-memcached_return_t memcached_connect(memcached_instance_st* server)
-{
- return _memcached_connect(server, true);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-memcached_return_t memcached_connect(memcached_instance_st*);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-/* string value */
-struct memcached_continuum_item_st
-{
- uint32_t index;
- uint32_t value;
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Configure Scripting Language
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-#ifndef YY_EXTRA_TYPE
-# define YY_EXTRA_TYPE Context*
-#endif
-
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-# define YY_TYPEDEF_YY_SCANNER_T
-typedef void* yyscan_t;
-#endif
-
-#include <libmemcached/common.h>
-#include <libmemcached/csl/server.h>
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Configure Scripting Language
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/csl/common.h>
-#include <libmemcached/csl/context.h>
-
-void Context::abort(const char *error_arg, config_tokentype last_token, const char *last_token_str)
-{
- rc= MEMCACHED_PARSE_ERROR;
- (void)last_token;
-
- if (error_arg)
- {
- memcached_set_parser_error(*memc, MEMCACHED_AT, "%s", error_arg);
- return;
- }
-
- if (last_token_str)
- {
- memcached_set_parser_error(*memc, MEMCACHED_AT, "%s", last_token_str);
- return;
- }
-
- memcached_set_parser_error(*memc, MEMCACHED_AT, "unknown parsing error");
-}
-
-void Context::error(const char *error_arg, config_tokentype last_token, const char *last_token_str)
-{
- rc= MEMCACHED_PARSE_ERROR;
- if (not error_arg)
- {
- memcached_set_parser_error(*memc, MEMCACHED_AT, "Unknown error occured during parsing (%s)", last_token_str ? last_token_str : " ");
- return;
- }
-
- if (strcmp(error_arg, "memory exhausted") == 0)
- {
- (void)memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_string_make_from_cstr(error_arg));
- return;
- }
-
- // We now test if it is something other then a syntax error, if it we
- // return a generic message
- if (strcmp(error_arg, "syntax error") != 0)
- {
- memcached_set_parser_error(*memc, MEMCACHED_AT, "Error occured during parsing (%s)", error_arg);
- return;
- }
-
- if (last_token == UNKNOWN_OPTION and begin)
- {
- memcached_set_parser_error(*memc, MEMCACHED_AT, "Unknown option: %s", begin);
- }
- else if (last_token == UNKNOWN)
- {
- memcached_set_parser_error(*memc, MEMCACHED_AT, "Error occured durring parsing, an unknown token was found.");
- }
- else
- {
- memcached_set_parser_error(*memc, MEMCACHED_AT, "Error occured while parsing (%s)", last_token_str ? last_token_str : " ");
- }
-}
-
-void Context::hostname(const char *str, size_t size, server_t& server_)
-{
- size_t copy_length= size_t(NI_MAXHOST) > size ? size : size_t(NI_MAXHOST);
- memcpy(_hostname, str, copy_length);
- _hostname[copy_length]= 0;
-
- server_.port= MEMCACHED_DEFAULT_PORT;
- server_.weight= 1;
- server_.c_str= _hostname;
- server_.size= size;
-}
-
-bool Context::string_buffer(const char *str, size_t size, memcached_string_t& string_)
-{
- if (memcached_string_set(_string_buffer, str, size))
- {
- string_.c_str= memcached_string_value(_string_buffer);
- string_.size= memcached_string_length(_string_buffer);
-
- return true;
- }
-
- return false;
-}
-
-bool Context::set_hash(memcached_hash_t hash)
-{
- if (_has_hash)
- {
- return false;
- }
-
- if ((memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, hash)) != MEMCACHED_SUCCESS)
- {
- return false;
- }
-
- return _has_hash= true;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Configure Scripting Language
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include "libmemcached/csl/common.h"
-#include "libmemcached/csl/parser.h"
-
-class Context
-{
-public:
- Context(const char *option_string, size_t option_string_length, memcached_st *memc_,
- memcached_return_t &rc_arg) :
- previous_token(END),
- scanner(NULL),
- buf(option_string),
- begin(NULL),
- pos(0),
- length(option_string_length),
- memc(memc_),
- rc(rc_arg),
- _is_server(false),
- _end(false),
- _has_hash(false)
- {
- _hostname[0]= 0;
- init_scanner();
- rc= MEMCACHED_SUCCESS;
-
- memc->state.is_parsing= true;
- memcached_string_create(memc,
- &_string_buffer,
- 1024);
- }
-
- bool end()
- {
- return _end;
- }
-
- void start();
-
- void set_end()
- {
- rc= MEMCACHED_SUCCESS;
- _end= true;
- }
-
- bool set_hash(memcached_hash_t hash);
-
- void set_server()
- {
- _is_server= true;
- }
-
- void unset_server()
- {
- _is_server= false;
- }
-
- bool is_server() const
- {
- return _is_server;
- }
-
- void hostname(const char*, size_t, server_t&);
-
- bool string_buffer(const char*, size_t, memcached_string_t&);
-
- const char *hostname() const
- {
- return _hostname;
- }
-
- void abort(const char *, config_tokentype, const char *);
- void error(const char *, config_tokentype, const char* );
-
- ~Context()
- {
- memcached_string_free(&_string_buffer);
- destroy_scanner();
- memc->state.is_parsing= false;
- }
-
- config_tokentype previous_token;
- void *scanner;
- const char *buf;
- const char *begin;
- size_t pos;
- size_t length;
- memcached_st *memc;
- memcached_return_t &rc;
-
-protected:
- void init_scanner();
- void destroy_scanner();
-
-private:
- bool _is_server;
- bool _end;
- char _hostname[NI_MAXHOST];
- bool _has_hash;
- memcached_string_st _string_buffer;
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-%{
-
-#include <libmemcached/csl/common.h>
-
-class Context;
-
-%}
-
-%define parse.error verbose
-%define api.pure
-%define api.prefix {config_}
-%define api.value.type {union CONFIG_STYPE}
-%debug
-%defines
-%expect 0
-%lex-param { yyscan_t *scanner }
-%parse-param { class Context *context }
-%parse-param { yyscan_t *scanner }
-%require "2.5"
-%start begin
-%verbose
-
-%{
-
-#include <libmemcached/options.hpp>
-
-#include <libmemcached/csl/context.h>
-#include <libmemcached/csl/symbol.h>
-#include <libmemcached/csl/scanner.h>
-
-#ifndef __INTEL_COMPILER
-# pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-#ifndef __INTEL_COMPILER
-# ifndef __clang__
-# pragma GCC diagnostic ignored "-Wlogical-op"
-# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
-# endif
-#endif
-
-int config_lex(YYSTYPE* lvalp, void* scanner);
-
-#define select_yychar(__context) yychar == UNKNOWN ? ( (__context)->previous_token == END ? UNKNOWN : (__context)->previous_token ) : yychar
-
-#define stryytname(__yytokentype) ((__yytokentype) < YYNTOKENS ) ? yytname[(__yytokentype)] : ""
-
-#define parser_abort(__context, __error_message) do { (__context)->abort((__error_message), config_tokentype(select_yychar(__context)), stryytname(YYTRANSLATE(select_yychar(__context)))); YYABORT; } while (0)
-
-// This is bison calling error.
-inline void __config_error(Context *context, yyscan_t *scanner, const char *error, int last_token, const char *last_token_str)
-{
- if (not context->end())
- {
- context->error(error, config_tokentype(last_token), last_token_str);
- }
- else
- {
- context->error(error, config_tokentype(last_token), last_token_str);
- }
-}
-
-#define config_error(__context, __scanner, __error_msg) do { __config_error((__context), (__scanner), (__error_msg), select_yychar(__context), stryytname(YYTRANSLATE(select_yychar(__context)))); } while (0)
-
-
-%}
-
-%token COMMENT
-%token END
-%token CSL_ERROR
-%token RESET
-%token PARSER_DEBUG
-%token INCLUDE
-%token CONFIGURE_FILE
-%token EMPTY_LINE
-%token SERVER
-%token CSL_SOCKET
-%token SERVERS
-%token SERVERS_OPTION
-%token UNKNOWN_OPTION
-%token UNKNOWN
-
-/* All behavior options */
-%token BINARY_PROTOCOL
-%token BUFFER_REQUESTS
-%token CONNECT_TIMEOUT
-%token DISTRIBUTION
-%token HASH
-%token HASH_WITH_NAMESPACE
-%token IO_BYTES_WATERMARK
-%token IO_KEY_PREFETCH
-%token IO_MSG_WATERMARK
-%token KETAMA_HASH
-%token KETAMA_WEIGHTED
-%token NOREPLY
-%token NUMBER_OF_REPLICAS
-%token POLL_TIMEOUT
-%token RANDOMIZE_REPLICA_READ
-%token RCV_TIMEOUT
-%token REMOVE_FAILED_SERVERS
-%token RETRY_TIMEOUT
-%token SND_TIMEOUT
-%token SOCKET_RECV_SIZE
-%token SOCKET_SEND_SIZE
-%token SORT_HOSTS
-%token SUPPORT_CAS
-%token USER_DATA
-%token USE_UDP
-%token VERIFY_KEY
-%token _TCP_KEEPALIVE
-%token _TCP_KEEPIDLE
-%token _TCP_NODELAY
-%token FETCH_VERSION
-
-/* Callbacks */
-%token NAMESPACE
-
-/* Pool */
-%token POOL_MIN
-%token POOL_MAX
-
-/* Hash types */
-%token MD5
-%token CRC
-%token FNV1_64
-%token FNV1A_64
-%token FNV1_32
-%token FNV1A_32
-%token HSIEH
-%token MURMUR
-%token JENKINS
-
-/* Distributions */
-%token CONSISTENT
-%token MODULA
-%token RANDOM
-
-/* Boolean values */
-%token <boolean> CSL_TRUE
-%token <boolean> CSL_FALSE
-
-%nonassoc ','
-%nonassoc '='
-
-%token <number> CSL_FLOAT
-%token <number> NUMBER
-%token <number> PORT
-%token <number> WEIGHT_START
-%token <server> IPADDRESS
-%token <server> HOSTNAME
-%token <string> STRING
-%token <string> QUOTED_STRING
-%token <string> FILE_PATH
-
-%type <behavior> behavior_boolean
-%type <behavior> behavior_number
-%type <distribution> distribution
-%type <hash> hash
-%type <number> optional_port
-%type <number> optional_weight
-%type <string> string
-
-%%
-
-begin:
- statement
- | begin ' ' statement
- ;
-
-statement:
- expression
- { }
- | COMMENT
- { }
- | EMPTY_LINE
- { }
- | END
- {
- context->set_end();
- YYACCEPT;
- }
- | CSL_ERROR
- {
- context->rc= MEMCACHED_PARSE_USER_ERROR;
- parser_abort(context, "ERROR called directly");
- }
- | RESET
- {
- memcached_reset(context->memc);
- }
- | PARSER_DEBUG
- {
- yydebug= 1;
- }
- | INCLUDE ' ' string
- {
- if ((context->rc= memcached_parse_configure_file(*context->memc, $3.c_str, $3.size)) != MEMCACHED_SUCCESS)
- {
- parser_abort(context, "Failed to parse configuration file");
- }
- }
- ;
-
-
-expression:
- SERVER HOSTNAME optional_port optional_weight
- {
- if (memcached_failed(context->rc= memcached_server_add_with_weight(context->memc, $2.c_str, $3, uint32_t($4))))
- {
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "Failed to add server: %s:%u", $2.c_str, uint32_t($3));
- parser_abort(context, buffer);
- }
- context->unset_server();
- }
- | SERVER IPADDRESS optional_port optional_weight
- {
- if (memcached_failed(context->rc= memcached_server_add_with_weight(context->memc, $2.c_str, $3, uint32_t($4))))
- {
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "Failed to add server: %s:%u", $2.c_str, uint32_t($3));
- parser_abort(context, buffer);
- }
- context->unset_server();
- }
- | CSL_SOCKET string optional_weight
- {
- if (memcached_failed(context->rc= memcached_server_add_unix_socket_with_weight(context->memc, $2.c_str, uint32_t($3))))
- {
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "Failed to add socket: %s", $2.c_str);
- parser_abort(context, buffer);
- }
- }
- | CONFIGURE_FILE string
- {
- memcached_set_configuration_file(context->memc, $2.c_str, $2.size);
- }
- | POOL_MIN NUMBER
- {
- context->memc->configure.initial_pool_size= uint32_t($2);
- }
- | POOL_MAX NUMBER
- {
- context->memc->configure.max_pool_size= uint32_t($2);
- }
- | behaviors
- ;
-
-behaviors:
- NAMESPACE string
- {
- if (memcached_callback_get(context->memc, MEMCACHED_CALLBACK_PREFIX_KEY, NULL))
- {
- parser_abort(context, "--NAMESPACE can only be called once");
- }
-
- if ((context->rc= memcached_set_namespace(*context->memc, $2.c_str, $2.size)) != MEMCACHED_SUCCESS)
- {
- parser_abort(context, memcached_last_error_message(context->memc));
- }
- }
- | FETCH_VERSION
- {
- memcached_flag(*context->memc, MEMCACHED_FLAG_IS_FETCHING_VERSION, true);
- }
- | DISTRIBUTION distribution
- {
- // Check to see if DISTRIBUTION has already been set
- if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $2)) != MEMCACHED_SUCCESS)
- {
- parser_abort(context, "--DISTRIBUTION can only be called once");
- }
-
- if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $2)) != MEMCACHED_SUCCESS)
- {
- parser_abort(context, memcached_last_error_message(context->memc));;
- }
- }
- | DISTRIBUTION distribution ',' hash
- {
- // Check to see if DISTRIBUTION has already been set
- if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $2)) != MEMCACHED_SUCCESS)
- {
- parser_abort(context, "--DISTRIBUTION can only be called once");
- }
-
- if ((context->rc= memcached_behavior_set_distribution_hash(context->memc, $4)) != MEMCACHED_SUCCESS)
- {
- parser_abort(context, "Unable to set the hash for the DISTRIBUTION requested");
- }
- }
- | HASH hash
- {
- if (context->set_hash($2) == false)
- {
- parser_abort(context, "--HASH can only be set once");
- }
- }
- | behavior_number NUMBER
- {
- if ((context->rc= memcached_behavior_set(context->memc, $1, $2)) != MEMCACHED_SUCCESS)
- {
- parser_abort(context, "Unable to set behavior");
- }
- }
- | behavior_boolean
- {
- if ((context->rc= memcached_behavior_set(context->memc, $1, true)) != MEMCACHED_SUCCESS)
- {
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "Could not set: %s", libmemcached_string_behavior($1));
- parser_abort(context, buffer);
- }
- }
- | USER_DATA
- {
- }
- ;
-
-behavior_number:
- REMOVE_FAILED_SERVERS
- {
- $$= MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS;
- }
- | CONNECT_TIMEOUT
- {
- $$= MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT;
- }
- | IO_MSG_WATERMARK
- {
- $$= MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK;
- }
- | IO_BYTES_WATERMARK
- {
- $$= MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK;
- }
- | IO_KEY_PREFETCH
- {
- $$= MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH;
- }
- | NUMBER_OF_REPLICAS
- {
- $$= MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS;
- }
- | POLL_TIMEOUT
- {
- $$= MEMCACHED_BEHAVIOR_POLL_TIMEOUT;
- }
- | RCV_TIMEOUT
- {
- $$= MEMCACHED_BEHAVIOR_RCV_TIMEOUT;
- }
- | RETRY_TIMEOUT
- {
- $$= MEMCACHED_BEHAVIOR_RETRY_TIMEOUT;
- }
- | SND_TIMEOUT
- {
- $$= MEMCACHED_BEHAVIOR_SND_TIMEOUT;
- }
- | SOCKET_RECV_SIZE
- {
- $$= MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE;
- }
- | SOCKET_SEND_SIZE
- {
- $$= MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE;
- }
- ;
-
-behavior_boolean:
- BINARY_PROTOCOL
- {
- $$= MEMCACHED_BEHAVIOR_BINARY_PROTOCOL;
- }
- | BUFFER_REQUESTS
- {
- $$= MEMCACHED_BEHAVIOR_BUFFER_REQUESTS;
- }
- | HASH_WITH_NAMESPACE
- {
- $$= MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY;
- }
- | NOREPLY
- {
- $$= MEMCACHED_BEHAVIOR_NOREPLY;
- }
- | RANDOMIZE_REPLICA_READ
- {
- $$= MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ;
- }
- | SORT_HOSTS
- {
- $$= MEMCACHED_BEHAVIOR_SORT_HOSTS;
- }
- | SUPPORT_CAS
- {
- $$= MEMCACHED_BEHAVIOR_SUPPORT_CAS;
- }
- | _TCP_NODELAY
- {
- $$= MEMCACHED_BEHAVIOR_TCP_NODELAY;
- }
- | _TCP_KEEPALIVE
- {
- $$= MEMCACHED_BEHAVIOR_TCP_KEEPALIVE;
- }
- | _TCP_KEEPIDLE
- {
- $$= MEMCACHED_BEHAVIOR_TCP_KEEPIDLE;
- }
- | USE_UDP
- {
- $$= MEMCACHED_BEHAVIOR_USE_UDP;
- }
- | VERIFY_KEY
- {
- $$= MEMCACHED_BEHAVIOR_VERIFY_KEY;
- }
-
-
-optional_port:
- { $$= MEMCACHED_DEFAULT_PORT;}
- | PORT
- { };
- ;
-
-optional_weight:
- { $$= 1; }
- | WEIGHT_START
- { }
- ;
-
-hash:
- MD5
- {
- $$= MEMCACHED_HASH_MD5;
- }
- | CRC
- {
- $$= MEMCACHED_HASH_CRC;
- }
- | FNV1_64
- {
- $$= MEMCACHED_HASH_FNV1_64;
- }
- | FNV1A_64
- {
- $$= MEMCACHED_HASH_FNV1A_64;
- }
- | FNV1_32
- {
- $$= MEMCACHED_HASH_FNV1_32;
- }
- | FNV1A_32
- {
- $$= MEMCACHED_HASH_FNV1A_32;
- }
- | HSIEH
- {
- $$= MEMCACHED_HASH_HSIEH;
- }
- | MURMUR
- {
- $$= MEMCACHED_HASH_MURMUR;
- }
- | JENKINS
- {
- $$= MEMCACHED_HASH_JENKINS;
- }
- ;
-
-string:
- STRING
- {
- $$= $1;
- }
- | QUOTED_STRING
- {
- $$= $1;
- }
- ;
-
-distribution:
- CONSISTENT
- {
- $$= MEMCACHED_DISTRIBUTION_CONSISTENT;
- }
- | MODULA
- {
- $$= MEMCACHED_DISTRIBUTION_MODULA;
- }
- | RANDOM
- {
- $$= MEMCACHED_DISTRIBUTION_RANDOM;
- }
- ;
-
-%%
-
-void Context::start()
-{
- config_parse(this, (void **)scanner);
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-%top{
-
-#include <libmemcached/csl/common.h>
-#include <libmemcached/csl/context.h>
-#include <libmemcached/csl/parser.h>
-#include <libmemcached/csl/symbol.h>
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#pragma GCC diagnostic ignored "-Wsign-compare"
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#pragma GCC diagnostic ignored "-Wmissing-declarations"
-#pragma GCC diagnostic ignored "-Wunused-result"
-#pragma GCC diagnostic ignored "-Wmissing-noreturn"
-#endif
-
-#ifdef __clang__
-#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
-#endif
-
-#ifndef __INTEL_COMPILER
-#ifndef __clang__
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
-#endif
-
-}
-
-
-%{
-#define PARAM yyget_extra(yyscanner)
-
-#define get_lex_chars(buffer, result, max_size, context) \
-{ \
- if (context->pos >= context->length) \
- { \
- result= YY_NULL; \
- } \
- else \
- { \
- result= (int)(context->length - context->pos); \
- (size_t)result > (size_t)max_size ? result= max_size : 0; \
- memcpy(buffer, context->buf + context->pos, result); \
- context->pos += result; \
- } \
-}
-
-#define YY_FATAL_ERROR(msg) \
-{ \
-}
-
-#define YYSTYPE CONFIG_STYPE
-
-#define YY_INPUT(buffer, result, max_size) get_lex_chars(buffer, result, max_size, PARAM)
-
-%}
-
-%option nostdinit
-%option 8bit
-%option warn
-%option bison-bridge
-%option never-interactive
-%option case-insensitive
-%option nodefault
-%option noinput
-%option nounput
-%option noyywrap
-%option perf-report
-%option prefix="config_"
-%option reentrant
-
-%%
-
-
-=|,|[ ] { return yytext[0];}
-
-[[:digit:]]+ { yylval->number= atoi(yytext); return (NUMBER); }
-
-:[[:digit:]]{1,5} { yylval->number= atoi(yytext +1); return PORT; }
-
-"/?"[[:digit:]]{1,5} { yylval->number= atoi(yytext +2); return WEIGHT_START; }
-
-[\t\r\n] ; /* skip whitespace */
-
-
-^#.*$ {
- return COMMENT;
- }
-
-"--SERVER=" { yyextra->begin= yytext; yyextra->set_server(); return yyextra->previous_token= SERVER; }
-
-"--SOCKET=" { yyextra->begin= yytext; return yyextra->previous_token= CSL_SOCKET; }
-
-"--BINARY-PROTOCOL" { yyextra->begin= yytext; return yyextra->previous_token= BINARY_PROTOCOL; }
-"--BUFFER-REQUESTS" { yyextra->begin= yytext; return yyextra->previous_token= BUFFER_REQUESTS; }
-"--CONFIGURE-FILE=" { yyextra->begin= yytext; return yyextra->previous_token= CONFIGURE_FILE; }
-"--CONNECT-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= CONNECT_TIMEOUT; }
-"--DISTRIBUTION=" { yyextra->begin= yytext; return yyextra->previous_token= DISTRIBUTION; }
-"--HASH-WITH-NAMESPACE" { yyextra->begin= yytext; return yyextra->previous_token= HASH_WITH_NAMESPACE; }
-"--HASH=" { yyextra->begin= yytext; return yyextra->previous_token= HASH; }
-"--IO-BYTES-WATERMARK=" { yyextra->begin= yytext; return yyextra->previous_token= IO_BYTES_WATERMARK; }
-"--IO-KEY-PREFETCH=" { yyextra->begin= yytext; return yyextra->previous_token= IO_KEY_PREFETCH; }
-"--IO-MSG-WATERMARK=" { yyextra->begin= yytext; return yyextra->previous_token= IO_MSG_WATERMARK; }
-"--NOREPLY" { yyextra->begin= yytext; return yyextra->previous_token= NOREPLY; }
-"--NUMBER-OF-REPLICAS=" { yyextra->begin= yytext; return yyextra->previous_token= NUMBER_OF_REPLICAS; }
-"--POLL-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= POLL_TIMEOUT; }
-"--RANDOMIZE-REPLICA-READ" { yyextra->begin= yytext; return yyextra->previous_token= RANDOMIZE_REPLICA_READ; }
-"--RCV-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= RCV_TIMEOUT; }
-"--REMOVE-FAILED-SERVERS=" { yyextra->begin= yytext; return yyextra->previous_token= REMOVE_FAILED_SERVERS; }
-"--RETRY-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= RETRY_TIMEOUT; }
-"--SND-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= SND_TIMEOUT; }
-"--SOCKET-RECV-SIZE=" { yyextra->begin= yytext; return yyextra->previous_token= SOCKET_RECV_SIZE; }
-"--SOCKET-SEND-SIZE=" { yyextra->begin= yytext; return yyextra->previous_token= SOCKET_SEND_SIZE; }
-"--SORT-HOSTS" { yyextra->begin= yytext; return yyextra->previous_token= SORT_HOSTS; }
-"--SUPPORT-CAS" { yyextra->begin= yytext; return yyextra->previous_token= SUPPORT_CAS; }
-"--TCP-KEEPALIVE" { yyextra->begin= yytext; return yyextra->previous_token= _TCP_KEEPALIVE; }
-"--TCP-KEEPIDLE" { yyextra->begin= yytext; return yyextra->previous_token= _TCP_KEEPIDLE; }
-"--TCP-NODELAY" { yyextra->begin= yytext; return yyextra->previous_token= _TCP_NODELAY; }
-"--USE-UDP" { yyextra->begin= yytext; return yyextra->previous_token= USE_UDP; }
-"--USER-DATA" { yyextra->begin= yytext; return yyextra->previous_token= USER_DATA; }
-"--VERIFY-KEY" { yyextra->begin= yytext; return yyextra->previous_token= VERIFY_KEY; }
-
-"--POOL-MIN=" { yyextra->begin= yytext; return yyextra->previous_token= POOL_MIN; }
-"--POOL-MAX=" { yyextra->begin= yytext; return yyextra->previous_token= POOL_MAX; }
-
-"--NAMESPACE=" { yyextra->begin= yytext; return yyextra->previous_token= NAMESPACE; }
-
-"--FETCH-VERSION" { yyextra->begin= yytext; return yyextra->previous_token= FETCH_VERSION; }
-
-INCLUDE { yyextra->begin= yytext; return yyextra->previous_token= INCLUDE; }
-RESET { yyextra->begin= yytext; return yyextra->previous_token= RESET; }
-DEBUG { yyextra->begin= yytext; return yyextra->previous_token= PARSER_DEBUG; }
-SERVERS { yyextra->begin= yytext; return yyextra->previous_token= SERVERS; }
-END { yyextra->begin= yytext; return yyextra->previous_token= END; }
-CSL_ERROR { yyextra->begin= yytext; return yyextra->previous_token= CSL_ERROR; }
-
-TRUE { return yyextra->previous_token= CSL_TRUE; }
-FALSE { return yyextra->previous_token= CSL_FALSE; }
-
-
-"--"[[:alnum:]]* {
- yyextra->begin= yytext;
- return UNKNOWN_OPTION;
- }
-
-CONSISTENT { return CONSISTENT; }
-MODULA { return MODULA; }
-RANDOM { return RANDOM; }
-
-MD5 { return MD5; }
-CRC { return CRC; }
-FNV1_64 { return FNV1_64; }
-FNV1A_64 { return FNV1A_64; }
-FNV1_32 { return FNV1_32; }
-FNV1A_32 { return FNV1A_32; }
-HSIEH { return HSIEH; }
-MURMUR { return MURMUR; }
-JENKINS { return JENKINS; }
-
-(([[:digit:]]{1,3}"."){3}([[:digit:]]{1,3})) {
- yyextra->hostname(yytext, yyleng, yylval->server);
- return IPADDRESS;
- }
-
-[[:alnum:]]["."[:alnum:]_-]+[[:alnum:]] {
- if (yyextra->is_server())
- {
- yyextra->hostname(yytext, yyleng, yylval->server);
-
- return HOSTNAME;
- }
-
- yyextra->string_buffer(yytext, yyleng, yylval->string);
-
- return STRING;
- }
-
-L?\"(\\.|[^\\"])*\" {
- yyget_text(yyscanner)[yyleng -1]= 0;
- yyextra->string_buffer(yytext +1, yyleng -2, yylval->string);
- return QUOTED_STRING;
- }
-
-. {
- yyextra->begin= yytext;
- return UNKNOWN;
- }
-
-%%
-
-void Context::init_scanner()
-{
- yylex_init(&scanner);
- yyset_extra(this, scanner);
-}
-
-void Context::destroy_scanner()
-{
- (void)yy_fatal_error; // Removes warning about unused yy_fatal_error()
- yylex_destroy(scanner);
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Configure Scripting Language
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <cstdlib>
-
-#ifdef HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#endif
-
-struct server_t
-{
- const char *c_str;
- size_t size;
- in_port_t port;
- uint32_t weight;
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Configure Scripting Language
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libmemcached/csl/common.h>
-
-union CONFIG_STYPE
-{
- long long number;
- memcached_string_t string;
- memcached_string_t option;
- double double_number;
- memcached_server_distribution_t distribution;
- memcached_hash_t hash;
- memcached_behavior_t behavior;
- bool boolean;
- server_t server;
-};
-
-typedef union CONFIG_STYPE CONFIG_STYPE;
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-memcached_return_t memcached_delete(memcached_st *shell, const char *key, size_t key_length,
- time_t expiration)
-{
- return memcached_delete_by_key(shell, key, key_length, key, key_length, expiration);
-}
-
-static inline memcached_return_t ascii_delete(memcached_instance_st* instance,
- uint32_t ,
- const char *key,
- const size_t key_length,
- const bool reply,
- const bool is_buffering)
-{
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { memcached_literal_param("delete ") },
- { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
- { key, key_length },
- { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
- { memcached_literal_param("\r\n") }
- };
-
- /* Send command header, only flush if we are NOT buffering */
- return memcached_vdo(instance, vector, 6, is_buffering ? false : true);
-}
-
-static inline memcached_return_t binary_delete(memcached_instance_st* instance,
- uint32_t server_key,
- const char *key,
- const size_t key_length,
- const bool reply,
- const bool is_buffering)
-{
- protocol_binary_request_delete request= {};
-
- bool should_flush= is_buffering ? false : true;
-
- initialize_binary_request(instance, request.message.header);
-
- if (reply)
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
- }
- else
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
- }
- request.message.header.request.keylen= htons(uint16_t(key_length + memcached_array_size(instance->root->_namespace)));
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl(uint32_t(key_length + memcached_array_size(instance->root->_namespace)));
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { request.bytes, sizeof(request.bytes) },
- { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
- { key, key_length }
- };
-
- memcached_return_t rc= memcached_vdo(instance, vector, 4, should_flush);
-
- if (memcached_has_replicas(instance))
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
-
- for (uint32_t x= 0; x < memcached_has_replicas(instance); ++x)
- {
- ++server_key;
-
- if (server_key == memcached_server_count(instance->root))
- {
- server_key= 0;
- }
-
- memcached_instance_st* replica= memcached_instance_fetch(instance->root, server_key);
-
- if (memcached_success(memcached_vdo(replica, vector, 4, should_flush)))
- {
- memcached_server_response_decrement(replica);
- }
- }
- }
-
- return rc;
-}
-
-memcached_return_t memcached_delete_by_key(memcached_st *shell,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- time_t expiration)
-{
- Memcached* memc= memcached2Memcached(shell);
- LIBMEMCACHED_MEMCACHED_DELETE_START();
-
- memcached_return_t rc;
- if (memcached_fatal(rc= initialize_query(memc, true)))
- {
- return rc;
- }
-
- if (memcached_fatal(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
- {
- return memcached_last_error(memc);
- }
-
- if (expiration)
- {
- return memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("Memcached server version does not allow expiration of deleted items"));
- }
-
- uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
- memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
-
- bool is_buffering= memcached_is_buffering(instance->root);
- bool is_replying= memcached_is_replying(instance->root);
-
- // If a delete trigger exists, we need a response, so no buffering/noreply
- if (memc->delete_trigger)
- {
- if (is_buffering)
- {
- return memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("Delete triggers cannot be used if buffering is enabled"));
- }
-
- if (is_replying == false)
- {
- return memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("Delete triggers cannot be used if MEMCACHED_BEHAVIOR_NOREPLY is set"));
- }
- }
-
- if (memcached_is_binary(memc))
- {
- rc= binary_delete(instance, server_key, key, key_length, is_replying, is_buffering);
- }
- else
- {
- rc= ascii_delete(instance, server_key, key, key_length, is_replying, is_buffering);
- }
-
- if (rc == MEMCACHED_SUCCESS)
- {
- if (is_buffering == true)
- {
- rc= MEMCACHED_BUFFERED;
- }
- else if (is_replying == false)
- {
- rc= MEMCACHED_SUCCESS;
- }
- else
- {
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
- if (rc == MEMCACHED_DELETED)
- {
- rc= MEMCACHED_SUCCESS;
- if (memc->delete_trigger)
- {
- memc->delete_trigger(memc, key, key_length);
- }
- }
- }
- }
-
- LIBMEMCACHED_MEMCACHED_DELETE_END();
- return rc;
-}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-#include <libmemcached/common.h>
-
-static memcached_return_t _vdo_udp(memcached_instance_st* instance,
- libmemcached_io_vector_st vector[],
- const size_t count)
-{
-#ifndef __MINGW32__
- if (vector[0].buffer or vector[0].length)
- {
- return memcached_set_error(*instance->root, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
- memcached_literal_param("UDP messages was attempted, but vector was not setup for it"));
- }
-
- struct msghdr msg;
- memset(&msg, 0, sizeof(msg));
-
- increment_udp_message_id(instance);
- vector[0].buffer= instance->write_buffer;
- vector[0].length= UDP_DATAGRAM_HEADER_LENGTH;
-
- msg.msg_iov= (struct iovec*)vector;
-#ifdef __APPLE__
- msg.msg_iovlen= int(count);
-#else
- msg.msg_iovlen= count;
-#endif
-
- uint32_t retry= 5;
- while (--retry)
- {
- ssize_t sendmsg_length= ::sendmsg(instance->fd, &msg, 0);
- if (sendmsg_length > 0)
- {
- break;
- }
- else if (sendmsg_length < 0)
- {
- if (errno == EMSGSIZE)
- {
- return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
- }
-
- return memcached_set_errno(*instance, errno, MEMCACHED_AT);
- }
- }
-
- return MEMCACHED_SUCCESS;
-#else
- (void)instance;
- (void)vector;
- (void)count;
- return MEMCACHED_FAILURE;
-#endif
-}
-
-memcached_return_t memcached_vdo(memcached_instance_st* instance,
- libmemcached_io_vector_st vector[],
- const size_t count,
- const bool with_flush)
-{
- memcached_return_t rc;
-
- assert_msg(vector, "Invalid vector passed");
-
- if (memcached_failed(rc= memcached_connect(instance)))
- {
- WATCHPOINT_ERROR(rc);
- assert_msg(instance->error_messages, "memcached_connect() returned an error but the Instance showed none.");
- 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.
- **/
- bool sent_success;
- if (memcached_is_udp(instance->root))
- {
- sent_success= memcached_success(rc= _vdo_udp(instance, vector, count));
- } else {
- sent_success= memcached_io_writev(instance, vector, count, with_flush);
- }
- if (sent_success == false)
- {
- rc= memcached_last_error(instance->root);
- if (rc == MEMCACHED_SUCCESS)
- {
- memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
- }
- memcached_io_reset(instance);
- }
- else if (memcached_is_replying(instance->root) && !memcached_is_udp(instance->root))
- {
- memcached_server_response_increment(instance);
- }
-
- return rc;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-memcached_return_t memcached_vdo(memcached_instance_st*,
- libmemcached_io_vector_st vector[],
- const size_t count,
- const bool with_flush);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- 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 <libmemcached/common.h>
-
-static memcached_return_t ascii_dump(Memcached *memc, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
-{
- memcached_version(memc);
- /* MAX_NUMBER_OF_SLAB_CLASSES is defined to 200 in Memcached 1.4.10 */
- for (uint32_t x= 0; x < 200; x++)
- {
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- int buffer_length= snprintf(buffer, sizeof(buffer), "%u", x);
- if (size_t(buffer_length) >= sizeof(buffer) or buffer_length < 0)
- {
- return memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
- }
-
- // @NOTE the hard coded zero means "no limit"
- libmemcached_io_vector_st vector[]=
- {
- { memcached_literal_param("stats cachedump ") },
- { buffer, size_t(buffer_length) },
- { memcached_literal_param(" 0\r\n") }
- };
-
- // Send message to all servers
- for (uint32_t server_key= 0; server_key < memcached_server_count(memc); server_key++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
-
- // skip slabs >63 for server versions >= 1.4.23
- if (x < 64 || memcached_version_instance_cmp(instance, 1, 4, 23) < 0) {
- memcached_return_t vdo_rc;
- if (memcached_failed((vdo_rc= memcached_vdo(instance, vector, 3, true))))
- {
- return vdo_rc;
- }
- }
- }
-
- // Collect the returned items
- memcached_instance_st* instance;
- memcached_return_t read_ret= MEMCACHED_SUCCESS;
- while ((instance= memcached_io_get_readable_server(memc, read_ret)))
- {
- memcached_return_t response_rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
- if (response_rc == MEMCACHED_ITEM)
- {
- char *string_ptr, *end_ptr;
-
- string_ptr= buffer;
- string_ptr+= 5; /* Move past ITEM */
-
- for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++) {} ;
-
- char *key= string_ptr;
- key[(size_t)(end_ptr-string_ptr)]= 0;
-
- for (uint32_t callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++)
- {
- memcached_return_t callback_rc= (*callback[callback_counter])(memc, key, (size_t)(end_ptr-string_ptr), context);
- if (callback_rc != MEMCACHED_SUCCESS)
- {
- // @todo build up a message for the error from the value
- memcached_set_error(*instance, callback_rc, MEMCACHED_AT);
- break;
- }
- }
- }
- else if (response_rc == MEMCACHED_END)
- {
- // All items have been returned
- }
- else if (response_rc == MEMCACHED_SERVER_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.
- */
- assert(response_rc == MEMCACHED_SUCCESS); // Just fail
- return response_rc;
- }
- else if (response_rc == MEMCACHED_CLIENT_ERROR)
- {
- /* The maximum number of slabs has changed in the past (currently 1<<6-1),
- * so ignore any client errors complaining about an illegal slab id.
- */
- if (0 == strncmp(buffer, "CLIENT_ERROR Illegal slab id", sizeof("CLIENT_ERROR Illegal slab id") - 1)) {
- memcached_error_free(*instance);
- memcached_error_free(*memc);
- } else {
- return response_rc;
- }
- }
- else
- {
- // IO error of some sort must have occurred
- return response_rc;
- }
- }
- }
-
- return memcached_has_current_error(*memc) ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_dump(memcached_st *shell, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
-{
- Memcached* ptr= memcached2Memcached(shell);
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(ptr, true)))
- {
- return rc;
- }
-
- /*
- No support for Binary protocol yet
- @todo Fix this so that we just flush, switch to ascii, and then go back to binary.
- */
- if (memcached_is_binary(ptr))
- {
- return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT, memcached_literal_param("Binary protocol is not supported for memcached_dump()"));
- }
-
- return ascii_dump(ptr, callback, context, number_of_callbacks);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-#include <libmemcached/assert.hpp>
-
-static void _set_encoding_key(Memcached& memc, const char *key, size_t key_length)
-{
- hashkit_key(&memc.hashkit, key, key_length);
-}
-
-memcached_return_t memcached_set_encoding_key(memcached_st* shell, const char *key, size_t key_length)
-{
- Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- _set_encoding_key(*memc, key, key_length);
- return MEMCACHED_SUCCESS;
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- memcached_string_t memcached_encoding_key(Memcached&);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-#include "libmemcached/assert.hpp"
-
-#include <cerrno>
-#include <cstdarg>
-#include <cstdio>
-
-#define MAX_ERROR_LENGTH 2048
-struct memcached_error_t
-{
- Memcached *root;
- uint64_t query_id;
- struct memcached_error_t *next;
- memcached_return_t rc;
- int local_errno;
- size_t size;
- char message[MAX_ERROR_LENGTH];
-};
-
-static void _set(memcached_instance_st& server, Memcached& memc)
-{
- if (server.error_messages and server.error_messages->query_id != server.root->query_id)
- {
- memcached_error_free(server);
- }
-
- if (memc.error_messages)
- {
- if (memc.error_messages->rc == MEMCACHED_TIMEOUT)
- {
- server.io_wait_count.timeouts++;
- }
-
- memcached_error_t *error= libmemcached_xmalloc(&memc, memcached_error_t);
- if (error)
- {
- memcpy(error, memc.error_messages, sizeof(memcached_error_t));
- error->next= server.error_messages;
- server.error_messages= error;
- }
- }
-}
-
-#if 0
-static int error_log_fd= -1;
-#endif
-
-static void _set(Memcached& memc, memcached_string_t *str, memcached_return_t &rc, const char *at, int local_errno= 0)
-{
- if (memc.error_messages && memc.error_messages->query_id != memc.query_id)
- {
- memcached_error_free(memc);
- }
-
- if (memcached_fatal(rc) or rc == MEMCACHED_CLIENT_ERROR)
- {
- // For memory allocation we use our error since it is a bit more specific
- if (local_errno == ENOMEM and rc == MEMCACHED_ERRNO)
- {
- rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
- {
- local_errno= ENOMEM;
- }
-
- if (rc == MEMCACHED_ERRNO and not local_errno)
- {
- local_errno= errno;
- rc= MEMCACHED_ERRNO;
- }
-
- if (rc == MEMCACHED_ERRNO and local_errno == ENOTCONN)
- {
- rc= MEMCACHED_CONNECTION_FAILURE;
- }
-
- if (rc == MEMCACHED_ERRNO and local_errno == ECONNRESET)
- {
- rc= MEMCACHED_CONNECTION_FAILURE;
- }
-
- if (local_errno == EINVAL)
- {
- rc= MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (local_errno == ECONNREFUSED)
- {
- rc= MEMCACHED_CONNECTION_FAILURE;
- }
-
- if (rc == MEMCACHED_TIMEOUT)
- {
- }
-
- memcached_error_t *error= libmemcached_xmalloc(&memc, memcached_error_t);
- if (error == NULL) // Bad business if this happens
- {
- assert_msg(error, "libmemcached_xmalloc() failed to allocate a memcached_error_t");
- return;
- }
-
- error->root= &memc;
- error->query_id= memc.query_id;
- error->rc= rc;
- error->local_errno= local_errno;
-
- // MEMCACHED_CLIENT_ERROR is a special case because it is an error coming from the server
- if (rc == MEMCACHED_CLIENT_ERROR)
- {
- assert(str);
- assert(str->size);
- if (str and str->size)
- {
- assert(error->local_errno == 0);
- error->local_errno= 0;
-
- error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %.*s",
- error->root,
- int(str->size), str->c_str);
- }
- }
- else if (local_errno)
- {
- const char *errmsg_ptr;
- char errmsg[MAX_ERROR_LENGTH];
- errmsg[0]= 0;
- errmsg_ptr= errmsg;
-
-#if defined(STRERROR_R_CHAR_P) && STRERROR_R_CHAR_P
- errmsg_ptr= strerror_r(local_errno, errmsg, sizeof(errmsg));
-#elif defined(HAVE_STRERROR_R) && HAVE_STRERROR_R
- strerror_r(local_errno, errmsg, sizeof(errmsg));
- errmsg_ptr= errmsg;
-#elif defined(HAVE_STRERROR) && HAVE_STRERROR
- snprintf(errmsg, sizeof(errmsg), "%s", strerror(local_errno));
- errmsg_ptr= errmsg;
-#endif
-
- if (str and str->size and local_errno)
- {
- error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s), %.*s -> %s",
- error->root,
- memcached_strerror(&memc, rc),
- errmsg_ptr,
- memcached_string_printf(*str), at);
- }
- else
- {
- error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s) -> %s",
- error->root,
- memcached_strerror(&memc, rc),
- errmsg_ptr,
- at);
- }
- }
- else if (rc == MEMCACHED_PARSE_ERROR and str and str->size)
- {
- error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %.*s -> %s",
- error->root,
- int(str->size), str->c_str, at);
- }
- else if (str and str->size)
- {
- error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s, %.*s -> %s",
- error->root,
- memcached_strerror(&memc, rc),
- int(str->size), str->c_str, at);
- }
- else
- {
- error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s -> %s",
- error->root,
- memcached_strerror(&memc, rc), at);
- }
-
- error->next= memc.error_messages;
- memc.error_messages= error;
-#if 0
- if (error_log_fd == -1)
- {
- // unlink("/tmp/libmemcachd.log");
- if ((error_log_fd= open("/tmp/libmemcachd.log", O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0)
- {
- perror("open");
- error_log_fd= -1;
- }
- }
- ::write(error_log_fd, error->message, error->size);
- ::write(error_log_fd, "\n", 1);
-#endif
- }
-}
-
-memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, const char *str, size_t length)
-{
- assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
- memcached_string_t tmp= { str, length };
- return memcached_set_error(memc, rc, at, tmp);
-}
-
-memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at, const char *str, size_t length)
-{
- assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
- assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a Instance");
-
- memcached_string_t tmp= { str, length };
- return memcached_set_error(self, rc, at, tmp);
-}
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-#endif
-
-memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, memcached_string_t& str)
-{
- assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
- if (memcached_fatal(rc))
- {
- _set(memc, &str, rc, at);
- }
-
- return rc;
-}
-
-memcached_return_t memcached_set_parser_error(Memcached& memc,
- const char *at,
- const char *format, ...)
-{
- va_list args;
-
- char buffer[BUFSIZ];
- va_start(args, format);
- int length= vsnprintf(buffer, sizeof(buffer), format, args);
- va_end(args);
-
- return memcached_set_error(memc, MEMCACHED_PARSE_ERROR, at, buffer, length);
-}
-
-static inline size_t append_host_to_string(memcached_instance_st& self, char* buffer, const size_t buffer_length)
-{
- size_t size= 0;
- switch (self.type)
- {
- case MEMCACHED_CONNECTION_TCP:
- case MEMCACHED_CONNECTION_UDP:
- size+= snprintf(buffer, buffer_length, " host: %s:%d",
- self.hostname(), int(self.port()));
- break;
-
- case MEMCACHED_CONNECTION_UNIX_SOCKET:
- size+= snprintf(buffer, buffer_length, " socket: %s",
- self.hostname());
- break;
- }
-
- return size;
-}
-
-memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at, memcached_string_t& str)
-{
- assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
- assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
- if (memcached_fatal(rc) == false and rc != MEMCACHED_CLIENT_ERROR)
- {
- return rc;
- }
-
- char hostname_port_message[MAX_ERROR_LENGTH];
- char* hostname_port_message_ptr= hostname_port_message;
- int size= 0;
- if (str.size)
- {
- size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ",
- memcached_string_printf(str));
- hostname_port_message_ptr+= size;
- }
-
- size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
-
- memcached_string_t error_host= { hostname_port_message, size_t(size) };
-
- assert_msg(self.root, "Programmer error, root was not set on instance");
- if (self.root)
- {
- _set(*self.root, &error_host, rc, at);
- _set(self, (*self.root));
- assert(self.error_messages);
- assert(self.root->error_messages);
- assert(self.error_messages->rc == self.root->error_messages->rc);
- }
-
- return rc;
-}
-
-memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at)
-{
- assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
- if (memcached_fatal(rc) == false)
- {
- return rc;
- }
-
- char hostname_port[MEMCACHED_NI_MAXHOST +MEMCACHED_NI_MAXSERV + sizeof("host : ")];
- size_t size= append_host_to_string(self, hostname_port, sizeof(hostname_port));
-
- memcached_string_t error_host= { hostname_port, size};
-
- if (self.root)
- {
- _set(*self.root, &error_host, rc, at);
- _set(self, *self.root);
- }
-
- return rc;
-}
-
-memcached_return_t memcached_set_error(Memcached& self, memcached_return_t rc, const char *at)
-{
- assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
- if (memcached_fatal(rc) == false)
- {
- return rc;
- }
-
- _set(self, NULL, rc, at);
-
- return rc;
-}
-
-memcached_return_t memcached_set_errno(Memcached& self, int local_errno, const char *at, const char *str, size_t length)
-{
- memcached_string_t tmp= { str, length };
- return memcached_set_errno(self, local_errno, at, tmp);
-}
-
-memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at, const char *str, size_t length)
-{
- memcached_string_t tmp= { str, length };
- return memcached_set_errno(self, local_errno, at, tmp);
-}
-
-memcached_return_t memcached_set_errno(Memcached& self, int local_errno, const char *at)
-{
- if (local_errno == 0)
- {
- return MEMCACHED_SUCCESS;
- }
-
- memcached_return_t rc= MEMCACHED_ERRNO;
- _set(self, NULL, rc, at, local_errno);
-
- return rc;
-}
-
-memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at, memcached_string_t& str)
-{
- if (local_errno == 0)
- {
- return MEMCACHED_SUCCESS;
- }
-
- memcached_return_t rc= MEMCACHED_ERRNO;
- _set(memc, &str, rc, at, local_errno);
-
- return rc;
-}
-
-memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at, memcached_string_t& str)
-{
- if (local_errno == 0)
- {
- return MEMCACHED_SUCCESS;
- }
-
- char hostname_port_message[MAX_ERROR_LENGTH];
- char* hostname_port_message_ptr= hostname_port_message;
- size_t size= 0;
- if (str.size)
- {
- size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ", memcached_string_printf(str));
- }
- size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
-
- memcached_string_t error_host= { hostname_port_message, size };
-
- memcached_return_t rc= MEMCACHED_ERRNO;
- if (self.root == NULL)
- {
- return rc;
- }
-
- _set(*self.root, &error_host, rc, at, local_errno);
- _set(self, (*self.root));
-
-#if 0
- if (self.root->error_messages->rc != self.error_messages->rc)
- {
- fprintf(stderr, "%s:%d %s != %s\n", __FILE__, __LINE__,
- memcached_strerror(NULL, self.root->error_messages->rc),
- memcached_strerror(NULL, self.error_messages->rc));
- }
-#endif
-
- return rc;
-}
-
-memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at)
-{
- if (local_errno == 0)
- {
- return MEMCACHED_SUCCESS;
- }
-
- char hostname_port_message[MAX_ERROR_LENGTH];
- size_t size= append_host_to_string(self, hostname_port_message, sizeof(hostname_port_message));
-
- memcached_string_t error_host= { hostname_port_message, size };
-
- memcached_return_t rc= MEMCACHED_ERRNO;
- if (self.root == NULL)
- {
- return rc;
- }
-
- _set(*self.root, &error_host, rc, at, local_errno);
- _set(self, (*self.root));
-
- return rc;
-}
-
-static void _error_print(const memcached_error_t *error)
-{
- if (error == NULL)
- {
- return;
- }
-
- if (error->size == 0)
- {
- fprintf(stderr, "\t%s\n", memcached_strerror(NULL, error->rc) );
- }
- else
- {
- fprintf(stderr, "\t%s %s\n", memcached_strerror(NULL, error->rc), error->message);
- }
-
- _error_print(error->next);
-}
-
-void memcached_error_print(const Memcached *shell)
-{
- const Memcached* self= memcached2Memcached(shell);
- if (self == NULL)
- {
- return;
- }
-
- _error_print(self->error_messages);
-
- for (uint32_t x= 0; x < memcached_server_count(self); x++)
- {
- memcached_instance_st* instance= memcached_instance_by_position(self, x);
-
- _error_print(instance->error_messages);
- }
-}
-
-static void _error_free(memcached_error_t *error)
-{
- if (error)
- {
- _error_free(error->next);
-
- libmemcached_free(error->root, error);
- }
-}
-
-void memcached_error_free(Memcached& self)
-{
- _error_free(self.error_messages);
- self.error_messages= NULL;
-}
-
-void memcached_error_free(memcached_instance_st& self)
-{
- _error_free(self.error_messages);
- self.error_messages= NULL;
-}
-
-void memcached_error_free(memcached_server_st& self)
-{
- _error_free(self.error_messages);
- self.error_messages= NULL;
-}
-
-const char *memcached_error(const memcached_st *memc)
-{
- return memcached_last_error_message(memc);
-}
-
-const char *memcached_last_error_message(const memcached_st *shell)
-{
- const Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- if (memc->error_messages)
- {
- if (memc->error_messages->size and memc->error_messages->message[0])
- {
- return memc->error_messages->message;
- }
-
- return memcached_strerror(memc, memc->error_messages->rc);
- }
-
- return memcached_strerror(memc, MEMCACHED_SUCCESS);
- }
-
- return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
-}
-
-bool memcached_has_current_error(Memcached &memc)
-{
- if (memc.error_messages
- and memc.error_messages->query_id == memc.query_id
- and memcached_failed(memc.error_messages->rc))
- {
- return true;
- }
-
- return false;
-}
-
-bool memcached_has_current_error(memcached_instance_st& server)
-{
- return memcached_has_current_error(*(server.root));
-}
-
-memcached_return_t memcached_last_error(const memcached_st *shell)
-{
- const Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- if (memc->error_messages)
- {
- return memc->error_messages->rc;
- }
-
- return MEMCACHED_SUCCESS;
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
-
-int memcached_last_error_errno(const memcached_st *shell)
-{
- const Memcached* memc= memcached2Memcached(shell);
- if (memc == NULL)
- {
- return 0;
- }
-
- if (memc->error_messages == NULL)
- {
- return 0;
- }
-
- return memc->error_messages->local_errno;
-}
-
-const char *memcached_server_error(const memcached_instance_st * server)
-{
- if (server == NULL)
- {
- return NULL;
- }
-
- if (server->error_messages == NULL)
- {
- return memcached_strerror(server->root, MEMCACHED_SUCCESS);
- }
-
- if (server->error_messages->size == 0)
- {
- return memcached_strerror(server->root, server->error_messages->rc);
- }
-
- return server->error_messages->message;
-}
-
-
-memcached_error_t *memcached_error_copy(const memcached_instance_st& server)
-{
- if (server.error_messages == NULL)
- {
- return NULL;
- }
-
- memcached_error_t *error= libmemcached_xmalloc(server.root, memcached_error_t);
- memcpy(error, server.error_messages, sizeof(memcached_error_t));
- error->next= NULL;
-
- return error;
-}
-
-memcached_return_t memcached_server_error_return(const memcached_instance_st * ptr)
-{
- if (ptr == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (ptr->error_messages)
- {
- return ptr->error_messages->rc;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_instance_error_return(memcached_instance_st* instance)
-{
- if (instance == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (instance->error_messages)
- {
- return instance->error_messages->rc;
- }
-
- return MEMCACHED_SUCCESS;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libmemcached/common.h"
-
-#pragma once
-
-#ifdef __cplusplus
-
-#define STRINGIFY(x) #x
-#define TOSTRING(x) STRINGIFY(x)
-#define MEMCACHED_AT __FILE__ ":" TOSTRING(__LINE__)
-
-memcached_return_t memcached_set_parser_error(Memcached& memc,
- const char *at,
- const char *format, ...);
-
-memcached_return_t memcached_set_error(Memcached&, memcached_return_t rc, const char *at);
-
-memcached_return_t memcached_set_error(memcached_instance_st&, memcached_return_t rc, const char *at);
-
-memcached_return_t memcached_set_error(Memcached&, memcached_return_t rc, const char *at, const char *str, size_t length);
-
-memcached_return_t memcached_set_error(memcached_instance_st&, memcached_return_t rc, const char *at, const char *str, size_t length);
-
-memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, memcached_string_t& str);
-
-memcached_return_t memcached_set_error(memcached_instance_st&, memcached_return_t rc, const char *at, memcached_string_t& str);
-
-memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at, memcached_string_t& str);
-
-memcached_return_t memcached_set_errno(memcached_instance_st&, int local_errno, const char *at, memcached_string_t& str);
-
-memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at, const char *str, size_t length);
-
-memcached_return_t memcached_set_errno(memcached_instance_st&, int local_errno, const char *at, const char *str, size_t length);
-
-memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at);
-
-memcached_return_t memcached_set_errno(memcached_instance_st&, int local_errno, const char *at);
-
-bool memcached_has_current_error(Memcached&);
-
-bool memcached_has_current_error(memcached_instance_st&);
-
-void memcached_error_free(Memcached&);
-
-void memcached_error_free(memcached_server_st&);
-
-void memcached_error_free(memcached_instance_st& self);
-
-memcached_error_t *memcached_error_copy(const memcached_instance_st&);
-
-memcached_return_t memcached_instance_error_return(memcached_instance_st*);
-
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-static memcached_return_t ascii_exist(Memcached *memc, memcached_instance_st* instance, const char *key, size_t key_length)
-{
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { memcached_literal_param("add ") },
- { memcached_array_string(memc->_namespace), memcached_array_size(memc->_namespace) },
- { key, key_length },
- { memcached_literal_param(" 0") },
- { memcached_literal_param(" 2678400") },
- { memcached_literal_param(" 0") },
- { memcached_literal_param("\r\n") },
- { memcached_literal_param("\r\n") }
- };
-
- /* Send command header */
- memcached_return_t rc;
- if (memcached_fatal(rc= memcached_vdo(instance, vector, 9, true)))
- {
- return rc;
- }
-
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
- if (rc == MEMCACHED_NOTSTORED)
- {
- rc= MEMCACHED_SUCCESS;
- }
-
- if (rc == MEMCACHED_STORED)
- {
- rc= MEMCACHED_NOTFOUND;
- }
-
- return rc;
-}
-
-static memcached_return_t binary_exist(Memcached *memc, memcached_instance_st* instance, const char *key, size_t key_length)
-{
- protocol_binary_request_set request= {};
- size_t send_length= sizeof(request.bytes);
-
- initialize_binary_request(instance, request.message.header);
-
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_ADD;
- request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(memc->_namespace)));
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.extlen= 8;
- request.message.body.flags= 0;
- request.message.body.expiration= htonl(2678400);
-
- request.message.header.request.bodylen= htonl((uint32_t) (key_length
- +memcached_array_size(memc->_namespace)
- +request.message.header.request.extlen));
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { request.bytes, send_length },
- { memcached_array_string(memc->_namespace), memcached_array_size(memc->_namespace) },
- { key, key_length }
- };
-
- /* write the header */
- memcached_return_t rc;
- if (memcached_fatal(rc= memcached_vdo(instance, vector, 4, true)))
- {
- return rc;
- }
-
- rc= memcached_response(instance, NULL, 0, NULL);
-
- if (rc == MEMCACHED_SUCCESS)
- {
- rc= MEMCACHED_NOTFOUND;
- }
-
- if (rc == MEMCACHED_DATA_EXISTS)
- {
- rc= MEMCACHED_SUCCESS;
- }
-
- return rc;
-}
-
-memcached_return_t memcached_exist(memcached_st *memc, const char *key, size_t key_length)
-{
- return memcached_exist_by_key(memc, key, key_length, key, key_length);
-}
-
-memcached_return_t memcached_exist_by_key(memcached_st *shell,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length)
-{
- Memcached* memc= memcached2Memcached(shell);
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(memc, true)))
- {
- return rc;
- }
-
- if (memcached_is_udp(memc))
- {
- return memcached_set_error(*memc, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
- }
-
- uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
- memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
-
- if (memcached_is_binary(memc))
- {
- rc= binary_exist(memc, instance, key, key_length);
- }
- else
- {
- rc= ascii_exist(memc, instance, key, key_length);
- }
-
- return rc;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-char *memcached_fetch(memcached_st *shell, char *key, size_t *key_length,
- size_t *value_length,
- uint32_t *flags,
- memcached_return_t *error)
-{
- Memcached* ptr= memcached2Memcached(shell);
- memcached_return_t unused;
- if (error == NULL)
- {
- error= &unused;
- }
-
- if (memcached_is_udp(ptr))
- {
- if (value_length)
- {
- *value_length= 0;
- }
-
- if (key_length)
- {
- *key_length= 0;
- }
-
- if (flags)
- {
- *flags= 0;
- }
-
- if (key)
- {
- *key= 0;
- }
-
- *error= MEMCACHED_NOT_SUPPORTED;
- return NULL;
- }
-
- memcached_result_st *result_buffer= &ptr->result;
- result_buffer= memcached_fetch_result(ptr, result_buffer, error);
- if (result_buffer == NULL or memcached_failed(*error))
- {
- WATCHPOINT_ASSERT(result_buffer == NULL);
- if (value_length)
- {
- *value_length= 0;
- }
-
- if (key_length)
- {
- *key_length= 0;
- }
-
- if (flags)
- {
- *flags= 0;
- }
-
- if (key)
- {
- *key= 0;
- }
-
- return NULL;
- }
-
- if (value_length)
- {
- *value_length= memcached_string_length(&result_buffer->value);
- }
-
- if (key)
- {
- if (result_buffer->key_length > MEMCACHED_MAX_KEY)
- {
- *error= MEMCACHED_KEY_TOO_BIG;
- if (value_length)
- {
- *value_length= 0;
- }
-
- if (key_length)
- {
- *key_length= 0;
- }
-
- if (flags)
- {
- *flags= 0;
- }
-
- if (key)
- {
- *key= 0;
- }
-
- return NULL;
- }
-
- strncpy(key, result_buffer->item_key, result_buffer->key_length); // For the binary protocol we will cut off the key :(
- if (key_length)
- {
- *key_length= result_buffer->key_length;
- }
- }
-
- if (flags)
- {
- *flags= result_buffer->item_flags;
- }
-
- return memcached_string_take_value(&result_buffer->value);
-}
-
-memcached_result_st *memcached_fetch_result(memcached_st *ptr,
- memcached_result_st *result,
- memcached_return_t *error)
-{
- memcached_return_t unused;
- if (error == NULL)
- {
- error= &unused;
- }
-
- if (ptr == NULL)
- {
- *error= MEMCACHED_INVALID_ARGUMENTS;
- return NULL;
- }
-
- if (memcached_is_udp(ptr))
- {
- *error= MEMCACHED_NOT_SUPPORTED;
- return NULL;
- }
-
- if (result == NULL)
- {
- // If we have already initialized (ie it is in use) our internal, we
- // create one.
- if (memcached_is_initialized(&ptr->result))
- {
- if ((result= memcached_result_create(ptr, NULL)) == NULL)
- {
- *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return NULL;
- }
- }
- else
- {
- result= memcached_result_create(ptr, &ptr->result);
- }
- }
-
- *error= MEMCACHED_MAXIMUM_RETURN; // We use this to see if we ever go into the loop
- memcached_instance_st *server;
- memcached_return_t read_ret= MEMCACHED_SUCCESS;
- bool connection_failures= false;
- while ((server= memcached_io_get_readable_server(ptr, read_ret)))
- {
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- *error= memcached_response(server, buffer, sizeof(buffer), result);
-
- if (*error == MEMCACHED_IN_PROGRESS)
- {
- continue;
- }
- else if (*error == MEMCACHED_CONNECTION_FAILURE)
- {
- connection_failures= true;
- continue;
- }
- else if (*error == MEMCACHED_SUCCESS)
- {
- result->count++;
- return result;
- }
- else if (*error == MEMCACHED_END)
- {
- memcached_server_response_reset(server);
- }
- else if (*error != MEMCACHED_NOTFOUND)
- {
- break;
- }
- }
-
- if (*error == MEMCACHED_NOTFOUND and result->count)
- {
- *error= MEMCACHED_END;
- }
- else if (*error == MEMCACHED_MAXIMUM_RETURN and result->count)
- {
- *error= MEMCACHED_END;
- }
- else if (*error == MEMCACHED_MAXIMUM_RETURN) // while() loop was never entered
- {
- *error= MEMCACHED_NOTFOUND;
- }
- else if (connection_failures)
- {
- /*
- If we have a connection failure to some servers, the caller may
- wish to treat that differently to getting a definitive NOT_FOUND
- from all servers, so return MEMCACHED_CONNECTION_FAILURE to allow
- that.
- */
- *error= MEMCACHED_CONNECTION_FAILURE;
- }
- else if (*error == MEMCACHED_SUCCESS)
- {
- *error= MEMCACHED_END;
- }
- else if (result->count == 0)
- {
- *error= MEMCACHED_NOTFOUND;
- }
-
- /* We have completed reading data */
- if (memcached_is_allocated(result))
- {
- memcached_result_free(result);
- }
- else
- {
- result->count= 0;
- memcached_string_reset(&result->value);
- }
-
- return NULL;
-}
-
-memcached_return_t memcached_fetch_execute(memcached_st *shell,
- memcached_execute_fn *callback,
- void *context,
- uint32_t number_of_callbacks)
-{
- Memcached* ptr= memcached2Memcached(shell);
- memcached_result_st *result= &ptr->result;
- memcached_return_t rc;
- bool some_errors= false;
-
- while ((result= memcached_fetch_result(ptr, result, &rc)))
- {
- if (memcached_failed(rc) and rc == MEMCACHED_NOTFOUND)
- {
- continue;
- }
- else if (memcached_failed(rc))
- {
- memcached_set_error(*ptr, rc, MEMCACHED_AT);
- some_errors= true;
- continue;
- }
-
- for (uint32_t x= 0; x < number_of_callbacks; x++)
- {
- memcached_return_t ret= (*callback[x])(ptr, result, context);
- if (memcached_failed(ret))
- {
- some_errors= true;
- memcached_set_error(*ptr, ret, MEMCACHED_AT);
- break;
- }
- }
- }
-
- if (some_errors)
- {
- return MEMCACHED_SOME_ERRORS;
- }
-
- // If we were able to run all keys without issue we return
- // MEMCACHED_SUCCESS
- if (memcached_success(rc))
- {
- return MEMCACHED_SUCCESS;
- }
-
- return rc;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-bool memcached_flag(const memcached_st& memc, const memcached_flag_t flag)
-{
- switch (flag)
- {
- case MEMCACHED_FLAG_AUTO_EJECT_HOSTS:
- return memcached_is_auto_eject_hosts(&memc);
-
- case MEMCACHED_FLAG_BINARY_PROTOCOL:
- return memcached_is_binary(&memc);
-
- case MEMCACHED_FLAG_BUFFER_REQUESTS:
- return memcached_is_buffering(&memc);
-
- case MEMCACHED_FLAG_HASH_WITH_NAMESPACE:
- return memcached_is_hash_with_namespace(&memc);
-
- case MEMCACHED_FLAG_NO_BLOCK:
- return memcached_is_no_block(&memc);
-
- case MEMCACHED_FLAG_REPLY:
- return memcached_is_replying(&memc);
-
- case MEMCACHED_FLAG_RANDOMIZE_REPLICA_READ:
- return memcached_is_randomize_replica_read(&memc);
-
- case MEMCACHED_FLAG_SUPPORT_CAS:
- return memcached_is_cas(&memc);
-
- case MEMCACHED_FLAG_TCP_NODELAY:
- return memcached_is_tcp_nodelay(&memc);
-
- case MEMCACHED_FLAG_USE_SORT_HOSTS:
- return memcached_is_use_sort_hosts(&memc);
-
- case MEMCACHED_FLAG_USE_UDP:
- return memcached_is_udp(&memc);
-
- case MEMCACHED_FLAG_VERIFY_KEY:
- return memcached_is_verify_key(&memc);
-
- case MEMCACHED_FLAG_TCP_KEEPALIVE:
- return memcached_is_use_sort_hosts(&memc);
-
- case MEMCACHED_FLAG_IS_AES:
- return memcached_is_aes(&memc);
-
- case MEMCACHED_FLAG_IS_FETCHING_VERSION:
- return memcached_is_fetching_version(&memc);
- }
-
- abort();
-}
-
-void memcached_flag(memcached_st& memc, const memcached_flag_t flag, const bool arg)
-{
- switch (flag)
- {
- case MEMCACHED_FLAG_AUTO_EJECT_HOSTS:
- memcached_set_auto_eject_hosts(memc, arg);
- break;
-
- case MEMCACHED_FLAG_BINARY_PROTOCOL:
- memcached_set_binary(memc, arg);
- break;
-
- case MEMCACHED_FLAG_BUFFER_REQUESTS:
- memcached_set_buffering(memc, arg);
- break;
-
- case MEMCACHED_FLAG_HASH_WITH_NAMESPACE:
- memcached_set_hash_with_namespace(memc, arg);
- break;
-
- case MEMCACHED_FLAG_NO_BLOCK:
- memcached_set_no_block(memc, arg);
- break;
-
- case MEMCACHED_FLAG_REPLY:
- memcached_set_replying(memc, arg);
- break;
-
- case MEMCACHED_FLAG_RANDOMIZE_REPLICA_READ:
- memcached_set_randomize_replica_read(memc, arg);
- break;
-
- case MEMCACHED_FLAG_SUPPORT_CAS:
- memcached_set_cas(memc, arg);
- break;
-
- case MEMCACHED_FLAG_TCP_NODELAY:
- memcached_set_tcp_nodelay(memc, arg);
- break;
-
- case MEMCACHED_FLAG_USE_SORT_HOSTS:
- memcached_set_use_sort_hosts(memc, arg);
- break;
-
- case MEMCACHED_FLAG_USE_UDP:
- memcached_set_udp(memc, arg);
- break;
-
- case MEMCACHED_FLAG_VERIFY_KEY:
- memcached_set_verify_key(memc, arg);
- break;
-
- case MEMCACHED_FLAG_TCP_KEEPALIVE:
- memcached_set_use_sort_hosts(memc, arg);
- break;
-
- case MEMCACHED_FLAG_IS_AES:
- memcached_set_aes(memc, arg);
- break;
-
- case MEMCACHED_FLAG_IS_FETCHING_VERSION:
- memcached_set_fetching_version(memc, arg);
- break;
- }
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-enum memcached_flag_t
-{
- MEMCACHED_FLAG_AUTO_EJECT_HOSTS,
- MEMCACHED_FLAG_BINARY_PROTOCOL,
- MEMCACHED_FLAG_BUFFER_REQUESTS,
- MEMCACHED_FLAG_HASH_WITH_NAMESPACE,
- MEMCACHED_FLAG_NO_BLOCK,
- MEMCACHED_FLAG_REPLY,
- MEMCACHED_FLAG_RANDOMIZE_REPLICA_READ,
- MEMCACHED_FLAG_SUPPORT_CAS,
- MEMCACHED_FLAG_TCP_NODELAY,
- MEMCACHED_FLAG_USE_SORT_HOSTS,
- MEMCACHED_FLAG_USE_UDP,
- MEMCACHED_FLAG_VERIFY_KEY,
- MEMCACHED_FLAG_TCP_KEEPALIVE,
- MEMCACHED_FLAG_IS_AES,
- MEMCACHED_FLAG_IS_FETCHING_VERSION
-};
-
-bool memcached_flag(const memcached_st&, const memcached_flag_t);
-void memcached_flag(memcached_st&, const memcached_flag_t, const bool);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-static memcached_return_t memcached_flush_binary(Memcached *ptr,
- time_t expiration,
- const bool reply)
-{
- protocol_binary_request_flush request= {};
-
- 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);
-
- memcached_return_t rc= MEMCACHED_SUCCESS;
-
- for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
- initialize_binary_request(instance, request.message.header);
-
- if (reply)
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
- }
- else
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ;
- }
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { request.bytes, sizeof(request.bytes) }
- };
-
- memcached_return_t rrc;
- if (memcached_failed(rrc= memcached_vdo(instance, vector, 2, true)))
- {
- if (instance->error_messages == NULL or instance->root->error_messages == NULL)
- {
- memcached_set_error(*instance, rrc, MEMCACHED_AT);
- }
- rc= MEMCACHED_SOME_ERRORS;
- }
- }
-
- for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
-
- if (instance->response_count() > 0)
- {
- (void)memcached_response(instance, NULL, 0, NULL);
- }
- }
-
- return rc;
-}
-
-static memcached_return_t memcached_flush_textual(Memcached *ptr,
- time_t expiration,
- const bool reply)
-{
- char buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
- int send_length= 0;
- if (expiration)
- {
- send_length= snprintf(buffer, sizeof(buffer), "%llu", (unsigned long long)expiration);
- }
-
- if (size_t(send_length) >= sizeof(buffer) or send_length < 0)
- {
- return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
- }
-
- memcached_return_t rc= MEMCACHED_SUCCESS;
- for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { memcached_literal_param("flush_all ") },
- { buffer, size_t(send_length) },
- { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
- { memcached_literal_param("\r\n") }
- };
-
- memcached_return_t rrc= memcached_vdo(instance, vector, 5, true);
- if (memcached_success(rrc) and reply == true)
- {
- char response_buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- rrc= memcached_response(instance, response_buffer, sizeof(response_buffer), NULL);
- }
-
- if (memcached_failed(rrc))
- {
- // If an error has already been reported, then don't add to it
- if (instance->error_messages == NULL or instance->root->error_messages == NULL)
- {
- memcached_set_error(*instance, rrc, MEMCACHED_AT);
- }
- rc= MEMCACHED_SOME_ERRORS;
- }
- }
-
- return rc;
-}
-
-memcached_return_t memcached_flush(memcached_st *shell, time_t expiration)
-{
- Memcached* ptr= memcached2Memcached(shell);
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(ptr, true)))
- {
- return rc;
- }
-
- bool reply= memcached_is_replying(ptr);
-
- LIBMEMCACHED_MEMCACHED_FLUSH_START();
- if (memcached_is_binary(ptr))
- {
- rc= memcached_flush_binary(ptr, expiration, reply);
- }
- else
- {
- rc= memcached_flush_textual(ptr, expiration, reply);
- }
- LIBMEMCACHED_MEMCACHED_FLUSH_END();
-
- return rc;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-memcached_return_t memcached_flush_buffers(memcached_st *shell)
-{
- Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- memcached_return_t ret= MEMCACHED_SUCCESS;
-
- for (uint32_t x= 0; x < memcached_server_count(memc); ++x)
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc, x);
-
- if (instance->write_buffer_offset != 0)
- {
- if (instance->fd == INVALID_SOCKET and
- (ret= memcached_connect(instance)) != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ERROR(ret);
- return ret;
- }
-
- if (memcached_io_write(instance) == false)
- {
- ret= MEMCACHED_SOME_ERRORS;
- }
- }
- }
-
- return ret;
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-/*
- 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 __mget_by_key_real(memcached_st *ptr,
- const char *group_key,
- size_t group_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- const bool mget_mode);
-char *memcached_get_by_key(memcached_st *shell,
- const char *group_key,
- size_t group_key_length,
- const char *key, size_t key_length,
- size_t *value_length,
- uint32_t *flags,
- memcached_return_t *error)
-{
- Memcached* ptr= memcached2Memcached(shell);
- memcached_return_t unused;
- if (error == NULL)
- {
- error= &unused;
- }
-
- uint64_t query_id= 0;
- if (ptr)
- {
- query_id= ptr->query_id;
- }
-
- /* Request the key */
- *error= __mget_by_key_real(ptr, group_key, group_key_length,
- (const char * const *)&key, &key_length,
- 1, false);
- if (ptr)
- {
- assert_msg(ptr->query_id == query_id +1, "Programmer error, the query_id was not incremented.");
- }
-
- if (memcached_failed(*error))
- {
- if (ptr)
- {
- if (memcached_has_current_error(*ptr)) // Find the most accurate error
- {
- *error= memcached_last_error(ptr);
- }
- }
-
- if (value_length)
- {
- *value_length= 0;
- }
-
- return NULL;
- }
-
- char *value= memcached_fetch(ptr, NULL, NULL,
- value_length, flags, error);
- assert_msg(ptr->query_id == query_id +1, "Programmer error, the query_id was not incremented.");
-
- /* This is for historical reasons */
- if (*error == MEMCACHED_END)
- {
- *error= MEMCACHED_NOTFOUND;
- }
- if (value == NULL)
- {
- if (ptr->get_key_failure and *error == MEMCACHED_NOTFOUND)
- {
- memcached_result_st key_failure_result;
- memcached_result_st* result_ptr= memcached_result_create(ptr, &key_failure_result);
- memcached_return_t rc= ptr->get_key_failure(ptr, key, key_length, result_ptr);
-
- /* On all failure drop to returning NULL */
- if (rc == MEMCACHED_SUCCESS or 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(result_ptr)),
- (memcached_result_length(result_ptr)),
- 0,
- (memcached_result_flags(result_ptr)));
-
- if (rc == MEMCACHED_BUFFERED and latch == 0)
- {
- memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
- }
- }
- else
- {
- rc= memcached_set(ptr, key, key_length,
- (memcached_result_value(result_ptr)),
- (memcached_result_length(result_ptr)),
- 0,
- (memcached_result_flags(result_ptr)));
- }
-
- if (rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED)
- {
- *error= rc;
- *value_length= memcached_result_length(result_ptr);
- *flags= memcached_result_flags(result_ptr);
- char *result_value= memcached_string_take_value(&result_ptr->value);
- memcached_result_free(result_ptr);
-
- return result_value;
- }
- }
-
- memcached_result_free(result_ptr);
- }
- assert_msg(ptr->query_id == query_id +1, "Programmer error, the query_id was not incremented.");
-
- return NULL;
- }
-
- 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,
- const uint32_t master_server_key,
- const bool is_group_key_set,
- const char * const *keys,
- const size_t *key_length,
- const size_t number_of_keys,
- const bool mget_mode);
-
-static memcached_return_t __mget_by_key_real(memcached_st *ptr,
- const char *group_key,
- const size_t group_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- const bool mget_mode)
-{
- bool failures_occured_in_sending= false;
- const char *get_command= "get";
- uint8_t get_command_length= 3;
- unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */
-
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(ptr, true)))
- {
- return rc;
- }
-
- if (memcached_is_udp(ptr))
- {
- return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
- }
-
- LIBMEMCACHED_MEMCACHED_MGET_START();
-
- if (number_of_keys == 0)
- {
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Numbers of keys provided was zero"));
- }
-
- if (memcached_failed((rc= memcached_key_test(*ptr, keys, key_length, number_of_keys))))
- {
- assert(memcached_last_error(ptr) == rc);
-
- return rc;
- }
-
- bool is_group_key_set= false;
- if (group_key and group_key_length)
- {
- master_server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
- is_group_key_set= true;
- }
-
- /*
- Here is where we pay for the non-block API. We need to remove any data sitting
- in the queue before we start our get.
-
- It might be optimum to bounce the connection if count > some number.
- */
- for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
-
- if (instance->response_count())
- {
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
- if (ptr->flags.no_block)
- {
- memcached_io_write(instance);
- }
-
- while(instance->response_count())
- {
- (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
- }
- }
- }
-
- if (memcached_is_binary(ptr))
- {
- return binary_mget_by_key(ptr, master_server_key, is_group_key_set, keys,
- key_length, number_of_keys, mget_mode);
- }
-
- if (ptr->flags.support_cas)
- {
- get_command= "gets";
- get_command_length= 4;
- }
-
- /*
- If a server fails we warn about errors and start all over with sending keys
- to the server.
- */
- WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
- size_t hosts_connected= 0;
- for (uint32_t x= 0; x < number_of_keys; x++)
- {
- uint32_t server_key;
-
- if (is_group_key_set)
- {
- server_key= master_server_key;
- }
- else
- {
- server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
- }
-
- memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
-
- libmemcached_io_vector_st vector[]=
- {
- { get_command, get_command_length },
- { memcached_literal_param(" ") },
- { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
- { keys[x], key_length[x] }
- };
-
-
- if (instance->response_count() == 0)
- {
- rc= memcached_connect(instance);
-
- if (memcached_failed(rc))
- {
- memcached_set_error(*instance, rc, MEMCACHED_AT);
- continue;
- }
- hosts_connected++;
-
- if ((memcached_io_writev(instance, vector, 1, false)) == false)
- {
- failures_occured_in_sending= true;
- continue;
- }
- WATCHPOINT_ASSERT(instance->cursor_active_ == 0);
- memcached_instance_response_increment(instance);
- WATCHPOINT_ASSERT(instance->cursor_active_ == 1);
- }
-
- {
- if ((memcached_io_writev(instance, (vector + 1), 3, false)) == false)
- {
- memcached_instance_response_reset(instance);
- failures_occured_in_sending= true;
- continue;
- }
- }
- }
-
- if (hosts_connected == 0)
- {
- LIBMEMCACHED_MEMCACHED_MGET_END();
-
- if (memcached_failed(rc))
- {
- return rc;
- }
-
- return memcached_set_error(*ptr, MEMCACHED_NO_SERVERS, MEMCACHED_AT);
- }
-
-
- /*
- Should we muddle on if some servers are dead?
- */
- bool success_happened= false;
- for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
-
- if (instance->response_count())
- {
- /* We need to do something about non-connnected hosts in the future */
- if ((memcached_io_write(instance, "\r\n", 2, true)) == -1)
- {
- failures_occured_in_sending= true;
- }
- else
- {
- success_happened= true;
- }
- }
- }
-
- LIBMEMCACHED_MEMCACHED_MGET_END();
-
- if (failures_occured_in_sending and success_happened)
- {
- return MEMCACHED_SOME_ERRORS;
- }
-
- if (success_happened)
- {
- return MEMCACHED_SUCCESS;
- }
-
- return MEMCACHED_FAILURE; // Complete failure occurred
-}
-
-memcached_return_t memcached_mget_by_key(memcached_st *shell,
- const char *group_key,
- size_t group_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys)
-{
- Memcached* ptr= memcached2Memcached(shell);
- return __mget_by_key_real(ptr, group_key, group_key_length, keys, key_length, number_of_keys, true);
-}
-
-memcached_return_t memcached_mget_execute(memcached_st *ptr,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- memcached_execute_fn *callback,
- void *context,
- unsigned int number_of_callbacks)
-{
- return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length,
- number_of_keys, callback,
- context, number_of_callbacks);
-}
-
-memcached_return_t memcached_mget_execute_by_key(memcached_st *shell,
- const char *group_key,
- size_t group_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- memcached_execute_fn *callback,
- void *context,
- unsigned int number_of_callbacks)
-{
- Memcached* ptr= memcached2Memcached(shell);
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(ptr, false)))
- {
- return rc;
- }
-
- if (memcached_is_udp(ptr))
- {
- return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
- }
-
- if (memcached_is_binary(ptr) == false)
- {
- return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
- memcached_literal_param("ASCII protocol is not supported for memcached_mget_execute_by_key()"));
- }
-
- memcached_callback_st *original_callbacks= ptr->callbacks;
- memcached_callback_st cb= {
- callback,
- context,
- number_of_callbacks
- };
-
- ptr->callbacks= &cb;
- rc= memcached_mget_by_key(ptr, group_key, group_key_length, keys,
- key_length, number_of_keys);
- ptr->callbacks= original_callbacks;
-
- return rc;
-}
-
-static memcached_return_t simple_binary_mget(memcached_st *ptr,
- const uint32_t master_server_key,
- bool is_group_key_set,
- const char * const *keys,
- const size_t *key_length,
- const size_t number_of_keys, const bool mget_mode)
-{
- memcached_return_t rc= MEMCACHED_NOTFOUND;
-
- bool flush= (number_of_keys == 1);
-
- if (memcached_failed(rc= memcached_key_test(*ptr, keys, key_length, number_of_keys)))
- {
- return rc;
- }
-
- /*
- If a server fails we warn about errors and start all over with sending keys
- to the server.
- */
- for (uint32_t x= 0; x < number_of_keys; ++x)
- {
- uint32_t server_key;
-
- if (is_group_key_set)
- {
- server_key= master_server_key;
- }
- else
- {
- server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
- }
-
- memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
-
- if (instance->response_count() == 0)
- {
- rc= memcached_connect(instance);
- if (memcached_failed(rc))
- {
- continue;
- }
- }
-
- protocol_binary_request_getk request= { }; //= {.bytes= {0}};
- initialize_binary_request(instance, request.message.header);
- if (mget_mode)
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ;
- }
- else
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
- }
-
-#if 0
- {
- memcached_return_t vk= memcached_validate_key_length(key_length[x], ptr->flags.binary_protocol);
- if (memcached_failed(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
- {
- memcached_set_error(ptr, vk, MEMCACHED_AT, memcached_literal_param("Key was too long."));
-
- if (x > 0)
- {
- memcached_io_reset(instance);
- }
-
- return vk;
- }
- }
-#endif
-
- request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->_namespace)));
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->_namespace)));
-
- libmemcached_io_vector_st vector[]=
- {
- { request.bytes, sizeof(request.bytes) },
- { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
- { keys[x], key_length[x] }
- };
-
- if (memcached_io_writev(instance, vector, 3, flush) == false)
- {
- 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 and x == ptr->io_key_prefetch) and 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.opcode= PROTOCOL_BINARY_CMD_NOOP;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
- for (uint32_t x= 0; x < memcached_server_count(ptr); ++x)
- {
- memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
-
- if (instance->response_count())
- {
- initialize_binary_request(instance, request.message.header);
- if ((memcached_io_write(instance) == false) or
- (memcached_io_write(instance, request.bytes, sizeof(request.bytes), true) == -1))
- {
- memcached_instance_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,
- const size_t number_of_keys)
-{
- memcached_return_t rc= MEMCACHED_NOTFOUND;
- uint32_t start= 0;
- uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
-
- if (randomize_read)
- {
- start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1);
- }
-
- /* Loop for each replica */
- for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica)
- {
- bool success= true;
-
- for (uint32_t x= 0; x < number_of_keys; ++x)
- {
- 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 and ((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;
- }
-
- memcached_instance_st* instance= memcached_instance_fetch(ptr, server);
-
- if (instance->response_count() == 0)
- {
- rc= memcached_connect(instance);
-
- if (memcached_failed(rc))
- {
- memcached_io_reset(instance);
- dead_servers[server]= true;
- success= false;
- continue;
- }
- }
-
- protocol_binary_request_getk request= {};
- initialize_binary_request(instance, request.message.header);
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
- request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->_namespace)));
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)(key_length[x] + memcached_array_size(ptr->_namespace)));
-
- /*
- * 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_
- */
- libmemcached_io_vector_st vector[]=
- {
- { request.bytes, sizeof(request.bytes) },
- { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
- { keys[x], key_length[x] }
- };
-
- if (memcached_io_writev(instance, vector, 3, true) == false)
- {
- 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,
- const uint32_t master_server_key,
- bool is_group_key_set,
- const char * const *keys,
- const size_t *key_length,
- const size_t number_of_keys,
- const bool mget_mode)
-{
- if (ptr->number_of_replicas == 0)
- {
- return simple_binary_mget(ptr, master_server_key, is_group_key_set,
- keys, key_length, number_of_keys, mget_mode);
- }
-
- uint32_t* hash= libmemcached_xvalloc(ptr, number_of_keys, uint32_t);
- bool* dead_servers= libmemcached_xcalloc(ptr, memcached_server_count(ptr), bool);
-
- if (hash == NULL or dead_servers == NULL)
- {
- libmemcached_free(ptr, hash);
- libmemcached_free(ptr, dead_servers);
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- if (is_group_key_set)
- {
- for (size_t x= 0; x < number_of_keys; x++)
- {
- hash[x]= master_server_key;
- }
- }
- else
- {
- for (size_t x= 0; x < number_of_keys; x++)
- {
- hash[x]= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
- }
- }
-
- memcached_return_t rc= replication_binary_mget(ptr, hash, dead_servers, keys,
- key_length, number_of_keys);
-
- WATCHPOINT_IFERROR(rc);
- libmemcached_free(ptr, hash);
- libmemcached_free(ptr, dead_servers);
-
- return MEMCACHED_SUCCESS;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libmemcached/common.h>
-
-#include <sys/time.h>
-
-#include <libmemcached/virtual_bucket.h>
-
-uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm)
-{
- return libhashkit_digest(key, key_length, (hashkit_hash_algorithm_t)hash_algorithm);
-}
-
-static inline uint32_t generate_hash(const Memcached *ptr, const char *key, size_t key_length)
-{
- return hashkit_digest(&ptr->hashkit, key, key_length);
-}
-
-static uint32_t dispatch_host(const Memcached *ptr, uint32_t hash)
-{
- switch (ptr->distribution)
- {
- case MEMCACHED_DISTRIBUTION_CONSISTENT:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
- {
- uint32_t num= ptr->ketama.continuum_points_counter;
- WATCHPOINT_ASSERT(ptr->ketama.continuum);
-
- memcached_continuum_item_st *begin, *end, *left, *right, *middle;
- begin= left= ptr->ketama.continuum;
- end= right= ptr->ketama.continuum + num;
-
- while (left < right)
- {
- middle= left + (right - left) / 2;
- if (middle->value < hash)
- left= middle + 1;
- else
- right= middle;
- }
- if (right == end)
- right= begin;
- return right->index;
- }
- case MEMCACHED_DISTRIBUTION_MODULA:
- return hash % memcached_server_count(ptr);
- case MEMCACHED_DISTRIBUTION_RANDOM:
- return (uint32_t) random() % memcached_server_count(ptr);
- case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
- {
- return memcached_virtual_bucket_get(ptr, hash);
- }
- default:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
- WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
- return hash % memcached_server_count(ptr);
- }
- /* NOTREACHED */
-}
-
-/*
- One version is public and will not modify the distribution hash, the other will.
-*/
-static inline uint32_t _generate_hash_wrapper(const Memcached *ptr, const char *key, size_t key_length)
-{
- WATCHPOINT_ASSERT(memcached_server_count(ptr));
-
- if (memcached_server_count(ptr) == 1)
- return 0;
-
- if (ptr->flags.hash_with_namespace)
- {
- size_t temp_length= memcached_array_size(ptr->_namespace) + key_length;
- char temp[MEMCACHED_MAX_KEY];
-
- if (temp_length > MEMCACHED_MAX_KEY -1)
- return 0;
-
- strncpy(temp, memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace));
- strncpy(temp + memcached_array_size(ptr->_namespace), key, key_length);
-
- return generate_hash(ptr, temp, temp_length);
- }
- else
- {
- return generate_hash(ptr, key, key_length);
- }
-}
-
-static inline void _regen_for_auto_eject(Memcached *ptr)
-{
- if (_is_auto_eject_host(ptr) && ptr->ketama.next_distribution_rebuild)
- {
- struct timeval now;
-
- if (gettimeofday(&now, NULL) == 0 and
- now.tv_sec > ptr->ketama.next_distribution_rebuild)
- {
- run_distribution(ptr);
- }
- }
-}
-
-void memcached_autoeject(memcached_st *ptr)
-{
- _regen_for_auto_eject(ptr);
-}
-
-uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length)
-{
- uint32_t hash= _generate_hash_wrapper(ptr, key, key_length);
-
- _regen_for_auto_eject(ptr);
-
- return dispatch_host(ptr, hash);
-}
-
-uint32_t memcached_generate_hash(const memcached_st *shell, const char *key, size_t key_length)
-{
- const Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- return dispatch_host(ptr, _generate_hash_wrapper(ptr, key, key_length));
- }
-
- return UINT32_MAX;
-}
-
-const hashkit_st *memcached_get_hashkit(const memcached_st *shell)
-{
- const Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- return &ptr->hashkit;
- }
-
- return NULL;
-}
-
-memcached_return_t memcached_set_hashkit(memcached_st *shell, hashkit_st *hashk)
-{
- Memcached* self= memcached2Memcached(shell);
- if (self)
- {
- hashkit_free(&self->hashkit);
- hashkit_clone(&self->hashkit, hashk);
-
- return MEMCACHED_SUCCESS;
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
-
-const char * libmemcached_string_hash(memcached_hash_t type)
-{
- return libhashkit_string_hash((hashkit_hash_algorithm_t)type);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-#include "libmemcached/assert.hpp"
-
-#include <cmath>
-#include <sys/time.h>
-
-/* Protoypes (static) */
-static memcached_return_t update_continuum(Memcached *ptr);
-
-static int compare_servers(const void *p1, const void *p2)
-{
- const memcached_instance_st * a= (const memcached_instance_st *)p1;
- const memcached_instance_st * b= (const memcached_instance_st *)p2;
-
- int 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 *ptr)
-{
- if (memcached_server_count(ptr))
- {
- qsort(memcached_instance_list(ptr), memcached_server_count(ptr), sizeof(memcached_instance_st), compare_servers);
- }
-}
-
-
-memcached_return_t run_distribution(Memcached *ptr)
-{
- if (ptr->flags.use_sort_hosts)
- {
- sort_hosts(ptr);
- }
-
- switch (ptr->distribution)
- {
- case MEMCACHED_DISTRIBUTION_CONSISTENT:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
- return update_continuum(ptr);
-
- case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
- case MEMCACHED_DISTRIBUTION_MODULA:
- break;
-
- case MEMCACHED_DISTRIBUTION_RANDOM:
- srandom((uint32_t) time(NULL));
- break;
-
- case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
- default:
- assert_msg(0, "Invalid distribution type passed to run_distribution()");
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-static uint32_t ketama_server_hash(const char *key, size_t key_length, uint32_t alignment)
-{
- unsigned char results[16];
-
- libhashkit_md5_signature((unsigned char*)key, key_length, results);
-
- return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
- | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
- | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
- | (results[0 + alignment * 4] & 0xFF);
-}
-
-static int continuum_item_cmp(const void *t1, const void *t2)
-{
- memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1;
- memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2;
-
- /* Why 153? Hmmm... */
- WATCHPOINT_ASSERT(ct1->value != 153);
- if (ct1->value == ct2->value)
- {
- if (ct1->index == ct2->index)
- {
- return 0;
- }
- else if (ct1->index > ct2->index)
- {
- return 1;
- }
- else
- {
- return -1;
- }
- }
- else if (ct1->value > ct2->value)
- {
- return 1;
- }
- else
- {
- return -1;
- }
-}
-
-static memcached_return_t update_continuum(Memcached *ptr)
-{
- uint32_t continuum_index= 0;
- uint32_t pointer_counter= 0;
- uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
- uint32_t pointer_per_hash= 1;
- uint32_t live_servers= 0;
- struct timeval now;
-
- if (gettimeofday(&now, NULL))
- {
- return memcached_set_errno(*ptr, errno, MEMCACHED_AT);
- }
-
- memcached_instance_st* list= memcached_instance_list(ptr);
-
- /* count live servers (those without a retry delay set) */
- bool is_auto_ejecting= _is_auto_eject_host(ptr);
- if (is_auto_ejecting)
- {
- live_servers= 0;
- ptr->ketama.next_distribution_rebuild= 0;
- for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
- {
- if (list[host_index].next_retry <= now.tv_sec)
- {
- live_servers++;
- }
- else
- {
- if (ptr->ketama.next_distribution_rebuild == 0 or list[host_index].next_retry < ptr->ketama.next_distribution_rebuild)
- {
- ptr->ketama.next_distribution_rebuild= list[host_index].next_retry;
- }
- }
- }
- }
- else
- {
- live_servers= memcached_server_count(ptr);
- }
-
- if (live_servers == 0)
- {
- return MEMCACHED_SUCCESS;
- }
-
- uint32_t points_per_server = (uint32_t) (memcached_is_weighted_ketama(ptr) ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER);
- uint32_t continuum_limit = live_servers * points_per_server;
- uint32_t continuum_extra = MEMCACHED_CONTINUUM_ADDITION * points_per_server;
-
- if (continuum_limit > ptr->ketama.continuum_count)
- {
- memcached_continuum_item_st *new_ptr;
-
- new_ptr= libmemcached_xrealloc(ptr, ptr->ketama.continuum, continuum_limit + continuum_extra, memcached_continuum_item_st);
-
- if (new_ptr == 0)
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- ptr->ketama.continuum= new_ptr;
- ptr->ketama.continuum_count= continuum_limit + continuum_extra;
- }
- assert_msg(ptr->ketama.continuum, "Programmer Error, empty ketama continuum");
-
- uint64_t total_weight= 0;
- if (memcached_is_weighted_ketama(ptr))
- {
- for (uint32_t host_index = 0; host_index < memcached_server_count(ptr); ++host_index)
- {
- if (is_auto_ejecting == false or list[host_index].next_retry <= now.tv_sec)
- {
- total_weight += list[host_index].weight;
- }
- }
- }
-
- for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
- {
- if (is_auto_ejecting and list[host_index].next_retry > now.tv_sec)
- {
- continue;
- }
-
- if (memcached_is_weighted_ketama(ptr))
- {
- float pct= (float)list[host_index].weight / (float)total_weight;
- pointer_per_server= (uint32_t) ((::floor((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
- pointer_per_hash= 4;
- if (0 && 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);
- }
- }
-
-
- if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY)
- {
- for (uint32_t pointer_index= 0;
- pointer_index < pointer_per_server / pointer_per_hash;
- pointer_index++)
- {
- char sort_host[1 +MEMCACHED_NI_MAXHOST +1 +MEMCACHED_NI_MAXSERV +1 + MEMCACHED_NI_MAXSERV ]= "";
- int sort_host_length;
-
- // Spymemcached ketema key format is: hostname/ip:port-index
- // If hostname is not available then: /ip:port-index
- sort_host_length= snprintf(sort_host, sizeof(sort_host),
- "/%s:%u-%u",
- list[host_index]._hostname,
- (uint32_t)list[host_index].port(),
- pointer_index);
-
- if (size_t(sort_host_length) >= sizeof(sort_host) or sort_host_length < 0)
- {
- return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(sizeof(sort_host))"));
- }
-
- if (0 && DEBUG)
- {
- fprintf(stdout, "update_continuum: key is %s\n", sort_host);
- }
-
- if (memcached_is_weighted_ketama(ptr))
- {
- for (uint32_t x= 0; x < pointer_per_hash; x++)
- {
- uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
- ptr->ketama.continuum[continuum_index].index= host_index;
- ptr->ketama.continuum[continuum_index++].value= value;
- }
- }
- else
- {
- uint32_t value= hashkit_digest(&ptr->hashkit, sort_host, (size_t)sort_host_length);
- ptr->ketama.continuum[continuum_index].index= host_index;
- ptr->ketama.continuum[continuum_index++].value= value;
- }
- }
- }
- else
- {
- for (uint32_t pointer_index= 1;
- pointer_index <= pointer_per_server / pointer_per_hash;
- pointer_index++)
- {
- char sort_host[MEMCACHED_NI_MAXHOST +1 +MEMCACHED_NI_MAXSERV +1 +MEMCACHED_NI_MAXSERV]= "";
- int sort_host_length;
-
- if (list[host_index].port() == MEMCACHED_DEFAULT_PORT)
- {
- sort_host_length= snprintf(sort_host, sizeof(sort_host),
- "%s-%u",
- list[host_index]._hostname,
- pointer_index - 1);
- }
- else
- {
- sort_host_length= snprintf(sort_host, sizeof(sort_host),
- "%s:%u-%u",
- list[host_index]._hostname,
- (uint32_t)list[host_index].port(),
- pointer_index - 1);
- }
-
- if (size_t(sort_host_length) >= sizeof(sort_host) or sort_host_length < 0)
- {
- return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(sizeof(sort_host)))"));
- }
-
- if (memcached_is_weighted_ketama(ptr))
- {
- for (uint32_t x = 0; x < pointer_per_hash; x++)
- {
- uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
- ptr->ketama.continuum[continuum_index].index= host_index;
- ptr->ketama.continuum[continuum_index++].value= value;
- }
- }
- else
- {
- uint32_t value= hashkit_digest(&ptr->hashkit, sort_host, (size_t)sort_host_length);
- ptr->ketama.continuum[continuum_index].index= host_index;
- ptr->ketama.continuum[continuum_index++].value= value;
- }
- }
- }
-
- pointer_counter+= pointer_per_server;
- }
-
- assert_msg(ptr, "Programmer Error, no valid ptr");
- assert_msg(ptr->ketama.continuum, "Programmer Error, empty ketama continuum");
- assert_msg(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE, "invalid size information being given to qsort()");
- ptr->ketama.continuum_points_counter= pointer_counter;
- qsort(ptr->ketama.continuum, ptr->ketama.continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
-
- if (DEBUG)
- {
- for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
- {
- WATCHPOINT_ASSERT(ptr->ketama.continuum[pointer_index].value <= ptr->ketama.continuum[pointer_index + 1].value);
- }
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t server_add(Memcached *memc,
- const memcached_string_t& hostname,
- in_port_t port,
- uint32_t weight,
- memcached_connection_t type)
-{
- assert_msg(memc, "Programmer mistake, somehow server_add() was passed a NULL memcached_st");
-
- if (memc->number_of_hosts)
- {
- assert(memcached_instance_list(memc));
- }
-
- if (memcached_instance_list(memc))
- {
- assert(memc->number_of_hosts);
- }
-
- uint32_t host_list_size= memc->number_of_hosts +1;
- memcached_instance_st* new_host_list= libmemcached_xrealloc(memc, memcached_instance_list(memc), host_list_size, memcached_instance_st);
-
- if (new_host_list == NULL)
- {
- return memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
-
- memcached_instance_set(memc, new_host_list, host_list_size);
- assert(memc->number_of_hosts == host_list_size);
-
- /* TODO: Check return type */
- memcached_instance_st* instance= memcached_instance_fetch(memc, memcached_server_count(memc) -1);
-
- if (__instance_create_with(memc, instance, hostname, port, weight, type) == NULL)
- {
- return memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
-
- if (weight > 1)
- {
- if (memcached_is_consistent_distribution(memc))
- {
- memcached_set_weighted_ketama(memc, true);
- }
- }
-
- return run_distribution(memc);
-}
-
-
-memcached_return_t memcached_server_push(memcached_st *shell, const memcached_server_list_st list)
-{
- if (list == NULL)
- {
- return MEMCACHED_SUCCESS;
- }
-
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- uint32_t original_host_size= memcached_server_count(ptr);
- uint32_t count= memcached_server_list_count(list);
- uint32_t host_list_size= count +original_host_size;
-
- memcached_instance_st* new_host_list= libmemcached_xrealloc(ptr, memcached_instance_list(ptr), host_list_size, memcached_instance_st);
-
- if (new_host_list == NULL)
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- memcached_instance_set(ptr, new_host_list, host_list_size);
-
- ptr->state.is_parsing= true;
- for (uint32_t x= 0; x < count; ++x, ++original_host_size)
- {
- WATCHPOINT_ASSERT(list[x].hostname[0] != 0);
-
- // We have extended the array, and now we will find it, and use it.
- memcached_instance_st* instance= memcached_instance_fetch(ptr, original_host_size);
- WATCHPOINT_ASSERT(instance);
-
- memcached_string_t hostname= { memcached_string_make_from_cstr(list[x].hostname) };
- if (__instance_create_with(ptr, instance,
- hostname,
- list[x].port, list[x].weight, list[x].type) == NULL)
- {
- ptr->state.is_parsing= false;
- return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
-
- if (list[x].weight > 1)
- {
- memcached_set_weighted_ketama(ptr, true);
- }
- }
- ptr->state.is_parsing= false;
-
- return run_distribution(ptr);
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
-
-memcached_return_t memcached_instance_push(memcached_st *ptr, const struct memcached_instance_st* list, uint32_t number_of_hosts)
-{
- if (list == NULL)
- {
- return MEMCACHED_SUCCESS;
- }
-
- uint32_t original_host_size= memcached_server_count(ptr);
- uint32_t host_list_size= number_of_hosts +original_host_size;
- memcached_instance_st* new_host_list= libmemcached_xrealloc(ptr, memcached_instance_list(ptr), host_list_size, memcached_instance_st);
-
- if (new_host_list == NULL)
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- memcached_instance_set(ptr, new_host_list, host_list_size);
-
- // We don't bother with lookups for this operation
- ptr->state.is_parsing= true;
-
- // We use original_host_size since size will now point to the first new
- // instance allocated.
- for (uint32_t x= 0; x < number_of_hosts; ++x, ++original_host_size)
- {
- WATCHPOINT_ASSERT(list[x]._hostname[0] != 0);
-
- // We have extended the array, and now we will find it, and use it.
- memcached_instance_st* instance= memcached_instance_fetch(ptr, original_host_size);
- WATCHPOINT_ASSERT(instance);
-
- memcached_string_t hostname= { memcached_string_make_from_cstr(list[x]._hostname) };
- if (__instance_create_with(ptr, instance,
- hostname,
- list[x].port(), list[x].weight, list[x].type) == NULL)
- {
- ptr->state.is_parsing= false;
- return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
-
- if (list[x].weight > 1)
- {
- memcached_set_weighted_ketama(ptr, true);
- }
- }
- ptr->state.is_parsing= false;
-
- 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 *shell,
- const char *filename,
- uint32_t weight)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr)
- {
- memcached_string_t _filename= { memcached_string_make_from_cstr(filename) };
- if (memcached_is_valid_filename(_filename) == false)
- {
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid filename for socket provided"));
- }
-
- return server_add(ptr, _filename, 0, weight, MEMCACHED_CONNECTION_UNIX_SOCKET);
- }
-
- return MEMCACHED_FAILURE;
-}
-
-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 *shell,
- const char *,
- in_port_t,
- uint32_t)
-{
- Memcached* self= memcached2Memcached(shell);
- if (self)
- {
- return memcached_set_error(*self, MEMCACHED_DEPRECATED, MEMCACHED_AT);
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
-
-memcached_return_t memcached_server_add(memcached_st *shell,
- const char *hostname,
- in_port_t port)
-{
- return memcached_server_add_with_weight(shell, hostname, port, 0);
-}
-
-memcached_return_t memcached_server_add_with_weight(memcached_st *shell,
- const char *hostname,
- in_port_t port,
- uint32_t weight)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (port == 0)
- {
- port= MEMCACHED_DEFAULT_PORT;
- }
-
- size_t hostname_length= hostname ? strlen(hostname) : 0;
- if (hostname_length == 0)
- {
- hostname= "localhost";
- hostname_length= memcached_literal_param_size("localhost");
- }
-
- memcached_string_t _hostname= { hostname, hostname_length };
-
- if (memcached_is_valid_servername(_hostname) == false)
- {
- return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid hostname provided"));
- }
-
- return server_add(ptr, _hostname, port, weight, _hostname.c_str[0] == '/' ? MEMCACHED_CONNECTION_UNIX_SOCKET : MEMCACHED_CONNECTION_TCP);
-}
-
-memcached_return_t memcached_server_add_parsed(memcached_st *ptr,
- const char *hostname,
- size_t hostname_length,
- in_port_t port,
- uint32_t weight)
-{
- char buffer[MEMCACHED_NI_MAXHOST]= { 0 };
-
- memcpy(buffer, hostname, hostname_length);
- buffer[hostname_length]= 0;
-
- memcached_string_t _hostname= { buffer, hostname_length };
-
- return server_add(ptr, _hostname,
- port,
- weight,
- MEMCACHED_CONNECTION_TCP);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-memcached_return_t initialize_query(Memcached *self, bool increment_query_id)
-{
- if (self == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (increment_query_id)
- {
- self->query_id++;
- }
-
- if (self->state.is_time_for_rebuild)
- {
- memcached_reset(self);
- }
-
- if (memcached_server_count(self) == 0)
- {
- return memcached_set_error(*self, MEMCACHED_NO_SERVERS, MEMCACHED_AT);
- }
-
- memcached_error_free(*self);
- memcached_result_reset(&self->result);
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t initialize_const_query(const Memcached *self)
-{
- if (self == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (memcached_server_count(self) == 0)
- {
- return MEMCACHED_NO_SERVERS;
- }
-
- return MEMCACHED_SUCCESS;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-memcached_return_t initialize_query(Memcached *self, bool increment_query_id);
-
-memcached_return_t initialize_const_query(const Memcached *self);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-static inline void _server_init(memcached_instance_st* self, Memcached *root,
- const memcached_string_t& hostname,
- in_port_t port,
- uint32_t weight, memcached_connection_t type)
-{
- self->options.is_shutting_down= false;
- self->options.is_dead= false;
- self->options.ready= false;
- self->_events= 0;
- self->_revents= 0;
- self->cursor_active_= 0;
- self->port_= port;
- self->fd= INVALID_SOCKET;
- self->io_bytes_sent= 0;
- self->request_id= 0;
- self->server_failure_counter= 0;
- self->server_failure_counter_query_id= 0;
- self->server_timeout_counter= 0;
- self->server_timeout_counter_query_id= 0;
- self->weight= weight ? weight : 1; // 1 is the default weight value
- self->io_wait_count.read= 0;
- self->io_wait_count.write= 0;
- self->io_wait_count.timeouts= 0;
- self->io_wait_count._bytes_read= 0;
- self->major_version= UINT8_MAX;
- self->micro_version= UINT8_MAX;
- self->minor_version= UINT8_MAX;
- self->type= type;
- self->error_messages= NULL;
- self->read_ptr= self->read_buffer;
- self->read_buffer_length= 0;
- self->write_buffer_offset= 0;
- self->address_info= NULL;
- self->address_info_next= NULL;
-
- self->state= MEMCACHED_SERVER_STATE_NEW;
- self->next_retry= 0;
-
- self->root= root;
- if (root)
- {
- self->version= ++root->server_info.version;
- }
- else
- {
- self->version= UINT_MAX;
- }
- self->limit_maxbytes= 0;
- self->hostname(hostname);
-}
-
-static memcached_instance_st* _server_create(memcached_instance_st* self, const memcached_st *memc)
-{
- if (self == NULL)
- {
- self= libmemcached_xmalloc(memc, memcached_instance_st);
-
- if (self == NULL)
- {
- return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
- }
-
- self->options.is_allocated= true;
- }
- else
- {
- self->options.is_allocated= false;
- }
-
- self->options.is_initialized= true;
-
- return self;
-}
-
-void memcached_instance_st::events(short arg)
-{
- if ((_events | arg) == _events)
- {
- return;
- }
-
- _events|= arg;
-}
-
-void memcached_instance_st::revents(short arg)
-{
- if (arg)
- {
- options.ready= true;
- }
-
- _revents= arg;
- _events&= short(~arg);
-}
-
-memcached_instance_st* __instance_create_with(memcached_st *memc,
- memcached_instance_st* self,
- const memcached_string_t& hostname,
- const in_port_t port,
- uint32_t weight,
- const memcached_connection_t type)
-{
- if (memcached_is_valid_servername(hostname) == false)
- {
- memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid hostname provided"));
- return NULL;
- }
-
- self= _server_create(self, memc);
-
- if (self == NULL)
- {
- return NULL;
- }
-
- _server_init(self, const_cast<memcached_st *>(memc), hostname, port, weight, type);
-
- if (memc and memcached_is_udp(memc))
- {
- self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
- memcached_io_init_udp_header(self, 0);
- }
-
- return self;
-}
-
-void __instance_free(memcached_instance_st* self)
-{
- memcached_quit_server(self, false);
-
- self->clear_addrinfo();
- assert(self->address_info_next == NULL);
-
- memcached_error_free(*self);
-
- if (memcached_is_allocated(self))
- {
- libmemcached_free(self->root, self);
- }
- else
- {
- self->options.is_initialized= false;
- }
-}
-
-void memcached_instance_free(memcached_instance_st* self)
-{
- if (self)
- {
- __instance_free(self);
- }
-}
-
-memcached_return_t memcached_server_cursor(const memcached_st* shell,
- const memcached_server_fn *callback,
- void *context,
- uint32_t number_of_callbacks)
-{
- const Memcached* memc= memcached2Memcached(shell);
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_const_query(memc)))
- {
- return rc;
- }
-
- size_t errors= 0;
- for (uint32_t x= 0; x < memcached_instance_list_count(memc); x++)
- {
- memcached_instance_st* instance= memcached_instance_by_position(memc, x);
-
- for (uint32_t y= 0; y < number_of_callbacks; y++)
- {
- memcached_return_t ret= (*callback[y])(memc, instance, context);
-
- if (memcached_failed(ret))
- {
- errors++;
- continue;
- }
- }
- }
-
- return errors ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_server_execute(memcached_st *memc,
- memcached_server_execute_fn callback,
- void *context)
-{
- if (callback == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- bool some_errors= false;;
- for (uint32_t x= 0; x < memcached_instance_list_count(memc); x++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc, x);
-
- memcached_return_t rc= (*callback)(memc, instance, context);
- if (rc == MEMCACHED_INVALID_ARGUMENTS)
- {
- return rc;
- }
- else if (memcached_fatal(rc))
- {
- some_errors= true;
- }
- }
-
- (void)some_errors;
- return MEMCACHED_SUCCESS;
-}
-
-const memcached_instance_st * memcached_server_by_key(memcached_st *shell,
- const char *key,
- size_t key_length,
- memcached_return_t *error)
-{
- Memcached* memc= memcached2Memcached(shell);
- memcached_return_t unused;
- if (error == NULL)
- {
- error= &unused;
- }
-
-
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_const_query(memc)))
- {
- *error= rc;
- return NULL;
- }
-
- if (memcached_failed((memcached_key_test(*memc, (const char **)&key, &key_length, 1))))
- {
- *error= memcached_last_error(memc);
- return NULL;
- }
-
- uint32_t server_key= memcached_generate_hash(memc, key, key_length);
- return memcached_instance_by_position(memc, server_key);
-}
-
-/*
- If we do not have a valid object to clone from, we toss an error.
-*/
-static memcached_instance_st* memcached_instance_clone(memcached_instance_st* source)
-{
- /* We just do a normal create if source is missing */
- if (source == NULL)
- {
- return NULL;
- }
-
- memcached_string_t hostname_= { memcached_string_make_from_cstr(source->hostname()) };
- return __instance_create_with(source->root,
- NULL,
- hostname_,
- source->port(), source->weight,
- source->type);
-}
-
-void set_last_disconnected_host(memcached_instance_st* self)
-{
- assert(self->root);
- if (self->root)
- {
- if (memcached_server_get_last_disconnect(self->root) and
- memcached_server_get_last_disconnect(self->root)->version == self->version)
- {
- return;
- }
-
- // const_cast
- memcached_st *root= (memcached_st *)self->root;
-
- memcached_instance_free((memcached_instance_st*)(root->last_disconnected_server));
-
- // We set is_parsing so that no lookup happens
- root->state.is_parsing= true;
- root->last_disconnected_server= memcached_instance_clone(self);
- root->state.is_parsing= false;
-
- ((memcached_instance_st*)memcached_server_get_last_disconnect(root))->version= self->version;
- }
-}
-
-const memcached_instance_st * memcached_server_get_last_disconnect(const memcached_st *shell)
-{
- const Memcached* self= memcached2Memcached(shell);
- if (self)
- {
- return (const memcached_instance_st *)self->last_disconnected_server;
- }
-
- return 0;
-}
-
-void memcached_instance_next_retry(const memcached_instance_st * self, const time_t absolute_time)
-{
- WATCHPOINT_ASSERT(self);
- if (self)
- {
- ((memcached_instance_st*)self)->next_retry= absolute_time;
- }
-}
-
-bool memcached_instance_st::valid() const
-{
- if (fd == INVALID_SOCKET)
- {
- return false;
- }
-
- return true;
-}
-
-bool memcached_instance_st::is_shutting_down() const
-{
- return options.is_shutting_down;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifndef WIN32
-# ifdef HAVE_NETDB_H
-# include <netdb.h>
-# endif
-#endif
-
-#ifdef NI_MAXHOST
-# define MEMCACHED_NI_MAXHOST NI_MAXHOST
-#else
-# define MEMCACHED_NI_MAXHOST 1025
-#endif
-
-#ifdef NI_MAXSERV
-# define MEMCACHED_NI_MAXSERV NI_MAXSERV
-#else
-# define MEMCACHED_NI_MAXSERV 32
-#endif
-
-#include "libmemcached/string.hpp"
-
-// @todo Complete class transformation
-struct memcached_instance_st {
- in_port_t port() const
- {
- return port_;
- }
-
- void port(in_port_t arg)
- {
- port_= arg;
- }
-
- void mark_server_as_clean()
- {
- server_failure_counter= 0;
- server_timeout_counter= 0;
- next_retry= 0;
- }
-
- void disable()
- {
- }
-
- void enable()
- {
- }
-
- bool valid() const;
-
- bool is_shutting_down() const;
-
- void start_close_socket();
- void close_socket();
- void reset_socket();
-
- uint32_t response_count() const
- {
- return cursor_active_;
- }
-
- struct {
- bool is_allocated;
- bool is_initialized;
- bool is_shutting_down;
- bool is_dead;
- bool ready;
- } options;
-
- short _events;
- short _revents;
-
- short events(void)
- {
- return _events;
- }
-
- short revents(void)
- {
- return _revents;
- }
-
- const char* hostname()
- {
- return _hostname;
- }
-
- void hostname(const memcached_string_t& hostname_)
- {
- if (hostname_.size)
- {
- memcpy(_hostname, hostname_.c_str, hostname_.size);
- _hostname[hostname_.size]= 0;
- }
- else
- {
- memcpy(_hostname, memcached_literal_param("localhost"));
- _hostname[memcached_literal_param_size("localhost")]= 0;
- }
- }
-
- void events(short);
- void revents(short);
-
- uint32_t cursor_active_;
- in_port_t port_;
- memcached_socket_t fd;
- uint32_t io_bytes_sent; /* # bytes sent since last read */
- uint32_t request_id;
- uint32_t server_failure_counter;
- uint64_t server_failure_counter_query_id;
- uint32_t server_timeout_counter;
- uint64_t server_timeout_counter_query_id;
- uint32_t weight;
- uint32_t version;
- enum memcached_server_state_t state;
- struct {
- uint32_t read;
- uint32_t write;
- uint32_t timeouts;
- size_t _bytes_read;
- } io_wait_count;
- uint8_t major_version; // Default definition of UINT8_MAX means that it has not been set.
- uint8_t micro_version; // ditto, and note that this is the third, not second version bit
- uint8_t minor_version; // ditto
- memcached_connection_t type;
- char *read_ptr;
- size_t read_buffer_length;
- size_t write_buffer_offset;
- struct addrinfo *address_info;
- struct addrinfo *address_info_next;
- time_t next_retry;
- struct memcached_st *root;
- uint64_t limit_maxbytes;
- struct memcached_error_t *error_messages;
- char read_buffer[MEMCACHED_MAX_BUFFER];
- char write_buffer[MEMCACHED_MAX_BUFFER];
- char _hostname[MEMCACHED_NI_MAXHOST];
-
- void clear_addrinfo()
- {
- if (address_info)
- {
- freeaddrinfo(address_info);
- address_info= NULL;
- address_info_next= NULL;
- }
- }
-};
-
-memcached_instance_st* __instance_create_with(memcached_st *memc,
- memcached_instance_st* self,
- const memcached_string_t& _hostname,
- const in_port_t port,
- uint32_t weight,
- const memcached_connection_t type);
-
-memcached_return_t memcached_instance_push(memcached_st *ptr, const memcached_instance_st*, uint32_t);
-
-void __instance_free(memcached_instance_st *);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libmemcached/common.h>
-
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
-
-void initialize_binary_request(memcached_instance_st* server, protocol_binary_request_header& header)
-{
- server->request_id++;
- header.request.magic= PROTOCOL_BINARY_REQ;
- header.request.opaque= htons(server->request_id);
-}
-
-enum memc_read_or_write {
- MEM_READ,
- MEM_WRITE
-};
-
-/**
- * Try to fill the input buffer for a server with as much
- * data as possible.
- *
- * @param instance the server to pack
- */
-static bool repack_input_buffer(memcached_instance_st* instance)
-{
- if (instance->read_ptr != instance->read_buffer)
- {
- /* Move all of the data to the beginning of the buffer so
- ** that we can fit more data into the buffer...
- */
- memmove(instance->read_buffer, instance->read_ptr, instance->read_buffer_length);
- instance->read_ptr= instance->read_buffer;
- }
-
- /* There is room in the buffer, try to fill it! */
- if (instance->read_buffer_length != MEMCACHED_MAX_BUFFER)
- {
- do {
- /* Just try a single read to grab what's available */
- ssize_t nr;
- if ((nr= ::recv(instance->fd,
- instance->read_ptr + instance->read_buffer_length,
- MEMCACHED_MAX_BUFFER - instance->read_buffer_length,
- MSG_NOSIGNAL)) <= 0)
- {
- if (nr == 0)
- {
- memcached_set_error(*instance, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT);
- }
- else
- {
- switch (get_socket_errno())
- {
- case EINTR:
- continue;
-
-#if EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
-#endif
- case EAGAIN:
-#ifdef __linux
- case ERESTART:
-#endif
- break; // No IO is fine, we can just move on
-
- default:
- memcached_set_errno(*instance, get_socket_errno(), MEMCACHED_AT);
- }
- }
-
- break;
- }
- else // We read data, append to our read buffer
- {
- instance->read_buffer_length+= size_t(nr);
-
- return true;
- }
- } while (false);
- }
-
- 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 instance the server to star processing iput messages for
- * @return true if we processed anything, false otherwise
- */
-static bool process_input_buffer(memcached_instance_st* instance)
-{
- /*
- ** We might be able to process some of the response messages if we
- ** have a callback set up
- */
- if (instance->root->callbacks != NULL)
- {
- /*
- * We might have responses... try to read them out and fire
- * callbacks
- */
- memcached_callback_st cb= *instance->root->callbacks;
-
- memcached_set_processing_input((Memcached *)instance->root, true);
-
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- Memcached *root= (Memcached *)instance->root;
- memcached_return_t error= memcached_response(instance, buffer, sizeof(buffer), &root->result);
-
- memcached_set_processing_input(root, false);
-
- if (error == MEMCACHED_SUCCESS)
- {
- for (unsigned int x= 0; x < cb.number_of_callback; x++)
- {
- error= (*cb.callback[x])(instance->root, &root->result, cb.context);
- if (error != MEMCACHED_SUCCESS)
- {
- break;
- }
- }
-
- /* @todo what should I do with the error message??? */
- }
- /* @todo what should I do with other error messages?? */
- return true;
- }
-
- return false;
-}
-
-static memcached_return_t io_wait(memcached_instance_st* instance,
- const short events)
-{
- /*
- ** 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 (events & POLLOUT)
- {
- if (memcached_purge(instance) == false)
- {
- return MEMCACHED_FAILURE;
- }
- }
-
- struct pollfd fds;
- fds.fd= instance->fd;
- fds.events= events;
- fds.revents= 0;
-
- if (fds.events & POLLOUT) /* write */
- {
- instance->io_wait_count.write++;
- }
- else
- {
- instance->io_wait_count.read++;
- }
-
- if (instance->root->poll_timeout == 0) // Mimic 0 causes timeout behavior (not all platforms do this)
- {
- return memcached_set_error(*instance, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_literal_param("poll_timeout() was set to zero"));
- }
-
- size_t loop_max= 5;
- while (--loop_max) // While loop is for ERESTART or EINTR
- {
- int active_fd= poll(&fds, 1, instance->root->poll_timeout);
-
- if (active_fd >= 1)
- {
- assert_msg(active_fd == 1 , "poll() returned an unexpected number of active file descriptors");
- if (fds.revents & POLLIN or fds.revents & POLLOUT)
- {
- return MEMCACHED_SUCCESS;
- }
-
- if (fds.revents & POLLHUP)
- {
- return memcached_set_error(*instance, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("poll() detected hang up"));
- }
-
- if (fds.revents & POLLERR)
- {
- int local_errno= EINVAL;
- int err;
- socklen_t len= sizeof (err);
- if (getsockopt(instance->fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == 0)
- {
- if (err == 0) // treat this as EINTR
- {
- continue;
- }
- local_errno= err;
- }
- memcached_quit_server(instance, true);
- return memcached_set_errno(*instance, local_errno, MEMCACHED_AT,
- memcached_literal_param("poll() returned POLLHUP"));
- }
-
- return memcached_set_error(*instance, MEMCACHED_FAILURE, MEMCACHED_AT, memcached_literal_param("poll() returned a value that was not dealt with"));
- }
-
- if (active_fd == 0)
- {
- return memcached_set_error(*instance, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_literal_param("No active_fd were found"));
- }
-
- // Only an error should result in this code being called.
- int local_errno= get_socket_errno(); // We cache in case memcached_quit_server() modifies errno
- assert_msg(active_fd == -1 , "poll() returned an unexpected value");
- switch (local_errno)
- {
-#ifdef __linux
- case ERESTART:
-#endif
- case EINTR:
- continue;
-
- case EFAULT:
- case ENOMEM:
- memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- break;
-
- case EINVAL:
- memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid"));
- break;
-
- default:
- memcached_set_errno(*instance, local_errno, MEMCACHED_AT, memcached_literal_param("poll"));
- }
-
- break;
- }
-
- memcached_quit_server(instance, true);
-
- if (memcached_has_error(instance))
- {
- return memcached_instance_error_return(instance);
- }
-
- return memcached_set_error(*instance, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("number of attempts to call io_wait() failed"));
-}
-
-static bool io_flush(memcached_instance_st* instance,
- const bool with_flush,
- memcached_return_t& error)
-{
- /*
- ** We might want to purge the input buffer if we haven't consumed
- ** any output yet... The test for the limits is the purge is inline
- ** in the purge function to avoid duplicating the logic..
- */
- {
- WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
-
- if (memcached_purge(instance) == false)
- {
- return false;
- }
- }
- char *local_write_ptr= instance->write_buffer;
- size_t write_length= instance->write_buffer_offset;
-
- error= MEMCACHED_SUCCESS;
-
- WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
-
- /* Looking for memory overflows */
-#if defined(DEBUG)
- if (write_length == MEMCACHED_MAX_BUFFER)
- WATCHPOINT_ASSERT(instance->write_buffer == local_write_ptr);
- WATCHPOINT_ASSERT((instance->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length));
-#endif
-
- while (write_length)
- {
- WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
- WATCHPOINT_ASSERT(write_length > 0);
-
- int flags;
- if (with_flush)
- {
- flags= MSG_NOSIGNAL;
- }
- else
- {
- flags= MSG_NOSIGNAL|MSG_MORE;
- }
-
- ssize_t sent_length= ::send(instance->fd, local_write_ptr, write_length, flags);
- int local_errno= get_socket_errno(); // We cache in case memcached_quit_server() modifies errno
-
- if (sent_length == SOCKET_ERROR)
- {
-#if 0 // @todo I should look at why we hit this bit of code hard frequently
- WATCHPOINT_ERRNO(get_socket_errno());
- WATCHPOINT_NUMBER(get_socket_errno());
-#endif
- switch (get_socket_errno())
- {
- case ENOBUFS:
- continue;
-
-#if EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
-#endif
- 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(instance) or process_input_buffer(instance))
- {
- continue;
- }
-
- memcached_return_t rc= io_wait(instance, POLLOUT);
- if (memcached_success(rc))
- {
- continue;
- }
- else if (rc == MEMCACHED_TIMEOUT)
- {
- return false;
- }
-
- memcached_quit_server(instance, true);
- error= memcached_set_errno(*instance, local_errno, MEMCACHED_AT);
- return false;
- }
- case ENOTCONN:
- case EPIPE:
- default:
- memcached_quit_server(instance, true);
- error= memcached_set_errno(*instance, local_errno, MEMCACHED_AT);
- WATCHPOINT_ASSERT(instance->fd == INVALID_SOCKET);
- return false;
- }
- }
-
- instance->io_bytes_sent+= uint32_t(sent_length);
-
- local_write_ptr+= sent_length;
- write_length-= uint32_t(sent_length);
- }
-
- WATCHPOINT_ASSERT(write_length == 0);
- instance->write_buffer_offset= 0;
-
- return true;
-}
-
-memcached_return_t memcached_io_wait_for_write(memcached_instance_st* instance)
-{
- return io_wait(instance, POLLOUT);
-}
-
-memcached_return_t memcached_io_wait_for_read(memcached_instance_st* instance)
-{
- return io_wait(instance, POLLIN);
-}
-
-static memcached_return_t _io_fill(memcached_instance_st* instance)
-{
- ssize_t data_read;
- do
- {
- data_read= ::recv(instance->fd, instance->read_buffer, MEMCACHED_MAX_BUFFER, MSG_NOSIGNAL);
- int local_errno= get_socket_errno(); // We cache in case memcached_quit_server() modifies errno
-
- if (data_read == SOCKET_ERROR)
- {
- switch (get_socket_errno())
- {
- case EINTR: // We just retry
- continue;
-
- case ETIMEDOUT: // OSX
-#if EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
-#endif
- case EAGAIN:
-#ifdef __linux
- case ERESTART:
-#endif
- {
- memcached_return_t io_wait_ret;
- if (memcached_success(io_wait_ret= io_wait(instance, POLLIN)))
- {
- continue;
- }
-
- return io_wait_ret;
- }
-
- /* fall through */
-
- case ENOTCONN: // Programmer Error
- WATCHPOINT_ASSERT(0);
- // fall through
- case ENOTSOCK:
- WATCHPOINT_ASSERT(0);
- // fall through
- case EBADF:
- assert_msg(instance->fd != INVALID_SOCKET, "Programmer error, invalid socket");
- /* fall through */
- case EINVAL:
- case EFAULT:
- case ECONNREFUSED:
- default:
- memcached_quit_server(instance, true);
- memcached_set_errno(*instance, local_errno, MEMCACHED_AT);
- break;
- }
-
- return memcached_instance_error_return(instance);
- }
- else if (data_read == 0)
- {
- /*
- 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(instance, true);
- return memcached_set_error(*instance, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("::rec() returned zero, server has disconnected"));
- }
- instance->io_wait_count._bytes_read+= data_read;
- } while (data_read <= 0);
-
- instance->io_bytes_sent= 0;
- instance->read_buffer_length= (size_t) data_read;
- instance->read_ptr= instance->read_buffer;
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_io_read(memcached_instance_st* instance,
- void *buffer, size_t length, ssize_t& nread)
-{
- assert(memcached_is_udp(instance->root) == false);
- assert_msg(instance, "Programmer error, memcached_io_read() recieved an invalid Instance"); // Programmer error
- char *buffer_ptr= static_cast<char *>(buffer);
-
- if (instance->fd == INVALID_SOCKET)
- {
-#if 0
- assert_msg(int(instance->state) <= int(MEMCACHED_SERVER_STATE_ADDRINFO), "Programmer error, invalid socket state");
-#endif
- return MEMCACHED_CONNECTION_FAILURE;
- }
-
- while (length)
- {
- if (instance->read_buffer_length == 0)
- {
- memcached_return_t io_fill_ret;
- if (memcached_fatal(io_fill_ret= _io_fill(instance)))
- {
- nread= -1;
- return io_fill_ret;
- }
- }
-
- if (length > 1)
- {
- size_t difference= (length > instance->read_buffer_length) ? instance->read_buffer_length : length;
-
- memcpy(buffer_ptr, instance->read_ptr, difference);
- length -= difference;
- instance->read_ptr+= difference;
- instance->read_buffer_length-= difference;
- buffer_ptr+= difference;
- }
- else
- {
- *buffer_ptr= *instance->read_ptr;
- instance->read_ptr++;
- instance->read_buffer_length--;
- buffer_ptr++;
- break;
- }
- }
-
- nread= ssize_t(buffer_ptr - (char*)buffer);
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_io_slurp(memcached_instance_st* instance)
-{
- assert_msg(instance, "Programmer error, invalid Instance");
- assert(memcached_is_udp(instance->root) == false);
-
- if (instance->fd == INVALID_SOCKET)
- {
- assert_msg(int(instance->state) <= int(MEMCACHED_SERVER_STATE_ADDRINFO), "Invalid socket state");
- return MEMCACHED_CONNECTION_FAILURE;
- }
-
- ssize_t data_read;
- char buffer[MEMCACHED_MAX_BUFFER];
- do
- {
- data_read= ::recv(instance->fd, instance->read_buffer, sizeof(buffer), MSG_NOSIGNAL);
- if (data_read == SOCKET_ERROR)
- {
- switch (get_socket_errno())
- {
- case EINTR: // We just retry
- continue;
-
- case ETIMEDOUT: // OSX
-#if EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
-#endif
- case EAGAIN:
-#ifdef __linux
- case ERESTART:
-#endif
- if (memcached_success(io_wait(instance, POLLIN)))
- {
- continue;
- }
- return MEMCACHED_IN_PROGRESS;
-
- /* fall through */
-
- case ENOTCONN: // Programmer Error
- case ENOTSOCK:
- assert(0);
- /* fall through */
- case EBADF:
- assert_msg(instance->fd != INVALID_SOCKET, "Invalid socket state");
- /* fall through */
- case EINVAL:
- case EFAULT:
- case ECONNREFUSED:
- default:
- return MEMCACHED_CONNECTION_FAILURE; // We want this!
- }
- }
- } while (data_read > 0);
-
- return MEMCACHED_CONNECTION_FAILURE;
-}
-
-static bool _io_write(memcached_instance_st* instance,
- const void *buffer, size_t length, bool with_flush,
- size_t& written)
-{
- assert(instance->fd != INVALID_SOCKET);
- assert(memcached_is_udp(instance->root) == false);
-
- const char *buffer_ptr= static_cast<const char *>(buffer);
-
- const size_t original_length= length;
-
- while (length)
- {
- char *write_ptr;
- size_t buffer_end= MEMCACHED_MAX_BUFFER;
- size_t should_write= buffer_end -instance->write_buffer_offset;
- should_write= (should_write < length) ? should_write : length;
-
- write_ptr= instance->write_buffer + instance->write_buffer_offset;
- memcpy(write_ptr, buffer_ptr, should_write);
- instance->write_buffer_offset+= should_write;
- buffer_ptr+= should_write;
- length-= should_write;
-
- if (instance->write_buffer_offset == buffer_end)
- {
- WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
-
- memcached_return_t rc;
- if (io_flush(instance, with_flush, rc) == false)
- {
- written= original_length -length;
- return false;
- }
- }
- }
-
- if (with_flush)
- {
- memcached_return_t rc;
- WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
- if (io_flush(instance, with_flush, rc) == false)
- {
- written= original_length -length;
- return false;
- }
- }
-
- written= original_length -length;
-
- return true;
-}
-
-bool memcached_io_write(memcached_instance_st* instance)
-{
- size_t written;
- return _io_write(instance, NULL, 0, true, written);
-}
-
-ssize_t memcached_io_write(memcached_instance_st* instance,
- const void *buffer, const size_t length, const bool with_flush)
-{
- size_t written;
-
- if (_io_write(instance, buffer, length, with_flush, written) == false)
- {
- return -1;
- }
-
- return ssize_t(written);
-}
-
-bool memcached_io_writev(memcached_instance_st* instance,
- libmemcached_io_vector_st vector[],
- const size_t number_of, const bool with_flush)
-{
- ssize_t complete_total= 0;
- ssize_t total= 0;
-
- for (size_t x= 0; x < number_of; x++, vector++)
- {
- complete_total+= vector->length;
- if (vector->length)
- {
- size_t written;
- if ((_io_write(instance, vector->buffer, vector->length, false, written)) == false)
- {
- return false;
- }
- total+= written;
- }
- }
-
- if (with_flush)
- {
- if (memcached_io_write(instance) == false)
- {
- return false;
- }
- }
-
- return (complete_total == total);
-}
-
-void memcached_instance_st::start_close_socket()
-{
- if (fd != INVALID_SOCKET)
- {
- shutdown(fd, SHUT_WR);
- options.is_shutting_down= true;
- }
-}
-
-void memcached_instance_st::reset_socket()
-{
- if (fd != INVALID_SOCKET)
- {
- (void)closesocket(fd);
- fd= INVALID_SOCKET;
- }
-}
-
-void memcached_instance_st::close_socket()
-{
- if (fd != INVALID_SOCKET)
- {
- int shutdown_options= SHUT_RD;
- if (options.is_shutting_down == false)
- {
- shutdown_options= SHUT_RDWR;
- }
-
- /* in case of death shutdown to avoid blocking at close() */
- if (shutdown(fd, shutdown_options) == SOCKET_ERROR and get_socket_errno() != ENOTCONN)
- {
- WATCHPOINT_NUMBER(fd);
- WATCHPOINT_ERRNO(get_socket_errno());
- WATCHPOINT_ASSERT(get_socket_errno());
- }
-
- reset_socket();
- state= MEMCACHED_SERVER_STATE_NEW;
- }
-
- state= MEMCACHED_SERVER_STATE_NEW;
- cursor_active_= 0;
- io_bytes_sent= 0;
- write_buffer_offset= size_t(root and memcached_is_udp(root) ? UDP_DATAGRAM_HEADER_LENGTH : 0);
- read_buffer_length= 0;
- read_ptr= read_buffer;
- options.is_shutting_down= false;
- memcached_server_response_reset(this);
-
- // We reset the version so that if we end up talking to a different server
- // we don't have stale server version information.
- major_version= minor_version= micro_version= UINT8_MAX;
-}
-
-memcached_instance_st* memcached_io_get_readable_server(Memcached *memc, memcached_return_t&)
-{
-#define MAX_SERVERS_TO_POLL 100
- struct pollfd fds[MAX_SERVERS_TO_POLL];
- nfds_t host_index= 0;
-
- for (uint32_t x= 0; x < memcached_server_count(memc) and host_index < MAX_SERVERS_TO_POLL; ++x)
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc, x);
-
- if (instance->read_buffer_length > 0) /* I have data in the buffer */
- {
- return instance;
- }
-
- if (instance->response_count() > 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_instance_st* instance= memcached_instance_fetch(memc, x);
-
- if (instance->response_count() > 0)
- {
- return instance;
- }
- }
-
- return NULL;
- }
-
- int error= poll(fds, host_index, memc->poll_timeout);
- switch (error)
- {
- case -1:
- memcached_set_errno(*memc, get_socket_errno(), MEMCACHED_AT);
- /* FALLTHROUGH */
- case 0:
- break;
-
- default:
- for (nfds_t x= 0; x < host_index; ++x)
- {
- if (fds[x].revents & POLLIN)
- {
- for (uint32_t y= 0; y < memcached_server_count(memc); ++y)
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc, y);
-
- if (instance->fd == fds[x].fd)
- {
- return instance;
- }
- }
- }
- }
- }
-
- return NULL;
-}
-
-/*
- Eventually we will just kill off the server with the problem.
-*/
-void memcached_io_reset(memcached_instance_st* instance)
-{
- memcached_quit_server(instance, true);
-}
-
-/**
- * Read a given number of bytes from the server and place it into a specific
- * buffer. Reset the IO channel on this server if an error occurs.
- */
-memcached_return_t memcached_safe_read(memcached_instance_st* instance,
- void *dta,
- const size_t size)
-{
- size_t offset= 0;
- char *data= static_cast<char *>(dta);
-
- while (offset < size)
- {
- ssize_t nread;
- memcached_return_t rc;
-
- while (memcached_continue(rc= memcached_io_read(instance, data + offset, size - offset, nread))) { };
-
- if (memcached_failed(rc))
- {
- return rc;
- }
-
- offset+= size_t(nread);
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_io_readline(memcached_instance_st* instance,
- char *buffer_ptr,
- size_t size,
- size_t& total_nr)
-{
- total_nr= 0;
- bool line_complete= false;
-
- while (line_complete == false)
- {
- if (instance->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(instance, buffer_ptr, 1, nread);
- if (memcached_failed(rc) and rc == MEMCACHED_IN_PROGRESS)
- {
- memcached_quit_server(instance, true);
- return memcached_set_error(*instance, rc, MEMCACHED_AT);
- }
- else if (memcached_failed(rc))
- {
- 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 (instance->read_buffer_length and total_nr < size and line_complete == false)
- {
- *buffer_ptr = *instance->read_ptr;
- if (*buffer_ptr == '\n')
- {
- line_complete = true;
- }
- --instance->read_buffer_length;
- ++instance->read_ptr;
- ++total_nr;
- ++buffer_ptr;
- }
-
- if (total_nr == size)
- {
- return MEMCACHED_PROTOCOL_ERROR;
- }
- }
-
- return MEMCACHED_SUCCESS;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-struct libmemcached_io_vector_st
-{
- const void *buffer;
- size_t length;
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-void initialize_binary_request(memcached_instance_st* server, protocol_binary_request_header&);
-
-bool memcached_io_write(memcached_instance_st* ptr);
-
-ssize_t memcached_io_write(memcached_instance_st* ptr,
- const void *buffer, size_t length, bool with_flush);
-
-bool memcached_io_writev(memcached_instance_st* ptr,
- libmemcached_io_vector_st vector[],
- const size_t number_of, const bool with_flush);
-
-memcached_return_t memcached_io_wait_for_write(memcached_instance_st*);
-memcached_return_t memcached_io_wait_for_read(memcached_instance_st*);
-
-void memcached_io_reset(memcached_instance_st* ptr);
-
-memcached_return_t memcached_io_read(memcached_instance_st* ptr,
- void *buffer, size_t length, ssize_t& nread);
-
-/* Read a line (terminated by '\n') into the buffer */
-memcached_return_t memcached_io_readline(memcached_instance_st* ptr,
- char *buffer_ptr,
- size_t size,
- size_t& total);
-
-/* Read n bytes of data from the server and store them in dta */
-memcached_return_t memcached_safe_read(memcached_instance_st* ptr,
- void *dta,
- const size_t size);
-
-memcached_instance_st* memcached_io_get_readable_server(memcached_st *memc, memcached_return_t&);
-
-memcached_return_t memcached_io_slurp(memcached_instance_st* ptr);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-/* These are private */
-#define memcached_is_allocated(__object) ((__object)->options.is_allocated)
-#define memcached_is_encrypted(__object) ((__object)->hashkit._key)
-#define memcached_is_initialized(__object) ((__object)->options.is_initialized)
-#define memcached_is_purging(__object) ((__object)->state.is_purging)
-#define memcached_is_processing_input(__object) ((__object)->state.is_processing_input)
-
-#define memcached_is_aes(__object) ((__object)->flags.is_aes)
-#define memcached_is_udp(__object) ((__object)->flags.use_udp)
-#define memcached_is_verify_key(__object) ((__object)->flags.verify_key)
-#define memcached_is_binary(__object) ((__object)->flags.binary_protocol)
-#define memcached_is_fetching_version(__object) ((__object)->flags.is_fetching_version)
-#define memcached_is_buffering(__object) ((__object)->flags.buffer_requests)
-#define memcached_is_replying(__object) ((__object)->flags.reply)
-#define memcached_is_cas(__object) ((__object)->flags.reply)
-#define memcached_is_randomize_replica_read(__object) ((__object)->flags.randomize_replica_read)
-#define memcached_is_no_block(__object) ((__object)->flags.no_block)
-#define memcached_is_hash_with_namespace(__object) ((__object)->flags.hash_with_namespace)
-#define memcached_is_tcp_nodelay(__object) ((__object)->flags.tcp_nodelay)
-#define memcached_is_auto_eject_hosts(__object) ((__object)->flags.auto_eject_hosts)
-#define memcached_is_use_sort_hosts(__object) ((__object)->flags.use_sort_hosts)
-
-#define memcached_is_ready(__object) ((__object)->options.ready)
-
-#define memcached_is_weighted_ketama(__object) ((__object)->ketama.weighted_)
-
-#define memcached_set_ready(__object, __flag) ((__object)->options.ready= (__flag))
-
-#define memcached_set_aes(__object, __flag) ((__object).flags.is_aes= __flag)
-#define memcached_set_udp(__object, __flag) ((__object).flags.use_udp= __flag)
-#define memcached_set_verify_key(__object, __flag) ((__object).flags.verify_key= __flag)
-#define memcached_set_binary(__object, __flag) ((__object).flags.binary_protocol= __flag)
-#define memcached_set_fetching_version(__object, __flag) ((__object).flags.is_fetching_version= __flag)
-#define memcached_set_buffering(__object, __flag) ((__object).flags.buffer_requests= __flag)
-#define memcached_set_replying(__object, __flag) ((__object).flags.reply= __flag)
-#define memcached_set_cas(__object, __flag) ((__object).flags.reply= __flag)
-#define memcached_set_randomize_replica_read(__object, __flag) ((__object).flags.randomize_replica_read= __flag)
-#define memcached_set_no_block(__object, __flag) ((__object).flags.no_block= __flag)
-#define memcached_set_hash_with_namespace(__object, __flag) ((__object).flags.hash_with_namespace= __flag)
-#define memcached_set_tcp_nodelay(__object, __flag) ((__object).flags.tcp_nodelay= __flag)
-#define memcached_set_auto_eject_hosts(__object, __flag) ((__object).flags.auto_eject_hosts= __flag)
-#define memcached_set_use_sort_hosts(__object, __flag) ((__object).flags.use_sort_hosts= __flag)
-
-#define memcached_has_root(__object) ((__object)->root)
-
-#define memcached_has_error(__object) ((__object)->error_messages)
-
-#define memcached_has_replicas(__object) ((__object)->root->number_of_replicas)
-
-#define memcached_set_processing_input(__object, __value) ((__object)->state.is_processing_input= (__value))
-#define memcached_set_initialized(__object, __value) ((__object)->options.is_initialized= (__value))
-#define memcached_set_allocated(__object, __value) ((__object)->options.is_allocated= (__value))
-
-#define memcached_set_weighted_ketama(__object, __value) ((__object)->ketama.weighted_= (__value))
-
-#define memcached2Memcached(__obj) (__obj)
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-static inline memcached_return_t memcached_validate_key_length(size_t key_length, bool)
-{
- if (key_length == 0)
- {
- return MEMCACHED_BAD_KEY_PROVIDED;
- }
-
- // No one ever reimplemented MEMCACHED to use keys longer then the original ascii length
-#if 0
- if (binary)
- {
- if (key_length > 0xffff)
- {
- return MEMCACHED_BAD_KEY_PROVIDED;
- }
- }
- else
-#endif
- {
- if (key_length >= MEMCACHED_MAX_KEY)
- {
- return MEMCACHED_BAD_KEY_PROVIDED;
- }
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_key_test(memcached_st &memc,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys)
-{
- if (number_of_keys == 0)
- {
- return memcached_set_error(memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Numbers of keys provided was zero"));
- }
-
- if (keys == NULL or key_length == NULL)
- {
- return memcached_set_error(memc, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT, memcached_literal_param("Key was NULL or length of key was zero."));
- }
-
- const bool is_binary= memcached_flag(memc, MEMCACHED_FLAG_BINARY_PROTOCOL);
-
- // If we don't need to verify the key, or we are using the binary protoocol,
- // we just check the size of the key
- for (size_t x= 0; x < number_of_keys; ++x)
- {
- // We should set binary key, but the memcached server is broken for
- // longer keys at the moment.
- memcached_return_t rc= memcached_validate_key_length(*(key_length +x), false /* memc.flags.binary_protocol */);
- if (memcached_failed(rc))
- {
- return memcached_set_error(memc, rc, MEMCACHED_AT, memcached_literal_param("Key provided was too long."));
- }
-
- if (memc.flags.verify_key and is_binary == false)
- {
- for (size_t y= 0; y < *(key_length +x); ++y)
- {
- if ((isgraph(keys[x][y])) == 0)
- {
- return memcached_set_error(memc, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT, memcached_literal_param("Key provided had invalid character."));
- }
- }
- }
- }
-
- return MEMCACHED_SUCCESS;
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-memcached_return_t memcached_key_test(memcached_st& memc,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys);
-
+++ /dev/null
-provider libmemcached {
- probe memcached_delete_start();
- probe memcached_delete_end();
- probe memcached_increment_with_initial_start();
- probe memcached_increment_with_initial_end();
- probe memcached_decrement_with_initial_start();
- probe memcached_decrement_with_initial_end();
- probe memcached_increment_start();
- probe memcached_increment_end();
- probe memcached_decrement_start();
- probe memcached_decrement_end();
- probe memcached_flush_start();
- probe memcached_flush_end();
- probe memcached_set_start();
- probe memcached_set_end();
- probe memcached_add_start();
- probe memcached_add_end();
- probe memcached_replace_start();
- probe memcached_replace_end();
- probe memcached_get_start();
- probe memcached_get_end();
- probe memcached_touch_start();
- probe memcached_touch_end();
- probe memcached_mget_start();
- probe memcached_mget_end();
- probe memcached_connect_start();
- probe memcached_connect_end();
- probe memcached_server_add_start();
- probe memcached_server_add_end();
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-/*
- * This file contains the definition of the various probes supported by
- * libmemcached. Currently it only support DTRACE, but just create an
- * implementation of the following macros to create your own sort of
- * probing :)
- */
-
-#ifdef HAVE_DTRACE
-/*
- * Create the DTrace probes on the system using it (to support both Solaris
- * and MacOS X
- */
-#include "libmemcached/dtrace_probes.h"
-
-#else
-/*
- * Provide dummy macros so that we don't need to clutter the code with
- * ifdefs when we want to use the probes.
- */
-
-#define LIBMEMCACHED_MEMCACHED_ADD_END()
-#define LIBMEMCACHED_MEMCACHED_ADD_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_ADD_START()
-#define LIBMEMCACHED_MEMCACHED_ADD_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_CONNECT_END()
-#define LIBMEMCACHED_MEMCACHED_CONNECT_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_CONNECT_START()
-#define LIBMEMCACHED_MEMCACHED_CONNECT_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_DECREMENT_END()
-#define LIBMEMCACHED_MEMCACHED_DECREMENT_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_DECREMENT_START()
-#define LIBMEMCACHED_MEMCACHED_DECREMENT_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_DECREMENT_WITH_INITIAL_END()
-#define LIBMEMCACHED_MEMCACHED_DECREMENT_WITH_INITIAL_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_DECREMENT_WITH_INITIAL_START()
-#define LIBMEMCACHED_MEMCACHED_DECREMENT_WITH_INITIAL_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_DELETE_END()
-#define LIBMEMCACHED_MEMCACHED_DELETE_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_DELETE_START()
-#define LIBMEMCACHED_MEMCACHED_DELETE_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_FLUSH_END()
-#define LIBMEMCACHED_MEMCACHED_FLUSH_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_FLUSH_START()
-#define LIBMEMCACHED_MEMCACHED_FLUSH_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_GET_END()
-#define LIBMEMCACHED_MEMCACHED_GET_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_GET_START()
-#define LIBMEMCACHED_MEMCACHED_GET_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_TOUCH_END()
-#define LIBMEMCACHED_MEMCACHED_TOUCH_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_TOUCH_START()
-#define LIBMEMCACHED_MEMCACHED_TOUCH_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_INCREMENT_END()
-#define LIBMEMCACHED_MEMCACHED_INCREMENT_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_INCREMENT_START()
-#define LIBMEMCACHED_MEMCACHED_INCREMENT_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END()
-#define LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START()
-#define LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_MGET_END()
-#define LIBMEMCACHED_MEMCACHED_MGET_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_MGET_START()
-#define LIBMEMCACHED_MEMCACHED_MGET_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_REPLACE_END()
-#define LIBMEMCACHED_MEMCACHED_REPLACE_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_REPLACE_START()
-#define LIBMEMCACHED_MEMCACHED_REPLACE_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_SERVER_ADD_END()
-#define LIBMEMCACHED_MEMCACHED_SERVER_ADD_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_SERVER_ADD_START()
-#define LIBMEMCACHED_MEMCACHED_SERVER_ADD_START_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_SET_END()
-#define LIBMEMCACHED_MEMCACHED_SET_END_ENABLED() (0)
-#define LIBMEMCACHED_MEMCACHED_SET_START()
-#define LIBMEMCACHED_MEMCACHED_SET_START_ENABLED() (0)
-
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-#include <libmemcached/options.hpp>
-#include <libmemcached/virtual_bucket.h>
-
-static inline bool _memcached_init(Memcached *self)
-{
- self->state.is_purging= false;
- self->state.is_processing_input= false;
- self->state.is_time_for_rebuild= false;
- self->state.is_parsing= false;
-
- self->flags.auto_eject_hosts= false;
- self->flags.binary_protocol= false;
- self->flags.buffer_requests= false;
- self->flags.hash_with_namespace= false;
- self->flags.no_block= false;
- self->flags.reply= true;
- self->flags.randomize_replica_read= false;
- self->flags.support_cas= false;
- self->flags.tcp_nodelay= false;
- self->flags.use_sort_hosts= false;
- self->flags.use_udp= false;
- self->flags.verify_key= false;
- self->flags.tcp_keepalive= false;
- self->flags.is_aes= false;
- self->flags.is_fetching_version= false;
-
- self->virtual_bucket= NULL;
-
- self->distribution= MEMCACHED_DISTRIBUTION_MODULA;
-
- if (hashkit_create(&self->hashkit) == NULL)
- {
- return false;
- }
-
- self->server_info.version= 0;
-
- self->ketama.continuum= NULL;
- self->ketama.continuum_count= 0;
- self->ketama.continuum_points_counter= 0;
- self->ketama.next_distribution_rebuild= 0;
- self->ketama.weighted_= false;
-
- self->number_of_hosts= 0;
- self->servers= NULL;
- self->last_disconnected_server= NULL;
-
- self->snd_timeout= 0;
- self->rcv_timeout= 0;
- self->server_failure_limit= MEMCACHED_SERVER_FAILURE_LIMIT;
- self->server_timeout_limit= MEMCACHED_SERVER_TIMEOUT_LIMIT;
- self->query_id= 1; // 0 is considered invalid
-
- /* TODO, Document why we picked these defaults */
- self->io_msg_watermark= 500;
- self->io_bytes_watermark= 65 * 1024;
-
- self->tcp_keepidle= 0;
-
- self->io_key_prefetch= 0;
- self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
- self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
- self->retry_timeout= MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT;
- self->dead_timeout= MEMCACHED_SERVER_FAILURE_DEAD_TIMEOUT;
-
- self->send_size= -1;
- self->recv_size= -1;
-
- self->user_data= NULL;
- self->number_of_replicas= 0;
-
- self->allocators= memcached_allocators_return_default();
-
- self->on_clone= NULL;
- self->on_cleanup= NULL;
- self->get_key_failure= NULL;
- self->delete_trigger= NULL;
- self->callbacks= NULL;
- self->sasl.callbacks= NULL;
- self->sasl.is_allocated= false;
-
- self->error_messages= NULL;
- self->_namespace= NULL;
- self->configure.initial_pool_size= 1;
- self->configure.max_pool_size= 1;
- self->configure.version= -1;
- self->configure.filename= NULL;
-
- return true;
-}
-
-static void __memcached_free(Memcached *ptr, bool release_st)
-{
- /* If we have anything open, lets close it now */
- send_quit(ptr);
- memcached_instance_list_free(memcached_instance_list(ptr), memcached_instance_list_count(ptr));
- memcached_result_free(&ptr->result);
-
- memcached_virtual_bucket_free(ptr);
-
- memcached_instance_free((memcached_instance_st*)ptr->last_disconnected_server);
-
- if (ptr->on_cleanup)
- {
- ptr->on_cleanup(ptr);
- }
-
- libmemcached_free(ptr, ptr->ketama.continuum);
- ptr->ketama.continuum= NULL;
-
- memcached_array_free(ptr->_namespace);
- ptr->_namespace= NULL;
-
- memcached_error_free(*ptr);
-
- if (LIBMEMCACHED_WITH_SASL_SUPPORT and ptr->sasl.callbacks)
- {
- memcached_destroy_sasl_auth_data(ptr);
- }
-
- if (release_st)
- {
- memcached_array_free(ptr->configure.filename);
- ptr->configure.filename= NULL;
- }
-
- hashkit_free(&ptr->hashkit);
-
- if (memcached_is_allocated(ptr) and release_st)
- {
- libmemcached_free(ptr, ptr);
- }
-}
-
-memcached_st *memcached_create(memcached_st *shell)
-{
- if (shell)
- {
- shell->options.is_allocated= false;
- }
- else
- {
- shell= (memcached_st *)libmemcached_xmalloc(NULL, memcached_st);
-
- if (shell == NULL)
- {
- return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
- }
-
- shell->options.is_allocated= true;
- }
-
- if (_memcached_init(shell) == false)
- {
- memcached_free(shell);
- return NULL;
- }
-
- Memcached* memc= memcached2Memcached(shell);
- if (memcached_result_create(shell, &memc->result) == NULL)
- {
- memcached_free(shell);
- return NULL;
- }
-
- WATCHPOINT_ASSERT_INITIALIZED(&memc->result);
-
- return shell;
-}
-
-memcached_st *memcached(const char *string, size_t length)
-{
- if (length == 0 and string)
- {
- return NULL;
- }
-
- if (length and string == NULL)
- {
- return NULL;
- }
-
- if (length == 0)
- {
- if (bool(getenv("LIBMEMCACHED")))
- {
- string= getenv("LIBMEMCACHED");
- length= string ? strlen(string) : 0;
- }
- }
-
- memcached_st *memc= memcached_create(NULL);
- if (memc == NULL)
- {
- return NULL;
- }
-
- if (length == 0 or string == NULL)
- {
- return memc;
- }
-
- memcached_return_t rc= memcached_parse_configuration(memc, string, length);
- if (memcached_success(rc) and memcached_parse_filename(memc))
- {
- rc= memcached_parse_configure_file(*memc, memcached_parse_filename(memc), memcached_parse_filename_length(memc));
- }
-
- if (memcached_failed(rc))
- {
- memcached_free(memc);
- return NULL;
- }
-
- return memc;
-}
-
-memcached_return_t memcached_reset(memcached_st *shell)
-{
- Memcached* ptr= memcached2Memcached(shell);
- WATCHPOINT_ASSERT(ptr);
- if (ptr == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- bool stored_is_allocated= memcached_is_allocated(ptr);
- uint64_t query_id= ptr->query_id;
- __memcached_free(ptr, false);
- memcached_create(ptr);
- memcached_set_allocated(ptr, stored_is_allocated);
- ptr->query_id= query_id;
-
- if (ptr->configure.filename)
- {
- return memcached_parse_configure_file(*ptr, memcached_param_array(ptr->configure.filename));
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-void memcached_servers_reset(memcached_st *shell)
-{
- Memcached* self= memcached2Memcached(shell);
- if (self)
- {
- libmemcached_free(self, self->ketama.continuum);
- self->ketama.continuum= NULL;
- self->ketama.continuum_count= 0;
- self->ketama.continuum_points_counter= 0;
-
- memcached_instance_list_free(memcached_instance_list(self), self->number_of_hosts);
- memcached_instance_set(self, NULL, 0);
-
- memcached_reset_last_disconnected_server(self);
- }
-}
-
-void memcached_reset_last_disconnected_server(memcached_st *shell)
-{
- Memcached* self= memcached2Memcached(shell);
- if (self)
- {
- memcached_instance_free((memcached_instance_st*)self->last_disconnected_server);
- self->last_disconnected_server= NULL;
- }
-}
-
-void memcached_free(memcached_st *ptr)
-{
- if (ptr)
- {
- __memcached_free(ptr, true);
- }
-}
-
-/*
- clone is the destination, while source is the structure to clone.
- If source is NULL the call is the same as if a memcached_create() was
- called.
-*/
-memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
-{
- if (source == NULL)
- {
- return memcached_create(clone);
- }
-
- if (clone and memcached_is_allocated(clone))
- {
- return NULL;
- }
-
- memcached_st *new_clone= memcached_create(clone);
-
- if (new_clone == NULL)
- {
- return NULL;
- }
-
- new_clone->flags= source->flags;
- new_clone->send_size= source->send_size;
- new_clone->recv_size= source->recv_size;
- new_clone->poll_timeout= source->poll_timeout;
- new_clone->connect_timeout= source->connect_timeout;
- new_clone->retry_timeout= source->retry_timeout;
- new_clone->dead_timeout= source->dead_timeout;
- new_clone->distribution= source->distribution;
-
- if (hashkit_clone(&new_clone->hashkit, &source->hashkit) == NULL)
- {
- memcached_free(new_clone);
- return NULL;
- }
-
- new_clone->user_data= source->user_data;
-
- new_clone->snd_timeout= source->snd_timeout;
- new_clone->rcv_timeout= source->rcv_timeout;
-
- new_clone->on_clone= source->on_clone;
- new_clone->on_cleanup= source->on_cleanup;
-
- new_clone->allocators= source->allocators;
-
- new_clone->get_key_failure= source->get_key_failure;
- new_clone->delete_trigger= source->delete_trigger;
- new_clone->server_failure_limit= source->server_failure_limit;
- new_clone->server_timeout_limit= source->server_timeout_limit;
- new_clone->io_msg_watermark= source->io_msg_watermark;
- new_clone->io_bytes_watermark= source->io_bytes_watermark;
- new_clone->io_key_prefetch= source->io_key_prefetch;
- new_clone->number_of_replicas= source->number_of_replicas;
- new_clone->tcp_keepidle= source->tcp_keepidle;
-
- if (memcached_server_count(source))
- {
- if (memcached_failed(memcached_push(new_clone, source)))
- {
- return NULL;
- }
- }
-
-
- new_clone->_namespace= memcached_array_clone(new_clone, source->_namespace);
- new_clone->configure.filename= memcached_array_clone(new_clone, source->_namespace);
- new_clone->configure.version= source->configure.version;
-
- if (LIBMEMCACHED_WITH_SASL_SUPPORT and source->sasl.callbacks)
- {
- if (memcached_failed(memcached_clone_sasl(new_clone, source)))
- {
- memcached_free(new_clone);
- return NULL;
- }
- }
-
- if (memcached_failed(run_distribution(new_clone)))
- {
- memcached_free(new_clone);
-
- return NULL;
- }
-
- if (source->on_clone)
- {
- source->on_clone(new_clone, source);
- }
-
- return new_clone;
-}
-
-void *memcached_get_user_data(const memcached_st *shell)
-{
- const Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- return memc->user_data;
- }
-
- return NULL;
-}
-
-void *memcached_set_user_data(memcached_st *shell, void *data)
-{
- Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- void *ret= memc->user_data;
- memc->user_data= data;
-
- return ret;
- }
-
- return NULL;
-}
-
-memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
-{
- return memcached_instance_push(destination, (memcached_instance_st*)source->servers, source->number_of_hosts);
-}
-
-memcached_instance_st* memcached_instance_fetch(Memcached *ptr, uint32_t server_key)
-{
- if (ptr == NULL)
- {
- return NULL;
- }
-
- return &ptr->servers[server_key];
-}
-
-const memcached_instance_st * memcached_server_instance_by_position(const memcached_st *shell, uint32_t server_key)
-{
- const Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- return &memc->servers[server_key];
- }
-
- return NULL;
-}
-
-memcached_instance_st* memcached_instance_by_position(const memcached_st *shell, uint32_t server_key)
-{
- const Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- return &memc->servers[server_key];
- }
-
- return NULL;
-}
-
-uint64_t memcached_query_id(const memcached_st *shell)
-{
- const Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- return memc->query_id;
- }
-
- return 0;
-}
-
-memcached_instance_st* memcached_instance_list(const memcached_st *shell)
-{
- const Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- return (memcached_instance_st*)memc->servers;
- }
-
- return NULL;
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libmemcached-1.0/memcached.h>
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libmemcached-1.0/memcached.hpp>
-
+++ /dev/null
-For your convenience libmemcached contains a copy of protocol_binary.h so that
-you may compile libmemcached without having a memcached server with support
-for the binary protocol installed on your computer. Please do not modify this
-fine, but replace it with a fresh copy from a new distribution if they are
-out of sync.
-
-Trond Norbye
+++ /dev/null
-/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) <2008>, Sun Microsystems, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*
- * Summary: Constants used by to implement the binary protocol.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Trond Norbye <trond.norbye@sun.com>
- */
-
-#ifndef PROTOCOL_BINARY_H
-#define PROTOCOL_BINARY_H
-
-#include <libmemcachedprotocol-0.0/vbucket.h>
-
-/**
- * \addtogroup Protocol
- * @{
- */
-
-/**
- * This file contains definitions of the constants and packet formats
- * defined in the binary specification. Please note that you _MUST_ remember
- * to convert each multibyte field to / from network byte order to / from
- * host order.
- */
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
- /**
- * Definition of the legal "magic" values used in a packet.
- * See section 3.1 Magic byte
- */
- typedef enum {
- PROTOCOL_BINARY_REQ = 0x80,
- PROTOCOL_BINARY_RES = 0x81
- } protocol_binary_magic;
-
- /**
- * Definition of the valid response status numbers.
- * See section 3.2 Response Status
- */
- typedef enum {
- PROTOCOL_BINARY_RESPONSE_SUCCESS = 0x00,
- PROTOCOL_BINARY_RESPONSE_KEY_ENOENT = 0x01,
- PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS = 0x02,
- PROTOCOL_BINARY_RESPONSE_E2BIG = 0x03,
- PROTOCOL_BINARY_RESPONSE_EINVAL = 0x04,
- PROTOCOL_BINARY_RESPONSE_NOT_STORED = 0x05,
- PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL = 0x06,
- PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET = 0x07,
- PROTOCOL_BINARY_RESPONSE_AUTH_ERROR = 0x20,
- PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE = 0x21,
- PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND = 0x81,
- PROTOCOL_BINARY_RESPONSE_ENOMEM = 0x82,
- PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED = 0x83,
- PROTOCOL_BINARY_RESPONSE_EINTERNAL = 0x84,
- PROTOCOL_BINARY_RESPONSE_EBUSY = 0x85,
- PROTOCOL_BINARY_RESPONSE_ETMPFAIL = 0x86
- } protocol_binary_response_status;
-
- /**
- * Defintion of the different command opcodes.
- * See section 3.3 Command Opcodes
- */
- typedef enum {
- PROTOCOL_BINARY_CMD_GET = 0x00,
- PROTOCOL_BINARY_CMD_SET = 0x01,
- PROTOCOL_BINARY_CMD_ADD = 0x02,
- PROTOCOL_BINARY_CMD_REPLACE = 0x03,
- PROTOCOL_BINARY_CMD_DELETE = 0x04,
- PROTOCOL_BINARY_CMD_INCREMENT = 0x05,
- PROTOCOL_BINARY_CMD_DECREMENT = 0x06,
- PROTOCOL_BINARY_CMD_QUIT = 0x07,
- PROTOCOL_BINARY_CMD_FLUSH = 0x08,
- PROTOCOL_BINARY_CMD_GETQ = 0x09,
- PROTOCOL_BINARY_CMD_NOOP = 0x0a,
- PROTOCOL_BINARY_CMD_VERSION = 0x0b,
- PROTOCOL_BINARY_CMD_GETK = 0x0c,
- PROTOCOL_BINARY_CMD_GETKQ = 0x0d,
- PROTOCOL_BINARY_CMD_APPEND = 0x0e,
- PROTOCOL_BINARY_CMD_PREPEND = 0x0f,
- PROTOCOL_BINARY_CMD_STAT = 0x10,
- PROTOCOL_BINARY_CMD_SETQ = 0x11,
- PROTOCOL_BINARY_CMD_ADDQ = 0x12,
- PROTOCOL_BINARY_CMD_REPLACEQ = 0x13,
- PROTOCOL_BINARY_CMD_DELETEQ = 0x14,
- PROTOCOL_BINARY_CMD_INCREMENTQ = 0x15,
- PROTOCOL_BINARY_CMD_DECREMENTQ = 0x16,
- PROTOCOL_BINARY_CMD_QUITQ = 0x17,
- PROTOCOL_BINARY_CMD_FLUSHQ = 0x18,
- PROTOCOL_BINARY_CMD_APPENDQ = 0x19,
- PROTOCOL_BINARY_CMD_PREPENDQ = 0x1a,
- PROTOCOL_BINARY_CMD_VERBOSITY = 0x1b,
- PROTOCOL_BINARY_CMD_TOUCH = 0x1c,
- PROTOCOL_BINARY_CMD_GAT = 0x1d,
- PROTOCOL_BINARY_CMD_GATQ = 0x1e,
- PROTOCOL_BINARY_CMD_GATK = 0x23,
- PROTOCOL_BINARY_CMD_GATKQ = 0x24,
-
- PROTOCOL_BINARY_CMD_SASL_LIST_MECHS = 0x20,
- PROTOCOL_BINARY_CMD_SASL_AUTH = 0x21,
- PROTOCOL_BINARY_CMD_SASL_STEP = 0x22,
-
- /* These commands are used for range operations and exist within
- * this header for use in other projects. Range operations are
- * not expected to be implemented in the memcached server itself.
- */
- PROTOCOL_BINARY_CMD_RGET = 0x30,
- PROTOCOL_BINARY_CMD_RSET = 0x31,
- PROTOCOL_BINARY_CMD_RSETQ = 0x32,
- PROTOCOL_BINARY_CMD_RAPPEND = 0x33,
- PROTOCOL_BINARY_CMD_RAPPENDQ = 0x34,
- PROTOCOL_BINARY_CMD_RPREPEND = 0x35,
- PROTOCOL_BINARY_CMD_RPREPENDQ = 0x36,
- PROTOCOL_BINARY_CMD_RDELETE = 0x37,
- PROTOCOL_BINARY_CMD_RDELETEQ = 0x38,
- PROTOCOL_BINARY_CMD_RINCR = 0x39,
- PROTOCOL_BINARY_CMD_RINCRQ = 0x3a,
- PROTOCOL_BINARY_CMD_RDECR = 0x3b,
- PROTOCOL_BINARY_CMD_RDECRQ = 0x3c,
- /* End Range operations */
-
- /* VBucket commands */
- PROTOCOL_BINARY_CMD_SET_VBUCKET = 0x3d,
- PROTOCOL_BINARY_CMD_GET_VBUCKET = 0x3e,
- PROTOCOL_BINARY_CMD_DEL_VBUCKET = 0x3f,
- /* End VBucket commands */
-
- /* TAP commands */
- PROTOCOL_BINARY_CMD_TAP_CONNECT = 0x40,
- PROTOCOL_BINARY_CMD_TAP_MUTATION = 0x41,
- PROTOCOL_BINARY_CMD_TAP_DELETE = 0x42,
- PROTOCOL_BINARY_CMD_TAP_FLUSH = 0x43,
- PROTOCOL_BINARY_CMD_TAP_OPAQUE = 0x44,
- PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET = 0x45,
- PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START = 0x46,
- PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END = 0x47,
- /* End TAP */
-
- PROTOCOL_BINARY_CMD_LAST_RESERVED = 0xef,
-
- /* Scrub the data */
- PROTOCOL_BINARY_CMD_SCRUB = 0xf0
- } protocol_binary_command;
-
- /**
- * Definition of the data types in the packet
- * See section 3.4 Data Types
- */
- typedef enum {
- PROTOCOL_BINARY_RAW_BYTES = 0x00
- } protocol_binary_datatypes;
-
- /**
- * Definition of the header structure for a request packet.
- * See section 2
- */
- typedef union {
- struct {
- uint8_t magic;
- uint8_t opcode;
- uint16_t keylen;
- uint8_t extlen;
- uint8_t datatype;
- uint16_t vbucket;
- uint32_t bodylen;
- uint32_t opaque;
- uint64_t cas;
- } request;
- uint8_t bytes[24];
- } protocol_binary_request_header;
-
- /**
- * Definition of the header structure for a response packet.
- * See section 2
- */
- typedef union {
- struct {
- uint8_t magic;
- uint8_t opcode;
- uint16_t keylen;
- uint8_t extlen;
- uint8_t datatype;
- uint16_t status;
- uint32_t bodylen;
- uint32_t opaque;
- uint64_t cas;
- } response;
- uint8_t bytes[24];
- } protocol_binary_response_header;
-
- /**
- * Definition of a request-packet containing no extras
- */
- union protocol_binary_request_no_extras {
- struct {
- protocol_binary_request_header header;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header)];
- };
- typedef union protocol_binary_request_no_extras protocol_binary_request_no_extras;
-
- /**
- * Definition of a response-packet containing no extras
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- } message;
- uint8_t bytes[sizeof(protocol_binary_response_header)];
- } protocol_binary_response_no_extras;
-
- /**
- * Definition of the packet used by the get, getq, getk and getkq command.
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_get;
- typedef protocol_binary_request_no_extras protocol_binary_request_getq;
- typedef protocol_binary_request_no_extras protocol_binary_request_getk;
- typedef protocol_binary_request_no_extras protocol_binary_request_getkq;
-
- /**
- * Definition of the packet returned from a successful get, getq, getk and
- * getkq.
- * See section 4
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- struct {
- uint32_t flags;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_response_header) + 4];
- } protocol_binary_response_get;
-
- typedef protocol_binary_response_get protocol_binary_response_getq;
- typedef protocol_binary_response_get protocol_binary_response_getk;
- typedef protocol_binary_response_get protocol_binary_response_getkq;
-
- /**
- * Definition of the packet used by the delete command
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_delete;
-
- /**
- * Definition of the packet returned by the delete command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_delete;
-
- /**
- * Definition of the packet used by the flush command
- * See section 4
- * Please note that the expiration field is optional, so remember to see
- * check the header.bodysize to see if it is present.
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_flush;
-
- /**
- * Definition of the packet returned by the flush command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_flush;
-
- /**
- * Definition of the packet used by set, add and replace
- * See section 4
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t flags;
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 8];
- } protocol_binary_request_set;
- typedef protocol_binary_request_set protocol_binary_request_add;
- typedef protocol_binary_request_set protocol_binary_request_replace;
-
- /**
- * Definition of the packet returned by set, add and replace
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_set;
- typedef protocol_binary_response_no_extras protocol_binary_response_add;
- typedef protocol_binary_response_no_extras protocol_binary_response_replace;
-
- /**
- * Definition of the noop packet
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_noop;
-
- /**
- * Definition of the packet returned by the noop command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_noop;
-
- /**
- * Definition of the structure used by the increment and decrement
- * command.
- * See section 4
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint64_t delta;
- uint64_t initial;
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 20];
- } protocol_binary_request_incr;
- typedef protocol_binary_request_incr protocol_binary_request_decr;
-
- /**
- * Definition of the response from an incr or decr command
- * command.
- * See section 4
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- struct {
- uint64_t value;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_response_header) + 8];
- } protocol_binary_response_incr;
- typedef protocol_binary_response_incr protocol_binary_response_decr;
-
- /**
- * Definition of the quit
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_quit;
-
- /**
- * Definition of the packet returned by the quit command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_quit;
-
- /**
- * Definition of the packet used by append and prepend command
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_append;
- typedef protocol_binary_request_no_extras protocol_binary_request_prepend;
-
- /**
- * Definition of the packet returned from a successful append or prepend
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_append;
- typedef protocol_binary_response_no_extras protocol_binary_response_prepend;
-
- /**
- * Definition of the packet used by the version command
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_version;
-
- /**
- * Definition of the packet returned from a successful version command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_version;
-
-
- /**
- * Definition of the packet used by the stats command.
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_stats;
-
- /**
- * Definition of the packet returned from a successful stats command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_stats;
-
- /**
- * Definition of the packet used by the verbosity command
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t level;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_verbosity;
-
- /**
- * Definition of the packet returned from the verbosity command
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_verbosity;
-
- /**
- * Definition of the packet used by the touch command.
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_touch;
-
- /**
- * Definition of the packet returned from the touch command
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_touch;
-
- /**
- * Definition of the packet used by the GAT(Q) command.
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_gat;
-
- typedef protocol_binary_request_gat protocol_binary_request_gatq;
-
- /**
- * Definition of the packet returned from the GAT(Q)
- */
- typedef protocol_binary_response_get protocol_binary_response_gat;
- typedef protocol_binary_response_get protocol_binary_response_gatq;
-
-
- /**
- * Definition of a request for a range operation.
- * See http://code.google.com/p/memcached/wiki/RangeOps
- *
- * These types are used for range operations and exist within
- * this header for use in other projects. Range operations are
- * not expected to be implemented in the memcached server itself.
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- struct {
- uint16_t size;
- uint8_t reserved;
- uint8_t flags;
- uint32_t max_results;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_rangeop;
-
- typedef protocol_binary_request_rangeop protocol_binary_request_rget;
- typedef protocol_binary_request_rangeop protocol_binary_request_rset;
- typedef protocol_binary_request_rangeop protocol_binary_request_rsetq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rappend;
- typedef protocol_binary_request_rangeop protocol_binary_request_rappendq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rprepend;
- typedef protocol_binary_request_rangeop protocol_binary_request_rprependq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rdelete;
- typedef protocol_binary_request_rangeop protocol_binary_request_rdeleteq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rincr;
- typedef protocol_binary_request_rangeop protocol_binary_request_rincrq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rdecr;
- typedef protocol_binary_request_rangeop protocol_binary_request_rdecrq;
-
-
- /**
- * Definition of tap commands
- * See To be written
- *
- */
-
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- /**
- * flags is a bitmask used to set properties for the
- * the connection. Please In order to be forward compatible
- * you should set all undefined bits to 0.
- *
- * If the bit require extra userdata, it will be stored
- * in the user-data field of the body (passed to the engine
- * as enginespeciffic). That means that when you parse the
- * flags and the engine-specific data, you have to work your
- * way from bit 0 and upwards to find the correct offset for
- * the data.
- *
- */
- uint32_t flags;
-
- /**
- * Backfill age
- *
- * By using this flag you can limit the amount of data being
- * transmitted. If you don't specify a backfill age, the
- * server will transmit everything it contains.
- *
- * The first 8 bytes in the engine specific data contains
- * the oldest entry (from epoc) you're interested in.
- * Specifying a time in the future (for the server you are
- * connecting to), will cause it to start streaming current
- * changes.
- */
-#define TAP_CONNECT_FLAG_BACKFILL 0x01
- /**
- * Dump will cause the server to send the data stored on the
- * server, but disconnect when the keys stored in the server
- * are transmitted.
- */
-#define TAP_CONNECT_FLAG_DUMP 0x02
- /**
- * The body contains a list of 16 bits words in network byte
- * order specifying the vbucket ids to monitor. The first 16
- * bit word contains the number of buckets. The number of 0
- * means "all buckets"
- */
-#define TAP_CONNECT_FLAG_LIST_VBUCKETS 0x04
- /**
- * The responsibility of the vbuckets is to be transferred
- * over to the caller when all items are transferred.
- */
-#define TAP_CONNECT_FLAG_TAKEOVER_VBUCKETS 0x08
- /**
- * The tap consumer supports ack'ing of tap messages
- */
-#define TAP_CONNECT_SUPPORT_ACK 0x10
- /**
- * The tap consumer would prefer to just get the keys
- * back. If the engine supports this it will set
- * the TAP_FLAG_NO_VALUE flag in each of the
- * tap packets returned.
- */
-#define TAP_CONNECT_REQUEST_KEYS_ONLY 0x20
- /**
- * The body contains a list of (vbucket_id, last_checkpoint_id)
- * pairs. This provides the checkpoint support in TAP streams.
- * The last checkpoint id represents the last checkpoint that
- * was successfully persisted.
- */
-#define TAP_CONNECT_CHECKPOINT 0x40
- /**
- * The tap consumer is a registered tap client, which means that
- * the tap server will maintain its checkpoint cursor permanently.
- */
-#define TAP_CONNECT_REGISTERED_CLIENT 0x80
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_tap_connect;
-
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- struct {
- uint16_t enginespecific_length;
- /*
- * The flag section support the following flags
- */
- /**
- * Request that the consumer send a response packet
- * for this packet. The opaque field must be preserved
- * in the response.
- */
-#define TAP_FLAG_ACK 0x01
- /**
- * The value for the key is not included in the packet
- */
-#define TAP_FLAG_NO_VALUE 0x02
- uint16_t flags;
- uint8_t ttl;
- uint8_t res1;
- uint8_t res2;
- uint8_t res3;
- } tap;
- struct {
- uint32_t flags;
- uint32_t expiration;
- } item;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 16];
- } protocol_binary_request_tap_mutation;
-
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- struct {
- uint16_t enginespecific_length;
- /**
- * See the definition of the flags for
- * protocol_binary_request_tap_mutation for a description
- * of the available flags.
- */
- uint16_t flags;
- uint8_t ttl;
- uint8_t res1;
- uint8_t res2;
- uint8_t res3;
- } tap;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 8];
- } protocol_binary_request_tap_no_extras;
-
- typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_delete;
- typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_flush;
- typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_opaque;
- typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_vbucket_set;
-
-
- /**
- * Definition of the packet used by the scrub.
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_scrub;
-
- /**
- * Definition of the packet returned from scrub.
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_scrub;
-
-
- /**
- * Definition of the packet used by set vbucket
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- vbucket_state_t state;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + sizeof(vbucket_state_t)];
- } protocol_binary_request_set_vbucket;
- /**
- * Definition of the packet returned from set vbucket
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_set_vbucket;
- /**
- * Definition of the packet used by del vbucket
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_del_vbucket;
- /**
- * Definition of the packet returned from del vbucket
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_del_vbucket;
-
- /**
- * Definition of the packet used by get vbucket
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_get_vbucket;
-
- /**
- * Definition of the packet returned from get vbucket
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- struct {
- vbucket_state_t state;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_response_header) + sizeof(vbucket_state_t)];
- } protocol_binary_response_get_vbucket;
-
-
- /**
- * @}
- */
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* PROTOCOL_BINARY_H */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-typedef enum {
- vbucket_state_active = 1, /**< Actively servicing a vbucket. */
- vbucket_state_replica, /**< Servicing a vbucket as a replica only. */
- vbucket_state_pending, /**< Pending active. */
- vbucket_state_dead /**< Not in use, pending deletion. */
-} vbucket_state_t;
-
-#define is_valid_vbucket_state_t(state) \
- (state == vbucket_state_active || \
- state == vbucket_state_replica || \
- state == vbucket_state_pending || \
- state == vbucket_state_dead)
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <mem_config.h>
-
-#include <libmemcached/common.h>
-
-#ifdef __cplusplus
-#include <cstddef>
-#include <cstdlib>
-#else
-#include <stddef.h>
-#include <stdlib.h>
-#endif
-
-static inline void libmemcached_free(const memcached_st *self, void *mem)
-{
- if (self)
- {
- self->allocators.free(self, mem, self->allocators.context);
- }
- else if (mem)
- {
-#ifdef __cplusplus
- std::free(mem);
-#else
- free(mem);
-#endif
- }
-}
-
-static inline void *libmemcached_malloc(const memcached_st *self, const size_t size)
-{
- if (self)
- {
- return self->allocators.malloc(self, size, self->allocators.context);
- }
-
-#ifdef __cplusplus
- return std::malloc(size);
-#else
- return malloc(size);
-#endif
-}
-#define libmemcached_xmalloc(__memcachd_st, __type) ((__type *)libmemcached_malloc((__memcachd_st), sizeof(__type)))
-
-static inline void *libmemcached_realloc(const memcached_st *self, void *mem, size_t nmemb, const size_t size)
-{
- if (self)
- {
- return self->allocators.realloc(self, mem, nmemb * size, self->allocators.context);
- }
-
-#ifdef __cplusplus
- return std::realloc(mem, size);
-#else
- return realloc(mem, size);
-#endif
-}
-#define libmemcached_xrealloc(__memcachd_st, __mem, __nelem, __type) ((__type *)libmemcached_realloc((__memcachd_st), (__mem), (__nelem), sizeof(__type)))
-#define libmemcached_xvalloc(__memcachd_st, __nelem, __type) ((__type *)libmemcached_realloc((__memcachd_st), NULL, (__nelem), sizeof(__type)))
-
-static inline void *libmemcached_calloc(const memcached_st *self, size_t nelem, size_t size)
-{
- if (self)
- {
- return self->allocators.calloc(self, nelem, size, self->allocators.context);
- }
-
-#ifdef __cplusplus
- return std::calloc(nelem, size);
-#else
- return calloc(nelem, size);
-#endif
-}
-#define libmemcached_xcalloc(__memcachd_st, __nelem, __type) ((__type *)libmemcached_calloc((__memcachd_st), (__nelem), sizeof(__type)))
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libmemcached/common.h"
-#include "libmemcached/assert.hpp"
-
-memcached_return_t memcached_set_namespace(Memcached& memc, const char *key, size_t key_length)
-{
- if (key and key_length == 0)
- {
- WATCHPOINT_ASSERT(key_length);
- return memcached_set_error(memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid namespace, namespace string had value but length was 0"));
- }
- else if (key_length and key == NULL)
- {
- WATCHPOINT_ASSERT(key);
- return memcached_set_error(memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid namespace, namespace string length was > 1 but namespace string was null "));
- }
- else if (key and key_length)
- {
- bool orig= memc.flags.verify_key;
- memc.flags.verify_key= true;
- if (memcached_failed(memcached_key_test(memc, (const char **)&key, &key_length, 1)))
- {
- memc.flags.verify_key= orig;
- return memcached_last_error(&memc);
- }
- memc.flags.verify_key= orig;
-
- if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1))
- {
- return memcached_set_error(memc, MEMCACHED_KEY_TOO_BIG, MEMCACHED_AT);
- }
-
- memcached_array_free(memc._namespace);
- memc._namespace= memcached_strcpy(&memc, key, key_length);
-
- if (memc._namespace == NULL)
- {
- return memcached_set_error(memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
- }
- else
- {
- memcached_array_free(memc._namespace);
- memc._namespace= NULL;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-const char * memcached_get_namespace(Memcached& memc)
-{
- if (memc._namespace == NULL)
- {
- return NULL;
- }
-
- return memcached_array_string(memc._namespace);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-
-memcached_return_t memcached_set_namespace(Memcached&, const char *str, size_t length);
-
-const char * memcached_get_namespace(Memcached&);
-
-#endif // __cplusplus
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-#include <libmemcached/options.hpp>
-
-#include <libmemcached/csl/context.h>
-
-const char *memcached_parse_filename(memcached_st *memc)
-{
- assert_msg(memc, "Invalid memcached_st");
- return memcached_array_string(memc->configure.filename);
-}
-
-size_t memcached_parse_filename_length(memcached_st *memc)
-{
- return memcached_array_size(memc->configure.filename);
-}
-
-static memcached_return_t _parse_file_options(memcached_st& self, memcached_array_st *real_name)
-{
- FILE *fp= fopen(memcached_array_string(real_name), "r");
- if (not fp)
- {
- memcached_string_t error_message= memcached_array_to_string(real_name);
- memcached_return_t rc= memcached_set_errno(self, errno, MEMCACHED_AT, error_message);
- return rc;
- }
-
- char buffer[BUFSIZ];
- memcached_return_t rc= MEMCACHED_INVALID_ARGUMENTS;
- while (fgets(buffer, sizeof(buffer), fp))
- {
- size_t length= strlen(buffer);
-
- if (length == 1 and buffer[0] == '\n')
- continue;
-
- if (memcached_failed(rc= memcached_parse_configuration(&self, buffer, length)))
- break;
- }
- fclose(fp);
-
- return rc;
-}
-
-memcached_return_t libmemcached_check_configuration(const char *option_string, size_t length, char *error_buffer, size_t error_buffer_size)
-{
- memcached_st memc, *memc_ptr;
-
- if (option_string == NULL or length == 0)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (error_buffer and error_buffer_size)
- {
- error_buffer[0]= 0;
- }
-
- if (not (memc_ptr= memcached_create(&memc)))
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- memcached_return_t rc= memcached_parse_configuration(memc_ptr, option_string, length);
- if (memcached_failed(rc) and error_buffer and error_buffer_size)
- {
- strncpy(error_buffer, memcached_last_error_message(memc_ptr), error_buffer_size);
- error_buffer[error_buffer_size -1]= 0;
- }
-
- bool has_filename= memcached_behavior_get(memc_ptr, MEMCACHED_BEHAVIOR_LOAD_FROM_FILE);
- if (memcached_success(rc) and has_filename)
- {
- assert_msg(memcached_parse_filename(memc_ptr), "Invalid configuration file");
- assert_msg(memcached_parse_filename_length(memc_ptr), "Invalid configuration file");
- rc= _parse_file_options(*memc_ptr, memc_ptr->configure.filename);
-
- if (memcached_failed(rc) and error_buffer and error_buffer_size)
- {
- strncpy(error_buffer, memcached_last_error_message(memc_ptr), error_buffer_size);
- error_buffer[error_buffer_size -1]= 0;
- }
- }
-
- memcached_free(memc_ptr);
-
- return rc;
-}
-
-memcached_return_t memcached_parse_configuration(memcached_st *self, char const *option_string, size_t length)
-{
- WATCHPOINT_ASSERT(self);
- if (not self)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- memcached_return_t rc;
- Context context(option_string, length, self, rc);
-
- context.start();
-
- return rc;
-}
-
-void memcached_set_configuration_file(memcached_st *self, const char *filename, size_t filename_length)
-{
- assert_msg(filename, "Invalid filename");
- assert_msg(filename_length, "Invalid filename_length");
- memcached_array_free(self->configure.filename);
- self->configure.filename= memcached_strcpy(self, filename, filename_length);
-}
-
-memcached_return_t memcached_parse_configure_file(memcached_st& self, const char *filename, size_t length)
-{
- if (not filename)
- {
- return memcached_set_error(self, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT);
- }
-
- WATCHPOINT_ASSERT(self);
- if (not length)
- {
- return memcached_set_error(self, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT);
- }
-
- memcached_array_st *tmp_array= memcached_strcpy(&self, filename, length);
-
- if (not tmp_array)
- {
- return memcached_set_error(self, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
-
- memcached_return_t rc= memcached_parse_configure_file(self, *tmp_array);
- memcached_array_free(tmp_array);
-
- return rc;
-}
-
-memcached_return_t memcached_parse_configure_file(memcached_st& self, memcached_array_st& filename)
-{
- WATCHPOINT_ASSERT(memcached_array_size(&filename));
- if (not memcached_array_size(&filename))
- {
- return memcached_set_error(self, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT);
- }
-
- return _parse_file_options(self, &filename);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-LIBMEMCACHED_LOCAL
- void memcached_set_configuration_file(memcached_st *self, const char *filename, size_t filename_length);
-
-LIBMEMCACHED_LOCAL
- const char *memcached_parse_filename(memcached_st *memc);
-
-LIBMEMCACHED_LOCAL
- memcached_return_t memcached_parse_configuration(memcached_st *ptr, const char *option_string, size_t length);
-
-LIBMEMCACHED_LOCAL
- size_t memcached_parse_filename_length(memcached_st *memc);
-
-LIBMEMCACHED_LOCAL
- memcached_return_t memcached_parse_configure_file(memcached_st&, const char *filename, size_t length);
-
-LIBMEMCACHED_LOCAL
- memcached_return_t memcached_parse_configure_file(memcached_st&, memcached_array_st& filename);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- I debated about putting this in the client library since it does an
- action I don't really believe belongs in the library.
-
- Frankly its too damn useful not to be here though.
-*/
-
-#include <libmemcached/common.h>
-
-memcached_server_list_st memcached_servers_parse(const char *server_strings)
-{
- char *string;
- const char *begin_ptr;
- const char *end_ptr;
- memcached_server_st *servers= NULL;
- memcached_return_t rc;
-
- WATCHPOINT_ASSERT(server_strings);
-
- end_ptr= server_strings + strlen(server_strings);
-
- for (begin_ptr= server_strings, string= (char *)index(server_strings, ',');
- begin_ptr != end_ptr;
- string= (char *)index(begin_ptr, ','))
- {
- char buffer[HUGE_STRING_LEN];
- char *ptr, *ptr2;
- uint32_t weight= 0;
-
- if (string)
- {
- memcpy(buffer, begin_ptr, (size_t) (string - begin_ptr));
- buffer[(unsigned int)(string - begin_ptr)]= 0;
- begin_ptr= string+1;
- }
- else
- {
- size_t length= strlen(begin_ptr);
- memcpy(buffer, begin_ptr, length);
- buffer[length]= 0;
- begin_ptr= end_ptr;
- }
-
- ptr= index(buffer, ':');
-
- in_port_t port= 0;
- if (ptr)
- {
- ptr[0]= 0;
-
- ptr++;
-
- errno= 0;
- port= (in_port_t) strtoul(ptr, (char **)NULL, 10);
- if (errno != 0)
- {
- memcached_server_free(servers);
- return NULL;
- }
-
- ptr2= index(ptr, ' ');
- if (! ptr2)
- ptr2= index(ptr, ':');
-
- if (ptr2)
- {
- ptr2++;
- errno= 0;
- weight= uint32_t(strtoul(ptr2, (char **)NULL, 10));
- if (errno != 0)
- {
- memcached_server_free(servers);
- return NULL;
- }
- }
- }
-
- servers= memcached_server_list_append_with_weight(servers, buffer, port, weight, &rc);
-
- if (isspace(*begin_ptr))
- {
- begin_ptr++;
- }
- }
-
- return servers;
-}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2013 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 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: Implementation of poll by using select
- *
- */
-
-#include "libmemcached/common.h"
-
-#if defined(_WIN32)
-#include "libmemcached/poll.h"
-
-#include <sys/time.h>
-#include <strings.h>
-
-int poll(struct pollfd fds[], nfds_t nfds, int tmo)
-{
- fd_set readfds, writefds, errorfds;
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
- FD_ZERO(&errorfds);
-
- int maxfd= 0;
-
- for (nfds_t x= 0; x < nfds; ++x)
- {
- if (fds[x].events & (POLLIN | POLLOUT))
- {
-#ifndef _WIN32
- if (fds[x].fd > maxfd)
- {
- maxfd= fds[x].fd;
- }
-#endif
- if (fds[x].events & POLLIN)
- {
- FD_SET(fds[x].fd, &readfds);
- }
- if (fds[x].events & POLLOUT)
- {
- FD_SET(fds[x].fd, &writefds);
- }
- }
- }
-
- struct timeval timeout= { .tv_sec = tmo / 1000,
- .tv_usec= (tmo % 1000) * 1000 };
- struct timeval *tp= &timeout;
- if (tmo == -1)
- {
- tp= NULL;
- }
- int ret= select(maxfd + 1, &readfds, &writefds, &errorfds, tp);
- if (ret <= 0)
- {
- return ret;
- }
-
- /* Iterate through all of them because I need to clear the revent map */
- for (nfds_t x= 0; x < nfds; ++x)
- {
- fds[x].revents= 0;
- if (FD_ISSET(fds[x].fd, &readfds))
- {
- fds[x].revents |= POLLIN;
- }
- if (FD_ISSET(fds[x].fd, &writefds))
- {
- fds[x].revents |= POLLOUT;
- }
- if (FD_ISSET(fds[x].fd, &errorfds))
- {
- fds[x].revents |= POLLERR;
- }
- }
-
- return ret;
-}
-
-#endif // defined(_WIN32)
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2013 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 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: Implementation of poll by using select
- *
- */
-
-#pragma once
-
-#if defined(_WIN32)
-
-#include <winsock2.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct pollfd
-{
-#if defined(_WIN32)
- SOCKET fd;
-#else
- int fd;
-#endif
- short events;
- short revents;
-} pollfd_t;
-
-typedef int nfds_t;
-
-#define POLLIN 0x0001
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x010 /* Hung up. */
-#define POLLNVAL 0x020 /* Invalid polling request. */
-
-int poll(struct pollfd fds[], nfds_t nfds, int tmo);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // defined(_WIN32)
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libmemcached/common.h>
-
-#define memcached_set_purging(__object, __value) ((__object)->state.is_purging= (__value))
-
-class Purge
-{
-public:
- Purge(Memcached* arg) :
- _memc(arg)
- {
- memcached_set_purging(_memc, true);
- }
-
- ~Purge()
- {
- memcached_set_purging(_memc, false);
- }
-
-private:
- Memcached* _memc;
-};
-
-class PollTimeout
-{
-public:
- PollTimeout(Memcached* arg) :
- _timeout(arg->poll_timeout),
- _origin(arg->poll_timeout)
- {
- _origin = 2000;
- }
-
- ~PollTimeout()
- {
- _origin= _timeout;
- }
-
-private:
- int32_t _timeout;
- int32_t& _origin;
-};
-
-bool memcached_purge(memcached_instance_st* ptr)
-{
- Memcached *root= (Memcached *)ptr->root;
-
- if (memcached_is_purging(ptr->root) || /* already purging */
- (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark &&
- ptr->io_bytes_sent < ptr->root->io_bytes_watermark) ||
- (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark &&
- memcached_server_response_count(ptr) < 2))
- {
- return true;
- }
-
- /*
- memcached_io_write and memcached_response may call memcached_purge
- so we need to be able stop any recursion..
- */
- Purge set_purge(root);
-
- WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
- /*
- 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) == false)
- {
- memcached_io_reset(ptr);
- memcached_set_error(*ptr, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
- return false;
- }
- WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
-
- bool is_successful= true;
- uint32_t no_msg= memcached_server_response_count(ptr);
- if (no_msg > 1)
- {
- memcached_result_st result;
-
- /*
- * 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
- */
- PollTimeout poll_timeout(ptr->root);
-
- memcached_result_st* result_ptr= memcached_result_create(root, &result);
- assert(result_ptr);
-
- for (uint32_t x= 0; x < no_msg - 1; x++)
- {
- memcached_result_reset(result_ptr);
- memcached_return_t rc= memcached_read_one_response(ptr, 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 or rc == MEMCACHED_UNKNOWN_READ_FAILURE or rc == MEMCACHED_READ_FAILURE)
- {
- WATCHPOINT_ERROR(rc);
- is_successful= false;
- }
-
- if (ptr->root->callbacks != NULL)
- {
- memcached_callback_st cb = *ptr->root->callbacks;
- if (memcached_success(rc))
- {
- for (uint32_t y= 0; y < cb.number_of_callback; y++)
- {
- if (memcached_fatal((*cb.callback[y])(ptr->root, result_ptr, cb.context)))
- {
- break;
- }
- }
- }
- }
- }
-
- memcached_result_free(result_ptr);
- }
-
- return is_successful;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-namespace {
- memcached_return_t send_quit_message(memcached_instance_st* instance)
- {
- memcached_return_t rc;
- if (instance->root->flags.binary_protocol)
- {
- protocol_binary_request_quit request= {}; // = {.bytes= {0}};
-
- initialize_binary_request(instance, request.message.header);
-
- request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT;
- request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
-
- libmemcached_io_vector_st vector[]=
- {
- { request.bytes, sizeof(request.bytes) }
- };
-
- rc= memcached_vdo(instance, vector, 1, true);
- }
- else
- {
- libmemcached_io_vector_st vector[]=
- {
- { memcached_literal_param("quit\r\n") }
- };
-
- rc= memcached_vdo(instance, vector, 1, true);
- }
-
- return rc;
- }
-
- void drain_instance(memcached_instance_st* instance)
- {
- /* read until socket is closed, or there is an error
- * closing the socket before all data is read
- * results in server throwing away all data which is
- * not read
- *
- * In .40 we began to only do this if we had been doing buffered
- * requests of had replication enabled.
- */
- if (instance->root->flags.buffer_requests or instance->root->number_of_replicas)
- {
- memcached_io_slurp(instance);
- }
-
- /*
- * 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.
- */
- instance->server_failure_counter= 0;
- instance->server_timeout_counter= 0;
- }
-}
-
-/*
- 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_instance_st* instance, bool io_death)
-{
- if (instance->valid())
- {
- if (io_death == false and memcached_is_udp(instance->root) == false and instance->is_shutting_down() == false)
- {
- send_quit_message(instance);
-
- instance->start_close_socket();
- drain_instance(instance);
- }
- }
-
- instance->close_socket();
-
- if (io_death and memcached_is_udp(instance->root))
- {
- /*
- If using UDP, we should stop using the server briefly on every IO
- failure. If using TCP, it may be that the connection went down a
- short while ago (e.g. the server failed) and we've only just
- noticed, so we should only set the retry timeout on a connect
- failure (which doesn't call this method).
- */
- memcached_mark_server_for_timeout(instance);
- }
-}
-
-void send_quit(Memcached *memc)
-{
- for (uint32_t x= 0; x < memcached_server_count(memc); x++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc, x);
-
- memcached_quit_server(instance, false);
- }
-}
-
-void memcached_quit(memcached_st *shell)
-{
- Memcached* memc= memcached2Memcached(shell);
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(memc, true)))
- {
- return;
- }
-
- send_quit(memc);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-void memcached_quit_server(memcached_instance_st* ptr, bool io_death);
-
-void send_quit(memcached_st *ptr);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-#include <libmemcached/string.hpp>
-
-static memcached_return_t textual_value_fetch(memcached_instance_st* instance,
- char *buffer,
- memcached_result_st *result)
-{
- char *next_ptr;
- ssize_t read_length= 0;
- size_t value_length;
-
- WATCHPOINT_ASSERT(instance->root);
- char *end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
-
- memcached_result_reset(result);
-
- char *string_ptr= buffer;
- string_ptr+= 6; /* "VALUE " */
-
-
- // Just used for cases of AES decrypt currently
- memcached_return_t rc= MEMCACHED_SUCCESS;
-
- /* We load the key */
- {
- char *key= result->item_key;
- result->key_length= 0;
-
- for (ptrdiff_t prefix_length= memcached_array_size(instance->root->_namespace); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
- {
- if (prefix_length == 0)
- {
- *key= *string_ptr;
- key++;
- result->key_length++;
- }
- else
- prefix_length--;
- }
- result->item_key[result->key_length]= 0;
- }
-
- if (end_ptr == string_ptr)
- {
- goto read_error;
- }
-
- /* Flags fetch move past space */
- string_ptr++;
- if (end_ptr == string_ptr)
- {
- goto read_error;
- }
-
- for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++) {};
- errno= 0;
- result->item_flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10);
-
- if (errno != 0 or 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++) {};
- errno= 0;
- value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
-
- if (errno != 0 or 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++) {};
- errno= 0;
- result->item_cas= strtoull(next_ptr, &string_ptr, 10);
- }
-
- if (errno != 0 or end_ptr < string_ptr)
- {
- goto read_error;
- }
-
- /* We add two bytes so that we can walk the \r\n */
- if (memcached_failed(memcached_string_check(&result->value, value_length +2)))
- {
- return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
-
- {
- char *value_ptr= memcached_string_value_mutable(&result->value);
- /*
- We read the \r\n into the string since not doing so is more
- cycles then the waster of memory to do so.
-
- We are null terminating through, which will most likely make
- some people lazy about using the return length.
- */
- size_t to_read= (value_length) + 2;
- memcached_return_t rrc= memcached_io_read(instance, value_ptr, to_read, read_length);
- if (memcached_failed(rrc) and rrc == MEMCACHED_IN_PROGRESS)
- {
- memcached_quit_server(instance, true);
- return memcached_set_error(*instance, MEMCACHED_IN_PROGRESS, MEMCACHED_AT);
- }
- else if (memcached_failed(rrc))
- {
- return rrc;
- }
- }
-
- if (read_length != (ssize_t)(value_length + 2))
- {
- goto read_error;
- }
-
- /* This next bit blows the API, but this is internal....*/
- {
- char *char_ptr;
- char_ptr= memcached_string_value_mutable(&result->value);;
- char_ptr[value_length]= 0;
- char_ptr[value_length +1]= 0;
- memcached_string_set_length(&result->value, value_length);
- }
-
- if (memcached_is_encrypted(instance->root) and memcached_result_length(result))
- {
- hashkit_string_st *destination;
-
- if ((destination= hashkit_decrypt(&instance->root->hashkit,
- memcached_result_value(result), memcached_result_length(result))) == NULL)
- {
- rc= memcached_set_error(*instance->root, MEMCACHED_FAILURE,
- MEMCACHED_AT, memcached_literal_param("hashkit_decrypt() failed"));
- }
- else
- {
- memcached_result_reset_value(result);
- if (memcached_failed(memcached_result_set_value(result, hashkit_string_c_str(destination), hashkit_string_length(destination))))
- {
- rc= memcached_set_error(*instance->root, MEMCACHED_FAILURE,
- MEMCACHED_AT, memcached_literal_param("hashkit_decrypt() failed"));
- }
- }
-
- if (memcached_failed(rc))
- {
- memcached_result_reset(result);
- }
- hashkit_string_free(destination);
- }
-
- return rc;
-
-read_error:
- memcached_io_reset(instance);
-
- return MEMCACHED_PARTIAL_READ;
-}
-
-static memcached_return_t textual_read_one_response(memcached_instance_st* instance,
- char *buffer, const size_t buffer_length,
- memcached_result_st *result)
-{
- size_t total_read;
- memcached_return_t rc= memcached_io_readline(instance, buffer, buffer_length, total_read);
-
- if (memcached_failed(rc))
- {
- return rc;
- }
- assert(total_read);
-
- switch(buffer[0])
- {
- case 'V':
- {
- // VALUE
- if (buffer[1] == 'A' and buffer[2] == 'L' and buffer[3] == 'U' and buffer[4] == 'E') /* VALUE */
- {
- /* We add back in one because we will need to search for END */
- memcached_server_response_increment(instance);
- return textual_value_fetch(instance, buffer, result);
- }
- // VERSION
- else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'S' and buffer[4] == 'I' and buffer[5] == 'O' and buffer[6] == 'N') /* VERSION */
- {
- /* Find the space, and then move one past it to copy version */
- char *response_ptr= index(buffer, ' ');
-
- char *endptr;
- errno= 0;
- long int version= strtol(response_ptr, &endptr, 10);
- if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX or version == 0)
- {
- instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version"));
- }
- instance->major_version= uint8_t(version);
-
- endptr++;
- errno= 0;
- version= strtol(endptr, &endptr, 10);
- if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX)
- {
- instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse minor version"));
- }
- instance->minor_version= uint8_t(version);
-
- endptr++;
- errno= 0;
- version= strtol(endptr, &endptr, 10);
- if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX)
- {
- instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
- }
- instance->micro_version= uint8_t(version);
-
- return MEMCACHED_SUCCESS;
- }
- }
- break;
-
- case 'O':
- {
- // OK
- if (buffer[1] == 'K')
- {
- return MEMCACHED_SUCCESS;
- }
- }
- break;
-
- case 'S':
- {
- // STAT
- if (buffer[1] == 'T' and buffer[2] == 'A' and buffer[3] == 'T') /* STORED STATS */
- {
- memcached_server_response_increment(instance);
- return MEMCACHED_STAT;
- }
- // SERVER_ERROR
- else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'V' and buffer[4] == 'E' and buffer[5] == 'R'
- and buffer[6] == '_'
- and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R' )
- {
- if (total_read == memcached_literal_param_size("SERVER_ERROR"))
- {
- return MEMCACHED_SERVER_ERROR;
- }
-
- if (total_read >= memcached_literal_param_size("SERVER_ERROR object too large for cache") and
- (memcmp(buffer, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
- {
- return MEMCACHED_E2BIG;
- }
-
- if (total_read >= memcached_literal_param_size("SERVER_ERROR out of memory") and
- ((memcmp(buffer, memcached_literal_param("SERVER_ERROR out of memory")) == 0) or
- (memcmp(buffer, memcached_literal_param("SERVER_ERROR Out of memory")) == 0)))
- {
- return MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE;
- }
-
- // Move past the basic error message and whitespace
- char *startptr= buffer + memcached_literal_param_size("SERVER_ERROR");
- if (startptr[0] == ' ')
- {
- startptr++;
- }
-
- char *endptr= startptr;
- while (*endptr != '\r' && *endptr != '\n') endptr++;
-
- return memcached_set_error(*instance, MEMCACHED_SERVER_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
- }
- // STORED
- else if (buffer[1] == 'T' and buffer[2] == 'O' and buffer[3] == 'R') // and buffer[4] == 'E' and buffer[5] == 'D')
- {
- return MEMCACHED_STORED;
- }
- }
- break;
-
- case 'D':
- {
- // DELETED
- if (buffer[1] == 'E' and buffer[2] == 'L' and buffer[3] == 'E' and buffer[4] == 'T' and buffer[5] == 'E' and buffer[6] == 'D')
- {
- return MEMCACHED_DELETED;
- }
- }
- break;
-
- case 'N':
- {
- // NOT_FOUND
- if (buffer[1] == 'O' and buffer[2] == 'T'
- and buffer[3] == '_'
- and buffer[4] == 'F' and buffer[5] == 'O' and buffer[6] == 'U' and buffer[7] == 'N' and buffer[8] == 'D')
- {
- return MEMCACHED_NOTFOUND;
- }
- // NOT_STORED
- else if (buffer[1] == 'O' and buffer[2] == 'T'
- and buffer[3] == '_'
- and buffer[4] == 'S' and buffer[5] == 'T' and buffer[6] == 'O' and buffer[7] == 'R' and buffer[8] == 'E' and buffer[9] == 'D')
- {
- return MEMCACHED_NOTSTORED;
- }
- }
- break;
-
- case 'E': /* PROTOCOL ERROR or END */
- {
- // END
- if (buffer[1] == 'N' and buffer[2] == 'D')
- {
- return MEMCACHED_END;
- }
-#if 0
- // PROTOCOL_ERROR
- else if (buffer[1] == 'R' and buffer[2] == 'O' and buffer[3] == 'T' and buffer[4] == 'O' and buffer[5] == 'C' and buffer[6] == 'O' and buffer[7] == 'L'
- and buffer[8] == '_'
- and buffer[9] == 'E' and buffer[10] == 'R' and buffer[11] == 'R' and buffer[12] == 'O' and buffer[13] == 'R')
- {
- return MEMCACHED_PROTOCOL_ERROR;
- }
-#endif
- // ERROR
- else if (buffer[1] == 'R' and buffer[2] == 'R' and buffer[3] == 'O' and buffer[4] == 'R')
- {
- return MEMCACHED_ERROR;
- }
- // EXISTS
- else if (buffer[1] == 'X' and buffer[2] == 'I' and buffer[3] == 'S' and buffer[4] == 'T' and buffer[5] == 'S')
- {
- return MEMCACHED_DATA_EXISTS;
- }
- }
- break;
-
- case 'T': /* TOUCHED */
- {
- // TOUCHED
- if (buffer[1] == 'O' and buffer[2] == 'U' and buffer[3] == 'C' and buffer[4] == 'H' and buffer[5] == 'E' and buffer[6] == 'D')
- {
- return MEMCACHED_SUCCESS;
- }
- }
- break;
-
- case 'I': /* ITEM */
- {
- // ITEM
- if (buffer[1] == 'T' and buffer[2] == 'E' and buffer[3] == 'M')
- {
- /* We add back in one because we will need to search for END */
- memcached_server_response_increment(instance);
- return MEMCACHED_ITEM;
- }
- }
- break;
-
- case 'C': /* CLIENT ERROR */
- {
- // CLIENT_ERROR
- if (buffer[1] == 'L' and buffer[2] == 'I' and buffer[3] == 'E' and buffer[4] == 'N' and buffer[5] == 'T'
- and buffer[6] == '_'
- and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R')
- {
- // Move past the basic error message and whitespace
- char *startptr= buffer + memcached_literal_param_size("CLIENT_ERROR");
- if (startptr[0] == ' ')
- {
- startptr++;
- }
-
- char *endptr= startptr;
- while (*endptr != '\r' && *endptr != '\n') endptr++;
-
- return memcached_set_error(*instance, MEMCACHED_CLIENT_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
- }
- }
- break;
-
- case '0': /* INCR/DECR response */
- case '1': /* INCR/DECR response */
- case '2': /* INCR/DECR response */
- case '3': /* INCR/DECR response */
- case '4': /* INCR/DECR response */
- case '5': /* INCR/DECR response */
- case '6': /* INCR/DECR response */
- case '7': /* INCR/DECR response */
- case '8': /* INCR/DECR response */
- case '9': /* INCR/DECR response */
- {
- errno= 0;
- unsigned long long int auto_return_value= strtoull(buffer, (char **)NULL, 10);
-
- if (auto_return_value == ULLONG_MAX and errno == ERANGE)
- {
- result->numeric_value= UINT64_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
- memcached_literal_param("Numeric response was out of range"));
- }
- else if (errno == EINVAL)
- {
- result->numeric_value= UINT64_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
- memcached_literal_param("Numeric response was out of range"));
- }
- else if (errno != 0)
- {
- result->numeric_value= UINT64_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
- memcached_literal_param("Numeric response was out of range"));
- }
-
- result->numeric_value= uint64_t(auto_return_value);
-
- WATCHPOINT_STRING(buffer);
- return MEMCACHED_SUCCESS;
- }
-
- default:
- break;
- }
-
- buffer[total_read]= 0;
-#if 0
- if (total_read >= sizeof("STORSTORED") -1)
- {
- fprintf(stderr, "%s:%d '%s', %.*s\n", __FILE__, __LINE__,
- buffer, MEMCACHED_MAX_BUFFER, instance->read_buffer);
- assert(memcmp(buffer,"STORSTORED", sizeof("STORSTORED") -1));
- }
-#endif
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
- buffer, total_read);
-}
-
-static memcached_return_t binary_read_one_response(memcached_instance_st* instance,
- char *buffer, const size_t buffer_length,
- memcached_result_st *result)
-{
- memcached_return_t rc;
- protocol_binary_response_header header;
-
- assert(memcached_is_binary(instance->root));
-
- if ((rc= memcached_safe_read(instance, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ERROR(rc);
- return rc;
- }
-
- if (header.response.magic != PROTOCOL_BINARY_RES)
- {
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
- }
-
- /*
- ** 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= memcached_ntohll(header.response.cas);
- uint32_t bodylen= header.response.bodylen;
-
- if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS or
- header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE)
- {
- switch (header.response.opcode)
- {
- case PROTOCOL_BINARY_CMD_GETKQ:
- /*
- * We didn't increment the response counter for the GETKQ packet
- * (only the final NOOP), so we need to increment the counter again.
- */
- memcached_server_response_increment(instance);
- /* fall through */
- case PROTOCOL_BINARY_CMD_GETK:
- {
- uint16_t keylen= header.response.keylen;
- memcached_result_reset(result);
- result->item_cas= header.response.cas;
-
- if ((rc= memcached_safe_read(instance, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ERROR(rc);
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
-
- result->item_flags= ntohl(result->item_flags);
- bodylen -= header.response.extlen;
-
- result->key_length= keylen;
- if (memcached_failed(rc= memcached_safe_read(instance, result->item_key, keylen)))
- {
- WATCHPOINT_ERROR(rc);
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
-
- // Only bother with doing this if key_length > 0
- if (result->key_length)
- {
- if (memcached_array_size(instance->root->_namespace) and memcached_array_size(instance->root->_namespace) >= result->key_length)
- {
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
- }
-
- if (memcached_array_size(instance->root->_namespace))
- {
- result->key_length-= memcached_array_size(instance->root->_namespace);
- memmove(result->item_key, result->item_key +memcached_array_size(instance->root->_namespace), result->key_length);
- }
- }
-
- bodylen -= keylen;
- if (memcached_failed(memcached_string_check(&result->value, bodylen)))
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- char *vptr= memcached_string_value_mutable(&result->value);
- if (memcached_failed(rc= memcached_safe_read(instance, vptr, bodylen)))
- {
- WATCHPOINT_ERROR(rc);
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
-
- memcached_string_set_length(&result->value, bodylen);
- }
- break;
-
- case PROTOCOL_BINARY_CMD_INCREMENT:
- case PROTOCOL_BINARY_CMD_DECREMENT:
- {
- if (bodylen != sizeof(uint64_t))
- {
- result->numeric_value= UINT64_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
- }
-
- uint64_t val;
- if ((rc= memcached_safe_read(instance, &val, sizeof(val))) != MEMCACHED_SUCCESS)
- {
- result->numeric_value= UINT64_MAX;
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
-
- result->numeric_value= memcached_ntohll(val);
- }
- break;
-
- case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
- {
- if (header.response.keylen != 0 || bodylen + 1 > buffer_length)
- {
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- else
- {
- if ((rc= memcached_safe_read(instance, buffer, bodylen)) != MEMCACHED_SUCCESS)
- {
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- }
- }
- break;
-
- case PROTOCOL_BINARY_CMD_VERSION:
- {
- char version_buffer[32]; // @todo document this number
- memset(version_buffer, 0, sizeof(version_buffer));
-
- if (memcached_safe_read(instance, version_buffer, bodylen) != MEMCACHED_SUCCESS)
- {
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
-
- char *endptr;
- errno= 0;
- long int version= strtol(version_buffer, &endptr, 10);
- if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX or version == 0)
- {
- instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version"));
- }
- instance->major_version= uint8_t(version);
-
- endptr++;
- errno= 0;
- version= strtol(endptr, &endptr, 10);
- if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX)
- {
- instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse minor version"));
- }
- instance->minor_version= uint8_t(version);
-
- endptr++;
- errno= 0;
- version= strtol(endptr, &endptr, 10);
- if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX)
- {
- instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
- }
- instance->micro_version= uint8_t(version);
- }
- break;
-
- case PROTOCOL_BINARY_CMD_TOUCH:
- {
- rc= MEMCACHED_SUCCESS;
- if (bodylen == 4) // The four byte read is a bug?
- {
- char touch_buffer[4]; // @todo document this number
- rc= memcached_safe_read(instance, touch_buffer, sizeof(touch_buffer));
-#if 0
- fprintf(stderr, "%s:%d %d %d %d %d %.*s(%d)\n", __FILE__, __LINE__,
- int(touch_buffer[0]),
- int(touch_buffer[1]),
- int(touch_buffer[2]),
- int(touch_buffer[3]),
- int(bodylen), touch_buffer, int(bodylen));
-#endif
- }
- return memcached_set_error(*instance, rc, MEMCACHED_AT);
- }
-
- case PROTOCOL_BINARY_CMD_FLUSH:
- case PROTOCOL_BINARY_CMD_QUIT:
- case PROTOCOL_BINARY_CMD_SET:
- case PROTOCOL_BINARY_CMD_ADD:
- case PROTOCOL_BINARY_CMD_REPLACE:
- case PROTOCOL_BINARY_CMD_APPEND:
- case PROTOCOL_BINARY_CMD_PREPEND:
- case PROTOCOL_BINARY_CMD_DELETE:
- {
- WATCHPOINT_ASSERT(bodylen == 0);
- return MEMCACHED_SUCCESS;
- }
-
- case PROTOCOL_BINARY_CMD_NOOP:
- {
- WATCHPOINT_ASSERT(bodylen == 0);
- return MEMCACHED_END;
- }
-
- case PROTOCOL_BINARY_CMD_STAT:
- {
- if (bodylen == 0)
- {
- return MEMCACHED_END;
- }
- else if (bodylen + 1 > buffer_length)
- {
- /* not enough space in buffer.. should not happen... */
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- else
- {
- size_t keylen= header.response.keylen;
- memset(buffer, 0, buffer_length);
- if ((rc= memcached_safe_read(instance, buffer, keylen)) != MEMCACHED_SUCCESS ||
- (rc= memcached_safe_read(instance, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ERROR(rc);
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- }
- }
- break;
-
- case PROTOCOL_BINARY_CMD_SASL_AUTH:
- case PROTOCOL_BINARY_CMD_SASL_STEP:
- {
- memcached_result_reset(result);
- result->item_cas= header.response.cas;
-
- if (memcached_string_check(&result->value,
- bodylen) != MEMCACHED_SUCCESS)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- char *vptr= memcached_string_value_mutable(&result->value);
- if ((rc= memcached_safe_read(instance, vptr, bodylen)) != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ERROR(rc);
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
-
- memcached_string_set_length(&result->value, bodylen);
- }
- break;
- default:
- {
- /* Command not implemented yet! */
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
- }
- }
- }
- else if (header.response.bodylen)
- {
- /* What should I do with the error message??? just discard it for now */
- char hole[SMALL_STRING_LEN];
- while (bodylen > 0)
- {
- size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
- if ((rc= memcached_safe_read(instance, hole, nr)) != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ERROR(rc);
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
- }
- 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 MEMCACHED_FETCH_NOTFINISHED;
-
- default:
- break;
- }
- }
-
- rc= MEMCACHED_SUCCESS;
- if (header.response.status != 0)
- {
- switch (header.response.status)
- {
- case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
- rc= MEMCACHED_NOTFOUND;
- break;
-
- case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
- rc= MEMCACHED_DATA_EXISTS;
- break;
-
- case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
- rc= MEMCACHED_NOTSTORED;
- break;
-
- case PROTOCOL_BINARY_RESPONSE_E2BIG:
- rc= MEMCACHED_E2BIG;
- break;
-
- case PROTOCOL_BINARY_RESPONSE_ENOMEM:
- rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- break;
-
- case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE:
- rc= MEMCACHED_AUTH_CONTINUE;
- break;
-
- case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
- rc= MEMCACHED_AUTH_FAILURE;
- break;
-
- case PROTOCOL_BINARY_RESPONSE_EINVAL:
- case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
- default:
- return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
- break;
- }
- }
-
- return rc;
-}
-
-static memcached_return_t _read_one_response(memcached_instance_st* instance,
- char *buffer, const size_t buffer_length,
- memcached_result_st *result)
-{
- memcached_server_response_decrement(instance);
-
- if (result == NULL)
- {
- Memcached *root= (Memcached *)instance->root;
- result = &root->result;
- }
-
- memcached_return_t rc;
- if (memcached_is_binary(instance->root))
- {
- do {
- rc= binary_read_one_response(instance, buffer, buffer_length, result);
- } while (rc == MEMCACHED_FETCH_NOTFINISHED);
- }
- else
- {
- rc= textual_read_one_response(instance, buffer, buffer_length, result);
- }
-
- if (memcached_fatal(rc))
- {
- memcached_io_reset(instance);
- }
-
- return rc;
-}
-
-memcached_return_t memcached_read_one_response(memcached_instance_st* instance,
- memcached_result_st *result)
-{
- char buffer[SMALL_STRING_LEN];
-
- if (memcached_is_udp(instance->root))
- {
- return memcached_set_error(*instance, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
- }
-
-
- return _read_one_response(instance, buffer, sizeof(buffer), result);
-}
-
-memcached_return_t memcached_response(memcached_instance_st* instance,
- memcached_result_st *result)
-{
- char buffer[1024];
-
- return memcached_response(instance, buffer, sizeof(buffer), result);
-}
-
-memcached_return_t memcached_response(memcached_instance_st* instance,
- char *buffer, size_t buffer_length,
- memcached_result_st *result)
-{
- if (memcached_is_udp(instance->root))
- {
- return memcached_set_error(*instance, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
- }
-
- /* We may have old commands in the buffer not sent, first purge */
- if ((instance->root->flags.no_block) and (memcached_is_processing_input(instance->root) == false))
- {
- (void)memcached_io_write(instance);
- }
-
- /* Before going into loop wait to see if we have any IO waiting for us */
- if (0)
- {
- memcached_return_t read_rc= memcached_io_wait_for_read(instance);
- fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, memcached_strerror(NULL, read_rc));
- }
-
- /*
- * The previous implementation purged all pending requests and just
- * returned the last one. Purge all pending messages to ensure backwards
- * compatibility.
- */
- if (memcached_is_binary(instance->root) == false and memcached_server_response_count(instance) > 1)
- {
- memcached_result_st junked_result;
- memcached_result_st *junked_result_ptr= memcached_result_create(instance->root, &junked_result);
-
- assert(junked_result_ptr);
-
- while (memcached_server_response_count(instance) > 1)
- {
- memcached_return_t rc= _read_one_response(instance, buffer, buffer_length, junked_result_ptr);
-
- // @TODO should we return an error on another but a bad read case?
- if (memcached_fatal(rc))
- {
- memcached_result_free(junked_result_ptr);
- return rc;
- }
- }
- memcached_result_free(junked_result_ptr);
- }
-
- return _read_one_response(instance, buffer, buffer_length, result);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-/* Read a single response from the server */
-memcached_return_t memcached_read_one_response(memcached_instance_st* ptr,
- memcached_result_st *result);
-
-memcached_return_t memcached_response(memcached_instance_st* ptr,
- memcached_result_st *result);
-
-memcached_return_t memcached_response(memcached_instance_st* ptr,
- char *buffer, size_t buffer_length,
- memcached_result_st *result);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-/*
- memcached_result_st are used to internally represent the return values from
- memcached. We use a structure so that long term as identifiers are added
- to memcached we will be able to absorb new attributes without having
- to addjust the entire API.
-*/
-#include <libmemcached/common.h>
-
-static inline void _result_init(memcached_result_st *self,
- Memcached *memc)
-{
- self->item_flags= 0;
- self->item_expiration= 0;
- self->key_length= 0;
- self->item_cas= 0;
- self->root= memc;
- self->numeric_value= UINT64_MAX;
- self->count= 0;
- self->item_key[0]= 0;
-}
-
-memcached_result_st *memcached_result_create(const memcached_st *shell,
- memcached_result_st *ptr)
-{
- const Memcached* memc= memcached2Memcached(shell);
-
- /* Saving malloc calls :) */
- if (ptr)
- {
- ptr->options.is_allocated= false;
- }
- else
- {
- ptr= libmemcached_xmalloc(memc, memcached_result_st);
-
- if (not ptr)
- {
- return NULL;
- }
-
- ptr->options.is_allocated= true;
- }
-
- ptr->options.is_initialized= true;
-
- _result_init(ptr, (memcached_st *)memc);
-
- WATCHPOINT_SET(ptr->value.options.is_initialized= false);
- memcached_string_create((memcached_st*)memc, &ptr->value, 0);
- WATCHPOINT_ASSERT_INITIALIZED(&ptr->value);
- WATCHPOINT_ASSERT(ptr->value.string == NULL);
-
- return ptr;
-}
-
-void memcached_result_reset(memcached_result_st *ptr)
-{
- ptr->key_length= 0;
- memcached_string_reset(&ptr->value);
- ptr->item_flags= 0;
- ptr->item_cas= 0;
- ptr->item_expiration= 0;
- ptr->numeric_value= UINT64_MAX;
-}
-
-void memcached_result_free(memcached_result_st *ptr)
-{
- if (ptr == NULL)
- {
- return;
- }
-
- memcached_string_free(&ptr->value);
- ptr->numeric_value= UINT64_MAX;
-
- if (memcached_is_allocated(ptr))
- {
- WATCHPOINT_ASSERT(ptr->root); // Without a root, that means that result was not properly initialized.
- libmemcached_free(ptr->root, ptr);
- }
- else
- {
- ptr->count= 0;
- ptr->options.is_initialized= false;
- }
-}
-
-void memcached_result_reset_value(memcached_result_st *ptr)
-{
- memcached_string_reset(&ptr->value);
-}
-
-memcached_return_t memcached_result_set_value(memcached_result_st *ptr,
- const char *value,
- size_t length)
-{
- if (memcached_failed(memcached_string_append(&ptr->value, value, length)))
- {
- return memcached_set_errno(*ptr->root, errno, MEMCACHED_AT);
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-const char *memcached_result_key_value(const memcached_result_st *self)
-{
- return self->key_length ? self->item_key : NULL;
-}
-
-size_t memcached_result_key_length(const memcached_result_st *self)
-{
- return self->key_length;
-}
-
-const char *memcached_result_value(const memcached_result_st *self)
-{
- const memcached_string_st *sptr= &self->value;
- return memcached_string_value(sptr);
-}
-
-size_t memcached_result_length(const memcached_result_st *self)
-{
- const memcached_string_st *sptr= &self->value;
- return memcached_string_length(sptr);
-}
-
-char *memcached_result_take_value(memcached_result_st *self)
-{
- memcached_string_st *sptr= &self->value;
- return memcached_string_take_value(sptr);
-}
-
-uint32_t memcached_result_flags(const memcached_result_st *self)
-{
- return self->item_flags;
-}
-
-uint64_t memcached_result_cas(const memcached_result_st *self)
-{
- return self->item_cas;
-}
-
-void memcached_result_set_flags(memcached_result_st *self, uint32_t flags)
-{
- self->item_flags= flags;
-}
-
-void memcached_result_set_expiration(memcached_result_st *self, time_t expiration)
-{
- self->item_expiration= expiration;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-void memcached_result_reset_value(memcached_result_st *ptr);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libmemcached/common.h"
-#include <cassert>
-#include <atomic>
-
-#if defined(LIBMEMCACHED_WITH_SASL_SUPPORT) && LIBMEMCACHED_WITH_SASL_SUPPORT
-
-#if defined(HAVE_LIBSASL) && HAVE_LIBSASL
-#include <sasl/sasl.h>
-#endif
-
-#define CAST_SASL_CB(cb) reinterpret_cast<int(*)()>(reinterpret_cast<intptr_t>(cb))
-
-#include <pthread.h>
-
-void memcached_set_sasl_callbacks(memcached_st *shell,
- const sasl_callback_t *callbacks)
-{
- Memcached* self= memcached2Memcached(shell);
- if (self)
- {
- self->sasl.callbacks= const_cast<sasl_callback_t *>(callbacks);
- self->sasl.is_allocated= false;
- }
-}
-
-sasl_callback_t *memcached_get_sasl_callbacks(memcached_st *shell)
-{
- Memcached* self= memcached2Memcached(shell);
- if (self)
- {
- return self->sasl.callbacks;
- }
-
- return NULL;
-}
-
-/**
- * Resolve the names for both ends of a connection
- * @param fd socket to check
- * @param laddr local address (out)
- * @param raddr remote address (out)
- * @return true on success false otherwise (errno contains more info)
- */
-static memcached_return_t resolve_names(memcached_instance_st& server, char *laddr, size_t laddr_length, char *raddr, size_t raddr_length)
-{
- char host[MEMCACHED_NI_MAXHOST];
- char port[MEMCACHED_NI_MAXSERV];
- struct sockaddr_storage saddr;
- socklen_t salen= sizeof(saddr);
-
- if (getsockname(server.fd, (struct sockaddr *)&saddr, &salen) < 0)
- {
- return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
- }
-
- if (getnameinfo((struct sockaddr *)&saddr, salen, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) < 0)
- {
- return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
- }
-
- (void)snprintf(laddr, laddr_length, "%s;%s", host, port);
- salen= sizeof(saddr);
-
- if (getpeername(server.fd, (struct sockaddr *)&saddr, &salen) < 0)
- {
- return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
- }
-
- if (getnameinfo((struct sockaddr *)&saddr, salen, host, sizeof(host),
- port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) < 0)
- {
- return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
- }
-
- (void)snprintf(raddr, raddr_length, "%s;%s", host, port);
-
- return MEMCACHED_SUCCESS;
-}
-
-extern "C" {
-
-static void sasl_shutdown_function()
-{
- sasl_done();
-}
-
-static std::atomic<int> sasl_startup_state(SASL_OK);
-pthread_mutex_t sasl_startup_state_LOCK= PTHREAD_MUTEX_INITIALIZER;
-static pthread_once_t sasl_startup_once= PTHREAD_ONCE_INIT;
-static void sasl_startup_function(void)
-{
- sasl_startup_state= sasl_client_init(NULL);
-
- if (sasl_startup_state == SASL_OK)
- {
- (void)atexit(sasl_shutdown_function);
- }
-}
-
-} // extern "C"
-
-memcached_return_t memcached_sasl_authenticate_connection(memcached_instance_st* server)
-{
- if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- return MEMCACHED_NOT_SUPPORTED;
- }
-
- if (server == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- /* SANITY CHECK: SASL can only be used with the binary protocol */
- if (memcached_is_binary(server->root) == false)
- {
- return memcached_set_error(*server, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
- memcached_literal_param("memcached_sasl_authenticate_connection() is not supported via the ASCII protocol"));
- }
-
- /* Try to get the supported mech from the server. Servers without SASL
- * support will return UNKNOWN COMMAND, so we can just treat that
- * as authenticated
- */
- protocol_binary_request_no_extras request= { };
-
- initialize_binary_request(server, request.message.header);
-
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SASL_LIST_MECHS;
-
- if (memcached_io_write(server, request.bytes, sizeof(request.bytes), true) != sizeof(request.bytes))
- {
- return MEMCACHED_WRITE_FAILURE;
- }
- assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
-
- memcached_server_response_increment(server);
-
- char mech[MEMCACHED_MAX_BUFFER];
- memcached_return_t rc= memcached_response(server, mech, sizeof(mech), NULL);
- if (memcached_failed(rc))
- {
- if (rc == MEMCACHED_PROTOCOL_ERROR)
- {
- /* If the server doesn't support SASL it will return PROTOCOL_ERROR.
- * This error may also be returned for other errors, but let's assume
- * that the server don't support SASL and treat it as success and
- * let the client fail with the next operation if the error was
- * caused by another problem....
- */
- rc= MEMCACHED_SUCCESS;
- }
-
- return rc;
- }
- assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
-
- /* set ip addresses */
- char laddr[MEMCACHED_NI_MAXHOST + MEMCACHED_NI_MAXSERV];
- char raddr[MEMCACHED_NI_MAXHOST + MEMCACHED_NI_MAXSERV];
-
- if (memcached_failed(rc= resolve_names(*server, laddr, sizeof(laddr), raddr, sizeof(raddr))))
- {
- return rc;
- }
-
- int pthread_error;
- if ((pthread_error= pthread_once(&sasl_startup_once, sasl_startup_function)) != 0)
- {
- return memcached_set_errno(*server, pthread_error, MEMCACHED_AT);
- }
-
- (void)pthread_mutex_lock(&sasl_startup_state_LOCK);
- if (sasl_startup_state != SASL_OK)
- {
- const char *sasl_error_msg= sasl_errstring(sasl_startup_state, NULL, NULL);
- return memcached_set_error(*server, MEMCACHED_AUTH_PROBLEM, MEMCACHED_AT,
- memcached_string_make_from_cstr(sasl_error_msg));
- }
- (void)pthread_mutex_unlock(&sasl_startup_state_LOCK);
-
- sasl_conn_t *conn;
- int ret;
- if ((ret= sasl_client_new("memcached", server->_hostname, laddr, raddr, server->root->sasl.callbacks, 0, &conn) ) != SASL_OK)
- {
- const char *sasl_error_msg= sasl_errstring(ret, NULL, NULL);
-
- sasl_dispose(&conn);
-
- return memcached_set_error(*server, MEMCACHED_AUTH_PROBLEM, MEMCACHED_AT,
- memcached_string_make_from_cstr(sasl_error_msg));
- }
-
- const char *data;
- const char *chosenmech;
- unsigned int len;
- ret= sasl_client_start(conn, mech, NULL, &data, &len, &chosenmech);
- if (ret != SASL_OK and ret != SASL_CONTINUE)
- {
- const char *sasl_error_msg= sasl_errstring(ret, NULL, NULL);
-
- sasl_dispose(&conn);
-
- return memcached_set_error(*server, MEMCACHED_AUTH_PROBLEM, MEMCACHED_AT,
- memcached_string_make_from_cstr(sasl_error_msg));
- }
- uint16_t keylen= (uint16_t)strlen(chosenmech);
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SASL_AUTH;
- request.message.header.request.keylen= htons(keylen);
- request.message.header.request.bodylen= htonl(len + keylen);
-
- do {
- /* send the packet */
-
- libmemcached_io_vector_st vector[]=
- {
- { request.bytes, sizeof(request.bytes) },
- { chosenmech, keylen },
- { data, len }
- };
-
- assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
- if (memcached_io_writev(server, vector, 3, true) == false)
- {
- rc= MEMCACHED_WRITE_FAILURE;
- break;
- }
- assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
- memcached_server_response_increment(server);
-
- /* read the response */
- assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
- rc= memcached_response(server, NULL, 0, NULL);
- if (rc != MEMCACHED_AUTH_CONTINUE)
- {
- break;
- }
- assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
-
- ret= sasl_client_step(conn, memcached_result_value(&server->root->result),
- (unsigned int)memcached_result_length(&server->root->result),
- NULL, &data, &len);
-
- if (ret != SASL_OK && ret != SASL_CONTINUE)
- {
- rc= MEMCACHED_AUTH_PROBLEM;
- break;
- }
-
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SASL_STEP;
- request.message.header.request.bodylen= htonl(len + keylen);
- } while (true);
-
- /* Release resources */
- sasl_dispose(&conn);
-
- return memcached_set_error(*server, rc, MEMCACHED_AT);
-}
-
-static int get_username(void *context, int id, const char **result, unsigned int *len)
-{
- if (!context || !result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME))
- {
- return SASL_BADPARAM;
- }
-
- *result= (char *)context;
- if (len)
- {
- *len= (unsigned int)strlen(*result);
- }
-
- return SASL_OK;
-}
-
-static int get_password(sasl_conn_t *conn, void *context, int id,
- sasl_secret_t **psecret)
-{
- if (!conn || ! psecret || id != SASL_CB_PASS)
- {
- return SASL_BADPARAM;
- }
-
- *psecret= (sasl_secret_t *)context;
-
- return SASL_OK;
-}
-
-memcached_return_t memcached_set_sasl_auth_data(memcached_st *shell,
- const char *username,
- const char *password)
-{
- Memcached* ptr= memcached2Memcached(shell);
- if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- return MEMCACHED_NOT_SUPPORTED;
- }
-
- if (ptr == NULL or username == NULL or password == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- memcached_return_t ret;
- if (memcached_failed(ret= memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1)))
- {
- return memcached_set_error(*ptr, ret, MEMCACHED_AT, memcached_literal_param("Unable change to binary protocol which is required for SASL."));
- }
-
- memcached_destroy_sasl_auth_data(ptr);
-
- sasl_callback_t *callbacks= libmemcached_xcalloc(ptr, 4, sasl_callback_t);
- size_t password_length= strlen(password);
- size_t username_length= strlen(username);
- char *name= (char *)libmemcached_malloc(ptr, username_length +1);
- sasl_secret_t *secret= (sasl_secret_t*)libmemcached_malloc(ptr, password_length +1 + sizeof(sasl_secret_t));
-
- if (callbacks == NULL or name == NULL or secret == NULL)
- {
- libmemcached_free(ptr, callbacks);
- libmemcached_free(ptr, name);
- libmemcached_free(ptr, secret);
- return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
-
- secret->len= password_length;
- memcpy(secret->data, password, password_length);
- secret->data[password_length]= 0;
-
- callbacks[0].id= SASL_CB_USER;
- callbacks[0].proc= CAST_SASL_CB(get_username);
- callbacks[0].context= strncpy(name, username, username_length +1);
- callbacks[1].id= SASL_CB_AUTHNAME;
- callbacks[1].proc= CAST_SASL_CB(get_username);
- callbacks[1].context= name;
- callbacks[2].id= SASL_CB_PASS;
- callbacks[2].proc= CAST_SASL_CB(get_password);
- callbacks[2].context= secret;
- callbacks[3].id= SASL_CB_LIST_END;
-
- ptr->sasl.callbacks= callbacks;
- ptr->sasl.is_allocated= true;
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_destroy_sasl_auth_data(memcached_st *shell)
-{
- if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- return MEMCACHED_NOT_SUPPORTED;
- }
-
- Memcached* ptr= memcached2Memcached(shell);
- if (ptr == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (ptr->sasl.callbacks == NULL)
- {
- return MEMCACHED_SUCCESS;
- }
-
- if (ptr->sasl.is_allocated)
- {
- libmemcached_free(ptr, ptr->sasl.callbacks[0].context);
- libmemcached_free(ptr, ptr->sasl.callbacks[2].context);
- libmemcached_free(ptr, (void*)ptr->sasl.callbacks);
- ptr->sasl.is_allocated= false;
- }
-
- ptr->sasl.callbacks= NULL;
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_clone_sasl(memcached_st *clone, const memcached_st *source)
-{
- if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- return MEMCACHED_NOT_SUPPORTED;
- }
-
- if (clone == NULL or source == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (source->sasl.callbacks == NULL)
- {
- return MEMCACHED_SUCCESS;
- }
-
- /* Hopefully we are using our own callback mechanisms.. */
- if (source->sasl.callbacks[0].id == SASL_CB_USER &&
- source->sasl.callbacks[0].proc == CAST_SASL_CB(get_username) &&
- source->sasl.callbacks[1].id == SASL_CB_AUTHNAME &&
- source->sasl.callbacks[1].proc == CAST_SASL_CB(get_username) &&
- source->sasl.callbacks[2].id == SASL_CB_PASS &&
- source->sasl.callbacks[2].proc == CAST_SASL_CB(get_password) &&
- source->sasl.callbacks[3].id == SASL_CB_LIST_END)
- {
- sasl_secret_t *secret= (sasl_secret_t *)source->sasl.callbacks[2].context;
- return memcached_set_sasl_auth_data(clone,
- (const char*)source->sasl.callbacks[0].context,
- (const char*)secret->data);
- }
-
- /*
- * But we're not. It may work if we know what the user tries to pass
- * into the list, but if we don't know the ID we don't know how to handle
- * the context...
- */
- ptrdiff_t total= 0;
-
- while (source->sasl.callbacks[total].id != SASL_CB_LIST_END)
- {
- switch (source->sasl.callbacks[total].id)
- {
- case SASL_CB_USER:
- case SASL_CB_AUTHNAME:
- case SASL_CB_PASS:
- break;
- default:
- /* I don't know how to deal with this... */
- return MEMCACHED_NOT_SUPPORTED;
- }
-
- ++total;
- }
-
- sasl_callback_t *callbacks= libmemcached_xcalloc(clone, total +1, sasl_callback_t);
- if (callbacks == NULL)
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
- memcpy(callbacks, source->sasl.callbacks, (total + 1) * sizeof(sasl_callback_t));
-
- /* Now update the context... */
- for (ptrdiff_t x= 0; x < total; ++x)
- {
- if (callbacks[x].id == SASL_CB_USER || callbacks[x].id == SASL_CB_AUTHNAME)
- {
- callbacks[x].context= (sasl_callback_t*)libmemcached_malloc(clone, strlen((const char*)source->sasl.callbacks[x].context));
-
- if (callbacks[x].context == NULL)
- {
- /* Failed to allocate memory, clean up previously allocated memory */
- for (ptrdiff_t y= 0; y < x; ++y)
- {
- libmemcached_free(clone, clone->sasl.callbacks[y].context);
- }
-
- libmemcached_free(clone, callbacks);
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
- strncpy((char*)callbacks[x].context, (const char*)source->sasl.callbacks[x].context, sizeof(callbacks[x].context));
- }
- else
- {
- sasl_secret_t *src= (sasl_secret_t *)source->sasl.callbacks[x].context;
- sasl_secret_t *n= (sasl_secret_t*)libmemcached_malloc(clone, src->len + 1 + sizeof(*n));
- if (n == NULL)
- {
- /* Failed to allocate memory, clean up previously allocated memory */
- for (ptrdiff_t y= 0; y < x; ++y)
- {
- libmemcached_free(clone, clone->sasl.callbacks[y].context);
- }
-
- libmemcached_free(clone, callbacks);
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
- memcpy(n, src, src->len + 1 + sizeof(*n));
- callbacks[x].context= n;
- }
- }
-
- clone->sasl.callbacks= callbacks;
- clone->sasl.is_allocated= true;
-
- return MEMCACHED_SUCCESS;
-}
-
-#else
-
-void memcached_set_sasl_callbacks(memcached_st *, const sasl_callback_t *)
-{
-}
-
-sasl_callback_t *memcached_get_sasl_callbacks(memcached_st *)
-{
- return NULL;
-}
-
-memcached_return_t memcached_set_sasl_auth_data(memcached_st *, const char *, const char *)
-{
- return MEMCACHED_NOT_SUPPORTED;
-}
-
-memcached_return_t memcached_clone_sasl(memcached_st *, const memcached_st *)
-{
- return MEMCACHED_NOT_SUPPORTED;
-}
-
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-memcached_return_t memcached_clone_sasl(memcached_st *clone, const memcached_st *source);
-
-memcached_return_t memcached_sasl_authenticate_connection(memcached_instance_st* server);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- This is a partial implementation for fetching/creating memcached_server_st objects.
-*/
-#include <libmemcached/common.h>
-
-static inline void _server_init(memcached_server_st *self, Memcached *root,
- const memcached_string_t& hostname,
- in_port_t port,
- uint32_t weight, memcached_connection_t type)
-{
- self->options.is_shutting_down= false;
- self->options.is_dead= false;
- self->number_of_hosts= 0;
- self->cursor_active= 0;
- self->port= port;
- self->io_bytes_sent= 0;
- self->request_id= 0;
- self->server_failure_counter= 0;
- self->server_failure_counter_query_id= 0;
- self->server_timeout_counter= 0;
- self->server_timeout_counter_query_id= 0;
- self->weight= weight ? weight : 1; // 1 is the default weight value
- self->io_wait_count.read= 0;
- self->io_wait_count.write= 0;
- self->io_wait_count.timeouts= 0;
- self->io_wait_count._bytes_read= 0;
- self->major_version= UINT8_MAX;
- self->micro_version= UINT8_MAX;
- self->minor_version= UINT8_MAX;
- self->type= type;
- self->error_messages= NULL;
-
- self->state= MEMCACHED_SERVER_STATE_NEW;
- self->next_retry= 0;
-
- self->root= root;
- if (root)
- {
- self->version= ++root->server_info.version;
- }
- else
- {
- self->version= UINT_MAX;
- }
- self->limit_maxbytes= 0;
- memcpy(self->hostname, hostname.c_str, hostname.size);
- self->hostname[hostname.size]= 0;
-}
-
-static memcached_server_st *_server_create(memcached_server_st *self, const Memcached *memc)
-{
- if (self == NULL)
- {
- self= libmemcached_xmalloc(memc, struct memcached_server_st);
-
- if (self == NULL)
- {
- return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
- }
-
- self->options.is_allocated= true;
- }
- else
- {
- self->options.is_allocated= false;
- }
-
- self->options.is_initialized= true;
-
- return self;
-}
-
-memcached_server_st *__server_create_with(Memcached *memc,
- memcached_server_st* allocated_instance,
- const memcached_string_t& hostname,
- const in_port_t port,
- uint32_t weight,
- const memcached_connection_t type)
-{
- if (memcached_is_valid_servername(hostname) == false)
- {
- memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid hostname provided"));
- return NULL;
- }
-
- allocated_instance= _server_create(allocated_instance, memc);
-
- if (allocated_instance == NULL)
- {
- return NULL;
- }
-
- _server_init(allocated_instance, const_cast<Memcached *>(memc), hostname, port, weight, type);
-
- return allocated_instance;
-}
-
-void __server_free(memcached_server_st *self)
-{
- memcached_error_free(*self);
-
- if (memcached_is_allocated(self))
- {
- libmemcached_free(self->root, self);
- }
- else
- {
- self->options.is_initialized= false;
- }
-}
-
-void memcached_server_free(memcached_server_st *self)
-{
- if (self == NULL)
- {
- return;
- }
-
- if (memcached_server_list_count(self))
- {
- memcached_server_list_free(self);
- return;
- }
-
- __server_free(self);
-}
-
-void memcached_server_error_reset(memcached_server_st *self)
-{
- WATCHPOINT_ASSERT(self);
- if (self == NULL)
- {
- return;
- }
-
- memcached_error_free(*self);
-}
-
-uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count)
-{
- WATCHPOINT_ASSERT(servers);
- if (servers == NULL)
- {
- return 0;
- }
-
- return servers->number_of_hosts= count;
-}
-
-uint32_t memcached_server_count(const memcached_st *self)
-{
- WATCHPOINT_ASSERT(self);
- if (self == NULL)
- return 0;
-
- return self->number_of_hosts;
-}
-
-const char *memcached_server_name(const memcached_instance_st * self)
-{
- WATCHPOINT_ASSERT(self);
- if (self)
- {
- return self->_hostname;
- }
-
- return NULL;
-}
-
-in_port_t memcached_server_port(const memcached_instance_st * self)
-{
- WATCHPOINT_ASSERT(self);
- if (self == NULL)
- {
- return 0;
- }
-
- return self->port();
-}
-
-in_port_t memcached_server_srcport(const memcached_instance_st * self)
-{
- WATCHPOINT_ASSERT(self);
- if (self == NULL || self->fd == INVALID_SOCKET || (self->type != MEMCACHED_CONNECTION_TCP && self->type != MEMCACHED_CONNECTION_UDP))
- {
- return 0;
- }
-
- struct sockaddr_in sin;
- socklen_t addrlen= sizeof(sin);
- if (getsockname(self->fd, (struct sockaddr*)&sin, &addrlen) != -1)
- {
- return ntohs(sin.sin_port);
- }
-
- return -1;
-}
-
-uint32_t memcached_server_response_count(const memcached_instance_st * self)
-{
- WATCHPOINT_ASSERT(self);
- if (self == NULL)
- {
- return 0;
- }
-
- return self->cursor_active_;
-}
-
-const char *memcached_server_type(const memcached_instance_st * ptr)
-{
- if (ptr)
- {
- switch (ptr->type)
- {
- case MEMCACHED_CONNECTION_TCP:
- return "TCP";
-
- case MEMCACHED_CONNECTION_UDP:
- return "UDP";
-
- case MEMCACHED_CONNECTION_UNIX_SOCKET:
- return "SOCKET";
- }
- }
-
- return "UNKNOWN";
-}
-
-uint8_t memcached_server_major_version(const memcached_instance_st * instance)
-{
- if (instance)
- {
- return instance->major_version;
- }
-
- return UINT8_MAX;
-}
-
-uint8_t memcached_server_minor_version(const memcached_instance_st * instance)
-{
- if (instance)
- {
- return instance->minor_version;
- }
-
- return UINT8_MAX;
-}
-
-uint8_t memcached_server_micro_version(const memcached_instance_st * instance)
-{
- if (instance)
- {
- return instance->micro_version;
- }
-
- return UINT8_MAX;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <cassert>
-
-memcached_server_st *__server_create_with(memcached_st *memc,
- memcached_server_st* self,
- const memcached_string_t& hostname,
- const in_port_t port,
- uint32_t weight,
- const memcached_connection_t type);
-
-memcached_return_t memcached_server_add_parsed(memcached_st *ptr,
- const char *hostname,
- size_t hostname_length,
- in_port_t port,
- uint32_t weight);
-
-void __server_free(memcached_server_st *);
-
-static inline bool memcached_is_valid_servername(const memcached_string_t& arg)
-{
- return (arg.c_str != NULL or arg.size == 0) and arg.size < MEMCACHED_NI_MAXHOST;
-}
-
-static inline bool memcached_is_valid_filename(const memcached_string_t& arg)
-{
- return arg.c_str != NULL and arg.size > 0 and arg.size < MEMCACHED_NI_MAXHOST;
-}
-
-void memcached_instance_free(memcached_instance_st *);
-
-void set_last_disconnected_host(memcached_instance_st* self);
-
-static inline void memcached_mark_server_for_timeout(memcached_instance_st* server)
-{
- if (server->state != MEMCACHED_SERVER_STATE_IN_TIMEOUT)
- {
- if (server->server_timeout_counter_query_id != server->root->query_id)
- {
- server->server_timeout_counter++;
- server->server_timeout_counter_query_id= server->root->query_id;
- }
-
- if (server->server_timeout_counter >= server->root->server_timeout_limit)
- {
- struct timeval next_time;
- if (gettimeofday(&next_time, NULL) == 0)
- {
- server->next_retry= next_time.tv_sec +server->root->retry_timeout;
- }
- else
- {
- server->next_retry= 1; // Setting the value to 1 causes the timeout to occur immediately
- }
-
- server->state= MEMCACHED_SERVER_STATE_IN_TIMEOUT;
- if (server->server_failure_counter_query_id != server->root->query_id)
- {
- server->server_failure_counter++;
- server->server_failure_counter_query_id= server->root->query_id;
- }
- set_last_disconnected_host(server);
- }
- }
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-typedef struct memcached_instance_st* memcached_server_write_instance_st;
-#else
-typedef void* memcached_server_write_instance_st;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef memcached_return_t (*memcached_server_execute_fn)(memcached_st *ptr, memcached_server_write_instance_st server, void *context);
-
-memcached_return_t memcached_server_execute(memcached_st *ptr,
- memcached_server_execute_fn callback,
- void *context);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-
-#include <libmemcached/common.h>
-
-memcached_server_list_st
-memcached_server_list_append_with_weight(memcached_server_list_st ptr,
- const char *hostname, in_port_t port,
- uint32_t weight,
- memcached_return_t *error)
-{
- memcached_return_t unused;
- if (error == NULL)
- {
- error= &unused;
- }
-
- if (hostname == NULL)
- {
- hostname= "localhost";
- }
-
- if (hostname[0] == '/')
- {
- port = 0;
- }
- else if (port == 0)
- {
- port= MEMCACHED_DEFAULT_PORT;
- }
-
-
- /* Increment count for hosts */
- uint32_t count= 1;
- if (ptr != NULL)
- {
- count+= memcached_server_list_count(ptr);
- }
-
- memcached_server_list_st new_host_list= (memcached_server_st*)realloc(ptr, sizeof(memcached_server_st) * count);
- if (new_host_list == NULL)
- {
-#if 0
- *error= memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
-#endif
- return NULL;
- }
-
- memcached_string_t _hostname= { memcached_string_make_from_cstr(hostname) };
- /* @todo Check return type */
- if (__server_create_with(NULL, &new_host_list[count-1], _hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET) == NULL)
- {
-#if 0
- *error= memcached_set_errno(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
-#endif
- free(new_host_list);
- return NULL;
- }
-
-#if 0
- // Handset allocated since
- new_host_list->options.is_allocated= true;
-#endif
-
- /* Backwards compatibility hack */
- memcached_servers_set_count(new_host_list, count);
-
- *error= MEMCACHED_SUCCESS;
- return new_host_list;
-}
-
-memcached_server_list_st
-memcached_server_list_append(memcached_server_list_st ptr,
- const char *hostname, in_port_t port,
- memcached_return_t *error)
-{
- return memcached_server_list_append_with_weight(ptr, hostname, port, 0, error);
-}
-
-uint32_t memcached_server_list_count(const memcached_server_list_st self)
-{
- return (self == NULL)
- ? 0
- : self->number_of_hosts;
-}
-
-uint32_t memcached_instance_list_count(const memcached_st* self)
-{
- return (self == NULL)
- ? 0
- : self->number_of_hosts;
-}
-
-void memcached_instance_set(memcached_st* memc, memcached_instance_st* list, const uint32_t host_list_size)
-{
- assert(memc);
- memc->servers= list;
- memc->number_of_hosts= host_list_size;
-}
-
-void memcached_server_list_free(memcached_server_list_st self)
-{
- if (self)
- {
- for (uint32_t x= 0; x < memcached_server_list_count(self); x++)
- {
- assert_msg(not memcached_is_allocated(&self[x]), "You have called memcached_server_list_free(), but you did not pass it a valid memcached_server_list_st");
- __server_free(&self[x]);
- }
-
- libmemcached_free(self->root, self);
- }
-}
-
-void memcached_instance_list_free(memcached_instance_st* self, uint32_t instance_count)
-{
- if (self)
- {
- for (uint32_t x= 0; x < instance_count; x++)
- {
- assert_msg(memcached_is_allocated(&self[x]) == false, "You have called memcached_server_list_free(), but you did not pass it a valid memcached_server_list_st");
- __instance_free(&self[x]);
- }
-
- libmemcached_free(self->root, self);
- }
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-memcached_instance_st* memcached_instance_list(const memcached_st *);
-
-uint32_t memcached_instance_list_count(const memcached_st*);
-
-uint32_t memcached_servers_set_count(memcached_server_list_st servers, uint32_t count);
-
-void memcached_instance_list_free(memcached_instance_st* self, uint32_t count);
-
-void memcached_instance_set(memcached_st*, memcached_instance_st*, const uint32_t host_list_size);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-/* To hide the platform differences between MS Windows and Unix, I am
- * going to use the Microsoft way and #define the Microsoft-specific
- * functions to the unix way. Microsoft use a separate subsystem for sockets,
- * but Unix normally just use a filedescriptor on the same functions. It is
- * a lot easier to map back to the unix way with macros than going the other
- * way without side effect ;-)
- */
-#if defined(WIN32) || defined(__MINGW32__)
-# include "win32/wrappers.h"
-# define get_socket_errno() WSAGetLastError()
-#else
-# include <unistd.h>
-# define INVALID_SOCKET -1
-# define SOCKET_ERROR -1
-# define closesocket(a) close(a)
-# define get_socket_errno() errno
-#endif
-
-#ifdef __cplusplus
-static inline void memcached_close_socket(memcached_socket_t& socket_fd)
-{
- closesocket(socket_fd);
- socket_fd= INVALID_SOCKET;
-}
-#endif
-
-#ifndef HAVE_MSG_NOSIGNAL
-# define MSG_NOSIGNAL 0
-#endif
-
-#ifndef HAVE_MSG_DONTWAIT
-# define MSG_DONTWAIT 0
-#endif
-
-#ifndef HAVE_MSG_MORE
-# define MSG_MORE 0
-#endif
-
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-static const char *memcached_stat_keys[] = {
- "pid",
- "uptime",
- "time",
- "version",
- "pointer_size",
- "rusage_user",
- "rusage_system",
- "curr_items",
- "total_items",
- "bytes",
- "curr_connections",
- "total_connections",
- "connection_structures",
- "cmd_get",
- "cmd_set",
- "get_hits",
- "get_misses",
- "evictions",
- "bytes_read",
- "bytes_written",
- "limit_maxbytes",
- "threads",
- NULL
-};
-
-struct local_context
-{
- memcached_stat_fn func;
- void *context;
- const char *args;
- const size_t args_length;
-
- local_context(memcached_stat_fn func_arg,
- void *context_arg,
- const char *args_arg,
- const size_t args_length_arg) :
- func(func_arg),
- context(context_arg),
- args(args_arg),
- args_length(args_length_arg)
- { }
-};
-
-
-static memcached_return_t set_data(memcached_stat_st *memc_stat, const char *key, const char *value)
-{
-
- if (strlen(key) < 1)
- {
- WATCHPOINT_STRING(key);
- return MEMCACHED_UNKNOWN_STAT_KEY;
- }
- else if (strcmp("pid", key) == 0)
- {
- errno= 0;
- int64_t temp= strtoll(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
-
- if (temp <= INT32_MAX and ( sizeof(pid_t) == sizeof(int32_t) ))
- {
- memc_stat->pid= pid_t(temp);
- }
- else if (temp > -1)
- {
- memc_stat->pid= pid_t(temp);
- }
- else
- {
- // If we got a value less then -1 then something went wrong in the
- // protocol
- }
- }
- else if (not strcmp("uptime", key))
- {
- errno= 0;
- memc_stat->uptime= strtoul(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("time", key))
- {
- errno= 0;
- memc_stat->time= strtoul(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("version", key))
- {
- memcpy(memc_stat->version, value, strlen(value));
- memc_stat->version[strlen(value)]= 0;
- }
- else if (not strcmp("pointer_size", key))
- {
- errno= 0;
- memc_stat->pointer_size= strtoul(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("rusage_user", key))
- {
- char *walk_ptr;
- for (walk_ptr= (char*)value; (!ispunct(*walk_ptr)); walk_ptr++) {};
- *walk_ptr= 0;
- walk_ptr++;
-
- errno= 0;
- memc_stat->rusage_user_seconds= strtoul(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
-
- errno= 0;
- memc_stat->rusage_user_microseconds= strtoul(walk_ptr, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("rusage_system", key))
- {
- char *walk_ptr;
- for (walk_ptr= (char*)value; (!ispunct(*walk_ptr)); walk_ptr++) {};
- *walk_ptr= 0;
- walk_ptr++;
-
- errno= 0;
- memc_stat->rusage_system_seconds= strtoul(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
-
- errno= 0;
- memc_stat->rusage_system_microseconds= strtoul(walk_ptr, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("curr_items", key))
- {
- errno= 0;
- memc_stat->curr_items= strtoul(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("total_items", key))
- {
- errno= 0;
- memc_stat->total_items= strtoul(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("bytes_read", key))
- {
- errno= 0;
- memc_stat->bytes_read= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("bytes_written", key))
- {
- errno= 0;
- memc_stat->bytes_written= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("bytes", key))
- {
- errno= 0;
- memc_stat->bytes= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("curr_connections", key))
- {
- errno= 0;
- memc_stat->curr_connections= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("total_connections", key))
- {
- errno= 0;
- memc_stat->total_connections= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("connection_structures", key))
- {
- errno= 0;
- memc_stat->connection_structures= strtoul(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("cmd_get", key))
- {
- errno= 0;
- memc_stat->cmd_get= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("cmd_set", key))
- {
- errno= 0;
- memc_stat->cmd_set= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("get_hits", key))
- {
- errno= 0;
- memc_stat->get_hits= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("get_misses", key))
- {
- errno= 0;
- memc_stat->get_misses= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("evictions", key))
- {
- errno= 0;
- memc_stat->evictions= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("limit_maxbytes", key))
- {
- errno= 0;
- memc_stat->limit_maxbytes= strtoull(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if (not strcmp("threads", key))
- {
- errno= 0;
- memc_stat->threads= strtoul(value, (char **)NULL, 10);
- if (errno != 0)
- {
- return MEMCACHED_FAILURE;
- }
- }
- else if ((strcmp("delete_misses", key) == 0 or /* New stats in the 1.3 beta */
- strcmp("delete_hits", key) == 0 or /* Just swallow them for now.. */
- strcmp("incr_misses", key) == 0 or
- strcmp("incr_hits", key) == 0 or
- strcmp("decr_misses", key) == 0 or
- strcmp("decr_hits", key) == 0 or
- strcmp("cas_misses", key) == 0 or
- strcmp("cas_hits", key) == 0 or
- strcmp("cas_badval", key) == 0 or
- strcmp("cmd_flush", key) == 0 or
- strcmp("accepting_conns", key) == 0 or
- strcmp("listen_disabled_num", key) == 0 or
- strcmp("conn_yields", key) == 0 or
- strcmp("auth_cmds", key) == 0 or
- strcmp("auth_errors", key) == 0 or
- strcmp("reclaimed", key) == 0) == 0)
- {
- WATCHPOINT_STRING(key);
- /* return MEMCACHED_UNKNOWN_STAT_KEY; */
- return MEMCACHED_SUCCESS;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-char *memcached_stat_get_value(const memcached_st* shell, memcached_stat_st *memc_stat,
- const char *key, memcached_return_t *error)
-{
- memcached_return_t not_used;
- if (error == NULL)
- {
- error= ¬_used;
- }
-
- if (memc_stat == NULL)
- {
- *error= MEMCACHED_INVALID_ARGUMENTS;
- return NULL;
- }
-
- char buffer[SMALL_STRING_LEN];
- int length;
-
- *error= MEMCACHED_SUCCESS;
-
- if (memcmp("pid", key, sizeof("pid") -1) == 0)
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lld", (signed long long)memc_stat->pid);
- }
- else if (not memcmp("uptime", key, sizeof("uptime") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->uptime);
- }
- else if (not memcmp("time", key, sizeof("time") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time);
- }
- else if (not memcmp("version", key, sizeof("version") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version);
- }
- else if (not memcmp("pointer_size", key, sizeof("pointer_size") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->pointer_size);
- }
- else if (not memcmp("rusage_user", key, sizeof("rusage_user") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu.%lu", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds);
- }
- else if (not memcmp("rusage_system", key, sizeof("rusage_system") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu.%lu", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds);
- }
- else if (not memcmp("curr_items", key, sizeof("curr_items") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->curr_items);
- }
- else if (not memcmp("total_items", key, sizeof("total_items") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->total_items);
- }
- else if (not memcmp("curr_connections", key, sizeof("curr_connections") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->curr_connections);
- }
- else if (not memcmp("total_connections", key, sizeof("total_connections") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->total_connections);
- }
- else if (not memcmp("connection_structures", key, sizeof("connection_structures") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->connection_structures);
- }
- else if (not memcmp("cmd_get", key, sizeof("cmd_get") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get);
- }
- else if (not memcmp("cmd_set", key, sizeof("cmd_set") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set);
- }
- else if (not memcmp("get_hits", key, sizeof("get_hits") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits);
- }
- else if (not memcmp("get_misses", key, sizeof("get_misses") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses);
- }
- else if (not memcmp("evictions", key, sizeof("evictions") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions);
- }
- else if (not memcmp("bytes_read", key, sizeof("bytes_read") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read);
- }
- else if (not memcmp("bytes_written", key, sizeof("bytes_written") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written);
- }
- else if (not memcmp("bytes", key, sizeof("bytes") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes);
- }
- else if (not memcmp("limit_maxbytes", key, sizeof("limit_maxbytes") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes);
- }
- else if (not memcmp("threads", key, sizeof("threads") -1))
- {
- length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->threads);
- }
- else
- {
- Memcached* memc= (Memcached*)memcached2Memcached(shell);
- *error= memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid key provided"));
- return NULL;
- }
-
- if (length >= SMALL_STRING_LEN || length < 0)
- {
- Memcached* memc= (Memcached*)memcached2Memcached(shell);
- *error= memcached_set_error(*memc, MEMCACHED_FAILURE, MEMCACHED_AT, memcached_literal_param("Internal failure occured with buffer, please report this bug."));
- return NULL;
- }
-
- // User is responsible for free() memory, so use malloc()
- char *ret= static_cast<char *>(malloc(size_t(length +1)));
- memcpy(ret, buffer, (size_t) length);
- ret[length]= '\0';
-
- return ret;
-}
-
-static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat,
- const char *args,
- const size_t args_length,
- memcached_instance_st* instance,
- struct local_context *check)
-{
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- protocol_binary_request_stats request= {}; // = {.bytes= {0}};
- memcached_return_t rc;
-
- initialize_binary_request(instance, request.message.header);
-
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
- if (args_length)
- {
- request.message.header.request.keylen= htons(uint16_t(args_length));
- request.message.header.request.bodylen= htonl(uint32_t( args_length));
-
- libmemcached_io_vector_st vector[]=
- {
- { request.bytes, sizeof(request.bytes) },
- { args, args_length }
- };
-
- if (memcached_failed(rc = memcached_vdo(instance, vector, 2, true)))
- {
- return rc;
- }
- }
- else
- {
- libmemcached_io_vector_st vector[]=
- {
- { request.bytes, sizeof(request.bytes) }
- };
-
- if (memcached_failed(rc = memcached_vdo(instance, vector, 1, true)))
- {
- return rc;
- }
- }
-
- memcached_server_response_decrement(instance);
- while (1)
- {
- rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
-
- if (rc == MEMCACHED_END)
- {
- break;
- }
-
- if (rc != MEMCACHED_SUCCESS)
- {
- return rc;
- }
-
- if (check && check->func)
- {
- size_t key_length= strlen(buffer);
-
- check->func(instance,
- buffer, key_length,
- buffer+key_length+1, strlen(buffer+key_length+1),
- check->context);
- }
-
- if (memc_stat)
- {
- if ((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
- {
- WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
- WATCHPOINT_ASSERT(0);
- }
- }
- }
-
- /*
- * memcached_response will decrement the counter, so I need to reset it..
- * todo: look at this and try to find a better solution.
- * */
- instance->cursor_active_= 0;
-
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat,
- const char *args,
- const size_t args_length,
- memcached_instance_st* instance,
- struct local_context *check)
-{
- libmemcached_io_vector_st vector[]=
- {
- { memcached_literal_param("stats ") },
- { args, args_length },
- { memcached_literal_param("\r\n") }
- };
-
- memcached_return_t rc= memcached_vdo(instance, vector, 3, true);
- if (memcached_success(rc))
- {
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- while ((rc= memcached_response(instance, buffer, sizeof(buffer), NULL)) == MEMCACHED_STAT)
- {
- char *string_ptr= buffer;
- string_ptr+= 5; /* Move past STAT */
-
- char *end_ptr;
- for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++) {};
- char *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++) {};
- char *value= string_ptr;
- value[(size_t)(end_ptr -string_ptr)]= 0;
-#if 0
- bool check_bool= bool(check);
- bool check_func_bool= bool(check) ? bool(check->func) : false;
- fprintf(stderr, "%s:%d %s %s %d:%d\n", __FILE__, __LINE__, key, value, check_bool, check_func_bool);
-#endif
-
- if (check and check->func)
- {
- check->func(instance,
- key, strlen(key),
- value, strlen(value),
- check->context);
- }
-
- if (memc_stat)
- {
- if((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY)
- {
- WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
- WATCHPOINT_ASSERT(0);
- }
- }
- }
- }
-
- if (rc == MEMCACHED_ERROR)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- if (rc == MEMCACHED_END)
- {
- return MEMCACHED_SUCCESS;
- }
-
- return rc;
-}
-
-memcached_stat_st *memcached_stat(memcached_st *shell, char *args, memcached_return_t *error)
-{
- Memcached* self= memcached2Memcached(shell);
- memcached_return_t unused;
- if (error == NULL)
- {
- error= &unused;
- }
-
- if (memcached_failed(*error= initialize_query(self, true)))
- {
- return NULL;
- }
-
- if (memcached_is_udp(self))
- {
- *error= memcached_set_error(*self, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
- return NULL;
- }
-
- memcached_return_t rc;
- size_t args_length= 0;
- if (args)
- {
- args_length= strlen(args);
- if (memcached_failed(rc= memcached_key_test(*self, (const char **)&args, &args_length, 1)))
- {
- *error= memcached_set_error(*self, rc, MEMCACHED_AT);
- return NULL;
- }
- }
-
- WATCHPOINT_ASSERT(error);
-
- memcached_stat_st *stats= libmemcached_xcalloc(self, memcached_server_count(self), memcached_stat_st);
- if (stats == NULL)
- {
- *error= memcached_set_error(*self, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- return NULL;
- }
-
- WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
- rc= MEMCACHED_SUCCESS;
- for (uint32_t x= 0; x < memcached_server_count(self); x++)
- {
- memcached_stat_st* stat_instance= stats +x;
-
- stat_instance->pid= -1;
- stat_instance->root= self;
-
- memcached_instance_st* instance= memcached_instance_fetch(self, x);
-
- memcached_return_t temp_return;
- if (memcached_is_binary(self))
- {
- temp_return= binary_stats_fetch(stat_instance, args, args_length, instance, NULL);
- }
- else
- {
- temp_return= ascii_stats_fetch(stat_instance, args, args_length, instance, NULL);
- }
-
- // Special case where "args" is invalid
- if (temp_return == MEMCACHED_INVALID_ARGUMENTS)
- {
- rc= MEMCACHED_INVALID_ARGUMENTS;
- break;
- }
-
- if (memcached_failed(temp_return))
- {
- 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_st memc;
-
- memcached_stat_st unused_memc_stat;
- if (memc_stat == NULL)
- {
- memc_stat= &unused_memc_stat;
- }
-
- memset(memc_stat, 0, sizeof(memcached_stat_st));
-
- memcached_st *memc_ptr= memcached_create(&memc);
- if (memc_ptr == NULL)
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- memcached_return_t rc;
- if (memcached_failed(rc= memcached_server_add(&memc, hostname, port)))
- {
- memcached_free(&memc);
- return rc;
- }
-
- if (memcached_success(rc= initialize_query(memc_ptr, true)))
- {
- size_t args_length= 0;
- if (args)
- {
- args_length= strlen(args);
- rc= memcached_key_test(*memc_ptr, (const char **)&args, &args_length, 1);
- }
-
- if (memcached_success(rc))
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc_ptr, 0);
- if (memc.flags.binary_protocol)
- {
- rc= binary_stats_fetch(memc_stat, args, args_length, instance, NULL);
- }
- else
- {
- rc= ascii_stats_fetch(memc_stat, args, args_length, instance, NULL);
- }
- }
- }
-
- memcached_free(&memc);
-
- return rc;
-}
-
-/*
- We make a copy of the keys since at some point in the not so distant future
- we will add support for "found" keys.
-*/
-char ** memcached_stat_get_keys(memcached_st *shell,
- memcached_stat_st *,
- memcached_return_t *error)
-{
- Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- char **list= static_cast<char **>(libmemcached_malloc(memc, sizeof(memcached_stat_keys)));
- if (list == NULL)
- {
- if (error)
- {
- *error= memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
-
- return NULL;
- }
-
- memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys));
-
- if (error)
- {
- *error= MEMCACHED_SUCCESS;
- }
-
- return list;
- }
-
- return NULL;
-}
-
-void memcached_stat_free(const memcached_st *, memcached_stat_st *memc_stat)
-{
- WATCHPOINT_ASSERT(memc_stat); // Be polite, but when debugging catch this as an error
- if (memc_stat)
- {
- libmemcached_free(memc_stat->root, memc_stat);
- }
-}
-
-static memcached_return_t call_stat_fn(memcached_st *memc,
- memcached_instance_st* instance,
- void *context)
-{
- if (memc)
- {
- local_context *check= (struct local_context *)context;
-
- if (memcached_is_binary(memc))
- {
- return binary_stats_fetch(NULL, check->args, check->args_length, instance, check);
- }
- else
- {
- return ascii_stats_fetch(NULL, check->args, check->args_length, instance, check);
- }
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
-
-memcached_return_t memcached_stat_execute(memcached_st *shell, const char *args, memcached_stat_fn func, void *context)
-{
- Memcached* memc= memcached2Memcached(shell);
- if (memcached_fatal(memcached_version(memc)))
- {
- return memcached_last_error(memc);
- }
-
- local_context check(func, context, args, args ? strlen(args) : 0);
-
- return memcached_server_execute(memc, call_stat_fn, (void *)&check);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libmemcached/common.h>
-
-enum memcached_storage_action_t {
- SET_OP,
- REPLACE_OP,
- ADD_OP,
- PREPEND_OP,
- APPEND_OP,
- CAS_OP
-};
-
-/* Inline this */
-static inline const char *storage_op_string(memcached_storage_action_t verb)
-{
- switch (verb)
- {
- case REPLACE_OP:
- return "replace ";
-
- case ADD_OP:
- return "add ";
-
- case PREPEND_OP:
- return "prepend ";
-
- case APPEND_OP:
- return "append ";
-
- case CAS_OP:
- return "cas ";
-
- case SET_OP:
- break;
- }
-
- return "set ";
-}
-
-static inline bool can_by_encrypted(const memcached_storage_action_t verb)
-{
- switch (verb)
- {
- case SET_OP:
- case ADD_OP:
- case CAS_OP:
- case REPLACE_OP:
- return true;
-
- case APPEND_OP:
- case PREPEND_OP:
- break;
- }
-
- return false;
-}
-
-static inline uint8_t get_com_code(const memcached_storage_action_t verb, const bool reply)
-{
- if (reply == false)
- {
- switch (verb)
- {
- case SET_OP:
- return PROTOCOL_BINARY_CMD_SETQ;
-
- case ADD_OP:
- return PROTOCOL_BINARY_CMD_ADDQ;
-
- case CAS_OP: /* FALLTHROUGH */
- case REPLACE_OP:
- return PROTOCOL_BINARY_CMD_REPLACEQ;
-
- case APPEND_OP:
- return PROTOCOL_BINARY_CMD_APPENDQ;
-
- case PREPEND_OP:
- return PROTOCOL_BINARY_CMD_PREPENDQ;
- }
- }
-
- switch (verb)
- {
- case SET_OP:
- break;
-
- case ADD_OP:
- return PROTOCOL_BINARY_CMD_ADD;
-
- case CAS_OP: /* FALLTHROUGH */
- case REPLACE_OP:
- return PROTOCOL_BINARY_CMD_REPLACE;
-
- case APPEND_OP:
- return PROTOCOL_BINARY_CMD_APPEND;
-
- case PREPEND_OP:
- return PROTOCOL_BINARY_CMD_PREPEND;
- }
-
- return PROTOCOL_BINARY_CMD_SET;
-}
-
-static memcached_return_t memcached_send_binary(Memcached *ptr,
- memcached_instance_st* server,
- uint32_t server_key,
- const char *key,
- const size_t key_length,
- const char *value,
- const size_t value_length,
- const time_t expiration,
- const uint32_t flags,
- const uint64_t cas,
- const bool flush,
- const bool reply,
- memcached_storage_action_t verb)
-{
- protocol_binary_request_set request= {};
- size_t send_length= sizeof(request.bytes);
-
- initialize_binary_request(server, request.message.header);
-
- request.message.header.request.opcode= get_com_code(verb, reply);
- request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace)));
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- if (verb == APPEND_OP or verb == PREPEND_OP)
- {
- send_length -= 8; /* append & prepend does not contain extras! */
- }
- else
- {
- request.message.header.request.extlen= 8;
- request.message.body.flags= htonl(flags);
- request.message.body.expiration= htonl((uint32_t)expiration);
- }
-
- request.message.header.request.bodylen= htonl((uint32_t) (key_length + memcached_array_size(ptr->_namespace) + value_length +
- request.message.header.request.extlen));
-
- if (cas)
- {
- request.message.header.request.cas= memcached_htonll(cas);
- }
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { request.bytes, send_length },
- { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
- { key, key_length },
- { value, value_length }
- };
-
- /* write the header */
- memcached_return_t rc;
- if ((rc= memcached_vdo(server, vector, 5, flush)) != MEMCACHED_SUCCESS)
- {
- assert(memcached_last_error(server->root) != MEMCACHED_SUCCESS);
- return memcached_last_error(server->root);
- }
-
- if (verb == SET_OP and ptr->number_of_replicas > 0)
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
- WATCHPOINT_STRING("replicating");
-
- for (uint32_t x= 0; x < ptr->number_of_replicas; x++)
- {
- ++server_key;
- if (server_key == memcached_server_count(ptr))
- {
- server_key= 0;
- }
-
- memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
-
- if (memcached_success(memcached_vdo(instance, vector, 5, false)))
- {
- memcached_server_response_decrement(instance);
- }
- }
- }
-
- if (flush == false)
- {
- return MEMCACHED_BUFFERED;
- }
-
- // No reply always assumes success
- if (reply == false)
- {
- return MEMCACHED_SUCCESS;
- }
-
- return memcached_response(server, NULL, 0, NULL);
-}
-
-static memcached_return_t memcached_send_ascii(Memcached *ptr,
- memcached_instance_st* instance,
- const char *key,
- const size_t key_length,
- const char *value,
- const size_t value_length,
- const time_t expiration,
- const uint32_t flags,
- const uint64_t cas,
- const bool flush,
- const bool reply,
- const memcached_storage_action_t verb)
-{
- char flags_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
- int flags_buffer_length= snprintf(flags_buffer, sizeof(flags_buffer), " %u", flags);
- if (size_t(flags_buffer_length) >= sizeof(flags_buffer) or flags_buffer_length < 0)
- {
- return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
- }
-
- char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
- int expiration_buffer_length= snprintf(expiration_buffer, sizeof(expiration_buffer), " %llu", (unsigned long long)expiration);
- if (size_t(expiration_buffer_length) >= sizeof(expiration_buffer) or expiration_buffer_length < 0)
- {
- return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
- }
-
- char value_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
- int value_buffer_length= snprintf(value_buffer, sizeof(value_buffer), " %llu", (unsigned long long)value_length);
- if (size_t(value_buffer_length) >= sizeof(value_buffer) or value_buffer_length < 0)
- {
- return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
- }
-
- char cas_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
- int cas_buffer_length= 0;
- if (cas)
- {
- cas_buffer_length= snprintf(cas_buffer, sizeof(cas_buffer), " %llu", (unsigned long long)cas);
- if (size_t(cas_buffer_length) >= sizeof(cas_buffer) or cas_buffer_length < 0)
- {
- return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
- }
- }
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { storage_op_string(verb), strlen(storage_op_string(verb))},
- { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
- { key, key_length },
- { flags_buffer, size_t(flags_buffer_length) },
- { expiration_buffer, size_t(expiration_buffer_length) },
- { value_buffer, size_t(value_buffer_length) },
- { cas_buffer, size_t(cas_buffer_length) },
- { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
- { memcached_literal_param("\r\n") },
- { value, value_length },
- { memcached_literal_param("\r\n") }
- };
-
- /* Send command header */
- memcached_return_t rc= memcached_vdo(instance, vector, 12, flush);
-
- // If we should not reply, return with MEMCACHED_SUCCESS, unless error
- if (reply == false)
- {
- return memcached_success(rc) ? MEMCACHED_SUCCESS : rc;
- }
-
- if (flush == false)
- {
- return memcached_success(rc) ? MEMCACHED_BUFFERED : rc;
- }
-
- if (rc == MEMCACHED_SUCCESS)
- {
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
-
- if (rc == MEMCACHED_STORED)
- {
- return MEMCACHED_SUCCESS;
- }
- }
-
- assert(memcached_failed(rc));
-#if 0
- if (memcached_has_error(ptr) == false)
- {
- return memcached_set_error(*ptr, rc, MEMCACHED_AT);
- }
-#endif
-
- return rc;
-}
-
-static inline memcached_return_t memcached_send(memcached_st *shell,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- const time_t expiration,
- const uint32_t flags,
- const uint64_t cas,
- memcached_storage_action_t verb)
-{
- Memcached* ptr= memcached2Memcached(shell);
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(ptr, true)))
- {
- return rc;
- }
-
- if (memcached_failed(memcached_key_test(*ptr, (const char **)&key, &key_length, 1)))
- {
- return memcached_last_error(ptr);
- }
-
- uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
- memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
-
- WATCHPOINT_SET(instance->io_wait_count.read= 0);
- WATCHPOINT_SET(instance->io_wait_count.write= 0);
-
- bool flush= true;
- if (memcached_is_buffering(instance->root) and verb == SET_OP)
- {
- flush= false;
- }
-
- bool reply= memcached_is_replying(ptr);
-
- hashkit_string_st* destination= NULL;
-
- if (memcached_is_encrypted(ptr))
- {
- if (can_by_encrypted(verb) == false)
- {
- return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
- memcached_literal_param("Operation not allowed while encyrption is enabled"));
- }
-
- if ((destination= hashkit_encrypt(&ptr->hashkit, value, value_length)) == NULL)
- {
- return rc;
- }
- value= hashkit_string_c_str(destination);
- value_length= hashkit_string_length(destination);
- }
-
- if (memcached_is_binary(ptr))
- {
- rc= memcached_send_binary(ptr, instance, server_key,
- key, key_length,
- value, value_length, expiration,
- flags, cas, flush, reply, verb);
- }
- else
- {
- rc= memcached_send_ascii(ptr, instance,
- key, key_length,
- value, value_length, expiration,
- flags, cas, flush, reply, verb);
- }
-
- hashkit_string_free(destination);
-
- return rc;
-}
-
-
-memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_SET_START();
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, SET_OP);
- LIBMEMCACHED_MEMCACHED_SET_END();
- return rc;
-}
-
-memcached_return_t memcached_add(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_ADD_START();
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, ADD_OP);
-
- LIBMEMCACHED_MEMCACHED_ADD_END();
- return rc;
-}
-
-memcached_return_t memcached_replace(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_REPLACE_START();
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, REPLACE_OP);
- LIBMEMCACHED_MEMCACHED_REPLACE_END();
- return rc;
-}
-
-memcached_return_t memcached_prepend(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, PREPEND_OP);
- return rc;
-}
-
-memcached_return_t memcached_append(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, APPEND_OP);
- return rc;
-}
-
-memcached_return_t memcached_cas(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas)
-{
- memcached_return_t rc;
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, cas, CAS_OP);
- return rc;
-}
-
-memcached_return_t memcached_set_by_key(memcached_st *ptr,
- const char *group_key,
- size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_SET_START();
- rc= memcached_send(ptr, group_key, group_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, SET_OP);
- LIBMEMCACHED_MEMCACHED_SET_END();
- return rc;
-}
-
-memcached_return_t memcached_add_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_ADD_START();
- rc= memcached_send(ptr, group_key, group_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, ADD_OP);
- LIBMEMCACHED_MEMCACHED_ADD_END();
- return rc;
-}
-
-memcached_return_t memcached_replace_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_REPLACE_START();
- rc= memcached_send(ptr, group_key, group_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, REPLACE_OP);
- LIBMEMCACHED_MEMCACHED_REPLACE_END();
- return rc;
-}
-
-memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- return memcached_send(ptr, group_key, group_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, PREPEND_OP);
-}
-
-memcached_return_t memcached_append_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- return memcached_send(ptr, group_key, group_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, APPEND_OP);
-}
-
-memcached_return_t memcached_cas_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas)
-{
- return memcached_send(ptr, group_key, group_key_length,
- key, key_length, value, value_length,
- expiration, flags, cas, CAS_OP);
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-const char *memcached_strerror(const memcached_st *, memcached_return_t rc)
-{
- switch (rc)
- {
- case MEMCACHED_SUCCESS:
- return "SUCCESS";
-
- case MEMCACHED_FAILURE:
- return "FAILURE";
-
- case MEMCACHED_HOST_LOOKUP_FAILURE: // getaddrinfo only
- return "getaddrinfo() or getnameinfo() HOSTNAME LOOKUP FAILURE";
-
- case MEMCACHED_CONNECTION_FAILURE:
- return "CONNECTION FAILURE";
-
- case MEMCACHED_CONNECTION_BIND_FAILURE: // DEPRECATED, see MEMCACHED_HOST_LOOKUP_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_ERROR:
- return "ERROR was returned by server";
-
- case MEMCACHED_DATA_EXISTS:
- return "CONNECTION DATA EXISTS";
-
- case MEMCACHED_DATA_DOES_NOT_EXIST:
- return "CONNECTION DATA DOES NOT EXIST";
-
- case MEMCACHED_NOTSTORED:
- return "NOT STORED";
-
- case MEMCACHED_STORED:
- return "STORED";
-
- case MEMCACHED_NOTFOUND:
- return "NOT FOUND";
-
- case MEMCACHED_MEMORY_ALLOCATION_FAILURE:
- return "MEMORY ALLOCATION FAILURE";
-
- case MEMCACHED_PARTIAL_READ:
- return "PARTIAL READ";
-
- case MEMCACHED_SOME_ERRORS:
- return "SOME ERRORS WERE REPORTED";
-
- case MEMCACHED_NO_SERVERS:
- return "NO SERVERS DEFINED";
-
- case MEMCACHED_END:
- return "SERVER END";
-
- case MEMCACHED_DELETED:
- return "SERVER DELETE";
-
- case MEMCACHED_VALUE:
- return "SERVER VALUE";
-
- case MEMCACHED_STAT:
- return "STAT VALUE";
-
- case MEMCACHED_ITEM:
- return "ITEM VALUE";
-
- case MEMCACHED_ERRNO:
- return "SYSTEM ERROR";
-
- case MEMCACHED_FAIL_UNIX_SOCKET:
- return "COULD NOT OPEN UNIX SOCKET";
-
- case MEMCACHED_NOT_SUPPORTED:
- return "ACTION NOT SUPPORTED";
-
- case MEMCACHED_FETCH_NOTFINISHED:
- return "FETCH WAS NOT COMPLETED";
-
- case MEMCACHED_NO_KEY_PROVIDED:
- return "A KEY LENGTH OF ZERO WAS PROVIDED";
-
- case MEMCACHED_BUFFERED:
- return "ACTION QUEUED";
-
- case MEMCACHED_TIMEOUT:
- return "A TIMEOUT OCCURRED";
-
- case MEMCACHED_BAD_KEY_PROVIDED:
- return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE";
-
- case MEMCACHED_INVALID_HOST_PROTOCOL:
- return "THE HOST TRANSPORT PROTOCOL DOES NOT MATCH THAT OF THE CLIENT";
-
- case MEMCACHED_SERVER_MARKED_DEAD:
- return "SERVER IS MARKED DEAD";
-
- case MEMCACHED_UNKNOWN_STAT_KEY:
- return "ENCOUNTERED AN UNKNOWN STAT KEY";
-
- case MEMCACHED_E2BIG:
- return "ITEM TOO BIG";
-
- case MEMCACHED_INVALID_ARGUMENTS:
- return "INVALID ARGUMENTS";
-
- case MEMCACHED_KEY_TOO_BIG:
- return "KEY RETURNED FROM SERVER WAS TOO LARGE";
-
- case MEMCACHED_AUTH_PROBLEM:
- return "FAILED TO SEND AUTHENTICATION TO SERVER";
-
- case MEMCACHED_AUTH_FAILURE:
- return "AUTHENTICATION FAILURE";
-
- case MEMCACHED_AUTH_CONTINUE:
- return "CONTINUE AUTHENTICATION";
-
- case MEMCACHED_PARSE_ERROR:
- return "ERROR OCCURED WHILE PARSING";
-
- case MEMCACHED_PARSE_USER_ERROR:
- return "USER INITIATED ERROR OCCURED WHILE PARSING";
-
- case MEMCACHED_DEPRECATED:
- return "DEPRECATED";
-
- case MEMCACHED_IN_PROGRESS:
- return "OPERATION IN PROCESS";
-
- case MEMCACHED_SERVER_TEMPORARILY_DISABLED:
- return "SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY";
-
- case MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE:
- return "SERVER FAILED TO ALLOCATE OBJECT";
-
- case MEMCACHED_UNIX_SOCKET_PATH_TOO_BIG:
- return "UNIX SOCKET PATH TOO LARGE";
-
- default:
- case MEMCACHED_MAXIMUM_RETURN:
- return "INVALID memcached_return_t";
- }
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libmemcached/common.h>
-
-inline static memcached_return_t _string_check(memcached_string_st *string, size_t need)
-{
- if (need && need > (size_t)(string->current_size - (size_t)(string->end - string->string)))
- {
- size_t current_offset= (size_t) (string->end - string->string);
-
- /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
- size_t adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / MEMCACHED_BLOCK_SIZE;
- adjust++;
-
- size_t new_size= sizeof(char) * (size_t)((adjust * MEMCACHED_BLOCK_SIZE) + string->current_size);
- /* Test for overflow */
- if (new_size < need)
- {
- char error_message[1024];
- int error_message_length= snprintf(error_message, sizeof(error_message),"Needed %ld, got %ld", (long)need, (long)new_size);
- return memcached_set_error(*string->root, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, error_message, error_message_length);
- }
-
- char *new_value= libmemcached_xrealloc(string->root, string->string, new_size, char);
-
- if (new_value == NULL)
- {
- return memcached_set_error(*string->root, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
- }
-
- string->string= new_value;
- string->end= string->string + current_offset;
-
- string->current_size+= (MEMCACHED_BLOCK_SIZE * adjust);
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-static inline void _init_string(memcached_string_st *self)
-{
- self->current_size= 0;
- self->end= self->string= NULL;
-}
-
-memcached_string_st *memcached_string_create(Memcached *memc, memcached_string_st *self, size_t initial_size)
-{
- WATCHPOINT_ASSERT(memc);
-
- /* Saving malloc calls :) */
- if (self)
- {
- WATCHPOINT_ASSERT(self->options.is_initialized == false);
-
- memcached_set_allocated(self, false);
- }
- else
- {
- self= libmemcached_xmalloc(memc, memcached_string_st);
-
- if (self == NULL)
- {
- return NULL;
- }
-
- memcached_set_allocated(self, true);
- }
- self->root= memc;
-
- _init_string(self);
-
- if (memcached_failed(_string_check(self, initial_size)))
- {
- if (memcached_is_allocated(self))
- {
- libmemcached_free(memc, self);
- }
-
- return NULL;
- }
-
- memcached_set_initialized(self, true);
-
- WATCHPOINT_ASSERT(self->string == self->end);
-
- return self;
-}
-
-static memcached_return_t memcached_string_append_null(memcached_string_st& string)
-{
- if (memcached_failed(_string_check(&string, 1)))
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- *string.end= 0;
-
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t memcached_string_append_null(memcached_string_st *string)
-{
- if (memcached_failed(_string_check(string, 1)))
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- *string->end= 0;
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_string_append_character(memcached_string_st *string,
- char character)
-{
- if (memcached_failed(_string_check(string, 1)))
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- *string->end= character;
- string->end++;
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_string_append(memcached_string_st *string,
- const char *value, size_t length)
-{
- if (memcached_failed(_string_check(string, length)))
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- 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)
-{
- if (memcached_string_length(string) == 0)
- {
- return NULL;
- }
-
- char *c_ptr= static_cast<char *>(libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char)));
-
- if (c_ptr == NULL)
- {
- return NULL;
- }
-
- memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string));
- c_ptr[memcached_string_length(string)]= 0;
-
- return c_ptr;
-}
-
-bool memcached_string_set(memcached_string_st& string, const char* value, size_t length)
-{
- memcached_string_reset(&string);
- if (memcached_success(memcached_string_append(&string, value, length)))
- {
- memcached_string_append_null(string);
- return true;
- }
-
- return false;
-}
-
-void memcached_string_reset(memcached_string_st *string)
-{
- string->end= string->string;
-}
-
-void memcached_string_free(memcached_string_st& ptr)
-{
- memcached_string_free(&ptr);
-}
-
-void memcached_string_free(memcached_string_st *ptr)
-{
- if (ptr == NULL)
- {
- return;
- }
-
- if (ptr->string)
- {
- libmemcached_free(ptr->root, ptr->string);
- }
-
- if (memcached_is_allocated(ptr))
- {
- libmemcached_free(ptr->root, ptr);
- }
- else
- {
- ptr->options.is_initialized= false;
- }
-}
-
-memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
-{
- return _string_check(string, need);
-}
-
-bool memcached_string_resize(memcached_string_st& string, const size_t need)
-{
- return memcached_success(_string_check(&string, need));
-}
-
-size_t memcached_string_length(const memcached_string_st *self)
-{
- return size_t(self->end -self->string);
-}
-
-size_t memcached_string_length(const memcached_string_st& self)
-{
- return size_t(self.end -self.string);
-}
-
-size_t memcached_string_size(const memcached_string_st *self)
-{
- return self->current_size;
-}
-
-const char *memcached_string_value(const memcached_string_st *self)
-{
- return self->string;
-}
-
-const char *memcached_string_value(const memcached_string_st& self)
-{
- return self.string;
-}
-
-char *memcached_string_take_value(memcached_string_st *self)
-{
- char* value= NULL;
-
- assert_msg(self, "Invalid memcached_string_st");
- if (self)
- {
- if (memcached_string_length(self))
- {
- // If we fail at adding the null, we copy and move on
- if (memcached_failed(memcached_string_append_null(self)))
- {
- return NULL;
- }
-
- value= self->string;
- _init_string(self);
- }
- }
-
- return value;
-}
-
-char *memcached_string_value_mutable(const memcached_string_st *self)
-{
- return self->string;
-}
-
-char *memcached_string_c_str(memcached_string_st& self)
-{
- return self.string;
-}
-
-void memcached_string_set_length(memcached_string_st *self, size_t length)
-{
- self->end= self->string +length;
-}
-
-void memcached_string_set_length(memcached_string_st& self, const size_t length)
-{
- assert(self.current_size >= length);
- size_t set_length= length;
- if (self.current_size > length)
- {
- if (memcached_failed(_string_check(&self, length)))
- {
- set_length= self.current_size;
- }
- }
- self.end= self.string +set_length;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * libmcachedd client library.
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include "util/string.hpp"
-
-#define memcached_literal_param util_literal_param
-#define memcached_literal_param_size util_literal_param_size
-#define memcached_string_make_from_cstr util_string_make_from_cstr
-#define memcached_array_length util_array_length
-
-/**
- Strings are always under our control so we make some assumptions
- about them.
-
- 1) is_initialized is always valid.
- 2) A string once intialized will always be, until free where we
- unset this flag.
- 3) A string always has a root.
-*/
-
-memcached_string_st *memcached_string_create(memcached_st *ptr,
- memcached_string_st *string,
- size_t initial_size);
-
-memcached_return_t memcached_string_check(memcached_string_st *string, size_t need);
-
-char *memcached_string_c_copy(memcached_string_st *string);
-
-memcached_return_t memcached_string_append_character(memcached_string_st *string,
- char character);
-
-memcached_return_t memcached_string_append(memcached_string_st *string,
- const char *value, size_t length);
-
-void memcached_string_reset(memcached_string_st *string);
-
-void memcached_string_free(memcached_string_st *string);
-void memcached_string_free(memcached_string_st&);
-
-size_t memcached_string_length(const memcached_string_st *self);
-size_t memcached_string_length(const memcached_string_st&);
-
-size_t memcached_string_size(const memcached_string_st *self);
-
-const char *memcached_string_value(const memcached_string_st *self);
-const char *memcached_string_value(const memcached_string_st&);
-
-char *memcached_string_take_value(memcached_string_st *self);
-
-char *memcached_string_value_mutable(const memcached_string_st *self);
-
-bool memcached_string_set(memcached_string_st&, const char*, size_t);
-
-void memcached_string_set_length(memcached_string_st *self, size_t length);
-void memcached_string_set_length(memcached_string_st&, const size_t length);
-
-bool memcached_string_resize(memcached_string_st&, const size_t);
-char *memcached_string_c_str(memcached_string_st&);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-static memcached_return_t ascii_touch(memcached_instance_st* instance,
- const char *key, size_t key_length,
- time_t expiration)
-{
- char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
- int expiration_buffer_length= snprintf(expiration_buffer, sizeof(expiration_buffer), " %llu", (unsigned long long)expiration);
- if (size_t(expiration_buffer_length) >= sizeof(expiration_buffer)+1 or expiration_buffer_length < 0)
- {
- return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
- }
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { memcached_literal_param("touch ") },
- { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
- { key, key_length },
- { expiration_buffer, size_t(expiration_buffer_length) },
- { memcached_literal_param("\r\n") }
- };
-
- memcached_return_t rc;
- if (memcached_failed(rc= memcached_vdo(instance, vector, 6, true)))
- {
- return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
- }
-
- return rc;
-}
-
-static memcached_return_t binary_touch(memcached_instance_st* instance,
- const char *key, size_t key_length,
- time_t expiration)
-{
- protocol_binary_request_touch request= {}; //{.bytes= {0}};
-
- initialize_binary_request(instance, request.message.header);
-
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_TOUCH;
- request.message.header.request.extlen= 4;
- request.message.header.request.keylen= htons((uint16_t)(key_length +memcached_array_size(instance->root->_namespace)));
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)(key_length +memcached_array_size(instance->root->_namespace) +request.message.header.request.extlen));
- request.message.body.expiration= htonl((uint32_t) expiration);
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { request.bytes, sizeof(request.bytes) },
- { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
- { key, key_length }
- };
-
- memcached_return_t rc;
- if (memcached_failed(rc= memcached_vdo(instance, vector, 4, true)))
- {
- return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
- }
-
- return rc;
-}
-
-memcached_return_t memcached_touch(memcached_st *ptr,
- const char *key, size_t key_length,
- time_t expiration)
-{
- return memcached_touch_by_key(ptr, key, key_length, key, key_length, expiration);
-}
-
-memcached_return_t memcached_touch_by_key(memcached_st *shell,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- time_t expiration)
-{
- Memcached* ptr= memcached2Memcached(shell);
- LIBMEMCACHED_MEMCACHED_TOUCH_START();
-
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(ptr, true)))
- {
- return rc;
- }
-
- if (memcached_failed(rc= memcached_key_test(*ptr, (const char **)&key, &key_length, 1)))
- {
- return memcached_set_error(*ptr, rc, MEMCACHED_AT);
- }
-
- uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
- memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
-
- if (ptr->flags.binary_protocol)
- {
- rc= binary_touch(instance, key, key_length, expiration);
- }
- else
- {
- rc= ascii_touch(instance, key, key_length, expiration);
- }
-
- if (memcached_failed(rc))
- {
- return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while writing touch command to server"));
- }
-
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
-
- if (rc == MEMCACHED_SUCCESS or rc == MEMCACHED_NOTFOUND)
- {
- return rc;
- }
-
- return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while reading response"));
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-/*
- * 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
- */
-void increment_udp_message_id(memcached_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));
-}
-
-bool memcached_io_init_udp_header(memcached_instance_st* ptr, const 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;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#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;
-};
-
-bool memcached_io_init_udp_header(memcached_instance_st*, const uint16_t thread_id);
-void increment_udp_message_id(memcached_instance_st*);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libmemcachedutil-1.0/util.h>
-
+++ /dev/null
-EXTRA_DIST= libmemcachedutil.ver
-
-lib_LTLIBRARIES=
-
-if BUILD_LIBMEMCACHEDUTIL
-lib_LTLIBRARIES+= libmemcachedutil.la
-endif
-
-libmemcachedutil_la_SOURCES= memcached_pool.c
-libmemcachedutil_la_LDFLAGS= -version-info $(MEMCACHEDUTIL_LIBRARY_VERSION) $(LD_UTIL_VERSION_SCRIPT)
-libmemcachedutil_la_LIBADD= ${top_builddir}/libmemcached/libmemcached.la
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-struct context_st
-{
- size_t length;
- const char *buffer;
-};
-
-static memcached_return_t _set_verbosity(const Memcached *,
- const memcached_instance_st * server,
- void *context)
-{
- libmemcached_io_vector_st *vector= (libmemcached_io_vector_st *)context;
-
- Memcached local_memc;
- Memcached *memc_ptr= memcached_create(&local_memc);
-
- memcached_return_t rc= memcached_server_add(memc_ptr, memcached_server_name(server), memcached_server_port(server));
-
- if (rc == MEMCACHED_SUCCESS)
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc_ptr, 0);
-
- rc= memcached_vdo(instance, vector, 2, true);
-
- if (rc == MEMCACHED_SUCCESS)
- {
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
- }
- }
-
- memcached_free(memc_ptr);
-
- return rc;
-}
-
-memcached_return_t memcached_verbosity(memcached_st *shell, uint32_t verbosity)
-{
- Memcached* ptr= memcached2Memcached(shell);
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(ptr, false)))
- {
- return rc;
- }
-
- memcached_server_fn callbacks[1];
-
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
- int send_length= snprintf(buffer, sizeof(buffer), "verbosity %u\r\n", verbosity);
- if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE or send_length < 0)
- {
- return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
- memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
- }
-
- libmemcached_io_vector_st vector[]=
- {
- { NULL, 0 },
- { buffer, size_t(send_length) },
- };
-
- callbacks[0]= _set_verbosity;
-
- return memcached_server_cursor(ptr, callbacks, vector, 1);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-#include <libmemcached/common.h>
-
-const char * memcached_lib_version(void)
-{
- return LIBMEMCACHED_VERSION_STRING;
-}
-
-static inline memcached_return_t memcached_version_textual(Memcached *memc)
-{
- libmemcached_io_vector_st vector[]=
- {
- { memcached_literal_param("version\r\n") },
- };
-
- uint32_t success= 0;
- bool errors_happened= false;
- for (uint32_t x= 0; x < memcached_server_count(memc); x++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc, x);
-
- // Optimization, we only fetch version once.
- if (instance->major_version != UINT8_MAX)
- {
- continue;
- }
-
- memcached_return_t rrc;
- if (memcached_failed(rrc= memcached_vdo(instance, vector, 1, true)))
- {
- errors_happened= true;
- (void)memcached_set_error(*instance, rrc, MEMCACHED_AT);
- continue;
- }
- success++;
- }
-
- if (success)
- {
- // Collect the returned items
- memcached_instance_st* instance;
- memcached_return_t readable_error;
- while ((instance= memcached_io_get_readable_server(memc, readable_error)))
- {
- memcached_return_t rrc= memcached_response(instance, NULL);
- if (memcached_failed(rrc))
- {
- errors_happened= true;
- }
- }
- }
-
- return errors_happened ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
-}
-
-static inline memcached_return_t memcached_version_binary(Memcached *memc)
-{
- protocol_binary_request_version request= {};
-
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
- libmemcached_io_vector_st vector[]=
- {
- { request.bytes, sizeof(request.bytes) }
- };
-
- uint32_t success= 0;
- bool errors_happened= false;
- for (uint32_t x= 0; x < memcached_server_count(memc); x++)
- {
- memcached_instance_st* instance= memcached_instance_fetch(memc, x);
-
- initialize_binary_request(instance, request.message.header);
-
- if (instance->major_version != UINT8_MAX)
- {
- continue;
- }
-
- memcached_return_t rrc= memcached_vdo(instance, vector, 1, true);
- if (memcached_failed(rrc))
- {
- errors_happened= true;
- continue;
- }
-
- success++;
- }
-
- if (success)
- {
- // Collect the returned items
- memcached_instance_st* instance;
- memcached_return_t readable_error;
- while ((instance= memcached_io_get_readable_server(memc, readable_error)))
- {
- char buffer[32];
- memcached_return_t rrc= memcached_response(instance, buffer, sizeof(buffer), NULL);
- if (memcached_failed(rrc))
- {
- errors_happened= true;
- }
- }
- }
-
- return errors_happened ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
-}
-
-static inline void version_ascii_instance(memcached_instance_st* instance)
-{
- if (instance->major_version != UINT8_MAX)
- {
- libmemcached_io_vector_st vector[]=
- {
- { memcached_literal_param("version\r\n") },
- };
-
- (void)memcached_vdo(instance, vector, 1, false);
- }
-}
-
-static inline void version_binary_instance(memcached_instance_st* instance)
-{
- if (instance->major_version != UINT8_MAX)
- {
- protocol_binary_request_version request= {};
-
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
- libmemcached_io_vector_st vector[]=
- {
- { request.bytes, sizeof(request.bytes) }
- };
-
- initialize_binary_request(instance, request.message.header);
-
- (void)memcached_vdo(instance, vector, 1, false);
- }
-}
-
-void memcached_version_instance(memcached_instance_st* instance)
-{
- if (instance)
- {
- if (memcached_has_root(instance))
- {
- if (memcached_is_fetching_version(instance->root))
- {
- if (memcached_is_udp(instance->root) == false)
- {
-
- if (memcached_is_binary(instance->root))
- {
- version_binary_instance(instance);
- return;
- }
-
- version_ascii_instance(instance);
- }
- }
- }
- }
-}
-
-int8_t memcached_version_instance_cmp(memcached_instance_st *instance,
- uint8_t maj, uint8_t min, uint8_t mic)
-{
- if (!instance || memcached_server_major_version(instance) == UINT8_MAX) {
- return INT8_MIN;
- } else {
- uint32_t sv, cv;
-
- sv = memcached_server_micro_version(instance)
- |memcached_server_minor_version(instance) << 8
- |memcached_server_major_version(instance) << 16
- ;
- cv = mic
- |min << 8
- |maj << 16
- ;
- if (sv < cv) {
- return -1;
- }
- return sv != cv;
- }
-}
-
-memcached_return_t memcached_version(memcached_st *shell)
-{
- Memcached* memc= memcached2Memcached(shell);
- if (memc)
- {
- memcached_return_t rc;
- if (memcached_failed(rc= initialize_query(memc, true)))
- {
- return rc;
- }
-
- if (memcached_is_udp(memc))
- {
- return MEMCACHED_NOT_SUPPORTED;
- }
-
- if (memcached_is_binary(memc))
- {
- return memcached_version_binary(memc);
- }
-
- return memcached_version_textual(memc);
- }
-
- return MEMCACHED_INVALID_ARGUMENTS;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/ All
- * rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- Common include file for libmemached
-*/
-
-#pragma once
-
-void memcached_version_instance(memcached_instance_st*);
-int8_t memcached_version_instance_cmp(memcached_instance_st*,
- uint8_t maj, uint8_t min, uint8_t mic);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-
-struct bucket_t {
- uint32_t master;
- uint32_t forward;
-};
-
-struct memcached_virtual_bucket_t {
- bool has_forward;
- uint32_t size;
- uint32_t replicas;
- struct bucket_t buckets[];
-};
-
-memcached_return_t memcached_virtual_bucket_create(memcached_st *self,
- const uint32_t *host_map,
- const uint32_t *forward_map,
- const uint32_t buckets,
- const uint32_t replicas)
-{
- if (self == NULL || host_map == NULL || buckets == 0U)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- memcached_virtual_bucket_free(self);
-
- struct memcached_virtual_bucket_t *virtual_bucket= (struct memcached_virtual_bucket_t *)malloc(sizeof(struct memcached_virtual_bucket_t) + sizeof(struct bucket_t) *buckets);
-
- if (virtual_bucket == NULL)
- {
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
-
- virtual_bucket->size= buckets;
- virtual_bucket->replicas= replicas;
- self->virtual_bucket= virtual_bucket;
-
- uint32_t x= 0;
- for (; x < buckets; x++)
- {
- virtual_bucket->buckets[x].master= host_map[x];
- if (forward_map)
- {
- virtual_bucket->buckets[x].forward= forward_map[x];
- }
- else
- {
- virtual_bucket->buckets[x].forward= 0;
- }
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-void memcached_virtual_bucket_free(memcached_st *self)
-{
- if (self)
- {
- if (self->virtual_bucket)
- {
- free(self->virtual_bucket);
- self->virtual_bucket= NULL;
- }
- }
-}
-
-uint32_t memcached_virtual_bucket_get(const memcached_st *self, uint32_t digest)
-{
- if (self)
- {
- if (self->virtual_bucket)
- {
- uint32_t result= (uint32_t) (digest & (self->virtual_bucket->size -1));
- return self->virtual_bucket->buckets[result].master;
- }
-
- return (uint32_t) (digest & (self->number_of_hosts -1));
- }
-
- return 0;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-memcached_return_t memcached_virtual_bucket_create(memcached_st *self,
- const uint32_t *host_map,
- const uint32_t *forward_map,
- const uint32_t buckets,
- const uint32_t replicas);
-
-uint32_t memcached_virtual_bucket_get(const memcached_st *self, uint32_t digest);
-
-void memcached_virtual_bucket_free(memcached_st *self);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#define WATCHPOINT
-#define WATCHPOINT_ERROR(A)
-#define WATCHPOINT_IFERROR(__memcached_return_t) (void)(__memcached_return_t)
-#define WATCHPOINT_STRING(A)
-#define WATCHPOINT_NUMBER(A)
-#define WATCHPOINT_LABELED_NUMBER(A,B)
-#define WATCHPOINT_IF_LABELED_NUMBER(A,B,C)
-#define WATCHPOINT_ERRNO(A)
-#define WATCHPOINT_ASSERT_PRINT(A,B,C)
-#define WATCHPOINT_ASSERT(A) (void)(A)
-#define WATCHPOINT_ASSERT_INITIALIZED(A)
-#define WATCHPOINT_SET(A)
+++ /dev/null
-/*
- * Libmemcached library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-# include <cerrno>
-#else
-# include <errno.h>
-#endif
-
-#ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-#endif
-
-#ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0501
-#endif
-
-#ifdef __MINGW32__
-# if(_WIN32_WINNT >= 0x0501)
-# else
-# undef _WIN32_WINNT
-# define _WIN32_WINNT 0x0501
-# endif /* _WIN32_WINNT >= 0x0501 */
-#endif /* __MINGW32__ */
-
-#if defined(HAVE_WINSOCK2_H) && HAVE_WINSOCK2_H
-# include <winsock2.h>
-#endif
-
-#if defined(HAVE_WS2TCPIP_H) && HAVE_WS2TCPIP_H
-# include <ws2tcpip.h>
-#endif
-
-#if defined(HAVE_IO_H) && HAVE_IO_H
-# include <io.h>
-#endif
-
-struct sockaddr_un
-{
- short int sun_family;
- char sun_path[108];
-};
-
-static inline int translate_windows_error()
-{
- int local_errno= WSAGetLastError();
-
- switch(local_errno) {
- case WSAEINVAL:
- local_errno= EINPROGRESS;
- break;
- case WSAEALREADY:
- case WSAEWOULDBLOCK:
- local_errno= EAGAIN;
- break;
-
- case WSAECONNREFUSED:
- local_errno= ECONNREFUSED;
- break;
-
- case WSAENETUNREACH:
- local_errno= ENETUNREACH;
- break;
-
- case WSAETIMEDOUT:
- local_errno= ETIMEDOUT;
- break;
-
- case WSAECONNRESET:
- local_errno= ECONNRESET;
- break;
-
- case WSAEADDRINUSE:
- local_errno= EADDRINUSE;
- break;
-
- case WSAEOPNOTSUPP:
- local_errno= EOPNOTSUPP;
- break;
-
- case WSAENOPROTOOPT:
- local_errno= ENOPROTOOPT;
- break;
-
- default:
- break;
- }
-
- return local_errno;
-}
+++ /dev/null
-/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) <2008>, Sun Microsystems, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*
- * Summary: Constants used by to implement the binary protocol.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Trond Norbye <trond.norbye@sun.com>
- */
-
-#ifndef PROTOCOL_BINARY_H
-#define PROTOCOL_BINARY_H
-
-#include <libmemcachedprotocol-0.0/vbucket.h>
-
-/**
- * \addtogroup Protocol
- * @{
- */
-
-/**
- * This file contains definitions of the constants and packet formats
- * defined in the binary specification. Please note that you _MUST_ remember
- * to convert each multibyte field to / from network byte order to / from
- * host order.
- */
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
- /**
- * Definition of the legal "magic" values used in a packet.
- * See section 3.1 Magic byte
- */
- typedef enum {
- PROTOCOL_BINARY_REQ = 0x80,
- PROTOCOL_BINARY_RES = 0x81
- } protocol_binary_magic;
-
- /**
- * Definition of the valid response status numbers.
- * See section 3.2 Response Status
- */
- typedef enum {
- PROTOCOL_BINARY_RESPONSE_SUCCESS = 0x00,
- PROTOCOL_BINARY_RESPONSE_KEY_ENOENT = 0x01,
- PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS = 0x02,
- PROTOCOL_BINARY_RESPONSE_E2BIG = 0x03,
- PROTOCOL_BINARY_RESPONSE_EINVAL = 0x04,
- PROTOCOL_BINARY_RESPONSE_NOT_STORED = 0x05,
- PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL = 0x06,
- PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET = 0x07,
- PROTOCOL_BINARY_RESPONSE_AUTH_ERROR = 0x20,
- PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE = 0x21,
- PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND = 0x81,
- PROTOCOL_BINARY_RESPONSE_ENOMEM = 0x82,
- PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED = 0x83,
- PROTOCOL_BINARY_RESPONSE_EINTERNAL = 0x84,
- PROTOCOL_BINARY_RESPONSE_EBUSY = 0x85,
- PROTOCOL_BINARY_RESPONSE_ETMPFAIL = 0x86
- } protocol_binary_response_status;
-
- /**
- * Defintion of the different command opcodes.
- * See section 3.3 Command Opcodes
- */
- typedef enum {
- PROTOCOL_BINARY_CMD_GET = 0x00,
- PROTOCOL_BINARY_CMD_SET = 0x01,
- PROTOCOL_BINARY_CMD_ADD = 0x02,
- PROTOCOL_BINARY_CMD_REPLACE = 0x03,
- PROTOCOL_BINARY_CMD_DELETE = 0x04,
- PROTOCOL_BINARY_CMD_INCREMENT = 0x05,
- PROTOCOL_BINARY_CMD_DECREMENT = 0x06,
- PROTOCOL_BINARY_CMD_QUIT = 0x07,
- PROTOCOL_BINARY_CMD_FLUSH = 0x08,
- PROTOCOL_BINARY_CMD_GETQ = 0x09,
- PROTOCOL_BINARY_CMD_NOOP = 0x0a,
- PROTOCOL_BINARY_CMD_VERSION = 0x0b,
- PROTOCOL_BINARY_CMD_GETK = 0x0c,
- PROTOCOL_BINARY_CMD_GETKQ = 0x0d,
- PROTOCOL_BINARY_CMD_APPEND = 0x0e,
- PROTOCOL_BINARY_CMD_PREPEND = 0x0f,
- PROTOCOL_BINARY_CMD_STAT = 0x10,
- PROTOCOL_BINARY_CMD_SETQ = 0x11,
- PROTOCOL_BINARY_CMD_ADDQ = 0x12,
- PROTOCOL_BINARY_CMD_REPLACEQ = 0x13,
- PROTOCOL_BINARY_CMD_DELETEQ = 0x14,
- PROTOCOL_BINARY_CMD_INCREMENTQ = 0x15,
- PROTOCOL_BINARY_CMD_DECREMENTQ = 0x16,
- PROTOCOL_BINARY_CMD_QUITQ = 0x17,
- PROTOCOL_BINARY_CMD_FLUSHQ = 0x18,
- PROTOCOL_BINARY_CMD_APPENDQ = 0x19,
- PROTOCOL_BINARY_CMD_PREPENDQ = 0x1a,
- PROTOCOL_BINARY_CMD_VERBOSITY = 0x1b,
- PROTOCOL_BINARY_CMD_TOUCH = 0x1c,
- PROTOCOL_BINARY_CMD_GAT = 0x1d,
- PROTOCOL_BINARY_CMD_GATQ = 0x1e,
- PROTOCOL_BINARY_CMD_GATK = 0x23,
- PROTOCOL_BINARY_CMD_GATKQ = 0x24,
-
- PROTOCOL_BINARY_CMD_SASL_LIST_MECHS = 0x20,
- PROTOCOL_BINARY_CMD_SASL_AUTH = 0x21,
- PROTOCOL_BINARY_CMD_SASL_STEP = 0x22,
-
- /* These commands are used for range operations and exist within
- * this header for use in other projects. Range operations are
- * not expected to be implemented in the memcached server itself.
- */
- PROTOCOL_BINARY_CMD_RGET = 0x30,
- PROTOCOL_BINARY_CMD_RSET = 0x31,
- PROTOCOL_BINARY_CMD_RSETQ = 0x32,
- PROTOCOL_BINARY_CMD_RAPPEND = 0x33,
- PROTOCOL_BINARY_CMD_RAPPENDQ = 0x34,
- PROTOCOL_BINARY_CMD_RPREPEND = 0x35,
- PROTOCOL_BINARY_CMD_RPREPENDQ = 0x36,
- PROTOCOL_BINARY_CMD_RDELETE = 0x37,
- PROTOCOL_BINARY_CMD_RDELETEQ = 0x38,
- PROTOCOL_BINARY_CMD_RINCR = 0x39,
- PROTOCOL_BINARY_CMD_RINCRQ = 0x3a,
- PROTOCOL_BINARY_CMD_RDECR = 0x3b,
- PROTOCOL_BINARY_CMD_RDECRQ = 0x3c,
- /* End Range operations */
-
- /* VBucket commands */
- PROTOCOL_BINARY_CMD_SET_VBUCKET = 0x3d,
- PROTOCOL_BINARY_CMD_GET_VBUCKET = 0x3e,
- PROTOCOL_BINARY_CMD_DEL_VBUCKET = 0x3f,
- /* End VBucket commands */
-
- /* TAP commands */
- PROTOCOL_BINARY_CMD_TAP_CONNECT = 0x40,
- PROTOCOL_BINARY_CMD_TAP_MUTATION = 0x41,
- PROTOCOL_BINARY_CMD_TAP_DELETE = 0x42,
- PROTOCOL_BINARY_CMD_TAP_FLUSH = 0x43,
- PROTOCOL_BINARY_CMD_TAP_OPAQUE = 0x44,
- PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET = 0x45,
- PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START = 0x46,
- PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END = 0x47,
- /* End TAP */
-
- PROTOCOL_BINARY_CMD_LAST_RESERVED = 0xef,
-
- /* Scrub the data */
- PROTOCOL_BINARY_CMD_SCRUB = 0xf0
- } protocol_binary_command;
-
- /**
- * Definition of the data types in the packet
- * See section 3.4 Data Types
- */
- typedef enum {
- PROTOCOL_BINARY_RAW_BYTES = 0x00
- } protocol_binary_datatypes;
-
- /**
- * Definition of the header structure for a request packet.
- * See section 2
- */
- typedef union {
- struct {
- uint8_t magic;
- uint8_t opcode;
- uint16_t keylen;
- uint8_t extlen;
- uint8_t datatype;
- uint16_t vbucket;
- uint32_t bodylen;
- uint32_t opaque;
- uint64_t cas;
- } request;
- uint8_t bytes[24];
- } protocol_binary_request_header;
-
- /**
- * Definition of the header structure for a response packet.
- * See section 2
- */
- typedef union {
- struct {
- uint8_t magic;
- uint8_t opcode;
- uint16_t keylen;
- uint8_t extlen;
- uint8_t datatype;
- uint16_t status;
- uint32_t bodylen;
- uint32_t opaque;
- uint64_t cas;
- } response;
- uint8_t bytes[24];
- } protocol_binary_response_header;
-
- /**
- * Definition of a request-packet containing no extras
- */
- union protocol_binary_request_no_extras {
- struct {
- protocol_binary_request_header header;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header)];
- };
- typedef union protocol_binary_request_no_extras protocol_binary_request_no_extras;
-
- /**
- * Definition of a response-packet containing no extras
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- } message;
- uint8_t bytes[sizeof(protocol_binary_response_header)];
- } protocol_binary_response_no_extras;
-
- /**
- * Definition of the packet used by the get, getq, getk and getkq command.
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_get;
- typedef protocol_binary_request_no_extras protocol_binary_request_getq;
- typedef protocol_binary_request_no_extras protocol_binary_request_getk;
- typedef protocol_binary_request_no_extras protocol_binary_request_getkq;
-
- /**
- * Definition of the packet returned from a successful get, getq, getk and
- * getkq.
- * See section 4
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- struct {
- uint32_t flags;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_response_header) + 4];
- } protocol_binary_response_get;
-
- typedef protocol_binary_response_get protocol_binary_response_getq;
- typedef protocol_binary_response_get protocol_binary_response_getk;
- typedef protocol_binary_response_get protocol_binary_response_getkq;
-
- /**
- * Definition of the packet used by the delete command
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_delete;
-
- /**
- * Definition of the packet returned by the delete command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_delete;
-
- /**
- * Definition of the packet used by the flush command
- * See section 4
- * Please note that the expiration field is optional, so remember to see
- * check the header.bodysize to see if it is present.
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_flush;
-
- /**
- * Definition of the packet returned by the flush command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_flush;
-
- /**
- * Definition of the packet used by set, add and replace
- * See section 4
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t flags;
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 8];
- } protocol_binary_request_set;
- typedef protocol_binary_request_set protocol_binary_request_add;
- typedef protocol_binary_request_set protocol_binary_request_replace;
-
- /**
- * Definition of the packet returned by set, add and replace
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_set;
- typedef protocol_binary_response_no_extras protocol_binary_response_add;
- typedef protocol_binary_response_no_extras protocol_binary_response_replace;
-
- /**
- * Definition of the noop packet
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_noop;
-
- /**
- * Definition of the packet returned by the noop command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_noop;
-
- /**
- * Definition of the structure used by the increment and decrement
- * command.
- * See section 4
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint64_t delta;
- uint64_t initial;
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 20];
- } protocol_binary_request_incr;
- typedef protocol_binary_request_incr protocol_binary_request_decr;
-
- /**
- * Definition of the response from an incr or decr command
- * command.
- * See section 4
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- struct {
- uint64_t value;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_response_header) + 8];
- } protocol_binary_response_incr;
- typedef protocol_binary_response_incr protocol_binary_response_decr;
-
- /**
- * Definition of the quit
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_quit;
-
- /**
- * Definition of the packet returned by the quit command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_quit;
-
- /**
- * Definition of the packet used by append and prepend command
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_append;
- typedef protocol_binary_request_no_extras protocol_binary_request_prepend;
-
- /**
- * Definition of the packet returned from a successful append or prepend
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_append;
- typedef protocol_binary_response_no_extras protocol_binary_response_prepend;
-
- /**
- * Definition of the packet used by the version command
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_version;
-
- /**
- * Definition of the packet returned from a successful version command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_version;
-
-
- /**
- * Definition of the packet used by the stats command.
- * See section 4
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_stats;
-
- /**
- * Definition of the packet returned from a successful stats command
- * See section 4
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_stats;
-
- /**
- * Definition of the packet used by the verbosity command
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t level;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_verbosity;
-
- /**
- * Definition of the packet returned from the verbosity command
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_verbosity;
-
- /**
- * Definition of the packet used by the touch command.
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_touch;
-
- /**
- * Definition of the packet returned from the touch command
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_touch;
-
- /**
- * Definition of the packet used by the GAT(Q) command.
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- uint32_t expiration;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_gat;
-
- typedef protocol_binary_request_gat protocol_binary_request_gatq;
-
- /**
- * Definition of the packet returned from the GAT(Q)
- */
- typedef protocol_binary_response_get protocol_binary_response_gat;
- typedef protocol_binary_response_get protocol_binary_response_gatq;
-
-
- /**
- * Definition of a request for a range operation.
- * See http://code.google.com/p/memcached/wiki/RangeOps
- *
- * These types are used for range operations and exist within
- * this header for use in other projects. Range operations are
- * not expected to be implemented in the memcached server itself.
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- struct {
- uint16_t size;
- uint8_t reserved;
- uint8_t flags;
- uint32_t max_results;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_rangeop;
-
- typedef protocol_binary_request_rangeop protocol_binary_request_rget;
- typedef protocol_binary_request_rangeop protocol_binary_request_rset;
- typedef protocol_binary_request_rangeop protocol_binary_request_rsetq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rappend;
- typedef protocol_binary_request_rangeop protocol_binary_request_rappendq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rprepend;
- typedef protocol_binary_request_rangeop protocol_binary_request_rprependq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rdelete;
- typedef protocol_binary_request_rangeop protocol_binary_request_rdeleteq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rincr;
- typedef protocol_binary_request_rangeop protocol_binary_request_rincrq;
- typedef protocol_binary_request_rangeop protocol_binary_request_rdecr;
- typedef protocol_binary_request_rangeop protocol_binary_request_rdecrq;
-
-
- /**
- * Definition of tap commands
- * See To be written
- *
- */
-
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- /**
- * flags is a bitmask used to set properties for the
- * the connection. Please In order to be forward compatible
- * you should set all undefined bits to 0.
- *
- * If the bit require extra userdata, it will be stored
- * in the user-data field of the body (passed to the engine
- * as enginespeciffic). That means that when you parse the
- * flags and the engine-specific data, you have to work your
- * way from bit 0 and upwards to find the correct offset for
- * the data.
- *
- */
- uint32_t flags;
-
- /**
- * Backfill age
- *
- * By using this flag you can limit the amount of data being
- * transmitted. If you don't specify a backfill age, the
- * server will transmit everything it contains.
- *
- * The first 8 bytes in the engine specific data contains
- * the oldest entry (from epoc) you're interested in.
- * Specifying a time in the future (for the server you are
- * connecting to), will cause it to start streaming current
- * changes.
- */
-#define TAP_CONNECT_FLAG_BACKFILL 0x01
- /**
- * Dump will cause the server to send the data stored on the
- * server, but disconnect when the keys stored in the server
- * are transmitted.
- */
-#define TAP_CONNECT_FLAG_DUMP 0x02
- /**
- * The body contains a list of 16 bits words in network byte
- * order specifying the vbucket ids to monitor. The first 16
- * bit word contains the number of buckets. The number of 0
- * means "all buckets"
- */
-#define TAP_CONNECT_FLAG_LIST_VBUCKETS 0x04
- /**
- * The responsibility of the vbuckets is to be transferred
- * over to the caller when all items are transferred.
- */
-#define TAP_CONNECT_FLAG_TAKEOVER_VBUCKETS 0x08
- /**
- * The tap consumer supports ack'ing of tap messages
- */
-#define TAP_CONNECT_SUPPORT_ACK 0x10
- /**
- * The tap consumer would prefer to just get the keys
- * back. If the engine supports this it will set
- * the TAP_FLAG_NO_VALUE flag in each of the
- * tap packets returned.
- */
-#define TAP_CONNECT_REQUEST_KEYS_ONLY 0x20
- /**
- * The body contains a list of (vbucket_id, last_checkpoint_id)
- * pairs. This provides the checkpoint support in TAP streams.
- * The last checkpoint id represents the last checkpoint that
- * was successfully persisted.
- */
-#define TAP_CONNECT_CHECKPOINT 0x40
- /**
- * The tap consumer is a registered tap client, which means that
- * the tap server will maintain its checkpoint cursor permanently.
- */
-#define TAP_CONNECT_REGISTERED_CLIENT 0x80
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
- } protocol_binary_request_tap_connect;
-
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- struct {
- uint16_t enginespecific_length;
- /*
- * The flag section support the following flags
- */
- /**
- * Request that the consumer send a response packet
- * for this packet. The opaque field must be preserved
- * in the response.
- */
-#define TAP_FLAG_ACK 0x01
- /**
- * The value for the key is not included in the packet
- */
-#define TAP_FLAG_NO_VALUE 0x02
- uint16_t flags;
- uint8_t ttl;
- uint8_t res1;
- uint8_t res2;
- uint8_t res3;
- } tap;
- struct {
- uint32_t flags;
- uint32_t expiration;
- } item;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 16];
- } protocol_binary_request_tap_mutation;
-
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- struct {
- uint16_t enginespecific_length;
- /**
- * See the definition of the flags for
- * protocol_binary_request_tap_mutation for a description
- * of the available flags.
- */
- uint16_t flags;
- uint8_t ttl;
- uint8_t res1;
- uint8_t res2;
- uint8_t res3;
- } tap;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + 8];
- } protocol_binary_request_tap_no_extras;
-
- typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_delete;
- typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_flush;
- typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_opaque;
- typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_vbucket_set;
-
-
- /**
- * Definition of the packet used by the scrub.
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_scrub;
-
- /**
- * Definition of the packet returned from scrub.
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_scrub;
-
-
- /**
- * Definition of the packet used by set vbucket
- */
- typedef union {
- struct {
- protocol_binary_request_header header;
- struct {
- vbucket_state_t state;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_request_header) + sizeof(vbucket_state_t)];
- } protocol_binary_request_set_vbucket;
- /**
- * Definition of the packet returned from set vbucket
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_set_vbucket;
- /**
- * Definition of the packet used by del vbucket
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_del_vbucket;
- /**
- * Definition of the packet returned from del vbucket
- */
- typedef protocol_binary_response_no_extras protocol_binary_response_del_vbucket;
-
- /**
- * Definition of the packet used by get vbucket
- */
- typedef protocol_binary_request_no_extras protocol_binary_request_get_vbucket;
-
- /**
- * Definition of the packet returned from get vbucket
- */
- typedef union {
- struct {
- protocol_binary_response_header header;
- struct {
- vbucket_state_t state;
- } body;
- } message;
- uint8_t bytes[sizeof(protocol_binary_response_header) + sizeof(vbucket_state_t)];
- } protocol_binary_response_get_vbucket;
-
-
- /**
- * @}
- */
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* PROTOCOL_BINARY_H */
+++ /dev/null
-/*
- * Summary: Definition of the callback interface
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Trond Norbye
- */
-
-#pragma once
-
-/**
- * Callback to send data back from a successful GET/GETQ/GETK/GETKQ command
- *
- * @param cookie Just pass along the cookie supplied in the callback
- * @param key What to insert as key in the reply
- * @param keylen The length of the key
- * @param body What to store in the body of the package
- * @param bodylen The number of bytes of the body
- * @param flags The flags stored with the item
- * @param cas The CAS value to insert into the response (should be 0
- * if you don't care)
- */
-typedef protocol_binary_response_status
-(*memcached_binary_protocol_get_response_handler)(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void *body,
- uint32_t bodylen,
- uint32_t flags,
- uint64_t cas);
-/**
- * Callback to send data back from a STAT command
- *
- * @param cookie Just pass along the cookie supplied in the callback
- * @param key What to insert as key in the reply
- * @param keylen The length of the key
- * @param body What to store in the body of the package
- * @param bodylen The number of bytes of the body
- */
-typedef protocol_binary_response_status
-(*memcached_binary_protocol_stat_response_handler)(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void *body,
- uint32_t bodylen);
-/**
- * Callback to send data back from a VERSION command
- *
- * @param cookie Just pass along the cookie supplied in the callback
- * @param text The version string
- * @param length The number of bytes in the version string
- */
-typedef protocol_binary_response_status
-(*memcached_binary_protocol_version_response_handler)(const void *cookie,
- const void *text,
- uint32_t length);
-
-
-/**
- * In the low level interface you need to format the response
- * packet yourself (giving you complete freedom :-)
- *
- * @param cookie Just pass along the cookie supplied in the callback
- * @param request Pointer to the request packet you are sending a reply to
- * @param response Pointer to the response packet to send
- *
- */
-typedef protocol_binary_response_status (*memcached_binary_protocol_raw_response_handler)(const void *cookie,
- protocol_binary_request_header *request,
- protocol_binary_response_header *response);
-
-/**
- * In the low lever interface you have to do most of the work by
- * yourself, but it also gives you a lot of freedom :-)
- * @param cookie identification for this connection, just pass it along to
- * the response handler
- * @param header the command received over the wire. Never try to access
- * <u>anything</u> outside the command.
- * @param resonse_handler call this function to send data back to the client
- */
-typedef protocol_binary_response_status (*memcached_binary_protocol_command_handler)(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler);
-
-/**
- * The raw interface to the packets is implemented in version 0. It contains
- * just an array with command handlers. The inxed in the array is the
- * com code.
- */
-typedef struct {
- memcached_binary_protocol_command_handler comcode[256];
-} memcached_binary_protocol_callback_v0_st;
-
-
-/**
- * The first version of the callback struct containing all of the
- * documented commands in the initial release of the binary protocol
- * (aka. memcached 1.4.0).
- *
- * You might miss the Q commands (addq etc) but the response function
- * knows how to deal with them so you don't need to worry about that :-)
- */
-typedef struct {
- /**
- * Add an item to the cache
- * @param cookie id of the client receiving the command
- * @param key the key to add
- * @param len the length of the key
- * @param val the value to store for the key (may be NIL)
- * @param vallen the length of the data
- * @param flags the flags to store with the key
- * @param exptime the expiry time for the key-value pair
- * @param cas the resulting cas for the add operation (if success)
- */
- protocol_binary_response_status (*add)(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint32_t flags,
- uint32_t exptime,
- uint64_t *cas);
-
- /**
- * Append data to an <b>existing</b> key-value pair.
- *
- * @param cookie id of the client receiving the command
- * @param key the key to add data to
- * @param len the length of the key
- * @param val the value to append to the value
- * @param vallen the length of the data
- * @param cas the CAS in the request
- * @param result_cas the resulting cas for the append operation
- *
- */
- protocol_binary_response_status (*append)(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint64_t cas,
- uint64_t *result_cas);
-
- /**
- * Decrement the value for a key
- *
- * @param cookie id of the client receiving the command
- * @param key the key to decrement the value for
- * @param len the length of the key
- * @param delta the amount to decrement
- * @param initial initial value to store (if the key doesn't exist)
- * @param expiration expiration time for the object (if the key doesn't exist)
- * @param cas the CAS in the request
- * @param result the result from the decrement
- * @param result_cas the cas of the item
- *
- */
- protocol_binary_response_status (*decrement)(const void *cookie,
- const void *key,
- uint16_t keylen,
- uint64_t delta,
- uint64_t initial,
- uint32_t expiration,
- uint64_t *result,
- uint64_t *result_cas);
-
- /**
- * Delete an existing key
- *
- * @param cookie id of the client receiving the command
- * @param key the key to delete_object
- * @param len the length of the key
- * @param cas the CAS in the request
- */
- protocol_binary_response_status (*delete_object)(const void *cookie,
- const void *key,
- uint16_t keylen,
- uint64_t cas);
-
-
- /**
- * Flush the cache
- *
- * @param cookie id of the client receiving the command
- * @param when when the cache should be flushed (0 == immediately)
- */
- protocol_binary_response_status (*flush_object)(const void *cookie,
- uint32_t when);
-
-
-
- /**
- * Get a key-value pair
- *
- * @param cookie id of the client receiving the command
- * @param key the key to get
- * @param len the length of the key
- * @param response_handler to send the result back to the client
- */
- protocol_binary_response_status (*get)(const void *cookie,
- const void *key,
- uint16_t keylen,
- memcached_binary_protocol_get_response_handler response_handler);
-
- /**
- * Increment the value for a key
- *
- * @param cookie id of the client receiving the command
- * @param key the key to increment the value on
- * @param len the length of the key
- * @param delta the amount to increment
- * @param initial initial value to store (if the key doesn't exist)
- * @param expiration expiration time for the object (if the key doesn't exist)
- * @param cas the CAS in the request
- * @param result the result from the decrement
- * @param result_cas the cas of the item
- *
- */
- protocol_binary_response_status (*increment)(const void *cookie,
- const void *key,
- uint16_t keylen,
- uint64_t delta,
- uint64_t initial,
- uint32_t expiration,
- uint64_t *result,
- uint64_t *result_cas);
-
- /**
- * The noop command was received. This is just a notification callback (the
- * response is automatically created).
- *
- * @param cookie id of the client receiving the command
- */
- protocol_binary_response_status (*noop)(const void *cookie);
-
- /**
- * Prepend data to an <b>existing</b> key-value pair.
- *
- * @param cookie id of the client receiving the command
- * @param key the key to prepend data to
- * @param len the length of the key
- * @param val the value to prepend to the value
- * @param vallen the length of the data
- * @param cas the CAS in the request
- * @param result-cas the cas id of the item
- *
- */
- protocol_binary_response_status (*prepend)(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint64_t cas,
- uint64_t *result_cas);
-
- /**
- * The quit command was received. This is just a notification callback (the
- * response is automatically created).
- *
- * @param cookie id of the client receiving the command
- */
- protocol_binary_response_status (*quit)(const void *cookie);
-
-
- /**
- * Replace an <b>existing</b> item to the cache
- *
- * @param cookie id of the client receiving the command
- * @param key the key to replace the content for
- * @param len the length of the key
- * @param val the value to store for the key (may be NIL)
- * @param vallen the length of the data
- * @param flags the flags to store with the key
- * @param exptime the expiry time for the key-value pair
- * @param cas the cas id in the request
- * @param result_cas the cas id of the item
- */
- protocol_binary_response_status (*replace)(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint32_t flags,
- uint32_t exptime,
- uint64_t cas,
- uint64_t *result_cas);
-
-
- /**
- * Set a key-value pair in the cache
- *
- * @param cookie id of the client receiving the command
- * @param key the key to insert
- * @param len the length of the key
- * @param val the value to store for the key (may be NIL)
- * @param vallen the length of the data
- * @param flags the flags to store with the key
- * @param exptime the expiry time for the key-value pair
- * @param cas the cas id in the request
- * @param result_cas the cas id of the new item
- */
- protocol_binary_response_status (*set)(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint32_t flags,
- uint32_t exptime,
- uint64_t cas,
- uint64_t *result_cas);
-
- /**
- * Get status information
- *
- * @param cookie id of the client receiving the command
- * @param key the key to get status for (or NIL to request all status).
- * Remember to insert the terminating packet if multiple
- * packets should be returned.
- * @param keylen the length of the key
- * @param response_handler to send the result back to the client, but
- * don't send reply on success!
- *
- */
- protocol_binary_response_status (*stat)(const void *cookie,
- const void *key,
- uint16_t keylen,
- memcached_binary_protocol_stat_response_handler response_handler);
-
- /**
- * Get the version information
- *
- * @param cookie id of the client receiving the command
- * @param response_handler to send the result back to the client, but
- * don't send reply on success!
- *
- */
- protocol_binary_response_status (*version)(const void *cookie,
- memcached_binary_protocol_version_response_handler response_handler);
-} memcached_binary_protocol_callback_v1_st;
-
-
-/**
- * The version numbers for the different callback structures.
- */
-typedef enum {
- /** Version 0 is a lowlevel interface that tries to maximize your freedom */
- MEMCACHED_PROTOCOL_HANDLER_V0= 0,
- /**
- * Version 1 abstracts more of the protocol details, and let you work at
- * a logical level
- */
- MEMCACHED_PROTOCOL_HANDLER_V1= 1
-} memcached_protocol_interface_version_t;
-
-/**
- * Definition of the protocol callback structure.
- */
-typedef struct {
- /**
- * The interface version you provide callbacks for.
- */
- memcached_protocol_interface_version_t interface_version;
-
- /**
- * Callback fired just before the command will be executed.
- *
- * @param cookie id of the client receiving the command
- * @param header the command header as received on the wire. If you look
- * at the content you <b>must</b> ensure that you don't
- * try to access beyond the end of the message.
- */
- void (*pre_execute)(const void *cookie,
- protocol_binary_request_header *header);
- /**
- * Callback fired just after the command was exected (please note
- * that the data transfer back to the client is not finished at this
- * time).
- *
- * @param cookie id of the client receiving the command
- * @param header the command header as received on the wire. If you look
- * at the content you <b>must</b> ensure that you don't
- * try to access beyond the end of the message.
- */
- void (*post_execute)(const void *cookie,
- protocol_binary_request_header *header);
-
- /**
- * Callback fired if no specialized callback is registered for this
- * specific command code.
- *
- * @param cookie id of the client receiving the command
- * @param header the command header as received on the wire. You <b>must</b>
- * ensure that you don't try to access beyond the end of the
- * message.
- * @param response_handler The response handler to send data back.
- */
- protocol_binary_response_status (*unknown)(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler);
-
- /**
- * The different interface levels we support. A pointer is used so the
- * size of the structure is fixed. You must ensure that the memory area
- * passed as the pointer is valid as long as you use the protocol handler.
- */
- union {
- memcached_binary_protocol_callback_v0_st v0;
-
- /**
- * The first version of the callback struct containing all of the
- * documented commands in the initial release of the binary protocol
- * (aka. memcached 1.4.0).
- */
- memcached_binary_protocol_callback_v1_st v1;
- } interface;
-} memcached_binary_protocol_callback_st;
+++ /dev/null
-/* 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: Definition of the callback interface to the protocol handler
- *
- * Author: Trond Norbye
- *
- */
-
-#pragma once
-
-#include <sys/types.h>
-#if !defined(__cplusplus)
-# include <stdbool.h>
-#endif
-
-#include <libmemcached-1.0/visibility.h>
-#include <libmemcached-1.0/platform.h>
-#include <libmemcachedprotocol-0.0/binary.h>
-#include <libmemcachedprotocol-0.0/callback.h>
-
-/* Forward declarations */
-/*
- * You should only access memcached_protocol_st from one thread!,
- * and never assume anything about the internal layout / sizes of the
- * structures.
- */
-typedef struct memcached_protocol_st memcached_protocol_st;
-typedef struct memcached_protocol_client_st memcached_protocol_client_st;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Function the protocol handler should call to receive data.
- * This function should behave exactly like read(2)
- *
- * @param cookie a cookie used to represent a given client
- * @param fd the filedescriptor associated with the client
- * @param buf destination buffer
- * @param nbuf number of bytes to receive
- * @return the number of bytes copied into buf
- * or -1 upon error (errno should contain more information)
- */
-typedef ssize_t (*memcached_protocol_recv_func)(const void *cookie,
- memcached_socket_t fd,
- void *buf,
- size_t nbuf);
-
-/**
- * Function the protocol handler should call to send data.
- * This function should behave exactly like write(2)
- *
- * @param cookie a cookie used to represent a given client
- * @param fd the filedescriptor associated with the client
- * @param buf the source buffer
- * @param nbuf number of bytes to send
- * @return the number of bytes sent
- * or -1 upon error (errno should contain more information)
- */
-typedef ssize_t (*memcached_protocol_send_func)(const void *cookie,
- memcached_socket_t fd,
- const void *buf,
- size_t nbuf);
-
-/**
- * Create an instance of the protocol handler
- *
- * @return NULL if allocation of an instance fails
- */
-LIBMEMCACHED_API
-memcached_protocol_st *memcached_protocol_create_instance(void);
-
-/**
- * Get the callbacks associated with a protocol handler instance
- * @return the callbacks currently used
- */
-LIBMEMCACHED_API
-memcached_binary_protocol_callback_st *memcached_binary_protocol_get_callbacks(memcached_protocol_st *instance);
-
-/**
- * Set the callbacks to be used by the given protocol handler instance
- * @param instance the instance to update
- * @param callback the callbacks to use
- */
-LIBMEMCACHED_API
-void memcached_binary_protocol_set_callbacks(memcached_protocol_st *instance, memcached_binary_protocol_callback_st *callback);
-
-/**
- * Should the library inspect the packages being sent and received and verify
- * that they are according to the specification? If it encounters an invalid
- * packet, it will return an EINVAL packet.
- *
- * @param instance the instance to update
- * @param enable true if you want the library to check packages, false otherwise
- */
-LIBMEMCACHED_API
-void memcached_binary_protocol_set_pedantic(memcached_protocol_st *instance, bool enable);
-
-/**
- * Is the library inpecting each package?
- * @param instance the instance to check
- * @return true it the library is inspecting each package, false otherwise
- */
-LIBMEMCACHED_API
-bool memcached_binary_protocol_get_pedantic(memcached_protocol_st *instance);
-
-/**
- * Destroy an instance of the protocol handler
- *
- * @param instance The instance to destroy
- */
-LIBMEMCACHED_API
-void memcached_protocol_destroy_instance(memcached_protocol_st *instance);
-
-/**
- * Set the IO functions used by the instance to send and receive data. The
- * functions should behave like recv(3socket) and send(3socket).
- *
- * @param instance the instance to specify the IO functions for
- * @param recv the function to call for reciving data
- * @param send the function to call for sending data
- */
-LIBMEMCACHED_API
-void memached_protocol_set_io_functions(memcached_protocol_st *instance,
- memcached_protocol_recv_func recv,
- memcached_protocol_send_func send);
-
-
-/**
- * Create a new client instance and associate it with a socket
- * @param instance the protocol instance to bind the client to
- * @param sock the client socket
- * @return NULL if allocation fails, otherwise an instance
- */
-LIBMEMCACHED_API
-memcached_protocol_client_st *memcached_protocol_create_client(memcached_protocol_st *instance, memcached_socket_t sock);
-
-/**
- * Destroy a client handle.
- * The caller needs to close the socket accociated with the client
- * <b>before</b> calling this function. This function invalidates the
- * client memory area.
- *
- * @param client the client to destroy
- */
-LIBMEMCACHED_API
-void memcached_protocol_client_destroy(memcached_protocol_client_st *client);
-
-LIBMEMCACHED_API
-void memcached_protocol_client_set_verbose(struct memcached_protocol_client_st *client, bool arg);
-
-/**
- * Error event means that the client encountered an error with the
- * connection so you should shut it down
- */
-#define MEMCACHED_PROTOCOL_ERROR_EVENT 1
-/**
- * Please notify when there is more data available to read
- */
-#define MEMCACHED_PROTOCOL_READ_EVENT 2
-/**
- * Please notify when it is possible to send more data
- */
-#define MEMCACHED_PROTOCOL_WRITE_EVENT 4
-/**
- * Backed paused the execution for this client
- */
-#define MEMCACHED_PROTOCOL_PAUSE_EVENT 8
-
-/**
- * The different events the client is interested in. This is a bitmask of
- * the constants defined above.
- */
-typedef uint32_t memcached_protocol_event_t;
-
-/**
- * Let the client do some work. This might involve reading / sending data
- * to/from the client, or perform callbacks to execute a command.
- * @param client the client structure to work on
- * @return The next event the protocol handler will be notified for
- */
-LIBMEMCACHED_API
-memcached_protocol_event_t memcached_protocol_client_work(memcached_protocol_client_st *client);
-
-/**
- * Get the socket attached to a client handle
- * @param client the client to query
- * @return the socket handle
- */
-LIBMEMCACHED_API
-memcached_socket_t memcached_protocol_client_get_socket(memcached_protocol_client_st *client);
-
-/**
- * Get the error id socket attached to a client handle
- * @param client the client to query for an error code
- * @return the OS error code from the client
- */
-LIBMEMCACHED_API
-int memcached_protocol_client_get_errno(memcached_protocol_client_st *client);
-
-/**
- * Get a raw response handler for the given cookie
- * @param cookie the cookie passed along into the callback
- * @return the raw reponse handler you may use if you find
- * the generic callback too limiting
- */
-LIBMEMCACHED_API
-memcached_binary_protocol_raw_response_handler memcached_binary_protocol_get_raw_response_handler(const void *cookie);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-typedef enum {
- vbucket_state_active = 1, /**< Actively servicing a vbucket. */
- vbucket_state_replica, /**< Servicing a vbucket as a replica only. */
- vbucket_state_pending, /**< Pending active. */
- vbucket_state_dead /**< Not in use, pending deletion. */
-} vbucket_state_t;
-
-#define is_valid_vbucket_state_t(state) \
- (state == vbucket_state_active || \
- state == vbucket_state_replica || \
- state == vbucket_state_pending || \
- state == vbucket_state_dead)
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcachedprotocol/common.h>
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-
-static void print_ascii_command(memcached_protocol_client_st *client)
-{
- if (client->is_verbose)
- {
- switch (client->ascii_command)
- {
- case SET_CMD:
- fprintf(stderr, "%s:%d SET_CMD\n", __FILE__, __LINE__);
- break;
-
- case ADD_CMD:
- fprintf(stderr, "%s:%d ADD_CMD\n", __FILE__, __LINE__);
- break;
-
- case REPLACE_CMD:
- fprintf(stderr, "%s:%d REPLACE_CMD\n", __FILE__, __LINE__);
- break;
-
- case CAS_CMD:
- fprintf(stderr, "%s:%d CAS_CMD\n", __FILE__, __LINE__);
- break;
-
- case APPEND_CMD:
- fprintf(stderr, "%s:%d APPEND_CMD\n", __FILE__, __LINE__);
- break;
-
- case PREPEND_CMD:
- fprintf(stderr, "%s:%d PREPEND_CMD\n", __FILE__, __LINE__);
- break;
-
- case DELETE_CMD:
- fprintf(stderr, "%s:%d DELETE_CMD\n", __FILE__, __LINE__);
- break;
-
- case INCR_CMD: /* FALLTHROUGH */
- fprintf(stderr, "%s:%d INCR_CMD\n", __FILE__, __LINE__);
- break;
-
- case DECR_CMD:
- fprintf(stderr, "%s:%d DECR_CMD\n", __FILE__, __LINE__);
- break;
-
- case STATS_CMD:
- fprintf(stderr, "%s:%d STATS_CMD\n", __FILE__, __LINE__);
- break;
-
- case FLUSH_ALL_CMD:
- fprintf(stderr, "%s:%d FLUSH_ALL_CMD\n", __FILE__, __LINE__);
- break;
-
- case VERSION_CMD:
- fprintf(stderr, "%s:%d VERSION_CMD\n", __FILE__, __LINE__);
- break;
-
- case QUIT_CMD:
- fprintf(stderr, "%s:%d QUIT_CMD\n", __FILE__, __LINE__);
- break;
-
- case VERBOSITY_CMD:
- fprintf(stderr, "%s:%d VERBOSITY_CMD\n", __FILE__, __LINE__);
- break;
-
- case GET_CMD:
- fprintf(stderr, "%s:%d GET_CMD\n", __FILE__, __LINE__);
- break;
-
- case GETS_CMD:
- fprintf(stderr, "%s:%d GETS_CMD\n", __FILE__, __LINE__);
- break;
-
- default:
- case UNKNOWN_CMD:
- fprintf(stderr, "%s:%d UNKNOWN_CMD\n", __FILE__, __LINE__);
- break;
-
- }
- }
-}
-
-/**
- * Try to parse a key from the string.
- * @pointer start pointer to a pointer to the string (IN and OUT)
- * @return length of the string of -1 if this was an illegal key (invalid
- * characters or invalid length)
- * @todo add length!
- */
-static uint16_t parse_ascii_key(char **start)
-{
- uint16_t len= 0;
- char *c= *start;
- /* Strip leading whitespaces */
- while (isspace(*c))
- {
- ++c;
- }
-
- *start= c;
-
- while (*c != '\0' && !isspace(*c) && !iscntrl(*c))
- {
- ++c;
- ++len;
- }
-
-
- if (len == 0 || len > 240 || (*c != '\0' && *c != '\r' && iscntrl(*c)))
- {
- return 0;
- }
-
- return len;
-}
-
-/**
- * Spool a zero-terminated string
- * @param client destination
- * @param text the text to spool
- * @return status of the spool operation
- */
-static protocol_binary_response_status raw_response_handler(memcached_protocol_client_st *client, const char *text)
-{
- if (client->is_verbose)
- {
- fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, text);
- }
-
- if (client->root->drain(client) == false)
- {
- return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
- }
-
- assert(client->output != NULL);
-#if 0
- if (client->output == NULL)
- {
- /* I can write directly to the socket.... */
- do
- {
- size_t num_bytes= len -offset;
- ssize_t nw= client->root->send(client,
- client->sock,
- ptr + offset,
- num_bytes);
- if (nw == -1)
- {
- if (get_socket_errno() == EWOULDBLOCK)
- {
- break;
- }
- else if (get_socket_errno() != EINTR)
- {
- client->error= errno;
- return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
- }
- }
- else
- {
- offset += (size_t)nw;
- }
- } while (offset < len);
- }
-#endif
-
- return client->root->spool(client, text, strlen(text));
-}
-
-/**
- * Send a "CLIENT_ERROR" message back to the client with the correct
- * format of the command being sent
- * @param client the client to send the message to
- */
-static void send_command_usage(memcached_protocol_client_st *client)
-{
- const char *errmsg[]= {
- [GET_CMD]= "CLIENT_ERROR: Syntax error: get <key>*\r\n",
- [GETS_CMD]= "CLIENT_ERROR: Syntax error: gets <key>*\r\n",
- [SET_CMD]= "CLIENT_ERROR: Syntax error: set <key> <flags> <exptime> <bytes> [noreply]\r\n",
- [ADD_CMD]= "CLIENT_ERROR: Syntax error: add <key> <flags> <exptime> <bytes> [noreply]\r\n",
- [REPLACE_CMD]= "CLIENT_ERROR: Syntax error: replace <key> <flags> <exptime> <bytes> [noreply]\r\n",
- [CAS_CMD]= "CLIENT_ERROR: Syntax error: cas <key> <flags> <exptime> <bytes> <casid> [noreply]\r\n",
- [APPEND_CMD]= "CLIENT_ERROR: Syntax error: append <key> <flags> <exptime> <bytes> [noreply]\r\n",
- [PREPEND_CMD]= "CLIENT_ERROR: Syntax error: prepend <key> <flags> <exptime> <bytes> [noreply]\r\n",
- [DELETE_CMD]= "CLIENT_ERROR: Syntax error: delete_object <key> [noreply]\r\n",
- [INCR_CMD]= "CLIENT_ERROR: Syntax error: incr <key> <value> [noreply]\r\n",
- [DECR_CMD]= "CLIENT_ERROR: Syntax error: decr <key> <value> [noreply]\r\n",
- [STATS_CMD]= "CLIENT_ERROR: Syntax error: stats [key]\r\n",
- [FLUSH_ALL_CMD]= "CLIENT_ERROR: Syntax error: flush_all [timeout] [noreply]\r\n",
- [VERSION_CMD]= "CLIENT_ERROR: Syntax error: version\r\n",
- [QUIT_CMD]="CLIENT_ERROR: Syntax error: quit\r\n",
-
- [VERBOSITY_CMD]= "CLIENT_ERROR: Syntax error: verbosity <num>\r\n",
- [UNKNOWN_CMD]= "CLIENT_ERROR: Unknown command\r\n",
- };
-
- client->mute = false;
- raw_response_handler(client, errmsg[client->ascii_command]);
-}
-
-/**
- * Callback for the VERSION responses
- * @param cookie client identifier
- * @param text the length of the body
- * @param textlen the length of the body
- */
-static protocol_binary_response_status ascii_version_response_handler(const void *cookie,
- const void *text,
- uint32_t textlen)
-{
- memcached_protocol_client_st *client= (memcached_protocol_client_st*)cookie;
- raw_response_handler(client, "VERSION ");
- client->root->spool(client, text, textlen);
- raw_response_handler(client, "\r\n");
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-/**
- * Callback for the GET/GETQ/GETK and GETKQ responses
- * @param cookie client identifier
- * @param key the key for the item
- * @param keylen the length of the key
- * @param body the length of the body
- * @param bodylen the length of the body
- * @param flags the flags for the item
- * @param cas the CAS id for the item
- */
-static protocol_binary_response_status
-ascii_get_response_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void *body,
- uint32_t bodylen,
- uint32_t flags,
- uint64_t cas)
-{
- memcached_protocol_client_st *client= (void*)cookie;
- char buffer[300];
- strcpy(buffer, "VALUE ");
- const char *source= key;
- char *dest= buffer + 6;
-
- for (int x= 0; x < keylen; ++x)
- {
- if (*source != '\0' && !isspace(*source) && !iscntrl(*source))
- {
- *dest= *source;
- }
- else
- {
- return PROTOCOL_BINARY_RESPONSE_EINVAL; /* key constraints in ascii */
- }
-
- ++dest;
- ++source;
- }
-
- size_t used= (size_t)(dest - buffer);
-
- if (client->ascii_command == GETS_CMD)
- {
- snprintf(dest, sizeof(buffer) - used, " %u %u %" PRIu64 "\r\n", flags,
- bodylen, cas);
- }
- else
- {
- snprintf(dest, sizeof(buffer) - used, " %u %u\r\n", flags, bodylen);
- }
-
- client->root->spool(client, buffer, strlen(buffer));
- client->root->spool(client, body, bodylen);
- client->root->spool(client, "\r\n", 2);
-
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-/**
- * Callback for the STAT responses
- * @param cookie client identifier
- * @param key the key for the item
- * @param keylen the length of the key
- * @param body the length of the body
- * @param bodylen the length of the body
- */
-static protocol_binary_response_status ascii_stat_response_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void *body,
- uint32_t bodylen)
-{
-
- memcached_protocol_client_st *client= (void*)cookie;
-
- if (key != NULL)
- {
- raw_response_handler(client, "STAT ");
- client->root->spool(client, key, keylen);
- raw_response_handler(client, " ");
- client->root->spool(client, body, bodylen);
- raw_response_handler(client, "\r\n");
- }
- else
- {
- raw_response_handler(client, "END\r\n");
- }
-
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-/**
- * Process a get or a gets request.
- * @param client the client handle
- * @param buffer the complete get(s) command
- * @param end the last character in the command
- */
-static void ascii_process_gets(memcached_protocol_client_st *client,
- char *buffer, char *end)
-{
- char *key= buffer;
-
- /* Skip command */
- key += (client->ascii_command == GETS_CMD) ? 5 : 4;
-
- int num_keys= 0;
- while (key < end)
- {
- uint16_t nkey= parse_ascii_key(&key);
- if (nkey == 0) /* Invalid key... stop processing this line */
- {
- break;
- }
-
- (void)client->root->callback->interface.v1.get(client, key, nkey,
- ascii_get_response_handler);
- key += nkey;
- ++num_keys;
- }
-
- if (num_keys == 0)
- {
- send_command_usage(client);
- }
- else
- {
- client->root->spool(client, "END\r\n", 5);
- }
-}
-
-/**
- * Try to split up the command line "asdf asdf asdf asdf\n" into an
- * argument vector for easier parsing.
- * @param start the first character in the command line
- * @param end the last character in the command line ("\n")
- * @param vec the vector to insert the pointers into
- * @size the number of elements in the vector
- * @return the number of tokens in the vector
- */
-static int ascii_tokenize_command(char *str, char *end, char **vec, int size)
-{
- int elem= 0;
-
- while (str < end)
- {
- /* Skip leading blanks */
- while (str < end && isspace(*str))
- {
- ++str;
- }
-
- if (str == end)
- {
- return elem;
- }
-
- vec[elem++]= str;
- /* find the next non-blank field */
- while (str < end && !isspace(*str))
- {
- ++str;
- }
-
- /* zero-terminate it for easier parsing later on */
- *str= '\0';
- ++str;
-
- /* Is the vector full? */
- if (elem == size)
- {
- break;
- }
- }
-
- return elem;
-}
-
-/**
- * If we for some reasons needs to push the line back to read more
- * data we have to reverse the tokenization. Just do the brain-dead replace
- * of all '\0' to ' ' and set the last character to '\n'. We could have used
- * the vector we created, but then we would have to search for all of the
- * spaces we ignored...
- * @param start pointer to the first character in the buffer to recover
- * @param end pointer to the last character in the buffer to recover
- */
-static void recover_tokenize_command(char *start, char *end)
-{
- while (start < end)
- {
- if (*start == '\0')
- *start= ' ';
- ++start;
- }
-
- *end= '\n';
-}
-
-/**
- * Convert the textual command into a comcode
- */
-static enum ascii_cmd ascii_to_cmd(char *start, size_t length)
-{
- struct {
- const char *cmd;
- size_t len;
- enum ascii_cmd cc;
- } commands[]= {
- { .cmd= "get", .len= 3, .cc= GET_CMD },
- { .cmd= "gets", .len= 4, .cc= GETS_CMD },
- { .cmd= "set", .len= 3, .cc= SET_CMD },
- { .cmd= "add", .len= 3, .cc= ADD_CMD },
- { .cmd= "replace", .len= 7, .cc= REPLACE_CMD },
- { .cmd= "cas", .len= 3, .cc= CAS_CMD },
- { .cmd= "append", .len= 6, .cc= APPEND_CMD },
- { .cmd= "prepend", .len= 7, .cc= PREPEND_CMD },
- { .cmd= "delete_object", .len= 6, .cc= DELETE_CMD },
- { .cmd= "incr", .len= 4, .cc= INCR_CMD },
- { .cmd= "decr", .len= 4, .cc= DECR_CMD },
- { .cmd= "stats", .len= 5, .cc= STATS_CMD },
- { .cmd= "flush_all", .len= 9, .cc= FLUSH_ALL_CMD },
- { .cmd= "version", .len= 7, .cc= VERSION_CMD },
- { .cmd= "quit", .len= 4, .cc= QUIT_CMD },
- { .cmd= "verbosity", .len= 9, .cc= VERBOSITY_CMD },
- { .cmd= NULL, .len= 0, .cc= UNKNOWN_CMD }};
-
- int x= 0;
- while (commands[x].len > 0) {
- if (length >= commands[x].len)
- {
- if (strncmp(start, commands[x].cmd, commands[x].len) == 0)
- {
- /* Potential hit */
- if (length == commands[x].len || isspace(*(start + commands[x].len)))
- {
- return commands[x].cc;
- }
- }
- }
- ++x;
- }
-
- return UNKNOWN_CMD;
-}
-
-/**
- * Perform a delete_object operation.
- *
- * @param client client requesting the deletion
- * @param tokens the command as a vector
- * @param ntokens the number of items in the vector
- */
-static void process_delete(memcached_protocol_client_st *client,
- char **tokens, int ntokens)
-{
- char *key= tokens[1];
- uint16_t nkey;
-
- if (ntokens != 2 || (nkey= parse_ascii_key(&key)) == 0)
- {
- send_command_usage(client);
- return;
- }
-
- if (client->root->callback->interface.v1.delete_object == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return;
- }
-
- protocol_binary_response_status rval= client->root->callback->interface.v1.delete_object(client, key, nkey, 0);
-
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
- {
- raw_response_handler(client, "DELETED\r\n");
- }
- else if (rval == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)
- {
- raw_response_handler(client, "NOT_FOUND\r\n");
- }
- else
- {
- char msg[80];
- snprintf(msg, sizeof(msg), "SERVER_ERROR: delete_object failed %u\r\n",(uint32_t)rval);
- raw_response_handler(client, msg);
- }
-}
-
-static void process_arithmetic(memcached_protocol_client_st *client,
- char **tokens, int ntokens)
-{
- char *key= tokens[1];
- uint16_t nkey;
-
- if (ntokens != 3 || (nkey= parse_ascii_key(&key)) == 0)
- {
- send_command_usage(client);
- return;
- }
-
- uint64_t cas;
- uint64_t result;
- errno= 0;
- uint64_t delta= strtoull(tokens[2], NULL, 10);
- if (errno != 0)
- {
- return; // Error
- }
-
- protocol_binary_response_status rval;
- if (client->ascii_command == INCR_CMD)
- {
- if (client->root->callback->interface.v1.increment == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return;
- }
- rval= client->root->callback->interface.v1.increment(client,
- key, nkey,
- delta, 0,
- 0,
- &result,
- &cas);
- }
- else
- {
- if (client->root->callback->interface.v1.decrement == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return;
- }
- rval= client->root->callback->interface.v1.decrement(client,
- key, nkey,
- delta, 0,
- 0,
- &result,
- &cas);
- }
-
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
- {
- char buffer[80];
- snprintf(buffer, sizeof(buffer), "%"PRIu64"\r\n", result);
- raw_response_handler(client, buffer);
- }
- else
- {
- raw_response_handler(client, "NOT_FOUND\r\n");
- }
-}
-
-/**
- * Process the stats command (with or without a key specified)
- * @param key pointer to the first character after "stats"
- * @param end pointer to the "\n"
- */
-static void process_stats(memcached_protocol_client_st *client,
- char *key, char *end)
-{
- if (client->root->callback->interface.v1.stat == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return;
- }
-
- while (isspace(*key))
- {
- key++;
- }
-
- uint16_t nkey= (uint16_t)(end - key);
- (void)client->root->callback->interface.v1.stat(client, key, nkey,
- ascii_stat_response_handler);
-}
-
-static void process_version(memcached_protocol_client_st *client,
- char **tokens, int ntokens)
-{
- (void)tokens;
- if (ntokens != 1)
- {
- send_command_usage(client);
- return;
- }
-
- if (client->root->callback->interface.v1.version == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return;
- }
-
- client->root->callback->interface.v1.version(client,
- ascii_version_response_handler);
-}
-
-static void process_flush(memcached_protocol_client_st *client,
- char **tokens, int ntokens)
-{
- if (ntokens > 2)
- {
- send_command_usage(client);
- return;
- }
-
- if (client->root->callback->interface.v1.flush_object == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return;
- }
-
- uint32_t timeout= 0;
- if (ntokens == 2)
- {
- errno= 0;
- timeout= (uint32_t)strtoul(tokens[1], NULL, 10);
- if (errno != 0)
- {
- return; // Error
- }
- }
-
- protocol_binary_response_status rval;
- rval= client->root->callback->interface.v1.flush_object(client, timeout);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
- raw_response_handler(client, "OK\r\n");
- else
- raw_response_handler(client, "SERVER_ERROR: internal error\r\n");
-}
-
-/**
- * Process one of the storage commands
- * @param client the client performing the operation
- * @param tokens the command tokens
- * @param ntokens the number of tokens
- * @param start pointer to the first character in the line
- * @param end pointer to the pointer where the last character of this
- * command is (IN and OUT)
- * @param length the number of bytes available
- * @return -1 if an error occurs (and we should just terminate the connection
- * because we are out of sync)
- * 0 storage command completed, continue processing
- * 1 We need more data, so just go ahead and wait for more!
- */
-static inline int process_storage_command(memcached_protocol_client_st *client,
- char **tokens, int ntokens, char *start,
- char **end, ssize_t length)
-{
- (void)ntokens; /* already checked */
- char *key= tokens[1];
- uint16_t nkey= parse_ascii_key(&key);
- if (nkey == 0)
- {
- /* return error */
- raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
- return -1;
- }
-
- errno= 0;
- uint32_t flags= (uint32_t)strtoul(tokens[2], NULL, 10);
- if (errno != 0)
- {
- /* return error */
- raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
- return -1;
- }
-
- uint32_t timeout= (uint32_t)strtoul(tokens[3], NULL, 10);
- if (errno != 0)
- {
- /* return error */
- raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
- return -1;
- }
-
- unsigned long nbytes= strtoul(tokens[4], NULL, 10);
- if (errno != 0)
- {
- /* return error */
- raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
- return -1;
- }
-
- /* Do we have all data? */
- unsigned long need= nbytes + (unsigned long)((*end - start) + 1) + 2; /* \n\r\n */
- if ((ssize_t)need > length)
- {
- /* Keep on reading */
- recover_tokenize_command(start, *end);
- return 1;
- }
-
- void *data= (*end) + 1;
- uint64_t cas= 0;
- uint64_t result_cas;
- protocol_binary_response_status rval;
- switch (client->ascii_command)
- {
- case SET_CMD:
- rval= client->root->callback->interface.v1.set(client, key,
- (uint16_t)nkey,
- data,
- (uint32_t)nbytes,
- flags,
- timeout, cas,
- &result_cas);
- break;
- case ADD_CMD:
- rval= client->root->callback->interface.v1.add(client, key,
- (uint16_t)nkey,
- data,
- (uint32_t)nbytes,
- flags,
- timeout, &result_cas);
- break;
- case CAS_CMD:
- errno= 0;
- cas= strtoull(tokens[5], NULL, 10);
- if (errno != 0)
- {
- /* return error */
- raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
- return -1;
- }
- /* FALLTHROUGH */
- case REPLACE_CMD:
- rval= client->root->callback->interface.v1.replace(client, key,
- (uint16_t)nkey,
- data,
- (uint32_t)nbytes,
- flags,
- timeout, cas,
- &result_cas);
- break;
- case APPEND_CMD:
- rval= client->root->callback->interface.v1.append(client, key,
- (uint16_t)nkey,
- data,
- (uint32_t)nbytes,
- cas,
- &result_cas);
- break;
- case PREPEND_CMD:
- rval= client->root->callback->interface.v1.prepend(client, key,
- (uint16_t)nkey,
- data,
- (uint32_t)nbytes,
- cas,
- &result_cas);
- break;
-
- /* gcc complains if I don't put all of the enums in here.. */
- case GET_CMD:
- case GETS_CMD:
- case DELETE_CMD:
- case DECR_CMD:
- case INCR_CMD:
- case STATS_CMD:
- case FLUSH_ALL_CMD:
- case VERSION_CMD:
- case QUIT_CMD:
- case VERBOSITY_CMD:
- case UNKNOWN_CMD:
- default:
- abort(); /* impossible */
- }
-
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
- {
- raw_response_handler(client, "STORED\r\n");
- }
- else
- {
- if (client->ascii_command == CAS_CMD)
- {
- if (rval == PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS)
- {
- raw_response_handler(client, "EXISTS\r\n");
- }
- else if (rval == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)
- {
- raw_response_handler(client, "NOT_FOUND\r\n");
- }
- else
- {
- raw_response_handler(client, "NOT_STORED\r\n");
- }
- }
- else
- {
- raw_response_handler(client, "NOT_STORED\r\n");
- }
- }
-
- *end += nbytes + 2;
-
- return 0;
-}
-
-static int process_cas_command(memcached_protocol_client_st *client,
- char **tokens, int ntokens, char *start,
- char **end, ssize_t length)
-{
- if (ntokens != 6)
- {
- send_command_usage(client);
- return false;
- }
-
- if (client->root->callback->interface.v1.replace == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return false;
- }
-
- return process_storage_command(client, tokens, ntokens, start, end, length);
-}
-
-static int process_set_command(memcached_protocol_client_st *client,
- char **tokens, int ntokens, char *start,
- char **end, ssize_t length)
-{
- if (ntokens != 5)
- {
- send_command_usage(client);
- return false;
- }
-
- if (client->root->callback->interface.v1.set == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return false;
- }
-
- return process_storage_command(client, tokens, ntokens, start, end, length);
-}
-
-static int process_add_command(memcached_protocol_client_st *client,
- char **tokens, int ntokens, char *start,
- char **end, ssize_t length)
-{
- if (ntokens != 5)
- {
- send_command_usage(client);
- return false;
- }
-
- if (client->root->callback->interface.v1.add == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return false;
- }
-
- return process_storage_command(client, tokens, ntokens, start, end, length);
-}
-
-static int process_replace_command(memcached_protocol_client_st *client,
- char **tokens, int ntokens, char *start,
- char **end, ssize_t length)
-{
- if (ntokens != 5)
- {
- send_command_usage(client);
- return false;
- }
-
- if (client->root->callback->interface.v1.replace == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return false;
- }
-
- return process_storage_command(client, tokens, ntokens, start, end, length);
-}
-
-static int process_append_command(memcached_protocol_client_st *client,
- char **tokens, int ntokens, char *start,
- char **end, ssize_t length)
-{
- if (ntokens != 5)
- {
- send_command_usage(client);
- return false;
- }
-
- if (client->root->callback->interface.v1.append == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return false;
- }
-
- return process_storage_command(client, tokens, ntokens, start, end, length);
-}
-
-static int process_prepend_command(memcached_protocol_client_st *client,
- char **tokens, int ntokens, char *start,
- char **end, ssize_t length)
-{
- if (ntokens != 5)
- {
- send_command_usage(client);
- return false;
- }
-
- if (client->root->callback->interface.v1.prepend == NULL)
- {
- raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
- return false;
- }
-
- return process_storage_command(client, tokens, ntokens, start, end, length);
-}
-
-/**
- * The ASCII protocol support is just one giant big hack. Instead of adding
- * a optimal ascii support, I just convert the ASCII commands to the binary
- * protocol and calls back into the command handlers for the binary protocol ;)
- */
-memcached_protocol_event_t memcached_ascii_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr)
-{
- char *ptr= (char*)client->root->input_buffer;
- *endptr= ptr;
-
- do {
- /* Do we have \n (indicating the command preamble)*/
- char *end= memchr(ptr, '\n', (size_t)*length);
- if (end == NULL)
- {
- *endptr= ptr;
- return MEMCACHED_PROTOCOL_READ_EVENT;
- }
-
- client->ascii_command= ascii_to_cmd(ptr, (size_t)(*length));
-
- /* we got all data available, execute the callback! */
- if (client->root->callback->pre_execute != NULL)
- {
- client->root->callback->pre_execute(client, NULL);
- }
-
-
- /* A multiget lists all of the keys, and I don't want to have an
- * avector of let's say 512 pointers to tokenize all of them, so let's
- * just handle them immediately
- */
- if (client->ascii_command == GET_CMD ||
- client->ascii_command == GETS_CMD)
- {
- if (client->root->callback->interface.v1.get != NULL)
- {
- ascii_process_gets(client, ptr, end);
- }
- else
- {
- raw_response_handler(client, "SERVER_ERROR: Command not implemented\n");
- }
- }
- else
- {
- /* None of the defined commands takes 10 parameters, so lets just use
- * that as a maximum limit.
- */
- char *tokens[10];
- int ntokens= ascii_tokenize_command(ptr, end, tokens, 10);
-
- if (ntokens < 10)
- {
- client->mute= strcmp(tokens[ntokens - 1], "noreply") == 0;
- if (client->mute)
- {
- --ntokens; /* processed noreply token*/
- }
- }
-
- int error= 0;
-
- print_ascii_command(client);
- switch (client->ascii_command)
- {
- case SET_CMD:
- error= process_set_command(client, tokens, ntokens, ptr, &end, *length);
- break;
-
- case ADD_CMD:
- error= process_add_command(client, tokens, ntokens, ptr, &end, *length);
- break;
-
- case REPLACE_CMD:
- error= process_replace_command(client, tokens, ntokens, ptr, &end, *length);
- break;
-
- case CAS_CMD:
- error= process_cas_command(client, tokens, ntokens, ptr, &end, *length);
- break;
-
- case APPEND_CMD:
- error= process_append_command(client, tokens, ntokens, ptr, &end, *length);
- break;
-
- case PREPEND_CMD:
- error= process_prepend_command(client, tokens, ntokens, ptr, &end, *length);
- break;
-
- case DELETE_CMD:
- process_delete(client, tokens, ntokens);
- break;
-
- case INCR_CMD: /* FALLTHROUGH */
- case DECR_CMD:
- process_arithmetic(client, tokens, ntokens);
- break;
-
- case STATS_CMD:
- if (client->mute)
- {
- send_command_usage(client);
- }
- else
- {
- recover_tokenize_command(ptr, end);
- process_stats(client, ptr + 6, end);
- }
- break;
-
- case FLUSH_ALL_CMD:
- process_flush(client, tokens, ntokens);
- break;
-
- case VERSION_CMD:
- if (client->mute)
- {
- send_command_usage(client);
- }
- else
- {
- process_version(client, tokens, ntokens);
- }
- break;
-
- case QUIT_CMD:
- if (ntokens != 1 || client->mute)
- {
- send_command_usage(client);
- }
- else
- {
- if (client->root->callback->interface.v1.quit != NULL)
- {
- client->root->callback->interface.v1.quit(client);
- }
-
- return MEMCACHED_PROTOCOL_ERROR_EVENT;
- }
- break;
-
- case VERBOSITY_CMD:
- if (ntokens != 2)
- {
- send_command_usage(client);
- }
- else
- {
- raw_response_handler(client, "OK\r\n");
- }
- break;
-
- case UNKNOWN_CMD:
- send_command_usage(client);
- break;
-
- case GET_CMD:
- case GETS_CMD:
- default:
- /* Should already be handled */
- abort();
- }
-
- if (error == -1)
- {
- return MEMCACHED_PROTOCOL_ERROR_EVENT;
- }
- else if (error == 1)
- {
- return MEMCACHED_PROTOCOL_READ_EVENT;
- }
- }
-
- if (client->root->callback->post_execute != NULL)
- {
- client->root->callback->post_execute(client, NULL);
- }
-
- /* Move past \n */
- ++end;
- *length -= end - ptr;
- ptr= end;
- } while (*length > 0);
-
- *endptr= ptr;
- return MEMCACHED_PROTOCOL_READ_EVENT;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-LIBMEMCACHED_LOCAL
-memcached_protocol_event_t memcached_ascii_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcachedprotocol/common.h>
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdio.h>
-
-/*
-** **********************************************************************
-** INTERNAL INTERFACE
-** **********************************************************************
-*/
-
-/**
- * Send a preformatted packet back to the client. If the connection is in
- * pedantic mode, it will validate the packet and refuse to send it if it
- * breaks the specification.
- *
- * @param cookie client identification
- * @param request the original request packet
- * @param response the packet to send
- * @return The status of the operation
- */
-static protocol_binary_response_status raw_response_handler(const void *cookie,
- protocol_binary_request_header *request,
- protocol_binary_response_header *response)
-{
- memcached_protocol_client_st *client= (void*)cookie;
-
- if (client->root->pedantic &&
- !memcached_binary_protocol_pedantic_check_response(request, response))
- {
- return PROTOCOL_BINARY_RESPONSE_EINVAL;
- }
-
- if (client->root->drain(client) == false)
- {
- return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
- }
-
- size_t len= sizeof(protocol_binary_response_header) + htonl(response->response.bodylen);
- size_t offset= 0;
- char *ptr= (void*)response;
-
- if (client->output == NULL)
- {
- /* I can write directly to the socket.... */
- do
- {
- size_t num_bytes= len - offset;
- ssize_t nw= client->root->send(client,
- client->sock,
- ptr + offset,
- num_bytes);
- if (nw == -1)
- {
- if (get_socket_errno() == EWOULDBLOCK)
- {
- break;
- }
- else if (get_socket_errno() != EINTR)
- {
- client->error= errno;
- return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
- }
- }
- else
- {
- offset += (size_t)nw;
- }
- } while (offset < len);
- }
-
- return client->root->spool(client, ptr, len - offset);
-}
-
-static void print_cmd(protocol_binary_command cmd)
-{
- switch (cmd)
- {
- case PROTOCOL_BINARY_CMD_GET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GET\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_SET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SET\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_ADD: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_ADD\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_REPLACE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_REPLACE\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_DELETE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DELETE\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_INCREMENT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_INCREMENT\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_DECREMENT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DECREMENT\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_QUIT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_QUIT\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_FLUSH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_FLUSH\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_GETQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_NOOP: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_NOOP\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_VERSION: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_VERSION\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_GETK: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETK\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_GETKQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETKQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_APPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_APPEND\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_PREPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_PREPEND\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_STAT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_STAT\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_SETQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SETQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_ADDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_ADDQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_REPLACEQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_REPLACEQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_DELETEQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DELETEQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_INCREMENTQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_INCREMENTQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_DECREMENTQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DECREMENTQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_QUITQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_QUITQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_FLUSHQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_FLUSHQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_APPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_APPENDQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_PREPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_PREPENDQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_VERBOSITY: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_VERBOSITY\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_TOUCH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TOUCH\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_GAT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GAT\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_GATQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_LIST_MECHS\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_SASL_AUTH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_AUTH\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_SASL_STEP: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_STEP\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RGET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RGET\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RSET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RSET\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RSETQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RSETQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RAPPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RAPPEND\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RAPPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RAPPENDQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RPREPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RPREPEND\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RPREPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RPREPENDQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RDELETE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDELETE\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RDELETEQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDELETEQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RINCR: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RINCR\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RINCRQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RINCRQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RDECR: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDECR\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_RDECRQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDECRQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_SET_VBUCKET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SET_VBUCKET\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_GET_VBUCKET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GET_VBUCKET\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_DEL_VBUCKET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DEL_VBUCKET\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_TAP_CONNECT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CONNECT\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_TAP_MUTATION: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_MUTATION\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_TAP_DELETE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_DELETE\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_TAP_FLUSH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_FLUSH\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_TAP_OPAQUE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_OPAQUE\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_LAST_RESERVED: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_LAST_RESERVED\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_GATK: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATK\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_GATKQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATKQ\n", __FILE__, __LINE__); return;
- case PROTOCOL_BINARY_CMD_SCRUB: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SCRUB\n", __FILE__, __LINE__); return;
- default:
- abort();
- }
-}
-
-/*
- * Version 0 of the interface is really low level and protocol specific,
- * while the version 1 of the interface is more API focused. We need a
- * way to translate between the command codes on the wire and the
- * application level interface in V1, so let's just use the V0 of the
- * interface as a map instead of creating a huuuge switch :-)
- */
-
-/**
- * Callback for the GET/GETQ/GETK and GETKQ responses
- * @param cookie client identifier
- * @param key the key for the item
- * @param keylen the length of the key
- * @param body the length of the body
- * @param bodylen the length of the body
- * @param flags the flags for the item
- * @param cas the CAS id for the item
- */
-static protocol_binary_response_status get_response_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void *body,
- uint32_t bodylen,
- uint32_t flags,
- uint64_t cas)
-{
- memcached_protocol_client_st *client= (void*)cookie;
- uint8_t opcode= client->current_command->request.opcode;
-
- if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETQ)
- {
- keylen= 0;
- }
-
- protocol_binary_response_get response= {
- .message.header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= opcode,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= client->current_command->request.opaque,
- .cas= memcached_htonll(cas),
- .keylen= htons(keylen),
- .extlen= 4,
- .bodylen= htonl(bodylen + keylen + 4),
- },
- };
-
- response.message.body.flags= htonl(flags);
-
- protocol_binary_response_status rval;
- const protocol_binary_response_status success= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- if ((rval= client->root->spool(client, response.bytes, sizeof(response.bytes))) != success ||
- (rval= client->root->spool(client, key, keylen)) != success ||
- (rval= client->root->spool(client, body, bodylen)) != success)
- {
- return rval;
- }
-
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-/**
- * Callback for the STAT responses
- * @param cookie client identifier
- * @param key the key for the item
- * @param keylen the length of the key
- * @param body the length of the body
- * @param bodylen the length of the body
- */
-static protocol_binary_response_status stat_response_handler(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void *body,
- uint32_t bodylen)
-{
-
- memcached_protocol_client_st *client= (void*)cookie;
-
- protocol_binary_response_no_extras response= {
- .message.header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= client->current_command->request.opcode,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= client->current_command->request.opaque,
- .keylen= htons(keylen),
- .bodylen= htonl(bodylen + keylen),
- .cas= 0
- },
- };
-
- protocol_binary_response_status rval;
- const protocol_binary_response_status success= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- if ((rval= client->root->spool(client, response.bytes, sizeof(response.bytes))) != success ||
- (rval= client->root->spool(client, key, keylen)) != success ||
- (rval= client->root->spool(client, body, bodylen)) != success)
- {
- return rval;
- }
-
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-/**
- * Callback for the VERSION responses
- * @param cookie client identifier
- * @param text the length of the body
- * @param textlen the length of the body
- */
-static protocol_binary_response_status version_response_handler(const void *cookie,
- const void *text,
- uint32_t textlen)
-{
-
- memcached_protocol_client_st *client= (void*)cookie;
-
- protocol_binary_response_no_extras response= {
- .message.header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= client->current_command->request.opcode,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= client->current_command->request.opaque,
- .bodylen= htonl(textlen),
- .cas= 0
- },
- };
-
- protocol_binary_response_status rval;
- const protocol_binary_response_status success= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- if ((rval= client->root->spool(client, response.bytes, sizeof(response.bytes))) != success ||
- (rval= client->root->spool(client, text, textlen)) != success)
- {
- return rval;
- }
-
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-/**
- * Callback for ADD and ADDQ
- * @param cookie the calling client
- * @param header the add/addq command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-add_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.add != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
- uint32_t datalen= ntohl(header->request.bodylen) - keylen - 8;
- protocol_binary_request_add *request= (void*)header;
- uint32_t flags= ntohl(request->message.body.flags);
- uint32_t timeout= ntohl(request->message.body.expiration);
- char *key= ((char*)header) + sizeof(*header) + 8;
- char *data= key + keylen;
- uint64_t cas;
-
- rval= client->root->callback->interface.v1.add(cookie, key, keylen,
- data, datalen, flags,
- timeout, &cas);
-
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
- {
- /* Send a positive request */
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_ADD,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- .cas= memcached_ntohll(cas)
- }
- }
- };
- rval= response_handler(cookie, header, (void*)&response);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for DECREMENT and DECREMENTQ
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-decrement_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.decrement != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
- protocol_binary_request_decr *request= (void*)header;
- uint64_t init= memcached_ntohll(request->message.body.initial);
- uint64_t delta= memcached_ntohll(request->message.body.delta);
- uint32_t timeout= ntohl(request->message.body.expiration);
- void *key= request->bytes + sizeof(request->bytes);
- uint64_t result;
- uint64_t cas;
-
- rval= client->root->callback->interface.v1.decrement(cookie, key, keylen,
- delta, init, timeout,
- &result, &cas);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENT)
- {
- /* Send a positive request */
- protocol_binary_response_decr response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_DECREMENT,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- .cas= memcached_ntohll(cas),
- .bodylen= htonl(8)
- },
- .body.value= memcached_htonll(result)
- }
- };
- rval= response_handler(cookie, header, (void*)&response);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for DELETE and DELETEQ
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status delete_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.delete_object != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
- void *key= (header +1);
- uint64_t cas= memcached_ntohll(header->request.cas);
- rval= client->root->callback->interface.v1.delete_object(cookie, key, keylen, cas);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
- {
- /* Send a positive request */
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_DELETE,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- }
- }
- };
- rval= response_handler(cookie, header, (void*)&response);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for FLUSH and FLUSHQ
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-flush_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.flush_object != NULL)
- {
- protocol_binary_request_flush *flush_object= (void*)header;
- uint32_t timeout= 0;
- if (htonl(header->request.bodylen) == 4)
- {
- timeout= ntohl(flush_object->message.body.expiration);
- }
-
- rval= client->root->callback->interface.v1.flush_object(cookie, timeout);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- header->request.opcode == PROTOCOL_BINARY_CMD_FLUSH)
- {
- /* Send a positive request */
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_FLUSH,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- }
- }
- };
- rval= response_handler(cookie, header, (void*)&response);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for GET, GETK, GETQ, GETKQ
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-get_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.get != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
- void *key= (header + 1);
- rval= client->root->callback->interface.v1.get(cookie, key, keylen,
- get_response_handler);
-
- if (rval == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT &&
- (header->request.opcode == PROTOCOL_BINARY_CMD_GETQ ||
- header->request.opcode == PROTOCOL_BINARY_CMD_GETKQ))
- {
- /* Quiet commands shouldn't respond on cache misses */
- rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for INCREMENT and INCREMENTQ
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-increment_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.increment != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
- protocol_binary_request_incr *request= (void*)header;
- uint64_t init= memcached_ntohll(request->message.body.initial);
- uint64_t delta= memcached_ntohll(request->message.body.delta);
- uint32_t timeout= ntohl(request->message.body.expiration);
- void *key= request->bytes + sizeof(request->bytes);
- uint64_t cas;
- uint64_t result;
-
- rval= client->root->callback->interface.v1.increment(cookie, key, keylen,
- delta, init, timeout,
- &result, &cas);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT)
- {
- /* Send a positive request */
- protocol_binary_response_incr response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_INCREMENT,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- .cas= memcached_ntohll(cas),
- .bodylen= htonl(8)
- },
- .body.value= memcached_htonll(result)
- }
- };
-
- rval= response_handler(cookie, header, (void*)&response);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for noop. Inform the v1 interface about the noop packet, and
- * create and send a packet back to the client
- *
- * @param cookie the calling client
- * @param header the command
- * @param response_handler the response handler
- * @return the result of the operation
- */
-static protocol_binary_response_status
-noop_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.noop != NULL)
- {
- client->root->callback->interface.v1.noop(cookie);
- }
-
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_NOOP,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- }
- }
- };
-
- return response_handler(cookie, header, (void*)&response);
-}
-
-/**
- * Callback for APPEND and APPENDQ
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-append_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.append != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
- uint32_t datalen= ntohl(header->request.bodylen) - keylen;
- char *key= (void*)(header +1);
- char *data= key +keylen;
- uint64_t cas= memcached_ntohll(header->request.cas);
- uint64_t result_cas;
-
- rval= client->root->callback->interface.v1.append(cookie, key, keylen,
- data, datalen, cas,
- &result_cas);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- header->request.opcode == PROTOCOL_BINARY_CMD_APPEND)
- {
- /* Send a positive request */
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_APPEND,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- .cas= memcached_ntohll(result_cas),
- },
- }
- };
- rval= response_handler(cookie, header, (void*)&response);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for PREPEND and PREPENDQ
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-prepend_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.prepend != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
- uint32_t datalen= ntohl(header->request.bodylen) - keylen;
- char *key= (char*)(header + 1);
- char *data= key + keylen;
- uint64_t cas= memcached_ntohll(header->request.cas);
- uint64_t result_cas;
- rval= client->root->callback->interface.v1.prepend(cookie, key, keylen,
- data, datalen, cas,
- &result_cas);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
- {
- /* Send a positive request */
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_PREPEND,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- .cas= memcached_ntohll(result_cas),
- },
- }
- };
- rval= response_handler(cookie, header, (void*)&response);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for QUIT and QUITQ. Notify the client and shut down the connection
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-quit_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.quit != NULL)
- {
- client->root->callback->interface.v1.quit(cookie);
- }
-
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_QUIT,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque
- }
- }
- };
-
- if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT)
- {
- response_handler(cookie, header, (void*)&response);
- }
-
- /* I need a better way to signal to close the connection */
- return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
-}
-
-/**
- * Callback for REPLACE and REPLACEQ
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-replace_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.replace != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
- uint32_t datalen= ntohl(header->request.bodylen) - keylen - 8;
- protocol_binary_request_replace *request= (void*)header;
- uint32_t flags= ntohl(request->message.body.flags);
- uint32_t timeout= ntohl(request->message.body.expiration);
- char *key= ((char*)header) + sizeof(*header) + 8;
- char *data= key + keylen;
- uint64_t cas= memcached_ntohll(header->request.cas);
- uint64_t result_cas;
-
- rval= client->root->callback->interface.v1.replace(cookie, key, keylen,
- data, datalen, flags,
- timeout, cas,
- &result_cas);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
- {
- /* Send a positive request */
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_REPLACE,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- .cas= memcached_ntohll(result_cas),
- },
- }
- };
- rval= response_handler(cookie, header, (void*)&response);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for SET and SETQ
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status set_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.set != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
- uint32_t datalen= ntohl(header->request.bodylen) - keylen - 8;
- protocol_binary_request_replace *request= (void*)header;
- uint32_t flags= ntohl(request->message.body.flags);
- uint32_t timeout= ntohl(request->message.body.expiration);
- char *key= ((char*)header) + sizeof(*header) + 8;
- char *data= key + keylen;
- uint64_t cas= memcached_ntohll(header->request.cas);
- uint64_t result_cas;
-
-
- rval= client->root->callback->interface.v1.set(cookie, key, keylen,
- data, datalen, flags,
- timeout, cas, &result_cas);
- if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- header->request.opcode == PROTOCOL_BINARY_CMD_SET)
- {
- /* Send a positive request */
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= PROTOCOL_BINARY_CMD_SET,
- .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
- .opaque= header->request.opaque,
- .cas= memcached_ntohll(result_cas),
- },
- }
- };
- rval= response_handler(cookie, header, (void*)&response);
- }
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for STAT
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-stat_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.stat != NULL)
- {
- uint16_t keylen= ntohs(header->request.keylen);
-
- rval= client->root->callback->interface.v1.stat(cookie,
- (void*)(header + 1),
- keylen,
- stat_response_handler);
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * Callback for VERSION
- * @param cookie the calling client
- * @param header the command
- * @param response_handler not used
- * @return the result of the operation
- */
-static protocol_binary_response_status
-version_command_handler(const void *cookie,
- protocol_binary_request_header *header,
- memcached_binary_protocol_raw_response_handler response_handler)
-{
- (void)response_handler;
- (void)header;
- protocol_binary_response_status rval;
-
- memcached_protocol_client_st *client= (void*)cookie;
- if (client->root->callback->interface.v1.version != NULL)
- {
- rval= client->root->callback->interface.v1.version(cookie,
- version_response_handler);
- }
- else
- {
- rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- }
-
- return rval;
-}
-
-/**
- * The map to remap between the com codes and the v1 logical setting
- */
-static memcached_binary_protocol_command_handler comcode_v0_v1_remap[256]= {
- [PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler,
- [PROTOCOL_BINARY_CMD_ADD]= add_command_handler,
- [PROTOCOL_BINARY_CMD_APPENDQ]= append_command_handler,
- [PROTOCOL_BINARY_CMD_APPEND]= append_command_handler,
- [PROTOCOL_BINARY_CMD_DECREMENTQ]= decrement_command_handler,
- [PROTOCOL_BINARY_CMD_DECREMENT]= decrement_command_handler,
- [PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler,
- [PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler,
- [PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler,
- [PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler,
- [PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler,
- [PROTOCOL_BINARY_CMD_GETK]= get_command_handler,
- [PROTOCOL_BINARY_CMD_GETQ]= get_command_handler,
- [PROTOCOL_BINARY_CMD_GET]= get_command_handler,
- [PROTOCOL_BINARY_CMD_INCREMENTQ]= increment_command_handler,
- [PROTOCOL_BINARY_CMD_INCREMENT]= increment_command_handler,
- [PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler,
- [PROTOCOL_BINARY_CMD_PREPENDQ]= prepend_command_handler,
- [PROTOCOL_BINARY_CMD_PREPEND]= prepend_command_handler,
- [PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler,
- [PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler,
- [PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler,
- [PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler,
- [PROTOCOL_BINARY_CMD_SETQ]= set_command_handler,
- [PROTOCOL_BINARY_CMD_SET]= set_command_handler,
- [PROTOCOL_BINARY_CMD_STAT]= stat_command_handler,
- [PROTOCOL_BINARY_CMD_VERSION]= version_command_handler,
-};
-
-/**
- * Try to execute a command. Fire the pre/post functions and the specialized
- * handler function if it's set. If not, the unknown probe should be fired
- * if it's present.
- * @param client the client connection to operate on
- * @param header the command to execute
- * @return true if success or false if a fatal error occured so that the
- * connection should be shut down.
- */
-static protocol_binary_response_status execute_command(memcached_protocol_client_st *client, protocol_binary_request_header *header)
-{
- if (client->root->pedantic &&
- memcached_binary_protocol_pedantic_check_request(header))
- {
- /* @todo return invalid command packet */
- }
-
- /* we got all data available, execute the callback! */
- if (client->root->callback->pre_execute != NULL)
- {
- client->root->callback->pre_execute(client, header);
- }
-
- protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
- uint8_t cc= header->request.opcode;
-
- if (client->is_verbose)
- {
- print_cmd(cc);
- }
-
- switch (client->root->callback->interface_version)
- {
- case 0:
- if (client->root->callback->interface.v0.comcode[cc] != NULL)
- {
- rval= client->root->callback->interface.v0.comcode[cc](client, header, raw_response_handler);
- }
- break;
-
- case 1:
- if (comcode_v0_v1_remap[cc] != NULL)
- {
- rval= comcode_v0_v1_remap[cc](client, header, raw_response_handler);
- }
- break;
-
- default:
- /* Unknown interface.
- * It should be impossible to get here so I'll just call abort
- * to avoid getting a compiler warning :-)
- */
- abort();
- }
-
-
- if (rval == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND &&
- client->root->callback->unknown != NULL)
- {
- rval= client->root->callback->unknown(client, header, raw_response_handler);
- }
-
- if (rval != PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- rval != PROTOCOL_BINARY_RESPONSE_EINTERNAL &&
- rval != PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED)
- {
- protocol_binary_response_no_extras response= {
- .message= {
- .header.response= {
- .magic= PROTOCOL_BINARY_RES,
- .opcode= cc,
- .status= htons(rval),
- .opaque= header->request.opaque,
- },
- }
- };
- rval= raw_response_handler(client, header, (void*)&response);
- }
-
- if (client->root->callback->post_execute != NULL)
- {
- client->root->callback->post_execute(client, header);
- }
-
- return rval;
-}
-
-/*
-** **********************************************************************
-** "PROTOECTED" INTERFACE
-** **********************************************************************
-*/
-memcached_protocol_event_t memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr)
-{
- /* try to parse all of the received packets */
- protocol_binary_request_header *header;
- header= (void*)client->root->input_buffer;
- if (header->request.magic != (uint8_t)PROTOCOL_BINARY_REQ)
- {
- client->error= EINVAL;
- return MEMCACHED_PROTOCOL_ERROR_EVENT;
- }
- ssize_t len= *length;
-
- while (len >= (ssize_t)sizeof(*header) &&
- (len >= (ssize_t)(sizeof(*header) + ntohl(header->request.bodylen))))
- {
- /* I have the complete package */
- client->current_command= header;
- protocol_binary_response_status rv= execute_command(client, header);
-
- if (rv == PROTOCOL_BINARY_RESPONSE_EINTERNAL)
- {
- *length= len;
- *endptr= (void*)header;
- return MEMCACHED_PROTOCOL_ERROR_EVENT;
- }
- else if (rv == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED)
- {
- return MEMCACHED_PROTOCOL_PAUSE_EVENT;
- }
-
- ssize_t total= (ssize_t)(sizeof(*header) + ntohl(header->request.bodylen));
- len -= total;
- if (len > 0)
- {
- intptr_t ptr= (intptr_t)header;
- ptr += total;
- if ((ptr % 8) == 0)
- {
- header= (void*)ptr;
- }
- else
- {
- /* Fix alignment */
- memmove(client->root->input_buffer, (void*)ptr, (size_t)len);
- header= (void*)client->root->input_buffer;
- }
- }
- *length= len;
- *endptr= (void*)header;
- }
-
- return MEMCACHED_PROTOCOL_READ_EVENT;
-}
-
-/*
-** **********************************************************************
-** PUBLIC INTERFACE
-** **********************************************************************
-*/
-memcached_binary_protocol_callback_st *memcached_binary_protocol_get_callbacks(memcached_protocol_st *instance)
-{
- return instance->callback;
-}
-
-void memcached_binary_protocol_set_callbacks(memcached_protocol_st *instance, memcached_binary_protocol_callback_st *callback)
-{
- instance->callback= callback;
-}
-
-memcached_binary_protocol_raw_response_handler memcached_binary_protocol_get_raw_response_handler(const void *cookie)
-{
- (void)cookie;
- return raw_response_handler;
-}
-
-void memcached_binary_protocol_set_pedantic(memcached_protocol_st *instance, bool enable)
-{
- instance->pedantic= enable;
-}
-
-bool memcached_binary_protocol_get_pedantic(memcached_protocol_st *instance)
-{
- return instance->pedantic;
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-LIBMEMCACHED_LOCAL
-bool memcached_binary_protocol_pedantic_check_request(const protocol_binary_request_header *request);
-
-LIBMEMCACHED_LOCAL
-bool memcached_binary_protocol_pedantic_check_response(const protocol_binary_request_header *request,
- const protocol_binary_response_header *response);
-
-LIBMEMCACHED_LOCAL
-memcached_protocol_event_t memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr);
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-#include "mem_config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-
-#ifndef NDEBUG
-#include <signal.h>
-#endif
-
-#include <libmemcachedprotocol/common.h>
-
-#ifndef NDEBUG
-const uint64_t redzone_pattern = 0xdeadbeefcafebabe;
-int cache_error = 0;
-#endif
-
-const size_t initial_pool_size = 64;
-
-cache_t* cache_create(const char *name, size_t bufsize, size_t align,
- cache_constructor_t* constructor,
- cache_destructor_t* destructor) {
- cache_t* ret = calloc(1, sizeof(cache_t));
- size_t name_length= strlen(name);
- char* nm= calloc(1, (sizeof(char) * name_length) +1);
- memcpy(nm, name, name_length);
- void** ptr = calloc(initial_pool_size, bufsize);
- if (ret == NULL || nm == NULL || ptr == NULL ||
- pthread_mutex_init(&ret->mutex, NULL) == -1) {
- free(ret);
- free(nm);
- free(ptr);
- return NULL;
- }
-
- ret->name = nm;
- ret->ptr = ptr;
- ret->freetotal = initial_pool_size;
- ret->constructor = constructor;
- ret->destructor = destructor;
-
-#ifndef NDEBUG
- ret->bufsize = bufsize + 2 * sizeof(redzone_pattern);
-#else
- ret->bufsize = bufsize;
-#endif
-
- (void)align;
-
- return ret;
-}
-
-static inline void* get_object(void *ptr) {
-#ifndef NDEBUG
- uint64_t *pre = ptr;
- return pre + 1;
-#else
- return ptr;
-#endif
-}
-
-void cache_destroy(cache_t *cache) {
- while (cache->freecurr > 0) {
- void *ptr = cache->ptr[--cache->freecurr];
- if (cache->destructor) {
- cache->destructor(get_object(ptr), NULL);
- }
- free(ptr);
- }
- free(cache->name);
- free(cache->ptr);
- pthread_mutex_destroy(&cache->mutex);
-}
-
-void* cache_alloc(cache_t *cache) {
- void *ret;
- void *object;
- pthread_mutex_lock(&cache->mutex);
- if (cache->freecurr > 0) {
- ret = cache->ptr[--cache->freecurr];
- object = get_object(ret);
- } else {
- object = ret = malloc(cache->bufsize);
- if (ret != NULL) {
- object = get_object(ret);
-
- if (cache->constructor != NULL &&
- cache->constructor(object, NULL, 0) != 0) {
- free(ret);
- object = NULL;
- }
- }
- }
- pthread_mutex_unlock(&cache->mutex);
-
-#ifndef NDEBUG
- if (object != NULL) {
- /* add a simple form of buffer-check */
- uint64_t *pre = ret;
- *pre = redzone_pattern;
- ret = pre+1;
- memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)),
- &redzone_pattern, sizeof(redzone_pattern));
- }
-#endif
-
- return object;
-}
-
-void cache_free(cache_t *cache, void *ptr) {
- pthread_mutex_lock(&cache->mutex);
-
-#ifndef NDEBUG
- /* validate redzone... */
- if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)),
- &redzone_pattern, sizeof(redzone_pattern)) != 0) {
- raise(SIGABRT);
- cache_error = 1;
- pthread_mutex_unlock(&cache->mutex);
- return;
- }
- uint64_t *pre = ptr;
- --pre;
- if (*pre != redzone_pattern) {
- raise(SIGABRT);
- cache_error = -1;
- pthread_mutex_unlock(&cache->mutex);
- return;
- }
- ptr = pre;
-#endif
- if (cache->freecurr < cache->freetotal) {
- cache->ptr[cache->freecurr++] = ptr;
- } else {
- /* try to enlarge free connections array */
- size_t newtotal = cache->freetotal * 2;
- void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal);
- if (new_free) {
- cache->freetotal = newtotal;
- cache->ptr = new_free;
- cache->ptr[cache->freecurr++] = ptr;
- } else {
- if (cache->destructor) {
- cache->destructor(ptr, NULL);
- }
- free(ptr);
-
- }
- }
- pthread_mutex_unlock(&cache->mutex);
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-#pragma once
-
-#include <pthread.h>
-
-#ifdef HAVE_UMEM_H
-# include <umem.h>
-# define cache_t umem_cache_t
-# define cache_alloc(a) umem_cache_alloc(a, UMEM_DEFAULT)
-# define cache_free(a, b) umem_cache_free(a, b)
-# define cache_create(a,b,c,d,e) umem_cache_create((char*)a, b, c, d, e, NULL, NULL, NULL, 0)
-# define cache_destroy(a) umem_cache_destroy(a);
-#else
-# ifndef NDEBUG
-/* may be used for debug purposes */
-extern int cache_error;
-# endif
-
-/**
- * Constructor used to initialize allocated objects
- *
- * @param obj pointer to the object to initialized.
- * @param notused1 This parameter is currently not used.
- * @param notused2 This parameter is currently not used.
- * @return you should return 0, but currently this is not checked
- */
-typedef int cache_constructor_t(void* obj, void* notused1, int notused2);
-/**
- * Destructor used to clean up allocated objects before they are
- * returned to the operating system.
- *
- * @param obj pointer to the object to initialized.
- * @param notused1 This parameter is currently not used.
- * @param notused2 This parameter is currently not used.
- * @return you should return 0, but currently this is not checked
- */
-typedef void cache_destructor_t(void* obj, void* notused);
-
-/**
- * Definition of the structure to keep track of the internal details of
- * the cache allocator. Touching any of these variables results in
- * undefined behavior.
- */
-typedef struct {
- /** Mutex to protect access to the structure */
- pthread_mutex_t mutex;
- /** Name of the cache objects in this cache (provided by the caller) */
- char *name;
- /** List of pointers to available buffers in this cache */
- void **ptr;
- /** The size of each element in this cache */
- size_t bufsize;
- /** The capacity of the list of elements */
- size_t freetotal;
- /** The current number of free elements */
- size_t freecurr;
- /** The constructor to be called each time we allocate more memory */
- cache_constructor_t* constructor;
- /** The destructor to be called each time before we release memory */
- cache_destructor_t* destructor;
-} cache_t;
-
-/**
- * Create an object cache.
- *
- * The object cache will let you allocate objects of the same size. It is fully
- * MT safe, so you may allocate objects from multiple threads without having to
- * do any syncrhonization in the application code.
- *
- * @param name the name of the object cache. This name may be used for debug purposes
- * and may help you track down what kind of object you have problems with
- * (buffer overruns, leakage etc)
- * @param bufsize the size of each object in the cache
- * @param align the alignment requirements of the objects in the cache.
- * @param constructor the function to be called to initialize memory when we need
- * to allocate more memory from the os.
- * @param destructor the function to be called before we release the memory back
- * to the os.
- * @return a handle to an object cache if successful, NULL otherwise.
- */
-cache_t* cache_create(const char* name, size_t bufsize, size_t align,
- cache_constructor_t* constructor,
- cache_destructor_t* destructor);
-/**
- * Destroy an object cache.
- *
- * Destroy and invalidate an object cache. You should return all buffers allocated
- * with cache_alloc by using cache_free before calling this function. Not doing
- * so results in undefined behavior (the buffers may or may not be invalidated)
- *
- * @param handle the handle to the object cache to destroy.
- */
-void cache_destroy(cache_t* handle);
-/**
- * Allocate an object from the cache.
- *
- * @param handle the handle to the object cache to allocate from
- * @return a pointer to an initialized object from the cache, or NULL if
- * the allocation cannot be satisfied.
- */
-void* cache_alloc(cache_t* handle);
-/**
- * Return an object back to the cache.
- *
- * The caller should return the object in an initialized state so that
- * the object may be returned in an expected state from cache_alloc.
- *
- * @param handle handle to the object cache to return the object to
- * @param ptr pointer to the object to return.
- */
-void cache_free(cache_t* handle, void* ptr);
-#endif // HAVE_UMEM_H
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include "mem_config.h"
-#include <assert.h>
-
-#include <libmemcachedprotocol-0.0/handler.h>
-#include <libmemcachedprotocol/cache.h>
-#include <libmemcached/byteorder.h>
-#include <libmemcached/socket.hpp>
-
-/*
- * I don't really need the following two functions as function pointers
- * in the instance handle, but I don't want to put them in the global
- * namespace for those linking statically (personally I don't like that,
- * but some people still do). If it ever shows up as a performance thing
- * I'll look into optimizing this ;-)
- */
-typedef bool (*drain_func)(memcached_protocol_client_st *client);
-typedef protocol_binary_response_status (*spool_func)(memcached_protocol_client_st *client,
- const void *data,
- size_t length);
-
-/**
- * Definition of the per instance structure.
- */
-struct memcached_protocol_st {
- memcached_binary_protocol_callback_st *callback;
- memcached_protocol_recv_func recv;
- memcached_protocol_send_func send;
-
- /*
- * I really don't need these as funciton pointers, but I don't want
- * to clutter the namespace if someone links statically.
- */
- drain_func drain;
- spool_func spool;
-
- /*
- * To avoid keeping a buffer in each client all the time I have a
- * bigger buffer in the instance that I read to initially, and then
- * I try to parse and execute as much from the buffer. If I wasn't able
- * to process all data I'll keep that in a per-connection buffer until
- * the next time I can read from the socket.
- */
- uint8_t *input_buffer;
- size_t input_buffer_size;
-
- bool pedantic;
- /* @todo use multiple sized buffers */
- cache_t *buffer_cache;
-};
-
-struct chunk_st {
- /* Pointer to the data */
- char *data;
- /* The offset to the first byte into the buffer that is used */
- size_t offset;
- /* The offset into the buffer for the first free byte */
- size_t nbytes;
- /* The number of bytes in the buffer */
- size_t size;
- /* Pointer to the next buffer in the chain */
- struct chunk_st *next;
-};
-
-#define CHUNK_BUFFERSIZE 2048
-
-typedef memcached_protocol_event_t (*process_data)(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr);
-
-enum ascii_cmd {
- GET_CMD,
- GETS_CMD,
- SET_CMD,
- ADD_CMD,
- REPLACE_CMD,
- CAS_CMD,
- APPEND_CMD,
- PREPEND_CMD,
- DELETE_CMD,
- INCR_CMD,
- DECR_CMD,
- STATS_CMD,
- FLUSH_ALL_CMD,
- VERSION_CMD,
- QUIT_CMD,
- VERBOSITY_CMD,
- UNKNOWN_CMD
-};
-
-struct memcached_protocol_client_st {
- bool is_verbose;
- memcached_protocol_st *root;
- memcached_socket_t sock;
- int error;
-
- /* Linked list of data to send */
- struct chunk_st *output;
- struct chunk_st *output_tail;
-
- /*
- * While we process input data, this is where we spool incomplete commands
- * if we need to receive more data....
- * @todo use the buffercace
- */
- uint8_t *input_buffer;
- size_t input_buffer_size;
- size_t input_buffer_offset;
-
- /* The callback to the protocol handler to use (ascii or binary) */
- process_data work;
-
- /*
- * Should the spool data discard the data to send or not? (aka noreply in
- * the ascii protocol..
- */
- bool mute;
-
- /* Members used by the binary protocol */
- protocol_binary_request_header *current_command;
-
- /* Members used by the ascii protocol */
- enum ascii_cmd ascii_command;
-};
-
-#include "ascii_handler.h"
-#include "binary_handler.h"
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include <libmemcachedprotocol/common.h>
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <string.h>
-#include <strings.h>
-#include <ctype.h>
-#include <stdio.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-
-/*
-** **********************************************************************
-** INTERNAL INTERFACE
-** **********************************************************************
-*/
-
-/**
- * The default function to receive data from the client. This function
- * just wraps the recv function to receive from a socket.
- * See man -s3socket recv for more information.
- *
- * @param cookie cookie indentifying a client, not used
- * @param sock socket to read from
- * @param buf the destination buffer
- * @param nbytes the number of bytes to read
- * @return the number of bytes transferred of -1 upon error
- */
-static ssize_t default_recv(const void *cookie,
- memcached_socket_t sock,
- void *buf,
- size_t nbytes)
-{
- (void)cookie;
- return recv(sock, buf, nbytes, 0);
-}
-
-/**
- * The default function to send data to the server. This function
- * just wraps the send function to send through a socket.
- * See man -s3socket send for more information.
- *
- * @param cookie cookie indentifying a client, not used
- * @param sock socket to send to
- * @param buf the source buffer
- * @param nbytes the number of bytes to send
- * @return the number of bytes transferred of -1 upon error
- */
-static ssize_t default_send(const void *cookie,
- memcached_socket_t fd,
- const void *buf,
- size_t nbytes)
-{
- (void)cookie;
- return send(fd, buf, nbytes, MSG_NOSIGNAL);
-}
-
-/**
- * Try to drain the output buffers without blocking
- *
- * @param client the client to drain
- * @return false if an error occured (connection should be shut down)
- * true otherwise (please note that there may be more data to
- * left in the buffer to send)
- */
-static bool drain_output(struct memcached_protocol_client_st *client)
-{
- if (client->is_verbose)
- {
- fprintf(stderr, "%s:%d %s mute:%d output:%s length:%d\n", __FILE__, __LINE__, __func__, (int)client->mute,
- client->output ? "yes" : "no",
- client->output ? (int)(client->output->nbytes - client->output->offset) : 0);
- }
-
- /* Do we have pending data to send? */
- while (client->output != NULL)
- {
- ssize_t len= client->root->send(client,
- client->sock,
- client->output->data + client->output->offset,
- client->output->nbytes - client->output->offset);
-
- if (len == -1)
- {
- if (get_socket_errno() == EWOULDBLOCK)
- {
- return true;
- }
- else if (get_socket_errno() != EINTR)
- {
- client->error= get_socket_errno();
- return false;
- }
- }
- else
- {
- client->output->offset += (size_t)len;
- if (client->output->offset == client->output->nbytes)
- {
- /* This was the complete buffer */
- struct chunk_st *old= client->output;
- client->output= client->output->next;
- if (client->output == NULL)
- {
- client->output_tail= NULL;
- }
- cache_free(client->root->buffer_cache, old);
- }
- }
- }
-
- return true;
-}
-
-/**
- * Allocate an output buffer and chain it into the output list
- *
- * @param client the client that needs the buffer
- * @return pointer to the new chunk if the allocation succeeds, NULL otherwise
- */
-static struct chunk_st *allocate_output_chunk(struct memcached_protocol_client_st *client)
-{
- struct chunk_st *ret= cache_alloc(client->root->buffer_cache);
-
- if (ret == NULL)
- {
- return NULL;
- }
-
- ret->offset= ret->nbytes= 0;
- ret->next= NULL;
- ret->size= CHUNK_BUFFERSIZE;
- ret->data= (void*)(ret + 1);
- if (client->output == NULL)
- {
- client->output= client->output_tail= ret;
- }
- else
- {
- client->output_tail->next= ret;
- client->output_tail= ret;
- }
-
- return ret;
-}
-
-/**
- * Spool data into the send-buffer for a client.
- *
- * @param client the client to spool the data for
- * @param data the data to spool
- * @param length the number of bytes of data to spool
- * @return PROTOCOL_BINARY_RESPONSE_SUCCESS if success,
- * PROTOCOL_BINARY_RESPONSE_ENOMEM if we failed to allocate memory
- */
-static protocol_binary_response_status spool_output(struct memcached_protocol_client_st *client,
- const void *data,
- size_t length)
-{
- if (client->is_verbose)
- {
- fprintf(stderr, "%s:%d %s mute:%d length:%d\n", __FILE__, __LINE__, __func__, (int)client->mute, (int)length);
- }
-
- if (client->mute)
- {
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
- }
-
- size_t offset= 0;
-
- struct chunk_st *chunk= client->output;
- while (offset < length)
- {
- if (chunk == NULL || (chunk->size - chunk->nbytes) == 0)
- {
- if ((chunk= allocate_output_chunk(client)) == NULL)
- {
- return PROTOCOL_BINARY_RESPONSE_ENOMEM;
- }
- }
-
- size_t bulk= length - offset;
- if (bulk > chunk->size - chunk->nbytes)
- {
- bulk= chunk->size - chunk->nbytes;
- }
-
- memcpy(chunk->data + chunk->nbytes, data, bulk);
- chunk->nbytes += bulk;
- offset += bulk;
- }
-
- return PROTOCOL_BINARY_RESPONSE_SUCCESS;
-}
-
-/**
- * Try to determine the protocol used on this connection.
- * If the first byte contains the magic byte PROTOCOL_BINARY_REQ we should
- * be using the binary protocol on the connection. I implemented the support
- * for the ASCII protocol by wrapping into the simple interface (aka v1),
- * so the implementors needs to provide an implementation of that interface
- *
- */
-static memcached_protocol_event_t determine_protocol(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr)
-{
- if (*client->root->input_buffer == (uint8_t)PROTOCOL_BINARY_REQ)
- {
- if (client->is_verbose)
- {
- fprintf(stderr, "%s:%d PROTOCOL: memcached_binary_protocol_process_data\n", __FILE__, __LINE__);
- }
- client->work= memcached_binary_protocol_process_data;
- }
- else if (client->root->callback->interface_version == 1)
- {
- if (client->is_verbose)
- {
- fprintf(stderr, "%s:%d PROTOCOL: memcached_ascii_protocol_process_data\n", __FILE__, __LINE__);
- }
-
- /*
- * The ASCII protocol can only be used if the implementors provide
- * an implementation for the version 1 of the interface..
- *
- * @todo I should allow the implementors to provide an implementation
- * for version 0 and 1 at the same time and set the preferred
- * interface to use...
- */
- client->work= memcached_ascii_protocol_process_data;
- }
- else
- {
- if (client->is_verbose)
- {
- fprintf(stderr, "%s:%d PROTOCOL: Unsupported protocol\n", __FILE__, __LINE__);
- }
-
- /* Let's just output a warning the way it is supposed to look like
- * in the ASCII protocol...
- */
- const char *err= "CLIENT_ERROR: Unsupported protocol\r\n";
- client->root->spool(client, err, strlen(err));
- client->root->drain(client);
-
- return MEMCACHED_PROTOCOL_ERROR_EVENT; /* Unsupported protocol */
- }
-
- return client->work(client, length, endptr);
-}
-
-/*
-** **********************************************************************
-** * PUBLIC INTERFACE
-** * See protocol_handler.h for function description
-** **********************************************************************
-*/
-struct memcached_protocol_st *memcached_protocol_create_instance(void)
-{
- struct memcached_protocol_st *ret= calloc(1, sizeof(*ret));
- if (ret != NULL)
- {
- ret->recv= default_recv;
- ret->send= default_send;
- ret->drain= drain_output;
- ret->spool= spool_output;
- ret->input_buffer_size= 1 * 1024 * 1024;
- ret->input_buffer= malloc(ret->input_buffer_size);
- if (ret->input_buffer == NULL)
- {
- free(ret);
- ret= NULL;
-
- return NULL;
- }
-
- ret->buffer_cache= cache_create("protocol_handler",
- CHUNK_BUFFERSIZE + sizeof(struct chunk_st),
- 0, NULL, NULL);
- if (ret->buffer_cache == NULL)
- {
- free(ret->input_buffer);
- free(ret);
- ret= NULL;
- }
- }
-
- return ret;
-}
-
-void memcached_protocol_destroy_instance(struct memcached_protocol_st *instance)
-{
- cache_destroy(instance->buffer_cache);
- free(instance->input_buffer);
- free(instance);
-}
-
-struct memcached_protocol_client_st *memcached_protocol_create_client(struct memcached_protocol_st *instance, memcached_socket_t sock)
-{
- struct memcached_protocol_client_st *ret= calloc(1, sizeof(memcached_protocol_client_st));
- if (ret != NULL)
- {
- ret->root= instance;
- ret->sock= sock;
- ret->work= determine_protocol;
- }
-
- return ret;
-}
-
-void memcached_protocol_client_destroy(struct memcached_protocol_client_st *client)
-{
- free(client);
-}
-
-void memcached_protocol_client_set_verbose(struct memcached_protocol_client_st *client, bool arg)
-{
- if (client)
- {
- client->is_verbose= arg;
- }
-}
-
-memcached_protocol_event_t memcached_protocol_client_work(struct memcached_protocol_client_st *client)
-{
- /* Try to send data and read from the socket */
- bool more_data= true;
- do
- {
- ssize_t len= client->root->recv(client,
- client->sock,
- client->root->input_buffer + client->input_buffer_offset,
- client->root->input_buffer_size - client->input_buffer_offset);
-
- if (len > 0)
- {
- /* Do we have the complete packet? */
- if (client->input_buffer_offset > 0)
- {
- memcpy(client->root->input_buffer, client->input_buffer,
- client->input_buffer_offset);
- len += (ssize_t)client->input_buffer_offset;
-
- /* @todo use buffer-cache! */
- free(client->input_buffer);
- client->input_buffer_offset= 0;
- }
-
- void *endptr;
- memcached_protocol_event_t events= client->work(client, &len, &endptr);
- if (events == MEMCACHED_PROTOCOL_ERROR_EVENT)
- {
- return MEMCACHED_PROTOCOL_ERROR_EVENT;
- }
-
- if (len > 0)
- {
- /* save the data for later on */
- /* @todo use buffer-cache */
- client->input_buffer= malloc((size_t)len);
- if (client->input_buffer == NULL)
- {
- client->error= ENOMEM;
- return MEMCACHED_PROTOCOL_ERROR_EVENT;
- }
- memcpy(client->input_buffer, endptr, (size_t)len);
- client->input_buffer_offset= (size_t)len;
- more_data= false;
- }
- }
- else if (len == 0)
- {
- /* Connection closed */
- drain_output(client);
- return MEMCACHED_PROTOCOL_ERROR_EVENT;
- }
- else
- {
- if (get_socket_errno() != EWOULDBLOCK)
- {
- client->error= get_socket_errno();
- /* mark this client as terminated! */
- return MEMCACHED_PROTOCOL_ERROR_EVENT;
- }
- more_data= false;
- }
- } while (more_data);
-
- if (!drain_output(client))
- {
- return MEMCACHED_PROTOCOL_ERROR_EVENT;
- }
-
- memcached_protocol_event_t ret= MEMCACHED_PROTOCOL_READ_EVENT;
- if (client->output)
- {
- ret|= MEMCACHED_PROTOCOL_READ_EVENT;
- }
-
- return ret;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include <libmemcachedprotocol/common.h>
-
-#include <sys/types.h>
-
-#define ensure(a) if (!(a)) { return false; }
-
-bool memcached_binary_protocol_pedantic_check_request(const protocol_binary_request_header *request)
-{
- ensure(request->request.magic == PROTOCOL_BINARY_REQ);
- ensure(request->request.datatype == PROTOCOL_BINARY_RAW_BYTES);
-
- ensure(request->bytes[6] == 0);
- ensure(request->bytes[7] == 0);
-
- uint8_t opcode= request->request.opcode;
- uint16_t keylen= ntohs(request->request.keylen);
- uint8_t extlen= request->request.extlen;
- uint32_t bodylen= ntohl(request->request.bodylen);
-
- ensure(bodylen >= (keylen + extlen));
-
- switch (opcode) {
- case PROTOCOL_BINARY_CMD_GET:
- case PROTOCOL_BINARY_CMD_GETK:
- case PROTOCOL_BINARY_CMD_GETKQ:
- case PROTOCOL_BINARY_CMD_GETQ:
- ensure(extlen == 0);
- ensure(keylen > 0);
- ensure(keylen == bodylen);
- ensure(request->request.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_ADD:
- case PROTOCOL_BINARY_CMD_ADDQ:
- /* it makes no sense to run add with a cas value */
- ensure(request->request.cas == 0);
- /* FALLTHROUGH */
- case PROTOCOL_BINARY_CMD_SET:
- case PROTOCOL_BINARY_CMD_SETQ:
- case PROTOCOL_BINARY_CMD_REPLACE:
- case PROTOCOL_BINARY_CMD_REPLACEQ:
- ensure(keylen > 0);
- ensure(extlen == 8);
- break;
-
- case PROTOCOL_BINARY_CMD_DELETE:
- case PROTOCOL_BINARY_CMD_DELETEQ:
- ensure(extlen == 0);
- ensure(keylen > 0);
- ensure(keylen == bodylen);
- break;
-
- case PROTOCOL_BINARY_CMD_INCREMENT:
- case PROTOCOL_BINARY_CMD_INCREMENTQ:
- case PROTOCOL_BINARY_CMD_DECREMENT:
- case PROTOCOL_BINARY_CMD_DECREMENTQ:
- ensure(extlen == 20);
- ensure(keylen > 0);
- ensure(keylen + extlen == bodylen);
- break;
-
- case PROTOCOL_BINARY_CMD_QUIT:
- case PROTOCOL_BINARY_CMD_QUITQ:
- case PROTOCOL_BINARY_CMD_NOOP:
- case PROTOCOL_BINARY_CMD_VERSION:
- ensure(extlen == 0);
- ensure(keylen == 0);
- ensure(bodylen == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_FLUSH:
- case PROTOCOL_BINARY_CMD_FLUSHQ:
- ensure(extlen == 0 || extlen == 4);
- ensure(keylen == 0);
- ensure(bodylen == extlen);
- break;
-
- case PROTOCOL_BINARY_CMD_STAT:
- ensure(extlen == 0);
- /* May have key, but not value */
- ensure(keylen == bodylen);
- break;
-
- case PROTOCOL_BINARY_CMD_APPEND:
- case PROTOCOL_BINARY_CMD_APPENDQ:
- case PROTOCOL_BINARY_CMD_PREPEND:
- case PROTOCOL_BINARY_CMD_PREPENDQ:
- ensure(extlen == 0);
- ensure(keylen > 0);
- break;
- default:
- /* Unknown command */
- ;
- }
-
- return true;
-}
-
-bool memcached_binary_protocol_pedantic_check_response(const protocol_binary_request_header *request,
- const protocol_binary_response_header *response)
-{
- ensure(response->response.magic == PROTOCOL_BINARY_RES);
- ensure(response->response.datatype == PROTOCOL_BINARY_RAW_BYTES);
- ensure(response->response.opaque == request->request.opaque);
-
- uint16_t status= ntohs(response->response.status);
- uint8_t opcode= response->response.opcode;
-
- if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS)
- {
- switch (opcode) {
- case PROTOCOL_BINARY_CMD_ADDQ:
- case PROTOCOL_BINARY_CMD_APPENDQ:
- case PROTOCOL_BINARY_CMD_DECREMENTQ:
- case PROTOCOL_BINARY_CMD_DELETEQ:
- case PROTOCOL_BINARY_CMD_FLUSHQ:
- case PROTOCOL_BINARY_CMD_INCREMENTQ:
- case PROTOCOL_BINARY_CMD_PREPENDQ:
- case PROTOCOL_BINARY_CMD_QUITQ:
- case PROTOCOL_BINARY_CMD_REPLACEQ:
- case PROTOCOL_BINARY_CMD_SETQ:
- /* Quiet command shouldn't return on success */
- return false;
- default:
- break;
- }
-
- switch (opcode) {
- case PROTOCOL_BINARY_CMD_ADD:
- case PROTOCOL_BINARY_CMD_REPLACE:
- case PROTOCOL_BINARY_CMD_SET:
- case PROTOCOL_BINARY_CMD_APPEND:
- case PROTOCOL_BINARY_CMD_PREPEND:
- ensure(response->response.keylen == 0);
- ensure(response->response.extlen == 0);
- ensure(response->response.bodylen == 0);
- ensure(response->response.cas != 0);
- break;
- case PROTOCOL_BINARY_CMD_FLUSH:
- case PROTOCOL_BINARY_CMD_NOOP:
- case PROTOCOL_BINARY_CMD_QUIT:
- case PROTOCOL_BINARY_CMD_DELETE:
- ensure(response->response.keylen == 0);
- ensure(response->response.extlen == 0);
- ensure(response->response.bodylen == 0);
- ensure(response->response.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_DECREMENT:
- case PROTOCOL_BINARY_CMD_INCREMENT:
- ensure(response->response.keylen == 0);
- ensure(response->response.extlen == 0);
- ensure(ntohl(response->response.bodylen) == 8);
- ensure(response->response.cas != 0);
- break;
-
- case PROTOCOL_BINARY_CMD_STAT:
- ensure(response->response.extlen == 0);
- /* key and value exists in all packets except in the terminating */
- ensure(response->response.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_VERSION:
- ensure(response->response.keylen == 0);
- ensure(response->response.extlen == 0);
- ensure(response->response.bodylen != 0);
- ensure(response->response.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_GET:
- case PROTOCOL_BINARY_CMD_GETQ:
- ensure(response->response.keylen == 0);
- ensure(response->response.extlen == 4);
- ensure(response->response.cas != 0);
- break;
-
- case PROTOCOL_BINARY_CMD_GETK:
- case PROTOCOL_BINARY_CMD_GETKQ:
- ensure(response->response.keylen != 0);
- ensure(response->response.extlen == 4);
- ensure(response->response.cas != 0);
- break;
-
- default:
- /* Undefined command code */
- break;
- }
- }
- else
- {
- ensure(response->response.cas == 0);
- ensure(response->response.extlen == 0);
- if (opcode != PROTOCOL_BINARY_CMD_GETK)
- {
- ensure(response->response.keylen == 0);
- }
- }
-
- return true;
-}
+++ /dev/null
-
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
- FILES_MATCHING REGEX "\\.h(pp)?$"
- )
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-bool libmemcached_util_flush(const char *hostname, in_port_t port, memcached_return_t *ret);
-
-#ifdef __cplusplus
-}
-#endif
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-static inline std::ostream& operator<<(std::ostream& output, const enum memcached_return_t &arg)
-{
- output << memcached_strerror(NULL, arg);
- return output;
-}
-
-static inline std::ostream& operator<<(std::ostream& output, const memcached_st &arg)
-{
- output << " query_id: " << memcached_query_id(&arg);
- output << " error: " << memcached_last_error_message(&arg);
- return output;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifndef _WIN32
-# include <netdb.h>
-#endif
-
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-pid_t libmemcached_util_getpid(const char *hostname, in_port_t port, memcached_return_t *ret);
-
-LIBMEMCACHED_API
-pid_t libmemcached_util_getpid2(const char *hostname, in_port_t port, const char *username, const char *password, memcached_return_t *ret);
-
-#ifdef __cplusplus
-}
-#endif
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret);
-
-LIBMEMCACHED_API
-bool libmemcached_util_ping2(const char *hostname, in_port_t port, const char *username, const char *password, memcached_return_t *ret);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-#include <libmemcached-1.0/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_pool_st *memcached_pool(const char *option_string, size_t option_string_length);
-
-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_release(memcached_pool_st* pool, memcached_st* mmc);
-
-LIBMEMCACHED_API
-memcached_st* memcached_pool_fetch(memcached_pool_st*, struct timespec* relative_time, memcached_return_t* rc);
-
-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
-} // extern "C"
-#endif
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libmemcached-1.0/memcached.h>
-
-#include <libmemcachedutil-1.0/pid.h>
-#include <libmemcachedutil-1.0/flush.h>
-#include <libmemcachedutil-1.0/ping.h>
-#include <libmemcachedutil-1.0/pool.h>
-#include <libmemcachedutil-1.0/version.h>
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
- bool libmemcached_util_version_check(memcached_st *memc,
- uint8_t major_version,
- uint8_t minor_version,
- uint8_t micro_version);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-
-add_library(libmemcachedutil SHARED
- ../libmemcached/backtrace.cc
- flush.cc
- pid.cc
- ping.cc
- pool.cc
- version.cc
- )
-add_library(memcachedutil ALIAS libmemcachedutil)
-set_target_properties(libmemcachedutil PROPERTIES LIBRARY_OUTPUT_NAME memcachedutil)
-target_include_directories(libmemcachedutil PRIVATE ..)
-target_compile_definitions(libmemcachedutil PRIVATE -DBUILDING_LIBMEMCACHED)
-target_link_libraries(libmemcachedutil libmemcached Threads::Threads)
-
-set_target_properties(libmemcachedutil PROPERTIES SOVERSION ${LIBMEMCACHEDUTIL_SO_VERSION})
-install(TARGETS libmemcachedutil EXPORT libmemcachedutil
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
-export(EXPORT libmemcachedutil)
-install(EXPORT libmemcachedutil DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake)
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached Utility library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Summary: connects to a host, and then flushes it (memcached_flush(3)).
- *
- */
-
-#pragma once
-
-#include "mem_config.h"
-
-#include <cstddef>
-#include <cstdlib>
-#include <cstdio>
-
-#include "libmemcachedutil-1.0/util.h"
-#include "libmemcached/assert.hpp"
-#include "libmemcached/backtrace.hpp"
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Summary: connects to a host, and then flushes it (memcached_flush(3)).
- *
- */
-
-#include <libmemcachedutil/common.h>
-
-
-bool libmemcached_util_flush(const char *hostname, in_port_t port, memcached_return_t *ret)
-{
- memcached_st *memc_ptr= memcached_create(NULL);
-
- memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
- if (memcached_success(rc))
- {
- rc= memcached_flush(memc_ptr, 0);
- }
-
- memcached_free(memc_ptr);
-
- if (ret)
- {
- *ret= rc;
- }
-
- return memcached_success(rc);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Summary: connects to a host, and determines what its pid is
- *
- */
-
-#include <libmemcachedutil/common.h>
-
-
-// Never look at the stat object directly.
-
-
-pid_t libmemcached_util_getpid(const char *hostname, in_port_t port, memcached_return_t *ret)
-{
- pid_t pid= -1;
-
- memcached_return_t unused;
- if (ret == NULL)
- {
- ret= &unused;
- }
-
- memcached_st *memc_ptr= memcached_create(NULL);
- if (memc_ptr == NULL)
- {
- *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return -1;
- }
-
- memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
- if (memcached_success(rc))
- {
- memcached_stat_st *stat= memcached_stat(memc_ptr, NULL, &rc);
- if (memcached_success(rc) and stat and stat->pid != -1)
- {
- pid= stat->pid;
- }
- else if (memcached_success(rc))
- {
- rc= MEMCACHED_UNKNOWN_STAT_KEY; // Something went wrong if this happens
- }
- else if (rc == MEMCACHED_SOME_ERRORS) // Generic answer, we will now find the specific reason (if one exists)
- {
- const memcached_instance_st * instance= memcached_server_instance_by_position(memc_ptr, 0);
-
- assert_msg(instance and memcached_server_error(instance), " ");
- if (instance and memcached_server_error(instance))
- {
- rc= memcached_server_error_return(instance);
- }
- }
-
- memcached_stat_free(memc_ptr, stat);
- }
- memcached_free(memc_ptr);
-
- *ret= rc;
-
- return pid;
-}
-
-pid_t libmemcached_util_getpid2(const char *hostname, in_port_t port, const char *username, const char *password, memcached_return_t *ret)
-{
- if (username == NULL)
- {
- return libmemcached_util_getpid(hostname, port, ret);
- }
-
- pid_t pid= -1;
-
- memcached_return_t unused;
- if (not ret)
- ret= &unused;
-
- if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- *ret= MEMCACHED_NOT_SUPPORTED;
- return pid;
- }
-
- memcached_st *memc_ptr= memcached_create(NULL);
- if (not memc_ptr)
- {
- *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return -1;
- }
-
- if (memcached_failed(*ret= memcached_set_sasl_auth_data(memc_ptr, username, password)))
- {
- memcached_free(memc_ptr);
- return false;
- }
-
-
- memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
- if (memcached_success(rc))
- {
- memcached_stat_st *stat= memcached_stat(memc_ptr, NULL, &rc);
- if (memcached_success(rc) and stat and stat->pid != -1)
- {
- pid= stat->pid;
- }
- else if (memcached_success(rc))
- {
- rc= MEMCACHED_UNKNOWN_STAT_KEY; // Something went wrong if this happens
- }
- else if (rc == MEMCACHED_SOME_ERRORS) // Generic answer, we will now find the specific reason (if one exists)
- {
- const memcached_instance_st * instance=
- memcached_server_instance_by_position(memc_ptr, 0);
-
-#if 0
- assert_msg(instance and instance->error_messages, " ");
-#endif
- if (instance and memcached_server_error(instance))
- {
- rc= memcached_server_error_return(instance);
- }
- }
-
- memcached_stat_free(memc_ptr, stat);
- }
- memcached_free(memc_ptr);
-
- *ret= rc;
-
- return pid;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Summary: connects to a host, and makes sure it is alive.
- *
- */
-
-#include <libmemcachedutil/common.h>
-
-bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret)
-{
- memcached_return_t unused;
- if (ret == NULL)
- {
- ret= &unused;
- }
-
- memcached_st *memc_ptr= memcached_create(NULL);
- if (memc_ptr == NULL)
- {
- *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return false;
- }
-
- if (memcached_success((*ret= memcached_behavior_set(memc_ptr, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, 400000))))
- {
- memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
- if (memcached_success(rc))
- {
- rc= memcached_version(memc_ptr);
- }
-
- if (memcached_failed(rc) and rc == MEMCACHED_SOME_ERRORS)
- {
- const memcached_instance_st * instance=
- memcached_server_instance_by_position(memc_ptr, 0);
-
- assert_msg(instance and memcached_server_error(instance), " ");
- if (instance and memcached_server_error(instance))
- {
- rc= memcached_server_error_return(instance);
- }
- }
-
- *ret= rc;
- }
- memcached_free(memc_ptr);
-
- return memcached_success(*ret);
-}
-
-bool libmemcached_util_ping2(const char *hostname, in_port_t port, const char *username, const char *password, memcached_return_t *ret)
-{
- if (username == NULL)
- {
- return libmemcached_util_ping(hostname, port, ret);
- }
-
- memcached_return_t unused;
- if (not ret)
- ret= &unused;
-
- if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
- {
- *ret= MEMCACHED_NOT_SUPPORTED;
- return false;
- }
-
- memcached_st *memc_ptr= memcached_create(NULL);
- if (not memc_ptr)
- {
- *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return false;
- }
-
- if (memcached_failed(*ret= memcached_set_sasl_auth_data(memc_ptr, username, password)))
- {
- memcached_free(memc_ptr);
- return false;
- }
-
- memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
- if (memcached_success(rc))
- {
- rc= memcached_version(memc_ptr);
- }
-
- if (memcached_failed(rc) and rc == MEMCACHED_SOME_ERRORS)
- {
- const memcached_instance_st * instance=
- memcached_server_instance_by_position(memc_ptr, 0);
-
- assert_msg(instance and memcached_server_error(instance), " ");
- if (instance and memcached_server_error(instance))
- {
- rc= memcached_server_error_return(instance);
- }
- }
- memcached_free(memc_ptr);
-
- *ret= rc;
-
- return memcached_success(rc);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libmemcachedutil/common.h>
-
-#include <cassert>
-#include <cerrno>
-#include <pthread.h>
-#include <memory>
-
-struct memcached_pool_st
-{
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- memcached_st *master;
- memcached_st **server_pool;
- int firstfree;
- const uint32_t size;
- uint32_t current_size;
- bool _owns_master;
- struct timespec _timeout;
-
- memcached_pool_st(memcached_st *master_arg, size_t max_arg) :
- master(master_arg),
- server_pool(NULL),
- firstfree(-1),
- size(uint32_t(max_arg)),
- current_size(0),
- _owns_master(false)
- {
- pthread_mutex_init(&mutex, NULL);
- pthread_cond_init(&cond, NULL);
- _timeout.tv_sec= 5;
- _timeout.tv_nsec= 0;
- }
-
- const struct timespec& timeout() const
- {
- return _timeout;
- }
-
- bool release(memcached_st*, memcached_return_t& rc);
-
- memcached_st *fetch(memcached_return_t& rc);
- memcached_st *fetch(const struct timespec&, memcached_return_t& rc);
-
- bool init(uint32_t initial);
-
- ~memcached_pool_st()
- {
- for (int x= 0; x <= firstfree; ++x)
- {
- memcached_free(server_pool[x]);
- server_pool[x]= NULL;
- }
-
- int error;
- if ((error= pthread_mutex_destroy(&mutex)) != 0)
- {
- assert_vmsg(error != 0, "pthread_mutex_destroy() %s(%d)", strerror(error), error);
- }
-
- if ((error= pthread_cond_destroy(&cond)) != 0)
- {
- assert_vmsg(error != 0, "pthread_cond_destroy() %s", strerror(error));
- }
-
- delete [] server_pool;
- if (_owns_master)
- {
- memcached_free(master);
- }
- }
-
- void increment_version()
- {
- ++master->configure.version;
- }
-
- bool compare_version(const memcached_st *arg) const
- {
- return (arg->configure.version == version());
- }
-
- int32_t version() const
- {
- return master->configure.version;
- }
-};
-
-
-/**
- * Grow the connection pool by creating a connection structure and clone the
- * original memcached handle.
- */
-static bool grow_pool(memcached_pool_st* pool)
-{
- assert(pool);
-
- memcached_st *obj;
- if (not (obj= memcached_clone(NULL, pool->master)))
- {
- return false;
- }
-
- pool->server_pool[++pool->firstfree]= obj;
- pool->current_size++;
- obj->configure.version= pool->version();
-
- return true;
-}
-
-bool memcached_pool_st::init(uint32_t initial)
-{
- server_pool= new (std::nothrow) memcached_st *[size];
- if (server_pool == NULL)
- {
- return false;
- }
-
- /*
- Try to create the initial size of the pool. An allocation failure at
- this time is not fatal..
- */
- for (unsigned int x= 0; x < initial; ++x)
- {
- if (grow_pool(this) == false)
- {
- break;
- }
- }
-
- return true;
-}
-
-
-static inline memcached_pool_st *_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
-{
- if (initial == 0 or max == 0 or (initial > max))
- {
- return NULL;
- }
-
- memcached_pool_st *object= new (std::nothrow) memcached_pool_st(master, max);
- if (object == NULL)
- {
- return NULL;
- }
-
- /*
- Try to create the initial size of the pool. An allocation failure at
- this time is not fatal..
- */
- if (not object->init(initial))
- {
- delete object;
- return NULL;
- }
-
- return object;
-}
-
-memcached_pool_st *memcached_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
-{
- return _pool_create(master, initial, max);
-}
-
-memcached_pool_st * memcached_pool(const char *option_string, size_t option_string_length)
-{
- memcached_st *memc= memcached(option_string, option_string_length);
-
- if (memc == NULL)
- {
- return NULL;
- }
-
- memcached_pool_st *self= memcached_pool_create(memc, memc->configure.initial_pool_size, memc->configure.max_pool_size);
- if (self == NULL)
- {
- memcached_free(memc);
- return NULL;
- }
-
- self->_owns_master= true;
-
- return self;
-}
-
-memcached_st* memcached_pool_destroy(memcached_pool_st* pool)
-{
- if (pool == NULL)
- {
- return NULL;
- }
-
- // Legacy that we return the original structure
- memcached_st *ret= NULL;
- if (pool->_owns_master)
- { }
- else
- {
- ret= pool->master;
- }
-
- delete pool;
-
- return ret;
-}
-
-memcached_st* memcached_pool_st::fetch(memcached_return_t& rc)
-{
- static struct timespec relative_time= { 0, 0 };
- return fetch(relative_time, rc);
-}
-
-memcached_st* memcached_pool_st::fetch(const struct timespec& relative_time, memcached_return_t& rc)
-{
- rc= MEMCACHED_SUCCESS;
-
- int error;
- if ((error= pthread_mutex_lock(&mutex)) != 0)
- {
- rc= MEMCACHED_IN_PROGRESS;
- return NULL;
- }
-
- memcached_st *ret= NULL;
- do
- {
- if (firstfree > -1)
- {
- ret= server_pool[firstfree--];
- }
- else if (current_size == size)
- {
- if (relative_time.tv_sec == 0 and relative_time.tv_nsec == 0)
- {
- error= pthread_mutex_unlock(&mutex);
- rc= MEMCACHED_NOTFOUND;
-
- return NULL;
- }
-
- struct timespec time_to_wait= {0, 0};
- time_to_wait.tv_sec= time(NULL) +relative_time.tv_sec;
- time_to_wait.tv_nsec= relative_time.tv_nsec;
-
- int thread_ret;
- if ((thread_ret= pthread_cond_timedwait(&cond, &mutex, &time_to_wait)) != 0)
- {
- int unlock_error;
- if ((unlock_error= pthread_mutex_unlock(&mutex)) != 0)
- {
- assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
- }
-
- if (thread_ret == ETIMEDOUT)
- {
- rc= MEMCACHED_TIMEOUT;
- }
- else
- {
- errno= thread_ret;
- rc= MEMCACHED_ERRNO;
- }
-
- return NULL;
- }
- }
- else if (grow_pool(this) == false)
- {
- int unlock_error;
- if ((unlock_error= pthread_mutex_unlock(&mutex)) != 0)
- {
- assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
- }
-
- return NULL;
- }
- } while (ret == NULL);
-
- if ((error= pthread_mutex_unlock(&mutex)) != 0)
- {
- assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
- }
-
- return ret;
-}
-
-bool memcached_pool_st::release(memcached_st *released, memcached_return_t& rc)
-{
- rc= MEMCACHED_SUCCESS;
- if (released == NULL)
- {
- rc= MEMCACHED_INVALID_ARGUMENTS;
- return false;
- }
-
- int error;
- if ((error= pthread_mutex_lock(&mutex)))
- {
- rc= MEMCACHED_IN_PROGRESS;
- return false;
- }
-
- /*
- Someone updated the behavior on the object, so we clone a new memcached_st with the new settings. If we fail to clone, we keep the old one around.
- */
- if (compare_version(released) == false)
- {
- memcached_st *memc;
- if ((memc= memcached_clone(NULL, master)))
- {
- memcached_free(released);
- released= memc;
- }
- }
-
- server_pool[++firstfree]= released;
-
- if (firstfree == 0 and current_size == size)
- {
- /* we might have people waiting for a connection.. wake them up :-) */
- if ((error= pthread_cond_broadcast(&cond)) != 0)
- {
- assert_vmsg(error != 0, "pthread_cond_broadcast() %s", strerror(error));
- }
- }
-
- if ((error= pthread_mutex_unlock(&mutex)) != 0)
- {
- }
-
- return true;
-}
-
-memcached_st* memcached_pool_fetch(memcached_pool_st* pool, struct timespec* relative_time, memcached_return_t* rc)
-{
- if (pool == NULL)
- {
- return NULL;
- }
-
- memcached_return_t unused;
- if (rc == NULL)
- {
- rc= &unused;
- }
-
- if (relative_time == NULL)
- {
- return pool->fetch(*rc);
- }
-
- return pool->fetch(*relative_time, *rc);
-}
-
-memcached_st* memcached_pool_pop(memcached_pool_st* pool,
- bool block,
- memcached_return_t *rc)
-{
- if (pool == NULL)
- {
- return NULL;
- }
-
- memcached_return_t unused;
- if (rc == NULL)
- {
- rc= &unused;
- }
-
- memcached_st *memc;
- if (block)
- {
- memc= pool->fetch(pool->timeout(), *rc);
- }
- else
- {
- memc= pool->fetch(*rc);
- }
-
- return memc;
-}
-
-memcached_return_t memcached_pool_release(memcached_pool_st* pool, memcached_st *released)
-{
- if (pool == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- memcached_return_t rc;
-
- (void) pool->release(released, rc);
-
- return rc;
-}
-
-memcached_return_t memcached_pool_push(memcached_pool_st* pool, memcached_st *released)
-{
- return memcached_pool_release(pool, released);
-}
-
-
-memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool,
- memcached_behavior_t flag,
- uint64_t data)
-{
- if (pool == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- int error;
- if ((error= pthread_mutex_lock(&pool->mutex)))
- {
- return MEMCACHED_IN_PROGRESS;
- }
-
- /* update the master */
- memcached_return_t rc= memcached_behavior_set(pool->master, flag, data);
- if (memcached_failed(rc))
- {
- if ((error= pthread_mutex_unlock(&pool->mutex)) != 0)
- {
- assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
- }
- return rc;
- }
-
- pool->increment_version();
- /* update the clones */
- for (int xx= 0; xx <= pool->firstfree; ++xx)
- {
- if (memcached_success(memcached_behavior_set(pool->server_pool[xx], flag, data)))
- {
- pool->server_pool[xx]->configure.version= pool->version();
- }
- else
- {
- memcached_st *memc;
- if ((memc= memcached_clone(NULL, pool->master)))
- {
- memcached_free(pool->server_pool[xx]);
- pool->server_pool[xx]= memc;
- /* 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....
- */
- }
- }
- }
-
- if ((error= pthread_mutex_unlock(&pool->mutex)) != 0)
- {
- assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
- }
-
- return rc;
-}
-
-memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool,
- memcached_behavior_t flag,
- uint64_t *value)
-{
- if (pool == NULL)
- {
- return MEMCACHED_INVALID_ARGUMENTS;
- }
-
- int error;
- if ((error= pthread_mutex_lock(&pool->mutex)))
- {
- return MEMCACHED_IN_PROGRESS;
- }
-
- *value= memcached_behavior_get(pool->master, flag);
-
- if ((error= pthread_mutex_unlock(&pool->mutex)) != 0)
- {
- assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
- }
-
- return MEMCACHED_SUCCESS;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2010 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libmemcachedutil/common.h>
-#include <cassert>
-
-struct local_context
-{
- uint8_t major_version;
- uint8_t minor_version;
- uint8_t micro_version;
-
- bool truth;
-};
-
-static memcached_return_t check_server_version(const memcached_st *,
- const memcached_instance_st * instance,
- void *context)
-{
- /* Do Nothing */
- struct local_context *check= (struct local_context *)context;
-
- if (memcached_server_major_version(instance) != UINT8_MAX) {
- uint32_t sv, cv;
-
- sv = memcached_server_micro_version(instance)
- |memcached_server_minor_version(instance) << 8
- |memcached_server_major_version(instance) << 16
- ;
- cv = check->micro_version
- |check->minor_version << 8
- |check->major_version << 16;
-
- if (sv >= cv) {
- return MEMCACHED_SUCCESS;
- }
- }
-
- check->truth= false;
-
- return MEMCACHED_FAILURE;
-}
-
-bool libmemcached_util_version_check(memcached_st *memc,
- uint8_t major_version,
- uint8_t minor_version,
- uint8_t micro_version)
-{
- if (memcached_failed(memcached_version(memc)))
- {
- return false;
- }
-
- struct local_context check= { major_version, minor_version, micro_version, true };
-
- memcached_server_fn callbacks[1];
- callbacks[0]= check_server_version;
- memcached_server_cursor(memc, callbacks, (void *)&check, 1);
-
- return check.truth;
-}
+++ /dev/null
-
-file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/tmp_chroot)
-file(WRITE ${CMAKE_BINARY_DIR}/libtool
-"#!/bin/bash
-shift
-exec $@
-")
-if(UNIX)
- if(EXISTS ${CMAKE_BINARY_DIR}/libtool)
- execute_process(COMMAND chmod +x ${CMAKE_BINARY_DIR}/libtool)
- endif()
-endif()
-
-add_library(libtest STATIC
- alarm.cc
- binaries.cc
- client.cc
- cmdline.cc
- collection.cc
- comparison.cc
- core.cc
- cpu.cc
- dns.cc
- dream.cc
- drizzled.cc
- exception.cc
- exception/fatal.cc
- formatter.cc
- framework.cc
- gearmand.cc
- has.cc
- http.cc
- is_local.cc
- killpid.cc
- libtool.cc
- main.cc
- memcached.cc
- port.cc
- result.cc
- runner.cc
- server.cc
- server_container.cc
- signal.cc
- socket.cc
- strerror.cc
- timer.cc
- tmpfile.cc
- vchar.cc
- )
-set_target_properties(libtest PROPERTIES LIBRARY_OUTPUT_NAME test)
-target_compile_definitions(libtest PRIVATE
- BUILDING_LIBTEST=1
- LIBTEST_TEMP=\"${CMAKE_BINARY_DIR}/tmp_chroot\"
-
- DRIZZLED_BINARY=\"drizzled\"
- GEARMAND_BINARY=\"gearmand\"
- MEMCACHED_BINARY=\"${MEMCACHED_BINARY}\"
- HAVE_MEMCACHED_BINARY=1
- )
-target_link_libraries(libtest PRIVATE Threads::Threads ${CMAKE_DL_LIBS})
-target_include_directories(libtest PRIVATE ..)
-
-add_executable(wait wait.cc dream.cc)
-target_include_directories(wait PRIVATE ..)
-
-add_executable(core_count core_count.cc cpu.cc)
-target_include_directories(core_count PRIVATE ..)
-
-add_executable(backtrace backtrace_test.cc ../libmemcached/backtrace.cc)
-target_link_libraries(backtrace PRIVATE ${CMAKE_DL_LIBS})
-target_include_directories(backtrace PRIVATE ..)
-
-configure_file(yatlcon.h.in yatlcon.h @ONLY)
-configure_file(version.h.in version.h @ONLY)
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/common.h>
-
-#include <sys/time.h>
-#include <cstdlib>
-
-namespace libtest {
-
-static const struct timeval default_it_value= { 600, 0 };
-static const struct timeval default_it_interval= { 0, 0 };
-static const struct itimerval defualt_timer= { default_it_interval, default_it_value };
-
-static const struct itimerval cancel_timer= { default_it_interval, default_it_interval };
-
-
-void set_alarm()
-{
- if (setitimer(ITIMER_VIRTUAL, &defualt_timer, NULL) == -1)
- {
- Error << "setitimer() failed";
- }
-}
-
-void set_alarm(long tv_sec, long tv_usec)
-{
- // For the moment use any value to YATL_ALARM to cancel alarming.
- if (getenv("YATL_ALARM"))
- {
- errno= 0;
- tv_sec= strtol(getenv("YATL_ALARM"), (char **) NULL, 10);
-
- if (errno != 0)
- {
- FATAL("Bad value for YATL_ALARM");
- }
- else if (tv_sec == 0)
- {
- cancel_alarm();
- }
- }
-
-#ifdef __APPLE__
- struct timeval it_value= { time_t(tv_sec), suseconds_t(tv_usec) };
-#else
- struct timeval it_value= { tv_sec, tv_usec };
-#endif
-
- struct itimerval timer= { default_it_interval, it_value };
-
- if (setitimer(ITIMER_VIRTUAL, &timer, NULL) == -1)
- {
- Error << "setitimer() failed";
- }
-}
-
-void cancel_alarm()
-{
- if (setitimer(ITIMER_VIRTUAL, &cancel_timer, NULL) == -1)
- {
- Error << "setitimer() failed";
- }
-}
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-void set_alarm(long tv_sec, long tv_usec);
-void set_alarm();
-void cancel_alarm();
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <cerrno>
-#include <csignal>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-
-#include "libmemcached/backtrace.hpp"
-
-class Test {
-public:
- Test()
- {
- }
-
- void call_backtrace()
- {
- std::cerr << __func__ << std::endl;
- custom_backtrace();
- }
-};
-
-void SIGSEGV_handler(int sig_num, siginfo_t* info, void* ucontext)
-{
- std::cerr << __func__ << std::endl;
- (void)sig_num;
- (void)info;
- (void)ucontext;
-
- custom_backtrace();
-}
-
-int raise_SIGSEGV()
-{
- std::cerr << std::endl << "Calling backtrace()" << std::endl;
- custom_backtrace();
- std::cerr << std::endl << "Calling raise()" << std::endl;
- return raise(SIGSEGV);
-}
-
-int layer4()
-{
- return raise_SIGSEGV();
-}
-
-int layer3()
-{
- return layer4();
-}
-
-int layer2()
-{
- return layer3();
-}
-
-int layer1()
-{
- return layer2();
-}
-
-int main(int, char **)
-{
- Test t;
-
- t.call_backtrace();
-
- struct sigaction sigact;
-
- sigact.sa_sigaction= SIGSEGV_handler;
- sigact.sa_flags= SA_RESTART | SA_SIGINFO;
-
- if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) != 0)
- {
- std::cerr << "error setting signal handler for " << strsignal(SIGSEGV) << "(" << SIGSEGV << ")" << std::endl;
-
- exit(EXIT_FAILURE);
- }
-
- int ret= layer1();
- if (ret)
- {
- std::cerr << "raise() " << strerror(errno) << std::endl;
- exit(EXIT_FAILURE);
- }
-
- exit(EXIT_SUCCESS);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-namespace libtest {
-
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <libtest/blobslap_worker.h>
-
-#include <cassert>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-namespace libtest {
-
-class BlobslapWorker : public Server
-{
-private:
-public:
- BlobslapWorker(in_port_t port_arg) :
- Server("localhost", port_arg, "benchmark/blobslap_worker", true)
- {
- set_pid_file();
- }
-
- pid_t get_pid(bool error_is_ok)
- {
- if (pid_file().empty())
- {
- Error << "pid_file was empty";
- return -1;
- }
-
- Wait wait(pid_file(), 0);
-
- if (error_is_ok and not wait.successful())
- {
- Error << "Pidfile was not found:" << pid_file();
- return -1;
- }
-
- std::stringstream error_message;
- pid_t ret= get_pid_from_file(pid_file(), error_message);
-
- if (error_is_ok and is_pid_valid(ret) == false)
- {
- Error << error_message.str();
- }
-
- return ret;
- }
-
- bool ping()
- {
- if (pid_file().empty())
- {
- Error << "No pid file available";
- return false;
- }
-
- Wait wait(pid_file(), 0);
- if (not wait.successful())
- {
- Error << "Pidfile was not found:" << pid_file();
- return false;
- }
-
- std::stringstream error_message;
- pid_t local_pid= get_pid_from_file(pid_file(), error_message);
- if (is_pid_valid(local_pid) == false)
- {
- Error << error_message.str();
- return false;
- }
-
- // Use kill to determine is the process exist
- if (::kill(local_pid, 0) == 0)
- {
- return true;
- }
-
- return false;
- }
-
- const char *name()
- {
- return "blobslap_worker";
- };
-
- bool has_port_option() const
- {
- return true;
- }
-
- bool has_log_file_option() const
- {
- return true;
- }
-
- bool is_libtool()
- {
- return true;
- }
-
- bool build();
-};
-
-
-#include <sstream>
-
-bool BlobslapWorker::build()
-{
- return true;
-}
-
-Server *build_blobslap_worker(in_port_t try_port)
-{
- return new BlobslapWorker(try_port);
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-Server *build_blobslap_worker(in_port_t try_port);
-
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void* (test_callback_create_fn)(libtest::server_startup_st&, test_return_t&);
-typedef bool test_callback_destroy_fn(void *);
-typedef enum test_return_t (test_callback_fn)(void *);
-typedef enum test_return_t (test_callback_runner_fn)(test_callback_fn*, void *);
-typedef enum test_return_t (test_callback_error_fn)(const test_return_t, void *);
-
-#ifdef __cplusplus
-}
-#endif
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <string>
-
-#ifdef HAVE_POLL_H
-# include <poll.h>
-#endif
-
-#ifndef HAVE_MSG_NOSIGNAL
-# define MSG_NOSIGNAL 0
-#endif
-
-namespace libtest {
-
-SimpleClient::SimpleClient(const std::string& hostname_, in_port_t port_) :
- _is_connected(false),
- _hostname(hostname_),
- _port(port_),
- sock_fd(INVALID_SOCKET),
- requested_message(1)
- {
- }
-
-bool SimpleClient::ready(int event_)
-{
- struct pollfd fds[1];
- fds[0].fd= sock_fd;
- fds[0].events= event_;
- fds[0].revents= 0;
-
- int timeout= 5000;
- if (_is_connected == false)
- {
- timeout= timeout * 30;
- }
-
- int ready_fds= poll(fds, 1, timeout);
-
- if (ready_fds == -1)
- {
- _error= strerror(errno);
- return false;
- }
- else if (ready_fds == 1)
- {
- if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL))
- {
- int err;
- socklen_t len= sizeof (err);
- // We replace errno with err if getsockopt() passes, but err has been
- // set.
- if (getsockopt(fds[0].fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0)
- {
- // We check the value to see what happened wth the socket.
- if (err == 0)
- {
- _error= "getsockopt() returned no error but poll() indicated one existed";
- return false;
- }
- errno= err;
- }
- _error= strerror(errno);
-
- return false;
- }
-
- _is_connected= true;
- if (fds[0].revents & event_)
- {
- return true;
- }
- }
-
- fatal_assert(ready_fds == 0);
- _error= "TIMEOUT";
-
- return false;
-}
-
-struct addrinfo* SimpleClient::lookup()
-{
- struct addrinfo *ai= NULL;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_socktype= SOCK_STREAM;
- hints.ai_protocol= IPPROTO_TCP;
-
- libtest::vchar_t service;
- service.resize(NI_MAXSERV);
- (void)snprintf(&service[0], service.size(), "%d", _port);
-
- int getaddrinfo_error;
- if ((getaddrinfo_error= getaddrinfo(_hostname.c_str(), &service[0], &hints, &ai)) != 0)
- {
- if (getaddrinfo_error != EAI_SYSTEM)
- {
- _error= gai_strerror(getaddrinfo_error);
- return NULL;
- }
- else
- {
- _error= strerror(getaddrinfo_error);
- return NULL;
- }
- }
-
- return ai;
-}
-
-SimpleClient::~SimpleClient()
-{
- close_socket();
-}
-
-void SimpleClient::close_socket()
-{
- if (sock_fd != INVALID_SOCKET)
- {
- close(sock_fd);
- sock_fd= INVALID_SOCKET;
- }
-}
-
-bool SimpleClient::instance_connect()
-{
- _is_connected= false;
- struct addrinfo *ai;
- if ((ai= lookup()))
- {
- {
- struct addrinfo* address_info_next= ai;
-
- while (address_info_next and sock_fd == INVALID_SOCKET)
- {
- if ((sock_fd= socket(address_info_next->ai_family, address_info_next->ai_socktype, address_info_next->ai_protocol)) != SOCKET_ERROR)
- {
- if (connect(sock_fd, address_info_next->ai_addr, address_info_next->ai_addrlen) == SOCKET_ERROR)
- {
- switch (errno)
- {
- case EINTR:
- close_socket();
- continue;
-
- case EINPROGRESS: // nonblocking mode - first return
- case EALREADY: // nonblocking mode - subsequent returns
- continue; // Jump to while() and continue on
-
-
- case ECONNREFUSED:
- default:
- break;
- }
-
- close_socket();
- _error= strerror(errno);
- }
- }
- else
- {
- FATAL(strerror(errno));
- }
- address_info_next= address_info_next->ai_next;
- }
-
- freeaddrinfo(ai);
- }
-
- if (sock_fd == INVALID_SOCKET)
- {
- fatal_assert(_error.size());
- }
-
- return bool(sock_fd != INVALID_SOCKET);
- }
-
- return false;
-}
-
-bool SimpleClient::is_valid()
-{
- _error.clear();
- if (sock_fd == INVALID_SOCKET)
- {
- return instance_connect();
- }
-
- return true;
-}
-
-bool SimpleClient::message(const char* ptr, const size_t len)
-{
- if (is_valid())
- {
- if (ready(POLLOUT))
- {
- off_t offset= 0;
- do
- {
- ssize_t nw= send(sock_fd, ptr + offset, len - offset, MSG_NOSIGNAL);
- if (nw == -1)
- {
- if (errno != EINTR)
- {
- _error= strerror(errno);
- return false;
- }
- }
- else
- {
- offset += nw;
- }
- } while (offset < ssize_t(len));
-
- return true;
- }
- }
-
- fatal_assert(_error.size());
-
- return false;
-}
-
-bool SimpleClient::send_message(const std::string& arg)
-{
- if (message(arg.c_str(), arg.size()) == true)
- {
- return message("\r\n", 2);
- }
-
- return false;
-}
-
-bool SimpleClient::send_data(const libtest::vchar_t& message_, libtest::vchar_t& response_)
-{
- requested_message++;
- if (message(&message_[0], message_.size()))
- {
- return response(response_);
- }
-
- return false;
-}
-
-bool SimpleClient::send_message(const std::string& message_, std::string& response_)
-{
- requested_message++;
- if (send_message(message_))
- {
- return response(response_);
- }
-
- return false;
-}
-
-bool SimpleClient::response(libtest::vchar_t& response_)
-{
- response_.clear();
-
- if (is_valid())
- {
- if (ready(POLLIN))
- {
- bool more= true;
- char buffer[2];
- buffer[1]= 0;
- do
- {
- ssize_t nr= recv(sock_fd, buffer, 1, MSG_NOSIGNAL);
- if (nr == -1)
- {
- if (errno != EINTR)
- {
- _error= strerror(errno);
- return false;
- }
- }
- else if (nr == 0)
- {
- close_socket();
- more= false;
- }
- else
- {
- response_.reserve(response_.size() + nr +1);
- fatal_assert(nr == 1);
- if (buffer[0] == '\n')
- {
- more= false;
- }
- response_.insert(response_.end(), buffer, buffer +nr);
- }
- } while (more);
-
- return response_.size();
- }
- }
-
- fatal_assert(_error.size());
- return false;
-}
-
-bool SimpleClient::response(std::string& response_)
-{
- response_.clear();
-
- if (is_valid())
- {
- if (ready(POLLIN))
- {
- bool more= true;
- char buffer[2];
- buffer[1]= 0;
- do
- {
- ssize_t nr= recv(sock_fd, buffer, 1, MSG_NOSIGNAL);
- if (nr == -1)
- {
- if (errno != EINTR)
- {
- _error= strerror(errno);
- return false;
- }
- }
- else if (nr == 0)
- {
- close_socket();
- more= false;
- }
- else
- {
- fatal_assert(nr == 1);
- if (buffer[0] == '\n')
- {
- more= false;
- }
- response_.append(buffer);
- }
- } while (more);
-
- return response_.size();
- }
- }
-
- fatal_assert(_error.size());
- return false;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-class SimpleClient {
-public:
- SimpleClient(const std::string& hostname_, in_port_t port_);
- ~SimpleClient();
-
- bool send_data(const libtest::vchar_t&, libtest::vchar_t&);
- bool send_message(const std::string&);
- bool send_message(const std::string&, std::string&);
- bool response(std::string&);
- bool response(libtest::vchar_t&);
-
- bool is_valid();
-
- const std::string& error() const
- {
- return _error;
- }
-
- bool is_error() const
- {
- return _error.size() ? true : false;
- }
-
-private: // Methods
- void close_socket();
- bool instance_connect();
- struct addrinfo* lookup();
- bool message(const char* ptr, const size_t len);
- bool ready(int event_);
-
-private:
- bool _is_connected;
- std::string _hostname;
- in_port_t _port;
- int sock_fd;
- std::string _error;
- int requested_message;
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include "libtest/common.h"
-
-using namespace libtest;
-
-#include <cstdlib>
-#include <cstring>
-#include <cerrno>
-#include <fcntl.h>
-#include <fstream>
-#include <memory>
-#ifdef HAVE_POLL_H
-# include <poll.h>
-#endif
-#ifdef HAVE_SPAWN_H
-# include <spawn.h>
-#endif
-#include <sstream>
-#include <string>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <stdexcept>
-
-#ifndef __USE_GNU
-static char **environ= NULL;
-#endif
-
-#ifndef FD_CLOEXEC
-# define FD_CLOEXEC 0
-#endif
-
-namespace {
-
- std::string print_argv(libtest::vchar_ptr_t& built_argv)
- {
- std::stringstream arg_buffer;
-
- for (vchar_ptr_t::iterator iter= built_argv.begin();
- iter != built_argv.end();
- ++iter)
- {
- if (*iter)
- {
- arg_buffer << *iter << " ";
- }
- }
-
- return arg_buffer.str();
- }
-
-#if 0
- std::string print_argv(char** argv)
- {
- std::stringstream arg_buffer;
-
- for (char** ptr= argv; *ptr; ++ptr)
- {
- arg_buffer << *ptr << " ";
- }
-
- return arg_buffer.str();
- }
-#endif
-
- static Application::error_t int_to_error_t(int arg)
- {
- switch (arg)
- {
- case 127:
- return Application::INVALID_POSIX_SPAWN;
-
- case 0:
- return Application::SUCCESS;
-
- case 1:
- return Application::FAILURE;
-
- default:
- return Application::UNKNOWN;
- }
- }
-}
-
-namespace libtest {
-
-Application::Application(const std::string& arg, const bool _use_libtool_arg) :
- _use_libtool(_use_libtool_arg),
- _use_valgrind(false),
- _use_gdb(false),
- _use_ptrcheck(false),
- _will_fail(false),
- _argc(0),
- _exectuble(arg),
- stdin_fd(STDIN_FILENO),
- stdout_fd(STDOUT_FILENO),
- stderr_fd(STDERR_FILENO),
- _pid(-1),
- _status(0),
- _app_exit_state(UNINITIALIZED)
- {
- if (_use_libtool)
- {
- if (libtool() == NULL)
- {
- FATAL("libtool requested, but no libtool was found");
- }
- }
-
- // Find just the name of the application with no path
- {
- size_t found= arg.find_last_of("/\\");
- if (found)
- {
- _exectuble_name= arg.substr(found +1);
- }
- else
- {
- _exectuble_name= arg;
- }
- }
-
- if (_use_libtool and getenv("PWD"))
- {
- _exectuble_with_path+= getenv("PWD");
- _exectuble_with_path+= "/";
- }
- _exectuble_with_path+= _exectuble;
- }
-
-Application::~Application()
-{
- murder();
- delete_argv();
-}
-
-Application::error_t Application::run(const char *args[])
-{
- stdin_fd.reset();
- stdout_fd.reset();
- stderr_fd.reset();
- _stdout_buffer.clear();
- _stderr_buffer.clear();
-
- posix_spawn_file_actions_t file_actions;
- posix_spawn_file_actions_init(&file_actions);
-
- stdin_fd.dup_for_spawn(file_actions);
- stdout_fd.dup_for_spawn(file_actions);
- stderr_fd.dup_for_spawn(file_actions);
-
- posix_spawnattr_t spawnattr;
- posix_spawnattr_init(&spawnattr);
-
- short flags= 0;
-
- // Child should not block signals
- flags |= POSIX_SPAWN_SETSIGMASK;
-
- sigset_t mask;
- sigemptyset(&mask);
-
- fatal_assert(posix_spawnattr_setsigmask(&spawnattr, &mask) == 0);
-
-#if defined(POSIX_SPAWN_USEVFORK) || defined(__linux__)
- // Use USEVFORK on linux
- flags |= POSIX_SPAWN_USEVFORK;
-#endif
-
- flags |= POSIX_SPAWN_SETPGROUP;
- fatal_assert(posix_spawnattr_setpgroup(&spawnattr, 0) == 0);
-
- fatal_assert(posix_spawnattr_setflags(&spawnattr, flags) == 0);
-
- create_argv(args);
-
- int spawn_ret;
- if (_use_gdb)
- {
- std::string gdb_run_file= create_tmpfile(_exectuble_name);
- std::fstream file_stream;
- file_stream.open(gdb_run_file.c_str(), std::fstream::out | std::fstream::trunc);
-
- _gdb_filename= create_tmpfile(_exectuble_name);
- file_stream
- << "set logging redirect on" << std::endl
- << "set logging file " << _gdb_filename << std::endl
- << "set logging overwrite on" << std::endl
- << "set logging on" << std::endl
- << "set environment LIBTEST_IN_GDB=1" << std::endl
- << "run " << arguments() << std::endl
- << "thread apply all bt" << std::endl
- << "quit" << std::endl;
-
- fatal_assert(file_stream.good());
- file_stream.close();
-
- if (_use_libtool)
- {
- // libtool --mode=execute gdb -f -x binary
- char *argv[]= {
- const_cast<char *>(libtool()),
- const_cast<char *>("--mode=execute"),
- const_cast<char *>("gdb"),
- const_cast<char *>("-batch"),
- const_cast<char *>("-f"),
- const_cast<char *>("-x"),
- const_cast<char *>(gdb_run_file.c_str()),
- const_cast<char *>(_exectuble_with_path.c_str()),
- 0};
-
- spawn_ret= posix_spawnp(&_pid, libtool(), &file_actions, &spawnattr, argv, environ);
- }
- else
- {
- // gdb binary
- char *argv[]= {
- const_cast<char *>("gdb"),
- const_cast<char *>("-batch"),
- const_cast<char *>("-f"),
- const_cast<char *>("-x"),
- const_cast<char *>(gdb_run_file.c_str()),
- const_cast<char *>(_exectuble_with_path.c_str()),
- 0};
- spawn_ret= posix_spawnp(&_pid, "gdb", &file_actions, &spawnattr, argv, environ);
- }
- }
- else
- {
- spawn_ret= posix_spawn(&_pid, built_argv[0], &file_actions, &spawnattr, &built_argv[0], environ);
- }
-
- posix_spawn_file_actions_destroy(&file_actions);
- posix_spawnattr_destroy(&spawnattr);
-
- stdin_fd.close(Application::Pipe::READ);
- stdout_fd.close(Application::Pipe::WRITE);
- stderr_fd.close(Application::Pipe::WRITE);
-
- if (spawn_ret != 0)
- {
- if (_will_fail == false)
- {
- std::string sb;
- char buf[1024];
-
- std::for_each(built_argv.begin(), built_argv.end()-1, [&sb](const char *a) {
- if (sb.size()) {
- sb.append(" ");
- }
- sb.append(a);
- });
- Error << strerror(spawn_ret) << "(" << spawn_ret << "): " << sb << " cwd:" << getcwd(buf, sizeof(buf)-1);
- }
- _pid= -1;
- return Application::INVALID_POSIX_SPAWN;
- }
-
- assert(_pid != -1);
- if (_pid == -1)
- {
- return Application::INVALID_POSIX_SPAWN;
- }
-
-#if 0
- app_thread_st* _app_thread= new app_thread_st(_pid, _status, built_argv[0], _app_exit_state);
- int error;
- if ((error= pthread_create(&_thread, NULL, &app_thread, _app_thread)) != 0)
- {
- Error << "pthread_create() died during pthread_create(" << strerror(error) << ")";
- return Application::FAILURE;
- }
-#endif
-
- return Application::SUCCESS;
-}
-
-bool Application::check() const
-{
- if (_pid > 1 and kill(_pid, 0) == 0)
- {
- return true;
- }
-
- return false;
-}
-
-void Application::murder()
-{
- if (check())
- {
- int count= 5;
- while ((count--) > 0 and check())
- {
- if (kill(_pid, SIGTERM) == 0)
- {
- join();
- }
- else
- {
- Error << "kill(pid, SIGTERM) failed after kill with error of " << strerror(errno);
- continue;
- }
-
- break;
- }
-
- // If for whatever reason it lives, kill it hard
- if (check())
- {
- Error << "using SIGKILL, things will likely go poorly from this point";
- (void)kill(_pid, SIGKILL);
- }
- }
- slurp();
-}
-
-// false means that no data was returned
-bool Application::slurp()
-{
- struct pollfd fds[2];
- fds[0].fd= stdout_fd.fd();
- fds[0].events= POLLRDNORM;
- fds[0].revents= 0;
- fds[1].fd= stderr_fd.fd();
- fds[1].events= POLLRDNORM;
- fds[1].revents= 0;
-
- int active_fd;
- if ((active_fd= poll(fds, 2, 0)) == -1)
- {
- int error;
- switch ((error= errno))
- {
-#ifdef __linux
- case ERESTART:
-#endif
- case EINTR:
- break;
-
- case EFAULT:
- case ENOMEM:
- FATAL(strerror(error));
- break;
-
- case EINVAL:
- FATAL("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid");
- break;
-
- default:
- FATAL(strerror(error));
- break;
- }
-
- return false;
- }
-
- if (active_fd == 0)
- {
- return false;
- }
-
- bool data_was_read= false;
- if (fds[0].revents & POLLRDNORM)
- {
- if (stdout_fd.read(_stdout_buffer) == true)
- {
- data_was_read= true;
- }
- }
-
- if (fds[1].revents & POLLRDNORM)
- {
- if (stderr_fd.read(_stderr_buffer) == true)
- {
- data_was_read= true;
- }
- }
-
- return data_was_read;
-}
-
-std::pair<std::string, std::string> Application::output()
-{
- slurp();
- return {
- std::string {
- stdout_result().data(),
- stdout_result().size()
- },
- std::string {
- stderr_result().data(),
- stderr_result().size()
- }
- };
-
-}
-
-Application::error_t Application::join()
-{
- pid_t waited_pid= waitpid(_pid, &_status, WUNTRACED);
- slurp();
- if (waited_pid == _pid and WIFEXITED(_status) == false)
- {
- /*
- What we are looking for here is how the exit status happened.
- - 127 means that posix_spawn() itself had an error.
- - If WEXITSTATUS is positive we need to see if it is a signal that we sent to kill the process. If not something bad happened in the process itself.
- - Finally something has happened that we don't currently understand.
- */
- if (WEXITSTATUS(_status) == 127)
- {
- _app_exit_state= Application::INVALID_POSIX_SPAWN;
- std::string error_string("posix_spawn() failed pid:");
- error_string+= _pid;
- error_string+= " name:";
- error_string+= print_argv(built_argv);
- if (stderr_result_length())
- {
- error_string+= " stderr: ";
- error_string+= stderr_c_str();
- }
- throw std::logic_error(error_string);
- }
- else if (WIFSIGNALED(_status))
- {
- if (WTERMSIG(_status) != SIGTERM and WTERMSIG(_status) != SIGHUP)
- {
- slurp();
- _app_exit_state= Application::INVALID_POSIX_SPAWN;
- std::string error_string(print_argv(built_argv));
- error_string+= " was killed by signal ";
- error_string+= strsignal(WTERMSIG(_status));
-
- if (stdout_result_length())
- {
- error_string+= " stdout: ";
- error_string+= stdout_c_str();
- }
-
- if (stderr_result_length())
- {
- error_string+= " stderr: ";
- error_string+= stderr_c_str();
- }
-
- throw std::runtime_error(error_string);
- }
-
- // If we terminted it on purpose then it counts as a success.
-#if defined(DEBUG)
- if (DEBUG)
- {
- Out << "waitpid() application terminated at request"
- << " pid:" << _pid
- << " name:" << built_argv[0];
- }
-#endif
- }
- else
- {
- _app_exit_state= Application::UNKNOWN;
- Error << "Unknown logic state at exit:" << WEXITSTATUS(_status)
- << " pid:" << _pid
- << " name:" << built_argv[0];
- }
- }
- else if (waited_pid == _pid and WIFEXITED(_status))
- {
- _app_exit_state= int_to_error_t(WEXITSTATUS(_status));
- }
- else if (waited_pid == -1)
- {
- std::string error_string;
- if (stdout_result_length())
- {
- error_string+= " stdout: ";
- error_string+= stdout_c_str();
- }
-
- if (stderr_result_length())
- {
- error_string+= " stderr: ";
- error_string+= stderr_c_str();
- }
- Error << "waitpid() returned errno:" << strerror(errno) << " " << error_string;
- _app_exit_state= Application::UNKNOWN;
- }
- else
- {
- _app_exit_state= Application::UNKNOWN;
- throw std::logic_error("waitpid() returned an unknown value");
- }
-
- return _app_exit_state;
-}
-
-void Application::add_long_option(const std::string& name, const std::string& option_value)
-{
- std::string arg(name);
- arg+= option_value;
- _options.push_back(std::make_pair(arg, std::string()));
-}
-
-void Application::add_option(const std::string& arg)
-{
- _options.push_back(std::make_pair(arg, std::string()));
-}
-
-void Application::add_option(const std::string& name, const std::string& value)
-{
- _options.push_back(std::make_pair(name, value));
-}
-
-Application::Pipe::Pipe(int arg) :
- _std_fd(arg)
-{
- _pipe_fd[READ]= -1;
- _pipe_fd[WRITE]= -1;
- _open[READ]= false;
- _open[WRITE]= false;
-}
-
-int Application::Pipe::Pipe::fd()
-{
- if (_std_fd == STDOUT_FILENO)
- {
- return _pipe_fd[READ];
- }
- else if (_std_fd == STDERR_FILENO)
- {
- return _pipe_fd[READ];
- }
-
- return _pipe_fd[WRITE]; // STDIN_FILENO
-}
-
-
-bool Application::Pipe::read(libtest::vchar_t& arg)
-{
- fatal_assert(_std_fd == STDOUT_FILENO or _std_fd == STDERR_FILENO);
-
- bool data_was_read= false;
-
- libtest::vchar_t buffer;
- buffer.resize(1024);
- ssize_t read_length;
- while ((read_length= ::read(_pipe_fd[READ], &buffer[0], buffer.size())))
- {
- if (read_length == -1)
- {
- switch(errno)
- {
- case EAGAIN:
- break;
-
- default:
- Error << strerror(errno);
- break;
- }
-
- break;
- }
-
- data_was_read= true;
- arg.reserve(read_length +1);
- for (size_t x= 0; x < size_t(read_length); ++x)
- {
- arg.push_back(buffer[x]);
- }
- // @todo Suck up all errput code here
- }
-
- return data_was_read;
-}
-
-void Application::Pipe::nonblock()
-{
- int flags;
- do
- {
- flags= fcntl(_pipe_fd[READ], F_GETFL, 0);
- } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
-
- if (flags == -1)
- {
- Error << "fcntl(F_GETFL) " << strerror(errno);
- throw strerror(errno);
- }
-
- int rval;
- do
- {
- rval= fcntl(_pipe_fd[READ], F_SETFL, flags | O_NONBLOCK);
- } while (rval == -1 and (errno == EINTR or errno == EAGAIN));
-
- if (rval == -1)
- {
- Error << "fcntl(F_SETFL) " << strerror(errno);
- throw strerror(errno);
- }
-}
-
-void Application::Pipe::reset()
-{
- close(READ);
- close(WRITE);
-
-#ifdef HAVE_PIPE2
- if (pipe2(_pipe_fd, O_NONBLOCK|O_CLOEXEC) == -1)
-#endif
- {
- if (pipe(_pipe_fd) == -1)
- {
- FATAL(strerror(errno));
- }
-
- // Since either pipe2() was not found/called we set the pipe directly
- nonblock();
- cloexec();
- }
- _open[0]= true;
- _open[1]= true;
-}
-
-void Application::Pipe::cloexec()
-{
- //if (SOCK_CLOEXEC == 0)
- {
- if (FD_CLOEXEC)
- {
- int flags;
- do
- {
- flags= fcntl(_pipe_fd[WRITE], F_GETFD, 0);
- } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
-
- if (flags == -1)
- {
- Error << "fcntl(F_GETFD) " << strerror(errno);
- throw strerror(errno);
- }
-
- int rval;
- do
- {
- rval= fcntl(_pipe_fd[WRITE], F_SETFD, flags | FD_CLOEXEC);
- } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
-
- if (rval == -1)
- {
- Error << "fcntl(F_SETFD) " << strerror(errno);
- throw strerror(errno);
- }
- }
- }
-}
-
-Application::Pipe::~Pipe()
-{
- if (_pipe_fd[0] != -1)
- {
- ::close(_pipe_fd[0]);
- }
-
- if (_pipe_fd[1] != -1)
- {
- ::close(_pipe_fd[1]);
- }
-}
-
-void Application::Pipe::dup_for_spawn(posix_spawn_file_actions_t& file_actions)
-{
- int type= STDIN_FILENO == _std_fd ? 0 : 1;
-
- int ret;
- if ((ret= posix_spawn_file_actions_adddup2(&file_actions, _pipe_fd[type], _std_fd )) < 0)
- {
- FATAL("posix_spawn_file_actions_adddup2(%s)", strerror(ret));
- }
-
- if ((ret= posix_spawn_file_actions_addclose(&file_actions, _pipe_fd[type])) < 0)
- {
- FATAL("posix_spawn_file_actions_addclose(%s)", strerror(ret));
- }
-}
-
-void Application::Pipe::close(const close_t& arg)
-{
- int type= int(arg);
-
- if (_open[type])
- {
- if (::close(_pipe_fd[type]) == -1)
- {
- Error << "close(" << strerror(errno) << ")";
- }
- _open[type]= false;
- _pipe_fd[type]= -1;
- }
-}
-
-void Application::create_argv(const char *args[])
-{
- delete_argv();
- if (_use_libtool)
- {
- assert(libtool());
- vchar::append(built_argv, libtool());
- vchar::append(built_argv, "--mode=execute");
- }
-
- if (_use_valgrind)
- {
- /*
- valgrind --error-exitcode=1 --leak-check=yes --track-fds=yes --malloc-fill=A5 --free-fill=DE
- */
- vchar::append(built_argv, "valgrind");
- vchar::append(built_argv, "--error-exitcode=1");
- vchar::append(built_argv, "--leak-check=yes");
-#if 0
- vchar::append(built_argv, "--show-reachable=yes"));
-#endif
- vchar::append(built_argv, "--track-fds=yes");
-#if 0
- built_argv[x++]= strdup("--track-origin=yes");
-#endif
- vchar::append(built_argv, "--malloc-fill=A5");
- vchar::append(built_argv, "--free-fill=DE");
-
- std::string log_file= create_tmpfile("valgrind");
- libtest::vchar_t buffer;
- buffer.resize(1024);
- int length= snprintf(&buffer[0], buffer.size(), "--log-file=%s", log_file.c_str());
- fatal_assert(length > 0 and size_t(length) < buffer.size());
- vchar::append(built_argv, &buffer[0]);
- }
- else if (_use_ptrcheck)
- {
- /*
- valgrind --error-exitcode=1 --tool=exp-ptrcheck --log-file=
- */
- vchar::append(built_argv, "valgrind");
- vchar::append(built_argv, "--error-exitcode=1");
- vchar::append(built_argv, "--tool=exp-ptrcheck");
- std::string log_file= create_tmpfile("ptrcheck");
- libtest::vchar_t buffer;
- buffer.resize(1024);
- int length= snprintf(&buffer[0], buffer.size(), "--log-file=%s", log_file.c_str());
- fatal_assert(length > 0 and size_t(length) < buffer.size());
- vchar::append(built_argv, &buffer[0]);
- }
- else if (_use_gdb)
- {
- vchar::append(built_argv, "gdb");
- }
-
- vchar::append(built_argv, _exectuble_with_path.c_str());
-
- for (Options::const_iterator iter= _options.begin(); iter != _options.end(); ++iter)
- {
- vchar::append(built_argv, (*iter).first.c_str());
- if ((*iter).second.empty() == false)
- {
- vchar::append(built_argv, (*iter).second.c_str());
- }
- }
-
- if (args)
- {
- for (const char **ptr= args; *ptr; ++ptr)
- {
- vchar::append(built_argv, *ptr);
- }
- }
- built_argv.push_back(nullptr);
-}
-
-std::string Application::print()
-{
- return print_argv(built_argv);
-}
-
-std::string Application::arguments()
-{
- std::stringstream arg_buffer;
-
- // Skip printing out the libtool reference
- for (size_t x= _use_libtool ? 2 : 0; x < _argc; ++x)
- {
- if (built_argv[x])
- {
- arg_buffer << built_argv[x] << " ";
- }
- }
-
- return arg_buffer.str();
-}
-
-void Application::delete_argv()
-{
- std::for_each(built_argv.begin(), built_argv.end(), FreeFromVector());
-
- built_argv.clear();
- _argc= 0;
-}
-
-
-int exec_cmdline(const std::string& command, const char *args[], bool use_libtool)
-{
- Application app(command, use_libtool);
-
- Application::error_t ret= app.run(args);
-
- if (Application::SUCCESS == ret) {
- ret = app.join();
- }
-
- if (ret != Application::SUCCESS)
- {
- auto out = app.output();
- Error << command << " stdout: " << out.first;
- Error << command << " stderr: " << out.second;
- }
-
- return int(ret);
-}
-
-} // namespace exec_cmdline
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <spawn.h>
-
-// http://www.gnu.org/software/automake/manual/automake.html#Using-the-TAP-test-protocol
-#ifndef EXIT_SKIP
-# define EXIT_SKIP 77
-#endif
-
-#ifndef EXIT_FATAL
-# define EXIT_FATAL 99
-#endif
-
-#ifndef EX_NOEXEC
-# define EX_NOEXEC 126
-#endif
-
-#ifndef EX_NOTFOUND
-# define EX_NOTFOUND 127
-#endif
-
-namespace libtest {
-
-class Application {
-private:
- typedef std::vector< std::pair<std::string, std::string> > Options;
-
-public:
-
- enum error_t {
- SUCCESS= EXIT_SUCCESS,
- FAILURE= EXIT_FAILURE,
- UNINITIALIZED,
- SIGTERM_KILLED,
- UNKNOWN,
- UNKNOWN_SIGNAL,
- INVALID_POSIX_SPAWN= 127
- };
-
- static const char* toString(error_t arg)
- {
- switch (arg)
- {
- case Application::SUCCESS:
- return "EXIT_SUCCESS";
-
- case Application::UNINITIALIZED:
- return "UNINITIALIZED";
-
- case Application::SIGTERM_KILLED:
- return "Exit happened via SIGTERM";
-
- case Application::FAILURE:
- return "EXIT_FAILURE";
-
- case Application::UNKNOWN_SIGNAL:
- return "Exit happened via a signal which was not SIGTERM";
-
- case Application::INVALID_POSIX_SPAWN:
- return "127: Invalid call to posix_spawn()";
-
- case Application::UNKNOWN:
- default:
- break;
- }
-
- return "EXIT_UNKNOWN";
- }
-
- class Pipe {
- public:
- Pipe(int);
- ~Pipe();
-
- int fd();
-
- enum close_t {
- READ= 0,
- WRITE= 1
- };
-
- void reset();
- void close(const close_t& arg);
- void dup_for_spawn(posix_spawn_file_actions_t& file_actions);
-
- void nonblock();
- void cloexec();
- bool read(libtest::vchar_t&);
-
- private:
- const int _std_fd;
- int _pipe_fd[2];
- bool _open[2];
- };
-
-public:
- Application(const std::string& arg, const bool _use_libtool_arg= false);
-
- virtual ~Application();
-
- void add_option(const std::string&);
- void add_option(const std::string&, const std::string&);
- void add_long_option(const std::string& option_name, const std::string& option_value);
- error_t run(const char *args[]= NULL);
- Application::error_t join();
-
- libtest::vchar_t stdout_result() const
- {
- return _stdout_buffer;
- }
-
- size_t stdout_result_length() const
- {
- return _stdout_buffer.size();
- }
-
- const char* stdout_c_str() const
- {
- return &_stdout_buffer[0];
- }
-
- libtest::vchar_t stderr_result() const
- {
- return _stderr_buffer;
- }
-
- const char* stderr_c_str() const
- {
- return &_stderr_buffer[0];
- }
-
- size_t stderr_result_length() const
- {
- return _stderr_buffer.size();
- }
-
- std::string print();
-
- void use_valgrind(bool arg)
- {
- _use_valgrind= arg;
- }
-
- bool check() const;
-
- bool slurp();
- std::pair<std::string, std::string> output();
- void murder();
-
- void clear()
- {
- slurp();
- _stdout_buffer.clear();
- _stderr_buffer.clear();
- }
-
- void use_gdb(bool arg)
- {
- _use_gdb= arg;
- }
-
- void use_ptrcheck(bool arg)
- {
- _use_ptrcheck= arg;
- }
-
- std::string arguments();
-
- std::string gdb_filename()
- {
- return _gdb_filename;
- }
-
- pid_t pid() const
- {
- return _pid;
- }
-
- void will_fail()
- {
- _will_fail= true;
- }
-
-private:
- void create_argv(const char *args[]);
- void delete_argv();
- void add_to_build_argv(const char*);
-
-private:
- const bool _use_libtool;
- bool _use_valgrind;
- bool _use_gdb;
- bool _use_ptrcheck;
- bool _will_fail;
- size_t _argc;
- std::string _exectuble_name;
- std::string _exectuble;
- std::string _exectuble_with_path;
- std::string _gdb_filename;
- Options _options;
- Pipe stdin_fd;
- Pipe stdout_fd;
- Pipe stderr_fd;
- libtest::vchar_ptr_t built_argv;
- pid_t _pid;
- libtest::vchar_t _stdout_buffer;
- libtest::vchar_t _stderr_buffer;
- int _status;
- pthread_t _thread;
- error_t _app_exit_state;
-};
-
-static inline std::ostream& operator<<(std::ostream& output, const enum Application::error_t &arg)
-{
- return output << Application::toString(arg);
-}
-
-int exec_cmdline(const std::string& executable, const char *args[], bool use_libtool= false);
-
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/common.h>
-
-// @todo possibly have this code fork off so if it fails nothing goes bad
-static test_return_t runner_code(libtest::Framework* frame,
- test_st* run,
- libtest::Timer& _timer)
-{ // Runner Code
-
- assert(frame->runner());
- assert(run->test_fn);
-
- test_return_t return_code;
- try
- {
- _timer.reset();
- assert(frame);
- assert(frame->runner());
- assert(run->test_fn);
- return_code= frame->runner()->main(run->test_fn, frame->creators_ptr());
- }
- // Special case where check for the testing of the exception
- // system.
- catch (const libtest::fatal& e)
- {
- if (libtest::fatal::is_disabled())
- {
- libtest::fatal::increment_disabled_counter();
- return_code= TEST_SUCCESS;
- }
- else
- {
- throw;
- }
- }
-
- _timer.sample();
-
- return return_code;
-}
-
-namespace libtest {
-
-Collection::Collection(Framework* frame_arg,
- collection_st* arg) :
- _name(arg->name),
- _pre(arg->pre),
- _post(arg->post),
- _tests(arg->tests),
- _frame(frame_arg),
- _success(0),
- _skipped(0),
- _failed(0),
- _total(0),
- _formatter(frame_arg->name(), _name)
-{
- fatal_assert(arg);
-}
-
-test_return_t Collection::exec()
-{
- if (test_success(_frame->runner()->setup(_pre, _frame->creators_ptr())))
- {
- for (test_st *run= _tests; run->name; run++)
- {
- formatter()->push_testcase(run->name);
- if (_frame->match(run->name))
- {
- formatter()->skipped();
- continue;
- }
- _total++;
-
- test_return_t return_code;
- try
- {
- if (run->requires_flush)
- {
- if (test_failed(_frame->runner()->flush(_frame->creators_ptr())))
- {
- Error << "frame->runner()->flush(creators_ptr)";
- _skipped++;
- formatter()->skipped();
- continue;
- }
- }
-
- set_alarm();
-
- try
- {
- return_code= runner_code(_frame, run, _timer);
- }
- catch (...)
- {
- cancel_alarm();
-
- throw;
- }
- libtest::cancel_alarm();
- }
- catch (const libtest::fatal& e)
- {
- _failed++;
- formatter()->failed();
- stream::make_cerr err(e.file(), e.line(), e.func());
- err << e.what();
- for (auto server : _frame->servers().servers)
- {
- auto output = server->output();
- if (output.first.size())
- {
- err << "Server(" << server->port() << ") stdout:\n" << output.first << "\n";
- }
- if (output.second.size())
- {
- err << "Server(" << server->port() << ") stderr:\n" << output.second << "\n";
- }
- }
- throw;
- }
-
- switch (return_code)
- {
- case TEST_SUCCESS:
- _success++;
- formatter()->success(_timer);
- break;
-
- case TEST_FAILURE:
- _failed++;
- formatter()->failed();
- for (auto server : _frame->servers().servers)
- {
- auto output = server->output();
- if (output.first.size())
- {
- Out << "Server(" << server->port() << ") stdout:\n" << output.first << "\n";
- }
- if (output.second.size())
- {
- Out << "Server(" << server->port() << ") stderr:\n" << output.second << "\n";
- }
- }
- break;
-
- case TEST_SKIPPED:
- _skipped++;
- formatter()->skipped();
- break;
-
- default:
- FATAL("invalid return code");
- }
-#if 0
- @TODO add code here to allow for a collection to define a method to reset to allow tests to continue.
-#endif
- }
-
- (void) _frame->runner()->teardown(_post, _frame->creators_ptr());
- }
-
- if (_failed == 0 and _skipped == 0 and _success)
- {
- return TEST_SUCCESS;
- }
-
- if (_failed)
- {
- return TEST_FAILURE;
- }
-
- fatal_assert(_skipped or _success == 0);
-
- return TEST_SKIPPED;
-}
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libtest/formatter.hpp>
-
-#include <libtest/timer.hpp>
-
-namespace { class Framework; }
-
-
-/**
- A structure which describes a collection of test cases.
-*/
-struct collection_st {
- const char *name;
- test_callback_fn *pre;
- test_callback_fn *post;
- struct test_st *tests;
-};
-
-namespace libtest {
-
-class Collection {
-public:
- Collection(libtest::Framework*, collection_st*);
-
- test_return_t exec();
-
- const char* name()
- {
- return _name.c_str();
- }
-
- uint32_t success()
- {
- return _success;
- }
-
- uint32_t skipped()
- {
- return _skipped;
- }
-
- uint32_t failed()
- {
- return _failed;
- }
-
- uint32_t total()
- {
- return _total;
- }
-
- libtest::Formatter* formatter()
- {
- return &_formatter;
- }
-
-private:
- std::string _name;
- test_callback_fn *_pre;
- test_callback_fn *_post;
- struct test_st *_tests;
- libtest::Framework* _frame;
- uint32_t _success;
- uint32_t _skipped;
- uint32_t _failed;
- uint32_t _total;
- libtest::Timer _timer;
- libtest::Formatter _formatter;
-
-private:
- Collection( const Collection& );
- const Collection& operator=( const Collection& );
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-/*
- Common include file for libtest
-*/
-
-#pragma once
-
-#include <cassert>
-#include <cerrno>
-#include <cstdlib>
-#include <sstream>
-#include <string>
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
-#ifdef HAVE_SYS_RESOURCE_H
-# include <sys/resource.h>
-#endif
-
-#ifdef HAVE_FNMATCH_H
-# include <fnmatch.h>
-#endif
-
-#ifdef HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#endif
-
-#if defined(WIN32)
-# include "win32/wrappers.h"
-# define get_socket_errno() WSAGetLastError()
-#else
-# ifdef HAVE_UNISTD_H
-# include <unistd.h>
-# endif
-# define INVALID_SOCKET -1
-# define SOCKET_ERROR -1
-# define closesocket(a) close(a)
-# define get_socket_errno() errno
-#endif
-
-#include <libtest/test.hpp>
-
-#include <libtest/is_pid.hpp>
-
-#include <libtest/gearmand.h>
-#include <libtest/blobslap_worker.h>
-#include <libtest/memcached.h>
-#include <libtest/drizzled.h>
-
-#include <libtest/libtool.hpp>
-#include <libtest/killpid.h>
-#include <libtest/signal.h>
-#include <libtest/dns.hpp>
-#include <libtest/formatter.hpp>
-
-struct FreeFromVector
-{
- template <class T>
- void operator() ( T* ptr) const
- {
- if (ptr)
- {
- free(ptr);
- ptr= NULL;
- }
- }
-};
-
-struct DeleteFromVector
-{
- template <class T>
- void operator() ( T* ptr) const
- {
- delete ptr;
- ptr= NULL;
- }
-};
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-namespace libtest {
-
-bool jenkins_is_caller(void)
-{
- if (bool(getenv("JENKINS_HOME")))
- {
- return true;
- }
-
- return false;
-}
-
-bool gdb_is_caller(void)
-{
- if (bool(getenv("LOG_COMPILER")) and strstr(getenv("LOG_COMPILER"), "gdb"))
- {
- return true;
- }
-
- if (bool(getenv("LIBTEST_IN_GDB")))
- {
- return true;
- }
-
- return false;
-}
-
-bool helgrind_is_caller(void)
-{
- if (bool(getenv("LOG_COMPILER")) and strstr(getenv("LOG_COMPILER"), "helgrind"))
- {
- return true;
- }
-
- return false;
-}
-
-bool _in_valgrind(const char*, int, const char*)
-{
- if (valgrind_is_caller())
- {
- return true;
- }
-
- return false;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <typeinfo>
-
-#if defined(HAVE_LIBMEMCACHED) && HAVE_LIBMEMCACHED
-#include <libmemcached-1.0/memcached.h>
-#include <libmemcachedutil-1.0/ostream.hpp>
-#include <libtest/memcached.hpp>
-#endif
-
-#if defined(HAVE_LIBGEARMAN) && HAVE_LIBGEARMAN
-#include <libgearman-1.0/ostream.hpp>
-#endif
-
-namespace libtest {
-
-LIBTEST_API
-bool jenkins_is_caller(void);
-
-LIBTEST_API
-bool gdb_is_caller(void);
-
-LIBTEST_API
-bool _in_valgrind(const char *file, int line, const char *func);
-
-LIBTEST_API
-bool helgrind_is_caller(void);
-
-template <class T_comparable>
-bool _compare_truth(const char *file, int line, const char *func, T_comparable __expected, const char *assertation_label)
-{
- if (__expected == false)
- {
- libtest::stream::make_cerr(file, line, func) << "Assertation \"" << assertation_label << "\"";
- return false;
- }
-
- return true;
-}
-
-template <class T1_comparable, class T2_comparable>
-bool _compare(const char *file, int line, const char *func, const T1_comparable& __expected, const T2_comparable& __actual, bool use_io)
-{
- if (__expected != __actual)
- {
- if (use_io)
- {
- libtest::stream::make_cerr(file, line, func) << "Expected \"" << __expected << "\" got \"" << __actual << "\"";
- }
-
- return false;
- }
-
- return true;
-}
-
-template <class T1_comparable, class T2_comparable>
-bool _compare_strcmp(const char *file, int line, const char *func, const T1_comparable *__expected, const T2_comparable *__actual)
-{
- if (__expected == NULL)
- {
- FATAL("Expected value was NULL, programmer error");
- }
-
- if (__actual == NULL)
- {
- libtest::stream::make_cerr(file, line, func) << "Expected " << __expected << " but got NULL";
- return false;
- }
-
- if (strncmp(__expected, __actual, strlen(__expected)))
- {
- libtest::stream::make_cerr(file, line, func) << "Expected " << __expected << " passed \"" << __actual << "\"";
- return false;
- }
-
- return true;
-}
-
-template <class T_comparable>
-bool _compare_zero(const char *file, int line, const char *func, T_comparable __actual)
-{
- if (T_comparable(0) != __actual)
- {
- libtest::stream::make_cerr(file, line, func) << "Expected 0 got \"" << __actual << "\"";
- return false;
- }
-
- return true;
-}
-
-template <class T1_comparable, class T2_comparable>
-bool _ne_compare(const char *file, int line, const char *func, T1_comparable __expected, T2_comparable __actual, bool io_error= true)
-{
- if (__expected == __actual)
- {
- if (io_error)
- {
- libtest::stream::make_cerr(file, line, func) << "Expected \"" << __expected << "\" got \"" << __actual << "\"";
- }
-
- return false;
- }
-
- return true;
-}
-
-template <class T_comparable, class T_expression_string>
-bool _assert_truth(const char *file, int line, const char *func, T_comparable __truth, T_expression_string __expression, const char* __explain= NULL)
-{
- if (__truth)
- {
- return true;
- }
-
- if (__explain)
- {
- libtest::stream::make_cerr(file, line, func) << "Assertion \"" << __expression << "\" warning:" << __explain;
- }
-
- return false;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-
-namespace libtest {
-
-void create_core(void)
-{
-#if defined(__APPLE__) && __APPLE__
- if (__APPLE__)
- {
- return;
- }
-#endif
- if (getenv("YATL_COREDUMP"))
- {
- pid_t pid= fork();
-
- if (pid == 0)
- {
- abort();
- }
- else
- {
- while (waitpid(pid, NULL, 0) != pid) {};
- }
- }
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-LIBTEST_API
-void create_core(void);
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <cstdlib>
-#include <fcntl.h>
-#include <getopt.h>
-#include <iostream>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <libtest/cpu.hpp>
-
-static void version_command(const char *command_name, int major_version, int minor_version)
-{
- std::cout << command_name << " " << major_version << "." << minor_version << std::endl;
-}
-
-static void help_command(const char *command_name,
- int major_version, int minor_version,
- const struct option *long_options)
-{
- std::cout << command_name << " " << major_version << "." << minor_version << std::endl;
- std::cout << "Prints the number of cores found on the local host." << std::endl << std::endl;
-
- for (uint32_t x= 0; long_options[x].name; x++)
- {
- std::cout << "\t --" << long_options[x].name << char(long_options[x].has_arg ? '=' : ' ') << std::endl;
- }
-
- std::cout << std::endl;
-}
-
-enum {
- OPT_HELP,
- OPT_VERSION
-};
-
-static void options_parse(int argc, char *argv[])
-{
- static struct option long_options[]=
- {
- { "version", no_argument, NULL, OPT_VERSION},
- { "help", no_argument, NULL, OPT_HELP},
- {0, 0, 0, 0},
- };
-
- bool opt_version= false;
- bool opt_help= false;
- int option_index= 0;
-
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
- if (option_rv == -1)
- {
- break;
- }
-
- switch (option_rv)
- {
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_VERSION: /* --version or -v */
- opt_version= true;
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(EXIT_FAILURE);
-
- default:
- help_command(argv[0], 1, 0, long_options);
- exit(EXIT_FAILURE);
- }
- }
-
- if (opt_version)
- {
- version_command(argv[0], 1, 0);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(argv[0], 1, 0, long_options);
- exit(EXIT_SUCCESS);
- }
-}
-
-int main(int argc, char *argv[])
-{
- options_parse(argc, argv);
-
- std::cout << libtest::number_of_cpus() << std::endl;
-
- return EXIT_SUCCESS;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <unistd.h>
-
-#pragma GCC diagnostic ignored "-Wundef"
-
-#if defined(HAVE_LINUX_SYSCTL_H) && HAVE_LINUX_SYSCTL_H
-#include <linux/sysctl.h>
-#elif defined(HAVE_SYS_SYSCTL_H) && HAVE_SYS_SYSCTL_H
-#include <sys/sysctl.h>
-#endif
-
-namespace libtest {
-
-size_t number_of_cpus()
-{
- size_t number_of_cpu= 1;
-#if defined(__linux) && __linux
- number_of_cpu= sysconf(_SC_NPROCESSORS_ONLN);
-#elif defined(HAVE_SYS_SYSCTL_H) && defined(CTL_HW) && defined(HW_NCPU) && defined(HW_AVAILCPU) && defined(HW_NCPU)
- int mib[4];
- size_t len= sizeof(number_of_cpu);
-
- /* set the mib for hw.ncpu */
- mib[0] = CTL_HW;
- mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
-
- /* get the number of CPUs from the system */
- sysctl(mib, 2, &number_of_cpu, &len, NULL, 0);
-
- if (number_of_cpu < 1)
- {
- mib[1]= HW_NCPU;
- sysctl(mib, 2, &number_of_cpu, &len, NULL, 0 );
-
- if (number_of_cpu < 1 )
- {
- number_of_cpu = 1;
- }
- }
-#else
- // Guessing number of CPU
-#endif
-
- return number_of_cpu;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-size_t number_of_cpus();
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-namespace libtest {
-
-bool lookup(const char* host)
-{
- bool success= false;
- assert(host and host[0]);
- if (host and host[0])
- {
- struct addrinfo *addrinfo= NULL;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(hints));
- hints.ai_socktype= SOCK_STREAM;
- hints.ai_protocol= IPPROTO_TCP;
-
- int limit= 5;
- while (--limit and success == false)
- {
- if (addrinfo)
- {
- freeaddrinfo(addrinfo);
- addrinfo= NULL;
- }
-
- int ret;
- if ((ret= getaddrinfo(host, "echo", &hints, &addrinfo)) == 0)
- {
- success= true;
- break;
- }
-
- switch (ret)
- {
- case EAI_AGAIN:
- continue;
-
- case EAI_NONAME:
- default:
- break;
- }
-
- break;
- }
-
- if (addrinfo)
- {
- freeaddrinfo(addrinfo);
- }
- }
-
- return success;
-}
-
-
-bool check_dns()
-{
- if (valgrind_is_caller())
- {
- return false;
- }
-
- if (lookup("exist.gearman.info") == false)
- {
- return false;
- }
-
- if (lookup("does_not_exist.gearman.info")) // This should fail, if it passes,...
- {
- fatal_assert("Your service provider sucks and is providing bogus DNS. You might be in an airport.");
- }
-
- return true;
-}
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-bool check_dns();
-bool lookup(const char*);
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-namespace libtest {
-
-void dream(time_t tv_sec, long tv_nsec)
-{
-#if defined(WIN32)
- if (tv_sec == 0 and tv_nsec)
- {
- tv_sec++;
- }
- sleep(tv_sec);
-#else
- struct timespec requested;
- requested.tv_sec= tv_sec;
- requested.tv_nsec= tv_nsec;
- nanosleep(&requested, NULL);
-#endif
-}
-
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-void dream(time_t tv_sec, long tv_nsec= 0);
-
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <libtest/drizzled.h>
-
-#include "util/instance.hpp"
-#include "util/operation.hpp"
-
-using namespace datadifferential;
-using namespace libtest;
-
-#include <cassert>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-#include <signal.h>
-#include <sstream>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-#if defined(HAVE_LIBDRIZZLE) && HAVE_LIBDRIZZLE
-# include <libdrizzle-5.1/drizzle_client.h>
-#endif
-
-using namespace libtest;
-
-namespace libtest {
-bool ping_drizzled(const in_port_t _port)
-{
- (void)(_port);
-#if defined(HAVE_LIBDRIZZLE) && HAVE_LIBDRIZZLE
- if (HAVE_LIBDRIZZLE)
- {
- drizzle_st *drizzle= drizzle_create(getenv("MYSQL_SERVER"),
- getenv("MYSQL_PORT") ? atoi("MYSQL_PORT") : DRIZZLE_DEFAULT_TCP_PORT,
- getenv("MYSQL_USER"),
- getenv("MYSQL_PASSWORD"),
- getenv("MYSQL_SCHEMA"), 0);
-
- if (drizzle == NULL)
- {
- return false;
- }
-
- bool success= false;
-
- drizzle_return_t rc;
- if ((rc= drizzle_connect(drizzle)) == DRIZZLE_RETURN_OK)
- {
- drizzle_result_st *result= drizzle_ping(drizzle, &rc);
- success= bool(result);
- drizzle_result_free(result);
- }
-
- if (success == true)
- { }
- else if (rc != DRIZZLE_RETURN_OK)
- {
- Error << drizzle_error(drizzle) << " localhost:" << _port;
- }
-
- drizzle_quit(drizzle);
-
- return success;
- }
-#endif
-
- return false;
-}
-} // namespace libtest
-
-class Drizzle : public libtest::Server
-{
-private:
-public:
- Drizzle(const std::string& host_arg, in_port_t port_arg) :
- libtest::Server(host_arg, port_arg, DRIZZLED_BINARY, false)
- {
- set_pid_file();
- }
-
- bool ping()
- {
- size_t limit= 5;
- while (_app.check() and --limit)
- {
- if (ping_drizzled(_port))
- {
- return true;
- }
- libtest::dream(1, 0);
- }
-
- return false;
- }
-
- const char *name()
- {
- return "drizzled";
- };
-
- void log_file_option(Application&, const std::string&)
- {
- }
-
- bool has_log_file_option() const
- {
- return true;
- }
-
- bool broken_pid_file()
- {
- return true;
- }
-
- bool is_libtool()
- {
- return false;
- }
-
- bool has_syslog() const
- {
- return true;
- }
-
- bool has_port_option() const
- {
- return true;
- }
-
- void port_option(Application& app, in_port_t arg)
- {
- if (arg > 0)
- {
- libtest::vchar_t buffer;
- buffer.resize(1024);
- snprintf(&buffer[1024], buffer.size(), "--drizzle-protocol.port=%d", int(arg));
- app.add_option(&buffer[1024]);
- }
- }
-
- bool build();
-};
-
-bool Drizzle::build()
-{
- if (getuid() == 0 or geteuid() == 0)
- {
- add_option("--user=root");
- }
-
- add_option("--verbose=INSPECT");
-#if 0
- add_option("--datadir=var/drizzle");
-#endif
-
- return true;
-}
-
-namespace libtest {
-
-libtest::Server *build_drizzled(const char *hostname, in_port_t try_port)
-{
- return new Drizzle(hostname, try_port);
-}
-
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <arpa/inet.h>
-
-namespace libtest { struct Server; }
-
-namespace libtest {
-
-libtest::Server *build_drizzled(const char *hostname, in_port_t try_port);
-
-bool ping_drizzled(const in_port_t);
-
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-enum test_return_t {
- TEST_SUCCESS,
- TEST_FAILURE,
- TEST_SKIPPED
-};
-
-
-static inline bool test_success(test_return_t rc)
-{
- return (rc == TEST_SUCCESS);
-}
-
-static inline bool test_failed(test_return_t rc)
-{
- return (rc != TEST_SUCCESS);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-#include <cstdarg>
-
-namespace libtest {
-
-exception::exception(const char *file_arg, int line_arg, const char *func_arg):
- std::exception(),
- _line(line_arg),
- _file(file_arg),
- _func(func_arg),
- _error_message(NULL),
- _error_message_size(0)
-{
-}
-
-#ifndef __INTEL_COMPILER
-# pragma GCC diagnostic ignored "-Wformat-nonliteral"
-#endif
-void exception::init(va_list args_)
-{
- const char *format= va_arg(args_, const char *);
- int error_message_length= vasprintf(&_error_message, format, args_);
- assert(error_message_length != -1);
- if (error_message_length > 0)
- {
- _error_message_size= error_message_length +1;
- }
-}
-
-exception::~exception() throw()
-{
- if (_error_message)
- {
- free(_error_message);
- }
-}
-
-void exception::what(size_t length_, const char* message_)
-{
- if (length_ > 0 and message_)
- {
- char *ptr= (char*) realloc(_error_message, length_ +1);
- if (ptr)
- {
- _error_message= ptr;
- memcpy(_error_message, message_, length_);
- _error_message[length_]= 0;
- }
- }
-}
-
-exception::exception(const exception& other) :
- std::exception(),
- _line(other._line),
- _file(other._file),
- _func(other._func),
- _error_message_size(0)
-{
- if (other.length() > 0)
- {
- _error_message= (char*) malloc(other.length() +1);
- if (_error_message)
- {
- memcpy(_error_message, other._error_message, other.length());
- _error_message_size= other.length();
- }
- }
-}
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-class exception : public std::exception
-{
-public:
- exception(const char *file, int line, const char *func);
-
- exception( const exception& );
-
- virtual ~exception() throw();
-
- virtual const char* what() const throw()
- {
- if (_error_message)
- {
- return _error_message;
- }
-
- return "";
- }
-
- void what(size_t, const char*);
-
- size_t length() const
- {
- return _error_message_size;
- }
-
- int line() const
- {
- return _line;
- }
-
- const char* file() const
- {
- return _file;
- }
-
- const char* func() const
- {
- return _func;
- }
-
-protected:
- void init(va_list);
-
-private:
- int _line;
- const char* _file;
- const char* _func;
- char* _error_message;
- size_t _error_message_size;
-};
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include "libtest/exception.hpp"
-
-namespace libtest {
-
-class disconnected : public libtest::exception
-{
-public:
- disconnected(const char *file, int line, const char *func, const std::string&, const unsigned port, ...);
-
- disconnected(const disconnected&);
-
- // The following are just for unittesting the exception class
- static bool is_disabled();
- static void disable();
- static void enable();
- static uint32_t disabled_counter();
- static void increment_disabled_counter();
-
-private:
- in_port_t _port;
- char _instance[BUFSIZ];
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-#include "libtest/exception.hpp"
-#include <cstdarg>
-
-namespace libtest {
-
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-
-fatal::fatal(const char *file_arg, int line_arg, const char *func_arg, ...) :
- libtest::exception(file_arg, line_arg, func_arg)
-{
- va_list args;
- va_start(args, func_arg);
- init(args);
- va_end(args);
-}
-
-fatal::fatal( const fatal& other ) :
- libtest::exception(other)
-{
-}
-
-static bool _disabled= false;
-static uint32_t _counter= 0;
-
-bool fatal::is_disabled() throw()
-{
- return _disabled;
-}
-
-void fatal::disable() throw()
-{
- _counter= 0;
- _disabled= true;
-}
-
-void fatal::enable() throw()
-{
- _counter= 0;
- _disabled= false;
-}
-
-uint32_t fatal::disabled_counter() throw()
-{
- return _counter;
-}
-
-void fatal::increment_disabled_counter() throw()
-{
- _counter++;
-}
-
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-disconnected::disconnected(const char *file_arg, int line_arg, const char *func_arg,
- const std::string& instance, const unsigned port, ...) :
- libtest::exception(file_arg, line_arg, func_arg),
- _port(port)
-{
- va_list args;
- va_start(args, port);
- const char *format= va_arg(args, const char *);
- char last_error[BUFSIZ];
- (void)vsnprintf(last_error, sizeof(last_error), format, args);
- va_end(args);
-
- char buffer_error[BUFSIZ];
- int error_length= snprintf(buffer_error, sizeof(buffer_error), "%s:%u %s", instance.c_str(), uint32_t(port), last_error);
-
- if (error_length > 0)
- {
- what(size_t(error_length), buffer_error);
- }
-}
-
-disconnected::disconnected(const disconnected& other):
- libtest::exception(other),
- _port(other._port)
-{
- strncpy(_instance, other._instance, BUFSIZ);
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-class fatal : public libtest::exception
-{
-public:
- fatal(const char *file, int line, const char *func, ...);
-
- fatal(const fatal&);
-
- // The following are just for unittesting the exception class
- static bool is_disabled() throw();
- static void disable() throw();
- static void enable() throw();
- static uint32_t disabled_counter() throw();
- static void increment_disabled_counter() throw();
-
- test_return_t return_code() const
- {
- return TEST_SKIPPED;
- }
-
-private:
-};
-
-} // namespace libtest
-
-#define FATAL(...) \
-do \
-{ \
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, __VA_ARGS__); \
-} while (0)
-
-#define FATAL_IF(__expression, ...) \
-do \
-{ \
- if ((__expression)) { \
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, (#__expression)); \
- } \
-} while (0)
-
-#define FATAL_IF_(__expression, ...) \
-do \
-{ \
- if ((__expression)) { \
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, __VA_ARGS__); \
- } \
-} while (0)
-
-#define fatal_assert(__assert) if((__assert)) {} else { throw libtest::fatal(LIBYATL_DEFAULT_PARAM, #__assert); }
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <libtest/failed.h>
-
-#include <iostream>
-#include <string>
-#include <vector>
-
-namespace libtest {
-
-struct failed_st {
- failed_st(const std::string& collection_arg, const std::string& test_arg) :
- collection(collection_arg),
- test(test_arg)
- { }
-
- std::string collection;
- std::string test;
-};
-
-typedef std::vector<failed_st> Failures;
-
-class Failed
-{
-private:
- Failures failures;
-
-public:
- void push(const char *collection, const char *test)
- {
- failures.push_back(failed_st(collection, test));
- }
-
- void print_failed_test(void)
- {
- for (Failures::iterator iter= failures.begin(); iter != failures.end(); ++iter)
- {
- Error << "\t" << (*iter).collection << " " << (*iter).test;
- }
- }
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/common.h>
-
-#include <algorithm>
-#include <fstream>
-#include <iostream>
-#include <ostream>
-
-namespace libtest {
-
-std::string& escape4XML(std::string const& arg, std::string& escaped_string)
-{
- escaped_string.clear();
-
- escaped_string+= '"';
- for (std::string::const_iterator x= arg.begin(), end= arg.end(); x != end; ++x)
- {
- unsigned char c= *x;
- if (c == '&')
- {
- escaped_string+= "&";
- }
- else if (c == '>')
- {
- escaped_string+= ">";
- }
- else if (c == '<')
- {
- escaped_string+= "<";
- }
- else if (c == '\'')
- {
- escaped_string+= "'"; break;
- }
- else if (c == '"')
- {
- escaped_string+= """;
- }
- else if (c == ' ')
- {
- escaped_string+= ' ';
- }
- else if (isalnum(c))
- {
- escaped_string+= c;
- }
- else
- {
- char const* const hexdig= "0123456789ABCDEF";
- escaped_string+= "&#x";
- escaped_string+= hexdig[c >> 4];
- escaped_string+= hexdig[c & 0xF];
- escaped_string+= ';';
- }
- }
- escaped_string+= '"';
-
- return escaped_string;
-}
-
-class TestCase {
-public:
- TestCase(const std::string& arg):
- _name(arg),
- _result(TEST_FAILURE)
- {
- }
-
- const std::string& name() const
- {
- return _name;
- }
-
- test_return_t result() const
- {
- return _result;
- }
-
- void result(test_return_t arg)
- {
- _result= arg;
- }
-
- void result(test_return_t arg, const libtest::Timer& timer_)
- {
- _result= arg;
- _timer= timer_;
- }
-
- const libtest::Timer& timer() const
- {
- return _timer;
- }
-
- void timer(libtest::Timer& arg)
- {
- _timer= arg;
- }
-
-private:
- std::string _name;
- test_return_t _result;
- libtest::Timer _timer;
-};
-
-Formatter::Formatter(const std::string& frame_name, const std::string& arg)
-{
- _suite_name= frame_name;
- _suite_name+= ".";
- _suite_name+= arg;
-}
-
-Formatter::~Formatter()
-{
- std::for_each(_testcases.begin(), _testcases.end(), DeleteFromVector());
- _testcases.clear();
-}
-
-TestCase* Formatter::current()
-{
- return _testcases.back();
-}
-
-void Formatter::skipped()
-{
- assert(current());
- current()->result(TEST_SKIPPED);
-
- Out
- << "[ " << test_strerror(current()->result()) << " ]"
- << "\t\t"
- << name() << "." << current()->name()
- ;
-
- reset();
-}
-
-void Formatter::failed()
-{
- assert(current());
- current()->result(TEST_FAILURE);
-
- Out
- << "[ " << test_strerror(current()->result()) << " ]"
- << "\t\t"
- << name() << "." << current()->name()
- ;
-
- reset();
-}
-
-void Formatter::success(const libtest::Timer& timer_)
-{
- assert(current());
- current()->result(TEST_SUCCESS, timer_);
-
- Out
- << "[ " << test_strerror(current()->result()) << " ]"
- << "\t"
- << current()->timer()
- << "\t"
- << name() << "." << current()->name()
- ;
-
- reset();
-}
-
-void Formatter::xml(libtest::Framework& framework_, std::ofstream& output)
-{
- std::string escaped_string;
-
- output << "<testsuites name="
- << escape4XML(framework_.name(), escaped_string) << ">" << std::endl;
-
- for (Suites::iterator framework_iter= framework_.suites().begin();
- framework_iter != framework_.suites().end();
- ++framework_iter)
- {
- output << "\t<testsuite name="
- << escape4XML((*framework_iter)->name(), escaped_string)
-#if 0
- << " classname=\"\" package=\"\""
-#endif
- << ">" << std::endl;
-
- for (TestCases::iterator case_iter= (*framework_iter)->formatter()->testcases().begin();
- case_iter != (*framework_iter)->formatter()->testcases().end();
- ++case_iter)
- {
- output << "\t\t<testcase name="
- << escape4XML((*case_iter)->name(), escaped_string)
- << " time=\""
- << (*case_iter)->timer().elapsed_milliseconds()
- << "\"";
-
- switch ((*case_iter)->result())
- {
- case TEST_SKIPPED:
- output << ">" << std::endl;
- output << "\t\t <skipped/>" << std::endl;
- output << "\t\t</testcase>" << std::endl;
- break;
-
- case TEST_FAILURE:
- output << ">" << std::endl;
- output << "\t\t <failure message=\"\" type=\"\"/>"<< std::endl;
- output << "\t\t</testcase>" << std::endl;
- break;
-
- case TEST_SUCCESS:
- output << "/>" << std::endl;
- break;
- }
- }
- output << "\t</testsuite>" << std::endl;
- }
- output << "</testsuites>" << std::endl;
-}
-
-void Formatter::push_testcase(const std::string& arg)
-{
- assert(_suite_name.empty() == false);
- TestCase* _current_testcase= new TestCase(arg);
- _testcases.push_back(_current_testcase);
-
- assert(current());
-
- Echo
- << "\t\t\t"
- << name() << "." << current()->name()
- << "... \r"
- ;
-}
-
-void Formatter::reset()
-{
-}
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <string>
-
-namespace libtest { class Framework; }
-
-
-namespace libtest {
-
-class TestCase;
-typedef std::vector<libtest::TestCase*> TestCases;
-
-class Formatter {
-public:
- Formatter(const std::string& frame_name, const std::string& arg);
-
- ~Formatter();
-
- void skipped();
-
- void failed();
-
- void success(const libtest::Timer&);
-
- void push_testcase(const std::string&);
-
- const std::string& name() const
- {
- return _suite_name;
- }
-
- TestCases& testcases()
- {
- return _testcases;
- }
-
- static void xml(libtest::Framework&, std::ofstream&);
-
-private:
- void reset();
-
- TestCase* current();
-
-private:
- std::string _suite_name;
- TestCases _testcases;
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/common.h>
-#include <libtest/collection.h>
-#include <libtest/signal.h>
-
-#include <algorithm>
-#include <fnmatch.h>
-#include <iostream>
-
-namespace libtest {
-
-Framework::Framework(libtest::SignalThread& signal_,
- const std::string& name_,
- const std::string& only_run_arg,
- const std::string& wildcard_arg) :
- _total(0),
- _success(0),
- _skipped(0),
- _failed(0),
- _create(NULL),
- _destroy(NULL),
- _on_error(NULL),
- _runner(NULL),
- _socket(false),
- _creators_ptr(NULL),
- _signal(signal_),
- _only_run(only_run_arg),
- _wildcard(wildcard_arg),
- _name(name_)
-{
- get_world(this);
-}
-
-void Framework::collections(collection_st collections_[])
-{
- for (collection_st *next= collections_; next and next->name; next++)
- {
- _collection.push_back(new Collection(this, next));
- }
-}
-
-Framework::~Framework()
-{
- if (_destroy and _destroy(_creators_ptr))
- {
- Error << "Failure in _destroy(), some resources may not have been cleaned up.";
- }
-
- _servers.shutdown();
-
- delete _runner;
-
- std::for_each(_collection.begin(), _collection.end(), DeleteFromVector());
- _collection.clear();
-}
-
-bool Framework::match(const char* arg)
-{
- if (_wildcard.empty() == false and fnmatch(_wildcard.c_str(), arg, 0))
- {
- return true;
- }
-
- return false;
-}
-
-void Framework::exec()
-{
- for (std::vector<Collection*>::iterator iter= _collection.begin();
- iter != _collection.end() and (_signal.is_shutdown() == false);
- ++iter)
- {
- if (*iter)
- {
- if (_only_run.empty() == false and
- fnmatch(_only_run.c_str(), (*iter)->name(), 0))
- {
- continue;
- }
-
- _total++;
-
- try {
- switch ((*iter)->exec())
- {
- case TEST_FAILURE:
- _failed++;
- break;
-
- case TEST_SKIPPED:
- _skipped++;
- break;
-
- // exec() can return SUCCESS, but that doesn't mean that some tests did
- // not fail or get skipped.
- case TEST_SUCCESS:
- _success++;
- break;
- }
- }
- catch (const libtest::fatal& e)
- {
- _failed++;
- stream::cerr(e.file(), e.line(), e.func()) << e.what();
- }
- catch (const libtest::disconnected& e)
- {
- _failed++;
- Error << "Unhandled disconnection occurred:" << e.what();
- throw;
- }
- catch (...)
- {
- _failed++;
- throw;
- }
- }
- }
-
- void xml(const std::string& testsuites_name, std::ostream& output);
-}
-
-uint32_t Framework::sum_total()
-{
- uint32_t count= 0;
- for (std::vector<Collection*>::iterator iter= _collection.begin();
- iter != _collection.end();
- ++iter)
- {
- count+= (*iter)->total();
- }
-
- return count;
-}
-
-uint32_t Framework::sum_success()
-{
- uint32_t count= 0;
- for (std::vector<Collection*>::iterator iter= _collection.begin();
- iter != _collection.end();
- ++iter)
- {
- count+= (*iter)->success();
- }
-
- return count;
-}
-
-uint32_t Framework::sum_skipped()
-{
- uint32_t count= 0;
- for (std::vector<Collection*>::iterator iter= _collection.begin();
- iter != _collection.end();
- ++iter)
- {
- count+= (*iter)->skipped();
- }
-
- return count;
-}
-
-uint32_t Framework::sum_failed()
-{
- uint32_t count= 0;
- for (std::vector<Collection*>::iterator iter= _collection.begin();
- iter != _collection.end();
- ++iter)
- {
- count+= (*iter)->failed();
- }
-
- return count;
-}
-
-libtest::Runner *Framework::runner()
-{
- if (_runner == NULL)
- {
- _runner= new Runner;
- }
- _runner->set_servers(_servers);
-
- return _runner;
-}
-
-test_return_t Framework::create()
-{
- test_return_t rc= TEST_SUCCESS;
- if (_create)
- {
- _creators_ptr= _create(_servers, rc);
- }
-
- return rc;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libtest/signal.h>
-
-/**
- Framework 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.
-*/
-
-#include <vector>
-
-namespace { class Collection; }
-typedef std::vector<libtest::Collection*> Suites;
-
-namespace libtest {
-
-class Framework {
-public:
-
-public:
- test_return_t create();
-
- const std::string& name() const
- {
- return _name;
- }
-
- void create(test_callback_create_fn* arg)
- {
- _create= arg;
- }
-
- void destroy(test_callback_destroy_fn* arg)
- {
- _destroy= arg;
- }
-
- void collections(collection_st arg[]);
-
- void set_on_error(test_callback_error_fn *arg)
- {
- _on_error= arg;
- }
-
- test_return_t on_error(const enum test_return_t, void *);
-
- void set_socket()
- {
- _servers.set_socket();
- }
-
- void set_sasl(const std::string& username_arg, const std::string& password_arg)
- {
- _servers.set_sasl(username_arg, password_arg);
- }
-
- libtest::server_startup_st& servers()
- {
- return _servers;
- }
-
- void set_runner(libtest::Runner *arg)
- {
- _runner= arg;
- }
-
- libtest::Runner *runner();
-
- void exec();
-
- libtest::Collection& collection();
-
- virtual ~Framework();
-
- Framework(libtest::SignalThread&,
- const std::string&,
- const std::string&,
- const std::string&);
-
- bool match(const char* arg);
-
- void *creators_ptr()
- {
- return _creators_ptr;
- }
-
- libtest::SignalThread& signal()
- {
- return _signal;
- }
-
- uint32_t sum_total();
- uint32_t sum_success();
- uint32_t sum_skipped();
- uint32_t sum_failed();
-
- size_t size()
- {
- return _collection.size();
- }
-
- uint32_t total() const
- {
- return _total;
- }
-
- uint32_t success() const
- {
- return _success;
- }
-
- uint32_t skipped() const
- {
- return _skipped;
- }
-
- uint32_t failed() const
- {
- return _failed;
- }
-
- Suites& suites()
- {
- return _collection;
- }
-
-private:
- uint32_t _total;
- uint32_t _success;
- uint32_t _skipped;
- uint32_t _failed;
-
- /* These methods are called outside of any collection call. */
- test_callback_create_fn *_create;
- test_callback_destroy_fn *_destroy;
-
- /**
- If an error occurs during the test, this is called.
- */
- test_callback_error_fn *_on_error;
-
- /**
- Runner represents the callers for the tests. If not implemented we will use
- a set of default implementations.
- */
- libtest::Runner *_runner;
-
- libtest::server_startup_st _servers;
- bool _socket;
- void *_creators_ptr;
- unsigned long int _servers_to_run;
- Suites _collection;
- libtest::SignalThread& _signal;
- std::string _only_run;
- std::string _wildcard;
- std::string _name;
-
-private:
- Framework( const Framework& );
- const Framework& operator=( const Framework& );
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <libtest/gearmand.h>
-
-using namespace libtest;
-
-#include <cassert>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-#include <signal.h>
-#include <sstream>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-using namespace libtest;
-
-class Gearmand : public libtest::Server
-{
-private:
-public:
- Gearmand(const std::string& host_arg, in_port_t port_arg, bool libtool_, const char* binary);
-
- bool ping()
- {
- reset_error();
-
- if (out_of_ban_killed())
- {
- return false;
- }
-
- SimpleClient client(_hostname, _port);
-
- std::string response;
- bool ret= client.send_message("version", response);
-
- if (client.is_error())
- {
- error(client.error());
- }
-
- return ret;
- }
-
- const char *name()
- {
- return "gearmand";
- };
-
- void log_file_option(Application& app, const std::string& arg)
- {
- if (arg.empty() == false)
- {
- std::string buffer("--log-file=");
- buffer+= arg;
- app.add_option("--verbose=DEBUG");
- app.add_option(buffer);
- }
- }
-
- bool has_log_file_option() const
- {
- return true;
- }
-
- bool is_libtool()
- {
- return true;
- }
-
- bool has_syslog() const
- {
- return false; // --syslog.errmsg-enable
- }
-
- bool has_port_option() const
- {
- return true;
- }
-
- bool build();
-};
-
-Gearmand::Gearmand(const std::string& host_arg, in_port_t port_arg, bool libtool_, const char* binary_arg) :
- libtest::Server(host_arg, port_arg, binary_arg, libtool_)
-{
- set_pid_file();
-}
-
-bool Gearmand::build()
-{
- if (getuid() == 0 or geteuid() == 0)
- {
- add_option("-u", "root");
- }
-
- add_option("--listen=localhost");
-
- return true;
-}
-
-namespace libtest {
-
-libtest::Server *build_gearmand(const char *hostname, in_port_t try_port, const char* binary)
-{
- if (binary == NULL)
- {
-#if defined(HAVE_GEARMAND_BINARY)
-# if defined(GEARMAND_BINARY)
- if (HAVE_GEARMAND_BINARY)
- {
- binary= GEARMAND_BINARY;
- }
-# endif
-#endif
- }
-
- if (binary == NULL)
- {
- return NULL;
- }
-
- bool is_libtool_script= true;
-
- if (binary[0] == '/')
- {
- is_libtool_script= false;
- }
-
- return new Gearmand(hostname, try_port, is_libtool_script, binary);
-}
-
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest { struct Server; }
-
-namespace libtest {
-
-libtest::Server *build_gearmand(const char *hostname, in_port_t try_port, const char* binary= NULL);
-
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- /* How we make all of this work :) */
- LIBTEST_API
- void get_world(libtest::Framework *world);
-
-#ifdef __cplusplus
-}
-#endif
-
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <cstdio>
-#include <cstdlib>
-#include <unistd.h>
-
-namespace libtest {
-
-bool has_libmemcached_sasl(void)
-{
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
- return LIBMEMCACHED_WITH_SASL_SUPPORT;
-#else
- return false;
-#endif
-}
-
-bool has_libmemcached(void)
-{
-#if defined(HAVE_LIBMEMCACHED) && HAVE_LIBMEMCACHED
- if (HAVE_LIBMEMCACHED)
- {
- return true;
- }
-#endif
-
- return false;
-}
-
-bool has_libdrizzle(void)
-{
-#if defined(HAVE_LIBDRIZZLE) && HAVE_LIBDRIZZLE
- if (HAVE_LIBDRIZZLE)
- {
- return true;
- }
-#endif
-
- return false;
-}
-
-bool has_postgres_support(void)
-{
- char *getenv_ptr;
- if (bool((getenv_ptr= getenv("POSTGRES_IS_RUNNING_AND_SETUP"))))
- {
- (void)(getenv_ptr);
-#if defined(HAVE_LIBPQ) && HAVE_LIBPQ
- if (HAVE_LIBPQ)
- {
- return true;
- }
-#endif
- }
-
- return false;
-}
-
-
-bool has_gearmand()
-{
-#if defined(GEARMAND_BINARY) && defined(HAVE_GEARMAND_BINARY) && HAVE_GEARMAND_BINARY
- if (HAVE_GEARMAND_BINARY)
- {
- std::stringstream arg_buffer;
-
- char *getenv_ptr;
- if (bool((getenv_ptr= getenv("PWD"))) and
- ((strcmp(GEARMAND_BINARY, "./gearmand/gearmand") == 0) or (strcmp(GEARMAND_BINARY, "gearmand/gearmand") == 0)))
- {
- arg_buffer << getenv_ptr;
- arg_buffer << "/";
- }
- arg_buffer << GEARMAND_BINARY;
-
- if (access(arg_buffer.str().c_str(), X_OK) == 0)
- {
- return true;
- }
- }
-#endif
-
- return false;
-}
-
-bool has_drizzled()
-{
-#if defined(DRIZZLED_BINARY) && defined(HAVE_DRIZZLED_BINARY) && HAVE_DRIZZLED_BINARY
- if (HAVE_DRIZZLED_BINARY)
- {
- if (access(DRIZZLED_BINARY, X_OK) == 0)
- {
- return true;
- }
- }
-#endif
-
- return false;
-}
-
-bool has_mysqld()
-{
-#if defined(MYSQLD_BINARY) && defined(HAVE_MYSQLD_BUILD) && HAVE_MYSQLD_BUILD
- if (HAVE_MYSQLD_BUILD)
- {
- if (access(MYSQLD_BINARY, X_OK) == 0)
- {
- return true;
- }
- }
-#endif
-
- return false;
-}
-
-static char memcached_binary_path[FILENAME_MAX];
-
-static void initialize_memcached_binary_path()
-{
- memcached_binary_path[0]= 0;
-
-#if defined(MEMCACHED_BINARY) && defined(HAVE_MEMCACHED_BINARY) && HAVE_MEMCACHED_BINARY
- if (HAVE_MEMCACHED_BINARY)
- {
- std::stringstream arg_buffer;
-
- char *getenv_ptr;
- if (bool((getenv_ptr= getenv("PWD"))) and strcmp(MEMCACHED_BINARY, "memcached/memcached") == 0)
- {
- arg_buffer << getenv_ptr;
- arg_buffer << "/";
- }
- arg_buffer << MEMCACHED_BINARY;
-
- if (access(arg_buffer.str().c_str(), X_OK) == 0)
- {
- strncpy(memcached_binary_path, arg_buffer.str().c_str(), FILENAME_MAX-1);
- }
- }
-#endif
-}
-
-static pthread_once_t memcached_binary_once= PTHREAD_ONCE_INIT;
-static void initialize_memcached_binary(void)
-{
- int ret;
- if ((ret= pthread_once(&memcached_binary_once, initialize_memcached_binary_path)) != 0)
- {
- FATAL(strerror(ret));
- }
-}
-
-bool has_memcached()
-{
- initialize_memcached_binary();
-
- if (memcached_binary_path[0] and (strlen(memcached_binary_path) > 0))
- {
- return true;
- }
-
- return false;
-}
-
-const char* memcached_binary()
-{
- initialize_memcached_binary();
-
- if (memcached_binary_path[0])
- {
- return memcached_binary_path;
- }
-
- return NULL;
-}
-
-const char *gearmand_binary()
-{
-#if defined(GEARMAND_BINARY)
- return GEARMAND_BINARY;
-#else
- return NULL;
-#endif
-}
-
-const char *drizzled_binary()
-{
-#if defined(DRIZZLED_BINARY)
- return DRIZZLED_BINARY;
-#else
- return NULL;
-#endif
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-LIBTEST_API
-bool has_libmemcached_sasl(void);
-
-LIBTEST_API
-bool has_libmemcached();
-
-LIBTEST_API
-bool has_libdrizzle();
-
-LIBTEST_API
-bool has_postgres_support();
-
-LIBTEST_API
-bool has_memcached();
-
-LIBTEST_API
-bool has_memcached_sasl();
-
-LIBTEST_API
-bool has_gearmand();
-
-LIBTEST_API
-bool has_drizzled();
-
-LIBTEST_API
-bool has_mysqld();
-
-LIBTEST_API
-const char* memcached_binary();
-
-LIBTEST_API
-const char *gearmand_binary();
-
-LIBTEST_API
-const char *drizzled_binary();
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/common.h>
-
-#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
-#include <curl/curl.h>
-#else
-class CURL;
-#endif
-
-
-static void cleanup_curl(void)
-{
-#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
- curl_global_cleanup();
-#endif
-}
-
-static void initialize_curl_startup()
-{
-#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
- if (curl_global_init(CURL_GLOBAL_ALL))
- {
- FATAL("curl_global_init(CURL_GLOBAL_ALL) failed");
- }
-#endif
-
- if (atexit(cleanup_curl))
- {
- FATAL("atexit() failed");
- }
-}
-
-static pthread_once_t start_key_once= PTHREAD_ONCE_INIT;
-static void initialize_curl(void)
-{
- int ret;
- if ((ret= pthread_once(&start_key_once, initialize_curl_startup)) != 0)
- {
- FATAL(strerror(ret));
- }
-}
-
-namespace libtest {
-namespace http {
-
-#define YATL_USERAGENT "YATL/1.0"
-
-static size_t http_get_result_callback(void *ptr, size_t size, size_t nmemb, void *data)
-{
- vchar_t *_body= (vchar_t*)data;
-
- _body->resize(size * nmemb);
- memcpy(&(*_body)[0], ptr, _body->size());
-
- return _body->size();
-}
-
-static void init(CURL *curl, const std::string& url)
-{
- (void)http_get_result_callback;
- (void)curl;
- (void)url;
-#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
- if (HAVE_LIBCURL)
- {
- assert(curl);
- curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
- curl_easy_setopt(curl, CURLOPT_USERAGENT, YATL_USERAGENT);
- }
-#endif
-}
-
-HTTP::HTTP(const std::string& url_arg) :
- _url(url_arg),
- _response(0)
-{
- initialize_curl();
-}
-
-bool GET::execute()
-{
- (void)init;
-
-#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
- if (HAVE_LIBCURL)
- {
- CURL *curl= curl_easy_init();
-
- init(curl, url());
-
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_callback);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&_body);
-
- CURLcode retref= curl_easy_perform(curl);
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response);
-
- curl_easy_cleanup(curl);
-
- return bool(retref == CURLE_OK);
- }
-#endif
-
- return false;
-}
-
-bool POST::execute()
-{
-#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
- if (HAVE_LIBCURL)
- {
- CURL *curl= curl_easy_init();;
-
- init(curl, url());
-
- curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, _body.size());
- curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (void *)&_body[0]);
-
- CURLcode retref= curl_easy_perform(curl);
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response);
-
- curl_easy_cleanup(curl);
-
- return bool(retref == CURLE_OK);
- }
-#endif
-
- return false;
-}
-
-bool TRACE::execute()
-{
-#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
- if (HAVE_LIBCURL)
- {
- CURL *curl= curl_easy_init();;
-
- init(curl, url());
-
- curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "TRACE");
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_callback);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&_body[0]);
-
- CURLcode retref= curl_easy_perform(curl);
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response);
-
- curl_easy_cleanup(curl);
-
- return retref == CURLE_OK;
- }
-#endif
-
- return false;
-}
-
-bool HEAD::execute()
-{
-#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
- if (HAVE_LIBCURL)
- {
- CURL *curl= curl_easy_init();
-
- init(curl, url());
-
- curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD");
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_callback);
-
- CURLcode retref= curl_easy_perform(curl);
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response);
-
- curl_easy_cleanup(curl);
-
- return retref == CURLE_OK;
- }
-#endif
-
- return false;
-}
-
-} // namespace http
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libtest/vchar.hpp>
-
-namespace libtest {
-namespace http {
-
-class HTTP {
-public:
-
- HTTP(const std::string& url_arg);
-
- virtual bool execute()= 0;
-
- virtual ~HTTP()
- { }
-
- const std::string& url() const
- {
- return _url;
- }
-
- long response()
- {
- return _response;
- }
-
-private:
- std::string _url;
-
-protected:
- long _response;
-};
-
-class GET: public HTTP {
-public:
-
- GET(const std::string& url_arg) :
- HTTP(url_arg)
- {
- }
-
- bool execute();
-
-private:
- libtest::vchar_t _body;
-};
-
-class POST: public HTTP {
-public:
-
- POST(const std::string& url_arg,
- const vchar_t& post_arg) :
- HTTP(url_arg),
- _post(post_arg)
- {
- }
-
- bool execute();
-
-private:
- libtest::vchar_t _post;
- libtest::vchar_t _body;
-};
-
-class TRACE: public HTTP {
-public:
-
- TRACE(const std::string& url_arg,
- const vchar_t& body_arg) :
- HTTP(url_arg),
- _body(body_arg)
- {
- }
-
- bool execute();
-
-private:
- libtest::vchar_t _body;
-};
-
-class HEAD: public HTTP {
-public:
-
- HEAD(const std::string& url_arg) :
- HTTP(url_arg)
- {
- }
-
- bool execute();
-
-private:
-};
-
-} // namespace http
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-
-namespace libtest {
-
-bool test_is_local()
-{
- return (getenv("LIBTEST_LOCAL"));
-}
-
-static bool _is_massive= false;
-void is_massive(bool arg)
-{
- _is_massive= arg;
-}
-
-bool is_massive()
-{
- return _is_massive;
-}
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-LIBTEST_API
-bool test_is_local();
-
-LIBTEST_API
-void is_massive(bool);
-
-LIBTEST_API
-bool is_massive();
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-static inline bool is_pid_valid(const pid_t pid)
-{
- return (pid > 1) ? true : false;
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-#include <sstream>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-
-#include <libtest/killpid.h>
-#include <libtest/stream.h>
-
-using namespace libtest;
-
-bool kill_pid(pid_t pid_arg)
-{
- assert(pid_arg > 0);
- if (pid_arg < 1)
- {
- Error << "Invalid pid:" << pid_arg;
- return false;
- }
-
- if ((::kill(pid_arg, SIGTERM) == -1))
- {
- switch (errno)
- {
- case EPERM:
- Error << "Does someone else have a process running locally for " << int(pid_arg) << "?";
- return false;
-
- case ESRCH:
- Error << "Process " << int(pid_arg) << " not found.";
- return false;
-
- default:
- case EINVAL:
- Error << "kill() " << strerror(errno);
- return false;
- }
- }
-
- {
- uint32_t this_wait= 0;
- uint32_t timeout= 20; // This number should be high enough for valgrind startup (which is slow)
- uint32_t waited;
- uint32_t retry;
-
- for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
- {
- int status= 0;
- if (waitpid(pid_arg, &status, WNOHANG) == 0)
- {
- break;
- }
- else if (errno == ECHILD)
- {
- // Server has already gone away
- break;
- }
- else if (waited >= timeout)
- {
- // Timeout failed
- kill(pid_arg, SIGKILL);
- break;
- }
-
- this_wait= retry * retry / 3 + 1;
- libtest::dream(this_wait, 0);
- }
- }
-
- return true;
-}
-
-bool check_pid(const std::string &filename)
-{
- if (filename.empty())
- {
- return false;
- }
-
- FILE *fp;
- if ((fp= fopen(filename.c_str(), "r")))
- {
- libtest::vchar_t pid_buffer;
- pid_buffer.resize(1024);
-
- char *ptr= fgets(&pid_buffer[0], int(pid_buffer.size()), fp);
- fclose(fp);
-
- if (ptr)
- {
- pid_t pid= (pid_t)atoi(&pid_buffer[0]);
- if (pid > 0)
- {
- return (::kill(pid, 0) == 0);
- }
- }
- }
-
- return false;
-}
-
-
-bool kill_file(const std::string &filename)
-{
- if (filename.empty())
- {
- return true;
- }
-
- FILE *fp;
- if ((fp= fopen(filename.c_str(), "r")))
- {
- libtest::vchar_t pid_buffer;
- pid_buffer.resize(1024);
-
- char *ptr= fgets(&pid_buffer[0], int(pid_buffer.size()), fp);
- fclose(fp);
-
- if (ptr)
- {
- pid_t pid= (pid_t)atoi(&pid_buffer[0]);
- if (pid != 0)
- {
- bool ret= kill_pid(pid);
- unlink(filename.c_str()); // If this happens we may be dealing with a dead server that left its pid file.
-
- return ret;
- }
- }
- }
-
- return false;
-}
-
-#define STRINGIFY(x) #x
-#define TOSTRING(x) STRINGIFY(x)
-#define LIBTEST_AT __FILE__ ":" TOSTRING(__LINE__)
-
-pid_t get_pid_from_file(const std::string &filename, std::stringstream& error_message)
-{
- pid_t ret= -1;
-
- if (filename.empty())
- {
- error_message << LIBTEST_AT << " empty pid file";
- return ret;
- }
-
- FILE *fp;
- if ((fp= fopen(filename.c_str(), "r")))
- {
- libtest::vchar_t pid_buffer;
- pid_buffer.resize(1024);
-
- char *ptr= fgets(&pid_buffer[0], int(pid_buffer.size()), fp);
- if (ptr)
- {
- ret= (pid_t)atoi(&pid_buffer[0]);
- if (ret < 1)
- {
- error_message << LIBTEST_AT << " Invalid pid was read from file " << filename;
- }
- }
- else
- {
- error_message << LIBTEST_AT << " File " << filename << " was empty ";
- }
-
- fclose(fp);
-
- return ret;
- }
- else
- {
- libtest::vchar_t buffer;
- buffer.resize(1024);
- char *current_directory= getcwd(&buffer[0], buffer.size());
- error_message << "Error while opening " << current_directory << "/" << filename << " " << strerror(errno);
- }
-
- return ret;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-bool kill_pid(pid_t pid_arg);
-
-bool kill_file(const std::string &filename);
-
-bool check_pid(const std::string &filename);
-
-pid_t get_pid_from_file(const std::string &filename, std::stringstream& error_message);
-
-static inline bool check_pid(pid_t pid_arg)
-{
- return (pid_arg > 1);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-#include <string>
-
-char _libtool[1024]= { 0 };
-
-namespace libtest {
-
-const char *libtool(void)
-{
- if (_libtool[0] == 0)
- {
- std::string libtool_buffer;
- if (getenv("PWD"))
- {
- libtool_buffer+= getenv("PWD");
- libtool_buffer+= "/";
- }
- else
- {
- libtool_buffer+= "./";
- }
-
- libtool_buffer+= "libtool";
- if (access(libtool_buffer.c_str(), R_OK | W_OK | X_OK))
- {
- Error << "Could not find libtool via access(" << libtool_buffer << ") :" << strerror(errno);
- return NULL;
- }
-
- snprintf(_libtool, sizeof(_libtool), "%s", libtool_buffer.c_str());
- }
-
- return _libtool;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-const char *libtool(void);
-
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifdef __cplusplus
-# include <cstdarg>
-# include <cstddef>
-# include <cstdio>
-# include <cstdlib>
-# include <cstring>
-#else
-# include <stdarg.h>
-# include <stdbool.h>
-# include <stddef.h>
-# include <stdio.h>
-# include <stdlib.h>
-# include <string.h>
-#endif
-
-#if defined(WIN32)
-# include <malloc.h>
-#else
-# include <alloca.h>
-#endif
-
-#ifndef __PRETTY_FUNCTION__
-# define __PRETTY_FUNCTION__ __func__
-#endif
-
-#ifndef EXIT_SKIP
-# define EXIT_SKIP 77
-#endif
-
-#ifndef YATL_FULL
-# define YATL_FULL 0
-#endif
-
-#ifndef FAIL
-# define FAIL(__message_format, ...)
-#endif
-
-#ifndef SKIP
-# define SKIP(__message_format, ...)
-#endif
-
-#include <libtest/valgrind.h>
-
-static inline size_t yatl_strlen(const char *s)
-{
- if (s)
- {
- return strlen(s);
- }
-
- return (size_t)(0);
-}
-
-static inline int yatl_strcmp(const char *s1, const char *s2, size_t *s1_length, size_t *s2_length)
-{
- *s1_length= yatl_strlen(s1);
- *s2_length= yatl_strlen(s2);
-
- if (*s1_length == 0 && *s1_length == *s2_length)
- {
- return 0;
- }
-
- if (*s1_length == 0 && *s2_length)
- {
- return 1;
- }
-
- if (*s1_length && *s2_length == 0)
- {
- return 1;
- }
-
- return strcmp(s1, s2);
-}
-
-#define SKIP_IF(__expression) \
-do \
-{ \
- if ((__expression)) { \
- if (YATL_FULL) { \
- SKIP(#__expression); \
- } \
- fprintf(stdout, "\n%s:%d: %s SKIP '!(%s)'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression); \
- exit(EXIT_SKIP); \
- } \
-} while (0)
-
-#define SKIP_IF_(__expression, ...) \
-do \
-{ \
- if ((__expression)) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- SKIP(#__expression, buffer); \
- } \
- fprintf(stdout, "\n%s:%d: %s SKIP '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer); \
- exit(EXIT_SKIP); \
- } \
-} while (0)
-
-#define SKIP_UNLESS(__expression) \
-do \
-{ \
- if (! (__expression)) { \
- if (YATL_FULL) { \
- SKIP(#__expression); \
- } \
- fprintf(stdout, "\n%s:%d: %s SKIP '(%s)'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression); \
- exit(EXIT_SKIP); \
- } \
-} while (0)
-
-#define SKIP_UNLESS_(__expression, ...) \
-do \
-{ \
- if (! (__expression)) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- SKIP(#__expression, buffer); \
- } \
- fprintf(stdout, "\n%s:%d: %s SKIP '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer); \
- exit(EXIT_SKIP); \
- } \
-} while (0)
-
-#define ASSERT_TRUE(__expression) \
-do \
-{ \
- if (! (__expression)) { \
- if (YATL_FULL) { \
- FAIL("Assertion '%s'", #__expression); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression);\
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_FALSE(__expression) \
-do \
-{ \
- if ((__expression)) { \
- if (YATL_FULL) { \
- FAIL("Assertion '!%s'", #__expression); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '!%s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression);\
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_NULL_(__expression, ...) \
-do \
-{ \
- if ((__expression) != NULL) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- FAIL("Assertion '%s' != NULL [ %s ]", #__expression, buffer);\
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%s' != NULL [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer);\
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_NOT_NULL(__expression) \
-do \
-{ \
- if ((__expression) == NULL) { \
- if (YATL_FULL) { \
- FAIL("Assertion '%s' == NULL", #__expression,);\
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%s' == NULL\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression,);\
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_NOT_NULL_(__expression, ...) \
-do \
-{ \
- if ((__expression) == NULL) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- FAIL("Assertion '%s' == NULL [ %s ]", #__expression, buffer);\
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%s' == NULL [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer);\
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_TRUE_(__expression, ...) \
-do \
-{ \
- if (! (__expression)) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- FAIL("Assertion '%s' [ %s ]", #__expression, buffer); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer); \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_EQ(__expected, __actual) \
-do \
-{ \
- if ((__expected) != (__actual)) { \
- if (YATL_FULL) { \
- FAIL("Assertion '%s' != '%s'", #__expected, #__actual); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%s' != '%s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expected, #__actual); \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_EQ_(__expected, __actual, ...) \
-do \
-{ \
- if ((__expected) != (__actual)) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- FAIL("Assertion '%s' != '%s' [ %s ]", #__expected, #__actual, buffer); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%s' != '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expected, #__actual, buffer); \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_STREQ(__expected_str, __actual_str) \
-do \
-{ \
- size_t __expected_length; \
- size_t __actual_length; \
- int ret= yatl_strcmp(__expected_str, __actual_str, &__expected_length, &__actual_length); \
- if (ret) { \
- if (YATL_FULL) { \
- FAIL("Assertion '%.*s' != '%.*s'\n", \
- (int)(__expected_length), (__expected_str), \
- (int)__actual_length, (__actual_str)) ; \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%.*s' != '%.*s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, \
- (int)(__expected_length), (__expected_str), \
- (int)__actual_length, (__actual_str)) ; \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_STREQ_(__expected_str, __actual_str, ...) \
-do \
-{ \
- size_t __expected_length; \
- size_t __actual_length; \
- int ret= yatl_strcmp(__expected_str, __actual_str, &__expected_length, &__actual_length); \
- if (ret) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- ask= snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- FAIL("Assertion '%.*s' != '%.*s' [ %.*s ]", \
- (int)(__expected_length), (__expected_str), \
- (int)(__actual_length), (__actual_str), \
- (int)(ask), buffer); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%.*s' != '%.*s' [ %.*s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, \
- (int)(__expected_length), (__expected_str), \
- (int)(__actual_length), (__actual_str), \
- (int)(ask), buffer); \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_STRNE(__expected_str, __actual_str) \
-do \
-{ \
- size_t __expected_length; \
- size_t __actual_length; \
- int ret= yatl_strcmp(__expected_str, __actual_str, &__expected_length, &__actual_length); \
- if (ret == 0) { \
- if (YATL_FULL) { \
- FAIL("Assertion '%.*s' == '%.*s'", \
- (int)(__expected_length), (__expected_str), \
- (int)__actual_length, (__actual_str)) ; \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%.*s' == '%.*s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, \
- (int)(__expected_length), (__expected_str), \
- (int)__actual_length, (__actual_str)) ; \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_STRNE_(__expected_str, __actual_str, ...) \
-do \
-{ \
- size_t __expected_length; \
- size_t __actual_length; \
- int ret= yatl_strcmp(__expected_str, __actual_str, &__expected_length, &__actual_length); \
- if (ret == 0) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- ask= snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- FAIL("Assertion '%.*s' == '%.*s' [ %.*s ]", \
- (int)(__expected_length), (__expected_str), \
- (int)(__actual_length), (__actual_str), \
- (int)(ask), buffer); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%.*s' == '%.*s' [ %.*s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, \
- (int)(__expected_length), (__expected_str), \
- (int)(__actual_length), (__actual_str), \
- (int)(ask), buffer); \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_NEQ(__expected, __actual) \
-do \
-{ \
- if ((__expected) == (__actual)) { \
- if (YATL_FULL) { \
- FAIL("Assertion '%s' == '%s'", #__expected, #__actual); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%s' == '%s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expected, #__actual); \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_NEQ_(__expected, __actual, ...) \
-do \
-{ \
- if ((__expected) == (__actual)) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- FAIL("Assertion '%s' == '%s' [ %s ]", #__expected, #__actual, buffer); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '%s' == '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expected, #__actual, buffer); \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
-
-#define ASSERT_FALSE_(__expression, ...) \
-do \
-{ \
- if ((__expression)) { \
- size_t ask= snprintf(0, 0, __VA_ARGS__); \
- ask++; \
- char *buffer= (char*)alloca(sizeof(char) * ask); \
- snprintf(buffer, ask, __VA_ARGS__); \
- if (YATL_FULL) { \
- FAIL("Assertion '!%s' [ %s ]", #__expression, buffer); \
- } \
- fprintf(stderr, "\n%s:%d: %s Assertion '!%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer); \
- exit(EXIT_FAILURE); \
- } \
-} while (0)
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <cassert>
-#include <cstdlib>
-#include <cstring>
-#include <ctime>
-#include <fnmatch.h>
-#include <iostream>
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#include <fstream>
-#include <memory>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <signal.h>
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-#if __cplusplus >= 201103L
-# define UNIQUE_PTR std::unique_ptr
-#else
-# define UNIQUE_PTR std::auto_ptr
-#endif
-
-using namespace libtest;
-
-static void stats_print(libtest::Framework *frame)
-{
- if (frame->failed() == 0 and frame->success() == 0)
- {
- return;
- }
-
- Outn();
- Out << "Collections\t\t\t\t\t" << frame->total();
- Out << "\tFailed\t\t\t\t\t" << frame->failed();
- Out << "\tSkipped\t\t\t\t\t" << frame->skipped();
- Out << "\tSucceeded\t\t\t\t" << frame->success();
- Outn();
- Out << "Tests\t\t\t\t\t" << frame->sum_total();
- Out << "\tFailed\t\t\t\t" << frame->sum_failed();
- Out << "\tSkipped\t\t\t\t" << frame->sum_skipped();
- Out << "\tSucceeded\t\t\t" << frame->sum_success();
-}
-
-#include <getopt.h>
-#include <unistd.h>
-
-int main(int argc, char *argv[])
-{
- bool opt_massive= false;
- unsigned long int opt_repeat= 1; // Run all tests once
- bool opt_quiet= false;
- std::string collection_to_run;
- std::string wildcard;
- std::string binary_name;
-
- const char *just_filename= rindex(argv[0], '/');
- if (just_filename)
- {
- just_filename++;
- }
- else
- {
- just_filename= argv[0];
- }
-
- if (just_filename[0] == 'l' and just_filename[1] == 't' and just_filename[2] == '-')
- {
- just_filename+= 3;
- }
- binary_name.append(just_filename);
-
- /*
- Valgrind does not currently work reliably, or sometimes at all, on OSX
- - Fri Jun 15 11:24:07 EDT 2012
- */
-#if defined(__APPLE__) && __APPLE__
- if (valgrind_is_caller())
- {
- return EXIT_SKIP;
- }
-#endif
-
- // Options parsing
- {
- enum long_option_t {
- OPT_LIBYATL_VERSION,
- OPT_LIBYATL_MATCH_COLLECTION,
- OPT_LIBYATL_MASSIVE,
- OPT_LIBYATL_QUIET,
- OPT_LIBYATL_MATCH_WILDCARD,
- OPT_LIBYATL_REPEAT
- };
-
- static struct option long_options[]=
- {
- { "version", no_argument, NULL, OPT_LIBYATL_VERSION },
- { "quiet", no_argument, NULL, OPT_LIBYATL_QUIET },
- { "repeat", required_argument, NULL, OPT_LIBYATL_REPEAT },
- { "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION },
- { "wildcard", required_argument, NULL, OPT_LIBYATL_MATCH_WILDCARD },
- { "massive", no_argument, NULL, OPT_LIBYATL_MASSIVE },
- { 0, 0, 0, 0 }
- };
-
- int option_index= 0;
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
- if (option_rv == -1)
- {
- break;
- }
-
- switch (option_rv)
- {
- case OPT_LIBYATL_VERSION:
- break;
-
- case OPT_LIBYATL_QUIET:
- opt_quiet= true;
- break;
-
- case OPT_LIBYATL_REPEAT:
- errno= 0;
- opt_repeat= strtoul(optarg, (char **) NULL, 10);
- if (errno != 0)
- {
- Error << "unknown value passed to --repeat: `" << optarg << "`";
- exit(EXIT_FAILURE);
- }
- break;
-
- case OPT_LIBYATL_MATCH_COLLECTION:
- collection_to_run= optarg;
- break;
-
- case OPT_LIBYATL_MATCH_WILDCARD:
- wildcard= optarg;
- break;
-
- case OPT_LIBYATL_MASSIVE:
- opt_massive= true;
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- Error << "unknown option to getopt_long()";
- exit(EXIT_FAILURE);
-
- default:
- break;
- }
- }
- }
-
- srandom((unsigned int)time(NULL));
-
- errno= 0;
- if (bool(getenv("YATL_REPEAT")))
- {
- errno= 0;
- opt_repeat= strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10);
- if (errno != 0)
- {
- Error << "ENV YATL_REPEAT passed an invalid value: `" << getenv("YATL_REPEAT") << "`";
- exit(EXIT_FAILURE);
- }
- }
-
- if ((bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "0") == 0)) or opt_quiet)
- {
- opt_quiet= true;
- }
- else if (getenv("JENKINS_URL"))
- {
- if (bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "1") == 0))
- { }
- else
- {
- opt_quiet= true;
- }
- }
-
- if ((bool(getenv("YATL_RUN_MASSIVE_TESTS"))) or opt_massive)
- {
- opt_massive= true;
- }
-
- if (opt_quiet)
- {
- close(STDOUT_FILENO);
- }
-
- if (opt_massive)
- {
- is_massive(opt_massive);
- }
-
- libtest::vchar_t tmp_directory;
- tmp_directory.resize(1024);
- if (getenv("LIBTEST_TMP"))
- {
- snprintf(&tmp_directory[0], tmp_directory.size(), "%s", getenv("LIBTEST_TMP"));
- }
- else
- {
- snprintf(&tmp_directory[0], tmp_directory.size(), "%s", LIBTEST_TEMP);
- }
-
- if (chdir(&tmp_directory[0]) == -1)
- {
- libtest::vchar_t getcwd_buffer;
- getcwd_buffer.resize(1024);
- char *dir= getcwd(&getcwd_buffer[0], getcwd_buffer.size());
-
- Error << "Unable to chdir() from " << dir << " to " << &tmp_directory[0] << " errno:" << strerror(errno);
- return EXIT_FAILURE;
- }
-
- if (getenv("YATL_COLLECTION_TO_RUN"))
- {
- if (strlen(getenv("YATL_COLLECTION_TO_RUN")))
- {
- collection_to_run= getenv("YATL_COLLECTION_TO_RUN");
- }
- }
-
- if (collection_to_run.compare("none") == 0)
- {
- return EXIT_SUCCESS;
- }
-
- if (collection_to_run.empty() == false)
- {
- Out << "Only testing " << collection_to_run;
- }
-
- int exit_code;
-
- try
- {
- do
- {
- exit_code= EXIT_SUCCESS;
- fatal_assert(sigignore(SIGPIPE) == 0);
-
- libtest::SignalThread signal;
- if (signal.setup() == false)
- {
- Error << "Failed to setup signals";
- return EXIT_FAILURE;
- }
-
- UNIQUE_PTR<libtest::Framework> frame(new libtest::Framework(signal, binary_name, collection_to_run, wildcard));
-
- // Run create(), bail on error.
- {
- switch (frame->create())
- {
- case TEST_SUCCESS:
- break;
-
- case TEST_SKIPPED:
- SKIP("SKIP was returned from framework create()");
- break;
-
- case TEST_FAILURE:
- std::cerr << "Could not call frame->create()" << std::endl;
- return EXIT_FAILURE;
- }
- }
-
- frame->exec();
-
- if (signal.is_shutdown() == false)
- {
- signal.set_shutdown(SHUTDOWN_GRACEFUL);
- }
-
- shutdown_t status= signal.get_shutdown();
- if (status == SHUTDOWN_FORCED)
- {
- Out << "Tests were aborted.";
- exit_code= EXIT_FAILURE;
- }
- else if (frame->failed())
- {
- Out << "Some test failed.";
- exit_code= EXIT_FAILURE;
- }
- else if (frame->skipped() and frame->failed() and frame->success())
- {
- Out << "Some tests were skipped.";
- }
- else if (frame->success() and (frame->failed() == 0))
- {
- Out;
- Out << "All tests completed successfully.";
- }
-
- stats_print(frame.get());
-
- std::ofstream xml_file;
- std::string file_name;
- file_name.append(&tmp_directory[0]);
- file_name.append(frame->name());
- file_name.append(".xml");
- xml_file.open(file_name.c_str(), std::ios::trunc);
- libtest::Formatter::xml(*frame, xml_file);
-
- Outn(); // Generate a blank to break up the messages if make check/test has been run
- } while (exit_code == EXIT_SUCCESS and --opt_repeat);
- }
- catch (const libtest::__skipped& e)
- {
- return EXIT_SKIP;
- }
- catch (const libtest::__failure& e)
- {
- libtest::stream::make_cout(e.file(), e.line(), e.func()) << e.what();
- exit_code= EXIT_FAILURE;
- }
- catch (const libtest::fatal& e)
- {
- std::cerr << "FATAL:" << e.what() << std::endl;
- exit_code= EXIT_FAILURE;
- }
- catch (const libtest::disconnected& e)
- {
- std::cerr << "Unhandled disconnection occurred:" << e.what() << std::endl;
- exit_code= EXIT_FAILURE;
- }
- catch (const std::exception& e)
- {
- std::cerr << "std::exception:" << e.what() << std::endl;
- exit_code= EXIT_FAILURE;
- }
- catch (char const* s)
- {
- std::cerr << "Exception:" << s << std::endl;
- exit_code= EXIT_FAILURE;
- }
- catch (...)
- {
- std::cerr << "Unknown exception halted execution." << std::endl;
- exit_code= EXIT_FAILURE;
- }
-
- return exit_code;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include "libtest/common.h"
-
-#include <cassert>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <libtest/server.h>
-#include <libtest/wait.h>
-
-#include <libtest/memcached.h>
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-namespace libtest {
-
-class Memcached : public libtest::Server
-{
- std::string _username;
- std::string _password;
-
-public:
- Memcached(const std::string& host_arg,
- const in_port_t port_arg,
- const bool is_socket_arg,
- const std::string& username_arg,
- const std::string& password_arg) :
- libtest::Server(host_arg, port_arg,
- memcached_binary(), false, is_socket_arg),
- _username(username_arg),
- _password(password_arg)
- { }
-
- Memcached(const std::string& host_arg, const in_port_t port_arg, const bool is_socket_arg) :
- libtest::Server(host_arg, port_arg,
- memcached_binary(), false, is_socket_arg)
- {
- set_pid_file();
- }
-
- virtual const char *sasl() const
- {
- return "-S";
- }
-
- bool is_sasl() const
- {
- return _username.size() && _password.size();
- }
-
- const std::string& password() const
- {
- return _password;
- }
-
- const std::string& username() const
- {
- return _username;
- }
-
- bool wait_for_pidfile() const
- {
- Wait wait(pid(), 4);
-
- return wait.successful();
- }
-
- bool ping()
- {
- if (out_of_ban_killed())
- {
- return false;
- }
-
- if (is_socket() or is_sasl())
- {
- return _app.check();
- }
-
- SimpleClient client(_hostname, _port);
-
- std::string response;
- return client.send_message("version", response);
- }
-
- const char *name()
- {
- return "memcached";
- };
-
- const char *executable()
- {
- return memcached_binary();
- }
-
- bool is_libtool()
- {
- return false;
- }
-
- virtual void pid_file_option(Application& app, const std::string& arg)
- {
- if (arg.empty() == false)
- {
- app.add_option("-P", arg);
- }
- }
-
- const char *socket_file_option() const
- {
- return "-s ";
- }
-
- virtual void port_option(Application& app, in_port_t arg)
- {
- char buffer[30];
- snprintf(buffer, sizeof(buffer), "%d", int(arg));
- app.add_option("-p", buffer);
-
- if(!is_sasl())
- {
- app.add_option("-U", buffer);
- }
- }
-
- bool has_port_option() const
- {
- return true;
- }
-
- bool has_socket_file_option() const
- {
- return has_socket();
- }
-
- void socket_file_option(Application& app, const std::string& socket_arg)
- {
- if (socket_arg.empty() == false)
- {
- app.add_option("-s", socket_arg);
- }
- }
-
- bool broken_socket_cleanup()
- {
- return true;
- }
-
- // Memcached's pidfile is broken
- bool broken_pid_file()
- {
- return true;
- }
-
- bool build();
-};
-
-
-#include <sstream>
-
-bool Memcached::build()
-{
- if (getuid() == 0 or geteuid() == 0)
- {
- add_option("-u", "root");
- }
-
- add_option("-l", "localhost");
-#ifdef __APPLE__
-#else
- add_option("-m", "128");
- add_option("-M");
-#endif
-
- if (is_sasl())
- {
- add_option(sasl());
- }
-
- //add_option("-vvv");
-
- return true;
-}
-
-libtest::Server *build_memcached(const std::string& hostname, const in_port_t try_port)
-{
- if (has_memcached())
- {
- return new Memcached(hostname, try_port, false);
- }
-
- return NULL;
-}
-
-libtest::Server *build_memcached_socket(const std::string& socket_file, const in_port_t try_port)
-{
- if (has_memcached())
- {
- return new Memcached(socket_file, try_port, true);
- }
-
- return NULL;
-}
-
-libtest::Server *build_memcached_sasl(const std::string &hostname, const in_port_t try_port, const std::string &username, const std::string &password)
-{
- if (has_memcached())
- {
- return new Memcached(hostname, try_port, false, username, password);
- }
-
- return NULL;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-libtest::Server *build_memcached(const std::string& hostname, const in_port_t try_port);
-
-libtest::Server *build_memcached_socket(const std::string& socket_file, const in_port_t try_port);
-
-libtest::Server *build_memcached_sasl(const std::string &hostname, const in_port_t try_port, const std::string &username, const std::string &password);
-
-}
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#if defined(HAVE_LIBMEMCACHED) && HAVE_LIBMEMCACHED
-inline bool operator== (const memcached_st& memc, const memcached_return_t rc)
-{
- if (memcached_last_error(const_cast<memcached_st *>(&memc)) == rc)
- {
- return true;
- }
-
- return false;
-}
-
-inline bool operator!= (const memcached_st& memc, memcached_return_t rc)
-{
- if (memcached_last_error(const_cast<memcached_st *>(&memc)) != rc)
- {
- return true;
- }
-
- return false;
-}
-
-inline bool operator== (memcached_st* const memc, memcached_return_t rc)
-{
- if (memcached_last_error(memc) == rc)
- {
- return true;
- }
-
- return false;
-}
-
-inline bool operator!= (memcached_st* const memc, memcached_return_t rc)
-{
- if (memcached_last_error(memc) != rc)
- {
- return true;
- }
-
- return false;
-}
-
-inline bool operator!= (memcached_return_t rc, const memcached_st& memc)
-{
- if (memcached_last_error(const_cast<memcached_st *>(&memc)) != rc)
- {
- return true;
- }
-
- return false;
-}
-
-inline bool operator!= (memcached_return_t rc, memcached_st* const memc)
-{
- if (memcached_last_error(memc) != rc)
- {
- return true;
- }
-
- return false;
-}
-#endif
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- Structures for generic tests.
-*/
-
-#include <cstdio>
-#include <poll.h>
-
-void print_poll(pollfd& fds)
-{
- if (fds.revents & POLLERR)
- {
- fprintf(stderr, "\tPOLLERR\n");
- }
-
- if (fds.revents & POLLHUP)
- {
- fprintf(stderr, "\tPOLLHUP\n");
- }
-
- if (fds.revents & POLLIN)
- {
- fprintf(stderr, "\tPOLLIN\n");
- }
-
- if (fds.revents & POLLIN)
- {
- fprintf(stderr, "\tPOLLIN\n");
- }
-
- if (fds.revents & POLLNVAL)
- {
- fprintf(stderr, "\tPOLLNVAL\n");
- }
-
- if (fds.revents & POLLOUT)
- {
- fprintf(stderr, "\tPOLLOUT\n");
- }
-
- if (fds.revents & POLLPRI)
- {
- fprintf(stderr, "\tPOLLPRI\n");
- }
-
- if (fds.revents & POLLRDBAND)
- {
- fprintf(stderr, "\tPOLLPRI\n");
- }
-
- if (fds.revents & POLLRDNORM)
- {
- fprintf(stderr, "\tPOLLRDNORM\n");
- }
-
- if (fds.revents & POLLWRBAND)
- {
- fprintf(stderr, "\tPOLLWRBAND\n");
- }
-
- if (fds.revents & POLLWRNORM)
- {
- fprintf(stderr, "\tPOLLWRNORM\n");
- }
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <cassert>
-#include <cstdlib>
-#include <cstring>
-#include <ctime>
-#include <fnmatch.h>
-#include <iostream>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <utility>
-#include <vector>
-
-#include <signal.h>
-
-#include <libtest/signal.h>
-
-#ifndef SOCK_CLOEXEC
-# define SOCK_CLOEXEC 0
-#endif
-
-#ifndef SOCK_NONBLOCK
-# define SOCK_NONBLOCK 0
-#endif
-
-#ifndef FD_CLOEXEC
-# define FD_CLOEXEC 0
-#endif
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-using namespace libtest;
-
-struct socket_st {
- typedef std::vector< std::pair< int, in_port_t> > socket_port_t;
- socket_port_t _pair;
- in_port_t last_port;
-
- socket_st():
- last_port(0)
- { }
-
- void release(in_port_t _arg)
- {
- for (socket_port_t::iterator iter= _pair.begin();
- iter != _pair.end();
- ++iter)
- {
- if ((*iter).second == _arg)
- {
- shutdown((*iter).first, SHUT_RDWR);
- close((*iter).first);
- }
- }
- }
-
- ~socket_st()
- {
- for (socket_port_t::iterator iter= _pair.begin();
- iter != _pair.end();
- ++iter)
- {
- shutdown((*iter).first, SHUT_RDWR);
- close((*iter).first);
- }
- }
-};
-
-static socket_st all_socket_fd;
-
-static in_port_t global_port= 0;
-
-namespace libtest {
-
-in_port_t default_port()
-{
- if (global_port == 0)
- {
- global_port= get_free_port();
- }
-
- return global_port;
-}
-
-void release_port(in_port_t arg)
-{
- all_socket_fd.release(arg);
-}
-
-in_port_t get_free_port()
-{
- const in_port_t default_port= in_port_t(-1);
-
- int retries= 1024;
-
- in_port_t ret_port;
- while (--retries)
- {
- ret_port= default_port;
- int sd;
- if ((sd= socket(AF_INET, SOCK_STREAM, 0)) != SOCKET_ERROR)
- {
- int optval= 1;
- if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != SOCKET_ERROR)
- {
- struct sockaddr_in sin;
- sin.sin_port= 0;
- sin.sin_addr.s_addr= 0;
- sin.sin_addr.s_addr= INADDR_ANY;
- sin.sin_family= AF_INET;
-
- int bind_ret;
- do
- {
- if ((bind_ret= bind(sd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in) )) != SOCKET_ERROR)
- {
- socklen_t addrlen= sizeof(sin);
-
- if (getsockname(sd, (struct sockaddr *)&sin, &addrlen) != -1)
- {
- ret_port= sin.sin_port;
- }
- }
- else
- {
- if (errno != EADDRINUSE)
- {
- Error << strerror(errno);
- }
- }
-
- if (errno == EADDRINUSE)
- {
- libtest::dream(2, 0);
- }
- } while (bind_ret == -1 and errno == EADDRINUSE);
-
- all_socket_fd._pair.push_back(std::make_pair(sd, ret_port));
- }
- else
- {
- Error << strerror(errno);
- }
- }
- else
- {
- Error << strerror(errno);
- }
-
- if (ret_port == default_port)
- {
- Error << "no ret_port set:" << strerror(errno);
- }
- else if (ret_port > 1024 and ret_port != all_socket_fd.last_port)
- {
- break;
- }
- }
-
- // We handle the case where if we max out retries, we still abort.
- if (retries == 0)
- {
- FATAL("No port could be found, exhausted retry");
- }
-
- if (ret_port == 0)
- {
- FATAL("No port could be found");
- }
-
- if (ret_port == default_port)
- {
- FATAL("No port could be found");
- }
-
- if (ret_port <= 1024)
- {
- FATAL("No port could be found, though some where available below or at 1024");
- }
-
- all_socket_fd.last_port= ret_port;
- release_port(ret_port);
-
- return ret_port;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- Structures for generic tests.
-*/
-
-#pragma once
-
-#define LIBTEST_FAIL_PORT 23
-
-namespace libtest {
-
-LIBTEST_API
-in_port_t default_port();
-
-LIBTEST_API
-in_port_t get_free_port();
-
-LIBTEST_API
-void release_port(in_port_t arg);
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-#include <cstdarg>
-
-namespace libtest {
-
-__test_result::__test_result(const char *file_arg, int line_arg, const char *func_arg):
- libtest::exception(file_arg, line_arg, func_arg)
- {
- }
-
-__success::__success(const char *file_arg, int line_arg, const char *func_arg):
- __test_result(file_arg, line_arg, func_arg)
-{
-}
-
-__skipped::__skipped(const char *file_arg, int line_arg, const char *func_arg, ...):
- __test_result(file_arg, line_arg, func_arg)
-{
- va_list args;
- va_start(args, func_arg);
- init(args);
- va_end(args);
-}
-
-__skipped::__skipped(const __skipped& other) :
- __test_result(other)
-{
-}
-
-__failure::__failure(const char *file_arg, int line_arg, const char *func_arg, ...) :
- __test_result(file_arg, line_arg, func_arg)
-{
- va_list args;
- va_start(args, func_arg);
- init(args);
- va_end(args);
-}
-
-__failure::__failure(const __failure& other) :
- __test_result(other)
-{
-}
-
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libtest/result/base.hpp>
-#include <libtest/result/fail.hpp>
-#include <libtest/result/skip.hpp>
-#include <libtest/result/success.hpp>
-
-#define _SUCCESS throw libtest::__success(LIBYATL_DEFAULT_PARAM)
-
-#define SKIP(...) \
-do \
-{ \
- throw libtest::__skipped(LIBYATL_DEFAULT_PARAM, __VA_ARGS__); \
-} while (0)
-
-#define FAIL(...) \
-do \
-{ \
- throw libtest::__failure(LIBYATL_DEFAULT_PARAM, __VA_ARGS__); \
-} while (0)
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include "libtest/exception.hpp"
-#include "libtest/error.h"
-
-namespace libtest {
-
-class __test_result : public libtest::exception
-{
-public:
- __test_result(const char *file, int line, const char *func);
-
- virtual test_return_t return_code() const= 0;
-
-private:
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-class __failure : public __test_result
-{
-public:
- __failure(const char *file, int line, const char *func, ...);
-
- __failure(const __failure&);
-
- test_return_t return_code() const
- {
- return TEST_FAILURE;
- }
-
-private:
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-class __skipped : public __test_result
-{
-public:
- __skipped(const char *file, int line, const char *func, ...);
-
- __skipped(const __skipped&);
-
- test_return_t return_code() const
- {
- return TEST_SKIPPED;
- }
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-class __success : public __test_result
-{
-public:
- __success(const char *file, int line, const char *func);
-
- const char* what() const throw()
- {
- return "SUCCESS";
- }
-
- test_return_t return_code() const
- {
- return TEST_SUCCESS;
- }
-
-private:
-};
-
-} // namespace libtest
+++ /dev/null
-set logging on
-set logging overwrite on
-set environment LIBTEST_IN_GDB=1
-set ASAN_OPTIONS=abort_on_error=1
-run
-thread apply all bt
-quit
+++ /dev/null
-set logging on
-set logging overwrite on
-set environment LIBTEST_IN_GDB=1
-#set ASAN_OPTIONS=abort_on_error=1
-handle SIGVTALRM stop
-run
-thread apply all bt
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-namespace libtest {
-
-Runner::Runner() :
- _servers(NULL)
-{
-}
-
-test_return_t Runner::main(test_callback_fn* func, void *object)
-{
- test_return_t ret;
- try {
- ret= run(func, object);
- }
- catch (const libtest::__skipped& e)
- {
- ret= TEST_SKIPPED;
- }
- catch (const libtest::__failure& e)
- {
- libtest::stream::make_cerr(e.file(), e.line(), e.func()) << e.what();
- ret= TEST_FAILURE;
- }
- catch (const libtest::__success&)
- {
- ret= TEST_SUCCESS;
- }
- catch (const libtest::fatal&)
- {
- throw;
- }
- catch (const std::exception& e)
- {
- libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << e.what();
- throw;
- }
- catch (...)
- {
- libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << "Unknown exception thrown";
- throw;
- }
-
- return ret;
-}
-
-test_return_t Runner::setup(test_callback_fn* func, void *object)
-{
- test_return_t ret;
- try {
- ret= pre(func, object);
- }
- catch (const libtest::__skipped& e)
- {
- ret= TEST_SKIPPED;
- }
- catch (const libtest::__failure& e)
- {
- libtest::stream::make_cout(e.file(), e.line(), e.func()) << e.what();
- ret= TEST_FAILURE;
- }
- catch (const libtest::__success&)
- {
- ret= TEST_SUCCESS;
- }
- catch (const libtest::fatal& e)
- {
- throw;
- }
- catch (const std::exception& e)
- {
- libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << e.what();
- throw;
- }
- catch (...)
- {
- libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << "Unknown exception thrown";
- throw;
- }
-
- return ret;
-}
-
-test_return_t Runner::teardown(test_callback_fn* func, void *object)
-{
- test_return_t ret;
- try {
- ret= post(func, object);
- }
- catch (const libtest::__skipped& e)
- {
- ret= TEST_SKIPPED;
- }
- catch (const libtest::__failure& e)
- {
- libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << e.what();
- ret= TEST_FAILURE;
- }
- catch (const libtest::__success&)
- {
- ret= TEST_SUCCESS;
- }
- catch (const libtest::fatal& e)
- {
- throw;
- }
- catch (const std::exception& e)
- {
- libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << e.what();
- throw;
- }
- catch (...)
- {
- libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << "Unknown exception thrown";
- throw;
- }
-
- return ret;
-}
-
-test_return_t Runner::flush(void*)
-{
- return TEST_SUCCESS;
-}
-
-test_return_t Runner::run(test_callback_fn* func, void *object)
-{
- if (func)
- {
- return func(object);
- }
-
- return TEST_SUCCESS;
-}
-
-test_return_t Runner::pre(test_callback_fn* func, void *object)
-{
- if (func)
- {
- return func(object);
- }
-
- return TEST_SUCCESS;
-}
-
-test_return_t Runner::post(test_callback_fn* func, void *object)
-{
- if (func)
- {
- return func(object);
- }
-
- return TEST_SUCCESS;
-}
-
-void Runner::set_servers(libtest::server_startup_st& arg)
-{
- _servers= &arg;
-}
-
-bool Runner::check()
-{
- return _servers ? _servers->check() : true;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-namespace libtest {
-
-/**
- Structure which houses the actual callers for the test cases contained in
- the collections.
-*/
-class Runner {
-public:
- test_return_t main(test_callback_fn* func, void *object);
- test_return_t setup(test_callback_fn* func, void *object);
- test_return_t teardown(test_callback_fn* func, void *object);
-
- Runner();
-
- void set_servers(libtest::server_startup_st& arg);
-
- bool check();
-
- virtual ~Runner() { }
-
- virtual test_return_t flush(void*);
- virtual test_return_t run(test_callback_fn* func, void *object);
- virtual test_return_t pre(test_callback_fn* func, void *object);
- virtual test_return_t post(test_callback_fn* func, void *object);
-
-private:
- libtest::server_startup_st* _servers;
-
-private:
- Runner( const Runner& );
- const Runner& operator=( const Runner& );
-};
-
-} // namespace Runner
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/common.h>
-
-#include <cassert>
-#include <cerrno>
-#include <climits>
-#include <cstdlib>
-#include <iostream>
-#include <string>
-
-#include <algorithm>
-#include <functional>
-#include <locale>
-#include <unistd.h>
-
-// trim from end
-static inline std::string &rtrim(std::string &s)
-{
- s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
- return s;
-}
-
-#include <libtest/server.h>
-#include <libtest/stream.h>
-#include <libtest/killpid.h>
-
-namespace libtest {
-
-std::ostream& operator<<(std::ostream& output, const Server &arg)
-{
- if (arg.is_socket())
- {
- output << arg.hostname();
- }
- else
- {
- output << arg.hostname() << ":" << arg.port();
- }
-
- if (arg.has_pid())
- {
- output << " Pid:" << arg.pid();
- }
-
- if (arg.has_socket())
- {
- output << " Socket:" << arg.socket();
- }
-
- if (arg.running().empty() == false)
- {
- output << " Exec:" << arg.running();
- }
-
- return output; // for multiple << operators
-}
-
-#ifdef __GLIBC__
-namespace {
-
-class Buffer
-{
-public:
- Buffer(char *b) : b_(b) {}
- ~Buffer() { if (b_) free(b_); }
- char* buf() { return b_; }
-private:
- char *b_;
-};
-
-}
-#endif // __GLIBC__
-
-#define MAGIC_MEMORY 123570
-
-Server::Server(const std::string& host_arg, const in_port_t port_arg,
- const std::string& executable, const bool _is_libtool,
- bool is_socket_arg) :
- _magic(MAGIC_MEMORY),
- _is_socket(is_socket_arg),
- _port(port_arg),
- _hostname(host_arg),
- _app(executable, _is_libtool),
- out_of_ban_killed_(false),
- _timeout(40)
-{
-}
-
-Server::~Server()
-{
- kill();
-}
-
-bool Server::check()
-{
- _app.clear();
- return _app.check();
-}
-
-bool Server::validate()
-{
- return _magic == MAGIC_MEMORY;
-}
-
-// If the server exists, kill it
-bool Server::cycle()
-{
- uint32_t limit= 3;
-
- // Try to ping, and kill the server #limit number of times
- while (--limit and
- is_pid_valid(_app.pid()))
- {
- if (kill())
- {
- Log << "Killed existing server," << *this;
- dream(0, 50000);
- continue;
- }
- }
-
- // For whatever reason we could not kill it, and we reached limit
- if (limit == 0)
- {
- Error << "Reached limit, could not kill server";
- return false;
- }
-
- return true;
-}
-
-bool Server::wait_for_pidfile() const
-{
- Wait wait(pid_file(), 4);
-
- return wait.successful();
-}
-
-bool Server::init(const char *argv[])
-{
- if (argv)
- {
- for (const char **ptr= argv; *ptr ; ++ptr)
- {
- if (ptr)
- {
- add_option(*ptr);
- }
- }
- }
-
- return build();
-}
-
-bool Server::has_pid() const
-{
- return (_app.pid() > 1);
-}
-
-
-bool Server::start()
-{
- if (getenv("YATL_GDB_SERVER"))
- {
- _app.use_gdb(true);
- }
-
- if (port() == LIBTEST_FAIL_PORT)
- {
- throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
- hostname(), port(), "Called failure");
- }
-
- if (getenv("YATL_PTRCHECK_SERVER"))
- {
- _app.use_ptrcheck(true);
- }
- else if (getenv("YATL_VALGRIND_SERVER"))
- {
- _app.use_valgrind(true);
- }
-
- out_of_ban_killed(false);
- if (args(_app) == false)
- {
- throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
- hostname(), port(), "Could not build command()");
- }
-
- libtest::release_port(_port);
-
- Application::error_t ret;
- if (Application::SUCCESS != (ret= _app.run()))
- {
- throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
- hostname(), port(), "Application::run() %s", libtest::Application::toString(ret));
- return false;
- }
- _running= _app.print();
-
- if (valgrind_is_caller())
- {
- dream(5, 50000);
- }
-
- size_t repeat= 5;
- _app.slurp();
- while (--repeat)
- {
- if (pid_file().empty() == false)
- {
- Wait wait(pid_file(), 8);
-
- if (wait.successful() == false)
- {
- if (_app.check())
- {
- _app.slurp();
- continue;
- }
-
-#ifdef __GLIBC__
- Buffer buf( get_current_dir_name());
- char *getcwd_buf= buf.buf();
-#else
- libtest::vchar_t buf;
- buf.resize(PATH_MAX);
- char *getcwd_buf= getcwd(&buf[0], buf.size());
-#endif // __GLIBC__
- throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
- hostname(), port(),
- "Unable to open pidfile in %s for: %s stderr:%s",
- getcwd_buf ? getcwd_buf : "",
- _running.c_str(),
- _app.stderr_c_str());
- }
- }
- }
-
- bool pinged= false;
- uint32_t this_wait= 0;
- {
- uint32_t waited;
- uint32_t retry;
-
- for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
- {
- if (_app.check() == false)
- {
- break;
- }
-
- if ((pinged= ping()) == true)
- {
- break;
- }
- else if (waited >= _timeout)
- {
- break;
- }
-
- this_wait= retry * retry / 3 + 1;
- libtest::dream(this_wait, 0);
- }
- }
-
- if (pinged == false)
- {
-#if 0
- Error << "Failed to ping(" << _app.pid() << ") wait: " << this_wait << " " << hostname() << ":" << port() << " run:" << _running << " " << error();
-#endif
-
- // If we happen to have a pid file, lets try to kill it
- if ((pid_file().empty() == false) and (access(pid_file().c_str(), R_OK) == 0))
- {
- _app.slurp();
- if (kill_file(pid_file()) == false)
- {
- throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
- hostname(), port(),
- "Failed to kill off server, waited: %u after startup occurred, when pinging failed: %.*s stderr:%.*s",
- this_wait,
- int(_running.size()), _running.c_str(),
- int(_app.stderr_result_length()), _app.stderr_c_str());
- }
- else
- {
- throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
- hostname(), port(),
- "Failed native ping(), pid: %d was alive: %s waited: %u server started, having pid_file. exec: %.*s stderr:%.*s",
- int(_app.pid()),
- _app.check() ? "true" : "false",
- this_wait,
- int(_running.size()), _running.c_str(),
- int(_app.stderr_result_length()), _app.stderr_c_str());
- }
- }
- else
- {
- throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
- hostname(), port(),
- "Failed native ping(), pid: %d is alive: %s waited: %u server started. exec: %.*s stderr:%.*s",
- int(_app.pid()),
- _app.check() ? "true" : "false",
- this_wait,
- int(_running.size()), _running.c_str(),
- int(_app.stderr_result_length()), _app.stderr_c_str());
- }
- _running.clear();
-
- return false;
- }
-
- return has_pid();
-}
-
-void Server::reset_pid()
-{
- _running.clear();
- _pid_file.clear();
-}
-
-pid_t Server::pid() const
-{
- return _app.pid();
-}
-
-void Server::add_option(const std::string& arg)
-{
- _options.push_back(std::make_pair(arg, std::string()));
-}
-
-void Server::add_option(const std::string& name_, const std::string& value_)
-{
- _options.push_back(std::make_pair(name_, value_));
-}
-
-bool Server::set_socket_file()
-{
- libtest::vchar_t file_buffer;
- file_buffer.resize(FILENAME_MAX);
- file_buffer[0]= 0;
-
- if (broken_pid_file())
- {
- snprintf(&file_buffer[0], file_buffer.size(), "/tmp/%s.socketXXXXXX", name());
- }
- else
- {
- snprintf(&file_buffer[0], file_buffer.size(), "var/run/%s.socketXXXXXX", name());
- }
-
- int fd;
- if ((fd= mkstemp(&file_buffer[0])) == -1)
- {
- perror(&file_buffer[0]);
- return false;
- }
- close(fd);
- unlink(&file_buffer[0]);
-
- _socket= &file_buffer[0];
-
- return true;
-}
-
-bool Server::set_pid_file()
-{
- libtest::vchar_t file_buffer;
- file_buffer.resize(FILENAME_MAX);
- file_buffer[0]= 0;
-
- if (broken_pid_file())
- {
- snprintf(&file_buffer[0], file_buffer.size(), "/tmp/%s.pidXXXXXX", name());
- }
- else
- {
- snprintf(&file_buffer[0], file_buffer.size(), "var/run/%s.pidXXXXXX", name());
- }
-
- int fd;
- if ((fd= mkstemp(&file_buffer[0])) == -1)
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", &file_buffer[0], strerror(errno));
- }
- close(fd);
- unlink(&file_buffer[0]);
-
- _pid_file= &file_buffer[0];
-
- return true;
-}
-
-bool Server::set_log_file()
-{
- libtest::vchar_t file_buffer;
- file_buffer.resize(FILENAME_MAX);
- file_buffer[0]= 0;
-
- snprintf(&file_buffer[0], file_buffer.size(), "var/log/%s.logXXXXXX", name());
- int fd;
- if ((fd= mkstemp(&file_buffer[0])) == -1)
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", &file_buffer[0], strerror(errno));
- }
- close(fd);
-
- _log_file= &file_buffer[0];
-
- return true;
-}
-
-bool Server::args(Application& app)
-{
-
- // Set a log file if it was requested (and we can)
- if (has_log_file_option())
- {
- set_log_file();
- log_file_option(app, _log_file);
- }
-
- if (getenv("LIBTEST_SYSLOG") and has_syslog())
- {
- app.add_option("--syslog");
- }
-
- // Update pid_file
- {
- if (_pid_file.empty() and set_pid_file() == false)
- {
- return false;
- }
-
- pid_file_option(app, pid_file());
- }
-
- if (has_socket_file_option())
- {
- if (set_socket_file() == false)
- {
- return false;
- }
-
- socket_file_option(app, _socket);
- }
-
- if (has_port_option())
- {
- port_option(app, _port);
- }
-
- for (Options::const_iterator iter= _options.begin(); iter != _options.end(); ++iter)
- {
- if ((*iter).first.empty() == false)
- {
- if ((*iter).second.empty() == false)
- {
- app.add_option((*iter).first, (*iter).second);
- }
- else
- {
- app.add_option((*iter).first);
- }
- }
- }
-
- return true;
-}
-
-bool Server::kill()
-{
- if (check_pid(_app.pid())) // If we kill it, reset
- {
- _app.murder();
- if (broken_pid_file() and pid_file().empty() == false)
- {
- unlink(pid_file().c_str());
- }
-
- if (broken_socket_cleanup() and has_socket() and not socket().empty())
- {
- unlink(socket().c_str());
- }
-
- reset_pid();
-
- return true;
- }
-
- return false;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libtest/cmdline.h>
-
-#include <cassert>
-#include <cstdio>
-#include <cstring>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <string>
-#include <unistd.h>
-#include <vector>
-
-namespace libtest {
-
-struct Server {
-private:
- typedef std::vector< std::pair<std::string, std::string> > Options;
-
-private:
- uint64_t _magic;
- bool _is_socket;
- std::string _socket;
- std::string _sasl;
- std::string _pid_file;
- std::string _log_file;
- std::string _base_command; // executable command which include libtool, valgrind, gdb, etc
- std::string _running; // Current string being used for system()
-
-protected:
- in_port_t _port;
- std::string _hostname;
- std::string _extra_args;
-
-public:
- Server(const std::string& hostname, const in_port_t port_arg,
- const std::string& executable, const bool _is_libtool,
- const bool is_socket_arg= false);
-
- virtual ~Server();
-
- virtual const char *name()= 0;
- virtual bool is_libtool()= 0;
-
- virtual bool has_socket_file_option() const
- {
- return false;
- }
-
- virtual void socket_file_option(Application& app, const std::string& socket_arg)
- {
- if (socket_arg.empty() == false)
- {
- std::string buffer("--socket=");
- buffer+= socket_arg;
- app.add_option(buffer);
- }
- }
-
- virtual bool has_log_file_option() const
- {
- return false;
- }
-
- virtual void log_file_option(Application& app, const std::string& arg)
- {
- if (arg.empty() == false)
- {
- std::string buffer("--log-file=");
- buffer+= arg;
- app.add_option(buffer);
- }
- }
-
- virtual void pid_file_option(Application& app, const std::string& arg)
- {
- if (arg.empty() == false)
- {
- std::string buffer("--pid-file=");
- buffer+= arg;
- app.add_option(buffer);
- }
- }
-
- virtual bool has_port_option() const
- {
- return false;
- }
-
- virtual void port_option(Application& app, in_port_t arg)
- {
- if (arg > 0)
- {
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "--port=%d", int(arg));
- app.add_option(buffer);
- }
- }
-
- virtual bool broken_socket_cleanup()
- {
- return false;
- }
-
- virtual bool broken_pid_file()
- {
- return false;
- }
-
- const std::string& pid_file() const
- {
- return _pid_file;
- }
-
- const std::string& base_command() const
- {
- return _base_command;
- }
-
- const std::string& log_file() const
- {
- return _log_file;
- }
-
- const std::string& hostname() const
- {
- return _hostname;
- }
-
- const std::string& socket() const
- {
- return _socket;
- }
-
- bool has_socket() const
- {
- return _is_socket;
- }
-
- bool cycle();
-
- virtual bool ping()= 0;
-
- bool init(const char *argv[]);
- virtual bool build()= 0;
-
- void add_option(const std::string&);
- void add_option(const std::string&, const std::string&);
-
- in_port_t port() const
- {
- return _port;
- }
-
- bool has_port() const
- {
- return (_port != 0);
- }
-
- virtual bool has_syslog() const
- {
- return false;
- }
-
- // Reset a server if another process has killed the server
- void reset()
- {
- _pid_file.clear();
- _log_file.clear();
- }
-
- std::pair<std::string, std::string> output()
- {
- return _app.output();
- }
-
- pid_t pid() const;
-
- bool has_pid() const;
-
- virtual bool has_pid_file() const
- {
- return true;
- }
-
- const std::string& error()
- {
- return _error;
- }
-
- void error(std::string arg)
- {
- _error= arg;
- }
-
- void reset_error()
- {
- _error.clear();
- }
-
- virtual bool wait_for_pidfile() const;
-
- bool check_pid(pid_t pid_arg) const
- {
- return (pid_arg > 1);
- }
-
- bool is_socket() const
- {
- return _is_socket;
- }
-
- const std::string running() const
- {
- return _running;
- }
-
- bool check();
-
- std::string log_and_pid();
-
- bool kill();
- bool start();
- bool command(libtest::Application& app);
-
- bool validate();
-
- void out_of_ban_killed(bool arg)
- {
- out_of_ban_killed_= arg;
- }
-
- bool out_of_ban_killed()
- {
- return out_of_ban_killed_;
- }
-
- void timeout(uint32_t timeout_)
- {
- _timeout= timeout_;
- }
-
-protected:
- bool set_pid_file();
- Options _options;
- Application _app;
-
-private:
- bool is_helgrind() const;
- bool is_valgrind() const;
- bool is_debug() const;
- bool set_log_file();
- bool set_socket_file();
- void reset_pid();
- bool out_of_ban_killed_;
- bool args(Application&);
-
- std::string _error;
- uint32_t _timeout; // This number should be high enough for valgrind startup (which is slow)
-};
-
-std::ostream& operator<<(std::ostream& output, const libtest::Server &arg);
-
-} // namespace libtest
-
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include "libtest/common.h"
-
-#include <cerrno>
-#include <cstdlib>
-#include <iostream>
-
-#include <algorithm>
-#include <functional>
-#include <locale>
-
-// trim from end
-static inline std::string &rtrim(std::string &s)
-{
- s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
- return s;
-}
-
-namespace libtest {
-
-Server* server_startup_st::last()
-{
- return servers.back();
-}
-
-void server_startup_st::push_server(Server *arg)
-{
- servers.push_back(arg);
-
- std::string server_config_string;
- if (arg->has_socket())
- {
- server_config_string+= "--socket=";
- server_config_string+= '"';
- server_config_string+= arg->socket();
- server_config_string+= '"';
- server_config_string+= " ";
- }
- else
- {
- libtest::vchar_t port_str;
- port_str.resize(NI_MAXSERV);
- snprintf(&port_str[0], port_str.size(), "%u", int(arg->port()));
-
- server_config_string+= "--server=";
- server_config_string+= arg->hostname();
- server_config_string+= ":";
- server_config_string+= &port_str[0];
- server_config_string+= " ";
- }
-
- server_list+= server_config_string;
-}
-
-Server* server_startup_st::pop_server()
-{
- Server *tmp= servers.back();
- servers.pop_back();
- return tmp;
-}
-
-// host_to_shutdown => host number to shutdown in array
-bool server_startup_st::shutdown(uint32_t host_to_shutdown)
-{
- if (servers.size() > host_to_shutdown)
- {
- Server* tmp= servers[host_to_shutdown];
-
- if (tmp and tmp->kill() == false)
- { }
- else
- {
- return true;
- }
- }
-
- return false;
-}
-
-void server_startup_st::clear()
-{
- std::for_each(servers.begin(), servers.end(), DeleteFromVector());
- servers.clear();
-}
-
-bool server_startup_st::check() const
-{
- bool success= true;
- for (std::vector<Server *>::const_iterator iter= servers.begin(); iter != servers.end(); ++iter)
- {
- if ((*iter)->check() == false)
- {
- success= false;
- }
- }
-
- return success;
-}
-
-bool server_startup_st::shutdown()
-{
- bool success= true;
- for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); ++iter)
- {
- if ((*iter)->has_pid() and (*iter)->kill() == false)
- {
- Error << "Unable to kill:" << *(*iter);
- success= false;
- }
- }
-
- return success;
-}
-
-void server_startup_st::restart()
-{
- for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); ++iter)
- {
- Server *server = *iter;
-
- if (server->check()) {
- server->kill();
- }
- server->start();
- }
-}
-
-#define MAGIC_MEMORY 123575
-server_startup_st::server_startup_st() :
- _magic(MAGIC_MEMORY),
- _socket(false),
- _sasl(false),
- udp(0),
- _servers_to_run(5)
-{ }
-
-server_startup_st::~server_startup_st()
-{
- clear();
-}
-
-bool server_startup_st::validate()
-{
- return _magic == MAGIC_MEMORY;
-}
-
-bool server_startup(server_startup_st& construct, const std::string& server_type, in_port_t try_port, const char *argv[])
-{
- return construct.start_server(server_type, try_port, argv);
-}
-
-libtest::Server* server_startup_st::create(const std::string& server_type, in_port_t try_port, const bool is_socket)
-{
- libtest::Server *server= NULL;
-
- if (is_socket == false)
- {
- if (try_port <= 0)
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "was passed the invalid port number %d", int(try_port));
- }
- }
-
- if (is_socket)
- {
- if (server_type.compare("memcached") == 0)
- {
- server= build_memcached_socket("localhost", try_port);
- }
- else
- {
- Error << "Socket is not support for server: " << server_type;
- return NULL;
- }
- }
- else if (server_type.compare("gearmand") == 0)
- {
- server= build_gearmand("localhost", try_port);
- }
- else if (server_type.compare("hostile-gearmand") == 0)
- {
- server= build_gearmand("localhost", try_port, "gearmand/hostile_gearmand");
- }
- else if (server_type.compare("drizzled") == 0)
- {
- if (has_drizzled())
- {
- if (has_libdrizzle())
- {
- server= build_drizzled("localhost", try_port);
- }
- }
- }
- else if (server_type.compare("blobslap_worker") == 0)
- {
- if (has_gearmand())
- {
-#ifdef GEARMAND_BLOBSLAP_WORKER
- if (GEARMAND_BLOBSLAP_WORKER)
- {
- if (HAVE_LIBGEARMAN)
- {
- server= build_blobslap_worker(try_port);
- }
- }
-#endif // GEARMAND_BLOBSLAP_WORKER
- }
- }
- else if (server_type.compare("memcached") == 0)
- {
- if (has_memcached())
- {
- server= build_memcached("localhost", try_port);
- }
- }
- else if (server_type == "memcached-sasl")
- {
- server = build_memcached_sasl("localhost", try_port, _username, _password);
- }
-
- return server;
-}
-
-class ServerPtr {
-public:
- ServerPtr(libtest::Server* server_):
- _server(server_)
- { }
-
- ~ServerPtr()
- {
- delete _server;
- }
-
- void reset()
- {
- delete _server;
- _server= NULL;
- }
-
- libtest::Server* release(libtest::Server* server_= NULL)
- {
- libtest::Server* tmp= _server;
- _server= server_;
- return tmp;
- }
-
- libtest::Server* operator->() const
- {
- return _server;
- }
-
- libtest::Server* operator&() const
- {
- return _server;
- }
-
-private:
- libtest::Server* _server;
-};
-
-bool server_startup_st::_start_server(const bool is_socket,
- const std::string& server_type,
- in_port_t try_port,
- const char *argv[])
-{
- try {
- ServerPtr server(create(server_type, try_port, is_socket));
-
- if (&server == NULL)
- {
- Error << "Could not allocate server: " << server_type;
- return false;
- }
-
- /*
- We will now cycle the server we have created.
- */
- if (server->cycle() == false)
- {
- Error << "Could not start up server " << &server;
- return false;
- }
-
- server->init(argv);
-
-#if 0
- if (false)
- {
- Out << "Pausing for startup, hit return when ready.";
- std::string gdb_command= server->base_command();
- getchar();
- }
- else
-#endif
-
- if (server->start() == false)
- {
- return false;
- }
- else
- {
- {
-#ifdef DEBUG
- if (DEBUG)
- {
- Outn();
- Out << "STARTING SERVER(pid:" << server->pid() << "): " << server->running();
- }
-#endif
- }
- }
-
- push_server(server.release());
-
- if (is_socket and &server)
- {
- set_default_socket(server->socket().c_str());
- }
- }
- catch (const libtest::disconnected& err)
- {
- if (fatal::is_disabled() == false and try_port != LIBTEST_FAIL_PORT)
- {
- stream::cerr(err.file(), err.line(), err.func()) << err.what();
- return false;
- }
- }
- catch (const libtest::__test_result& err)
- {
- stream::cerr(err.file(), err.line(), err.func()) << err.what();
- return false;
- }
- catch (const std::exception& err)
- {
- Error << err.what();
- return false;
- }
- catch (...)
- {
- Error << "error occured while creating server: " << server_type;
- return false;
- }
-
- return true;
-}
-
-bool server_startup_st::start_server(const std::string& server_type, in_port_t try_port, const char *argv[])
-{
- return _start_server(false, server_type, try_port, argv);
-}
-
-bool server_startup_st::start_socket_server(const std::string& server_type, const in_port_t try_port, const char *argv[])
-{
- return _start_server(true, server_type, try_port, argv);
-}
-
-std::string server_startup_st::option_string() const
-{
- std::string temp= server_list;
- rtrim(temp);
- return temp;
-}
-
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <cassert>
-#include <cstdio>
-#include <cstring>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <string>
-#include <unistd.h>
-#include <vector>
-
-namespace libtest {
-
-class server_startup_st
-{
-private:
- uint64_t _magic;
- std::string server_list;
- bool _socket;
- bool _sasl;
- std::string _username;
- std::string _password;
-
-public:
-
- uint8_t udp;
- std::vector<Server *> servers;
-
- server_startup_st();
- ~server_startup_st();
-
- bool validate();
-
- bool start_socket_server(const std::string& server_type, const in_port_t try_port, const char *argv[]);
- bool start_server(const std::string& server_type, const in_port_t try_port, const char *argv[]);
-
- uint32_t count() const
- {
- return uint32_t(servers.size());
- }
-
- void restart();
-
- std::string option_string() const;
-
- const std::string& password() const
- {
- return _password;
- }
-
- const std::string& username() const
- {
- return _username;
- }
-
- bool socket()
- {
- return _socket;
- }
-
- bool sasl()
- {
- return _sasl;
- }
-
- void set_socket()
- {
- _socket= true;
- }
-
- void set_sasl(const std::string& username_arg, const std::string& password_arg)
- {
- _sasl= true;
- _username= username_arg;
- _password= password_arg;
- }
-
-
- // Just remove everything after shutdown
- void clear();
-
- bool shutdown();
- bool shutdown(uint32_t number_of_host);
-
- bool check() const;
-
- void push_server(Server *);
- Server* last();
- Server *pop_server();
-
- Server* create(const std::string& server_type, in_port_t try_port, const bool is_socket);
-
- unsigned long int servers_to_run() const
- {
- return _servers_to_run;
- }
-
- void set_servers_to_run(unsigned long int arg)
- {
- _servers_to_run= arg;
- }
-
-private:
- bool _start_server(const bool is_socket,
- const std::string& server_type,
- const in_port_t try_port,
- const char *argv[]);
-
-private:
- unsigned long int _servers_to_run;
-};
-
-bool server_startup(server_startup_st&, const std::string&, in_port_t try_port, const char *argv[]);
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-#include <csignal>
-
-#include <libtest/signal.h>
-
-using namespace libtest;
-
-#define MAGIC_MEMORY 123569
-
-bool SignalThread::is_shutdown()
-{
- bool ret;
- pthread_mutex_lock(&shutdown_mutex);
- ret= bool(__shutdown != SHUTDOWN_RUNNING);
- pthread_mutex_unlock(&shutdown_mutex);
-
- return ret;
-}
-
-void SignalThread::set_shutdown(shutdown_t arg)
-{
- pthread_mutex_lock(&shutdown_mutex);
- __shutdown= arg;
- pthread_mutex_unlock(&shutdown_mutex);
-
- if (arg == SHUTDOWN_GRACEFUL)
- {
- if (pthread_kill(thread, SIGUSR2) == 0)
- {
- void *retval;
- pthread_join(thread, &retval);
- }
- }
-}
-
-shutdown_t SignalThread::get_shutdown()
-{
- shutdown_t local;
- pthread_mutex_lock(&shutdown_mutex);
- local= __shutdown;
- pthread_mutex_unlock(&shutdown_mutex);
-
- return local;
-}
-
-void SignalThread::post()
-{
- sem_post(&lock);
-}
-
-void SignalThread::test()
-{
- assert(magic_memory == MAGIC_MEMORY);
- if (bool(getenv("LIBTEST_IN_GDB")) == false)
- {
- assert(sigismember(&set, SIGALRM));
- assert(sigismember(&set, SIGABRT));
- assert(sigismember(&set, SIGQUIT));
- assert(sigismember(&set, SIGINT));
- assert(sigismember(&set, SIGVTALRM));
- }
- assert(sigismember(&set, SIGUSR2));
-}
-
-bool SignalThread::unblock()
-{
- int error;
- if ((error= pthread_sigmask(SIG_UNBLOCK, &set, NULL)) != 0)
- {
- Error << "While trying to reset signal mask to original set, pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")";
- return false;
- }
-
- return true;
-}
-
-SignalThread::~SignalThread()
-{
- if (is_shutdown() == false)
- {
- set_shutdown(SHUTDOWN_GRACEFUL);
- }
-
-#if 0
- if (pthread_equal(thread, pthread_self()) != 0 and (pthread_kill(thread, 0) == ESRCH) == true)
- {
- void *retval;
- pthread_join(thread, &retval);
- }
-#endif
- sem_destroy(&lock);
-
- unblock();
-}
-
-extern "C" {
-
-static void *sig_thread(void *arg)
-{
- SignalThread *context= (SignalThread*)arg;
-
- context->test();
- context->post();
-
- while (context->get_shutdown() == SHUTDOWN_RUNNING)
- {
- int sig;
-
- if (context->wait(sig) == -1)
- {
- Error << "sigwait() returned errno:" << strerror(errno);
- continue;
- }
-
- switch (sig)
- {
- case SIGALRM:
- case SIGVTALRM:
- Error << strsignal(sig);
- if (gdb_is_caller())
- {
- abort();
- }
- exit(EXIT_FAILURE);
-
- case SIGABRT:
- case SIGUSR2:
- case SIGINT:
- case SIGQUIT:
- if (context->is_shutdown() == false)
- {
- context->set_shutdown(SHUTDOWN_FORCED);
- }
- break;
- case SIGPIPE:
- {
- Error << "Ignoring SIGPIPE";
- }
- break;
-
- case 0:
- Error << "Inside of gdb";
- break;
-
- default:
- Error << "Signal handling thread got unexpected signal " << strsignal(sig);
- break;
- }
- }
-
- return NULL;
-}
-
-}
-
-SignalThread::SignalThread() :
- magic_memory(MAGIC_MEMORY),
- thread(pthread_self())
-{
- pthread_mutex_init(&shutdown_mutex, NULL);
- sigemptyset(&set);
- if (bool(getenv("LIBTEST_IN_GDB")) == false)
- {
- sigaddset(&set, SIGALRM);
- sigaddset(&set, SIGABRT);
- sigaddset(&set, SIGQUIT);
- sigaddset(&set, SIGINT);
- sigaddset(&set, SIGVTALRM);
- }
- sigaddset(&set, SIGPIPE);
-
- sigaddset(&set, SIGUSR2);
-
- sem_init(&lock, 0, 0);
-
- sigemptyset(&original_set);
- pthread_sigmask(SIG_BLOCK, NULL, &original_set);
-}
-
-
-bool SignalThread::setup()
-{
- set_shutdown(SHUTDOWN_RUNNING);
-
- if (sigismember(&original_set, SIGQUIT))
- {
- Error << strsignal(SIGQUIT) << " has been previously set.";
- }
-
- if (sigismember(&original_set, SIGINT))
- {
- Error << strsignal(SIGINT) << " has been previously set.";
- }
-
- if (sigismember(&original_set, SIGVTALRM))
- {
- Error << strsignal(SIGVTALRM) << " has been previously set.";
- }
-
- if (sigismember(&original_set, SIGUSR2))
- {
- Error << strsignal(SIGUSR2) << " has been previously set.";
- }
-
- int error;
- if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
- {
- Error << "pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")";
- return false;
- }
-
- if ((error= pthread_create(&thread, NULL, &sig_thread, this)) != 0)
- {
- Error << "pthread_create() died during pthread_create(" << strerror(error) << ")";
- return false;
- }
-
- sem_wait(&lock);
-
- return true;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-
-enum shutdown_t {
- SHUTDOWN_RUNNING,
- SHUTDOWN_GRACEFUL,
- SHUTDOWN_FORCED
-};
-
-namespace libtest {
-
-class SignalThread {
- sigset_t set;
- sem_t lock;
- uint64_t magic_memory;
- volatile shutdown_t __shutdown;
- pthread_mutex_t shutdown_mutex;
- pthread_t thread;
- sigset_t original_set;
-
-public:
-
- SignalThread();
- ~SignalThread();
-
- void test();
- void post();
- bool setup();
- bool unblock();
-
- int wait(int& sig)
- {
- return sigwait(&set, &sig);
- }
-
- void set_shutdown(shutdown_t arg);
- bool is_shutdown();
- shutdown_t get_shutdown();
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/test.hpp>
-
-#include <cstdlib>
-#include <unistd.h>
-
-using namespace libtest;
-
-
-static void *world_create(server_startup_st&, test_return_t& rc)
-{
- rc= TEST_SKIPPED;
-
- return NULL;
-}
-
-void get_world(libtest::Framework *world)
-{
- world->create(world_create);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-static char global_socket[1024]= { 0 };
-
-namespace libtest {
-
-const char *default_socket()
-{
- if (global_socket[0] == 0)
- {
- return NULL;
- }
-
- return global_socket;
-}
-
-void set_default_socket(const char *socket)
-{
- if (socket)
- {
- strncpy(global_socket, socket, sizeof(global_socket)-1);
- }
-}
-
-}
+++ /dev/null
-
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-namespace libtest {
-
-const char *default_socket();
-
-void set_default_socket(const char *socket);
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <iostream>
-#include <cassert>
-#include <sstream>
-#include <ctime>
-#include <ostream>
-
-namespace libtest {
-namespace stream {
-
-namespace detail {
-
-template<class Ch, class Tr, class A>
- class channel {
- private:
-
- public:
- typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
-
- public:
- void operator()(const stream_buffer& s, std::ostream& _out,
- const char* filename, int line_number, const char* func)
- {
- if (filename)
- {
- _out
- << filename
- << ":"
- << line_number
- << ": in "
- << func << "() "
- << s.str()
- << std::endl;
- }
- else
- {
- _out
- << s.str()
- << std::endl;
- }
- }
- };
-
-template<class Ch, class Tr, class A>
- class channelln {
- private:
-
- public:
- typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
-
- public:
- void operator()(const stream_buffer& s, std::ostream& _out,
- const char* filename, int line_number, const char* func)
- {
- if (filename)
- {
- _out
- << std::endl
- << filename
- << ":"
- << line_number
- << ": in "
- << func << "() "
- << s.str()
- << std::endl;
- }
- else
- {
- _out
- << std::endl
- << s.str()
- << std::endl;
- }
- }
- };
-
-template<class Ch, class Tr, class A>
- class channelfl {
- private:
-
- public:
- typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
-
- public:
- void operator()(const stream_buffer& s, std::ostream& _out,
- const char* filename, int line_number, const char* func)
- {
- if (filename)
- {
- _out
- << filename
- << ":"
- << line_number
- << ": in "
- << func << "() "
- << s.str()
- << std::flush;
- }
- else
- {
- _out
- << s.str()
- << std::flush;
- }
- }
- };
-
-template<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> >
- class log {
- private:
- typedef OutputPolicy<Ch, Tr, A> output_policy;
-
- private:
- std::ostream& _out;
- const char *_filename;
- int _line_number;
- const char *_func;
-
- public:
- log(std::ostream& out_arg, const char* filename, int line_number, const char* func) :
- _out(out_arg),
- _filename(filename),
- _line_number(line_number),
- _func(func)
- { }
-
- virtual ~log()
- {
- output_policy()(arg, _out, _filename, _line_number, _func);
- }
-
- public:
- template<class T>
- log &operator<<(const T &x)
- {
- arg << x;
- return *this;
- }
-
- private:
- typename output_policy::stream_buffer arg;
-
- private:
- log( const log& );
- const log& operator=( const log& );
- };
-} // namespace detail
-
-class make_cerr : public detail::log<detail::channelln> {
-public:
- make_cerr(const char* filename, int line_number, const char* func) :
- detail::log<detail::channelln>(std::cerr, filename, line_number, func)
- { }
-
-private:
- make_cerr( const make_cerr& );
- const make_cerr& operator=( const make_cerr& );
-};
-
-class cerr : public detail::log<detail::channel> {
-public:
- cerr(const char* filename, int line_number, const char* func) :
- detail::log<detail::channel>(std::cout, filename, line_number, func)
- { }
-
-private:
- cerr( const cerr& );
- const cerr& operator=( const cerr& );
-};
-
-class clog : public detail::log<detail::channel> {
-public:
- clog(const char* filename, int line_number, const char* func) :
- detail::log<detail::channel>(std::clog, filename, line_number, func)
- { }
-
-private:
- clog( const clog& );
- const clog& operator=( const clog& );
-};
-
-class make_cout : public detail::log<detail::channelln> {
-public:
- make_cout(const char* filename, int line_number, const char* func) :
- detail::log<detail::channelln>(std::cout, filename, line_number, func)
- { }
-
-private:
- make_cout( const make_cout& );
- const make_cout& operator=( const make_cout& );
-};
-
-class cout : public detail::log<detail::channel> {
-public:
- cout(const char* filename, int line_number, const char* func) :
- detail::log<detail::channel>(std::cout, filename, line_number, func)
- { }
-
-private:
- cout( const cout& );
- const cout& operator=( const cout& );
-};
-
-class cecho : public detail::log<detail::channelfl> {
-public:
- cecho(const char* filename, int line_number, const char* func) :
- detail::log<detail::channelfl>(std::cout, filename, line_number, func)
- { }
-
-private:
- cecho( const cecho& );
- const cecho& operator=( const cecho& );
-};
-
-} // namespace stream
-
-#define Error stream::cerr(__FILE__, __LINE__, __func__)
-
-#define Echo stream::cecho(NULL, __LINE__, __func__)
-
-#define Out stream::cout(NULL, __LINE__, __func__)
-
-#define Outn() stream::cout(NULL, __LINE__, __func__) << " "
-
-#define Log stream::clog(NULL, __LINE__, __func__)
-
-#define Logn() stream::clog(NULL, __LINE__, __func__) << " "
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-namespace libtest {
-
-const char *test_strerror(test_return_t code)
-{
- switch (code) {
- case TEST_SUCCESS:
- return "ok";
-
- case TEST_FAILURE:
- return "failed";
-
- case TEST_SKIPPED:
- return "skipped";
- }
-
- FATAL("No port could be found");
-}
-
-} // namespace libtest
-
-
-std::ostream& operator<<(std::ostream& output, const enum test_return_t &arg)
-{
- output << libtest::test_strerror(arg);
- return output;
-}
-
-std::ostream& operator<<(std::ostream& output, const std::vector<char> &arg)
-{
- output << "std::vector<char>:" << arg.size();
- return output;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <vector>
-#include <iostream>
-
-namespace libtest {
-
-/**
- @note Friendly print function for errors.
-*/
-LIBTEST_API
-const char *test_strerror(test_return_t code);
-
-} // namespace libtest
-
-std::ostream& operator<<(std::ostream& output, const enum test_return_t &arg);
-std::ostream& operator<<(std::ostream& output, const std::vector<char> &arg);
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include "util/string.hpp"
-
-#define test_literal_param util_literal_param
-#define test_literal_compare_param util_literal_compare_param
-#define test_literal_param_size util_literal_param_size
-#define test_string_make_from_cstr util_string_make_from_cstr
-#define test_string_make_from_array util_string_make_from_array
-#define test_array_length util_array_length
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-#include <libtest/lite.h>
-
-/**
- A structure describing the test case.
-*/
-struct test_st {
- const char *name;
- bool requires_flush;
- test_callback_fn *test_fn;
-};
-
-#define test_assert_errno(A) \
-do \
-{ \
- if ((A)) { \
- fprintf(stderr, "\n%s:%d: Assertion failed for %s: ", __FILE__, __LINE__, __func__);\
- perror(#A); \
- fprintf(stderr, "\n"); \
- libtest::create_core(); \
- assert((A)); \
- } \
-} while (0)
-
-#define test_truth(A) \
-do \
-{ \
- if (! (A)) { \
- fprintf(stderr, "\n%s:%d: Assertion \"%s\" failed, in %s\n", __FILE__, __LINE__, #A, __func__);\
- libtest::create_core(); \
- return TEST_FAILURE; \
- } \
-} while (0)
-
-#define test_true(A) \
-do \
-{ \
- if (! (A)) { \
- fprintf(stderr, "\n%s:%d: Assertion \"%s\" failed, in %s\n", __FILE__, __LINE__, #A, __func__);\
- libtest::create_core(); \
- return TEST_FAILURE; \
- } \
-} while (0)
-
-#define test_true_got(A, B) test_true(A);
-#define test_true_hint(A, B) test_true(A);
-
-#define test_compare_hint(A, B, C) test_compare(A, B);
-#define test_compare_got(A, B, C) test_compare(A, B);
-
-#define test_skip(__expected, __actual) \
-do \
-{ \
- if (libtest::_compare(__FILE__, __LINE__, __func__, ((__expected)), ((__actual)), false) == false) \
- { \
- return TEST_SKIPPED; \
- } \
-} while (0)
-
-#define test_skip_valgrind() \
-do \
-{ \
- if (libtest::_in_valgrind(__FILE__, __LINE__, __func__)) \
- { \
- return TEST_SKIPPED; \
- } \
-} while (0)
-
-#define test_fail(A) \
-do \
-{ \
- if (1) { \
- fprintf(stderr, "\n%s:%d: Failed with %s, in %s\n", __FILE__, __LINE__, #A, __func__);\
- libtest::create_core(); \
- return TEST_FAILURE; \
- } \
-} while (0)
-
-
-#define test_false(A) \
-do \
-{ \
- if ((A)) { \
- fprintf(stderr, "\n%s:%d: Assertion failed %s, in %s\n", __FILE__, __LINE__, #A, __func__);\
- libtest::create_core(); \
- return TEST_FAILURE; \
- } \
-} while (0)
-
-#define test_false_with(A,B) \
-do \
-{ \
- if ((A)) { \
- fprintf(stderr, "\n%s:%d: Assertion failed %s with %s\n", __FILE__, __LINE__, #A, (B));\
- libtest::create_core(); \
- return TEST_FAILURE; \
- } \
-} while (0)
-
-#define test_ne_compare(__expected, __actual) \
-do \
-{ \
- if (libtest::_ne_compare(__FILE__, __LINE__, __func__, ((__expected)), ((__actual)), true) == false) \
- { \
- libtest::create_core(); \
- return TEST_FAILURE; \
- } \
-} while (0)
-
-#define test_compare(__expected, __actual) \
-do \
-{ \
- if (libtest::_compare(__FILE__, __LINE__, __func__, ((__expected)), ((__actual)), true) == false) \
- { \
- libtest::create_core(); \
- return TEST_FAILURE; \
- } \
-} while (0)
-
-#define test_zero(__actual) \
-do \
-{ \
- if (libtest::_compare_zero(__FILE__, __LINE__, __func__, ((__actual))) == false) \
- { \
- libtest::create_core(); \
- return TEST_FAILURE; \
- } \
-} while (0)
-
-#define test_null test_zero
-
-#define test_compare_warn(__expected, __actual) \
-do \
-{ \
- void(libtest::_compare(__FILE__, __LINE__, __func__, (__expected), (__actual)), true); \
-} while (0)
-
-#define test_warn(__truth, __explain) \
-do \
-{ \
- void(libtest::_assert_truth(__FILE__, __LINE__, __func__, bool((__truth)), #__truth, __explain)); \
-} while (0)
-
-#define test_strcmp(__expected, __actual) \
-do \
-{ \
- void(libtest::_compare_strcmp(__FILE__, __LINE__, __func__, (__expected), (__actual))); \
-} while (0)
-
-#define test_memcmp(A,B,C) \
-do \
-{ \
- if ((A) == NULL or (B) == NULL or memcmp((A), (B), (C))) \
- { \
- fprintf(stderr, "\n%s:%d: %.*s -> %.*s\n", __FILE__, __LINE__, (int)(C), (char *)(A), (int)(C), (char *)(B)); \
- libtest::create_core(); \
- return TEST_FAILURE; \
- } \
-} while (0)
-
-#define test_return_if(__test_return_t) \
-do \
-{ \
- if ((__test_return_t) != TEST_SUCCESS) \
- { \
- return __test_return_t; \
- } \
-} while (0)
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- Structures for generic tests.
-*/
-
-#pragma once
-
-#ifndef YATL_FULL
-# define YATL_FULL 1
-#endif
-
-#ifndef __PRETTY_FUNCTION__
-# define __PRETTY_FUNCTION__ __func__
-#endif
-
-#define YATL_STRINGIFY(x) #x
-#define YATL_TOSTRING(x) YATL_STRINGIFY(x)
-#define YATL_AT __FILE__ ":" YATL_TOSTRING(__LINE__)
-#define YATL_AT_PARAM __func__, AT
-#define YATL_UNIQUE __FILE__ ":" YATL_TOSTRING(__LINE__) "_unique"
-#define YATL_UNIQUE_FUNC_NAME __FILE__ ":" YATL_TOSTRING(__LINE__) "_unique_func"
-
-#define LIBYATL_DEFAULT_PARAM __FILE__, __LINE__, __PRETTY_FUNCTION__
-
-#include <cstdio>
-#include <cstdlib>
-#include <arpa/inet.h>
-
-#include <libtest/visibility.h>
-#include <libtest/version.h>
-
-#include <libtest/vchar.hpp>
-#include <libtest/error.h>
-#include <libtest/exception.hpp>
-#include <libtest/exception/disconnected.hpp>
-#include <libtest/exception/fatal.hpp>
-#include <libtest/result.hpp>
-
-#include <libtest/has.hpp>
-#include <libtest/error.h>
-#include <libtest/strerror.h>
-#include <libtest/timer.hpp>
-#include <libtest/alarm.h>
-#include <libtest/stream.h>
-#include <libtest/comparison.hpp>
-#include <libtest/server.h>
-#include <libtest/server_container.h>
-#include <libtest/wait.h>
-#include <libtest/callbacks.h>
-#include <libtest/test.h>
-#include <libtest/dream.h>
-#include <libtest/core.h>
-#include <libtest/runner.h>
-#include <libtest/port.h>
-#include <libtest/is_local.hpp>
-#include <libtest/socket.hpp>
-#include <libtest/collection.h>
-#include <libtest/framework.h>
-#include <libtest/get.h>
-#include <libtest/cmdline.h>
-#include <libtest/string.hpp>
-#include <libtest/binaries.h>
-#include <libtest/http.hpp>
-#include <libtest/cpu.hpp>
-#include <libtest/tmpfile.hpp>
-#include <libtest/client.hpp>
-#include <libtest/thread.hpp>
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <pthread.h>
-
-#if __cplusplus < 201103L
-# define noexcept(a)
-#endif
-
-namespace libtest
-{
-namespace thread
-{
-
-class Mutex
-{
-public:
- Mutex() :
- _err(0)
- {
- _err= pthread_mutex_init(&_mutex, NULL);
- }
-
- ~Mutex() noexcept(false)
- {
- if ((_err= pthread_mutex_destroy(&_mutex)))
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_destroy: %s", strerror(_err));
- }
- }
-
- pthread_mutex_t* handle()
- {
- if (_err != 0)
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_mutex_init: %s", strerror(_err));
- }
-
- return &_mutex;
- }
-
-private:
- int _err;
- pthread_mutex_t _mutex;
-};
-
-class ScopedLock
-{
-public:
- ScopedLock(Mutex& mutex_) :
- _mutex(mutex_)
- {
- init();
- }
-
- ~ScopedLock() noexcept(false)
- {
- int err;
- if ((err= pthread_mutex_unlock(_mutex.handle())))
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_mutex_unlock: %s", strerror(err));
- }
- }
-
- Mutex* handle()
- {
- return &_mutex;
- }
-
-private:
- void init()
- {
- int err;
- if ((err= pthread_mutex_lock(_mutex.handle())))
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_mutex_lock: %s", strerror(err));
- }
- }
-
-private:
- Mutex& _mutex;
-};
-
-class Condition
-{
-public:
- Condition()
- {
- int err;
- if ((err= pthread_cond_init(&_cond, NULL)))
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_mutex_init: %s", strerror(err));
- }
- }
-
- ~Condition() noexcept(false)
- {
- int err;
- if ((err= pthread_cond_destroy(&_cond)))
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_destroy: %s", strerror(err));
- }
- }
-
- void broadcast()
- {
- int err;
- if ((err= pthread_cond_broadcast(&_cond)))
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_broadcast: %s", strerror(err));
- }
- }
-
- void signal()
- {
- int err;
- if ((err= pthread_cond_signal(&_cond)))
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_broadcast: %s", strerror(err));
- }
- }
-
- void wait(ScopedLock& lock_)
- {
- int err;
- if ((err= pthread_cond_wait(&_cond, lock_.handle()->handle())))
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_wait: %s", strerror(err));
- }
- }
-
-private:
- pthread_cond_t _cond;
-};
-
-class Barrier
-{
-public:
- explicit Barrier(uint32_t count):
- _threshold(count),
- _count(count),
- _generation(0)
- {
- if (_count == 0)
- {
- fatal_assert("Zero is an invalid value");
- }
- }
-
- ~Barrier()
- {
- }
-
- bool wait()
- {
- ScopedLock l(_mutex);
- uint32_t gen = _generation;
-
- if (--_count == 0)
- {
- _generation++;
- _count = _threshold;
- _cond.broadcast();
-
- return true;
- }
-
- while (gen == _generation)
- {
- _cond.wait(l);
- }
-
- return false;
- }
-
-private:
- Mutex _mutex;
- Condition _cond;
- uint32_t _threshold;
- uint32_t _count;
- uint32_t _generation;
-};
-
-class Thread
-{
-private:
- typedef void *(*start_routine_fn) (void *);
-
-public:
- template <class Function,class Arg1>
- Thread(Function func, Arg1 arg):
- _joined(false),
- _func((start_routine_fn)func),
- _context(arg)
- {
- int err;
- if ((err= pthread_create(&_thread, NULL, entry_func, (void*)this)))
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_create: %s", strerror(err));
- }
- _owner= pthread_self();
- }
-
- bool running() const
- {
- return (pthread_kill(_thread, 0) == 0);
- }
-
- bool detached()
- {
- if (EDEADLK == pthread_join(_thread, NULL))
- {
- return true;
- }
-
- /* Result of pthread_join was EINVAL == detached thread */
- return false;
- }
-
- bool join()
- {
- if (_thread == pthread_self())
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "Thread cannot join on itself");
- }
-
- if (_owner != pthread_self())
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "Attempt made by a non-owner thead to join on thread");
- }
-
- bool ret= false;
- {
- ScopedLock l(_join_mutex);
- if (_joined == false)
- {
- int err;
- if ((err= pthread_join(_thread, NULL)))
- {
- switch(err)
- {
- case EINVAL:
- break;
-
- case ESRCH:
- ret= true;
- break;
-
- case EDEADLK:
- default:
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_join: %s", strerror(err));
- }
- }
- else
- {
- ret= true;
- }
-
- _joined= true;
- }
- }
-
- return ret;
- }
-
- ~Thread()
- {
- join();
- }
-
-protected:
- void run()
- {
- _func(_context);
- }
-
-private:
- static void * entry_func(void* This)
- {
- ((Thread *)This)->run();
- return NULL;
- }
-
-private:
- bool _joined;
- pthread_t _thread;
- pthread_t _owner;
- start_routine_fn _func;
- void* _context;
- Mutex _join_mutex;
-};
-
-} // namespace thread
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/timer.hpp>
-
-#include <ctime>
-#include <iomanip>
-
-#ifdef __MACH__
-# include <mach/clock.h>
-# include <mach/mach.h>
-#else
-# include <sys/time.h>
-#endif
-
-namespace libtest {
-
-Timer::Timer()
-{
- _begin.tv_sec= 0;
- _begin.tv_nsec= 0;
- _end.tv_sec= 0;
- _end.tv_nsec= 0;
-}
-
-void Timer::reset()
-{
- _end.tv_sec= 0;
- _end.tv_nsec= 0;
- _time(_begin);
-}
-
-void Timer::sample()
-{
- _time(_end);
-}
-
-void Timer::offset(int64_t minutes_arg, int64_t seconds_arg, int64_t nanoseconds)
-{
- reset();
- _end= _begin;
- _end.tv_sec+= (minutes_arg * 60) +seconds_arg;
- _end.tv_nsec+= nanoseconds;
-}
-
-int64_t Timer::minutes()
-{
- struct timespec result;
- difference(result);
- return int64_t(result.tv_sec / 60);
-}
-
-uint64_t Timer::elapsed_milliseconds() const
-{
- struct timespec temp;
- difference(temp);
-
- return temp.tv_sec*1000 +temp.tv_nsec/1000000;
-}
-
-void Timer::difference(struct timespec& arg) const
-{
- if ((_end.tv_nsec -_begin.tv_nsec) < 0)
- {
- arg.tv_sec= _end.tv_sec -_begin.tv_sec -1;
- arg.tv_nsec= 1000000000 +_end.tv_nsec -_begin.tv_nsec;
-
- }
- else
- {
- arg.tv_sec= _end.tv_sec -_begin.tv_sec;
- arg.tv_nsec= _end.tv_nsec -_begin.tv_nsec;
- }
-}
-
-void Timer::_time(struct timespec& ts)
-{
-#ifdef __MACH__ // OSX lacks clock_gettime()
- clock_serv_t _clock_serv;
- mach_timespec_t _mach_timespec;
- host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &_clock_serv);
- clock_get_time(_clock_serv, &_mach_timespec);
- mach_port_deallocate(mach_task_self(), _clock_serv);
- ts.tv_sec= _mach_timespec.tv_sec;
- ts.tv_nsec= _mach_timespec.tv_nsec;
-#elif defined(_WIN32)
- ts.tv_sec= time(NULL);
- ts.tv_nsec= 0;
-#else
- clock_gettime(CLOCK_REALTIME, &ts);
-#endif
-}
-
-std::ostream& operator<<(std::ostream& output, const libtest::Timer& arg)
-{
- struct timespec temp;
- arg.difference(temp);
-
- if (temp.tv_sec > 60)
- {
- output << temp.tv_sec / 60;
- output << "." << temp.tv_sec % 60;
- }
- else
- {
- output << temp.tv_sec;
- }
-
- output << ":";
- output << std::setfill('0') << std::setw(9) << temp.tv_nsec;
-
- return output;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <cstdlib>
-#include <ctime>
-#include <iostream>
-
-
-namespace libtest {
-
-class Timer {
-public:
-
- Timer();
-
- void reset();
-
- void sample();
-
- void offset(int64_t minutes_arg, int64_t seconds_arg, int64_t nanoseconds);
-
- int64_t minutes();
-
- uint64_t elapsed_milliseconds() const;
-
- void difference(struct timespec& arg) const;
-
-private:
- void _time(struct timespec& ts);
-
-private:
- struct timespec _begin;
- struct timespec _end;
-};
-
-std::ostream& operator<<(std::ostream& output, const libtest::Timer& arg);
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/common.h>
-
-namespace libtest {
-
-std::string create_tmpfile(const std::string& name, int& fd)
-{
- libtest::vchar_t file_buffer;
- file_buffer.resize(FILENAME_MAX);
- file_buffer[0]= 0;
-
- int length= snprintf(&file_buffer[0], file_buffer.size(), "var/tmp/%s.XXXXXX", name.c_str());
- fatal_assert(length > 0);
-
- if ((fd= mkstemp(&file_buffer[0])) == -1)
- {
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", &file_buffer[0], strerror(errno));
- }
-
- return &file_buffer[0];
-}
-
-std::string create_tmpfile(const std::string& name)
-{
- int fd;
- std::string ret_file= create_tmpfile(name, fd);
- close(fd);
- unlink(ret_file.c_str());
-
- return ret_file.c_str();
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <libtest/common.h>
-
-namespace libtest {
-
-std::string create_tmpfile(const std::string&, int&);
-std::string create_tmpfile(const std::string&);
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <libtest/yatl.h>
-
-#if defined(HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H) && HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H
-# include <libmemcached-1.0/types/return.h>
-#endif
-
-#if defined(HAVE_LIBGEARMAN_1_0_RETURN_H) && HAVE_LIBGEARMAN_1_0_RETURN_H
-# include <libgearman-1.0/return.h>
-#endif
-
-#include <cstdlib>
-#include <unistd.h>
-
-using namespace libtest;
-
-static std::string testing_service;
-
-// Used to track setups where we see if failure is happening
-static uint32_t fatal_calls= 0;
-
-static test_return_t getenv_TEST(void *)
-{
-#if 0
- for (char **ptr= environ; *ptr; ptr++)
- {
- Error << *ptr;
- }
-#endif
-
- return TEST_SUCCESS;
-}
-
-static test_return_t LIBTOOL_COMMAND_test(void *)
-{
- test_true(getenv("LIBTOOL_COMMAND"));
- return TEST_SUCCESS;
-}
-
-static test_return_t VALGRIND_COMMAND_test(void *)
-{
- test_true(getenv("VALGRIND_COMMAND"));
- return TEST_SUCCESS;
-}
-
-static test_return_t HELGRIND_COMMAND_test(void *)
-{
- test_true(getenv("HELGRIND_COMMAND"));
- return TEST_SUCCESS;
-}
-
-static test_return_t GDB_COMMAND_test(void *)
-{
- test_true(getenv("GDB_COMMAND"));
- return TEST_SUCCESS;
-}
-
-static test_return_t test_success_equals_one_test(void *)
-{
- test_skip(HAVE_LIBMEMCACHED, 1);
-#if defined(HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H) && HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H
- test_zero(MEMCACHED_SUCCESS);
-#endif
- return TEST_SUCCESS;
-}
-
-static test_return_t test_success_test(void *)
-{
- return TEST_SUCCESS;
-}
-
-static test_return_t test_throw_success_TEST(void *)
-{
- try {
- _SUCCESS;
- }
- catch (const libtest::__success&)
- {
- return TEST_SUCCESS;
- }
- catch (...)
- {
- return TEST_FAILURE;
- }
-
- return TEST_FAILURE;
-}
-
-static test_return_t test_throw_skip_macro_TEST(void *)
-{
- try {
- SKIP_IF(true);
- }
- catch (const libtest::__skipped&)
- {
- return TEST_SUCCESS;
- }
- catch (...)
- {
- FAIL("SLIP_IF() failed to throw libtest::_skipped");
- }
-
- FAIL("SLIP_IF() failed to throw");
-
- return TEST_FAILURE;
-}
-
-static test_return_t test_throw_skip_unless_macro_TEST(void *)
-{
- try {
- SKIP_UNLESS(false);
- }
- catch (const libtest::__skipped&)
- {
- return TEST_SUCCESS;
- }
- catch (...)
- {
- FAIL("SLIP_UNLESS() failed to throw libtest::_skipped");
- }
-
- FAIL("SLIP_UNLESS() failed to throw");
-
- return TEST_FAILURE;
-}
-
-static test_return_t test_throw_skip_TEST(void *)
-{
- try {
- throw libtest::__skipped(LIBYATL_DEFAULT_PARAM, "basic test");
- }
- catch (const libtest::__skipped&)
- {
- return TEST_SUCCESS;
- }
- catch (...)
- {
- FAIL("SLIP_IF() failed to throw libtest::_skipped");
- }
-
- FAIL("SLIP_IF() failed to throw");
-
- return TEST_FAILURE;
-}
-
-static test_return_t test_throw_fail_TEST(void *)
-{
- try {
- FAIL("test message!");
- }
- catch (const libtest::__failure& e)
- {
- std::string compare_message("test message!");
- test_zero(compare_message.compare(e.what()));
- return TEST_SUCCESS;
- }
- catch (...)
- {
- return TEST_FAILURE;
- }
-
- return TEST_FAILURE;
-}
-#pragma GCC diagnostic ignored "-Wstack-protector"
-
-#ifdef __clang__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wformat-security"
-#endif
-
-static test_return_t ASSERT_FALSE__TEST(void *)
-{
- try {
- ASSERT_FALSE(true);
- }
- catch (const libtest::__failure& e)
- {
- ASSERT_STREQ(e.what(), "Assertion '!true'");
- return TEST_SUCCESS;
- }
- catch (...)
- {
- return TEST_FAILURE;
- }
-
- return TEST_FAILURE;
-}
-
-#ifdef __clang__
-# pragma GCC diagnostic pop
-#endif
-
-static test_return_t ASSERT_NEQ_FAIL_TEST(void *)
-{
- try {
- ASSERT_NEQ(1,1);
- }
- catch (const libtest::__failure& e)
- {
- ASSERT_STREQ(e.what(), "Assertion '1' == '1'");
- return TEST_SUCCESS;
- }
- catch (...)
- {
- return TEST_FAILURE;
- }
-
- return TEST_FAILURE;
-}
-
-static test_return_t ASSERT_NEQ_TEST(void *)
-{
- ASSERT_NEQ(1,0);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t ASSERT_FALSE_TEST(void *)
-{
- try {
- FAIL(__func__);
- }
- catch (const libtest::__failure& e)
- {
- ASSERT_STREQ(e.what(), __func__);
- return TEST_SUCCESS;
- }
- catch (...)
- {
- return TEST_FAILURE;
- }
-
- return TEST_FAILURE;
-}
-
-static test_return_t test_failure_test(void *)
-{
- return TEST_SKIPPED; // Only run this when debugging
-
- ASSERT_EQ(1, 2);
- return TEST_SUCCESS;
-}
-
-static test_return_t local_test(void *)
-{
- if (getenv("LIBTEST_LOCAL"))
- {
- test_true(test_is_local());
- }
- else
- {
- test_false(test_is_local());
- }
-
- return TEST_SUCCESS;
-}
-
-static test_return_t local_not_test(void *)
-{
- return TEST_SKIPPED;
-
- std::string temp;
-
- const char *ptr;
- if ((ptr= getenv("LIBTEST_LOCAL")) == NULL)
- {
- temp.append(ptr);
- }
-
- // unsetenv() will cause issues with valgrind
- _compare(__FILE__, __LINE__, __func__, 0, unsetenv("LIBTEST_LOCAL"), true);
- ASSERT_EQ(0, unsetenv("LIBTEST_LOCAL"));
- test_false(test_is_local());
-
- ASSERT_EQ(0, setenv("LIBTEST_LOCAL", "1", 1));
- test_true(test_is_local());
-
- if (temp.empty())
- {
- ASSERT_EQ(0, unsetenv("LIBTEST_LOCAL"));
- }
- else
- {
- char *old_string= strdup(temp.c_str());
- ASSERT_EQ(0, setenv("LIBTEST_LOCAL", old_string, 1));
- }
-
- return TEST_SUCCESS;
-}
-
-static test_return_t var_exists_test(void *)
-{
- ASSERT_EQ(0, access("var", R_OK | W_OK | X_OK));
- return TEST_SUCCESS;
-}
-
-static test_return_t var_tmp_exists_test(void *)
-{
- ASSERT_EQ(0, access("var/tmp", R_OK | W_OK | X_OK));
- return TEST_SUCCESS;
-}
-
-static test_return_t var_run_exists_test(void *)
-{
- ASSERT_EQ(0, access("var/run", R_OK | W_OK | X_OK));
- return TEST_SUCCESS;
-}
-
-static test_return_t var_log_exists_test(void *)
-{
- ASSERT_EQ(0, access("var/log", R_OK | W_OK | X_OK));
- return TEST_SUCCESS;
-}
-
-static test_return_t var_drizzle_exists_test(void *)
-{
- ASSERT_EQ(0, access("var/drizzle", R_OK | W_OK | X_OK));
- return TEST_SUCCESS;
-}
-
-static test_return_t var_tmp_test(void *)
-{
- FILE *file= fopen("var/tmp/junk", "w+");
- test_true(file);
- fclose(file);
- return TEST_SUCCESS;
-}
-
-static test_return_t var_run_test(void *)
-{
- FILE *file= fopen("var/run/junk", "w+");
- test_true(file);
- fclose(file);
- return TEST_SUCCESS;
-}
-
-static test_return_t var_log_test(void *)
-{
- FILE *file= fopen("var/log/junk", "w+");
- test_true(file);
- fclose(file);
- return TEST_SUCCESS;
-}
-
-static test_return_t var_drizzle_test(void *)
-{
- FILE *file= fopen("var/drizzle/junk", "w+");
- test_true(file);
- fclose(file);
- return TEST_SUCCESS;
-}
-
-static test_return_t var_tmp_rm_test(void *)
-{
- test_true(unlink("var/tmp/junk") == 0);
- return TEST_SUCCESS;
-}
-
-static test_return_t var_run_rm_test(void *)
-{
- test_true(unlink("var/run/junk") == 0);
- return TEST_SUCCESS;
-}
-
-static test_return_t var_log_rm_test(void *)
-{
- test_true(unlink("var/log/junk") == 0);
- return TEST_SUCCESS;
-}
-
-static test_return_t var_drizzle_rm_test(void *)
-{
- test_true(unlink("var/drizzle/junk") == 0);
- return TEST_SUCCESS;
-}
-
-static test_return_t _compare_test_return_t_test(void *)
-{
- ASSERT_EQ(TEST_SUCCESS, TEST_SUCCESS);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t _compare_memcached_return_t_test(void *)
-{
- test_skip(HAVE_LIBMEMCACHED, true);
-#if defined(HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H) && HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H
- ASSERT_EQ(MEMCACHED_SUCCESS, MEMCACHED_SUCCESS);
-#endif
-
- return TEST_SUCCESS;
-}
-
-static test_return_t _compare_gearman_return_t_test(void *)
-{
- test_skip(HAVE_LIBGEARMAN, true);
-#if defined(HAVE_LIBGEARMAN_1_0_RETURN_H) && HAVE_LIBGEARMAN_1_0_RETURN_H
- ASSERT_EQ(GEARMAN_SUCCESS, GEARMAN_SUCCESS);
-#endif
-
- return TEST_SUCCESS;
-}
-
-static test_return_t drizzled_cycle_test(void *object)
-{
- server_startup_st *servers= (server_startup_st*)object;
- test_true(servers and servers->validate());
-
-#if defined(HAVE_GEARMAND_BINARY) && HAVE_GEARMAND_BINARY
- test_true(has_drizzled());
-#endif
-
- test_skip(true, has_drizzled());
-
- test_skip(true, server_startup(*servers, "drizzled", get_free_port(), NULL));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t gearmand_cycle_test(void *object)
-{
- server_startup_st *servers= (server_startup_st*)object;
- test_true(servers and servers->validate());
-
- test_skip(true, has_gearmand());
- test_skip(true, server_startup(*servers, "gearmand", get_free_port(), NULL));
- servers->clear();
-
- return TEST_SUCCESS;
-}
-
-static test_return_t skip_shim(bool a, bool b)
-{
- test_skip(a, b);
- return TEST_SUCCESS;
-}
-
-static test_return_t test_skip_true_TEST(void*)
-{
- ASSERT_EQ(true, true);
- ASSERT_EQ(false, false);
- ASSERT_EQ(TEST_SUCCESS, skip_shim(true, true));
- ASSERT_EQ(TEST_SUCCESS, skip_shim(false, false));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t test_skip_false_TEST(void*)
-{
- ASSERT_EQ(TEST_SKIPPED, skip_shim(true, false));
- ASSERT_EQ(TEST_SKIPPED, skip_shim(false, true));
- return TEST_SUCCESS;
-}
-
-static test_return_t server_startup_fail_TEST(void *object)
-{
- server_startup_st *servers= (server_startup_st*)object;
- test_true(servers);
-
- fatal::disable();
- ASSERT_EQ(servers->start_server(testing_service, LIBTEST_FAIL_PORT, NULL), true);
- fatal::enable();
-
- return TEST_SUCCESS;
-}
-
-static test_return_t server_startup_TEST(void *object)
-{
- server_startup_st *servers= (server_startup_st*)object;
- test_true(servers);
-
- ASSERT_EQ(servers->start_server(testing_service, get_free_port(), NULL), true);
-
- test_true(servers->last());
- pid_t last_pid= servers->last()->pid();
-
- ASSERT_EQ(servers->last()->pid(), last_pid);
- test_true(last_pid > 1);
- ASSERT_EQ(kill(last_pid, 0), 0);
-
- test_true(servers->shutdown());
-#if 0
- ASSERT_EQ(servers->last()->pid(), -1);
- ASSERT_EQ(kill(last_pid, 0), -1);
-#endif
-
- return TEST_SUCCESS;
-}
-
-static test_return_t socket_server_startup_TEST(void *object)
-{
- server_startup_st *servers= (server_startup_st*)object;
- test_true(servers);
-
- test_true(servers->start_socket_server(testing_service, get_free_port(), NULL));
-
- return TEST_SUCCESS;
-}
-
-#if 0
-static test_return_t memcached_sasl_test(void *object)
-{
- server_startup_st *servers= (server_startup_st*)object;
- test_true(servers);
-
- test_skip(false, bool(getenv("LOG_COMPILER")));
-
- if (MEMCACHED_SASL_BINARY)
- {
- if (HAVE_LIBMEMCACHED)
- {
- test_true(has_memcached_sasl());
- test_true(server_startup(*servers, "memcached-sasl", get_free_port(), NULL));
-
- return TEST_SUCCESS;
- }
- }
-
- return TEST_SKIPPED;
-}
-#endif
-
-static test_return_t application_true_BINARY(void *)
-{
- test_skip(0, access("/usr/bin/true", X_OK ));
- Application true_app("/usr/bin/true");
-
- ASSERT_EQ(Application::SUCCESS, true_app.run());
- ASSERT_EQ(Application::SUCCESS, true_app.join());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t application_gdb_true_BINARY2(void *)
-{
- test_skip(0, access("/usr/bin/gdb", X_OK ));
- test_skip(0, access("/usr/bin/true", X_OK ));
-
- Application true_app("/usr/bin/true");
- true_app.use_gdb(true);
-
- ASSERT_EQ(Application::SUCCESS, true_app.run());
- ASSERT_EQ(Application::SUCCESS, true_app.join());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t application_gdb_true_BINARY(void *)
-{
- test_skip(0, access("/usr/bin/gdb", X_OK ));
- test_skip(0, access("/usr/bin/true", X_OK ));
-
- Application true_app("/usr/bin/true");
- true_app.use_gdb(true);
-
- const char *args[]= { "--fubar", 0 };
- ASSERT_EQ(Application::SUCCESS, true_app.run(args));
- ASSERT_EQ(Application::SUCCESS, true_app.join());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t application_true_fubar_BINARY(void *)
-{
- test_skip(0, access("/usr/bin/true", X_OK ));
- Application true_app("/usr/bin/true");
-
- const char *args[]= { "--fubar", 0 };
- ASSERT_EQ(Application::SUCCESS, true_app.run(args));
- ASSERT_EQ(Application::SUCCESS, true_app.join());
- test_zero(true_app.stdout_result().size());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t application_doesnotexist_BINARY(void *)
-{
-
- test_skip_valgrind();
- Application true_app("doesnotexist");
- true_app.will_fail();
-
- const char *args[]= { "--fubar", 0 };
-#if defined(__APPLE__) && __APPLE__
- ASSERT_EQ(Application::INVALID_POSIX_SPAWN, true_app.run(args));
-#elif defined(__FreeBSD__) && __FreeBSD__
- ASSERT_EQ(Application::INVALID_POSIX_SPAWN, true_app.run(args));
-#else
- Application::error_t rc = true_app.run(args);
- if (Application::SUCCESS == rc) {
- ASSERT_EQ(Application::INVALID_POSIX_SPAWN, true_app.join());
- } else {
- ASSERT_EQ(Application::INVALID_POSIX_SPAWN, rc);
- }
-#endif
-
- test_zero(true_app.stdout_result().size());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t GET_TEST(void *)
-{
- libtest::http::GET get("http://foo.example.com/");
-
- ASSERT_EQ(false, get.execute());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t POST_TEST(void *)
-{
- libtest::vchar_t body;
- libtest::http::POST post("http://foo.example.com/", body);
-
- ASSERT_EQ(false, post.execute());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t TRACE_TEST(void *)
-{
- libtest::vchar_t body;
- libtest::http::TRACE trace("http://foo.example.com/", body);
-
- ASSERT_EQ(false, trace.execute());
-
- return TEST_SUCCESS;
-}
-
-
-static test_return_t vchar_t_TEST(void *)
-{
- libtest::vchar_t response;
- libtest::make_vector(response, test_literal_param("fubar\n"));
- ASSERT_EQ(response, response);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t vchar_t_make_append_TEST(void *)
-{
- libtest::vchar_t hostname;
- libtest::vchar::make(hostname, 23);
- libtest::vchar::append(hostname, ".com");
- ASSERT_EQ(28, hostname.size());
- ASSERT_EQ(0, hostname[27]);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t vchar_t_compare_neg_TEST(void *)
-{
- libtest::vchar_t response;
- libtest::vchar_t response2;
- libtest::make_vector(response, test_literal_param("fubar\n"));
- libtest::make_vector(response2, test_literal_param(__func__));
- test_true(response != response2);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t application_echo_fubar_BINARY(void *)
-{
- if (0)
- {
- test_skip(0, access("/bin/echo", X_OK ));
- Application true_app("/bin/echo");
-
- const char *args[]= { "fubar", 0 };
- ASSERT_EQ(Application::SUCCESS, true_app.run(args));
-
- while (true_app.slurp() == false) {} ;
-
- libtest::vchar_t response;
- make_vector(response, test_literal_param("fubar\n"));
- ASSERT_EQ(response, true_app.stdout_result());
- }
-
- return TEST_SUCCESS;
-}
-
-static test_return_t application_echo_fubar_BINARY2(void *)
-{
- if (0)
- {
- test_skip(0, access("/bin/echo", X_OK ));
- Application true_app("/bin/echo");
-
- true_app.add_option("fubar");
-
- ASSERT_EQ(Application::SUCCESS, true_app.run());
- ASSERT_EQ(Application::SUCCESS, true_app.join());
-
- libtest::vchar_t response;
- make_vector(response, test_literal_param("fubar\n"));
- ASSERT_EQ(response, true_app.stdout_result());
- }
-
- return TEST_SUCCESS;
-}
-
-static test_return_t echo_fubar_BINARY(void *)
-{
- const char *args[]= { "fubar", 0 };
- ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("/bin/echo", args));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t core_count_BINARY(void *)
-{
- const char *args[]= { 0 };
-
- ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/core-count", args, true));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t wait_BINARY(void *)
-{
- const char *args[]= { "--quiet", 0 };
-
- ASSERT_EQ(EXIT_FAILURE, exec_cmdline("libtest/wait", args, true));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t wait_help_BINARY(void *)
-{
- const char *args[]= { "--quiet", "--help", 0 };
-
- ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t wait_version_BINARY(void *)
-{
- const char *args[]= { "--quiet", "--version", 0 };
-
- ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t wait_services_BINARY(void *)
-{
- test_skip(0, access("/etc/services", R_OK ));
-
- const char *args[]= { "--quiet", "/etc/services", 0 };
-
- ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t wait_services_BINARY2(void *)
-{
- test_skip(0, access("/etc/services", R_OK ));
-
- const char *args[]= { "/etc/services", 0 };
-
- ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t wait_services_appliction_TEST(void *)
-{
- test_skip(0, access("/etc/services", R_OK ));
- test_skip(0, access("/usr/bin/gdb", X_OK ));
- test_skip(0, access("libtest/wait", X_OK ));
-
- libtest::Application wait_app("libtest/wait", true);
- wait_app.use_gdb(true);
-
- const char *args[]= { "/etc/services", 0 };
- ASSERT_EQ(Application::SUCCESS, wait_app.run(args));
- ASSERT_EQ(Application::SUCCESS, wait_app.join());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t gdb_wait_services_appliction_TEST(void *)
-{
- test_skip(true, false);
-#if defined(__APPLE__) && __APPLE__
- test_skip(0, __APPLE__);
-#endif
-
- test_skip(0, access("/etc/services", R_OK ));
- test_skip(0, access("/usr/bin/gdb", X_OK ));
- test_skip(0, access("libtest/wait", X_OK ));
-
- libtest::Application wait_app("libtest/wait", true);
- wait_app.use_gdb(true);
-
- const char *args[]= { "/etc/services", 0 };
- ASSERT_EQ(Application::SUCCESS, wait_app.run(args));
- ASSERT_EQ(Application::SUCCESS, wait_app.join());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t gdb_abort_services_appliction_TEST(void *)
-{
- test_skip(0, access("/usr/bin/gdb", X_OK ));
- test_skip(0, access("libtest/abort", X_OK ));
- test_skip(true, false);
-
-#if defined(__APPLE__) && __APPLE__
- test_skip(0, __APPLE__);
-#endif
-
- libtest::Application abort_app("libtest/abort", true);
- abort_app.use_gdb(true);
-
- ASSERT_EQ(Application::SUCCESS, abort_app.run());
- ASSERT_EQ(Application::SUCCESS, abort_app.join());
-
- std::string gdb_filename= abort_app.gdb_filename();
- test_skip(0, access(gdb_filename.c_str(), R_OK ));
- const char *args[]= { "SIGABRT", gdb_filename.c_str(), 0 };
- ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("grep", args));
-
- // Sanity test
- args[0]= "THIS_WILL_NOT_BE_FOUND";
- ASSERT_EQ(EXIT_FAILURE, exec_cmdline("grep", args));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t get_free_port_TEST(void *)
-{
- in_port_t ret_port;
- test_true((ret_port= get_free_port()));
- test_true(get_free_port() != default_port());
- test_true(get_free_port() != get_free_port());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t fatal_TEST(void *)
-{
- ASSERT_EQ(fatal_calls++, fatal::disabled_counter());
- throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "Testing va_args based fatal(): %d", 10);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t number_of_cpus_TEST(void *)
-{
- test_true(number_of_cpus() >= 1);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t check_dns_TEST(void *)
-{
- test_warn(libtest::check_dns(), "Broken DNS server/no DNS server found");
-
- return TEST_SUCCESS;
-}
-
-static test_return_t Timer_TEST(void *)
-{
- int64_t minutes= random() % 50;
- minutes++;
-
- Timer check;
-
- check.reset();
- check.offset(minutes, 2, 200);
-
- ASSERT_EQ(check.minutes(), minutes);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t lookup_true_TEST(void *)
-{
- test_warn(libtest::lookup("exist.gearman.info"), "dns is not currently working");
- return TEST_SUCCESS;
-}
-
-static test_return_t lookup_false_TEST(void *)
-{
- SKIP_IF_(libtest::lookup("does_not_exist.gearman.info"),
- "Broken DNS server detected");
-
- return TEST_SUCCESS;
-}
-
-static test_return_t create_tmpfile_TEST(void *)
-{
- test_skip(0, access("/usr/bin/touch", X_OK ));
- std::string tmp= create_tmpfile(__func__);
- ASSERT_EQ(-1, access(tmp.c_str(), R_OK));
- ASSERT_EQ(-1, access(tmp.c_str(), F_OK));
-
- Application touch_app("/usr/bin/touch");
- const char *args[]= { tmp.c_str(), 0 };
- ASSERT_EQ(Application::SUCCESS, touch_app.run(args));
- ASSERT_EQ(Application::SUCCESS, touch_app.join());
-
- ASSERT_EQ(0, access(tmp.c_str(), R_OK));
- ASSERT_EQ(0, unlink(tmp.c_str()));
-
- return TEST_SUCCESS;
-}
-
-static test_return_t fatal_message_TEST(void *)
-{
- ASSERT_EQ(fatal_calls++, fatal::disabled_counter());
- FATAL("Fatal test");
-
- return TEST_SUCCESS;
-}
-
-static test_return_t default_port_TEST(void *)
-{
- in_port_t ret_port= default_port();
- ASSERT_EQ(ret_port, libtest::default_port());
- ASSERT_EQ(ret_port, libtest::default_port());
-
- return TEST_SUCCESS;
-}
-
-static test_return_t check_for_VALGRIND(void *)
-{
- test_skip_valgrind();
- return TEST_SUCCESS;
-}
-
-static test_return_t check_for_gearman(void *)
-{
- test_skip(true, HAVE_LIBGEARMAN);
- test_skip(true, has_gearmand());
-#if defined(HAVE_GEARMAND_BINARY) && HAVE_GEARMAND_BINARY
- if (GEARMAND_BINARY)
- {
- if (strcmp(GEARMAND_BINARY, "./gearmand/gearmand"))
- {
- test_zero(access(GEARMAND_BINARY, X_OK ));
- }
- }
- else
- {
- return TEST_SKIPPED;
- }
-#endif
-
- testing_service= "gearmand";
-
- return TEST_SUCCESS;
-}
-
-static test_return_t check_for_drizzle(void *)
-{
- test_skip(true, has_drizzled());
-
- testing_service= "drizzled";
-
- return TEST_SUCCESS;
-}
-
-
-test_st drizzled_tests[] ={
- {"drizzled startup-shutdown", 0, drizzled_cycle_test },
- {0, 0, 0}
-};
-
-test_st gearmand_tests[] ={
-#if 0
- {"pause", 0, pause_test },
-#endif
- {"gearmand startup-shutdown", 0, gearmand_cycle_test },
- {"_compare(gearman_return_t)", 0, _compare_gearman_return_t_test },
- {"server_startup(fail)", 0, server_startup_fail_TEST },
- {0, 0, 0}
-};
-
-static test_return_t clear_servers(void* object)
-{
- server_startup_st *servers= (server_startup_st*)object;
- test_true(servers);
- servers->clear();
-
- testing_service.clear();
-
- return TEST_SUCCESS;
-}
-
-static test_return_t check_for_memcached(void* object)
-{
- test_skip(true, has_memcached());
-
- server_startup_st *servers= (server_startup_st*)object;
- test_true(servers);
- servers->clear();
-
- testing_service= "memcached";
-
- return TEST_SUCCESS;
-}
-
-test_st memcached_TESTS[] ={
- {"memcached startup-shutdown", 0, server_startup_TEST },
- {"memcached(socket file) startup-shutdown", 0, socket_server_startup_TEST },
- {"_compare(memcached_return_t)", 0, _compare_memcached_return_t_test },
- {"server_startup(fail)", 0, server_startup_fail_TEST },
- {0, 0, 0}
-};
-
-test_st test_skip_TESTS[] ={
- {"true, true", 0, test_skip_true_TEST },
- {"true, false", 0, test_skip_false_TEST },
- {0, 0, 0}
-};
-
-test_st environment_tests[] ={
- {"getenv()", 0, getenv_TEST },
- {"LIBTOOL_COMMAND", 0, LIBTOOL_COMMAND_test },
- {"VALGRIND_COMMAND", 0, VALGRIND_COMMAND_test },
- {"HELGRIND_COMMAND", 0, HELGRIND_COMMAND_test },
- {"GDB_COMMAND", 0, GDB_COMMAND_test },
- {0, 0, 0}
-};
-
-test_st tests_log[] ={
- {"TEST_SUCCESS", false, test_success_test },
- {"TEST_FAILURE", false, test_failure_test },
- {"TEST_SUCCESS == 0", false, test_success_equals_one_test },
- {"SUCCESS", false, test_throw_success_TEST },
- {"libtest::__skipped", false, test_throw_skip_TEST },
- {"SKIP_IF", false, test_throw_skip_macro_TEST },
- {"SKIP_UNLESS", false, test_throw_skip_unless_macro_TEST },
- {"FAIL", false, test_throw_fail_TEST },
- {"ASSERT_FALSE_", false, ASSERT_FALSE__TEST },
- {"ASSERT_FALSE", false, ASSERT_FALSE_TEST },
- {"ASSERT_NEQ", false, ASSERT_NEQ_TEST },
- {"ASSERT_NEQ FAIL", false, ASSERT_NEQ_FAIL_TEST },
- {0, 0, 0}
-};
-
-test_st local_log[] ={
- {"test_is_local()", 0, local_test },
- {"test_is_local(NOT)", 0, local_not_test },
- {0, 0, 0}
-};
-
-test_st directories_tests[] ={
- {"var exists", 0, var_exists_test },
- {"var/tmp exists", 0, var_tmp_exists_test },
- {"var/run exists", 0, var_run_exists_test },
- {"var/log exists", 0, var_log_exists_test },
- {"var/drizzle exists", 0, var_drizzle_exists_test },
- {"var/tmp", 0, var_tmp_test },
- {"var/run", 0, var_run_test },
- {"var/log", 0, var_log_test },
- {"var/drizzle", 0, var_drizzle_test },
- {"var/tmp rm", 0, var_tmp_rm_test },
- {"var/run rm", 0, var_run_rm_test },
- {"var/log rm", 0, var_log_rm_test },
- {"var/drizzle rm", 0, var_drizzle_rm_test },
- {0, 0, 0}
-};
-
-test_st comparison_tests[] ={
- {"_compare(test_return_t)", 0, _compare_test_return_t_test },
- {0, 0, 0}
-};
-
-test_st cmdline_tests[] ={
- {"echo fubar", 0, echo_fubar_BINARY },
- {"core-count", 0, core_count_BINARY },
- {"wait --quiet", 0, wait_BINARY },
- {"wait --quiet --help", 0, wait_help_BINARY },
- {"wait --quiet --version", 0, wait_version_BINARY },
- {"wait --quiet /etc/services", 0, wait_services_BINARY },
- {"wait /etc/services", 0, wait_services_BINARY2 },
- {"wait /etc/services", 0, wait_services_appliction_TEST },
- {"gdb wait /etc/services", 0, gdb_wait_services_appliction_TEST },
- {"gdb abort", 0, gdb_abort_services_appliction_TEST },
- {0, 0, 0}
-};
-
-test_st get_free_port_TESTS[] ={
- {"get_free_port()", 0, get_free_port_TEST },
- {"default_port()", 0, default_port_TEST },
- {0, 0, 0}
-};
-
-test_st fatal_message_TESTS[] ={
- {"libtest::fatal", 0, fatal_TEST },
- {"fatal_message()", 0, fatal_message_TEST },
- {0, 0, 0}
-};
-
-test_st number_of_cpus_TESTS[] ={
- {"libtest::number_of_cpus()", 0, number_of_cpus_TEST },
- {0, 0, 0}
-};
-
-test_st create_tmpfile_TESTS[] ={
- {"libtest::create_tmpfile()", 0, create_tmpfile_TEST },
- {0, 0, 0}
-};
-
-test_st timer_TESTS[] ={
- {"libtest::Timer", 0, Timer_TEST },
- {0, 0, 0}
-};
-
-test_st dns_TESTS[] ={
- {"libtest::lookup(true)", 0, lookup_true_TEST },
- {"libtest::lookup(false)", 0, lookup_false_TEST },
- {"libtest::check_dns()", 0, check_dns_TEST },
- {0, 0, 0}
-};
-
-test_st application_tests[] ={
- {"vchar_t", 0, vchar_t_TEST },
- {"vchar_t make() append()", 0, vchar_t_make_append_TEST },
- {"vchar_t compare()", 0, vchar_t_compare_neg_TEST },
- {"true", 0, application_true_BINARY },
- {"gbd true --fubar", 0, application_gdb_true_BINARY },
- {"gbd true", 0, application_gdb_true_BINARY2 },
- {"true --fubar", 0, application_true_fubar_BINARY },
- {"doesnotexist --fubar", 0, application_doesnotexist_BINARY },
- {"echo fubar", 0, application_echo_fubar_BINARY },
- {"echo fubar (as option)", 0, application_echo_fubar_BINARY2 },
- {0, 0, 0}
-};
-
-static test_return_t check_for_curl(void *)
-{
- test_skip_valgrind();
- test_skip(true, HAVE_LIBCURL);
- return TEST_SUCCESS;
-}
-
-static test_return_t disable_fatal_exception(void *)
-{
- fatal_calls= 0;
- fatal::disable();
- return TEST_SUCCESS;
-}
-
-static test_return_t enable_fatal_exception(void *)
-{
- fatal::enable();
- return TEST_SUCCESS;
-}
-
-test_st http_tests[] ={
- {"GET", 0, GET_TEST },
- {"POST", 0, POST_TEST },
- {"TRACE", 0, TRACE_TEST },
- {0, 0, 0}
-};
-
-collection_st collection[] ={
- {"environment", 0, 0, environment_tests},
- {"return values", 0, 0, tests_log},
- {"test_skip()", 0, 0, test_skip_TESTS },
- {"local", 0, 0, local_log},
- {"directories", 0, 0, directories_tests},
- {"comparison", 0, 0, comparison_tests},
- {"gearmand", check_for_gearman, clear_servers, gearmand_tests},
- {"memcached", check_for_memcached, clear_servers, memcached_TESTS },
- {"drizzled", check_for_drizzle, clear_servers, drizzled_tests},
- {"cmdline", 0, 0, cmdline_tests},
- {"application", 0, 0, application_tests},
- {"http", check_for_curl, 0, http_tests},
- {"http", check_for_curl, 0, http_tests},
- {"get_free_port()", 0, 0, get_free_port_TESTS },
- {"fatal", disable_fatal_exception, enable_fatal_exception, fatal_message_TESTS },
- {"number_of_cpus()", 0, 0, number_of_cpus_TESTS },
- {"create_tmpfile()", 0, 0, create_tmpfile_TESTS },
- {"dns", check_for_VALGRIND, 0, dns_TESTS },
- {"libtest::Timer", 0, 0, timer_TESTS },
- {0, 0, 0, 0}
-};
-
-static void *world_create(server_startup_st& servers, test_return_t&)
-{
- return &servers;
-}
-
-void get_world(libtest::Framework *world)
-{
- world->collections(collection);
- world->create(world_create);
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-static inline bool valgrind_is_caller(void)
-{
- if (getenv("LOG_COMPILER") && strstr(getenv("LOG_COMPILER"), "valgrind"))
- {
- if (strstr(getenv("LOG_COMPILER"), "--tool") == NULL)
- {
- return true;
- }
-
- if (strstr(getenv("LOG_COMPILER"), "--tool=memcheck"))
- {
- return true;
- }
- }
-
- return false;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-#include <libtest/common.h>
-
-/* Use this for string generation */
-static const char ALPHANUMERICS[]=
- "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
-
-#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
-
-static size_t get_alpha_num(void)
-{
- return (size_t)random() % ALPHANUMERICS_SIZE;
-}
-
-namespace libtest {
-
-int random_alpha_num(void)
-{
- return ALPHANUMERICS[get_alpha_num()];
-}
-
-static std::string printer(const char *str, size_t length)
-{
- std::ostringstream buf;
- for (size_t x= 0; x < length; x++)
- {
- if (isprint(str[x]))
- {
- buf << str[x];
- }
- else
- {
- buf << "(" << int(str[x]) << ")";
- }
- }
-
- return buf.str();
-}
-
-namespace vchar {
-
-int compare(libtest::vchar_t& arg, const char *str, size_t length)
-{
- if (arg.size() == length and (memcmp(&arg[0], str, length) == 0))
- {
- return 0;
- }
- else if (arg.size() > length)
- {
- return 1;
- }
-
- return -1;
-}
-
-void make(libtest::vchar_t& arg)
-{
- size_t length= rand() % 1024;
- make(arg, length);
-}
-
-void make(libtest::vchar_t& arg, size_t length)
-{
- arg.reserve(length);
- for (uint32_t x= 0; x < length; ++x)
- {
- arg.push_back(ALPHANUMERICS[get_alpha_num()]);
- }
-}
-
-void chomp(libtest::vchar_t& arg)
-{
- while(arg.size())
- {
- if (arg.back() == 0)
- {
- arg.pop_back();
- }
- else
- {
- break;
- }
- }
-}
-
-void append(libtest::vchar_ptr_t& arg, const char* ptr)
-{
- if (ptr)
- {
- char* new_ptr= strdup(ptr);
- if (new_ptr == NULL)
- {
- FATAL("UNABLE to allocate %s(%p)", ptr, ptr);
- }
-
- arg.push_back(new_ptr);
- }
-}
-
-void append(libtest::vchar_t& arg, const char* ptr)
-{
- if (ptr)
- {
- size_t length= strlen(ptr);
- ASSERT_TRUE(length);
- arg.reserve(length);
- do
- {
- arg.push_back(*ptr);
- ++ptr;
- } while (*ptr);
-
- arg.push_back(0);
- }
-}
-
-} // namespace vchar
-
-void make_vector(libtest::vchar_t& arg, const char *str, size_t length)
-{
- arg.resize(length);
- memcpy(&arg[0], str, length);
-}
-
-std::ostream& operator<<(std::ostream& output, const libtest::vchar_t& arg)
-{
- std::string tmp= libtest::printer(arg.data(), arg.size());
- output << tmp << "[" << arg.size() << "]";
-
- return output;
-}
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <cstring>
-#include <iostream>
-#include <ostream>
-#include <sstream>
-#include <vector>
-
-namespace libtest {
-
-int random_alpha_num(void);
-
-typedef std::vector<char*> vchar_ptr_t;
-typedef std::vector<char> vchar_t;
-
-void make_vector(libtest::vchar_t& arg, const char *str, size_t length);
-
-namespace vchar {
-
-int compare(libtest::vchar_t& arg, const char *str, size_t length);
-void chomp(libtest::vchar_t& arg);
-void make(libtest::vchar_t& arg);
-void make(libtest::vchar_t& arg, size_t length);
-void append(libtest::vchar_ptr_t& arg, const char*);
-void append(libtest::vchar_t& arg, const char*);
-
-} // namespace vchar
-
-#define vchar_param(__arg) (&__arg[0]), (__arg.size())
-#define vchar_printf(__arg) int(__arg.size()), (&__arg[0])
-
-std::ostream& operator<<(std::ostream& output, const libtest::vchar_t& arg);
-
-} // namespace libtest
-
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#define LIBTEST_VERSION @LIBTEST_VERSION@
-#define LIBTEST_VERSION_STRING "@LIBTEST_VERSION@"
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#if defined(BUILDING_LIBTEST)
-# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
-# define LIBTEST_API __attribute__ ((visibility("default")))
-# define LIBTEST_LOCAL __attribute__ ((visibility("default")))
-# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
-# define LIBTEST_API __global
-# define LIBTEST_LOCAL __global
-# elif defined(_MSC_VER)
-# define LIBTEST_API extern __declspec(dllexport)
-# define LIBTEST_LOCAL extern __declspec(dllexport)
-# else
-# define LIBTEST_API
-# define LIBTEST_LOCAL
-# endif
-#else
-# if defined(BUILDING_LIBTEST)
-# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
-# define LIBTEST_API __attribute__ ((visibility("default")))
-# define LIBTEST_LOCAL __attribute__ ((visibility("hidden")))
-# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
-# define LIBTEST_API __global
-# define LIBTEST_LOCAL __hidden
-# elif defined(_MSC_VER)
-# define LIBTEST_API extern __declspec(dllexport)
-# define LIBTEST_LOCAL
-# else
-# define LIBTEST_API
-# define LIBTEST_LOCAL
-# endif /* defined(HAVE_VISIBILITY) */
-# else /* defined(BUILDING_LIBTEST) */
-# if defined(_MSC_VER)
-# define LIBTEST_API extern __declspec(dllimport)
-# define LIBTEST_LOCAL
-# else
-# define LIBTEST_API
-# define LIBTEST_LOCAL
-# endif /* defined(_MSC_VER) */
-# endif /* defined(BUILDING_LIBTEST) */
-#endif /* defined(BUILDING_LIBTESTINTERNAL) */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "libtest/yatlcon.h"
-
-#include <cstdlib>
-#include <fcntl.h>
-#include <getopt.h>
-#include <iostream>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <libtest/wait.h>
-
-static void version_command(const char *command_name, int major_version, int minor_version)
-{
- std::cout << command_name << " " << major_version << "." << minor_version << std::endl;
-}
-
-static void help_command(const char *command_name,
- int major_version, int minor_version,
- const struct option *long_options)
-{
- std::cout << command_name << " " << major_version << "." << minor_version << std::endl;
- std::cout << "Current options. A '=' means the option takes a value." << std::endl << std::endl;
-
- for (uint32_t x= 0; long_options[x].name; x++)
- {
- std::cout << "\t --" << long_options[x].name << char(long_options[x].has_arg ? '=' : ' ') << std::endl;
- }
-
- std::cout << std::endl;
-}
-
-static void close_stdio(void)
-{
- int fd;
- if ((fd = open("/dev/null", O_RDWR, 0)) < 0)
- {
- return;
- }
- else
- {
- if (dup2(fd, STDIN_FILENO) < 0)
- {
- return;
- }
-
- if (dup2(fd, STDOUT_FILENO) < 0)
- {
- return;
- }
-
- if (dup2(fd, STDERR_FILENO) < 0)
- {
- return;
- }
-
- if (fd > STDERR_FILENO)
- {
- close(fd);
- }
- }
-}
-
-enum {
- OPT_HELP,
- OPT_QUIET,
- OPT_VERSION
-};
-
-static void options_parse(int argc, char *argv[])
-{
- static struct option long_options[]=
- {
- { "version", no_argument, NULL, OPT_VERSION},
- { "help", no_argument, NULL, OPT_HELP},
- { "quiet", no_argument, NULL, OPT_QUIET},
- {0, 0, 0, 0},
- };
-
- bool opt_version= false;
- bool opt_help= false;
- bool opt_quiet= false;
- int option_index= 0;
-
- while (1)
- {
- int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
- if (option_rv == -1)
- {
- break;
- }
-
- switch (option_rv)
- {
- case OPT_HELP: /* --help or -h */
- opt_help= true;
- break;
-
- case OPT_VERSION: /* --version or -v */
- opt_version= true;
- break;
-
- case OPT_QUIET:
- opt_quiet= true;
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- exit(EXIT_FAILURE);
-
- default:
- help_command(argv[0], 1, 0, long_options);
- exit(EXIT_FAILURE);
- }
- }
-
- if (opt_quiet)
- {
- close_stdio();
- }
-
- if (opt_version)
- {
- version_command(argv[0], 1, 0);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_help)
- {
- help_command(argv[0], 1, 0, long_options);
- exit(EXIT_SUCCESS);
- }
-}
-
-int main(int argc, char *argv[])
-{
- if (argc == 1)
- {
- return EXIT_FAILURE;
- }
-
- options_parse(argc, argv);
-
- int ret= EXIT_FAILURE;
- while (optind < argc)
- {
- libtest::Wait wait(argv[optind++]);
-
- if (wait.successful() == false)
- {
- return EXIT_FAILURE;
- }
-
- ret= EXIT_SUCCESS;
- }
-
- return ret;
-}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <unistd.h>
-#include <string>
-#include <signal.h>
-
-#include <libtest/dream.h>
-
-namespace libtest {
-
-class Wait
-{
-public:
-
- Wait(const std::string &filename, uint32_t timeout= 6) :
- _successful(false)
- {
- uint32_t waited;
- uint32_t this_wait;
- uint32_t retry;
-
- if (filename.empty())
- {
- _successful= false;
- return;
- }
-
- for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
- {
- if (access(filename.c_str(), R_OK) == 0)
- {
- _successful= true;
- break;
- }
- else if (waited >= timeout)
- {
- break;
- }
-
- this_wait= retry * retry / 3 + 1;
- libtest::dream(0, this_wait * 10000000);
- }
- }
-
- Wait(const pid_t &_pid_arg, uint32_t timeout= 6) :
- _successful(false)
- {
- uint32_t waited;
- uint32_t this_wait;
- uint32_t retry;
-
- for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
- {
- if (kill(_pid_arg, 0) == 0)
- {
- _successful= true;
- break;
- }
- else if (waited >= timeout)
- {
- break;
- }
-
- this_wait= retry * retry / 3 + 1;
- libtest::dream(0, this_wait * 10000000);
- }
- }
-
- bool successful() const
- {
- return _successful;
- }
-
-private:
- bool _successful;
-};
-
-} // namespace libtest
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#ifndef YATL_FULL
-# define YATL_FULL 1
-#endif
-
-#include <libtest/test.hpp>
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential YATL (i.e. libtest) library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#pragma once
-
-#include "@AUTOHEADER_FILE@"
-
-#ifndef LIBTEST_TEMP
-# define LIBTEST_TEMP "/tmp"
-#endif
-
-#define HAVE_LIBMEMCACHED 1
+++ /dev/null
-#pragma once
-
-#cmakedefine01 LIBMEMCACHED_WITH_SASL_SUPPORT
-
-#define LIBMEMCACHED_WITH_SASL_PWDB "@LIBMEMCACHED_WITH_SASL_PWDB@"
-#define LIBMEMCACHED_WITH_SASL_CONF "@LIBMEMCACHED_WITH_SASL_CONF@"
-
-#cmakedefine HAVE_C_STDATOMIC 1
-#cmakedefine HAVE_CXX_STDATOMIC 1
-
-#cmakedefine HAVE_ARPA_INET_H 1
-#cmakedefine HAVE_DLFCN_H 1
-#cmakedefine HAVE_DTRACE 1
-#cmakedefine HAVE_ERRNO_H 1
-#cmakedefine HAVE_EXECINFO_H 1
-#cmakedefine HAVE_FCNTL 1
-#cmakedefine HAVE_FCNTL_H 1
-#cmakedefine HAVE_FNV64_HASH 1
-#cmakedefine HAVE_GETLINE
-#cmakedefine HAVE_HSIEH_HASH 1
-#cmakedefine HAVE_HTONLL 1
-#cmakedefine HAVE_IN_PORT_T 1
-#cmakedefine HAVE_IO_H 1
-#cmakedefine HAVE_LIBEVENT 1
-#cmakedefine HAVE_LIBSASL 1
-#cmakedefine HAVE_LIBUUID 1
-#cmakedefine HAVE_LIMITS_H 1
-#cmakedefine HAVE_MSG_DONTWAIT 1
-#cmakedefine HAVE_MSG_MORE 1
-#cmakedefine HAVE_MSG_NOSIGNAL 1
-#cmakedefine HAVE_MURMUR_HASH 1
-#cmakedefine HAVE_NETDB_H 1
-#cmakedefine HAVE_POLL_H 1
-#cmakedefine HAVE_RCVTIMEO 1
-#cmakedefine HAVE_SASL_SASL_H 1
-#cmakedefine HAVE_SHARED_ENABLED 1
-#cmakedefine HAVE_SNDTIMEO 1
-#cmakedefine HAVE_STDDEF_H 1
-#cmakedefine HAVE_STDLIB_H 1
-#cmakedefine HAVE_STRERROR 1
-#cmakedefine HAVE_STRERROR_R 1
-#cmakedefine HAVE_STRINGS_H 1
-#cmakedefine HAVE_SYS_SOCKET_H 1
-#cmakedefine HAVE_SYS_TIME_H 1
-#cmakedefine HAVE_SYS_TYPES_H 1
-#cmakedefine HAVE_SYS_WAIT_H 1
-#cmakedefine HAVE_SYS_UN_H 1
-#cmakedefine HAVE_TIME_H 1
-#cmakedefine HAVE_UMEM_H 1
-#cmakedefine HAVE_UNISTD_H 1
-#cmakedefine HAVE_VISIBILITY 1
-#cmakedefine HAVE_WINSOCK2_H 1
-#cmakedefine HAVE_WS2TCPIP_H 1
-
-#cmakedefine HAVE_ABI____CXA_DEMANGLE 1
-#cmakedefine HAVE_GCC_ABI_DEMANGLE 1
-
-#cmakedefine HAVE_CINTTYPES 1
-#cmakedefine HAVE_CSTDINT 1
-#if defined(__cplusplus)
-# if defined HAVE_CINTTYPES
-# include <cinttypes>
-# elif defined HAVE_CSTDINT
-# include <cstdint>
-# endif
-#else
-# include <inttypes.h>
-#endif
-
-#define HAVE_LIBMEMCACHED 1
--- /dev/null
+
+add_subdirectory(bin)
+add_subdirectory(libhashkit)
+add_subdirectory(libmemcached)
+add_subdirectory(libmemcachedutil)
+
+if(BUILD_TESTING)
+ add_subdirectory(libtest)
+endif()
--- /dev/null
+
+add_library(libclient_utilities STATIC utilities.cc generator.cc execute.cc)
+add_library(client_utilities ALIAS libclient_utilities)
+target_link_libraries(libclient_utilities libmemcachedinternal)
+
+foreach(CLIENT IN LISTS CLIENTS)
+ add_executable(${CLIENT} ${CLIENT}.cc)
+ target_include_directories(${CLIENT} PRIVATE ..)
+ target_link_libraries(${CLIENT} libclient_utilities)
+ install(TARGETS ${CLIENT}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+endforeach()
+
+# extra sources
+
+target_sources(memcapable PRIVATE ../libmemcached/byteorder.cc)
+
+# extra libs
+
+target_link_libraries(memcapable Threads::Threads)
+target_link_libraries(memping libmemcachedutil)
+target_link_libraries(memslap Threads::Threads)
+
+# memaslap is special
+
+if(ENABLE_MEMASLAP)
+ if(LIBEVENT AND HAVE_C_STDATOMIC)
+ add_executable(memaslap memaslap.c
+ ms_conn.c ms_setting.c ms_sigsegv.c ms_stats.c ms_task.c ms_thread.c)
+ target_include_directories(memaslap PRIVATE ${LIBEVENT_INCLUDEDIR})
+ target_link_libraries(memaslap libclient_utilities ${LIBEVENT_LIBRARIES} Threads::Threads)
+ install(TARGETS memaslap
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+ endif()
+endif()
--- /dev/null
+/* 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:
+ *
+ */
+
+#pragma once
+
+typedef struct memcached_help_text_st memcached_help_text_st;
+
+enum memcached_options {
+ OPT_SERVERS= 's',
+ OPT_VERSION= 'V',
+ OPT_HELP= 'h',
+ OPT_VERBOSE= 'v',
+ OPT_DEBUG= 'd',
+ OPT_ANALYZE= 'a',
+ OPT_FLAG= 257,
+ OPT_EXPIRE,
+ OPT_SET,
+ OPT_REPLACE,
+ OPT_ADD,
+ OPT_SLAP_EXECUTE_NUMBER,
+ OPT_SLAP_INITIAL_LOAD,
+ OPT_SLAP_TEST,
+ OPT_SLAP_CONCURRENCY,
+ OPT_SLAP_NON_BLOCK,
+ OPT_SLAP_TCP_NODELAY,
+ OPT_FLUSH,
+ OPT_HASH,
+ OPT_BINARY,
+ OPT_UDP,
+ OPT_BUFFER,
+ OPT_USERNAME,
+ OPT_PASSWD,
+ OPT_STAT_ARGS,
+ OPT_SERVER_VERSION,
+ OPT_QUIET,
+ OPT_FILE= 'f'
+};
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+/*
+ Execute a memcached_set() a set of pairs.
+ Return the number of rows set.
+*/
+
+#include <mem_config.h>
+#include "execute.h"
+
+unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
+{
+ uint32_t count= 0;
+ for (; count < number_of; ++count)
+ {
+ memcached_return_t rc= memcached_set(memc, pairs[count].key, pairs[count].key_length,
+ pairs[count].value, pairs[count].value_length,
+ 0, 0);
+ if (memcached_failed(rc))
+ {
+ fprintf(stderr, "%s:%d Failure on %u insert (%s) of %.*s\n",
+ __FILE__, __LINE__, count,
+ memcached_last_error_message(memc),
+ (unsigned int)pairs[count].key_length, pairs[count].key);
+
+ // We will try to reconnect and see if that fixes the issue
+ memcached_quit(memc);
+
+ return count;
+ }
+ }
+
+ return count;
+}
+
+/*
+ Execute a memcached_get() on a set of pairs.
+ Return the number of rows retrieved.
+*/
+unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
+{
+ unsigned int x;
+ unsigned int retrieved;
+
+
+ for (retrieved= 0,x= 0; x < number_of; x++)
+ {
+ size_t value_length;
+ uint32_t flags;
+
+ unsigned int fetch_key= (unsigned int)((unsigned int)random() % number_of);
+
+ memcached_return_t rc;
+ char *value= memcached_get(memc, pairs[fetch_key].key, pairs[fetch_key].key_length,
+ &value_length, &flags, &rc);
+
+ if (memcached_failed(rc))
+ {
+ fprintf(stderr, "%s:%d Failure on read(%s) of %.*s\n",
+ __FILE__, __LINE__,
+ memcached_last_error_message(memc),
+ (unsigned int)pairs[fetch_key].key_length, pairs[fetch_key].key);
+ }
+ else
+ {
+ retrieved++;
+ }
+
+ ::free(value);
+ }
+
+ return retrieved;
+}
+
+/**
+ * Callback function to count the number of results
+ */
+static memcached_return_t callback_counter(const memcached_st *ptr,
+ memcached_result_st *result,
+ void *context)
+{
+ (void)ptr;
+ (void)result;
+ unsigned int *counter= (unsigned int *)context;
+ *counter= *counter + 1;
+
+ return MEMCACHED_SUCCESS;
+}
+
+/**
+ * Try to run a large mget to get all of the keys
+ * @param memc memcached handle
+ * @param keys the keys to get
+ * @param key_length the length of the keys
+ * @param number_of the number of keys to try to get
+ * @return the number of keys received
+ */
+unsigned int execute_mget(memcached_st *memc,
+ const char * const *keys,
+ size_t *key_length,
+ unsigned int number_of)
+{
+ unsigned int retrieved= 0;
+ memcached_execute_fn callbacks[]= { callback_counter };
+ memcached_return_t rc;
+ rc= memcached_mget_execute(memc, keys, key_length,
+ (size_t)number_of, callbacks, &retrieved, 1);
+
+ if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_NOTFOUND ||
+ rc == MEMCACHED_BUFFERED || rc == MEMCACHED_END)
+ {
+ rc= memcached_fetch_execute(memc, callbacks, (void *)&retrieved, 1);
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_END)
+ {
+ fprintf(stderr, "%s:%d Failed to execute mget: %s\n",
+ __FILE__, __LINE__,
+ memcached_strerror(memc, rc));
+ memcached_quit(memc);
+ return 0;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s:%d Failed to execute mget: %s\n",
+ __FILE__, __LINE__,
+ memcached_strerror(memc, rc));
+ memcached_quit(memc);
+ return 0;
+ }
+
+ return retrieved;
+}
--- /dev/null
+/* 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:
+ *
+ */
+
+#pragma once
+
+#include <stdio.h>
+
+#include <libmemcached-1.0/memcached.h>
+#include "generator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of);
+unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of);
+unsigned int execute_mget(memcached_st *memc, const char * const *keys, size_t *key_length,
+ unsigned int number_of);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 <mem_config.h>
+
+#include <stdint.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <unistd.h>
+
+#include "generator.h"
+
+#define KEY_BYTES 20
+
+/* Use this for string generation */
+static const char ALPHANUMERICS[]=
+ "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
+
+#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
+
+static size_t get_alpha_num(void)
+{
+ return (size_t)random() % ALPHANUMERICS_SIZE;
+}
+
+void get_random_string(char *buffer, size_t size)
+{
+ char *buffer_ptr= buffer;
+
+ while (--size)
+ {
+ *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
+ }
+ *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
+}
+
+void pairs_free(pairs_st *pairs)
+{
+ if (pairs == NULL)
+ {
+ return;
+ }
+
+ /* We free until we hit the null pair we stores during creation */
+ for (uint32_t x= 0; pairs[x].key; x++)
+ {
+ free(pairs[x].key);
+ if (pairs[x].value)
+ {
+ free(pairs[x].value);
+ }
+ }
+
+ free(pairs);
+}
+
+pairs_st *pairs_generate(uint64_t number_of, size_t value_length)
+{
+ pairs_st *pairs= (pairs_st*)calloc((size_t)number_of + 1, sizeof(pairs_st));
+
+ if (pairs == NULL)
+ {
+ goto error;
+ }
+
+ for (uint64_t x= 0; x < number_of; x++)
+ {
+ pairs[x].key= (char *)calloc(KEY_BYTES, sizeof(char));
+
+ if (pairs[x].key == NULL)
+ goto error;
+
+ get_random_string(pairs[x].key, KEY_BYTES);
+ pairs[x].key_length= KEY_BYTES;
+
+ if (value_length)
+ {
+ pairs[x].value= (char *)calloc(value_length, sizeof(char));
+
+ if (pairs[x].value == NULL)
+ goto error;
+
+ get_random_string(pairs[x].value, value_length);
+ pairs[x].value_length= value_length;
+ }
+ else
+ {
+ pairs[x].value= NULL;
+ pairs[x].value_length= 0;
+ }
+ }
+
+ return pairs;
+error:
+ std::cerr << "Memory Allocation failure in pairs_generate." << std::endl;
+ exit(EXIT_SUCCESS);
+}
--- /dev/null
+/* 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
+*/
+
+#pragma once
+
+typedef struct pairs_st pairs_st;
+
+struct pairs_st {
+ char *key;
+ size_t key_length;
+ char *value;
+ size_t value_length;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+pairs_st *pairs_generate(uint64_t number_of, size_t value_length);
+void pairs_free(pairs_st *pairs);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/*
+ * 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 "mem_config.h"
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <limits.h>
+
+#if defined(HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#endif
+
+#if defined(HAVE_TIME_H)
+# include <time.h>
+#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
+
+/* 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 */
+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 in_time);
+static void ms_print_memslap_stats(struct timeval *start_time,
+ struct timeval *end_time);
+static void ms_monitor_slap_mode(void);
+
+/**
+ * output the help information
+ *
+ * @param command_name, the string of this process
+ * @param description, description of this process
+ * @param long_options, global options array
+ */
+static __attribute__((noreturn)) 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++)
+ {
+ 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)
+ {
+ printf(" %s\n", help_message);
+ }
+ }
+
+ 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");
+
+ exit(0);
+} /* ms_help_command */
+
+
+/* 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);
+
+ ms_global.warmup_lock.count = 0;
+ pthread_mutex_init(&ms_global.warmup_lock.lock, NULL);
+ pthread_cond_init(&ms_global.warmup_lock.cond, NULL);
+
+ 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()
+{
+ pthread_mutex_destroy(&ms_global.init_lock.lock);
+ pthread_cond_destroy(&ms_global.init_lock.cond);
+
+ pthread_mutex_destroy(&ms_global.warmup_lock.lock);
+ pthread_cond_destroy(&ms_global.warmup_lock.cond);
+
+ pthread_mutex_destroy(&ms_global.run_lock.lock);
+ pthread_cond_destroy(&ms_global.run_lock.cond);
+
+ pthread_mutex_destroy(&ms_global.quit_mutex);
+ pthread_mutex_destroy(&ms_global.seq_mutex);
+
+ if (ms_setting.stat_freq > 0)
+ {
+ pthread_mutex_destroy(&ms_statistic.stat_mutex);
+ }
+} /* ms_sync_lock_destroy */
+
+
+/* initialize the global structure */
+static void ms_global_struct_init()
+{
+ ms_sync_lock_init();
+ ms_global.finish_warmup= false;
+ ms_global.time_out= false;
+}
+
+
+/* destroy the global structure */
+static void ms_global_struct_destroy()
+{
+ ms_sync_lock_destroy();
+}
+
+
+/**
+ * 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);
+}
+
+
+/**
+ * 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)
+{
+ 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";
+
+ case OPT_VERSION:
+ return "Display the version of the application and then exit.";
+
+ case OPT_HELP:
+ return "Display this message and then exit.";
+
+ case OPT_EXECUTE_NUMBER:
+ return "Number of operations(get and set) to execute for the\n"
+ " given test. Default 1000000.";
+
+ 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.";
+
+ case OPT_RECONNECT:
+ return
+ "Reconnect support, when connection is closed it will be reconnected.";
+
+ case OPT_VERBOSE:
+ return
+ "Whether it outputs detailed information when verification fails.";
+
+ case OPT_FACEBOOK_TEST:
+ return
+ "Whether it enables facebook test feature, set with TCP and multi-get with UDP.";
+
+ 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 */
+
+
+/* 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)
+ {
+ case 'd':
+ case 'D':
+ ret*= 24;
+ /* fall through */
+ case 'h':
+ case 'H':
+ ret*= 60;
+ /* fall through */
+ case 'm':
+ case 'M':
+ ret*= 60;
+ /* fall through */
+ case 's':
+ case 'S':
+ break;
+
+ default:
+ ret= -1;
+ break;
+ } /* switch */
+
+ return ret;
+} /* ms_parse_time */
+
+
+/* used to parse the size string */
+static int64_t ms_parse_size()
+{
+ int64_t ret= -1;
+ char unit= optarg[strlen(optarg) - 1];
+
+ optarg[strlen(optarg) - 1]= '\0';
+ errno= 0;
+ ret= strtoll(optarg, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ fprintf(stderr, "strtoll(optarg,..): %s\n", strerror(errno));
+ exit(1);
+ }
+
+ switch (unit)
+ {
+ case 'k':
+ case 'K':
+ ret*= 1024;
+ break;
+
+ 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 ((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)
+ {
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ 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 */
+ errno= 0;
+ ms_setting.nconns= (uint32_t)strtoul(optarg, (char **) NULL, 10);
+ if (ms_setting.nconns <= 0 || errno != 0)
+ {
+ fprintf(stderr, "Concurrency must be greater than 0.:-)\n");
+ exit(1);
+ }
+ break;
+
+ case OPT_EXECUTE_NUMBER: /* --execute_number or -x */
+ errno= 0;
+ ms_setting.exec_num= (int)strtol(optarg, (char **) NULL, 10);
+ if (ms_setting.exec_num <= 0 || errno != 0)
+ {
+ fprintf(stderr, "Execute number must be greater than 0.:-)\n");
+ exit(1);
+ }
+ break;
+
+ case OPT_THREAD_NUMBER: /* --threads or -T */
+ errno= 0;
+ ms_setting.nthreads= (uint32_t)strtoul(optarg, (char **) NULL, 10);
+ if (ms_setting.nthreads <= 0 || errno != 0)
+ {
+ fprintf(stderr, "Threads number must be greater than 0.:-)\n");
+ exit(1);
+ }
+ break;
+
+ case OPT_FIXED_LTH: /* --fixed_size or -X */
+ errno= 0;
+ ms_setting.fixed_value_size= (size_t)strtoull(optarg, (char **) NULL, 10);
+ if ((ms_setting.fixed_value_size <= 0 || errno != 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_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_GETS_DIVISION: /* --division or -d */
+ errno= 0;
+ ms_setting.mult_key_num= (int)strtol(optarg, (char **) NULL, 10);
+ if (ms_setting.mult_key_num <= 0 || errno != 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_CONFIG_CMD: /* --cfg_cmd or -F */
+ ms_setting.cfg_file= strdup(optarg);
+ break;
+
+ 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)
+ {
+ 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);
+ }
+
+ if (ms_setting.stat_freq == 0)
+ {
+ fprintf(stderr, "The frequency of dumping statistic information "
+ "can not be 0. :-)\n");
+ exit(1);
+ }
+ break;
+
+ case OPT_SOCK_PER_CONN: /* --conn_sock or -n */
+ errno= 0;
+ ms_setting.sock_per_conn= (uint32_t)strtoul(optarg, (char **) NULL, 10);
+ if (ms_setting.sock_per_conn <= 0 || errno != 0)
+ {
+ fprintf(stderr, "Number of socks of each concurrency "
+ "must be greater than 0.:-)\n");
+ exit(1);
+ }
+ break;
+
+ case OPT_RECONNECT: /* --reconnect or -R */
+ ms_setting.reconnect= true;
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -b */
+ ms_setting.verbose= true;
+ break;
+
+ 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 */
+ errno= 0;
+ ms_setting.rep_write_srv= (uint32_t)strtoul(optarg, (char **) NULL, 10);
+ if (ms_setting.rep_write_srv <= 0 || errno != 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 (ms_setting.nconns % (uint32_t)ms_setting.nthreads != 0)
+ {
+ fprintf(stderr, "Concurrency must be the multiples of threads count.\n");
+ return -1;
+ }
+
+ if (ms_setting.win_size % UNIT_ITEMS_COUNT != 0)
+ {
+ fprintf(stderr, "Window size must be the multiples of 1024.\n\n");
+ return -1;
+ }
+
+ return EXIT_SUCCESS;
+} /* ms_check_para */
+
+
+/* initialize the statistic structure */
+static void ms_statistic_init()
+{
+ 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 */
+
+
+/* initialize the global state structure */
+static void ms_stats_init()
+{
+ memset(&ms_stats, 0, sizeof(ms_stats_t));
+ if (ms_setting.stat_freq > 0)
+ {
+ ms_statistic_init();
+ }
+} /* ms_stats_init */
+
+
+/* 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+= snprintf(pos,
+ sizeof(buf), "cmd_get: %lu\n",
+ (unsigned long) ms_stats.cmd_get);
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "cmd_set: %lu\n",
+ (unsigned long) ms_stats.cmd_set);
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "get_misses: %lu\n",
+ (unsigned long) ms_stats.get_misses);
+
+ if (ms_setting.verify_percent > 0)
+ {
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "verify_misses: %lu\n",
+ (unsigned long) ms_stats.vef_miss);
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "verify_failed: %lu\n",
+ (unsigned long) ms_stats.vef_failed);
+ }
+
+ if (ms_setting.exp_ver_per > 0)
+ {
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "expired_get: %lu\n",
+ (unsigned long) ms_stats.exp_get);
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "unexpired_unget: %lu\n",
+ (unsigned long) ms_stats.unexp_unget);
+ }
+
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "written_bytes: %lu\n",
+ (unsigned long) ms_stats.bytes_written);
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "read_bytes: %lu\n",
+ (unsigned long) ms_stats.bytes_read);
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "object_bytes: %lu\n",
+ (unsigned long) ms_stats.obj_bytes);
+
+ if (ms_setting.udp || ms_setting.facebook_test)
+ {
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "packet_disorder: %lu\n",
+ (unsigned long) ms_stats.pkt_disorder);
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "packet_drop: %lu\n",
+ (unsigned long)ms_stats.pkt_drop);
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "udp_timeout: %lu\n",
+ (unsigned long)ms_stats.udp_timeout);
+ }
+
+ 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);
+ }
+
+ int64_t time_diff= ms_time_diff(start_time, end_time);
+ pos+= snprintf(pos,
+ sizeof(buf) - (size_t)(pos -buf),
+ "\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));
+ assert(pos <= buf);
+
+ 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()
+{
+ struct timeval start_time, end_time;
+
+ /* Wait all the threads complete initialization. */
+ pthread_mutex_lock(&ms_global.init_lock.lock);
+ while (ms_global.init_lock.count < ms_setting.nthreads)
+ {
+ pthread_cond_wait(&ms_global.init_lock.cond,
+ &ms_global.init_lock.lock);
+ }
+ pthread_mutex_unlock(&ms_global.init_lock.lock);
+
+ /* 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.warmup_lock.lock);
+ while (ms_global.warmup_lock.count < ms_setting.nconns)
+ {
+ pthread_cond_wait(&ms_global.warmup_lock.cond, &ms_global.warmup_lock.lock);
+ }
+ pthread_mutex_unlock(&ms_global.warmup_lock.lock);
+ }
+ ms_global.finish_warmup= true;
+
+ /* running in "run time" mode, user specify run time */
+ if (ms_setting.run_time > 0)
+ {
+ int second= 0;
+ gettimeofday(&start_time, NULL);
+ while (1)
+ {
+ sleep(1);
+ second++;
+
+ 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 < 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[])
+{
+ srandom((unsigned int)time(NULL));
+ ms_global_struct_init();
+
+ /* 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();
+
+ /* waiting work thread complete its task */
+ ms_monitor_slap_mode();
+
+ /* clean up */
+ ms_thread_cleanup();
+ ms_global_struct_destroy();
+ ms_setting_cleanup();
+
+ return EXIT_SUCCESS;
+} /* main */
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 <mem_config.h>
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#else
+#include "poll/poll.h"
+#endif
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctype.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libmemcached-1.0/memcached.h>
+
+#include "libmemcached/socket.hpp"
+#include "libmemcachedprotocol-0.0/binary.h"
+#include "libmemcached/byteorder.h"
+#include "utilities.h"
+
+#include <vector>
+
+#ifdef linux
+/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
+ * optimize the conversion functions, but the prototypes generate warnings
+ * from gcc. The conversion methods isn't the bottleneck for my app, so
+ * just remove the warnings by undef'ing the optimization ..
+ */
+#undef ntohs
+#undef ntohl
+#endif
+
+/* Should we generate coredumps when we enounter an error (-c) */
+static bool do_core= false;
+/* connection to the server */
+static memcached_socket_t sock;
+/* Should the output from test failures be verbose or quiet? */
+static bool verbose= false;
+
+/* The number of seconds to wait for an IO-operation */
+static int timeout= 2;
+
+/*
+ * Instead of having to cast between the different datatypes we create
+ * a union of all of the different types of pacages we want to send.
+ * A lot of the different commands use the same packet layout, so I'll
+ * just define the different types I need. The typedefs only contain
+ * the header of the message, so we need some space for keys and body
+ * To avoid to have to do multiple writes, lets add a chunk of memory
+ * to use. 1k should be more than enough for header, key and body.
+ */
+typedef union
+{
+ protocol_binary_request_no_extras plain;
+ protocol_binary_request_flush flush;
+ protocol_binary_request_incr incr;
+ protocol_binary_request_set set;
+ char bytes[1024];
+} command;
+
+typedef union
+{
+ protocol_binary_response_no_extras plain;
+ protocol_binary_response_incr incr;
+ protocol_binary_response_decr decr;
+ char bytes[1024];
+} response;
+
+enum test_return
+{
+ TEST_SKIP, TEST_PASS, TEST_PASS_RECONNECT, TEST_FAIL
+};
+
+/**
+ * Try to get an addrinfo struct for a given port on a given host
+ */
+static struct addrinfo *lookuphost(const char *hostname, const char *port)
+{
+ struct addrinfo *ai= 0;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family=AF_UNSPEC;
+ hints.ai_protocol=IPPROTO_TCP;
+ hints.ai_socktype=SOCK_STREAM;
+
+ int error= getaddrinfo(hostname, port, &hints, &ai);
+ if (error != 0)
+ {
+ if (error != EAI_SYSTEM)
+ {
+ fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
+ }
+ else
+ {
+ perror("getaddrinfo()");
+ }
+ }
+
+ return ai;
+}
+
+/**
+ * Set the socket in nonblocking mode
+ * @return -1 if failure, the socket otherwise
+ */
+static memcached_socket_t set_noblock(void)
+{
+#if defined(_WIN32)
+ u_long arg = 1;
+ if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
+ {
+ perror("Failed to set nonblocking io");
+ closesocket(sock);
+ return INVALID_SOCKET;
+ }
+#else
+ int flags= fcntl(sock, F_GETFL, 0);
+ if (flags == -1)
+ {
+ perror("Failed to get socket flags");
+ memcached_close_socket(sock);
+ return INVALID_SOCKET;
+ }
+
+ if ((flags & O_NONBLOCK) != O_NONBLOCK)
+ {
+ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
+ {
+ perror("Failed to set socket to nonblocking mode");
+ memcached_close_socket(sock);
+ return INVALID_SOCKET;
+ }
+ }
+#endif
+ return sock;
+}
+
+/**
+ * Try to open a connection to the server
+ * @param hostname the name of the server to connect to
+ * @param port the port number (or service) to connect to
+ * @return positive integer if success, -1 otherwise
+ */
+static memcached_socket_t connect_server(const char *hostname, const char *port)
+{
+ struct addrinfo *ai= lookuphost(hostname, port);
+ sock= INVALID_SOCKET;
+ if (ai != NULL)
+ {
+ if ((sock= socket(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol)) != INVALID_SOCKET)
+ {
+ if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR)
+ {
+ fprintf(stderr, "Failed to connect socket: %s\n",
+ strerror(get_socket_errno()));
+ closesocket(sock);
+ sock= INVALID_SOCKET;
+ }
+ else
+ {
+ sock= set_noblock();
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Failed to create socket: %s\n", strerror(get_socket_errno()));
+ }
+
+ freeaddrinfo(ai);
+ }
+
+ return sock;
+}
+
+static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len)
+{
+ ssize_t ret;
+
+ if (direction == POLLOUT)
+ {
+ ret= send(fd, buf, len, 0);
+ }
+ else
+ {
+ ret= recv(fd, buf, len, 0);
+ }
+
+ if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK)
+ {
+ struct pollfd fds;
+ memset(&fds, 0, sizeof(struct pollfd));
+ fds.events= direction;
+ fds.fd= fd;
+
+ int err= poll(&fds, 1, timeout * 1000);
+ if (err == 1)
+ {
+ if (direction == POLLOUT)
+ {
+ ret= send(fd, buf, len, 0);
+ }
+ else
+ {
+ ret= recv(fd, buf, len, 0);
+ }
+ }
+ else if (err == 0)
+ {
+ errno= ETIMEDOUT;
+ }
+ else
+ {
+ perror("Failed to poll");
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Ensure that an expression is true. If it isn't print out a message similar
+ * to assert() and create a coredump if the user wants that. If not an error
+ * message is returned.
+ *
+ */
+static enum test_return ensure(bool val, const char *expression, const char *file, int line)
+{
+ if (!val)
+ {
+ if (verbose)
+ {
+ fprintf(stdout, "\n%s:%d: %s", file, line, expression);
+ }
+
+ if (do_core)
+ {
+ abort();
+ }
+
+ return TEST_FAIL;
+ }
+
+ return TEST_PASS;
+}
+
+#define verify(expression) do { if (ensure(expression, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
+#define execute(expression) do { if (ensure(expression == TEST_PASS, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
+
+/**
+ * Send a chunk of memory over the socket (retry if the call is iterrupted
+ */
+static enum test_return retry_write(const void* buf, size_t len)
+{
+ size_t offset= 0;
+ const char* ptr= static_cast<const char *>(buf);
+
+ do
+ {
+ size_t num_bytes= len - offset;
+ ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes);
+ if (nw == -1)
+ {
+ verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
+ }
+ else
+ {
+ offset+= (size_t)nw;
+ }
+
+ } while (offset < len);
+
+ return TEST_PASS;
+}
+
+/**
+ * Resend a packet to the server (All fields in the command header should
+ * be in network byte order)
+ */
+static enum test_return resend_packet(command *cmd)
+{
+ size_t length= sizeof (protocol_binary_request_no_extras) +
+ ntohl(cmd->plain.message.header.request.bodylen);
+
+ execute(retry_write(cmd, length));
+ return TEST_PASS;
+}
+
+/**
+ * Send a command to the server. The command header needs to be updated
+ * to network byte order
+ */
+static enum test_return send_packet(command *cmd)
+{
+ /* Fix the byteorder of the header */
+ cmd->plain.message.header.request.keylen=
+ ntohs(cmd->plain.message.header.request.keylen);
+ cmd->plain.message.header.request.bodylen=
+ ntohl(cmd->plain.message.header.request.bodylen);
+ cmd->plain.message.header.request.cas=
+ memcached_ntohll(cmd->plain.message.header.request.cas);
+
+ execute(resend_packet(cmd));
+ return TEST_PASS;
+}
+
+/**
+ * Read a fixed length chunk of data from the server
+ */
+static enum test_return retry_read(void *buf, size_t len)
+{
+ size_t offset= 0;
+ do
+ {
+ ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset);
+ switch (nr) {
+ case -1 :
+ fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno));
+ verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
+ break;
+
+ case 0:
+ return TEST_FAIL;
+
+ default:
+ offset+= (size_t)nr;
+ }
+ } while (offset < len);
+
+ return TEST_PASS;
+}
+
+/**
+ * Receive a response from the server and conver the fields in the header
+ * to local byte order
+ */
+static enum test_return recv_packet(response *rsp)
+{
+ execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras)));
+
+ /* Fix the byte order in the packet header */
+ rsp->plain.message.header.response.keylen=
+ ntohs(rsp->plain.message.header.response.keylen);
+ rsp->plain.message.header.response.status=
+ ntohs(rsp->plain.message.header.response.status);
+ rsp->plain.message.header.response.bodylen=
+ ntohl(rsp->plain.message.header.response.bodylen);
+ rsp->plain.message.header.response.cas=
+ memcached_ntohll(rsp->plain.message.header.response.cas);
+
+ size_t bodysz= rsp->plain.message.header.response.bodylen;
+ if (bodysz > 0)
+ execute(retry_read(rsp->bytes + sizeof (protocol_binary_response_no_extras), bodysz));
+
+ return TEST_PASS;
+}
+
+/**
+ * Create a storage command (add, set, replace etc)
+ *
+ * @param cmd destination buffer
+ * @param cc the storage command to create
+ * @param key the key to store
+ * @param keylen the length of the key
+ * @param dta the data to store with the key
+ * @param dtalen the length of the data to store with the key
+ * @param flags the flags to store along with the key
+ * @param exptime the expiry time for the key
+ */
+static void storage_command(command *cmd,
+ uint8_t cc,
+ const void* key,
+ size_t keylen,
+ const void* dta,
+ size_t dtalen,
+ uint32_t flags,
+ uint32_t exptime)
+{
+ /* all of the storage commands use the same command layout */
+ protocol_binary_request_set *request= &cmd->set;
+
+ memset(request, 0, sizeof (*request));
+ request->message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request->message.header.request.opcode= cc;
+ request->message.header.request.keylen= (uint16_t)keylen;
+ request->message.header.request.extlen= 8;
+ request->message.header.request.bodylen= (uint32_t)(keylen + 8 + dtalen);
+ request->message.header.request.opaque= 0xdeadbeef;
+ request->message.body.flags= flags;
+ request->message.body.expiration= exptime;
+
+ off_t key_offset= sizeof (protocol_binary_request_no_extras) + 8;
+ memcpy(cmd->bytes + key_offset, key, keylen);
+ if (dta != NULL)
+ memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
+}
+
+/**
+ * Create a basic command to send to the server
+ * @param cmd destination buffer
+ * @param cc the command to create
+ * @param key the key to store
+ * @param keylen the length of the key
+ * @param dta the data to store with the key
+ * @param dtalen the length of the data to store with the key
+ */
+static void raw_command(command *cmd,
+ uint8_t cc,
+ const void* key,
+ size_t keylen,
+ const void* dta,
+ size_t dtalen)
+{
+ /* all of the storage commands use the same command layout */
+ memset(cmd, 0, sizeof (*cmd));
+ cmd->plain.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ cmd->plain.message.header.request.opcode= cc;
+ cmd->plain.message.header.request.keylen= (uint16_t)keylen;
+ cmd->plain.message.header.request.bodylen= (uint32_t)(keylen + dtalen);
+ cmd->plain.message.header.request.opaque= 0xdeadbeef;
+
+ off_t key_offset= sizeof (protocol_binary_request_no_extras);
+
+ if (key != NULL)
+ memcpy(cmd->bytes + key_offset, key, keylen);
+
+ if (dta != NULL)
+ memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
+}
+
+/**
+ * Create the flush command
+ * @param cmd destination buffer
+ * @param cc the command to create (FLUSH/FLUSHQ)
+ * @param exptime when to flush
+ * @param use_extra to force using of the extra field?
+ */
+static void flush_command(command *cmd,
+ uint8_t cc, uint32_t exptime, bool use_extra)
+{
+ memset(cmd, 0, sizeof (cmd->flush));
+ cmd->flush.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ cmd->flush.message.header.request.opcode= cc;
+ cmd->flush.message.header.request.opaque= 0xdeadbeef;
+
+ if (exptime != 0 || use_extra)
+ {
+ cmd->flush.message.header.request.extlen= 4;
+ cmd->flush.message.body.expiration= htonl(exptime);
+ cmd->flush.message.header.request.bodylen= 4;
+ }
+}
+
+/**
+ * Create a incr/decr command
+ * @param cc the cmd to create (FLUSH/FLUSHQ)
+ * @param key the key to operate on
+ * @param keylen the number of bytes in the key
+ * @param delta the number to add/subtract
+ * @param initial the initial value if the key doesn't exist
+ * @param exptime when the key should expire if it isn't set
+ */
+static void arithmetic_command(command *cmd,
+ uint8_t cc,
+ const void* key,
+ size_t keylen,
+ uint64_t delta,
+ uint64_t initial,
+ uint32_t exptime)
+{
+ memset(cmd, 0, sizeof (cmd->incr));
+ cmd->incr.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ cmd->incr.message.header.request.opcode= cc;
+ cmd->incr.message.header.request.keylen= (uint16_t)keylen;
+ cmd->incr.message.header.request.extlen= 20;
+ cmd->incr.message.header.request.bodylen= (uint32_t)(keylen + 20);
+ cmd->incr.message.header.request.opaque= 0xdeadbeef;
+ cmd->incr.message.body.delta= memcached_htonll(delta);
+ cmd->incr.message.body.initial= memcached_htonll(initial);
+ cmd->incr.message.body.expiration= htonl(exptime);
+
+ off_t key_offset= sizeof (protocol_binary_request_no_extras) + 20;
+ memcpy(cmd->bytes + key_offset, key, keylen);
+}
+
+/**
+ * Validate the response header from the server
+ * @param rsp the response to check
+ * @param cc the expected command
+ * @param status the expected status
+ */
+static enum test_return do_validate_response_header(response *rsp,
+ uint8_t cc, uint16_t status)
+{
+ verify(rsp->plain.message.header.response.magic == PROTOCOL_BINARY_RES);
+ verify(rsp->plain.message.header.response.opcode == cc);
+ verify(rsp->plain.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
+ verify(rsp->plain.message.header.response.status == status);
+ verify(rsp->plain.message.header.response.opaque == 0xdeadbeef);
+
+ if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS)
+ {
+ switch (cc) {
+ case PROTOCOL_BINARY_CMD_ADDQ:
+ case PROTOCOL_BINARY_CMD_APPENDQ:
+ case PROTOCOL_BINARY_CMD_DECREMENTQ:
+ case PROTOCOL_BINARY_CMD_DELETEQ:
+ case PROTOCOL_BINARY_CMD_FLUSHQ:
+ case PROTOCOL_BINARY_CMD_INCREMENTQ:
+ case PROTOCOL_BINARY_CMD_PREPENDQ:
+ case PROTOCOL_BINARY_CMD_QUITQ:
+ case PROTOCOL_BINARY_CMD_REPLACEQ:
+ case PROTOCOL_BINARY_CMD_SETQ:
+ verify("Quiet command shouldn't return on success" == NULL);
+ /* fall through */
+ default:
+ break;
+ }
+
+ switch (cc) {
+ case PROTOCOL_BINARY_CMD_ADD:
+ case PROTOCOL_BINARY_CMD_REPLACE:
+ case PROTOCOL_BINARY_CMD_SET:
+ case PROTOCOL_BINARY_CMD_APPEND:
+ case PROTOCOL_BINARY_CMD_PREPEND:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ verify(rsp->plain.message.header.response.bodylen == 0);
+ verify(rsp->plain.message.header.response.cas != 0);
+ break;
+ case PROTOCOL_BINARY_CMD_FLUSH:
+ case PROTOCOL_BINARY_CMD_NOOP:
+ case PROTOCOL_BINARY_CMD_QUIT:
+ case PROTOCOL_BINARY_CMD_DELETE:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ verify(rsp->plain.message.header.response.bodylen == 0);
+ verify(rsp->plain.message.header.response.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_DECREMENT:
+ case PROTOCOL_BINARY_CMD_INCREMENT:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ verify(rsp->plain.message.header.response.bodylen == 8);
+ verify(rsp->plain.message.header.response.cas != 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_STAT:
+ verify(rsp->plain.message.header.response.extlen == 0);
+ /* key and value exists in all packets except in the terminating */
+ verify(rsp->plain.message.header.response.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_VERSION:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ verify(rsp->plain.message.header.response.bodylen != 0);
+ verify(rsp->plain.message.header.response.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_GET:
+ case PROTOCOL_BINARY_CMD_GETQ:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 4);
+ verify(rsp->plain.message.header.response.cas != 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_GETK:
+ case PROTOCOL_BINARY_CMD_GETKQ:
+ verify(rsp->plain.message.header.response.keylen != 0);
+ verify(rsp->plain.message.header.response.extlen == 4);
+ verify(rsp->plain.message.header.response.cas != 0);
+ break;
+
+ default:
+ /* Undefined command code */
+ break;
+ }
+ }
+ else
+ {
+ verify(rsp->plain.message.header.response.cas == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ if (cc != PROTOCOL_BINARY_CMD_GETK)
+ {
+ verify(rsp->plain.message.header.response.keylen == 0);
+ }
+ }
+
+ return TEST_PASS;
+}
+
+/* We call verify(validate_response_header), but that macro
+ * expects a boolean expression, and the function returns
+ * an enum.... Let's just create a macro to avoid cluttering
+ * the code with all of the == TEST_PASS ;-)
+ */
+#define validate_response_header(a,b,c) \
+ do_validate_response_header(a,b,c) == TEST_PASS
+
+
+static enum test_return send_binary_noop(void)
+{
+ command cmd;
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_NOOP, NULL, 0, NULL, 0);
+ execute(send_packet(&cmd));
+ return TEST_PASS;
+}
+
+static enum test_return receive_binary_noop(void)
+{
+ response rsp;
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_NOOP,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_noop(void)
+{
+ execute(send_binary_noop());
+ execute(receive_binary_noop());
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_quit_impl(uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ raw_command(&cmd, cc, NULL, 0, NULL, 0);
+
+ execute(send_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_QUIT)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_QUIT,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+
+ /* Socket should be closed now, read should return EXIT_SUCCESS */
+ verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0);
+
+ return TEST_PASS_RECONNECT;
+}
+
+static enum test_return test_binary_quit(void)
+{
+ return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
+}
+
+static enum test_return test_binary_quitq(void)
+{
+ return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
+}
+
+static enum test_return test_binary_set_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+
+ uint64_t value= 0xdeadbeefdeadcafeULL;
+ storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
+
+ /* set should always work */
+ for (int ii= 0; ii < 10; ii++)
+ {
+ if (ii == 0)
+ {
+ execute(send_packet(&cmd));
+ }
+ else
+ {
+ execute(resend_packet(&cmd));
+ }
+
+ if (cc == PROTOCOL_BINARY_CMD_SET)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ execute(test_binary_noop());
+ }
+
+ /*
+ * We need to get the current CAS id, and at this time we haven't
+ * verified that we have a working get
+ */
+ if (cc == PROTOCOL_BINARY_CMD_SETQ)
+ {
+ cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET;
+ execute(resend_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
+ }
+
+ /* try to set with the correct CAS value */
+ cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas);
+ execute(resend_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_SET)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ execute(test_binary_noop());
+
+ /* try to set with an incorrect CAS value */
+ cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas - 1);
+ execute(resend_packet(&cmd));
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
+ execute(receive_binary_noop());
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_set(void)
+{
+ return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
+}
+
+static enum test_return test_binary_setq(void)
+{
+ return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
+}
+
+static enum test_return test_binary_add_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ uint64_t value= 0xdeadbeefdeadcafeULL;
+ storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
+
+ /* first add should work, rest of them should fail (even with cas
+ as wildcard */
+ for (int ii=0; ii < 10; ii++)
+ {
+ if (ii == 0)
+ execute(send_packet(&cmd));
+ else
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_ADD || ii > 0)
+ {
+ uint16_t expected_result;
+ if (ii == 0)
+ expected_result= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ else
+ expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ execute(receive_binary_noop());
+ verify(validate_response_header(&rsp, cc, expected_result));
+ }
+ else
+ execute(test_binary_noop());
+ }
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_add(void)
+{
+ return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
+}
+
+static enum test_return test_binary_addq(void)
+{
+ return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
+}
+
+static enum test_return binary_set_item(const char *key, const char *value)
+{
+ command cmd;
+ response rsp;
+ storage_command(&cmd, PROTOCOL_BINARY_CMD_SET, key, strlen(key),
+ value, strlen(value), 0, 0);
+ execute(send_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_replace_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ uint64_t value= 0xdeadbeefdeadcafeULL;
+ storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
+
+ /* first replace should fail, successive should succeed (when the
+ item is added! */
+ for (int ii= 0; ii < 10; ii++)
+ {
+ if (ii == 0)
+ {
+ execute(send_packet(&cmd));
+ }
+ else
+ {
+ execute(resend_packet(&cmd));
+ }
+
+ if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0)
+ {
+ uint16_t expected_result;
+ if (ii == 0)
+ {
+ expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
+ }
+ else
+ {
+ expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ }
+
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ execute(receive_binary_noop());
+ verify(validate_response_header(&rsp, cc, expected_result));
+
+ if (ii == 0)
+ execute(binary_set_item(key, key));
+ }
+ else
+ {
+ execute(test_binary_noop());
+ }
+ }
+
+ /* verify that replace with CAS value works! */
+ cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas);
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_REPLACE)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ execute(test_binary_noop());
+
+ /* try to set with an incorrect CAS value */
+ cmd.plain.message.header.request.cas= memcached_htonll(rsp.plain.message.header.response.cas - 1);
+ execute(resend_packet(&cmd));
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ execute(receive_binary_noop());
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_replace(void)
+{
+ return test_binary_replace_impl("test_binary_replace", PROTOCOL_BINARY_CMD_REPLACE);
+}
+
+static enum test_return test_binary_replaceq(void)
+{
+ return test_binary_replace_impl("test_binary_replaceq", PROTOCOL_BINARY_CMD_REPLACEQ);
+}
+
+static enum test_return test_binary_delete_impl(const char *key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ raw_command(&cmd, cc, key, strlen(key), NULL, 0);
+
+ /* The delete shouldn't work the first time, because the item isn't there */
+ execute(send_packet(&cmd));
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
+ execute(receive_binary_noop());
+ execute(binary_set_item(key, key));
+
+ /* The item should be present now, resend*/
+ execute(resend_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_DELETE)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+
+ execute(test_binary_noop());
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_delete(void)
+{
+ return test_binary_delete_impl("test_binary_delete", PROTOCOL_BINARY_CMD_DELETE);
+}
+
+static enum test_return test_binary_deleteq(void)
+{
+ return test_binary_delete_impl("test_binary_deleteq", PROTOCOL_BINARY_CMD_DELETEQ);
+}
+
+static enum test_return test_binary_get_impl(const char *key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+
+ raw_command(&cmd, cc, key, strlen(key), NULL, 0);
+ execute(send_packet(&cmd));
+ execute(send_binary_noop());
+
+ if (cc == PROTOCOL_BINARY_CMD_GET || cc == PROTOCOL_BINARY_CMD_GETK)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
+ }
+
+ execute(receive_binary_noop());
+
+ execute(binary_set_item(key, key));
+ execute(resend_packet(&cmd));
+ execute(send_binary_noop());
+
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ execute(receive_binary_noop());
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_get(void)
+{
+ return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
+}
+
+static enum test_return test_binary_getk(void)
+{
+ return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
+}
+
+static enum test_return test_binary_getq(void)
+{
+ return test_binary_get_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
+}
+
+static enum test_return test_binary_getkq(void)
+{
+ return test_binary_get_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
+}
+
+static enum test_return test_binary_incr_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ arithmetic_command(&cmd, cc, key, strlen(key), 1, 0, 0);
+
+ uint64_t ii;
+ for (ii= 0; ii < 10; ++ii)
+ {
+ if (ii == 0)
+ execute(send_packet(&cmd));
+ else
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_INCREMENT)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ verify(memcached_ntohll(rsp.incr.message.body.value) == ii);
+ }
+ else
+ execute(test_binary_noop());
+ }
+
+ /* @todo add incorrect CAS */
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_incr(void)
+{
+ return test_binary_incr_impl("test_binary_incr", PROTOCOL_BINARY_CMD_INCREMENT);
+}
+
+static enum test_return test_binary_incrq(void)
+{
+ return test_binary_incr_impl("test_binary_incrq", PROTOCOL_BINARY_CMD_INCREMENTQ);
+}
+
+static enum test_return test_binary_decr_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ arithmetic_command(&cmd, cc, key, strlen(key), 1, 9, 0);
+
+ int ii;
+ for (ii= 9; ii > -1; --ii)
+ {
+ if (ii == 9)
+ execute(send_packet(&cmd));
+ else
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ verify(memcached_ntohll(rsp.decr.message.body.value) == (uint64_t)ii);
+ }
+ else
+ execute(test_binary_noop());
+ }
+
+ /* decr 0 should not wrap */
+ execute(resend_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ verify(memcached_ntohll(rsp.decr.message.body.value) == 0);
+ }
+ else
+ {
+ /* @todo get the value and verify! */
+
+ }
+
+ /* @todo add incorrect cas */
+ execute(test_binary_noop());
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_decr(void)
+{
+ return test_binary_decr_impl("test_binary_decr",
+ PROTOCOL_BINARY_CMD_DECREMENT);
+}
+
+static enum test_return test_binary_decrq(void)
+{
+ return test_binary_decr_impl("test_binary_decrq",
+ PROTOCOL_BINARY_CMD_DECREMENTQ);
+}
+
+static enum test_return test_binary_version(void)
+{
+ command cmd;
+ response rsp;
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_VERSION, NULL, 0, NULL, 0);
+
+ execute(send_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_VERSION,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_flush_impl(const char *key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+
+ for (int ii= 0; ii < 2; ++ii)
+ {
+ execute(binary_set_item(key, key));
+ flush_command(&cmd, cc, 0, ii == 0);
+ execute(send_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_FLUSH)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ execute(test_binary_noop());
+
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
+ execute(send_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
+ PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
+ }
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_flush(void)
+{
+ return test_binary_flush_impl("test_binary_flush", PROTOCOL_BINARY_CMD_FLUSH);
+}
+
+static enum test_return test_binary_flushq(void)
+{
+ return test_binary_flush_impl("test_binary_flushq", PROTOCOL_BINARY_CMD_FLUSHQ);
+}
+
+static enum test_return test_binary_concat_impl(const char *key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ const char *value;
+
+ if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
+ {
+ value="hello";
+ }
+ else
+ {
+ value=" world";
+ }
+
+ execute(binary_set_item(key, value));
+
+ if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
+ {
+ value=" world";
+ }
+ else
+ {
+ value="hello";
+ }
+
+ raw_command(&cmd, cc, key, strlen(key), value, strlen(value));
+ execute(send_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_PREPEND)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ {
+ execute(test_binary_noop());
+ }
+
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
+ execute(send_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ verify(rsp.plain.message.header.response.bodylen - 4 == 11);
+ verify(memcmp(rsp.bytes + 28, "hello world", 11) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_append(void)
+{
+ return test_binary_concat_impl("test_binary_append", PROTOCOL_BINARY_CMD_APPEND);
+}
+
+static enum test_return test_binary_prepend(void)
+{
+ return test_binary_concat_impl("test_binary_prepend", PROTOCOL_BINARY_CMD_PREPEND);
+}
+
+static enum test_return test_binary_appendq(void)
+{
+ return test_binary_concat_impl("test_binary_appendq", PROTOCOL_BINARY_CMD_APPENDQ);
+}
+
+static enum test_return test_binary_prependq(void)
+{
+ return test_binary_concat_impl("test_binary_prependq", PROTOCOL_BINARY_CMD_PREPENDQ);
+}
+
+static enum test_return test_binary_stat(void)
+{
+ command cmd;
+ response rsp;
+
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_STAT, NULL, 0, NULL, 0);
+ execute(send_packet(&cmd));
+
+ do
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_STAT,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ } while (rsp.plain.message.header.response.keylen != 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return send_string(const char *cmd)
+{
+ execute(retry_write(cmd, strlen(cmd)));
+ return TEST_PASS;
+}
+
+static enum test_return receive_line(char *buffer, size_t size)
+{
+ size_t offset= 0;
+ while (offset < size)
+ {
+ execute(retry_read(buffer + offset, 1));
+ if (buffer[offset] == '\n')
+ {
+ if (offset + 1 < size)
+ {
+ buffer[offset + 1]= '\0';
+ return TEST_PASS;
+ }
+ else
+ return TEST_FAIL;
+ }
+ ++offset;
+ }
+
+ return TEST_FAIL;
+}
+
+static enum test_return receive_response(const char *msg) {
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ if (strcmp(msg, buffer) != 0) {
+ fprintf(stderr, "[%s]\n", buffer);
+ }
+ verify(strcmp(msg, buffer) == 0);
+ return TEST_PASS;
+}
+
+static enum test_return receive_error_response(void)
+{
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "ERROR", 5) == 0 ||
+ strncmp(buffer, "CLIENT_ERROR", 12) == 0 ||
+ strncmp(buffer, "SERVER_ERROR", 12) == 0);
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_quit(void)
+{
+ /* Verify that quit handles unknown options */
+ execute(send_string("quit foo bar\r\n"));
+ execute(receive_error_response());
+
+ /* quit doesn't support noreply */
+ execute(send_string("quit noreply\r\n"));
+ execute(receive_error_response());
+
+ /* Verify that quit works */
+ execute(send_string("quit\r\n"));
+
+ /* Socket should be closed now, read should return EXIT_SUCCESS */
+ char buffer[80];
+ verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0);
+ return TEST_PASS_RECONNECT;
+
+}
+
+static enum test_return test_ascii_version(void)
+{
+ /* Verify that version command handles unknown options */
+ execute(send_string("version foo bar\r\n"));
+ execute(receive_error_response());
+
+ /* version doesn't support noreply */
+ execute(send_string("version noreply\r\n"));
+ execute(receive_error_response());
+
+ /* Verify that verify works */
+ execute(send_string("version\r\n"));
+ char buffer[256];
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "VERSION ", 8) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_verbosity(void)
+{
+ /* This command does not adhere to the spec! */
+ execute(send_string("verbosity foo bar my\r\n"));
+ execute(receive_error_response());
+
+ execute(send_string("verbosity noreply\r\n"));
+ execute(test_ascii_version());
+
+ execute(send_string("verbosity 0 noreply\r\n"));
+ execute(test_ascii_version());
+
+ execute(send_string("verbosity\r\n"));
+ execute(receive_error_response());
+
+ execute(send_string("verbosity 1\r\n"));
+ execute(receive_response("OK\r\n"));
+
+ execute(send_string("verbosity 0\r\n"));
+ execute(receive_response("OK\r\n"));
+
+ return TEST_PASS;
+}
+
+
+
+static enum test_return test_ascii_set_impl(const char* key, bool noreply)
+{
+ /* @todo add tests for bogus format! */
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (!noreply)
+ {
+ execute(receive_response("STORED\r\n"));
+ }
+
+ return test_ascii_version();
+}
+
+static enum test_return test_ascii_set(void)
+{
+ return test_ascii_set_impl("test_ascii_set", false);
+}
+
+static enum test_return test_ascii_set_noreply(void)
+{
+ return test_ascii_set_impl("test_ascii_set_noreply", true);
+}
+
+static enum test_return test_ascii_add_impl(const char* key, bool noreply)
+{
+ /* @todo add tests for bogus format! */
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (!noreply)
+ {
+ execute(receive_response("STORED\r\n"));
+ }
+
+ execute(send_string(buffer));
+
+ if (!noreply)
+ {
+ execute(receive_response("NOT_STORED\r\n"));
+ }
+
+ return test_ascii_version();
+}
+
+static enum test_return test_ascii_add(void)
+{
+ return test_ascii_add_impl("test_ascii_add", false);
+}
+
+static enum test_return test_ascii_add_noreply(void)
+{
+ return test_ascii_add_impl("test_ascii_add_noreply", true);
+}
+
+static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata)
+{
+ char buffer[1024];
+
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "VALUE ", 6) == 0);
+ char *end= strchr(buffer + 6, ' ');
+ verify(end != NULL);
+ if (end)
+ {
+ *end= '\0';
+ }
+ *key= strdup(buffer + 6);
+ verify(*key != NULL);
+ char *ptr= end + 1;
+
+ errno= 0;
+ unsigned long val= strtoul(ptr, &end, 10); /* flags */
+ verify(errno == 0);
+ verify(ptr != end);
+ verify(val == 0);
+ verify(end != NULL);
+ errno= 0;
+ *ndata = (ssize_t)strtoul(end, &end, 10); /* size */
+ verify(errno == 0);
+ verify(ptr != end);
+ verify(end != NULL);
+ while (end and *end != '\n' and isspace(*end))
+ ++end;
+ verify(end and *end == '\n');
+
+ *value= static_cast<char*>(malloc((size_t)*ndata));
+ verify(*value != NULL);
+
+ execute(retry_read(*value, (size_t)*ndata));
+
+ execute(retry_read(buffer, 2));
+ verify(memcmp(buffer, "\r\n", 2) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_get_value(const char *key, const char *value)
+{
+
+ char buffer[1024];
+ size_t datasize= strlen(value);
+
+ verify(datasize < sizeof(buffer));
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "VALUE ", 6) == 0);
+ verify(strncmp(buffer + 6, key, strlen(key)) == 0);
+ char *ptr= buffer + 6 + strlen(key) + 1;
+ char *end;
+
+ errno= 0;
+ unsigned long val= strtoul(ptr, &end, 10); /* flags */
+ verify(errno == 0);
+ verify(ptr != end);
+ verify(val == 0);
+ verify(end != NULL);
+
+ errno= 0;
+ val= strtoul(end, &end, 10); /* size */
+ verify(errno == 0);
+ verify(ptr != end);
+ verify(val == datasize);
+ verify(end != NULL);
+ while (end and *end != '\n' and isspace(*end))
+ {
+ ++end;
+ }
+ verify(end and *end == '\n');
+
+ execute(retry_read(buffer, datasize));
+ verify(memcmp(buffer, value, datasize) == 0);
+
+ execute(retry_read(buffer, 2));
+ verify(memcmp(buffer, "\r\n", 2) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_get_item(const char *key, const char *value,
+ bool exist)
+{
+ char buffer[1024];
+ size_t datasize= 0;
+ if (value != NULL)
+ {
+ datasize= strlen(value);
+ }
+
+ verify(datasize < sizeof(buffer));
+ snprintf(buffer, sizeof(buffer), "get %s\r\n", key);
+ execute(send_string(buffer));
+
+ if (exist)
+ {
+ execute(ascii_get_value(key, value));
+ }
+
+ execute(retry_read(buffer, 5));
+ verify(memcmp(buffer, "END\r\n", 5) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_gets_value(const char *key, const char *value,
+ unsigned long *cas)
+{
+
+ char buffer[1024];
+ size_t datasize= strlen(value);
+
+ verify(datasize < sizeof(buffer));
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "VALUE ", 6) == 0);
+ verify(strncmp(buffer + 6, key, strlen(key)) == 0);
+ char *ptr= buffer + 6 + strlen(key) + 1;
+ char *end;
+
+ errno= 0;
+ unsigned long val= strtoul(ptr, &end, 10); /* flags */
+ verify(errno == 0);
+ verify(ptr != end);
+ verify(val == 0);
+ verify(end != NULL);
+
+ errno= 0;
+ val= strtoul(end, &end, 10); /* size */
+ verify(errno == 0);
+ verify(ptr != end);
+ verify(val == datasize);
+ verify(end != NULL);
+
+ errno= 0;
+ *cas= strtoul(end, &end, 10); /* cas */
+ verify(errno == 0);
+ verify(ptr != end);
+ verify(val == datasize);
+ verify(end != NULL);
+
+ while (end and *end != '\n' and isspace(*end))
+ {
+ ++end;
+ }
+ verify(end and *end == '\n');
+
+ execute(retry_read(buffer, datasize));
+ verify(memcmp(buffer, value, datasize) == 0);
+
+ execute(retry_read(buffer, 2));
+ verify(memcmp(buffer, "\r\n", 2) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_gets_item(const char *key, const char *value,
+ bool exist, unsigned long *cas)
+{
+ char buffer[1024];
+ size_t datasize= 0;
+ if (value != NULL)
+ {
+ datasize= strlen(value);
+ }
+
+ verify(datasize < sizeof(buffer));
+ snprintf(buffer, sizeof(buffer), "gets %s\r\n", key);
+ execute(send_string(buffer));
+
+ if (exist)
+ execute(ascii_gets_value(key, value, cas));
+
+ execute(retry_read(buffer, 5));
+ verify(memcmp(buffer, "END\r\n", 5) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_set_item(const char *key, const char *value)
+{
+ char buffer[300];
+ size_t len= strlen(value);
+ snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len);
+ execute(send_string(buffer));
+ execute(retry_write(value, len));
+ execute(send_string("\r\n"));
+ execute(receive_response("STORED\r\n"));
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_replace_impl(const char* key, bool noreply)
+{
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (noreply)
+ {
+ execute(test_ascii_version());
+ }
+ else
+ {
+ execute(receive_response("NOT_STORED\r\n"));
+ }
+
+ execute(ascii_set_item(key, "value"));
+ execute(ascii_get_item(key, "value", true));
+
+
+ execute(send_string(buffer));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("STORED\r\n"));
+
+ return test_ascii_version();
+}
+
+static enum test_return test_ascii_replace(void)
+{
+ return test_ascii_replace_impl("test_ascii_replace", false);
+}
+
+static enum test_return test_ascii_replace_noreply(void)
+{
+ return test_ascii_replace_impl("test_ascii_replace_noreply", true);
+}
+
+static enum test_return test_ascii_cas_impl(const char* key, bool noreply)
+{
+ char buffer[1024];
+ unsigned long cas;
+
+ execute(ascii_set_item(key, "value"));
+ execute(ascii_gets_item(key, "value", true, &cas));
+
+ snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (noreply)
+ {
+ execute(test_ascii_version());
+ }
+ else
+ {
+ execute(receive_response("STORED\r\n"));
+ }
+
+ /* reexecute the same command should fail due to illegal cas */
+ execute(send_string(buffer));
+
+ if (noreply)
+ {
+ execute(test_ascii_version());
+ }
+ else
+ {
+ execute(receive_response("EXISTS\r\n"));
+ }
+
+ return test_ascii_version();
+}
+
+static enum test_return test_ascii_cas(void)
+{
+ return test_ascii_cas_impl("test_ascii_cas", false);
+}
+
+static enum test_return test_ascii_cas_noreply(void)
+{
+ return test_ascii_cas_impl("test_ascii_cas_noreply", true);
+}
+
+static enum test_return test_ascii_delete_impl(const char *key, bool noreply)
+{
+ execute(ascii_set_item(key, "value"));
+
+ execute(send_string("delete\r\n"));
+ execute(receive_error_response());
+ /* BUG: the server accepts delete a b */
+ execute(send_string("delete a b c d e\r\n"));
+ execute(receive_error_response());
+
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("DELETED\r\n"));
+
+ execute(ascii_get_item(key, "value", false));
+ execute(send_string(buffer));
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("NOT_FOUND\r\n"));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_delete(void)
+{
+ return test_ascii_delete_impl("test_ascii_delete", false);
+}
+
+static enum test_return test_ascii_delete_noreply(void)
+{
+ return test_ascii_delete_impl("test_ascii_delete_noreply", true);
+}
+
+static enum test_return test_ascii_get(void)
+{
+ execute(ascii_set_item("test_ascii_get", "value"));
+
+ execute(send_string("get\r\n"));
+ execute(receive_error_response());
+ execute(ascii_get_item("test_ascii_get", "value", true));
+ execute(ascii_get_item("test_ascii_get_notfound", "value", false));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_gets(void)
+{
+ execute(ascii_set_item("test_ascii_gets", "value"));
+
+ execute(send_string("gets\r\n"));
+ execute(receive_error_response());
+ unsigned long cas;
+ execute(ascii_gets_item("test_ascii_gets", "value", true, &cas));
+ execute(ascii_gets_item("test_ascii_gets_notfound", "value", false, &cas));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_mget(void)
+{
+ const uint32_t nkeys= 5;
+ const char * const keys[]= {
+ "test_ascii_mget1",
+ "test_ascii_mget2",
+ /* test_ascii_mget_3 does not exist :) */
+ "test_ascii_mget4",
+ "test_ascii_mget5",
+ "test_ascii_mget6"
+ };
+
+ for (uint32_t x= 0; x < nkeys; ++x)
+ {
+ execute(ascii_set_item(keys[x], "value"));
+ }
+
+ /* Ask for a key that doesn't exist as well */
+ execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 "
+ "test_ascii_mget4 test_ascii_mget5 "
+ "test_ascii_mget6\r\n"));
+
+ std::vector<char *> returned;
+ returned.resize(nkeys);
+
+ for (uint32_t x= 0; x < nkeys; ++x)
+ {
+ ssize_t nbytes = 0;
+ char *v= NULL;
+ execute(ascii_get_unknown_value(&returned[x], &v, &nbytes));
+ verify(nbytes == 5);
+ verify(memcmp(v, "value", 5) == 0);
+ free(v);
+ }
+
+ char buffer[5];
+ execute(retry_read(buffer, 5));
+ verify(memcmp(buffer, "END\r\n", 5) == 0);
+
+ /* verify that we got all the keys we expected */
+ for (uint32_t x= 0; x < nkeys; ++x)
+ {
+ bool found= false;
+ for (uint32_t y= 0; y < nkeys; ++y)
+ {
+ if (strcmp(keys[x], returned[y]) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+ verify(found);
+ }
+
+ for (uint32_t x= 0; x < nkeys; ++x)
+ {
+ free(returned[x]);
+ }
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_incr_impl(const char* key, bool noreply)
+{
+ char cmd[300];
+ snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : "");
+
+ execute(ascii_set_item(key, "0"));
+ for (int x= 1; x < 11; ++x)
+ {
+ execute(send_string(cmd));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ {
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ int val= atoi(buffer);
+ verify(val == x);
+ }
+ }
+
+ execute(ascii_get_item(key, "10", true));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_incr(void)
+{
+ return test_ascii_incr_impl("test_ascii_incr", false);
+}
+
+static enum test_return test_ascii_incr_noreply(void)
+{
+ return test_ascii_incr_impl("test_ascii_incr_noreply", true);
+}
+
+static enum test_return test_ascii_decr_impl(const char* key, bool noreply)
+{
+ char cmd[300];
+ snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : "");
+
+ execute(ascii_set_item(key, "9"));
+ for (int x= 8; x > -1; --x)
+ {
+ execute(send_string(cmd));
+
+ if (noreply)
+ {
+ execute(test_ascii_version());
+ }
+ else
+ {
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ int val= atoi(buffer);
+ verify(val == x);
+ }
+ }
+
+ execute(ascii_get_item(key, "0", true));
+
+ /* verify that it doesn't wrap */
+ execute(send_string(cmd));
+ if (noreply)
+ {
+ execute(test_ascii_version());
+ }
+ else
+ {
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ }
+ execute(ascii_get_item(key, "0", true));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_decr(void)
+{
+ return test_ascii_decr_impl("test_ascii_decr", false);
+}
+
+static enum test_return test_ascii_decr_noreply(void)
+{
+ return test_ascii_decr_impl("test_ascii_decr_noreply", true);
+}
+
+
+static enum test_return test_ascii_flush_impl(const char *key, bool noreply)
+{
+#if 0
+ /* Verify that the flush_all command handles unknown options */
+ /* Bug in the current memcached server! */
+ execute(send_string("flush_all foo bar\r\n"));
+ execute(receive_error_response());
+#endif
+
+ execute(ascii_set_item(key, key));
+ execute(ascii_get_item(key, key, true));
+
+ if (noreply)
+ {
+ execute(send_string("flush_all noreply\r\n"));
+ execute(test_ascii_version());
+ }
+ else
+ {
+ execute(send_string("flush_all\r\n"));
+ execute(receive_response("OK\r\n"));
+ }
+
+ execute(ascii_get_item(key, key, false));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_flush(void)
+{
+ return test_ascii_flush_impl("test_ascii_flush", false);
+}
+
+static enum test_return test_ascii_flush_noreply(void)
+{
+ return test_ascii_flush_impl("test_ascii_flush_noreply", true);
+}
+
+static enum test_return test_ascii_concat_impl(const char *key,
+ bool append,
+ bool noreply)
+{
+ const char *value;
+
+ if (append)
+ value="hello";
+ else
+ value=" world";
+
+ execute(ascii_set_item(key, value));
+
+ if (append)
+ {
+ value=" world";
+ }
+ else
+ {
+ value="hello";
+ }
+
+ char cmd[400];
+ snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n",
+ append ? "append" : "prepend",
+ key, (unsigned int)strlen(value), noreply ? " noreply" : "",
+ value);
+ execute(send_string(cmd));
+
+ if (noreply)
+ {
+ execute(test_ascii_version());
+ }
+ else
+ {
+ execute(receive_response("STORED\r\n"));
+ }
+
+ execute(ascii_get_item(key, "hello world", true));
+
+ snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n",
+ append ? "append" : "prepend",
+ key, (unsigned int)strlen(value), noreply ? " noreply" : "",
+ value);
+ execute(send_string(cmd));
+
+ if (noreply)
+ {
+ execute(test_ascii_version());
+ }
+ else
+ {
+ execute(receive_response("NOT_STORED\r\n"));
+ }
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_append(void)
+{
+ return test_ascii_concat_impl("test_ascii_append", true, false);
+}
+
+static enum test_return test_ascii_prepend(void)
+{
+ return test_ascii_concat_impl("test_ascii_prepend", false, false);
+}
+
+static enum test_return test_ascii_append_noreply(void)
+{
+ return test_ascii_concat_impl("test_ascii_append_noreply", true, true);
+}
+
+static enum test_return test_ascii_prepend_noreply(void)
+{
+ return test_ascii_concat_impl("test_ascii_prepend_noreply", false, true);
+}
+
+static enum test_return test_ascii_stat(void)
+{
+ execute(send_string("stats noreply\r\n"));
+ execute(receive_error_response());
+ execute(send_string("stats\r\n"));
+ char buffer[1024];
+ do {
+ execute(receive_line(buffer, sizeof(buffer)));
+ } while (strcmp(buffer, "END\r\n") != 0);
+
+ return TEST_PASS_RECONNECT;
+}
+
+typedef enum test_return(*TEST_FUNC)(void);
+
+struct testcase
+{
+ const char *description;
+ TEST_FUNC function;
+};
+
+struct testcase testcases[]= {
+ { "ascii quit", test_ascii_quit },
+ { "ascii version", test_ascii_version },
+ { "ascii verbosity", test_ascii_verbosity },
+ { "ascii set", test_ascii_set },
+ { "ascii set noreply", test_ascii_set_noreply },
+ { "ascii get", test_ascii_get },
+ { "ascii gets", test_ascii_gets },
+ { "ascii mget", test_ascii_mget },
+ { "ascii flush", test_ascii_flush },
+ { "ascii flush noreply", test_ascii_flush_noreply },
+ { "ascii add", test_ascii_add },
+ { "ascii add noreply", test_ascii_add_noreply },
+ { "ascii replace", test_ascii_replace },
+ { "ascii replace noreply", test_ascii_replace_noreply },
+ { "ascii cas", test_ascii_cas },
+ { "ascii cas noreply", test_ascii_cas_noreply },
+ { "ascii delete", test_ascii_delete },
+ { "ascii delete noreply", test_ascii_delete_noreply },
+ { "ascii incr", test_ascii_incr },
+ { "ascii incr noreply", test_ascii_incr_noreply },
+ { "ascii decr", test_ascii_decr },
+ { "ascii decr noreply", test_ascii_decr_noreply },
+ { "ascii append", test_ascii_append },
+ { "ascii append noreply", test_ascii_append_noreply },
+ { "ascii prepend", test_ascii_prepend },
+ { "ascii prepend noreply", test_ascii_prepend_noreply },
+ { "ascii stat", test_ascii_stat },
+ { "binary noop", test_binary_noop },
+ { "binary quit", test_binary_quit },
+ { "binary quitq", test_binary_quitq },
+ { "binary set", test_binary_set },
+ { "binary setq", test_binary_setq },
+ { "binary flush", test_binary_flush },
+ { "binary flushq", test_binary_flushq },
+ { "binary add", test_binary_add },
+ { "binary addq", test_binary_addq },
+ { "binary replace", test_binary_replace },
+ { "binary replaceq", test_binary_replaceq },
+ { "binary delete", test_binary_delete },
+ { "binary deleteq", test_binary_deleteq },
+ { "binary get", test_binary_get },
+ { "binary getq", test_binary_getq },
+ { "binary getk", test_binary_getk },
+ { "binary getkq", test_binary_getkq },
+ { "binary incr", test_binary_incr },
+ { "binary incrq", test_binary_incrq },
+ { "binary decr", test_binary_decr },
+ { "binary decrq", test_binary_decrq },
+ { "binary version", test_binary_version },
+ { "binary append", test_binary_append },
+ { "binary appendq", test_binary_appendq },
+ { "binary prepend", test_binary_prepend },
+ { "binary prependq", test_binary_prependq },
+ { "binary stat", test_binary_stat },
+ { NULL, NULL}
+};
+
+const int ascii_tests = 1;
+const int binary_tests = 2;
+
+struct test_type_st
+{
+ bool ascii;
+ bool binary;
+};
+
+int main(int argc, char **argv)
+{
+ static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"};
+ struct test_type_st tests= { true, true };
+ int total= 0;
+ int failed= 0;
+ const char *hostname= NULL;
+ const char *port= MEMCACHED_DEFAULT_PORT_STRING;
+ int cmd;
+ bool prompt= false;
+ const char *testname= NULL;
+
+
+
+ while ((cmd= getopt(argc, argv, "qt:vch:p:PT:?ab")) != EOF)
+ {
+ switch (cmd) {
+ case 'a':
+ tests.ascii= true;
+ tests.binary= false;
+ break;
+
+ case 'b':
+ tests.ascii= false;
+ tests.binary= true;
+ break;
+
+ case 't':
+ timeout= atoi(optarg);
+ if (timeout == 0)
+ {
+ fprintf(stderr, "Invalid timeout. Please specify a number for -t\n");
+ return EXIT_FAILURE;
+ }
+ break;
+
+ case 'v': verbose= true;
+ break;
+
+ case 'c': do_core= true;
+ break;
+
+ case 'h': hostname= optarg;
+ break;
+
+ case 'p': port= optarg;
+ break;
+
+ case 'q':
+ close_stdio();
+ break;
+
+ case 'P': prompt= true;
+ break;
+
+ case 'T': testname= optarg;
+ break;
+
+ default:
+ fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n"
+ "\t-c\tGenerate coredump if a test fails\n"
+ "\t-v\tVerbose test output (print out the assertion)\n"
+ "\t-t n\tSet the timeout for io-operations to n seconds\n"
+ "\t-P\tPrompt the user before starting a test.\n"
+ "\t\t\t\"skip\" will skip the test\n"
+ "\t\t\t\"quit\" will terminate memcapable\n"
+ "\t\t\tEverything else will start the test\n"
+ "\t-T n\tJust run the test named n\n"
+ "\t-a\tOnly test the ascii protocol\n"
+ "\t-b\tOnly test the binary protocol\n",
+ argv[0]);
+ return EXIT_SUCCESS;
+ }
+ }
+
+ if (!hostname)
+ {
+ fprintf(stderr, "No hostname was provided.\n");
+ return EXIT_FAILURE;
+ }
+
+ initialize_sockets();
+ sock= connect_server(hostname, port);
+ if (sock == INVALID_SOCKET)
+ {
+ fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
+ hostname?:"(null)", port?:"(null)", strerror(get_socket_errno()));
+ return EXIT_FAILURE;
+ }
+
+ for (int ii= 0; testcases[ii].description != NULL; ++ii)
+ {
+ if (testname != NULL && strcmp(testcases[ii].description, testname) != 0)
+ {
+ continue;
+ }
+
+ if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) ||
+ (testcases[ii].description[0] == 'b' && (tests.binary) == 0))
+ {
+ continue;
+ }
+ ++total;
+ fprintf(stdout, "%-40s", testcases[ii].description);
+ fflush(stdout);
+
+ if (prompt)
+ {
+ fprintf(stdout, "\nPress <return> when you are ready? ");
+ char buffer[80] = {0};
+ if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
+ if (strncmp(buffer, "skip", 4) == 0)
+ {
+ fprintf(stdout, "%-40s%s\n", testcases[ii].description,
+ status_msg[TEST_SKIP]);
+ fflush(stdout);
+ continue;
+ }
+ if (strncmp(buffer, "quit", 4) == 0)
+ {
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ fprintf(stdout, "%-40s", testcases[ii].description);
+ fflush(stdout);
+ }
+
+ bool reconnect= false;
+ enum test_return ret= testcases[ii].function();
+ if (ret == TEST_FAIL)
+ {
+ reconnect= true;
+ ++failed;
+ if (verbose)
+ {
+ fprintf(stderr, "\n");
+ }
+ }
+ else if (ret == TEST_PASS_RECONNECT)
+ {
+ reconnect= true;
+ }
+
+ if (ret == TEST_FAIL)
+ {
+ fprintf(stderr, "%s\n", status_msg[ret]);
+ }
+ else
+ {
+ fprintf(stdout, "%s\n", status_msg[ret]);
+ }
+
+ if (reconnect)
+ {
+ closesocket(sock);
+ if ((sock= connect_server(hostname, port)) == INVALID_SOCKET)
+ {
+ fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", hostname?:"(null)", port?:"(null)", strerror(get_socket_errno()));
+ fprintf(stderr, "%d of %d tests failed\n", failed, total);
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ closesocket(sock);
+ if (failed == 0)
+ {
+ fprintf(stdout, "All tests passed\n");
+ }
+ else
+ {
+ fprintf(stderr, "%d of %d tests failed\n", failed, total);
+ }
+
+ return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
--- /dev/null
+#!/bin/sh
+src/bin/memcapable -vh localhost
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 <mem_config.h>
+
+#include <cstdio>
+#include <cstring>
+#include <getopt.h>
+#include <iostream>
+#include <unistd.h>
+#include <libmemcached-1.0/memcached.h>
+
+#include "utilities.h"
+
+#define PROGRAM_NAME "memcat"
+#define PROGRAM_DESCRIPTION "Cat a set of key values to stdout."
+
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static int opt_displayflag= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+static char *opt_file;
+
+int main(int argc, char *argv[])
+{
+ char *string;
+ size_t string_length;
+ uint32_t flags;
+ memcached_return_t rc;
+
+ int return_code= EXIT_SUCCESS;
+
+ options_parse(argc, argv);
+ initialize_sockets();
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No servers provided" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_server_st* servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ memcached_st* memc= memcached_create(NULL);
+ process_hash_option(memc, opt_hash);
+
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t)opt_binary);
+
+ if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ memcached_free(memc);
+ std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (opt_username)
+ {
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
+ {
+ std::cerr << memcached_last_error_message(memc) << std::endl;
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+ }
+
+ while (optind < argc)
+ {
+ string= memcached_get(memc, argv[optind], strlen(argv[optind]),
+ &string_length, &flags, &rc);
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ if (opt_displayflag)
+ {
+ if (opt_verbose)
+ {
+ std::cout << "key: " << argv[optind] << std::endl << "flags: " << flags << std::endl;
+ }
+ }
+ else
+ {
+ if (opt_verbose)
+ {
+ std::cout << "key: " << argv[optind] << std::endl << "flags: " << flags << std::endl << "length: " << string_length << std::endl << "value: ";
+ }
+
+ if (opt_file)
+ {
+ FILE *fp= fopen(opt_file, "w");
+ if (fp == NULL)
+ {
+ perror("fopen");
+ return_code= EXIT_FAILURE;
+ break;
+ }
+
+ size_t written= fwrite(string, 1, string_length, fp);
+ if (written != string_length)
+ {
+ std::cerr << "error writing file to file " << opt_file << " wrote " << written << ", should have written" << string_length << std::endl;
+ return_code= EXIT_FAILURE;
+ break;
+ }
+
+ if (fclose(fp))
+ {
+ std::cerr << "error closing " << opt_file << std::endl;
+ return_code= EXIT_FAILURE;
+ break;
+ }
+ }
+ else
+ {
+ std::cout.write(string, string_length);
+ std::cout << std::endl;
+ }
+ free(string);
+ }
+ }
+ else if (rc != MEMCACHED_NOTFOUND)
+ {
+ std::cerr << "error on " << argv[optind] << "(" << memcached_strerror(memc, rc) << ")";
+ if (memcached_last_error_errno(memc))
+ {
+ std::cerr << " system error (" << strerror(memcached_last_error_errno(memc)) << ")" << std::endl;
+ }
+ std::cerr << std::endl;
+
+ return_code= EXIT_FAILURE;
+ break;
+ }
+ else // Unknown Issue
+ {
+ std::cerr << "error on " << argv[optind] << "("<< memcached_strerror(NULL, rc) << ")" << std::endl;
+ return_code= EXIT_FAILURE;
+ }
+ optind++;
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ {
+ free(opt_servers);
+ }
+ if (opt_hash)
+ {
+ free(opt_hash);
+ }
+
+ return return_code;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+ int option_index= 0;
+
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {(OPTIONSTRING)"file", required_argument, NULL, OPT_FILE},
+ {0, 0, 0, 0},
+ };
+
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1) break;
+ switch (option_rv)
+ {
+ case 0:
+ break;
+ case OPT_BINARY:
+ opt_binary = 1;
+ break;
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ break;
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+ case OPT_FILE:
+ opt_file= optarg;
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(EXIT_FAILURE);
+ default:
+ abort();
+ }
+ }
+}
--- /dev/null
+#!/bin/sh
+src/bin/memcp.sh
+src/bin/memcat --servers=localhost -v mem.testdata
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ * 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 "mem_config.h"
+
+#include <cerrno>
+#include <climits>
+#include <cstdio>
+#include <cstdlib>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <getopt.h>
+#include <iostream>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#include <libmemcached-1.0/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+
+#define PROGRAM_NAME "memcp"
+#define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+static bool opt_binary= false;
+static bool opt_udp= false;
+static bool opt_buffer= false;
+static int opt_verbose= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static int opt_method= OPT_SET;
+static uint32_t opt_flags= 0;
+static time_t opt_expires= 0;
+static char *opt_username;
+static char *opt_passwd;
+
+static long strtol_wrapper(const char *nptr, int base, bool *error)
+{
+ long val;
+ char *endptr;
+
+ errno= 0; /* To distinguish success/failure after call */
+ val= strtol(nptr, &endptr, base);
+
+ /* Check for various possible errors */
+
+ if ((errno == ERANGE and (val == LONG_MAX or val == LONG_MIN))
+ or (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[])
+{
+
+ options_parse(argc, argv);
+
+ if (optind >= argc)
+ {
+ fprintf(stderr, "Expected argument after options\n");
+ exit(EXIT_FAILURE);
+ }
+
+ initialize_sockets();
+
+ memcached_st *memc= memcached_create(NULL);
+
+ if (opt_udp)
+ {
+ if (opt_verbose)
+ {
+ std::cout << "Enabling UDP" << std::endl;
+ }
+
+ if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, opt_udp)))
+ {
+ memcached_free(memc);
+ std::cerr << "Could not enable UDP protocol." << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (opt_buffer)
+ {
+ if (opt_verbose)
+ {
+ std::cout << "Enabling MEMCACHED_BEHAVIOR_BUFFER_REQUESTS" << std::endl;
+ }
+
+ if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, opt_buffer)))
+ {
+ memcached_free(memc);
+ std::cerr << "Could not enable MEMCACHED_BEHAVIOR_BUFFER_REQUESTS." << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ process_hash_option(memc, opt_hash);
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+#if 0
+ else if (argc >= 1 and argv[--argc])
+ {
+ opt_servers= strdup(argv[argc]);
+ }
+#endif
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No Servers provided" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_server_st* servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, opt_binary);
+ if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ memcached_free(memc);
+ std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (opt_username)
+ {
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
+ {
+ std::cerr << memcached_last_error_message(memc) << std::endl;
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+ }
+
+ int exit_code= EXIT_SUCCESS;
+ while (optind < argc)
+ {
+ int fd= open(argv[optind], O_RDONLY);
+ if (fd < 0)
+ {
+ std::cerr << "memcp " << argv[optind] << " " << strerror(errno) << std::endl;
+ optind++;
+ exit_code= EXIT_FAILURE;
+ continue;
+ }
+
+ struct stat sbuf;
+ if (fstat(fd, &sbuf) == -1)
+ {
+ std::cerr << "memcp " << argv[optind] << " " << strerror(errno) << std::endl;
+ optind++;
+ exit_code= EXIT_FAILURE;
+ continue;
+ }
+
+ char *ptr= rindex(argv[optind], '/');
+ if (ptr)
+ {
+ ptr++;
+ }
+ else
+ {
+ ptr= argv[optind];
+ }
+
+ if (opt_verbose)
+ {
+ static const char *opstr[] = { "set", "add", "replace" };
+ printf("op: %s\nsource file: %s\nlength: %lu\n"
+ "key: %s\nflags: %x\nexpires: %lu\n",
+ opstr[opt_method - OPT_SET], argv[optind], (unsigned long)sbuf.st_size,
+ ptr, opt_flags, (unsigned long)opt_expires);
+ }
+
+ // The file may be empty
+ char *file_buffer_ptr= NULL;
+ if (sbuf.st_size > 0)
+ {
+ if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL)
+ {
+ std::cerr << "Error allocating file buffer(" << strerror(errno) << ")" << std::endl;
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+
+ ssize_t read_length;
+ if ((read_length= ::read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1)
+ {
+ std::cerr << "Error while reading file " << file_buffer_ptr << " (" << strerror(errno) << ")" << std::endl;
+ close(fd);
+ free(file_buffer_ptr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (read_length != sbuf.st_size)
+ {
+ std::cerr << "Failure while reading file. Read length was not equal to stat() length" << std::endl;
+ close(fd);
+ free(file_buffer_ptr);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_return_t rc;
+ if (opt_method == OPT_ADD)
+ {
+ rc= memcached_add(memc, ptr, strlen(ptr),
+ file_buffer_ptr, (size_t)sbuf.st_size,
+ opt_expires, opt_flags);
+ }
+ else if (opt_method == OPT_REPLACE)
+ {
+ rc= memcached_replace(memc, ptr, strlen(ptr),
+ file_buffer_ptr, (size_t)sbuf.st_size,
+ opt_expires, opt_flags);
+ }
+ else
+ {
+ rc= memcached_set(memc, ptr, strlen(ptr),
+ file_buffer_ptr, (size_t)sbuf.st_size,
+ opt_expires, opt_flags);
+ }
+
+ if (memcached_failed(rc))
+ {
+ std::cerr << "Error occrrured during memcached_set(): " << memcached_last_error_message(memc) << std::endl;
+ exit_code= EXIT_FAILURE;
+ }
+
+ ::free(file_buffer_ptr);
+ ::close(fd);
+ optind++;
+ }
+
+ if (opt_verbose)
+ {
+ std::cout << "Calling memcached_free()" << std::endl;
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ {
+ free(opt_servers);
+ }
+
+ if (opt_hash)
+ {
+ free(opt_hash);
+ }
+
+ return exit_code;
+}
+
+static void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP},
+ {(OPTIONSTRING)"buffer", no_argument, NULL, OPT_BUFFER},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG},
+ {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+ {(OPTIONSTRING)"set", no_argument, NULL, OPT_SET},
+ {(OPTIONSTRING)"add", no_argument, NULL, OPT_ADD},
+ {(OPTIONSTRING)"replace", no_argument, NULL, OPT_REPLACE},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0},
+ };
+
+ bool opt_version= false;
+ bool opt_help= false;
+ int option_index= 0;
+
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+
+ if (option_rv == -1)
+ break;
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_BINARY:
+ opt_binary= true;
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose= OPT_VERBOSE;
+ break;
+
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose= OPT_DEBUG;
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ opt_version= true;
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+
+ case OPT_FLAG: /* --flag */
+ {
+ bool strtol_error;
+ opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error);
+ if (strtol_error == true)
+ {
+ fprintf(stderr, "Bad value passed via --flag\n");
+ exit(1);
+ }
+ }
+ break;
+
+ case OPT_EXPIRE: /* --expire */
+ {
+ bool strtol_error;
+ opt_expires= (time_t)strtol_wrapper(optarg, 10, &strtol_error);
+ if (strtol_error == true)
+ {
+ fprintf(stderr, "Bad value passed via --expire\n");
+ exit(1);
+ }
+ }
+ break;
+
+ case OPT_SET:
+ opt_method= OPT_SET;
+ break;
+
+ case OPT_REPLACE:
+ opt_method= OPT_REPLACE;
+ break;
+
+ case OPT_ADD:
+ opt_method= OPT_ADD;
+ break;
+
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+ case OPT_UDP:
+ opt_udp= true;
+ break;
+
+ case OPT_BUFFER:
+ opt_buffer= true;
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ exit(EXIT_SUCCESS);
+ }
+}
--- /dev/null
+#!/bin/sh
+src/bin/memcp -v --servers localhost mem.testdata
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 "mem_config.h"
+
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <iostream>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libmemcached-1.0/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+
+#define PROGRAM_NAME "memdump"
+#define PROGRAM_DESCRIPTION "Dump all values from one or many servers."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+static bool opt_binary=0;
+static int opt_verbose= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+/* Print the keys and counter how many were found */
+static memcached_return_t key_printer(const memcached_st *,
+ const char *key, size_t key_length,
+ void *)
+{
+ std::cout.write(key, key_length);
+ std::cout << std::endl;
+
+ return MEMCACHED_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ memcached_dump_fn callbacks[1];
+
+ callbacks[0]= &key_printer;
+
+ options_parse(argc, argv);
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+ else if (argc >= 1 and argv[--argc])
+ {
+ opt_servers= strdup(argv[argc]);
+ }
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No Servers provided" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_server_st* servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ memcached_st *memc= memcached_create(NULL);
+ if (memc == NULL)
+ {
+ std::cerr << "Could not allocate a memcached_st structure.\n" << std::endl;
+ return EXIT_FAILURE;
+ }
+ process_hash_option(memc, opt_hash);
+
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t)opt_binary);
+
+ if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ memcached_free(memc);
+ std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (opt_username)
+ {
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
+ {
+ std::cerr << memcached_last_error_message(memc) << std::endl;
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+ }
+
+ memcached_return_t rc= memcached_dump(memc, callbacks, NULL, 1);
+
+ int exit_code= EXIT_SUCCESS;
+ if (memcached_failed(rc))
+ {
+ if (opt_verbose)
+ {
+ std::cerr << "Failed to dump keys: " << memcached_last_error_message(memc) << std::endl;
+ }
+ exit_code= EXIT_FAILURE;
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ {
+ free(opt_servers);
+ }
+ if (opt_hash)
+ {
+ free(opt_hash);
+ }
+
+ return exit_code;
+}
+
+static void options_parse(int argc, char *argv[])
+{
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0}
+ };
+
+ int option_index= 0;
+ bool opt_version= false;
+ bool opt_help= false;
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+
+ if (option_rv == -1) break;
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_BINARY:
+ opt_binary= true;
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose= OPT_VERBOSE;
+ break;
+
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose= OPT_DEBUG;
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ opt_verbose= true;
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
+ exit(EXIT_SUCCESS);
+ }
+}
--- /dev/null
+#!/bin/bash
+src/bin/memdump -v --servers localhost
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 "mem_config.h"
+
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <climits>
+
+#include <getopt.h>
+#include <iostream>
+#include <unistd.h>
+
+#include <libmemcached-1.0/memcached.h>
+
+#include "utilities.h"
+
+#define PROGRAM_NAME "memerror"
+#define PROGRAM_DESCRIPTION "Translate a memcached errror code into a string."
+
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+ options_parse(argc, argv);
+
+ if (argc < 2)
+ {
+ return EXIT_FAILURE;
+ }
+
+ while (optind < argc)
+ {
+ errno= 0;
+ char *nptr;
+ unsigned long value= strtoul(argv[optind], &nptr, 10);
+
+ if ((errno != 0) or
+ (nptr == argv[optind] and value == 0) or
+ (value == ULONG_MAX and errno == ERANGE) or
+ (value == 0 and errno == EINVAL))
+ {
+ std::cerr << "strtoul() was unable to parse given value" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (value < MEMCACHED_MAXIMUM_RETURN)
+ {
+ std::cout << memcached_strerror(NULL, (memcached_return_t)value) << std::endl;
+ }
+ else
+ {
+ std::cerr << memcached_strerror(NULL, MEMCACHED_MAXIMUM_RETURN) << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ optind++;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {0, 0, 0, 0},
+ };
+
+ bool opt_version= false;
+ bool opt_help= false;
+ int option_index= 0;
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1)
+ {
+ break;
+ }
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ opt_version= true;
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(EXIT_FAILURE);
+
+ default:
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
+ exit(EXIT_SUCCESS);
+ }
+}
--- /dev/null
+#!/bin/sh
+src/bin/memerror 0 1 2 3
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 "mem_config.h"
+
+#include <cstdio>
+#include <cstring>
+#include <getopt.h>
+#include <iostream>
+#include <unistd.h>
+
+#include <libmemcached-1.0/memcached.h>
+#include "client_options.h"
+#include "utilities.h"
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+#define PROGRAM_NAME "memexist"
+#define PROGRAM_DESCRIPTION "Check for the existance of a key within a cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+ options_parse(argc, argv);
+ initialize_sockets();
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No Servers provided" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_server_st* servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ memcached_st* memc= memcached_create(NULL);
+ process_hash_option(memc, opt_hash);
+
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t) opt_binary);
+
+ if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ memcached_free(memc);
+ std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (opt_username)
+ {
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
+ {
+ std::cerr << memcached_last_error_message(memc) << std::endl;
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+ }
+
+ int return_code= EXIT_SUCCESS;
+
+ while (optind < argc)
+ {
+ memcached_return_t rc= memcached_exist(memc, argv[optind], strlen(argv[optind]));
+
+ if (rc == MEMCACHED_NOTFOUND)
+ {
+ if (opt_verbose)
+ {
+ std::cout << "Could not find key \"" << argv[optind] << "\"" << std::endl;
+ }
+
+ return_code= EXIT_FAILURE;
+ }
+ else if (memcached_failed(rc))
+ {
+ if (opt_verbose)
+ {
+ std::cerr << "Fatal error for key \"" << argv[optind] << "\" :" << memcached_last_error_message(memc) << std::endl;
+ }
+
+ return_code= EXIT_FAILURE;
+ }
+ else // success
+ {
+ if (opt_verbose)
+ {
+ std::cout << "Found key " << argv[optind] << std::endl;
+ }
+ }
+
+ optind++;
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ {
+ free(opt_servers);
+ }
+
+ if (opt_hash)
+ {
+ free(opt_hash);
+ }
+
+ return return_code;
+}
+
+
+static void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0},
+ };
+
+ bool opt_version= false;
+ bool opt_help= false;
+ int option_index= 0;
+
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1)
+ {
+ break;
+ }
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_BINARY:
+ opt_binary = 1;
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ opt_version= true;
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(EXIT_SUCCESS);
+
+ default:
+ abort();
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ exit(EXIT_SUCCESS);
+ }
+}
--- /dev/null
+#!/bin/bash
+src/bin/memcp.sh
+src/bin/memexist -v --servers localhost mem.testdata
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 "mem_config.h"
+
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <getopt.h>
+#include <iostream>
+#include <unistd.h>
+
+#include <libmemcached-1.0/memcached.h>
+#include "client_options.h"
+#include "utilities.h"
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static time_t opt_expire= 0;
+static char *opt_servers= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+#define PROGRAM_NAME "memflush"
+#define PROGRAM_DESCRIPTION "Erase all data in a server of memcached servers."
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+ options_parse(argc, argv);
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No Servers provided" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_server_st* servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ memcached_st *memc= memcached_create(NULL);
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t) opt_binary);
+
+ if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ memcached_free(memc);
+ std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (opt_username)
+ {
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
+ {
+ std::cerr << memcached_last_error_message(memc) << std::endl;
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+ }
+
+ memcached_return_t rc = memcached_flush(memc, opt_expire);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ std::cerr << memcached_last_error_message(memc) << std::endl;
+ }
+
+ memcached_free(memc);
+
+ free(opt_servers);
+
+ return EXIT_SUCCESS;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0},
+ };
+
+ bool opt_version= false;
+ bool opt_help= false;
+ int option_index= 0;
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1) break;
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_BINARY:
+ opt_binary= true;
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose= OPT_VERBOSE;
+ break;
+
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose= OPT_DEBUG;
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ opt_version= true;
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+
+ case OPT_EXPIRE: /* --expire */
+ errno= 0;
+ opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ std::cerr << "Incorrect value passed to --expire: `" << optarg << "`" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(EXIT_FAILURE);
+
+ default:
+ abort();
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
+ exit(EXIT_SUCCESS);
+ }
+}
--- /dev/null
+#!/bin/sh
+src/bin/memflush -v --servers localhost
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <mem_config.h>
+
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+
+#include <libmemcached-1.0/memcached.h>
+
+int main(int argc, char *argv[])
+{
+
+ if (argc < 2)
+ {
+ std::cerr << "No arguments provided." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ for (int x= 1; x < argc; x++)
+ {
+ char buffer[BUFSIZ];
+ memcached_return_t rc;
+ rc= libmemcached_check_configuration(argv[x], strlen(argv[x]), buffer, sizeof(buffer));
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ std::cerr << "Failed to parse argument #" << x << " " << argv[x] << std::endl;
+ std::cerr << buffer << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+#!/bin/sh
+src/bin/memparse --server=localhost:11211/?1 --server=127.0.0.1:11211/?2
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 "mem_config.h"
+
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <libmemcached-1.0/memcached.h>
+#include <libmemcachedutil-1.0/util.h>
+#include "client_options.h"
+#include "utilities.h"
+
+#include <iostream>
+
+static bool opt_binary= false;
+static int opt_verbose= 0;
+static time_t opt_expire= 0;
+static char *opt_servers= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+#define PROGRAM_NAME "memping"
+#define PROGRAM_DESCRIPTION "Ping a server to see if it is alive"
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+ options_parse(argc, argv);
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No Servers provided" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ int exit_code= EXIT_SUCCESS;
+ memcached_server_st *servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ exit_code= EXIT_FAILURE;
+ }
+ else
+ {
+ for (uint32_t x= 0; x < memcached_server_list_count(servers); x++)
+ {
+ memcached_return_t instance_rc;
+ const char *hostname= servers[x].hostname;
+ in_port_t port= servers[x].port;
+
+ if (opt_verbose)
+ {
+ std::cout << "Trying to ping " << hostname << ":" << port << std::endl;
+ }
+
+ if (libmemcached_util_ping2(hostname, port, opt_username, opt_passwd, &instance_rc) == false)
+ {
+ std::cerr << "Failed to ping " << hostname << ":" << port << " " << memcached_strerror(NULL, instance_rc) << std::endl;
+ exit_code= EXIT_FAILURE;
+ }
+ }
+ }
+ memcached_server_list_free(servers);
+
+ free(opt_servers);
+
+ return exit_code;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0},
+ };
+
+ bool opt_version= false;
+ bool opt_help= false;
+ int option_index= 0;
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+
+ if (option_rv == -1) break;
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_BINARY:
+ opt_binary= true;
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ break;
+
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+
+ case OPT_EXPIRE: /* --expire */
+ errno= 0;
+ opt_expire= time_t(strtoll(optarg, (char **)NULL, 10));
+ if (errno != 0)
+ {
+ std::cerr << "Incorrect value passed to --expire: `" << optarg << "`" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_USERNAME:
+ opt_username= optarg;
+ opt_binary= true;
+ break;
+
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ exit(EXIT_SUCCESS);
+ }
+}
--- /dev/null
+#!/bin/sh
+src/bin/memping -v --servers localhost
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 "mem_config.h"
+
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <getopt.h>
+#include <iostream>
+#include <unistd.h>
+
+#include <libmemcached-1.0/memcached.h>
+#include "client_options.h"
+#include "utilities.h"
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static time_t opt_expire= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+#define PROGRAM_NAME "memrm"
+#define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+ options_parse(argc, argv);
+ initialize_sockets();
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No Servers provided" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_server_st* servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ memcached_st* memc= memcached_create(NULL);
+ process_hash_option(memc, opt_hash);
+
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t) opt_binary);
+
+ if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ memcached_free(memc);
+ std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (opt_username)
+ {
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
+ {
+ std::cerr << memcached_last_error_message(memc) << std::endl;
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+ }
+
+ int return_code= EXIT_SUCCESS;
+
+ while (optind < argc)
+ {
+ memcached_return_t rc= memcached_delete(memc, argv[optind], strlen(argv[optind]), opt_expire);
+
+ if (rc == MEMCACHED_NOTFOUND)
+ {
+ if (opt_verbose)
+ {
+ std::cerr << "Could not find key \"" << argv[optind] << "\"" << std::endl;
+ }
+ }
+ else if (memcached_fatal(rc))
+ {
+ if (opt_verbose)
+ {
+ std::cerr << "Failed to delete key \"" << argv[optind] << "\" :" << memcached_last_error_message(memc) << std::endl;
+ }
+
+ return_code= EXIT_FAILURE;
+ }
+ else // success
+ {
+ if (opt_verbose)
+ {
+ std::cout << "Deleted key " << argv[optind];
+ if (opt_expire)
+ {
+ std::cout << " expires: " << opt_expire << std::endl;
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ optind++;
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ {
+ free(opt_servers);
+ }
+
+ if (opt_hash)
+ {
+ free(opt_hash);
+ }
+
+ return return_code;
+}
+
+
+static void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0},
+ };
+
+ bool opt_version= false;
+ bool opt_help= false;
+ int option_index= 0;
+
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1)
+ {
+ break;
+ }
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_BINARY:
+ opt_binary = 1;
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ opt_version= true;
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+
+ case OPT_EXPIRE: /* --expire */
+ errno= 0;
+ opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ std::cerr << "Incorrect value passed to --expire: `" << optarg << "`" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(EXIT_SUCCESS);
+
+ default:
+ abort();
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ exit(EXIT_SUCCESS);
+ }
+}
--- /dev/null
+#!/bin/sh
+src/bin/memcp.sh
+src/bin/memrm -v --servers localhost mem.testdata
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <mem_config.h>
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <getopt.h>
+#include <memory>
+#include <pthread.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <iostream>
+
+#include <libmemcached-1.0/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 VALUE_BYTES 4096
+
+#define PROGRAM_NAME "memslap"
+#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
+
+/* Global Thread counter */
+volatile unsigned int master_wakeup;
+pthread_mutex_t sleeper_mutex;
+pthread_cond_t sleep_threshhold;
+
+/* Types */
+enum test_t {
+ SET_TEST,
+ GET_TEST,
+ MGET_TEST
+};
+
+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_t test;
+ memcached_st *memc;
+ const memcached_st* root;
+
+ thread_context_st(const memcached_st* memc_arg, test_t test_arg) :
+ key_count(0),
+ initial_pairs(NULL),
+ initial_number(0),
+ execute_pairs(NULL),
+ execute_number(0),
+ keys(0),
+ key_lengths(NULL),
+ test(test_arg),
+ memc(NULL),
+ root(memc_arg)
+ {
+ }
+
+ void init()
+ {
+ memc= memcached_clone(NULL, root);
+ }
+
+ ~thread_context_st()
+ {
+ if (execute_pairs)
+ {
+ pairs_free(execute_pairs);
+ }
+ memcached_free(memc);
+ }
+};
+
+struct conclusions_st {
+ long int load_time;
+ long int read_time;
+ unsigned int rows_loaded;
+ unsigned int rows_read;
+
+ conclusions_st() :
+ load_time(0),
+ read_time(0),
+ rows_loaded(0),
+ rows_read()
+ { }
+};
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+void conclusions_print(conclusions_st *conclusion);
+void scheduler(memcached_server_st *servers, conclusions_st *conclusion);
+pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
+ unsigned int *actual_loaded);
+void flush_all(memcached_st *memc);
+
+static bool 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 bool opt_udp_io= false;
+test_t opt_test= SET_TEST;
+
+extern "C" {
+
+static __attribute__((noreturn)) void *run_task(void *p)
+{
+ thread_context_st *context= (thread_context_st *)p;
+
+ context->init();
+
+ pthread_mutex_lock(&sleeper_mutex);
+ while (master_wakeup)
+ {
+ pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
+ }
+ pthread_mutex_unlock(&sleeper_mutex);
+
+ /* Do Stuff */
+ switch (context->test)
+ {
+ case SET_TEST:
+ assert(context->execute_pairs);
+ execute_set(context->memc, context->execute_pairs, context->execute_number);
+ break;
+
+ case GET_TEST:
+ execute_get(context->memc, context->initial_pairs, context->initial_number);
+ break;
+
+ case MGET_TEST:
+ execute_mget(context->memc, (const char*const*)context->keys, context->key_lengths, context->initial_number);
+ break;
+ }
+
+ delete context;
+
+ pthread_exit(0);
+}
+
+}
+
+
+int main(int argc, char *argv[])
+{
+ conclusions_st conclusion;
+
+ srandom((unsigned int)time(NULL));
+ options_parse(argc, argv);
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No Servers provided" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_server_st *servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ pthread_mutex_init(&sleeper_mutex, NULL);
+ pthread_cond_init(&sleep_threshhold, NULL);
+
+ int error_code= EXIT_SUCCESS;
+ try {
+ scheduler(servers, &conclusion);
+ }
+ catch(std::exception& e)
+ {
+ std::cerr << "Died with exception: " << e.what() << std::endl;
+ error_code= EXIT_FAILURE;
+ }
+
+ free(opt_servers);
+
+ (void)pthread_mutex_destroy(&sleeper_mutex);
+ (void)pthread_cond_destroy(&sleep_threshhold);
+ conclusions_print(&conclusion);
+ memcached_server_list_free(servers);
+
+ return error_code;
+}
+
+void scheduler(memcached_server_st *servers, conclusions_st *conclusion)
+{
+ unsigned int actual_loaded= 0; /* Fix warning */
+
+ struct timeval start_time, end_time;
+ pairs_st *pairs= NULL;
+
+ memcached_st *memc= memcached_create(NULL);
+
+ memcached_server_push(memc, servers);
+
+ /* We need to set udp behavior before adding servers to the client */
+ if (opt_udp_io)
+ {
+ if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, opt_udp_io)))
+ {
+ std::cerr << "Failed to enable UDP." << std::endl;
+ memcached_free(memc);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t)opt_binary);
+
+ if (opt_flush)
+ {
+ flush_all(memc);
+ }
+
+ if (opt_createial_load)
+ {
+ pairs= load_create_data(memc, opt_createial_load, &actual_loaded);
+ }
+
+ char **keys= static_cast<char **>(calloc(actual_loaded, sizeof(char*)));
+ size_t *key_lengths= static_cast<size_t *>(calloc(actual_loaded, sizeof(size_t)));
+
+ if (keys == NULL or key_lengths == NULL)
+ {
+ free(keys);
+ free(key_lengths);
+ keys= NULL;
+ key_lengths= NULL;
+ }
+ else
+ {
+ for (uint32_t x= 0; x < actual_loaded; ++x)
+ {
+ keys[x]= pairs[x].key;
+ key_lengths[x]= pairs[x].key_length;
+ }
+ }
+
+ /* We set this after we have loaded */
+ {
+ if (opt_non_blocking_io)
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
+
+ if (opt_tcp_nodelay)
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
+ }
+
+ pthread_mutex_lock(&sleeper_mutex);
+ master_wakeup= 1;
+ pthread_mutex_unlock(&sleeper_mutex);
+
+ pthread_t *threads= new (std::nothrow) pthread_t[opt_concurrency];
+
+ if (threads == NULL)
+ {
+ exit(EXIT_FAILURE);
+ }
+
+ for (uint32_t x= 0; x < opt_concurrency; x++)
+ {
+ thread_context_st *context= new thread_context_st(memc, opt_test);
+ context->test= opt_test;
+
+ context->initial_pairs= pairs;
+ context->initial_number= actual_loaded;
+ context->keys= keys;
+ context->key_lengths= key_lengths;
+
+ if (opt_test == SET_TEST)
+ {
+ context->execute_pairs= pairs_generate(opt_execute_number, VALUE_BYTES);
+ context->execute_number= opt_execute_number;
+ }
+
+ /* now you create the thread */
+ if (pthread_create(threads +x, NULL, run_task, (void *)context) != 0)
+ {
+ fprintf(stderr,"Could not create thread\n");
+ exit(1);
+ }
+ }
+
+ pthread_mutex_lock(&sleeper_mutex);
+ master_wakeup= 0;
+ pthread_mutex_unlock(&sleeper_mutex);
+ pthread_cond_broadcast(&sleep_threshhold);
+ gettimeofday(&start_time, NULL);
+
+ for (uint32_t x= 0; x < opt_concurrency; x++)
+ {
+ void *retval;
+ pthread_join(threads[x], &retval);
+ }
+ delete [] threads;
+
+ gettimeofday(&end_time, NULL);
+
+ conclusion->load_time= timedif(end_time, start_time);
+ conclusion->read_time= timedif(end_time, start_time);
+ free(keys);
+ free(key_lengths);
+ pairs_free(pairs);
+ memcached_free(memc);
+}
+
+void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(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},
+ };
+
+ bool opt_help= false;
+ bool opt_version= false;
+ int option_index= 0;
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+
+ if (option_rv == -1) break;
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_UDP:
+ if (opt_test == GET_TEST)
+ {
+ fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
+ "does not currently support get ops.\n");
+ exit(1);
+ }
+ opt_udp_io= true;
+ break;
+
+ case OPT_BINARY:
+ opt_binary= true;
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose= OPT_VERBOSE;
+ break;
+
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose= OPT_DEBUG;
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ opt_version= true;
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+
+ case OPT_SLAP_TEST:
+ if (strcmp(optarg, "get") == 0)
+ {
+ 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(EXIT_FAILURE);
+ }
+ opt_test= GET_TEST ;
+ }
+ else if (strcmp(optarg, "set") == 0)
+ {
+ opt_test= SET_TEST;
+ }
+ else if (strcmp(optarg, "mget") == 0)
+ {
+ opt_test= MGET_TEST;
+ }
+ else
+ {
+ fprintf(stderr, "Your test, %s, is not a known test\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_SLAP_CONCURRENCY:
+ errno= 0;
+ opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ fprintf(stderr, "Invalid value for concurrency: %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_SLAP_EXECUTE_NUMBER:
+ errno= 0;
+ opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ fprintf(stderr, "Invalid value for execute: %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_SLAP_INITIAL_LOAD:
+ errno= 0;
+ opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ fprintf(stderr, "Invalid value for initial load: %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(EXIT_FAILURE);
+
+ default:
+ abort();
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ exit(EXIT_SUCCESS);
+ }
+
+ if ((opt_test == GET_TEST or opt_test == MGET_TEST) and opt_createial_load == 0)
+ opt_createial_load= DEFAULT_INITIAL_LOAD;
+
+ if (opt_execute_number == 0)
+ opt_execute_number= DEFAULT_EXECUTE_NUMBER;
+
+ if (opt_concurrency == 0)
+ opt_concurrency= DEFAULT_CONCURRENCY;
+}
+
+void conclusions_print(conclusions_st *conclusion)
+{
+ printf("\tThreads connecting to servers %u\n", opt_concurrency);
+#ifdef NOT_FINISHED
+ printf("\tLoaded %u rows\n", conclusion->rows_loaded);
+ printf("\tRead %u rows\n", conclusion->rows_read);
+#endif
+ if (opt_test == SET_TEST)
+ printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000,
+ conclusion->load_time % 1000);
+ else
+ printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000,
+ conclusion->read_time % 1000);
+}
+
+void flush_all(memcached_st *memc)
+{
+ memcached_flush(memc, 0);
+}
+
+pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
+ unsigned int *actual_loaded)
+{
+ memcached_st *memc_clone= memcached_clone(NULL, memc);
+ /* We always used non-blocking IO for load since it is faster */
+ memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
+
+ pairs_st *pairs= pairs_generate(number_of, VALUE_BYTES);
+ *actual_loaded= execute_set(memc_clone, pairs, number_of);
+
+ memcached_free(memc_clone);
+
+ return pairs;
+}
--- /dev/null
+#!/bin/sh
+src/bin/memslap -v --servers localhost
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 <mem_config.h>
+
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+#include <iostream>
+#include <fcntl.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/types.h>
+
+#include <libmemcached-1.0/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+
+#define PROGRAM_NAME "memstat"
+#define PROGRAM_DESCRIPTION "Output the state of a memcached cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat);
+static void print_analysis_report(memcached_st *memc,
+ memcached_analysis_st *report);
+
+static bool opt_binary= false;
+static bool opt_verbose= false;
+static bool opt_server_version= false;
+static bool opt_analyze= false;
+static char *opt_servers= NULL;
+static char *stat_args= NULL;
+static char *analyze_mode= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+static struct option long_options[]=
+{
+ {(OPTIONSTRING)"args", required_argument, NULL, OPT_STAT_ARGS},
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(OPTIONSTRING)"verbose", no_argument, NULL, OPT_VERBOSE},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"debug", no_argument, NULL, OPT_DEBUG},
+ {(OPTIONSTRING)"server-version", no_argument, NULL, OPT_SERVER_VERSION},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0},
+};
+
+
+static memcached_return_t stat_printer(const memcached_instance_st * instance,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ void *context)
+{
+ static const memcached_instance_st * last= NULL;
+ (void)context;
+
+ if (last != instance)
+ {
+ printf("Server: %s (%u)\n", memcached_server_name(instance),
+ (uint32_t)memcached_server_port(instance));
+ last= instance;
+ }
+
+ printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value);
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t server_print_callback(const memcached_st *,
+ const memcached_instance_st * instance,
+ void *)
+{
+ std::cerr << memcached_server_name(instance) << ":" << memcached_server_port(instance) <<
+ " " << int(memcached_server_major_version(instance)) <<
+ "." << int(memcached_server_minor_version(instance)) <<
+ "." << int(memcached_server_micro_version(instance)) << std::endl;
+
+ return MEMCACHED_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ options_parse(argc, argv);
+ initialize_sockets();
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No Servers provided" << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ memcached_server_st* servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (opt_servers)
+ {
+ free(opt_servers);
+ }
+
+ memcached_st *memc= memcached_create(NULL);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, opt_binary);
+
+ memcached_return_t rc= memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+
+ if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ memcached_free(memc);
+ std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (opt_username)
+ {
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
+ {
+ std::cerr << memcached_last_error_message(memc) << std::endl;
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (rc != MEMCACHED_SUCCESS and rc != MEMCACHED_SOME_ERRORS)
+ {
+ printf("Failure to communicate with servers (%s)\n",
+ memcached_strerror(memc, rc));
+ exit(EXIT_FAILURE);
+ }
+
+ if (opt_server_version)
+ {
+ if (memcached_failed(memcached_version(memc)))
+ {
+ std::cerr << "Unable to obtain server version";
+ exit(EXIT_FAILURE);
+ }
+
+ memcached_server_fn callbacks[1];
+ callbacks[0]= server_print_callback;
+ memcached_server_cursor(memc, callbacks, NULL, 1);
+ }
+ else if (opt_analyze)
+ {
+ memcached_stat_st *memc_stat= memcached_stat(memc, NULL, &rc);
+
+ if (memc_stat == NULL)
+ {
+ exit(EXIT_FAILURE);
+ }
+
+ run_analyzer(memc, memc_stat);
+
+ memcached_stat_free(memc, memc_stat);
+ }
+ else
+ {
+ rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL);
+ }
+
+ memcached_free(memc);
+
+ return rc == MEMCACHED_SUCCESS ? EXIT_SUCCESS: EXIT_FAILURE;
+}
+
+static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat)
+{
+ memcached_return_t rc;
+
+ if (analyze_mode == NULL)
+ {
+ memcached_analysis_st *report;
+ report= memcached_analyze(memc, memc_stat, &rc);
+ if (rc != MEMCACHED_SUCCESS || report == NULL)
+ {
+ printf("Failure to analyze servers (%s)\n",
+ memcached_strerror(memc, rc));
+ exit(1);
+ }
+ print_analysis_report(memc, report);
+ free(report);
+ }
+ else if (strcmp(analyze_mode, "latency") == 0)
+ {
+ uint32_t flags, server_count= memcached_server_count(memc);
+ uint32_t num_of_tests= 32;
+ const char *test_key= "libmemcached_test_key";
+
+ memcached_st **servers= static_cast<memcached_st**>(malloc(sizeof(memcached_st*) * server_count));
+ if (servers == NULL)
+ {
+ fprintf(stderr, "Failed to allocate memory\n");
+ return;
+ }
+
+ for (uint32_t x= 0; x < server_count; x++)
+ {
+ const memcached_instance_st * instance=
+ memcached_server_instance_by_position(memc, x);
+
+ if ((servers[x]= memcached_create(NULL)) == NULL)
+ {
+ fprintf(stderr, "Failed to memcached_create()\n");
+ if (x > 0)
+ {
+ memcached_free(servers[0]);
+ }
+ x--;
+
+ for (; x > 0; x--)
+ {
+ memcached_free(servers[x]);
+ }
+
+ free(servers);
+
+ return;
+ }
+ memcached_server_add(servers[x],
+ memcached_server_name(instance),
+ memcached_server_port(instance));
+ }
+
+ printf("Network Latency Test:\n\n");
+ struct timeval start_time, end_time;
+ uint32_t slowest_server= 0;
+ long elapsed_time, slowest_time= 0;
+
+ for (uint32_t x= 0; x < server_count; x++)
+ {
+ const memcached_instance_st * instance=
+ memcached_server_instance_by_position(memc, x);
+ gettimeofday(&start_time, NULL);
+
+ for (uint32_t y= 0; y < num_of_tests; y++)
+ {
+ size_t vlen;
+ char *val= memcached_get(servers[x], test_key, strlen(test_key),
+ &vlen, &flags, &rc);
+ if (rc != MEMCACHED_NOTFOUND and rc != MEMCACHED_SUCCESS)
+ {
+ break;
+ }
+ free(val);
+ }
+ gettimeofday(&end_time, NULL);
+
+ elapsed_time= (long) timedif(end_time, start_time);
+ elapsed_time /= (long) num_of_tests;
+
+ if (elapsed_time > slowest_time)
+ {
+ slowest_server= x;
+ slowest_time= elapsed_time;
+ }
+
+ if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
+ {
+ printf("\t %s (%d) => failed to reach the server\n",
+ memcached_server_name(instance),
+ memcached_server_port(instance));
+ }
+ else
+ {
+ printf("\t %s (%d) => %ld.%ld seconds\n",
+ memcached_server_name(instance),
+ memcached_server_port(instance),
+ elapsed_time / 1000, elapsed_time % 1000);
+ }
+ }
+
+ if (server_count > 1 && slowest_time > 0)
+ {
+ const memcached_instance_st * slowest=
+ memcached_server_instance_by_position(memc, slowest_server);
+
+ printf("---\n");
+ printf("Slowest Server: %s (%d) => %ld.%ld seconds\n",
+ memcached_server_name(slowest),
+ memcached_server_port(slowest),
+ slowest_time / 1000, slowest_time % 1000);
+ }
+ printf("\n");
+
+ for (uint32_t x= 0; x < server_count; x++)
+ {
+ memcached_free(servers[x]);
+ }
+
+ free(servers);
+ free(analyze_mode);
+ }
+ else
+ {
+ fprintf(stderr, "Invalid Analyzer Option provided\n");
+ free(analyze_mode);
+ }
+}
+
+static void print_analysis_report(memcached_st *memc,
+ memcached_analysis_st *report)
+
+{
+ uint32_t server_count= memcached_server_count(memc);
+ const memcached_instance_st * most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server);
+ const memcached_instance_st * least_free_server= memcached_server_instance_by_position(memc, report->least_free_server);
+ const memcached_instance_st * oldest_server= memcached_server_instance_by_position(memc, report->oldest_server);
+
+ printf("Memcached Cluster Analysis Report\n\n");
+
+ printf("\tNumber of Servers Analyzed : %u\n", server_count);
+ printf("\tAverage Item Size (incl/overhead) : %u bytes\n",
+ report->average_item_size);
+
+ if (server_count == 1)
+ {
+ printf("\nFor a detailed report, you must supply multiple servers.\n");
+ return;
+ }
+
+ printf("\n");
+ printf("\tNode with most memory consumption : %s:%u (%llu bytes)\n",
+ memcached_server_name(most_consumed_server),
+ (uint32_t)memcached_server_port(most_consumed_server),
+ (unsigned long long)report->most_used_bytes);
+ printf("\tNode with least free space : %s:%u (%llu bytes remaining)\n",
+ memcached_server_name(least_free_server),
+ (uint32_t)memcached_server_port(least_free_server),
+ (unsigned long long)report->least_remaining_bytes);
+ printf("\tNode with longest uptime : %s:%u (%us)\n",
+ memcached_server_name(oldest_server),
+ (uint32_t)memcached_server_port(oldest_server),
+ report->longest_uptime);
+ printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio);
+ printf("\n");
+}
+
+static void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ int option_index= 0;
+
+ bool opt_version= false;
+ bool opt_help= false;
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index);
+
+ if (option_rv == -1)
+ break;
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose= true;
+ break;
+
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose= true;
+ break;
+
+ case OPT_BINARY:
+ opt_binary= true;
+ break;
+
+ case OPT_SERVER_VERSION:
+ opt_server_version= true;
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ opt_version= true;
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+
+ case OPT_STAT_ARGS:
+ stat_args= strdup(optarg);
+ break;
+
+ case OPT_ANALYZE: /* --analyze or -a */
+ opt_analyze= true;
+ analyze_mode= (optarg) ? strdup(optarg) : NULL;
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+ case OPT_USERNAME:
+ opt_username= optarg;
+ opt_binary= true;
+ break;
+
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ exit(EXIT_SUCCESS);
+ }
+}
--- /dev/null
+#!/bin/bash
+src/bin/memstat -v --servers localhost
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 <mem_config.h>
+
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <getopt.h>
+#include <iostream>
+#include <unistd.h>
+
+#include <libmemcached-1.0/memcached.h>
+
+#include "utilities.h"
+
+#define PROGRAM_NAME "memtouch"
+#define PROGRAM_DESCRIPTION "Update the expiration value of an already existing value in the server"
+
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+time_t expiration= 0;
+
+int main(int argc, char *argv[])
+{
+ int return_code= EXIT_SUCCESS;
+
+ options_parse(argc, argv);
+ initialize_sockets();
+
+ if (opt_servers == NULL)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+
+ if (opt_servers == NULL)
+ {
+ std::cerr << "No Servers provided" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcached_server_st* servers= memcached_servers_parse(opt_servers);
+ if (servers == NULL or memcached_server_list_count(servers) == 0)
+ {
+ std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ memcached_st *memc= memcached_create(NULL);
+ process_hash_option(memc, opt_hash);
+
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t)opt_binary);
+
+ if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ memcached_free(memc);
+ std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (opt_username)
+ {
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
+ {
+ std::cerr << memcached_last_error_message(memc) << std::endl;
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+ }
+
+ while (optind < argc)
+ {
+ memcached_return_t rc= memcached_touch(memc, argv[optind], strlen(argv[optind]), expiration);
+ if (rc == MEMCACHED_NOTFOUND)
+ {
+ if (opt_verbose)
+ {
+ std::cout << "Could not find key \"" << argv[optind] << "\"" << std::endl;
+ }
+
+ return_code= EXIT_FAILURE;
+ }
+ else if (memcached_failed(rc))
+ {
+ if (opt_verbose)
+ {
+ std::cerr << "Fatal error for key \"" << argv[optind] << "\" :" << memcached_last_error_message(memc) << std::endl;
+ }
+
+ return_code= EXIT_FAILURE;
+ }
+ else // success
+ {
+ if (opt_verbose)
+ {
+ std::cout << "Found key " << argv[optind] << std::endl;
+ }
+ }
+
+ optind++;
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ {
+ free(opt_servers);
+ }
+
+ if (opt_hash)
+ {
+ free(opt_hash);
+ }
+
+ return return_code;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+ {0, 0, 0, 0},
+ };
+
+ bool opt_version= false;
+ bool opt_help= false;
+ int option_index= 0;
+
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1)
+ {
+ break;
+ }
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+
+ case OPT_BINARY:
+ opt_binary = true;
+ break;
+
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+
+ case OPT_VERSION: /* --version or -V */
+ opt_version= true;
+ break;
+
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+
+ case OPT_EXPIRE:
+ errno= 0;
+ expiration= time_t(strtoul(optarg, (char **)NULL, 10));
+ if (errno != 0)
+ {
+ fprintf(stderr, "Invalid value for --expire: %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_QUIET:
+ close_stdio();
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(EXIT_FAILURE);
+
+ default:
+ abort();
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(PROGRAM_NAME);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ exit(EXIT_SUCCESS);
+ }
+}
--- /dev/null
+#!/bin/sh
+src/bin/memcp.sh
+src/bin/memtouch -v --servers localhost mem.testdata
--- /dev/null
+/* 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 HAVE_C_STDATOMIC
+# define ATOMIC _Atomic
+#else
+# define ATOMIC volatile
+#endif
+
+#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
+#elif HAVE_GCC_ATOMIC_BUILTINS
+# 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)
+#elif HAVE_C_STDATOMIC
+# include <stdatomic.h>
+# define atomic_add_8(X, Y) atomic_fetch_add(X, Y)
+# define atomic_add_16(X, Y) atomic_fetch_add(X, Y)
+# define atomic_add_32(X, Y) atomic_fetch_add(X, Y)
+# define atomic_add_size(X, Y) atomic_fetch_add(X, Y)
+# define atomic_dec_8(X) atomic_fetch_sub(X, 1)
+# define atomic_dec_16(X) atomic_fetch_sub(X, 1)
+# define atomic_dec_32(X) atomic_fetch_sub(X, 1)
+# define atomic_dec_size(X) atomic_fetch_sub(X, 1)
+/* The same as above, but these return the new value instead of void */
+# define ATOMIC_ADD_FETCH_DECL(T) \
+static inline T atomic_add_fetch_##T(ATOMIC T *ptr, T add) { \
+ T des, cur = atomic_load(ptr); \
+ do { \
+ des = cur + add; \
+ } while(!atomic_compare_exchange_weak(ptr, &cur, des)); \
+ return des; \
+}
+# define ATOMIC_SUB_FETCH_DECL(T) \
+T atomic_sub_fetch_##T(ATOMIC T *ptr) { \
+ T des, cur = atomic_load(ptr); \
+ do { \
+ des = cur - 1; \
+ } while(!atomic_compare_exchange_weak(ptr, &cur, des)); \
+ return des; \
+}
+ATOMIC_ADD_FETCH_DECL(uint8_t)
+# define atomic_add_8_nv(X, Y) atomic_add_fetch_uint8_t(X, Y)
+ATOMIC_ADD_FETCH_DECL(uint16_t)
+# define atomic_add_16_nv(X, Y) atomic_add_fetch_uint16_t(X, Y)
+ATOMIC_ADD_FETCH_DECL(uint32_t)
+# define atomic_add_32_nv(X, Y) atomic_add_fetch_uint32_t(X, Y)
+ATOMIC_ADD_FETCH_DECL(size_t)
+# define atomic_add_size_nv(X, Y) atomic_add_fetch_size_t(X, Y)
+# define atomic_dec_8_nv(X) atomic_sub_fetch<uint8_t>(X, Y)
+# define atomic_dec_16_nv(X) atomic_sub_fetch<uint16_t>(X, Y)
+# define atomic_dec_32_nv(X) atomic_sub_fetch<uint32_t>(X, Y)
+# define atomic_dec_size_nv(X) atomic_sub_fetch<size_t>(X, Y)
+#else
+#warning "Atomic operators not found so memslap will not work correctly"
+# define atomic_add_8(X, Y) 0
+# define atomic_add_16(X, Y) 0
+# define atomic_add_32(X, Y) 0
+# define atomic_add_size(X, Y) 0
+# define atomic_dec_8(X) 0
+# define atomic_dec_16(X) 0
+# define atomic_dec_32(X) 0
+# define atomic_dec_size(X) 0
+/* The same as above, but these return the new value instead of void */
+# define atomic_add_8_nv(X, Y) 0
+# define atomic_add_16_nv(X, Y) 0
+# define atomic_add_32_nv(X, Y) 0
+# define atomic_add_size_nv(X, Y) 0
+# define atomic_dec_8_nv(X) 0
+# define atomic_dec_16_nv(X) 0
+# define atomic_dec_32_nv(X) 0
+# define atomic_dec_size_nv(X) 0
+#endif /* defined(__SUNPRO_C) */
+
+#endif /* CLIENTS_MS_ATOMIC_H */
--- /dev/null
+/*
+ * File: ms_conn.c
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "mem_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 <netinet/in.h>
+
+#if defined(HAVE_ARPA_INET_H)
+# include <arpa/inet.h>
+#endif
+
+#if defined(HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#endif
+
+#if defined(HAVE_TIME_H)
+# include <time.h>
+#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 ATOMIC 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 uint32_t ms_get_rep_sock_index(ms_conn_t *c, int cmd);
+static uint32_t 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 * ms_setting.sock_per_conn;
+ }
+ 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
+ {
+ 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, else return -1
+ */
+static int ms_conn_sock_init(ms_conn_t *c)
+{
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+ uint32_t i;
+ int ret_sfd;
+ uint32_t 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 % ms_setting.srv_cnt;
+ }
+ 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 (uint32_t j= 0; j < i; j++)
+ {
+ close(c->tcpsfd[j]);
+ }
+ }
+
+ if (c->udpsfd != 0)
+ {
+ close(c->udpsfd);
+ }
+
+ return -1;
+ }
+
+ return EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, else return -1
+ */
+static int ms_conn_event_init(ms_conn_t *c)
+{
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+ 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 (event_add(&c->event, NULL) == -1)
+ {
+ return -1;
+ }
+
+ return EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 (uint32_t 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 EXIT_SUCCESS, 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;
+ }
+ }
+ (void)last_good;
+} /* 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 EXIT_SUCCESS, 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));
+#ifdef AI_ADDRCONFIG
+ hints.ai_flags= AI_PASSIVE | AI_ADDRCONFIG;
+#else
+ hints.ai_flags= AI_PASSIVE;
+#endif /* 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 EXIT_SUCCESS, else return -1
+ */
+static int ms_reconn(ms_conn_t *c)
+{
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+ uint32_t srv_idx= 0;
+ uint32_t srv_conn_cnt= 0;
+
+ if (ms_setting.rep_write_srv > 0)
+ {
+ srv_idx= c->cur_idx % ms_setting.srv_cnt;
+ srv_conn_cnt= ms_setting.sock_per_conn * ms_setting.nconns;
+ }
+ else
+ {
+ srv_idx= ms_thread->thread_ctx->srv_idx;
+ srv_conn_cnt= 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)
+ % 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)
+ {
+ uint32_t 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 (ms_setting.rep_write_srv == 0 && c->total_sfds > 0)
+ {
+ /* wait a second and reconnect */
+ sleep(1);
+ }
+ }
+ while (ms_setting.rep_write_srv == 0 && c->total_sfds > 0);
+ }
+
+ if ((c->total_sfds > 1) && (c->tcpsfd[c->cur_idx] == 0))
+ {
+ c->sfd= 0;
+ c->alive_sfds--;
+ }
+
+ return EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, else return -1
+ */
+int ms_reconn_socks(ms_conn_t *c)
+{
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+ uint32_t srv_idx= 0;
+ int ret_sfd= 0;
+ uint32_t srv_conn_cnt= 0;
+ struct timeval cur_time;
+
+ assert(c != NULL);
+
+ if ((c->total_sfds == 1) || (c->total_sfds == c->alive_sfds))
+ {
+ return EXIT_SUCCESS;
+ }
+
+ for (uint32_t 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 % ms_setting.srv_cnt;
+ srv_conn_cnt= ms_setting.sock_per_conn * ms_setting.nconns;
+ }
+ else
+ {
+ srv_idx= ms_thread->thread_ctx->srv_idx;
+ srv_conn_cnt= 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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);
+ errno= 0;
+ value_len= strtol(tokens[VALUELEN_TOKEN].value, NULL, 10);
+ if (errno != 0)
+ {
+ printf("<%d ERROR %s\n", c->sfd, strerror(errno));
+ }
+ 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;
+ break;
+
+ 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;
+ c->msgcurr = 0;
+ c->msgused = 0;
+ c->iovused = 0;
+ 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+ }
+ 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 EXIT_SUCCESS;
+ }
+
+ /* 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 EXIT_SUCCESS;
+
+ el= memchr(c->rcurr, '\n', (size_t)c->rbytes);
+ if (! el)
+ return EXIT_SUCCESS;
+
+ 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;
+ }
+ }
+ (void)packets;
+
+ 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 EXIT_SUCCESS 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 EXIT_SUCCESS if there's nothing to read on the first read.
+ * return EXIT_FAILURE 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_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_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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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;
+
+#ifdef IOV_MAX
+ /* 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];
+ }
+#endif
+
+ 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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)
+{
+ 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 (event_add(&c->event, NULL) == -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);
+
+ 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 EXIT_SUCCESS
+ */
+static uint32_t ms_get_rep_sock_index(ms_conn_t *c, int cmd)
+{
+ uint32_t sock_index= 0;
+ uint32_t i= 0;
+
+ if (c->total_sfds == 1)
+ {
+ return EXIT_SUCCESS;
+ }
+
+ 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= (uint32_t)random() % c->total_sfds;
+ }
+ else
+ {
+ /* random get one replication writing server to write */
+ sock_index= (uint32_t)random() % ms_setting.rep_write_srv;
+ }
+ }
+ else if (cmd == CMD_GET)
+ {
+ /* random get one replication server to read */
+ sock_index= (uint32_t)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 uint32_t ms_get_next_sock_index(ms_conn_t *c)
+{
+ uint32_t 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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= snprintf(buffer,
+ c->wsize,
+ " %u %d %d\r\n",
+ 0,
+ item->exp_time,
+ item->value_size);
+
+ if (write_len > c->wsize || write_len < 0)
+ {
+ /* 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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
+ *
+ * @return int, if success, return EXIT_SUCCESS, else return -1
+ */
+int ms_mcd_get(ms_conn_t *c, ms_task_item_t *item)
+{
+ 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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);
+ }
+
+ (void)item;
+
+ return EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_FAILURE;
+ }
+ 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 EXIT_SUCCESS;
+} /* 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.vbucket= 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* ms_build_bin_write_buf_mlget */
--- /dev/null
+/*
+ * 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 <libmemcachedprotocol-0.0/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 30 /* maximum waiting time of UDP, 30s */
+#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 */
+ 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
+{
+ uint32_t 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 */
+ uint32_t total_sfds; /* how many socks in the tcpsfd array */
+ uint32_t alive_sfds; /* alive socks */
+ uint32_t 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 */
+ bool 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);
+
+
+/* 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 */
--- /dev/null
+/*
+ * 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"
+#include "ms_atomic.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
+{
+ ATOMIC uint32_t active_conns; /* active connections */
+ ATOMIC size_t bytes_read; /* read bytes */
+ ATOMIC size_t bytes_written; /* written bytes */
+ ATOMIC size_t obj_bytes; /* object bytes */
+ ATOMIC size_t pre_cmd_get; /* previous total get command count */
+ ATOMIC size_t pre_cmd_set; /* previous total set command count */
+ ATOMIC size_t cmd_get; /* current total get command count */
+ ATOMIC size_t cmd_set; /* current total set command count */
+ ATOMIC size_t get_misses; /* total objects of get miss */
+ ATOMIC size_t vef_miss; /* total objects of verification miss */
+ ATOMIC size_t vef_failed; /* total objects of verification failed */
+ ATOMIC size_t unexp_unget; /* total objects which is unexpired but not get */
+ ATOMIC size_t exp_get; /* total objects which is expired but get */
+ ATOMIC size_t pkt_disorder; /* disorder packages of UDP */
+ ATOMIC size_t pkt_drop; /* packages dropped of UDP */
+ ATOMIC size_t udp_timeout; /* how many times timeout of UDP happens */
+} ms_stats_t;
+
+/* lock adapter */
+typedef struct sync_lock
+{
+ uint32_t 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 warmup_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 */
--- /dev/null
+/*
+ * File: ms_setting.c
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "mem_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 <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 uint32_t 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 EXIT_FAILURE
+ */
+static uint32_t 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 EXIT_FAILURE;
+} /* 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 EXIT_FAILURE, else return EXIT_SUCCESS
+ */
+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 EXIT_SUCCESS;
+
+ return EXIT_FAILURE;
+} /* 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 EXIT_SUCCESS, else return EXIT_FAILURE
+ */
+static int ms_read_is_data(char *line, ssize_t nread)
+{
+ if ((nread == EOF) || ! ms_is_line_data(line))
+ return EXIT_SUCCESS;
+
+ return EXIT_FAILURE;
+} /* 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;
+ 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", &start_len, &end_len,
+ &proportion) != 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", &cmd_type, &proportion) != 2)
+ {
+ conf_type= ms_get_conf_type(line);
+ break;
+ }
+ if (cmd_type >= CMD_NULL)
+ {
+ continue;
+ }
+ 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 EXIT_SUCCESS
+ */
+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 EXIT_SUCCESS;
+} /* 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.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.facebook_test && (ms_setting.rep_write_srv > 0))
+ {
+ fprintf(stderr, "facebook test couldn't work with replication.\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 */
--- /dev/null
+/*
+ * 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_server
+{
+ char srv_host_name[MCD_HOST_LENGTH]; /* host name of server */
+ int srv_port; /* server port */
+
+ /* for calculating how long the server disconnects */
+ ATOMIC uint32_t disconn_cnt; /* number of disconnections count */
+ ATOMIC 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
+{
+ uint32_t ncpu; /* cpu count of this system */
+ uint32_t 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 */
+ uint32_t total_srv_cnt; /* total servers count of the servers array */
+ uint32_t 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 */
+ uint32_t sock_per_conn; /* number of socks per connection structure */
+ bool binary_prot_; /* whether it use binary protocol */
+ int expected_tps; /* expected throughput */
+ uint32_t 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 */
--- /dev/null
+/*
+ * 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 "mem_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");
+#if 0
+ pandora_print_callstack(stderr);
+#endif
+ fprintf(stderr, "End of stack trace\n");
+ pthread_mutex_unlock(&ms_global.quit_mutex);
+ abort();
+}
+
+/* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+ }
+
+ return -1;
+} /* ms_setup_sigsegv */
+
+
+/**
+ * redirect signal pipe
+ *
+ * @return if success, return EXIT_SUCCESS, else return -1
+ */
+int ms_setup_sigpipe(void)
+{
+ /* ignore the SIGPIPE signal */
+ signal(SIGPIPE, SIG_IGN);
+
+ return -1;
+} /* ms_setup_sigpipe */
+
+
+/**
+ * redirect signal int
+ *
+ * @return if success, return EXIT_SUCCESS, 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 EXIT_SUCCESS;
+ }
+
+ 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * File: ms_stats.h
+ * Author: Mingqiang Zhuang
+ *
+ * Created on March 25, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "mem_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;
+
+ 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);
+
+ uint64_t diff_time= stat->total_time - stat->pre_total_time;
+ uint64_t 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;
+ double 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));
+ double 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * File: ms_task.c
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "mem_config.h"
+
+#if defined(HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#endif
+
+#if defined(HAVE_TIME_H)
+# include <time.h>
+#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_random_overwrite_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_overwrite_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_random_overwrite_item(ms_conn_t *c)
+{
+ return ms_get_next_get_item(c);
+} /* ms_get_random_overwrite_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_overwrite_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_overwrite_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_overwrite_item(task))
+ {
+ /**
+ * overwrite not use the item with current set cursor, revert
+ * set cursor.
+ */
+ c->set_cursor--;
+
+ item= ms_get_random_overwrite_item(c);
+ if (item->value_offset != INVALID_OFFSET)
+ {
+ task->item= item;
+ task->overwrite_set++;
+ }
+ else /* item is a new item */
+ {
+ /* select the 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.warmup_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);
+ }
+ }
+} /* 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 EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* ms_run_getset_task */
+
+
+/**
+ * the state machine call the function to execute task.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return EXIT_SUCCESS, 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 EXIT_SUCCESS;
+} /* ms_exec_task */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * File: ms_thread.c
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "mem_config.h"
+
+#if defined(HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#endif
+
+#if defined(HAVE_TIME_H)
+# include <time.h>
+#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 uint32_t ms_set_thread_cpu_affinity(uint32_t 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 (uint32_t 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 (uint32_t 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 EXIT_SUCCESS, else return -1
+ */
+static uint32_t ms_set_thread_cpu_affinity(uint32_t cpu)
+{
+ uint32_t 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 EXIT_SUCCESS, 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 ATOMIC 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 (uint32_t 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 EXIT_SUCCESS;
+} /* 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= NULL;
+ 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);
+
+ pthread_mutex_lock(&ms_global.init_lock.lock);
+ ms_global.init_lock.count++;
+ pthread_cond_signal(&ms_global.init_lock.cond);
+ pthread_mutex_unlock(&ms_global.init_lock.lock);
+
+ ms_thread= pthread_getspecific(ms_thread_key);
+ 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 (uint32_t i= 0; i < ms_setting.nthreads; i++)
+ {
+ ms_thread_ctx[i].thd_idx= i;
+ ms_thread_ctx[i].nconns= 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 (uint32_t 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 */
--- /dev/null
+/*
+ * 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
+{
+ uint32_t thd_idx; /* the thread index */
+ uint32_t nconns; /* how many connections included by the thread */
+ uint32_t 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 */
+ uint32_t 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 */
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * 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 <mem_config.h>
+
+#include "utilities.h"
+
+#include <cstdio>
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+long int timedif(struct timeval a, struct timeval b)
+{
+ long us, s;
+
+ us = (int)(a.tv_usec - b.tv_usec);
+ us /= 1000;
+ s = (int)(a.tv_sec - b.tv_sec);
+ s *= 1000;
+ return s + us;
+}
+
+void version_command(const char *command_name)
+{
+ printf("%s v%u.%u\n", command_name, 1U, 0U);
+ exit(EXIT_SUCCESS);
+}
+
+void close_stdio(void)
+{
+ int fd;
+ if ((fd = open("/dev/null", O_RDWR, 0)) < 0)
+ {
+ return;
+ }
+ else
+ {
+ if (dup2(fd, STDIN_FILENO) < 0)
+ {
+ return;
+ }
+
+ if (dup2(fd, STDOUT_FILENO) < 0)
+ {
+ return;
+ }
+
+ if (dup2(fd, STDERR_FILENO) < 0)
+ {
+ return;
+ }
+
+ if (fd > STDERR_FILENO)
+ {
+ close(fd);
+ }
+ }
+}
+
+
+static const char *lookup_help(memcached_options option)
+{
+ switch (option)
+ {
+ case OPT_SERVERS: return("List which servers you wish to connect to.");
+ case OPT_VERSION: return("Display the version of the application and then exit.");
+ case OPT_HELP: return("Display this message and then exit.");
+ case OPT_VERBOSE: return("Give more details on the progression of the application.");
+ case OPT_QUIET: return("stderr and stdin will be closed at application startup.");
+ case OPT_DEBUG: return("Provide output only useful for debugging.");
+ case OPT_FLAG: return("Provide flag information for storage operation.");
+ case OPT_EXPIRE: return("Set the expire option for the object.");
+ case OPT_SET: return("Use set command with memcached when storing.");
+ case OPT_REPLACE: return("Use replace command with memcached when storing.");
+ case OPT_ADD: return("Use add command with memcached when storing.");
+ case OPT_SLAP_EXECUTE_NUMBER: return("Number of times to execute the given test.");
+ case OPT_SLAP_INITIAL_LOAD: return("Number of key pairs to load before executing tests.");
+ case OPT_SLAP_TEST: return("Test to run (currently \"get\" or \"set\").");
+ case OPT_SLAP_CONCURRENCY: return("Number of users to simulate with load.");
+ case OPT_SLAP_NON_BLOCK: return("Set TCP up to use non-blocking IO.");
+ case OPT_SLAP_TCP_NODELAY: return("Set TCP socket up to use nodelay.");
+ case OPT_FLUSH: return("Flush servers before running tests.");
+ case OPT_HASH: return("Select hash type.");
+ case OPT_BINARY: return("Switch to binary protocol.");
+ case OPT_ANALYZE: return("Analyze the provided servers.");
+ case OPT_UDP: return("Use UDP protocol when communicating with server.");
+ case OPT_BUFFER: return("Enable request buffering.");
+ case OPT_USERNAME: return "Username to use for SASL authentication";
+ case OPT_PASSWD: return "Password to use for SASL authentication";
+ case OPT_FILE: return "Path to file in which to save result";
+ case OPT_STAT_ARGS: return "Argument for statistics";
+ case OPT_SERVER_VERSION: return "Memcached daemon software version";
+ default:
+ break;
+ };
+
+ assert(0);
+ return "forgot to document this function :)";
+}
+
+void help_command(const char *command_name, const char *description,
+ const struct option *long_options,
+ memcached_programs_help_st *options)
+{
+ unsigned int x;
+ (void)options;
+
+ printf("%s v%u.%u\n\n", command_name, 1U, 0U);
+ printf("\t%s\n\n", description);
+ printf("Current options. A '=' means the option takes a value.\n\n");
+
+ for (x= 0; long_options[x].name; x++)
+ {
+ const char *help_message;
+
+ printf("\t --%s%c\n", long_options[x].name,
+ long_options[x].has_arg ? '=' : ' ');
+ if ((help_message= lookup_help(memcached_options(long_options[x].val))))
+ printf("\t\t%s\n", help_message);
+ }
+
+ printf("\n");
+ exit(EXIT_SUCCESS);
+}
+
+void process_hash_option(memcached_st *memc, char *opt_hash)
+{
+ uint64_t set;
+ memcached_return_t rc;
+
+ if (opt_hash == NULL)
+ {
+ return;
+ }
+
+ set= MEMCACHED_HASH_DEFAULT; /* Just here to solve warning */
+ if (!strcasecmp(opt_hash, "CRC"))
+ {
+ set= MEMCACHED_HASH_CRC;
+ }
+ else if (!strcasecmp(opt_hash, "FNV1_64"))
+ {
+ set= MEMCACHED_HASH_FNV1_64;
+ }
+ else if (!strcasecmp(opt_hash, "FNV1A_64"))
+ {
+ set= MEMCACHED_HASH_FNV1A_64;
+ }
+ else if (!strcasecmp(opt_hash, "FNV1_32"))
+ {
+ set= MEMCACHED_HASH_FNV1_32;
+ }
+ else if (!strcasecmp(opt_hash, "FNV1A_32"))
+ {
+ set= MEMCACHED_HASH_FNV1A_32;
+ }
+ else
+ {
+ fprintf(stderr, "hash: type not recognized %s\n", opt_hash);
+ exit(EXIT_FAILURE);
+ }
+
+ rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ fprintf(stderr, "hash: memcache error %s\n", memcached_strerror(memc, rc));
+ exit(EXIT_FAILURE);
+ }
+}
+
+void initialize_sockets(void)
+{
+ /* Define the function for all platforms to avoid #ifdefs in each program */
+#if defined(_WIN32)
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0)
+ {
+ fprintf(stderr, "Socket Initialization Error. Program aborted\n");
+ exit(EXIT_FAILURE);
+ }
+#endif // #if defined(_WIN32)
+}
--- /dev/null
+/* 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:
+ *
+ */
+
+#pragma once
+
+#include <getopt.h>
+#include <libmemcached-1.0/memcached.h>
+#include "client_options.h"
+
+#if defined(HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#endif
+
+#if defined(HAVE_TIME_H)
+# include <time.h>
+#endif
+
+
+#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
+
+typedef struct memcached_programs_help_st memcached_programs_help_st;
+
+struct memcached_programs_help_st
+{
+ char *not_used_yet;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char *strdup_cleanup(const char *str);
+void cleanup(void);
+long int timedif(struct timeval a, struct timeval b);
+void version_command(const char *command_name) __attribute__ ((noreturn));
+void help_command(const char *command_name, const char *description,
+ const struct option *long_options,
+ memcached_programs_help_st *options) __attribute__ ((noreturn));
+void process_hash_option(memcached_st *memc, char *opt_hash);
+bool initialize_sasl(memcached_st *memc, char *user, char *password);
+void shutdown_sasl(void);
+void initialize_sockets(void);
+void close_stdio(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+if(HAVE_HSIEH_HASH)
+ set(HSIEH_CC hsieh.cc)
+else()
+ set(HSIEH_CC nohsieh.cc)
+endif()
+
+add_library(libhashkit SHARED
+ aes.cc
+ algorithm.cc
+ behavior.cc
+ crc32.cc
+ digest.cc
+ encrypt.cc
+ fnv_32.cc
+ fnv_64.cc
+ function.cc
+ has.cc
+ hashkit.cc
+ ${HSIEH_CC}
+ jenkins.cc
+ ketama.cc
+ md5.cc
+ murmur.cc
+ murmur3.cc
+ murmur3_api.cc
+ nohsieh.cc
+ one_at_a_time.cc
+ rijndael.cc
+ str_algorithm.cc
+ strerror.cc
+ string.cc
+ )
+add_library(hashkit ALIAS libhashkit)
+set_target_properties(libhashkit PROPERTIES LIBRARY_OUTPUT_NAME hashkit)
+target_compile_options(libhashkit PRIVATE -DBUILDING_HASHKIT)
+
+configure_file(hashkitcon.h.in hashkitcon.h @ONLY)
+
+set_target_properties(libhashkit PROPERTIES SOVERSION ${LIBHASHKIT_SO_VERSION})
+install(TARGETS libhashkit EXPORT libhashkit
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+export(EXPORT libhashkit)
+install(EXPORT libhashkit DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake)
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ FILES_MATCHING PATTERN hashkit.h
+ )
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libhashkit library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include "libhashkit/common.h"
+
+#include "libhashkit/rijndael.hpp"
+
+#include <cstring>
+
+#define AES_KEY_LENGTH 256 /* 128, 192, 256 */
+#define AES_BLOCK_SIZE 16
+
+enum encrypt_t
+{
+ AES_ENCRYPT,
+ AES_DECRYPT
+};
+
+struct _key_t {
+ int nr;
+ uint32_t rk[4*(AES_MAXNR +1)];
+};
+
+struct aes_key_t {
+ _key_t encode_key;
+ _key_t decode_key;
+};
+
+aes_key_t* aes_create_key(const char *key, const size_t key_length)
+{
+ aes_key_t* _aes_key= (aes_key_t*)(calloc(1, sizeof(aes_key_t)));
+ if (_aes_key)
+ {
+ uint8_t rkey[AES_KEY_LENGTH/8];
+ uint8_t *rkey_end= rkey +AES_KEY_LENGTH/8;
+ const char *key_end= key +key_length;
+
+ memset(rkey, 0, sizeof(rkey)); /* Set initial key */
+
+ uint8_t *ptr= rkey;
+ const char* sptr= key;
+ for (; sptr < key_end; ptr++,sptr++)
+ {
+ if (ptr == rkey_end)
+ {
+ ptr= rkey; /* Just loop over tmp_key until we used all key */
+ }
+ *ptr^= (uint8_t)(*sptr);
+ }
+
+ _aes_key->decode_key.nr= rijndaelKeySetupDec(_aes_key->decode_key.rk, rkey, AES_KEY_LENGTH);
+ _aes_key->encode_key.nr= rijndaelKeySetupEnc(_aes_key->encode_key.rk, rkey, AES_KEY_LENGTH);
+ }
+
+ return _aes_key;
+}
+
+aes_key_t* aes_clone_key(aes_key_t *_aes_key)
+{
+ if (_aes_key == NULL)
+ {
+ return NULL;
+ }
+
+ aes_key_t* _aes_clone_key= (aes_key_t*)(calloc(1, sizeof(aes_key_t)));
+ if (_aes_clone_key)
+ {
+ memcpy(_aes_clone_key, _aes_key, sizeof(aes_key_t));
+ }
+
+ return _aes_clone_key;
+}
+
+hashkit_string_st* aes_encrypt(aes_key_t *_aes_key,
+ const char* source, size_t source_length)
+{
+ if (_aes_key == NULL)
+ {
+ return NULL;
+ }
+
+ size_t num_blocks= source_length/AES_BLOCK_SIZE;
+
+ hashkit_string_st* destination= hashkit_string_create(source_length);
+ if (destination)
+ {
+ char *dest= hashkit_string_c_str_mutable(destination);
+
+ for (size_t x= num_blocks; x > 0; x--) /* Encode complete blocks */
+ {
+ rijndaelEncrypt(_aes_key->encode_key.rk, _aes_key->encode_key.nr, (const uint8_t*)(source),
+ (uint8_t*) (dest));
+ source+= AES_BLOCK_SIZE;
+ dest+= AES_BLOCK_SIZE;
+ }
+
+ uint8_t block[AES_BLOCK_SIZE];
+ char pad_len= AES_BLOCK_SIZE - (source_length - AES_BLOCK_SIZE*num_blocks);
+ memcpy(block, source, 16 -pad_len);
+ memset(block + AES_BLOCK_SIZE -pad_len, pad_len, pad_len);
+ rijndaelEncrypt(_aes_key->encode_key.rk, _aes_key->encode_key.nr, block, (uint8_t*) (dest));
+ hashkit_string_set_length(destination, AES_BLOCK_SIZE*(num_blocks + 1));
+ }
+
+ return destination;
+}
+
+hashkit_string_st* aes_decrypt(aes_key_t *_aes_key,
+ const char* source, size_t source_length)
+{
+ if (_aes_key == NULL)
+ {
+ return NULL;
+ }
+
+ size_t num_blocks= source_length/AES_BLOCK_SIZE;
+ if ((source_length != num_blocks*AES_BLOCK_SIZE) or num_blocks ==0 )
+ {
+ return NULL;
+ }
+
+ hashkit_string_st* destination= hashkit_string_create(source_length);
+ if (destination)
+ {
+ char *dest= hashkit_string_c_str_mutable(destination);
+
+ for (size_t x = num_blocks-1; x > 0; x--)
+ {
+ rijndaelDecrypt(_aes_key->decode_key.rk, _aes_key->decode_key.nr, (const uint8_t*) (source), (uint8_t*)(dest));
+ source+= AES_BLOCK_SIZE;
+ dest+= AES_BLOCK_SIZE;
+ }
+
+ uint8_t block[AES_BLOCK_SIZE];
+ rijndaelDecrypt(_aes_key->decode_key.rk, _aes_key->decode_key.nr, (const uint8_t*)(source), block);
+ /* Use last char in the block as size */
+ unsigned int pad_len= (unsigned int) (unsigned char)(block[AES_BLOCK_SIZE-1]);
+ if (pad_len > AES_BLOCK_SIZE)
+ {
+ hashkit_string_free(destination);
+ return NULL;
+ }
+
+ /* We could also check whole padding but we do not really need this */
+
+ memcpy(dest, block, AES_BLOCK_SIZE - pad_len);
+ hashkit_string_set_length(destination, AES_BLOCK_SIZE*num_blocks - pad_len);
+ }
+
+ return destination;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+struct aes_key_t;
+
+hashkit_string_st* aes_encrypt(aes_key_t* _aes_key,
+ const char* source, size_t source_length);
+
+hashkit_string_st* aes_decrypt(aes_key_t* _aes_key,
+ const char* source, size_t source_length);
+
+aes_key_t* aes_create_key(const char *key, const size_t key_length);
+
+aes_key_t* aes_clone_key(aes_key_t* _aes_key);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2006-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libhashkit/common.h"
+
+uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length)
+{
+ return hashkit_one_at_a_time(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1_64(const char *key, size_t key_length)
+{
+ return hashkit_fnv1_64(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length)
+{
+ return hashkit_fnv1a_64(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1_32(const char *key, size_t key_length)
+{
+ return hashkit_fnv1_32(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length)
+{
+ return hashkit_fnv1a_32(key, key_length, NULL);
+}
+
+uint32_t libhashkit_crc32(const char *key, size_t key_length)
+{
+ return hashkit_crc32(key, key_length, NULL);
+}
+
+uint32_t libhashkit_hsieh(const char *key, size_t key_length)
+{
+ return hashkit_hsieh(key, key_length, NULL);
+}
+
+uint32_t libhashkit_murmur3(const char *key, size_t key_length)
+{
+ return hashkit_murmur3(key, key_length, NULL);
+}
+
+uint32_t libhashkit_murmur(const char *key, size_t key_length)
+{
+ return hashkit_murmur(key, key_length, NULL);
+}
+
+uint32_t libhashkit_jenkins(const char *key, size_t key_length)
+{
+ return hashkit_jenkins(key, key_length, NULL);
+}
+
+uint32_t libhashkit_md5(const char *key, size_t key_length)
+{
+ return hashkit_md5(key, key_length, NULL);
+}
+
+void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result)
+{
+ md5_signature(key, (uint32_t)length, result);
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/**
+ * @file
+ * @brief HashKit Header
+ */
+
+#pragma once
+
+uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_crc32(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_hsieh(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_murmur(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_murmur3(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_jenkins(const char *key, size_t key_length, void *context);
+
+uint32_t hashkit_md5(const char *key, size_t key_length, void *context);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2009-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libhashkit/common.h>
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#include "libhashkit/hashkitcon.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifndef __WORDSIZE
+# ifdef __MINGW32__
+# define __WORDSIZE 32
+# endif
+#endif
+
+#include <libhashkit-1.0/hashkit.h>
+#include "libhashkit/algorithm.h"
+#include "libhashkit/is.h"
+#include "libhashkit/string.h"
+#include "libhashkit/aes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result);
+
+int update_continuum(hashkit_st *hashkit);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2009-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* The crc32 functions and data was originally written by Spencer
+ * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source
+ * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at
+ * src/usr.bin/cksum/crc32.c.
+ */
+
+#include <libhashkit/common.h>
+
+static const uint32_t crc32tab[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+uint32_t hashkit_crc32(const char *key, size_t key_length, void *context)
+{
+ uint64_t x;
+ uint32_t crc= UINT32_MAX;
+ (void)context;
+
+ for (x= 0; x < key_length; x++)
+ crc= (crc >> 8) ^ crc32tab[(crc ^ (uint64_t)key[x]) & 0xff];
+
+ return ((~crc) >> 16) & 0x7fff;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2010-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libhashkit/common.h>
+
+uint32_t hashkit_digest(const hashkit_st *self, const char *key, size_t key_length)
+{
+ return self->base_hash.function(key, key_length, self->base_hash.context);
+}
+
+uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm)
+{
+ switch (hash_algorithm)
+ {
+ case HASHKIT_HASH_DEFAULT:
+ return libhashkit_one_at_a_time(key, key_length);
+ case HASHKIT_HASH_MD5:
+ return libhashkit_md5(key, key_length);
+ case HASHKIT_HASH_CRC:
+ return libhashkit_crc32(key, key_length);
+ case HASHKIT_HASH_FNV1_64:
+ return libhashkit_fnv1_64(key, key_length);
+ case HASHKIT_HASH_FNV1A_64:
+ return libhashkit_fnv1a_64(key, key_length);
+ case HASHKIT_HASH_FNV1_32:
+ return libhashkit_fnv1_32(key, key_length);
+ case HASHKIT_HASH_FNV1A_32:
+ return libhashkit_fnv1a_32(key, key_length);
+ case HASHKIT_HASH_HSIEH:
+#ifdef HAVE_HSIEH_HASH
+ return libhashkit_hsieh(key, key_length);
+#else
+ return 1;
+#endif
+ case HASHKIT_HASH_MURMUR3:
+ return libhashkit_murmur3(key, key_length);
+
+ case HASHKIT_HASH_MURMUR:
+#ifdef HAVE_MURMUR_HASH
+ return libhashkit_murmur(key, key_length);
+#else
+ return 1;
+#endif
+ case HASHKIT_HASH_JENKINS:
+ return libhashkit_jenkins(key, key_length);
+ case HASHKIT_HASH_CUSTOM:
+ case HASHKIT_HASH_MAX:
+ default:
+ if (DEBUG)
+ {
+ fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n");
+ fflush(stderr);
+ assert(0);
+ }
+ break;
+ }
+
+ return 1;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libhashkit library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libhashkit/common.h>
+
+hashkit_string_st *hashkit_encrypt(hashkit_st *kit,
+ const char* source, size_t source_length)
+{
+ return aes_encrypt(static_cast<aes_key_t*>(kit->_key), source, source_length);
+}
+
+hashkit_string_st *hashkit_decrypt(hashkit_st *kit,
+ const char* source, size_t source_length)
+{
+ return aes_decrypt(static_cast<aes_key_t*>(kit->_key), source, source_length);
+}
+
+bool hashkit_key(hashkit_st *kit, const char *key, const size_t key_length)
+{
+ if (kit->_key)
+ {
+ free(kit->_key);
+ }
+
+ kit->_key= aes_create_key(key, key_length);
+
+ return bool(kit->_key);
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libhashkit/common.h>
+
+/* FNV hash'es lifted from Dustin Sallings work */
+static uint32_t FNV_32_INIT= 2166136261UL;
+static uint32_t FNV_32_PRIME= 16777619;
+
+uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context)
+{
+ uint32_t hash= FNV_32_INIT;
+ (void)context;
+
+ for (size_t x= 0; x < key_length; x++)
+ {
+ uint32_t val= (uint32_t)key[x];
+ hash *= FNV_32_PRIME;
+ hash ^= val;
+ }
+
+ return hash;
+}
+
+uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context)
+{
+ uint32_t hash= FNV_32_INIT;
+ (void)context;
+
+ for (size_t x= 0; x < key_length; x++)
+ {
+ uint32_t val= (uint32_t)key[x];
+ hash ^= val;
+ hash *= FNV_32_PRIME;
+ }
+
+ return hash;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libhashkit/common.h>
+
+#if __WORDSIZE == 64 && defined(HAVE_FNV64_HASH)
+
+/* FNV hash'es lifted from Dustin Sallings work */
+static uint64_t FNV_64_INIT= 0xcbf29ce484222325;
+static uint64_t FNV_64_PRIME= 0x100000001b3;
+
+uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *)
+{
+ /* Thanks to pierre@demartines.com for the pointer */
+ uint64_t hash= FNV_64_INIT;
+
+ for (size_t x= 0; x < key_length; x++)
+ {
+ hash *= FNV_64_PRIME;
+ hash ^= (uint64_t)key[x];
+ }
+
+ return (uint32_t)hash;
+}
+
+uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *)
+{
+ uint32_t hash= (uint32_t) FNV_64_INIT;
+
+ for (size_t x= 0; x < key_length; x++)
+ {
+ uint32_t val= (uint32_t)key[x];
+ hash ^= val;
+ hash *= (uint32_t) FNV_64_PRIME;
+ }
+
+ return hash;
+}
+
+#else
+uint32_t hashkit_fnv1_64(const char *, size_t, void *)
+{
+ return 0;
+}
+
+uint32_t hashkit_fnv1a_64(const char *, size_t, void *)
+{
+ return 0;
+}
+#endif
--- /dev/null
+/* HashKit
+ * Copyright (C) 2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+static hashkit_return_t _set_function(struct hashkit_st::hashkit_function_st *self, hashkit_hash_algorithm_t hash_algorithm)
+{
+ if (self == NULL)
+ {
+ return HASHKIT_INVALID_ARGUMENT;
+ }
+
+ switch (hash_algorithm)
+ {
+ case HASHKIT_HASH_MD5:
+ self->function= hashkit_md5;
+ break;
+
+ case HASHKIT_HASH_CRC:
+ self->function= hashkit_crc32;
+ break;
+
+ case HASHKIT_HASH_FNV1_64:
+ if (libhashkit_has_algorithm(HASHKIT_HASH_FNV1_64))
+ {
+ self->function= hashkit_fnv1_64;
+ break;
+ }
+ return HASHKIT_INVALID_ARGUMENT;
+
+ case HASHKIT_HASH_FNV1A_64:
+ if (libhashkit_has_algorithm(HASHKIT_HASH_FNV1_64))
+ {
+ self->function= hashkit_fnv1a_64;
+ break;
+ }
+ return HASHKIT_INVALID_ARGUMENT;
+
+ case HASHKIT_HASH_FNV1_32:
+ self->function= hashkit_fnv1_32;
+ break;
+
+ case HASHKIT_HASH_FNV1A_32:
+ self->function= hashkit_fnv1a_32;
+ break;
+
+ case HASHKIT_HASH_HSIEH:
+ if (libhashkit_has_algorithm(HASHKIT_HASH_HSIEH))
+ {
+ self->function= hashkit_hsieh;
+ break;
+ }
+ return HASHKIT_INVALID_ARGUMENT;
+
+ case HASHKIT_HASH_MURMUR3:
+ if (libhashkit_has_algorithm(HASHKIT_HASH_MURMUR3))
+ {
+ self->function= hashkit_murmur3;
+ break;
+ }
+ return HASHKIT_INVALID_ARGUMENT;
+ case HASHKIT_HASH_MURMUR:
+ if (libhashkit_has_algorithm(HASHKIT_HASH_MURMUR))
+ {
+ self->function= hashkit_murmur;
+ break;
+ }
+ return HASHKIT_INVALID_ARGUMENT;
+
+ case HASHKIT_HASH_JENKINS:
+ self->function= hashkit_jenkins;
+ break;
+
+ case HASHKIT_HASH_CUSTOM:
+ return HASHKIT_INVALID_ARGUMENT;
+
+ case HASHKIT_HASH_DEFAULT:
+ self->function= hashkit_one_at_a_time;
+ break;
+
+ case HASHKIT_HASH_MAX:
+ self->function= hashkit_one_at_a_time;
+ return HASHKIT_INVALID_HASH;
+ }
+
+ self->context= NULL;
+
+ return HASHKIT_SUCCESS;
+}
+
+hashkit_return_t hashkit_set_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm)
+{
+ return _set_function(&self->base_hash, hash_algorithm);
+}
+
+hashkit_return_t hashkit_set_distribution_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm)
+{
+ return _set_function(&self->distribution_hash, hash_algorithm);
+}
+
+static hashkit_return_t _set_custom_function(struct hashkit_st::hashkit_function_st *self, hashkit_hash_fn function, void *context)
+{
+ if (self == NULL)
+ {
+ return HASHKIT_INVALID_ARGUMENT;
+ }
+
+ if (function)
+ {
+ self->function= function;
+ self->context= context;
+
+ return HASHKIT_SUCCESS;
+ }
+
+ return HASHKIT_FAILURE;
+}
+
+hashkit_return_t hashkit_set_custom_function(hashkit_st *self, hashkit_hash_fn function, void *context)
+{
+ if (self == NULL)
+ {
+ return HASHKIT_INVALID_ARGUMENT;
+ }
+
+
+ return _set_custom_function(&self->base_hash, function, context);
+}
+
+hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context)
+{
+ if (self == NULL)
+ {
+ return HASHKIT_INVALID_ARGUMENT;
+ }
+
+ return _set_custom_function(&self->distribution_hash, function, context);
+}
+
+static hashkit_hash_algorithm_t get_function_type(const hashkit_hash_fn function)
+{
+ if (function == hashkit_one_at_a_time)
+ {
+ return HASHKIT_HASH_DEFAULT;
+ }
+ else if (function == hashkit_md5)
+ {
+ return HASHKIT_HASH_MD5;
+ }
+ else if (function == hashkit_crc32)
+ {
+ return HASHKIT_HASH_CRC;
+ }
+ else if (function == hashkit_fnv1_64)
+ {
+ return HASHKIT_HASH_FNV1_64;
+ }
+ else if (function == hashkit_fnv1a_64)
+ {
+ return HASHKIT_HASH_FNV1A_64;
+ }
+ else if (function == hashkit_fnv1_32)
+ {
+ return HASHKIT_HASH_FNV1_32;
+ }
+ else if (function == hashkit_fnv1a_32)
+ {
+ return HASHKIT_HASH_FNV1A_32;
+ }
+ else if (function == hashkit_hsieh)
+ {
+ return HASHKIT_HASH_HSIEH;
+ }
+ else if (function == hashkit_murmur)
+ {
+ return HASHKIT_HASH_MURMUR;
+ }
+ else if (function == hashkit_murmur3)
+ {
+ return HASHKIT_HASH_MURMUR3;
+ }
+ else if (function == hashkit_jenkins)
+ {
+ return HASHKIT_HASH_JENKINS;
+ }
+
+ return HASHKIT_HASH_CUSTOM;
+}
+
+hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *self)
+{
+ if (self == NULL)
+ {
+ return HASHKIT_HASH_DEFAULT;
+ }
+
+ return get_function_type(self->base_hash.function);
+}
+
+hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self)
+{
+ if (self == NULL)
+ {
+ return HASHKIT_HASH_DEFAULT;
+ }
+
+ return get_function_type(self->distribution_hash.function);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libhashkit/common.h>
+
+bool libhashkit_has_algorithm(const hashkit_hash_algorithm_t algo)
+{
+ switch (algo)
+ {
+ case HASHKIT_HASH_FNV1_64:
+ case HASHKIT_HASH_FNV1A_64:
+#if __WORDSIZE == 64 && defined(HAVE_FNV64_HASH)
+ return true;
+#else
+ return false;
+#endif
+
+ case HASHKIT_HASH_HSIEH:
+#ifdef HAVE_HSIEH_HASH
+ return true;
+#else
+ return false;
+#endif
+
+ case HASHKIT_HASH_MURMUR3:
+ case HASHKIT_HASH_MURMUR:
+#ifdef HAVE_MURMUR_HASH
+ return true;
+#else
+ return false;
+#endif
+
+ case HASHKIT_HASH_FNV1_32:
+ case HASHKIT_HASH_FNV1A_32:
+ case HASHKIT_HASH_DEFAULT:
+ case HASHKIT_HASH_MD5:
+ case HASHKIT_HASH_CRC:
+ case HASHKIT_HASH_JENKINS:
+ case HASHKIT_HASH_CUSTOM:
+ return true;
+
+ case HASHKIT_HASH_MAX:
+ break;
+ }
+
+ return false;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libhashkit/common.h>
+
+static inline void _hashkit_init(hashkit_st *self)
+{
+ self->base_hash.function= hashkit_one_at_a_time;
+ self->base_hash.context= NULL;
+
+ self->distribution_hash.function= hashkit_one_at_a_time;
+ self->distribution_hash.context= NULL;
+
+ self->flags.is_base_same_distributed= true;
+ self->_key= NULL;
+}
+
+static inline hashkit_st *_hashkit_create(hashkit_st *self)
+{
+ if (self)
+ {
+ self->options.is_allocated= false;
+ }
+ else
+ {
+ self= (hashkit_st*)calloc(1, sizeof(hashkit_st));
+ if (self == NULL)
+ {
+ return NULL;
+ }
+
+ self->options.is_allocated= true;
+ }
+
+ return self;
+}
+
+hashkit_st *hashkit_create(hashkit_st *self)
+{
+ self= _hashkit_create(self);
+ if (self == NULL)
+ {
+ return NULL;
+ }
+
+ _hashkit_init(self);
+
+ return self;
+}
+
+
+void hashkit_free(hashkit_st *self)
+{
+ if (self and self->_key)
+ {
+ free(self->_key);
+ self->_key= NULL;
+ }
+
+ if (hashkit_is_allocated(self))
+ {
+ free(self);
+ }
+}
+
+hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source)
+{
+ if (source == NULL)
+ {
+ return hashkit_create(destination);
+ }
+
+ /* new_clone will be a pointer to destination */
+ destination= _hashkit_create(destination);
+
+ // Should only happen on allocation failure.
+ if (destination == NULL)
+ {
+ return NULL;
+ }
+
+ destination->base_hash= source->base_hash;
+ destination->distribution_hash= source->distribution_hash;
+ destination->flags= source->flags;
+ destination->_key= aes_clone_key(static_cast<aes_key_t*>(source->_key));
+
+ return destination;
+}
+
+bool hashkit_compare(const hashkit_st *first, const hashkit_st *second)
+{
+ if (not first or not second)
+ return false;
+
+ if (first->base_hash.function == second->base_hash.function and
+ first->base_hash.context == second->base_hash.context and
+ first->distribution_hash.function == second->distribution_hash.function and
+ first->distribution_hash.context == second->distribution_hash.context and
+ first->flags.is_base_same_distributed == second->flags.is_base_same_distributed)
+ {
+ return true;
+ }
+
+ return false;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#include <libhashkit-1.0/hashkit.h>
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#include "@AUTOHEADER_FILE@"
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* By Paul Hsieh (C) 2004, 2005. Covered under the Paul Hsieh
+ * derivative license.
+ * See: http://www.azillionmonkeys.com/qed/weblicense.html for license
+ * details.
+ * http://www.azillionmonkeys.com/qed/hash.html
+*/
+
+#include <libhashkit/common.h>
+
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__))
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+#ifdef HAVE_HSIEH_HASH
+uint32_t hashkit_hsieh(const char *key, size_t key_length, void *)
+{
+ uint32_t hash = 0, tmp;
+ int rem;
+
+ if (key_length <= 0 || key == NULL)
+ return 0;
+
+ rem = key_length & 3;
+ key_length >>= 2;
+
+ /* Main loop */
+ for (;key_length > 0; key_length--)
+ {
+ hash += get16bits (key);
+ tmp = (get16bits (key+2) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ key += 2*sizeof (uint16_t);
+ hash += hash >> 11;
+ }
+
+ /* Handle end cases */
+ switch (rem)
+ {
+ case 3: hash += get16bits (key);
+ hash ^= hash << 16;
+ hash ^= (uint32_t)key[sizeof (uint16_t)] << 18;
+ hash += hash >> 11;
+ break;
+ case 2: hash += get16bits (key);
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ break;
+ case 1: hash += (unsigned char)(*key);
+ hash ^= hash << 10;
+ hash += hash >> 1;
+ default:
+ break;
+ }
+
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+
+ return hash;
+}
+#else
+uint32_t hashkit_hsieh(const char *, size_t , void *)
+{
+ return 0;
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+#pragma once
+
+#define hashkit_is_allocated(__object) ((__object)->options.is_allocated)
+#define hashkit_is_initialized(__object) ((__object)->options.is_initialized)
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+*
+* By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+* code any way you wish, private, educational, or commercial. It's free.
+* Use for hash table lookup, or anything where one collision in 2^^32 is
+* acceptable. Do NOT use for cryptographic purposes.
+* http://burtleburtle.net/bob/hash/index.html
+*
+* Modified by Brian Pontz for libmemcached
+* TODO:
+* Add big endian support
+*/
+
+#include <libhashkit/common.h>
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+#define JENKINS_INITVAL 13
+
+/*
+jenkins_hash() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+*/
+
+uint32_t hashkit_jenkins(const char *key, size_t length, void *)
+{
+ uint32_t a,b,c; /* internal state */
+#ifndef WORDS_BIGENDIAN
+ union { const void *ptr; size_t i; } u;
+ u.ptr = key;
+#endif
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + JENKINS_INITVAL;
+
+#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;
+ /* fall through */
+ case 11: c+=((uint32_t)k[10])<<16;
+ /* fall through */
+ case 10: c+=((uint32_t)k[9])<<8;
+ /* fall through */
+ case 9 : c+=k[8];
+ /* fall through */
+ case 8 : b+=((uint32_t)k[7])<<24;
+ /* fall through */
+ case 7 : b+=((uint32_t)k[6])<<16;
+ /* fall through */
+ case 6 : b+=((uint32_t)k[5])<<8;
+ /* fall through */
+ case 5 : b+=k[4];
+ /* fall through */
+ case 4 : a+=((uint32_t)k[3])<<24;
+ /* fall through */
+ case 3 : a+=((uint32_t)k[2])<<16;
+ /* fall through */
+ case 2 : a+=((uint32_t)k[1])<<8;
+ /* fall through */
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ default : return c;
+ }
+#ifndef WORDS_BIGENDIAN
+ }
+#endif
+
+ final(a,b,c);
+ return c;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libhashkit/common.h>
+#include <math.h>
+
+#if 0
+static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment)
+{
+ unsigned char results[16];
+
+ md5_signature((unsigned char*)key, key_length, results);
+ return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
+ | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
+ | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
+ | (results[0 + alignment * 4] & 0xFF);
+}
+
+static int continuum_points_cmp(const void *t1, const void *t2)
+{
+ hashkit_continuum_point_st *ct1= (hashkit_continuum_point_st *)t1;
+ hashkit_continuum_point_st *ct2= (hashkit_continuum_point_st *)t2;
+
+ if (ct1->value == ct2->value)
+ return 0;
+ else if (ct1->value > ct2->value)
+ return 1;
+ else
+ return -1;
+}
+
+int update_continuum(hashkit_st *hashkit)
+{
+ uint32_t count;
+ uint32_t continuum_index= 0;
+ uint32_t value;
+ uint32_t points_index;
+ uint32_t points_count= 0;
+ uint32_t points_per_server;
+ uint32_t points_per_hash;
+ uint64_t total_weight= 0;
+ uint32_t live_servers;
+ uint8_t *context;
+
+ if (hashkit->active_fn != NULL || hashkit->weight_fn != NULL)
+ {
+ live_servers= 0;
+
+ for (count= 0, context= hashkit->list; count < hashkit->list_size;
+ count++, context+= hashkit->context_size)
+ {
+ if (hashkit->active_fn != NULL)
+ {
+ if (hashkit->active_fn(context))
+ live_servers++;
+ else
+ continue;
+ }
+
+ if (hashkit->weight_fn != NULL)
+ total_weight+= hashkit->weight_fn(context);
+ }
+ }
+
+ if (hashkit->active_fn == NULL)
+ live_servers= (uint32_t)hashkit->list_size;
+
+ if (live_servers == 0)
+ return 0;
+
+ if (hashkit->weight_fn == NULL)
+ {
+ points_per_server= HASHKIT_POINTS_PER_NODE;
+ points_per_hash= 1;
+ }
+ else
+ {
+ points_per_server= HASHKIT_POINTS_PER_NODE_WEIGHTED;
+ points_per_hash= 4;
+ }
+
+ if (live_servers > hashkit->continuum_count)
+ {
+ hashkit_continuum_point_st *new_continuum;
+
+ new_continuum= realloc(hashkit->continuum,
+ sizeof(hashkit_continuum_point_st) *
+ (live_servers + HASHKIT_CONTINUUM_ADDITION) *
+ points_per_server);
+
+ if (new_continuum == NULL)
+ return ENOMEM;
+
+ hashkit->continuum= new_continuum;
+ hashkit->continuum_count= live_servers + HASHKIT_CONTINUUM_ADDITION;
+ }
+
+ for (count= 0, context= hashkit->list; count < hashkit->list_size;
+ count++, context+= hashkit->context_size)
+ {
+ if (hashkit->active_fn != NULL && hashkit->active_fn(context) == false)
+ continue;
+
+ if (hashkit->weight_fn != NULL)
+ {
+ float pct = (float)hashkit->weight_fn(context) / (float)total_weight;
+ points_per_server= (uint32_t) ((floorf((float) (pct * HASHKIT_POINTS_PER_NODE_WEIGHTED / 4 * (float)live_servers + 0.0000000001))) * 4);
+ }
+
+ for (points_index= 0;
+ points_index < points_per_server / points_per_hash;
+ points_index++)
+ {
+ char sort_host[HASHKIT_CONTINUUM_KEY_SIZE]= "";
+ size_t sort_host_length;
+
+ if (hashkit->continuum_key_fn == NULL)
+ {
+ sort_host_length= (size_t) snprintf(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, "%u",
+ points_index);
+ }
+ else
+ {
+ sort_host_length= hashkit->continuum_key_fn(sort_host, HASHKIT_CONTINUUM_KEY_SIZE,
+ points_index, context);
+ }
+
+ if (hashkit->weight_fn == NULL)
+ {
+ if (hashkit->continuum_hash_fn == NULL)
+ value= hashkit_default(sort_host, sort_host_length);
+ else
+ value= hashkit->continuum_hash_fn(sort_host, sort_host_length);
+
+ hashkit->continuum[continuum_index].index= count;
+ hashkit->continuum[continuum_index++].value= value;
+ }
+ else
+ {
+ unsigned int i;
+ for (i = 0; i < points_per_hash; i++)
+ {
+ value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
+ hashkit->continuum[continuum_index].index= count;
+ hashkit->continuum[continuum_index++].value= value;
+ }
+ }
+ }
+
+ points_count+= points_per_server;
+ }
+
+ hashkit->continuum_points_count= points_count;
+ qsort(hashkit->continuum, hashkit->continuum_points_count, sizeof(hashkit_continuum_point_st),
+ continuum_points_cmp);
+
+ return 0;
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ This Library has been modified from its original form by
+ Brian Aker (brian@tangent.org)
+
+ See below for original Copyright.
+*/
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+#include <libhashkit/common.h>
+
+#include <string.h>
+#include <sys/types.h>
+
+#define GCC_VERSION (__GNUC__ * 10000 \
+ + __GNUC_MINOR__ * 100 \
+ + __GNUC_PATCHLEVEL__)
+
+#if GCC_VERSION > 40600
+# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+typedef const unsigned char *CONST_POINTER;
+
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4;
+
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+static void MD5Init (MD5_CTX *context); /* context */
+static void MD5Update ( MD5_CTX *context, /* context */
+ const unsigned char *input, /* input block */
+ unsigned int inputLen); /* length of input block */
+static void MD5Final ( unsigned char digest[16], /* message digest */
+ MD5_CTX *context); /* context */
+
+/* Constants for MD5Transform routine. */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+
+static void MD5Transform (UINT4 state[4],
+ const unsigned char block[64]);
+static void Encode (unsigned char *output,
+ UINT4 *input,
+ unsigned int len);
+static void Decode(UINT4 *output, const unsigned char *input, unsigned int len);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+
+/*
+ Just a simple method for getting the signature
+ result must be == 16
+*/
+void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result)
+{
+ MD5_CTX my_md5;
+
+ MD5Init(&my_md5);
+ (void)MD5Update(&my_md5, key, length);
+ MD5Final(result, &my_md5);
+}
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+static void MD5Init (MD5_CTX *context) /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+
+static void MD5Update (
+ MD5_CTX *context, /* context */
+ const unsigned char *input, /* input block */
+ unsigned int inputLen) /* length of input block */
+{
+ unsigned int i, idx, partLen;
+
+ /* Compute number of bytes mod 64 */
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - idx;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, (CONST_POINTER)&input[i]);
+
+ idx = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+
+static void MD5Final (
+ unsigned char digest[16], /* message digest */
+ MD5_CTX *context) /* context */
+{
+ unsigned char bits[8];
+ unsigned int idx, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ memset((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (
+ UINT4 state[4],
+ const unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ memset((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (
+unsigned char *output,
+UINT4 *input,
+unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (
+ UINT4 *output,
+ const unsigned char *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+uint32_t hashkit_md5(const char *key, size_t key_length, void *context)
+{
+ unsigned char results[16];
+ (void)context;
+
+ md5_signature((unsigned char*)key, (unsigned int)key_length, results);
+
+ return ((uint32_t) (results[3] & 0xFF) << 24)
+ | ((uint32_t) (results[2] & 0xFF) << 16)
+ | ((uint32_t) (results[1] & 0xFF) << 8)
+ | (results[0] & 0xFF);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ "Murmur" hash provided by Austin, tanjent@gmail.com
+ http://murmurhash.googlepages.com/
+
+ Note - This code makes a few assumptions about how your machine behaves -
+
+ 1. We can read a 4-byte value from any address without crashing
+ 2. sizeof(int) == 4
+
+ And it has a few limitations -
+ 1. It will not work incrementally.
+ 2. It will not produce the same results on little-endian and big-endian
+ machines.
+
+ Updated to murmur2 hash - BP
+*/
+
+#include <libhashkit/common.h>
+
+#ifdef HAVE_MURMUR_HASH
+
+#include <cstring>
+
+uint32_t hashkit_murmur(const char *key, size_t length, void *context)
+{
+ /*
+ 'm' and 'r' are mixing constants generated offline. They're not
+ really 'magic', they just happen to work well.
+ */
+
+ const unsigned int m= 0x5bd1e995;
+ const uint32_t seed= (0xdeadbeef * (uint32_t)length);
+ const int r= 24;
+
+
+ // Initialize the hash to a 'random' value
+
+ uint32_t h= seed ^ (uint32_t)length;
+
+ // Mix 4 bytes at a time into the hash
+
+ const unsigned char * data= (const unsigned char *)key;
+ (void)context;
+
+ while(length >= 4)
+ {
+ unsigned int k;
+ memcpy(&k, data, sizeof(unsigned int));
+
+ 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; /* fall through */
+ case 2: h ^= ((uint32_t)data[1]) << 8; /* fall through */
+ 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;
+}
+
+#else
+uint32_t hashkit_murmur(const char *, size_t , void *)
+{
+ return 0;
+}
+#endif
--- /dev/null
+//-----------------------------------------------------------------------------
+//MurmurHash3 was written by Austin Appleby, and is placed in the public
+//domain. The author hereby disclaims copyright to this source code.
+
+// Note - The x86 and x64 versions do _not_ produce the same results, as the
+// algorithms are optimized for their respective platforms. You can still
+// compile and run any of them on any platform, but your performance with the
+// non-native version will be less than optimal.
+
+#include "libhashkit/hashkitcon.h"
+
+#include "libhashkit/murmur3.h"
+
+//-----------------------------------------------------------------------------
+// Platform-specific functions and macros
+
+#ifdef __GNUC__
+#define FORCE_INLINE __attribute__((always_inline)) inline
+#else
+#define FORCE_INLINE inline
+#endif
+
+static FORCE_INLINE uint32_t rotl32 ( uint32_t x, int8_t r )
+{
+ return (x << r) | (x >> (32 - r));
+}
+
+static FORCE_INLINE uint64_t rotl64 ( uint64_t x, int8_t r )
+{
+ return (x << r) | (x >> (64 - r));
+}
+
+#define ROTL32(x,y) rotl32(x,y)
+#define ROTL64(x,y) rotl64(x,y)
+
+#define BIG_CONSTANT(x) (x##LLU)
+
+//-----------------------------------------------------------------------------
+// Block read - if your platform needs to do endian-swapping or can only
+// handle aligned reads, do the conversion here
+
+#include <cstring>
+template <typename T>
+static inline T getblock(const T *blocks, int i) {
+ T b;
+ memcpy(&b, ((const uint8_t *) blocks) + i * sizeof(T), sizeof(T));
+ return b;
+}
+
+//-----------------------------------------------------------------------------
+// Finalization mix - force all bits of a hash block to avalanche
+
+static FORCE_INLINE uint32_t fmix32 ( uint32_t h )
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+
+ return h;
+}
+
+//----------
+
+static FORCE_INLINE uint64_t fmix64 ( uint64_t k )
+{
+ k ^= k >> 33;
+ k *= BIG_CONSTANT(0xff51afd7ed558ccd);
+ k ^= k >> 33;
+ k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
+ k ^= k >> 33;
+
+ return k;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_32 ( const void * key, int len,
+ uint32_t seed, void * out )
+{
+ const uint8_t * data = (const uint8_t*)key;
+ const int nblocks = len / 4;
+ int i;
+
+ uint32_t h1 = seed;
+
+ uint32_t c1 = 0xcc9e2d51;
+ uint32_t c2 = 0x1b873593;
+
+ //----------
+ // body
+
+ const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
+
+ for(i = -nblocks; i; i++)
+ {
+ uint32_t k1 = getblock(blocks,i);
+
+ k1 *= c1;
+ k1 = ROTL32(k1,15);
+ k1 *= c2;
+
+ h1 ^= k1;
+ h1 = ROTL32(h1,13);
+ h1 = h1*5+0xe6546b64;
+ }
+
+ //----------
+ // tail
+
+ const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
+
+ uint32_t k1 = 0;
+
+ switch(len & 3)
+ {
+ case 3: k1 ^= tail[2] << 16;
+ /* fall through */
+ case 2: k1 ^= tail[1] << 8;
+ /* fall through */
+ case 1: k1 ^= tail[0];
+ k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+ };
+
+ //----------
+ // finalization
+
+ h1 ^= len;
+
+ h1 = fmix32(h1);
+
+ *(uint32_t*)out = h1;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_128 ( const void * key, const int len,
+ uint32_t seed, void * out )
+{
+ const uint8_t * data = (const uint8_t*)key;
+ const int nblocks = len / 16;
+ int i;
+
+ uint32_t h1 = seed;
+ uint32_t h2 = seed;
+ uint32_t h3 = seed;
+ uint32_t h4 = seed;
+
+ uint32_t c1 = 0x239b961b;
+ uint32_t c2 = 0xab0e9789;
+ uint32_t c3 = 0x38b34ae5;
+ uint32_t c4 = 0xa1e38b93;
+
+ //----------
+ // body
+
+ const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
+
+ for(i = -nblocks; i; i++)
+ {
+ uint32_t k1 = getblock(blocks,i*4+0);
+ uint32_t k2 = getblock(blocks,i*4+1);
+ uint32_t k3 = getblock(blocks,i*4+2);
+ uint32_t k4 = getblock(blocks,i*4+3);
+
+ k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+
+ h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
+
+ k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
+
+ h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
+
+ k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
+
+ h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
+
+ k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
+
+ h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
+ }
+
+ //----------
+ // tail
+
+ const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
+
+ uint32_t k1 = 0;
+ uint32_t k2 = 0;
+ uint32_t k3 = 0;
+ uint32_t k4 = 0;
+
+ switch(len & 15)
+ {
+ case 15: k4 ^= tail[14] << 16;
+ /* fall through */
+ case 14: k4 ^= tail[13] << 8;
+ /* fall through */
+ case 13: k4 ^= tail[12] << 0;
+ k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
+ /* fall through */
+ case 12: k3 ^= tail[11] << 24;
+ /* fall through */
+ case 11: k3 ^= tail[10] << 16;
+ /* fall through */
+ case 10: k3 ^= tail[ 9] << 8;
+ /* fall through */
+ case 9: k3 ^= tail[ 8] << 0;
+ k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
+ /* fall through */
+ case 8: k2 ^= tail[ 7] << 24;
+ /* fall through */
+ case 7: k2 ^= tail[ 6] << 16;
+ /* fall through */
+ case 6: k2 ^= tail[ 5] << 8;
+ /* fall through */
+ case 5: k2 ^= tail[ 4] << 0;
+ k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
+ /* fall through */
+ case 4: k1 ^= tail[ 3] << 24;
+ /* fall through */
+ case 3: k1 ^= tail[ 2] << 16;
+ /* fall through */
+ case 2: k1 ^= tail[ 1] << 8;
+ /* fall through */
+ case 1: k1 ^= tail[ 0] << 0;
+ k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+ };
+
+ //----------
+ // finalization
+
+ h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
+
+ h1 += h2; h1 += h3; h1 += h4;
+ h2 += h1; h3 += h1; h4 += h1;
+
+ h1 = fmix32(h1);
+ h2 = fmix32(h2);
+ h3 = fmix32(h3);
+ h4 = fmix32(h4);
+
+ h1 += h2; h1 += h3; h1 += h4;
+ h2 += h1; h3 += h1; h4 += h1;
+
+ ((uint32_t*)out)[0] = h1;
+ ((uint32_t*)out)[1] = h2;
+ ((uint32_t*)out)[2] = h3;
+ ((uint32_t*)out)[3] = h4;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x64_128 ( const void * key, const int len,
+ const uint32_t seed, void * out )
+{
+ const uint8_t * data = (const uint8_t*)key;
+ const int nblocks = len / 16;
+ int i;
+
+ uint64_t h1 = seed;
+ uint64_t h2 = seed;
+
+ uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
+ uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
+
+ //----------
+ // body
+
+ const uint64_t * blocks = (const uint64_t *)(data);
+
+ for(i = 0; i < nblocks; i++)
+ {
+ uint64_t k1 = getblock(blocks,i*2+0);
+ uint64_t k2 = getblock(blocks,i*2+1);
+
+ k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
+
+ h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
+
+ k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
+
+ h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
+ }
+
+ //----------
+ // tail
+
+ const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
+
+ uint64_t k1 = 0;
+ uint64_t k2 = 0;
+
+ switch(len & 15)
+ {
+ case 15: k2 ^= (uint64_t)(tail[14]) << 48;
+ /* fall through */
+ case 14: k2 ^= (uint64_t)(tail[13]) << 40;
+ /* fall through */
+ case 13: k2 ^= (uint64_t)(tail[12]) << 32;
+ /* fall through */
+ case 12: k2 ^= (uint64_t)(tail[11]) << 24;
+ /* fall through */
+ case 11: k2 ^= (uint64_t)(tail[10]) << 16;
+ /* fall through */
+ case 10: k2 ^= (uint64_t)(tail[ 9]) << 8;
+ /* fall through */
+ case 9: k2 ^= (uint64_t)(tail[ 8]) << 0;
+ k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
+ /* fall through */
+ case 8: k1 ^= (uint64_t)(tail[ 7]) << 56;
+ /* fall through */
+ case 7: k1 ^= (uint64_t)(tail[ 6]) << 48;
+ /* fall through */
+ case 6: k1 ^= (uint64_t)(tail[ 5]) << 40;
+ /* fall through */
+ case 5: k1 ^= (uint64_t)(tail[ 4]) << 32;
+ /* fall through */
+ case 4: k1 ^= (uint64_t)(tail[ 3]) << 24;
+ /* fall through */
+ case 3: k1 ^= (uint64_t)(tail[ 2]) << 16;
+ /* fall through */
+ case 2: k1 ^= (uint64_t)(tail[ 1]) << 8;
+ /* fall through */
+ case 1: k1 ^= (uint64_t)(tail[ 0]) << 0;
+ k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
+ };
+
+ //----------
+ // finalization
+
+ h1 ^= len; h2 ^= len;
+
+ h1 += h2;
+ h2 += h1;
+
+ h1 = fmix64(h1);
+ h2 = fmix64(h2);
+
+ h1 += h2;
+ h2 += h1;
+
+ ((uint64_t*)out)[0] = h1;
+ ((uint64_t*)out)[1] = h2;
+}
+
+//-----------------------------------------------------------------------------
+
--- /dev/null
+//-----------------------------------------------------------------------------
+// MurmurHash3 was written by Austin Appleby, and is placed in the
+// public domain. The author hereby disclaims copyright to this source
+// code.
+
+#pragma once
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_32 (const void *key, int len, uint32_t seed, void *out);
+
+void MurmurHash3_x86_128(const void *key, int len, uint32_t seed, void *out);
+
+void MurmurHash3_x64_128(const void *key, int len, uint32_t seed, void *out);
+
+//-----------------------------------------------------------------------------
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libhashkit/common.h"
+#include "libhashkit/murmur3.h"
+
+uint32_t hashkit_murmur3(const char *key, size_t length, void *)
+{
+ const uint32_t seed= (0xdeadbeef * (uint32_t)length);
+
+ uint32_t ret;
+ MurmurHash3_x86_32(key, int(length), seed, &ret);
+
+ return ret;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libhashkit/common.h>
+
+#ifdef HAVE_HSIEH_HASH
+#error "not supported"
+#else
+uint32_t hashkit_hsieh(const char *, size_t , void *)
+{
+ return 0;
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/*
+ This has is Jenkin's "One at A time Hash".
+http://en.wikipedia.org/wiki/Jenkins_hash_function
+*/
+
+#include <libhashkit/common.h>
+
+uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context)
+{
+ const char *ptr= key;
+ uint32_t value= 0;
+ (void)context;
+
+ while (key_length--)
+ {
+ uint32_t val= (uint32_t) *ptr++;
+ value += val;
+ value += (value << 10);
+ value ^= (value >> 6);
+ }
+ value += (value << 3);
+ value ^= (value >> 11);
+ value += (value << 15);
+
+ return value;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/**
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <stdlib.h>
+
+#include "libhashkit/rijndael.hpp"
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+ 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+ 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+ 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+ 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+ 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+ 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+ 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+ 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+ 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+ 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+ 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+ 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+ 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+ 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+ 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+ 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+ 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+ 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+ 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+ 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+ 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+ 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+ 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+ 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+ 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+ 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+ 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+ 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+ 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+ 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+ 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+ 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+ 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+ 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+ 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+ 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+ 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+ 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+ 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+ 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+ 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+ 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+ 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+ 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+ 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+ 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+ 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+ 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+ 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+ 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+ 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+ 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+ 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+ 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+ 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+ 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+ 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+ 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+ 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+ 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+ 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+ 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+ 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+ 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+ 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+ 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+ 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+ 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+ 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+ 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+ 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+ 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+ 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+ 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+ 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+ 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+ 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+ 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+ 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+ 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+ 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+ 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+ 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+ 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+ 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+ 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+ 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+ 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+ 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+ 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+ 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+ 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+ 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+ 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+ 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+ 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+ 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+ 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+ 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+ 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+ 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+ 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+ 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+ 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+ 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+ 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+ 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+ 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+ 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+ 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+ 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+ 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+ 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+ 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+ 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+ 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+ 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+ 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+ 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+ 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+ 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+ 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+ 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+ 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+ 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+ 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+ 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+ 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+ 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+ 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+ 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+ 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+ 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+ 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+ 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+ 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+ 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+ 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+ 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+ 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+ 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+ 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+ 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+ 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+ 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+ 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+ 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+ 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+ 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+ 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+ 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+ 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+ 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+ 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+ 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+ 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+ 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+ 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+ 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+ 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+ 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+ 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+ 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+ 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+ 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+ 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+ 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+ 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+ 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+ 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+ 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+ 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+ 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+ 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+ 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+ 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+ 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+ 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+ 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+ 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+ 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+ 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+ 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+ 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+ 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+ 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+ 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+ 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+ 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+ 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+ 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+ 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+ 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+ 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+ 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+ 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+ 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+ 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+ 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+ 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+ 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+ 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+ 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+ 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+ 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+ 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+ 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+ 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+ 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+ 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+ 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+ 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+ 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+ 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+ 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+ 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+ 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+ 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+ 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+ 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+ 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+ 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+ 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+ 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+ 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+ 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+ 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+ 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+ 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+ 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+ 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+ 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+ 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+ 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+ 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+ 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+ 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+ 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+ 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+ 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+ 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+ 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+ 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+ 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+ 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+ 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+ 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+ 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+ 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+ 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+ 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+ 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+ 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+ 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+ 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+ 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+static const u32 Td0[256] = {
+ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+ 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+ 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+ 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+ 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+ 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+ 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+ 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+ 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+ 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+ 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+ 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+ 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+ 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+ 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+ 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+ 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+ 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+ 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+ 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+ 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+ 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+ 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+ 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+ 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+ 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+ 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+ 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+ 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+ 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+ 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+ 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+ 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+ 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+ 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+ 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+ 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+ 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+ 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+ 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+ 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+ 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+ 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+ 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+ 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+ 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+ 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+ 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+ 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+ 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+ 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+ 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+ 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+ 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+ 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+ 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+ 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+ 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+ 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+ 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+ 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+ 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+ 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+ 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+ 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+ 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+ 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+ 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+ 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+ 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+ 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+ 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+ 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+ 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+ 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+ 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+ 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+ 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+ 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+ 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+ 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+ 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+ 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+ 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+ 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+ 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+ 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+ 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+ 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+ 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+ 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+ 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+ 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+ 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+ 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+ 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+ 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+ 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+ 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+ 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+ 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+ 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+ 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+ 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+ 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+ 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+ 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+ 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+ 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+ 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+ 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+ 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+ 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+ 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+ 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+ 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+ 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+ 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+ 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+ 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+ 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+ 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+ 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+ 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+ 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+ 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+ 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+ 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+ 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+ 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+ 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+ 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+ 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+ 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+ 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+ 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+ 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+ 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+ 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+ 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+ 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+ 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+ 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+ 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+ 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+ 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+ 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+ 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+ 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+ 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+ 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+ 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+ 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+ 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+ 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+ 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+ 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+ 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+ 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+ 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+ 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+ 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+ 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+ 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+ 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+ 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+ 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+ 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+ 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+ 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+ 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+ 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+ 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+ 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+ 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+ 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+ 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+ 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+ 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+ 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+ 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+ 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+ 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+ 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+ 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+ 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+ 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+ 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+ 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+ 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+ 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+ 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+ 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+ 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+ 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+ 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+ 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+ 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+ 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+ 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+ 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+ 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+ 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+ 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+ 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+ 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+ 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+ 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+ 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+ 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+ 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+ 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+ 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+ 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+ 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+ 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+ 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+ 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+ 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+ 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+ 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+ 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+ 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+ 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+ 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+ 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+ 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+ 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+ 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+ 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+ 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+ 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+ 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+ 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+ 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+ 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+ 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+ 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+ 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+ 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+ 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+ 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+ 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+ 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+ 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+ 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+ 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+ 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+ 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+ 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+ 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+ 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+ 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+ 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+ 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+ 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+ 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+
+#ifdef _MSC_VER
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
+#endif
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+ int i = 0;
+ u32 temp;
+
+ rk[0] = GETU32(cipherKey );
+ rk[1] = GETU32(cipherKey + 4);
+ rk[2] = GETU32(cipherKey + 8);
+ rk[3] = GETU32(cipherKey + 12);
+ if (keyBits == 128) {
+ for (;;) {
+ temp = rk[3];
+ rk[4] = rk[0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[5] = rk[1] ^ rk[4];
+ rk[6] = rk[2] ^ rk[5];
+ rk[7] = rk[3] ^ rk[6];
+ if (++i == 10) {
+ return 10;
+ }
+ rk += 4;
+ }
+ }
+ rk[4] = GETU32(cipherKey + 16);
+ rk[5] = GETU32(cipherKey + 20);
+ if (keyBits == 192) {
+ for (;;) {
+ temp = rk[ 5];
+ rk[ 6] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[ 7] = rk[ 1] ^ rk[ 6];
+ rk[ 8] = rk[ 2] ^ rk[ 7];
+ rk[ 9] = rk[ 3] ^ rk[ 8];
+ if (++i == 8) {
+ return 12;
+ }
+ rk[10] = rk[ 4] ^ rk[ 9];
+ rk[11] = rk[ 5] ^ rk[10];
+ rk += 6;
+ }
+ }
+ rk[6] = GETU32(cipherKey + 24);
+ rk[7] = GETU32(cipherKey + 28);
+ if (keyBits == 256) {
+ for (;;) {
+ temp = rk[ 7];
+ rk[ 8] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[ 9] = rk[ 1] ^ rk[ 8];
+ rk[10] = rk[ 2] ^ rk[ 9];
+ rk[11] = rk[ 3] ^ rk[10];
+ if (++i == 7) {
+ return 14;
+ }
+ temp = rk[11];
+ rk[12] = rk[ 4] ^
+ (Te4[(temp >> 24) ] & 0xff000000) ^
+ (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp ) & 0xff] & 0x000000ff);
+ rk[13] = rk[ 5] ^ rk[12];
+ rk[14] = rk[ 6] ^ rk[13];
+ rk[15] = rk[ 7] ^ rk[14];
+
+ rk += 8;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+ int Nr, i, j;
+ u32 temp;
+
+ /* expand the cipher key: */
+ Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
+ /* invert the order of the round keys: */
+ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+ temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
+ temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+ temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+ temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+ }
+ /* apply the inverse MixColumn transform to all round keys but the first and the last: */
+ for (i = 1; i < Nr; i++) {
+ rk += 4;
+ rk[0] =
+ Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[0] ) & 0xff] & 0xff];
+ rk[1] =
+ Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[1] ) & 0xff] & 0xff];
+ rk[2] =
+ Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[2] ) & 0xff] & 0xff];
+ rk[3] =
+ Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[3] ) & 0xff] & 0xff];
+ }
+ return Nr;
+}
+
+void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(pt ) ^ rk[0];
+ s1 = GETU32(pt + 4) ^ rk[1];
+ s2 = GETU32(pt + 8) ^ rk[2];
+ s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+ if (Nr > 10) {
+ /* round 10: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+ if (Nr > 12) {
+ /* round 12: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+ }
+ }
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Te0[(s0 >> 24) ] ^
+ Te1[(s1 >> 16) & 0xff] ^
+ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Te0[(s1 >> 24) ] ^
+ Te1[(s2 >> 16) & 0xff] ^
+ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Te0[(s2 >> 24) ] ^
+ Te1[(s3 >> 16) & 0xff] ^
+ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Te0[(s3 >> 24) ] ^
+ Te1[(s0 >> 16) & 0xff] ^
+ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Te0[(t0 >> 24) ] ^
+ Te1[(t1 >> 16) & 0xff] ^
+ Te2[(t2 >> 8) & 0xff] ^
+ Te3[(t3 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Te0[(t1 >> 24) ] ^
+ Te1[(t2 >> 16) & 0xff] ^
+ Te2[(t3 >> 8) & 0xff] ^
+ Te3[(t0 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Te0[(t2 >> 24) ] ^
+ Te1[(t3 >> 16) & 0xff] ^
+ Te2[(t0 >> 8) & 0xff] ^
+ Te3[(t1 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Te0[(t3 >> 24) ] ^
+ Te1[(t0 >> 16) & 0xff] ^
+ Te2[(t1 >> 8) & 0xff] ^
+ Te3[(t2 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Te4[(t0 >> 24) ] & 0xff000000) ^
+ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(ct , s0);
+ s1 =
+ (Te4[(t1 >> 24) ] & 0xff000000) ^
+ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(ct + 4, s1);
+ s2 =
+ (Te4[(t2 >> 24) ] & 0xff000000) ^
+ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(ct + 8, s2);
+ s3 =
+ (Te4[(t3 >> 24) ] & 0xff000000) ^
+ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(ct + 12, s3);
+}
+
+void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) {
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(ct ) ^ rk[0];
+ s1 = GETU32(ct + 4) ^ rk[1];
+ s2 = GETU32(ct + 8) ^ rk[2];
+ s3 = GETU32(ct + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+ if (Nr > 10) {
+ /* round 10: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+ if (Nr > 12) {
+ /* round 12: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+ }
+ }
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Td0[(s0 >> 24) ] ^
+ Td1[(s3 >> 16) & 0xff] ^
+ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Td0[(s1 >> 24) ] ^
+ Td1[(s0 >> 16) & 0xff] ^
+ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Td0[(s2 >> 24) ] ^
+ Td1[(s1 >> 16) & 0xff] ^
+ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Td0[(s3 >> 24) ] ^
+ Td1[(s2 >> 16) & 0xff] ^
+ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Td0[(t0 >> 24) ] ^
+ Td1[(t3 >> 16) & 0xff] ^
+ Td2[(t2 >> 8) & 0xff] ^
+ Td3[(t1 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Td0[(t1 >> 24) ] ^
+ Td1[(t0 >> 16) & 0xff] ^
+ Td2[(t3 >> 8) & 0xff] ^
+ Td3[(t2 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Td0[(t2 >> 24) ] ^
+ Td1[(t1 >> 16) & 0xff] ^
+ Td2[(t0 >> 8) & 0xff] ^
+ Td3[(t3 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Td0[(t3 >> 24) ] ^
+ Td1[(t2 >> 16) & 0xff] ^
+ Td2[(t1 >> 8) & 0xff] ^
+ Td3[(t0 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Td4[(t0 >> 24) ] & 0xff000000) ^
+ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(pt , s0);
+ s1 =
+ (Td4[(t1 >> 24) ] & 0xff000000) ^
+ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(pt + 4, s1);
+ s2 =
+ (Td4[(t2 >> 24) ] & 0xff000000) ^
+ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(pt + 8, s2);
+ s3 =
+ (Td4[(t3 >> 24) ] & 0xff000000) ^
+ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(pt + 12, s3);
+}
+
+#ifdef INTERMEDIATE_VALUE_KAT
+
+void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) {
+ int r;
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(block ) ^ rk[0];
+ s1 = GETU32(block + 4) ^ rk[1];
+ s2 = GETU32(block + 8) ^ rk[2];
+ s3 = GETU32(block + 12) ^ rk[3];
+ rk += 4;
+
+ /*
+ * Nr - 1 full rounds:
+ */
+ for (r = (rounds < Nr ? rounds : Nr - 1); r > 0; r--) {
+ t0 =
+ Te0[(s0 >> 24) ] ^
+ Te1[(s1 >> 16) & 0xff] ^
+ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3 ) & 0xff] ^
+ rk[0];
+ t1 =
+ Te0[(s1 >> 24) ] ^
+ Te1[(s2 >> 16) & 0xff] ^
+ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0 ) & 0xff] ^
+ rk[1];
+ t2 =
+ Te0[(s2 >> 24) ] ^
+ Te1[(s3 >> 16) & 0xff] ^
+ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1 ) & 0xff] ^
+ rk[2];
+ t3 =
+ Te0[(s3 >> 24) ] ^
+ Te1[(s0 >> 16) & 0xff] ^
+ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2 ) & 0xff] ^
+ rk[3];
+
+ s0 = t0;
+ s1 = t1;
+ s2 = t2;
+ s3 = t3;
+ rk += 4;
+
+ }
+
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ if (rounds == Nr) {
+ t0 =
+ (Te4[(s0 >> 24) ] & 0xff000000) ^
+ (Te4[(s1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(s2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(s3 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ t1 =
+ (Te4[(s1 >> 24) ] & 0xff000000) ^
+ (Te4[(s2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(s3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(s0 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ t2 =
+ (Te4[(s2 >> 24) ] & 0xff000000) ^
+ (Te4[(s3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(s0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(s1 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ t3 =
+ (Te4[(s3 >> 24) ] & 0xff000000) ^
+ (Te4[(s0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(s1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(s2 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+
+ s0 = t0;
+ s1 = t1;
+ s2 = t2;
+ s3 = t3;
+ }
+
+ PUTU32(block , s0);
+ PUTU32(block + 4, s1);
+ PUTU32(block + 8, s2);
+ PUTU32(block + 12, s3);
+}
+
+void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) {
+ int r;
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(block ) ^ rk[0];
+ s1 = GETU32(block + 4) ^ rk[1];
+ s2 = GETU32(block + 8) ^ rk[2];
+ s3 = GETU32(block + 12) ^ rk[3];
+ rk += 4;
+
+ /*
+ * Nr - 1 full rounds:
+ */
+ for (r = (rounds < Nr ? rounds : Nr) - 1; r > 0; r--) {
+ t0 =
+ Td0[(s0 >> 24) ] ^
+ Td1[(s3 >> 16) & 0xff] ^
+ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1 ) & 0xff] ^
+ rk[0];
+ t1 =
+ Td0[(s1 >> 24) ] ^
+ Td1[(s0 >> 16) & 0xff] ^
+ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2 ) & 0xff] ^
+ rk[1];
+ t2 =
+ Td0[(s2 >> 24) ] ^
+ Td1[(s1 >> 16) & 0xff] ^
+ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3 ) & 0xff] ^
+ rk[2];
+ t3 =
+ Td0[(s3 >> 24) ] ^
+ Td1[(s2 >> 16) & 0xff] ^
+ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0 ) & 0xff] ^
+ rk[3];
+
+ s0 = t0;
+ s1 = t1;
+ s2 = t2;
+ s3 = t3;
+ rk += 4;
+
+ }
+
+ /*
+ * complete the last round and
+ * map cipher state to byte array block:
+ */
+ t0 =
+ (Td4[(s0 >> 24) ] & 0xff000000) ^
+ (Td4[(s3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(s2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(s1 ) & 0xff] & 0x000000ff);
+ t1 =
+ (Td4[(s1 >> 24) ] & 0xff000000) ^
+ (Td4[(s0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(s3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(s2 ) & 0xff] & 0x000000ff);
+ t2 =
+ (Td4[(s2 >> 24) ] & 0xff000000) ^
+ (Td4[(s1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(s0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(s3 ) & 0xff] & 0x000000ff);
+ t3 =
+ (Td4[(s3 >> 24) ] & 0xff000000) ^
+ (Td4[(s2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(s1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(s0 ) & 0xff] & 0x000000ff);
+
+ if (rounds == Nr) {
+ t0 ^= rk[0];
+ t1 ^= rk[1];
+ t2 ^= rk[2];
+ t3 ^= rk[3];
+ }
+
+ PUTU32(block , t0);
+ PUTU32(block + 4, t1);
+ PUTU32(block + 8, t2);
+ PUTU32(block + 12, t3);
+}
+
+#endif /* INTERMEDIATE_VALUE_KAT */
--- /dev/null
+/**
+ * rijndael-alg-fst.h
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#define MAXKC (256/32)
+#define MAXKB (256/8)
+#define MAXNR 14
+
+#define AES_MAXKC MAXKC
+#define AES_MAXKB MAXKB
+#define AES_MAXNR MAXNR
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]);
+void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]);
+
+#ifdef INTERMEDIATE_VALUE_KAT
+void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds);
+void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds);
+#endif /* INTERMEDIATE_VALUE_KAT */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libhashkit/common.h>
+
+const char * libhashkit_string_hash(hashkit_hash_algorithm_t type)
+{
+ switch(type)
+ {
+ case HASHKIT_HASH_DEFAULT: return "DEFAULT";
+ case HASHKIT_HASH_MD5: return "MD5";
+ case HASHKIT_HASH_CRC: return "CRC";
+ case HASHKIT_HASH_FNV1_64: return "FNV1_64";
+ case HASHKIT_HASH_FNV1A_64: return "FNV1A_64";
+ case HASHKIT_HASH_FNV1_32: return "FNV1_32";
+ case HASHKIT_HASH_FNV1A_32: return "FNV1A_32";
+ case HASHKIT_HASH_HSIEH: return "HSIEH";
+ case HASHKIT_HASH_MURMUR: return "MURMUR";
+ case HASHKIT_HASH_MURMUR3: return "MURMUR3";
+ case HASHKIT_HASH_JENKINS: return "JENKINS";
+ case HASHKIT_HASH_CUSTOM: return "CUSTOM";
+ default:
+ case HASHKIT_HASH_MAX: return "INVALID";
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2009 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+#include <libhashkit/common.h>
+
+const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc)
+{
+ (void)ptr;
+ switch (rc)
+ {
+ case HASHKIT_SUCCESS: return "SUCCESS";
+ case HASHKIT_FAILURE: return "FAILURE";
+ case HASHKIT_MEMORY_ALLOCATION_FAILURE: return "MEMORY ALLOCATION FAILURE";
+ case HASHKIT_INVALID_ARGUMENT: return "INVALID ARGUMENT";
+ case HASHKIT_INVALID_HASH: return "INVALID hashkit_hash_algorithm_t";
+ case HASHKIT_MAXIMUM_RETURN:
+ default:
+ return "INVALID hashkit_return_t";
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libhashkit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libhashkit/common.h>
+
+#include <cassert>
+#include <cstring>
+
+#define HASHKIT_BLOCK_SIZE 1024
+
+struct hashkit_string_st {
+ char *end;
+ size_t current_size;
+ char *string;
+};
+
+inline static bool _string_check(hashkit_string_st *string, size_t need)
+{
+ if (need and need > (size_t)(string->current_size - (size_t)(string->end - string->string)))
+ {
+ size_t current_offset= (size_t) (string->end - string->string);
+
+ /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
+ size_t adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / HASHKIT_BLOCK_SIZE;
+ adjust++;
+
+ size_t new_size= sizeof(char) * (size_t)((adjust * HASHKIT_BLOCK_SIZE) + string->current_size);
+ /* Test for overflow */
+ if (new_size < need)
+ {
+ return false;
+ }
+
+ char *new_value= (char*)realloc(string->string, new_size);
+
+ if (new_value == NULL)
+ {
+ return false;
+ }
+
+ string->string= new_value;
+ string->end= string->string + current_offset;
+
+ string->current_size+= (HASHKIT_BLOCK_SIZE * adjust);
+ }
+
+ return true;
+}
+
+static inline void _init_string(hashkit_string_st *self)
+{
+ self->current_size= 0;
+ self->end= self->string= NULL;
+}
+
+hashkit_string_st *hashkit_string_create(size_t initial_size)
+{
+ hashkit_string_st* self= (hashkit_string_st*)calloc(1, sizeof(hashkit_string_st));
+
+ if (self)
+ {
+ if (_string_check(self, initial_size) == false)
+ {
+ free(self);
+
+ return NULL;
+ }
+ }
+
+ return self;
+}
+
+#if 0
+static bool hashkit_string_append_null(hashkit_string_st *string)
+{
+ if (_string_check(string, 1) == false)
+ {
+ return false;
+ }
+
+ *string->end= 0;
+
+ return true;
+}
+#endif
+
+bool hashkit_string_append_character(hashkit_string_st *string,
+ char character)
+{
+ if (_string_check(string, 1) == false)
+ {
+ return false;
+ }
+
+ *string->end= character;
+ string->end++;
+
+ return true;
+}
+
+bool hashkit_string_append(hashkit_string_st *string,
+ const char *value, size_t length)
+{
+ if (_string_check(string, length) == false)
+ {
+ return false;
+ }
+
+ assert(length <= string->current_size);
+ assert(string->string);
+ assert(string->end >= string->string);
+
+ memcpy(string->end, value, length);
+ string->end+= length;
+
+ return true;
+}
+
+char *hashkit_string_c_copy(hashkit_string_st *string)
+{
+ if (hashkit_string_length(string) == 0)
+ {
+ return NULL;
+ }
+
+ char *c_ptr= static_cast<char *>(malloc((hashkit_string_length(string)+1) * sizeof(char)));
+ if (c_ptr == NULL)
+ {
+ return NULL;
+ }
+
+ memcpy(c_ptr, hashkit_string_c_str(string), hashkit_string_length(string));
+ c_ptr[hashkit_string_length(string)]= 0;
+
+ return c_ptr;
+}
+
+void hashkit_string_reset(hashkit_string_st *string)
+{
+ string->end= string->string;
+}
+
+void hashkit_string_free(hashkit_string_st *ptr)
+{
+ if (ptr == NULL)
+ {
+ return;
+ }
+
+ if (ptr->string)
+ {
+ free(ptr->string);
+ }
+ free(ptr);
+}
+
+bool hashkit_string_resize(hashkit_string_st& string, const size_t need)
+{
+ return _string_check(&string, need);
+}
+
+size_t hashkit_string_length(const hashkit_string_st *self)
+{
+ return size_t(self->end -self->string);
+}
+
+size_t hashkit_string_max_size(const hashkit_string_st *self)
+{
+ return self->current_size;
+}
+
+char *hashkit_string_take(hashkit_string_st *self)
+{
+ assert(self);
+ if (self == NULL)
+ {
+ return NULL;
+ }
+ char *value= self->string;
+
+ _init_string(self);
+
+ return value;
+}
+
+char *hashkit_string_c_str_mutable(hashkit_string_st *self)
+{
+ assert(self);
+ if (self == NULL)
+ {
+ return NULL;
+ }
+ return self->string;
+}
+
+const char *hashkit_string_c_str(const hashkit_string_st* self)
+{
+ assert(self);
+ if (self == NULL)
+ {
+ return NULL;
+ }
+ return self->string;
+}
+
+void hashkit_string_set_length(hashkit_string_st *self, size_t length)
+{
+ assert(self);
+ if (self and _string_check(self, length))
+ {
+ self->end= self->string +length;
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Hashkit library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+hashkit_string_st *hashkit_string_create(size_t initial_size);
+
+bool hashkit_string_append_character(hashkit_string_st *string, char character);
+
+bool hashkit_string_append(hashkit_string_st *string, const char *value, size_t length);
+
+char *hashkit_string_c_copy(hashkit_string_st *string);
+
+void hashkit_string_reset(hashkit_string_st *string);
+
+bool hashkit_string_resize(hashkit_string_st& string, const size_t need);
+
+size_t hashkit_string_max_size(const hashkit_string_st *self);
+
+char *hashkit_string_take(hashkit_string_st *self);
+
+char *hashkit_string_c_str_mutable(hashkit_string_st *self);
+
+void hashkit_string_set_length(hashkit_string_st *self, size_t length);
--- /dev/null
+
+find_package(FLEX)
+find_package(BISON)
+
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/csl)
+bison_target(CSL_PARSER csl/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/csl/parser.cc
+ DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/csl/parser.h
+ )
+flex_target(CSL_SCANNER csl/scanner.l ${CMAKE_CURRENT_BINARY_DIR}/csl/scanner.cc
+ DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/csl/scanner.h
+ )
+add_flex_bison_dependency(CSL_SCANNER CSL_PARSER)
+
+set(LIBMEMCACHED_SOURCES
+ csl/context.cc
+ ${BISON_CSL_PARSER_OUTPUTS}
+ ${FLEX_CSL_SCANNER_OUTPUTS}
+ allocators.cc
+ analyze.cc
+ array.c
+ auto.cc
+ backtrace.cc
+ behavior.cc
+ byteorder.cc
+ callback.cc
+ connect.cc
+ delete.cc
+ do.cc
+ dump.cc
+ encoding_key.cc
+ error.cc
+ exist.cc
+ fetch.cc
+ flag.cc
+ flush.cc
+ flush_buffers.cc
+ get.cc
+ hash.cc
+ hosts.cc
+ initialize_query.cc
+ instance.cc
+ io.cc
+ key.cc
+ memcached.cc
+ namespace.cc
+ options.cc
+ parse.cc
+ poll.cc
+ purge.cc
+ quit.cc
+ response.cc
+ result.cc
+ sasl.cc
+ server.cc
+ server_list.cc
+ stats.cc
+ storage.cc
+ strerror.cc
+ string.cc
+ touch.cc
+ udp.cc
+ verbosity.cc
+ version.cc
+ virtual_bucket.c)
+
+add_library(libmemcached SHARED
+ ${LIBMEMCACHED_SOURCES})
+add_library(memcached ALIAS libmemcached)
+set_target_properties(libmemcached PROPERTIES LIBRARY_OUTPUT_NAME memcached)
+target_link_libraries(libmemcached libhashkit Threads::Threads ${LIBSASL_LIBRARIES} ${CMAKE_DL_LIBS})
+target_include_directories(libmemcached PRIVATE ${LIBSASL_INCLUDEDIR})
+target_compile_definitions(libmemcached PRIVATE -DBUILDING_LIBMEMCACHED)
+
+set_target_properties(libmemcached PROPERTIES SOVERSION ${LIBMEMCACHED_SO_VERSION})
+install(TARGETS libmemcached EXPORT libmemcached
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+export(EXPORT libmemcached)
+install(EXPORT libmemcached DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake)
+
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ FILES_MATCHING REGEX "(memcached|util)\\.h(pp)?"
+ PATTERN csl EXCLUDE
+ PATTERN memcached EXCLUDE
+ PATTERN util EXCLUDE
+ )
+
+# FIXME: dtrace
+
+add_library(libmemcachedinternal STATIC
+ ${LIBMEMCACHED_SOURCES})
+add_library(memcachedinternal ALIAS libmemcachedinternal)
+set_target_properties(libmemcachedinternal PROPERTIES LIBRARY_OUTPUT_NAME memcachedinternal)
+target_link_libraries(libmemcachedinternal libhashkit Threads::Threads ${LIBSASL_LIBRARIES} ${CMAKE_DL_LIBS})
+target_include_directories(libmemcachedinternal PRIVATE ${LIBSASL_INCLUDEDIR})
+target_compile_definitions(libmemcachedinternal PRIVATE -DBUILDING_LIBMEMCACHEDINTERNAL)
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+void _libmemcached_free(const memcached_st*, void *mem, void*)
+{
+ if (mem)
+ {
+ std::free(mem);
+ }
+}
+
+void *_libmemcached_malloc(const memcached_st *, size_t size, void *)
+{
+ return std::malloc(size);
+}
+
+void *_libmemcached_realloc(const memcached_st*, void *mem, size_t size, void *)
+{
+ return std::realloc(mem, size);
+}
+
+void *_libmemcached_calloc(const memcached_st *self, size_t nelem, size_t size, void *context)
+{
+ if (self->allocators.malloc != _libmemcached_malloc)
+ {
+ void *ret= _libmemcached_malloc(self, nelem * size, context);
+ if (ret)
+ {
+ memset(ret, 0, nelem * size);
+ }
+
+ return ret;
+ }
+
+ return std::calloc(nelem, size);
+}
+
+struct memcached_allocator_t memcached_allocators_return_default(void)
+{
+ static struct memcached_allocator_t global_default_allocator= { _libmemcached_calloc, _libmemcached_free, _libmemcached_malloc, _libmemcached_realloc, 0 };
+ return global_default_allocator;
+}
+
+memcached_return_t memcached_set_memory_allocators(memcached_st *shell,
+ memcached_malloc_fn mem_malloc,
+ memcached_free_fn mem_free,
+ memcached_realloc_fn mem_realloc,
+ memcached_calloc_fn mem_calloc,
+ void *context)
+{
+ Memcached* self= memcached2Memcached(shell);
+ if (self == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ /* All should be set, or none should be set */
+ if (mem_malloc == NULL and mem_free == NULL and mem_realloc == NULL and mem_calloc == NULL)
+ {
+ self->allocators= memcached_allocators_return_default();
+ }
+ else if (mem_malloc == NULL or mem_free == NULL or mem_realloc == NULL or mem_calloc == NULL)
+ {
+ return memcached_set_error(*self, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("NULL parameter provided for one or more allocators"));
+ }
+ else
+ {
+ self->allocators.malloc= mem_malloc;
+ self->allocators.free= mem_free;
+ self->allocators.realloc= mem_realloc;
+ self->allocators.calloc= mem_calloc;
+ self->allocators.context= context;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+void *memcached_get_memory_allocators_context(const memcached_st *shell)
+{
+ const Memcached* self= memcached2Memcached(shell);
+ if (self)
+ {
+ return self->allocators.context;
+ }
+
+ return NULL;
+}
+
+void memcached_get_memory_allocators(const memcached_st *shell,
+ memcached_malloc_fn *mem_malloc,
+ memcached_free_fn *mem_free,
+ memcached_realloc_fn *mem_realloc,
+ memcached_calloc_fn *mem_calloc)
+{
+ const Memcached* self= memcached2Memcached(shell);
+ if (self)
+ {
+ if (mem_malloc)
+ {
+ *mem_malloc= self->allocators.malloc;
+ }
+
+ if (mem_free)
+ {
+ *mem_free= self->allocators.free;
+ }
+
+ if (mem_realloc)
+ {
+ *mem_realloc= self->allocators.realloc;
+ }
+
+ if (mem_calloc)
+ {
+ *mem_calloc= self->allocators.calloc;
+ }
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+void _libmemcached_free(const memcached_st *ptr, void *mem, void *context);
+
+void *_libmemcached_malloc(const memcached_st *ptr, const size_t size, void *context);
+
+void *_libmemcached_realloc(const memcached_st *ptr, void *mem, const size_t size, void *context);
+
+void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context);
+
+struct memcached_allocator_t memcached_allocators_return_default(void);
--- /dev/null
+#include <libmemcached/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 *shell,
+ memcached_stat_st *memc_stat,
+ memcached_return_t *error)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ uint64_t total_items= 0, total_bytes= 0;
+ uint64_t total_get_cmds= 0, total_get_hits= 0;
+
+ if (memc == NULL or memc_stat == NULL)
+ {
+ return NULL;
+ }
+
+ memcached_return_t not_used;
+ if (error == NULL)
+ {
+ error= ¬_used;
+ }
+
+ *error= MEMCACHED_SUCCESS;
+ uint32_t server_count= memcached_server_count(memc);
+ memcached_analysis_st *result= (memcached_analysis_st*)libmemcached_xcalloc(memc,
+ memcached_server_count(memc),
+ memcached_analysis_st);
+
+ if (result == NULL)
+ {
+ *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return NULL;
+ }
+
+ result->root= memc;
+
+ for (uint32_t x= 0; x < server_count; x++)
+ {
+ calc_largest_consumption(result, x, memc_stat[x].bytes);
+ calc_oldest_node(result, x, uint32_t(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)
+{
+ libmemcached_free(ptr->root, ptr);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <assert.h>
+#include <iso646.h>
+
+struct memcached_array_st
+{
+ Memcached *root;
+ size_t size;
+ char c_str[];
+};
+
+
+memcached_array_st *memcached_array_clone(Memcached *memc, const memcached_array_st *original)
+{
+ if (original)
+ {
+ return memcached_strcpy(memc, original->c_str, original->size);
+ }
+
+ return NULL;
+}
+
+memcached_array_st *memcached_strcpy(Memcached *memc, const char *str, size_t str_length)
+{
+ assert(memc);
+ assert(str);
+ assert(str_length);
+
+ memcached_array_st *array= (struct memcached_array_st *)libmemcached_malloc(memc, sizeof(struct memcached_array_st) +str_length +1);
+
+ if (array)
+ {
+ array->root= memc;
+ array->size= str_length; // We don't count the NULL ending
+ memcpy(array->c_str, str, str_length);
+ array->c_str[str_length]= 0;
+ }
+
+ return array;
+}
+
+bool memcached_array_is_null(memcached_array_st *array)
+{
+ if (array)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+memcached_string_t memcached_array_to_string(memcached_array_st *array)
+{
+ assert(array);
+ assert(array->c_str);
+ assert(array->size);
+ memcached_string_t tmp;
+ tmp.c_str= array->c_str;
+ tmp.size= array->size;
+
+ return tmp;
+}
+
+void memcached_array_free(memcached_array_st *array)
+{
+ if (array)
+ {
+ WATCHPOINT_ASSERT(array->root);
+ libmemcached_free(array->root, array);
+ }
+}
+
+size_t memcached_array_size(memcached_array_st *array)
+{
+ if (array)
+ {
+ return array->size;
+ }
+
+ return 0;
+}
+
+const char *memcached_array_string(memcached_array_st *array)
+{
+ if (array)
+ {
+ return array->c_str;
+ }
+
+ return NULL;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+memcached_array_st *memcached_array_clone(Memcached* memc, const memcached_array_st *original);
+
+memcached_array_st *memcached_strcpy(Memcached* memc, const char *str, size_t str_length);
+
+void memcached_array_free(memcached_array_st *array);
+
+size_t memcached_array_size(memcached_array_st *array);
+
+const char *memcached_array_string(memcached_array_st *array);
+
+memcached_string_t memcached_array_to_string(memcached_array_st *array);
+
+bool memcached_array_is_null(memcached_array_st *array);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#ifdef __cplusplus
+#define memcached_print_array(X) static_cast<int>(memcached_array_size(X)), memcached_array_string(X)
+#define memcached_param_array(X) memcached_array_string(X), memcached_array_size(X)
+#else
+#define memcached_print_array(X) (int)memcached_array_size((X)), memcached_array_string((X))
+#define memcached_param_array(X) memcached_array_string(X), memcached_array_size(X)
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * libmcachedd client library.
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+# include <cassert>
+#else
+# include <assert.h>
+#endif // __cplusplus
+
+#ifdef NDEBUG
+# define assert_msg(__expr, __mesg) (void)(__expr); (void)(__mesg);
+# define assert_vmsg(__expr, __mesg, ...) (void)(__expr); (void)(__mesg);
+#else
+
+# ifdef _WIN32
+# include <malloc.h>
+# else
+# include <alloca.h>
+# endif
+
+#ifdef __cplusplus
+# include <cstdarg>
+# include <cstdio>
+#else
+# include <stdarg.h>
+# include <stdio.h>
+#endif
+
+# include <libmemcached/backtrace.hpp>
+
+# define assert_msg(__expr, __mesg) \
+do \
+{ \
+ if (not (__expr)) \
+ { \
+ fprintf(stderr, "\n%s:%d Assertion \"%s\" failed for function \"%s\" likely for %s\n", __FILE__, __LINE__, #__expr, __func__, (#__mesg));\
+ custom_backtrace(); \
+ abort(); \
+ } \
+} while (0)
+
+# define assert_vmsg(__expr, __mesg, ...) \
+do \
+{ \
+ if (not (__expr)) \
+ { \
+ size_t ask= snprintf(0, 0, (__mesg), __VA_ARGS__); \
+ ask++; \
+ char *_error_message= (char*)alloca(sizeof(char) * ask); \
+ size_t _error_message_size= snprintf(_error_message, ask, (__mesg), __VA_ARGS__); \
+ fprintf(stderr, "\n%s:%d Assertion '%s' failed for function '%s' [ %.*s ]\n", __FILE__, __LINE__, #__expr, __func__, int(_error_message_size), _error_message);\
+ custom_backtrace(); \
+ abort(); \
+ } \
+} while (0)
+
+#endif // NDEBUG
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static void auto_response(memcached_instance_st* instance, const bool reply, memcached_return_t& rc, uint64_t* value)
+{
+ // If the message was successfully sent, then get the response, otherwise
+ // fail.
+ if (memcached_success(rc))
+ {
+ if (reply == false)
+ {
+ *value= UINT64_MAX;
+ return;
+ }
+
+ rc= memcached_response(instance, &instance->root->result);
+ }
+
+ if (memcached_fatal(rc))
+ {
+ assert(memcached_last_error(instance->root) != MEMCACHED_SUCCESS);
+ *value= UINT64_MAX;
+ }
+ else if (memcached_failed(rc))
+ {
+ *value= UINT64_MAX;
+ }
+ else
+ {
+ assert(memcached_last_error(instance->root) != MEMCACHED_NOTFOUND);
+ *value= instance->root->result.numeric_value;
+ }
+}
+
+static memcached_return_t text_incr_decr(memcached_instance_st* instance,
+ const bool is_incr,
+ const char *key, size_t key_length,
+ const uint64_t offset,
+ const bool reply)
+{
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+ int send_length= snprintf(buffer, sizeof(buffer), " %" PRIu64, offset);
+ if (size_t(send_length) >= sizeof(buffer) or send_length < 0)
+ {
+ return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
+ }
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { memcached_literal_param("incr ") },
+ { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
+ { key, key_length },
+ { buffer, size_t(send_length) },
+ { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
+ { memcached_literal_param("\r\n") }
+ };
+
+ if (is_incr == false)
+ {
+ vector[1].buffer= "decr ";
+ }
+
+ return memcached_vdo(instance, vector, 7, true);
+}
+
+static memcached_return_t binary_incr_decr(memcached_instance_st* instance,
+ protocol_binary_command cmd,
+ const char *key, const size_t key_length,
+ const uint64_t offset,
+ const uint64_t initial,
+ const uint32_t expiration,
+ const bool reply)
+{
+ if (reply == false)
+ {
+ 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}};
+
+ initialize_binary_request(instance, request.message.header);
+
+ request.message.header.request.opcode= cmd;
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(instance->root->_namespace)));
+ request.message.header.request.extlen= 20;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(instance->root->_namespace) +request.message.header.request.extlen));
+ request.message.body.delta= memcached_htonll(offset);
+ request.message.body.initial= memcached_htonll(initial);
+ request.message.body.expiration= htonl((uint32_t) expiration);
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { request.bytes, sizeof(request.bytes) },
+ { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
+ { key, key_length }
+ };
+
+ return memcached_vdo(instance, vector, 4, true);
+}
+
+memcached_return_t memcached_increment(memcached_st *memc,
+ const char *key, size_t key_length,
+ uint32_t offset,
+ uint64_t *value)
+{
+ return memcached_increment_by_key(memc, key, key_length, key, key_length, offset, value);
+}
+
+static memcached_return_t increment_decrement_by_key(const protocol_binary_command command,
+ Memcached *memc,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ uint64_t offset,
+ uint64_t *value)
+{
+ uint64_t local_value;
+ if (value == NULL)
+ {
+ value= &local_value;
+ }
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(memc, true)))
+ {
+ return rc;
+ }
+
+ if (memcached_is_encrypted(memc))
+ {
+ return memcached_set_error(*memc, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
+ memcached_literal_param("Operation not allowed while encyrption is enabled"));
+ }
+
+ if (memcached_failed(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
+ {
+ return memcached_last_error(memc);
+ }
+
+ uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
+ memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
+
+ bool reply= memcached_is_replying(instance->root);
+
+ if (memcached_is_binary(memc))
+ {
+ rc= binary_incr_decr(instance, command,
+ key, key_length,
+ uint64_t(offset), 0, MEMCACHED_EXPIRATION_NOT_ADD,
+ reply);
+ }
+ else
+ {
+ rc= text_incr_decr(instance,
+ command == PROTOCOL_BINARY_CMD_INCREMENT ? true : false,
+ key, key_length,
+ offset, reply);
+ }
+
+ auto_response(instance, reply, rc, value);
+
+ return rc;
+}
+
+static memcached_return_t increment_decrement_with_initial_by_key(const protocol_binary_command command,
+ Memcached *memc,
+ const char *group_key,
+ size_t group_key_length,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value)
+{
+ uint64_t local_value;
+ if (value == NULL)
+ {
+ value= &local_value;
+ }
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(memc, true)))
+ {
+ return rc;
+ }
+
+ if (memcached_is_encrypted(memc))
+ {
+ return memcached_set_error(*memc, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
+ memcached_literal_param("Operation not allowed while encryption is enabled"));
+ }
+
+ if (memcached_failed(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
+ {
+ return memcached_last_error(memc);
+ }
+
+ uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
+ memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
+
+ bool reply= memcached_is_replying(instance->root);
+
+ if (memcached_is_binary(memc))
+ {
+ rc= binary_incr_decr(instance, command,
+ key, key_length,
+ offset, initial, uint32_t(expiration),
+ reply);
+
+ }
+ else
+ {
+ rc= memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("memcached_increment_with_initial_by_key() is not supported via the ASCII protocol"));
+ }
+
+ auto_response(instance, reply, rc, value);
+
+ return rc;
+}
+
+memcached_return_t memcached_decrement(memcached_st *memc,
+ const char *key, size_t key_length,
+ uint32_t offset,
+ uint64_t *value)
+{
+ return memcached_decrement_by_key(memc, key, key_length, key, key_length, offset, value);
+}
+
+
+memcached_return_t memcached_increment_by_key(memcached_st *shell,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ uint64_t offset,
+ uint64_t *value)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ LIBMEMCACHED_MEMCACHED_INCREMENT_START();
+ memcached_return_t rc= increment_decrement_by_key(PROTOCOL_BINARY_CMD_INCREMENT,
+ memc,
+ group_key, group_key_length,
+ key, key_length,
+ offset, value);
+
+ LIBMEMCACHED_MEMCACHED_INCREMENT_END();
+
+ return rc;
+}
+
+memcached_return_t memcached_decrement_by_key(memcached_st *shell,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ uint64_t offset,
+ uint64_t *value)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ LIBMEMCACHED_MEMCACHED_DECREMENT_START();
+ memcached_return_t rc= increment_decrement_by_key(PROTOCOL_BINARY_CMD_DECREMENT,
+ memc,
+ group_key, group_key_length,
+ key, key_length,
+ offset, value);
+ LIBMEMCACHED_MEMCACHED_DECREMENT_END();
+
+ return rc;
+}
+
+memcached_return_t memcached_increment_with_initial(memcached_st *memc,
+ 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(memc, key, key_length,
+ key, key_length,
+ offset, initial, expiration, value);
+}
+
+memcached_return_t memcached_increment_with_initial_by_key(memcached_st *shell,
+ const char *group_key,
+ size_t group_key_length,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value)
+{
+ LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
+ Memcached* memc= memcached2Memcached(shell);
+ memcached_return_t rc= increment_decrement_with_initial_by_key(PROTOCOL_BINARY_CMD_INCREMENT,
+ memc,
+ group_key, group_key_length,
+ key, key_length,
+ offset, initial, expiration, value);
+ LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
+
+ return rc;
+}
+
+memcached_return_t memcached_decrement_with_initial(memcached_st *memc,
+ 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(memc, key, key_length,
+ key, key_length,
+ offset, initial, expiration, value);
+}
+
+memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *shell,
+ const char *group_key,
+ size_t group_key_length,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value)
+{
+ LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
+ Memcached* memc= memcached2Memcached(shell);
+ memcached_return_t rc= increment_decrement_with_initial_by_key(PROTOCOL_BINARY_CMD_DECREMENT,
+ memc,
+ group_key, group_key_length,
+ key, key_length,
+ offset, initial, expiration, value);
+
+ LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
+
+ return rc;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached client library.
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "mem_config.h"
+
+#include "libmemcached/backtrace.hpp"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#if defined(HAVE_SHARED_ENABLED) && HAVE_SHARED_ENABLED
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+#ifdef HAVE_GCC_ABI_DEMANGLE
+# include <cxxabi.h>
+# define USE_DEMANGLE 1
+#else
+# define USE_DEMANGLE 0
+#endif
+
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+
+const int MAX_DEPTH= 50;
+
+void custom_backtrace(void)
+{
+#ifdef HAVE_EXECINFO_H
+ void *backtrace_buffer[MAX_DEPTH +1];
+
+ int stack_frames= backtrace(backtrace_buffer, MAX_DEPTH);
+ if (stack_frames)
+ {
+ char **symbollist= backtrace_symbols(backtrace_buffer, stack_frames);
+ if (symbollist)
+ {
+ for (int x= 0; x < stack_frames; x++)
+ {
+ bool was_demangled= false;
+
+ if (USE_DEMANGLE)
+ {
+#ifdef HAVE_DLFCN_H
+ Dl_info dlinfo;
+ if (dladdr(backtrace_buffer[x], &dlinfo))
+ {
+ char demangled_buffer[1024];
+ const char *called_in= "<unresolved>";
+ if (dlinfo.dli_sname)
+ {
+ size_t demangled_size= sizeof(demangled_buffer);
+ int status;
+ char* demangled;
+ if ((demangled= abi::__cxa_demangle(dlinfo.dli_sname, demangled_buffer, &demangled_size, &status)))
+ {
+ called_in= demangled;
+ fprintf(stderr, "---> demangled: %s -> %s\n", demangled_buffer, demangled);
+ }
+ else
+ {
+ called_in= dlinfo.dli_sname;
+ }
+
+ was_demangled= true;
+ fprintf(stderr, "#%d %p in %s at %s\n",
+ x, backtrace_buffer[x],
+ called_in,
+ dlinfo.dli_fname);
+ }
+ }
+#endif
+ }
+
+ if (was_demangled == false)
+ {
+ fprintf(stderr, "?%d %p in %s\n", x, backtrace_buffer[x], symbollist[x]);
+ }
+ }
+
+ ::free(symbollist);
+ }
+ }
+#endif // HAVE_EXECINFO_H
+}
+
+#else // HAVE_SHARED_ENABLED
+
+void custom_backtrace(void)
+{
+ fprintf(stderr, "Backtrace null function called\n");
+}
+#endif // AX_ENABLE_BACKTRACE
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * libmcachedd client library.
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void custom_backtrace(void);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <libmemcached/options.hpp>
+#include <libmemcached/virtual_bucket.h>
+
+#include <ctime>
+#include <sys/types.h>
+
+bool memcached_is_consistent_distribution(const Memcached* memc)
+{
+ switch (memc->distribution)
+ {
+ case MEMCACHED_DISTRIBUTION_CONSISTENT:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
+ return true;
+
+ case MEMCACHED_DISTRIBUTION_MODULA:
+ case MEMCACHED_DISTRIBUTION_RANDOM:
+ case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
+ break;
+ }
+
+ return false;
+}
+
+/*
+ This function is used to modify the behavior of running client.
+
+ We quit all connections so we can reset the sockets.
+*/
+
+memcached_return_t memcached_behavior_set(memcached_st *shell,
+ const memcached_behavior_t flag,
+ uint64_t data)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ switch (flag)
+ {
+ case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
+ ptr->number_of_replicas= (uint32_t)data;
+ break;
+
+ case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
+ ptr->io_msg_watermark= (uint32_t) data;
+ break;
+
+ case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
+ ptr->io_bytes_watermark= (uint32_t)data;
+ break;
+
+ case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
+ ptr->io_key_prefetch = (uint32_t)data;
+ break;
+
+ case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
+ ptr->snd_timeout= (int32_t)data;
+ break;
+
+ case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
+ ptr->rcv_timeout= (int32_t)data;
+ break;
+
+ case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
+ ptr->flags.auto_eject_hosts= bool(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
+ if (data == 0)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT requires a value greater then zero."));
+ }
+ ptr->server_failure_limit= uint32_t(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT:
+ ptr->server_timeout_limit= uint32_t(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
+ send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
+ if (data)
+ {
+ ptr->flags.verify_key= false;
+ }
+ ptr->flags.binary_protocol= bool(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+ ptr->flags.support_cas= bool(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_NO_BLOCK:
+ ptr->flags.no_block= bool(data);
+ send_quit(ptr);
+ break;
+
+ case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
+ if (memcached_is_udp(ptr))
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_BUFFER_REQUESTS cannot be set while MEMCACHED_BEHAVIOR_USE_UDP is enabled."));
+ }
+ ptr->flags.buffer_requests= bool(data);
+ send_quit(ptr);
+ break;
+
+ case MEMCACHED_BEHAVIOR_USE_UDP:
+ send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
+ ptr->flags.use_udp= bool(data);
+ if (bool(data))
+ {
+ ptr->flags.reply= false;
+ ptr->flags.buffer_requests= false;
+ }
+ else
+ {
+ ptr->flags.reply= true;
+ }
+ break;
+
+ case MEMCACHED_BEHAVIOR_TCP_NODELAY:
+ ptr->flags.tcp_nodelay= bool(data);
+ send_quit(ptr);
+ break;
+
+ case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
+ ptr->flags.tcp_keepalive= bool(data);
+ send_quit(ptr);
+ break;
+
+ case MEMCACHED_BEHAVIOR_DISTRIBUTION:
+ return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data);
+
+ case MEMCACHED_BEHAVIOR_KETAMA:
+ {
+ if (data) // Turn on
+ {
+ return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
+ }
+
+ return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA);
+ }
+
+ case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
+ {
+ if (bool(data) == false)
+ {
+ return memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_KETAMA, true);
+ }
+
+ (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
+ (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
+ /**
+ @note We try to keep the same distribution going. This should be deprecated and rewritten.
+ */
+ return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED);
+ }
+
+ case MEMCACHED_BEHAVIOR_HASH:
+ return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data));
+
+ case MEMCACHED_BEHAVIOR_KETAMA_HASH:
+ return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data));
+
+ case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
+ return memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_CACHE_LOOKUPS has been deprecated."));
+
+ case MEMCACHED_BEHAVIOR_VERIFY_KEY:
+ if (ptr->flags.binary_protocol)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled."));
+ }
+ ptr->flags.verify_key= bool(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+ {
+ ptr->flags.use_sort_hosts= bool(data);
+ return run_distribution(ptr);
+ }
+
+ 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_DEAD_TIMEOUT:
+ ptr->dead_timeout= int32_t(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
+ ptr->send_size= (int32_t)data;
+ send_quit(ptr);
+ break;
+
+ case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
+ ptr->recv_size= (int32_t)data;
+ send_quit(ptr);
+ break;
+
+ case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
+ ptr->tcp_keepidle= (uint32_t)data;
+ send_quit(ptr);
+ break;
+
+ case MEMCACHED_BEHAVIOR_USER_DATA:
+ return memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
+
+ case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
+ ptr->flags.hash_with_namespace= bool(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_NOREPLY:
+ if (memcached_is_udp(ptr) and bool(data) == false)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_NOREPLY cannot be disabled while MEMCACHED_BEHAVIOR_USE_UDP is enabled."));
+ }
+ // We reverse the logic here to make it easier to understand throughout the
+ // code.
+ ptr->flags.reply= bool(data) ? false : true;
+ break;
+
+ case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
+ ptr->flags.auto_eject_hosts= bool(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
+ srandom((uint32_t) time(NULL));
+ ptr->flags.randomize_replica_read= bool(data);
+ break;
+
+ case MEMCACHED_BEHAVIOR_CORK:
+ return memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_CORK is now incorporated into the driver by default."));
+
+ case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()"));
+
+ case MEMCACHED_BEHAVIOR_MAX:
+ default:
+ /* Shouldn't get here */
+ assert_msg(0, "Invalid behavior passed to memcached_behavior_set()");
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("Invalid behavior passed to memcached_behavior_set()"));
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+bool _is_auto_eject_host(const memcached_st *ptr)
+{
+ return ptr->flags.auto_eject_hosts;
+}
+
+uint64_t memcached_behavior_get(memcached_st *shell,
+ const memcached_behavior_t flag)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ switch (flag)
+ {
+ case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
+ return ptr->number_of_replicas;
+
+ case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
+ return ptr->io_msg_watermark;
+
+ case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
+ return ptr->io_bytes_watermark;
+
+ case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
+ return ptr->io_key_prefetch;
+
+ case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
+ return ptr->flags.binary_protocol;
+
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+ return ptr->flags.support_cas;
+
+ case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
+ return true;
+
+ case MEMCACHED_BEHAVIOR_NO_BLOCK:
+ return ptr->flags.no_block;
+
+ case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
+ return ptr->flags.buffer_requests;
+
+ case MEMCACHED_BEHAVIOR_USE_UDP:
+ return memcached_is_udp(ptr);
+
+ 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:
+ if (memcached_is_consistent_distribution(ptr))
+ {
+ return memcached_is_weighted_ketama(ptr);
+ }
+ return false;
+
+ case MEMCACHED_BEHAVIOR_DISTRIBUTION:
+ return ptr->distribution;
+
+ case MEMCACHED_BEHAVIOR_KETAMA:
+ return memcached_is_consistent_distribution(ptr);
+
+ case MEMCACHED_BEHAVIOR_HASH:
+ return hashkit_get_function(&ptr->hashkit);
+
+ case MEMCACHED_BEHAVIOR_KETAMA_HASH:
+ return hashkit_get_function(&ptr->hashkit);
+
+ case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
+ return ptr->flags.auto_eject_hosts;
+
+ case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
+ return ptr->server_failure_limit;
+
+ case MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT:
+ return ptr->server_timeout_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_DEAD_TIMEOUT:
+ return uint64_t(ptr->dead_timeout);
+
+ case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
+ return (uint64_t)ptr->snd_timeout;
+
+ case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
+ return (uint64_t)ptr->rcv_timeout;
+
+ case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
+ return (uint64_t)ptr->tcp_keepidle;
+
+ case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
+ {
+ int sock_size= 0;
+ socklen_t sock_length= sizeof(int);
+
+ if (ptr->send_size != -1) // If value is -1 then we are using the default
+ {
+ return (uint64_t) ptr->send_size;
+ }
+
+ memcached_instance_st* instance= memcached_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_failed(memcached_connect(instance)))
+ {
+ return 0;
+ }
+
+ if (memcached_failed(memcached_io_wait_for_write(instance)))
+ {
+ return 0;
+ }
+
+ if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, (char*)&sock_size, &sock_length) < 0)
+ {
+ memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
+ 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);
+
+ if (ptr->recv_size != -1) // If value is -1 then we are using the default
+ return (uint64_t) ptr->recv_size;
+
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, 0);
+
+ /**
+ @note REFACTOR
+ */
+ if (instance)
+ {
+ /* We just try the first host, and if it is down we return zero */
+ if (memcached_failed(memcached_connect(instance)))
+ {
+ return 0;
+ }
+
+ if (memcached_failed(memcached_io_wait_for_write(instance)))
+ {
+ return 0;
+ }
+
+ if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, (char*)&sock_size, &sock_length) < 0)
+ {
+ memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
+ return 0; /* Zero means error */
+ }
+ }
+
+ return (uint64_t) sock_size;
+ }
+
+ case MEMCACHED_BEHAVIOR_USER_DATA:
+ memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
+ return 0;
+
+ case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
+ return ptr->flags.hash_with_namespace;
+
+ case MEMCACHED_BEHAVIOR_NOREPLY:
+ return ptr->flags.reply ? false : true;
+
+ case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
+ return ptr->flags.auto_eject_hosts;
+
+ case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
+ return ptr->flags.randomize_replica_read;
+
+ case MEMCACHED_BEHAVIOR_CORK:
+#ifdef HAVE_MSG_MORE
+ return true;
+#else
+ return false;
+#endif
+
+ case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
+ return ptr->flags.tcp_keepalive;
+
+ case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
+ return bool(memcached_parse_filename(ptr));
+
+ case MEMCACHED_BEHAVIOR_MAX:
+ default:
+ assert_msg(0, "Invalid behavior passed to memcached_behavior_get()");
+ return 0;
+ }
+
+ /* NOTREACHED */
+}
+
+
+memcached_return_t memcached_behavior_set_distribution(memcached_st *shell, memcached_server_distribution_t type)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ switch (type)
+ {
+ case MEMCACHED_DISTRIBUTION_MODULA:
+ break;
+
+ case MEMCACHED_DISTRIBUTION_CONSISTENT:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+ memcached_set_weighted_ketama(ptr, false);
+ break;
+
+ case MEMCACHED_DISTRIBUTION_RANDOM:
+ break;
+
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+ break;
+
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
+ memcached_set_weighted_ketama(ptr, true);
+ break;
+
+ case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
+ break;
+
+ default:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("Invalid memcached_server_distribution_t"));
+ }
+ ptr->distribution= type;
+
+ return run_distribution(ptr);
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
+
+
+memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *shell)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ return ptr->distribution;
+ }
+
+ return MEMCACHED_DISTRIBUTION_CONSISTENT_MAX;
+}
+
+memcached_return_t memcached_behavior_set_key_hash(memcached_st *shell, memcached_hash_t type)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ if (hashkit_success(hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type)))
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("Invalid memcached_hash_t()"));
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
+
+memcached_hash_t memcached_behavior_get_key_hash(memcached_st *shell)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
+ }
+
+ return MEMCACHED_HASH_MAX;
+}
+
+memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *shell, memcached_hash_t type)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ if (hashkit_success(hashkit_set_distribution_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type)))
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("Invalid memcached_hash_t()"));
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
+
+memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *shell)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
+ }
+
+ return MEMCACHED_HASH_MAX;
+}
+
+const char *libmemcached_string_behavior(const memcached_behavior_t flag)
+{
+ switch (flag)
+ {
+ case MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT";
+ case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK";
+ case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY";
+ case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH";
+ case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA";
+ case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE";
+ case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE";
+ case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS";
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS";
+ case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION";
+ case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS";
+ case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA";
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS";
+ case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY";
+ case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_DEAD_TIMEOUT: return "MEMCACHED_BEHAVIOR_DEAD_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED";
+ case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH";
+ case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL";
+ case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT";
+ case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK";
+ case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK";
+ case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH";
+ case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY";
+ case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY";
+ case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP";
+ case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS";
+ case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: return "MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS";
+ case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS";
+ case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ";
+ case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK";
+ case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE";
+ case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE";
+ case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE";
+ default:
+ case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t";
+ }
+}
+
+const char *libmemcached_string_distribution(const memcached_server_distribution_t flag)
+{
+ switch (flag)
+ {
+ case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA";
+ case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: return "MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED";
+ case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: return "MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET";
+ default:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t";
+ }
+}
+
+memcached_return_t memcached_bucket_set(memcached_st *shell,
+ const uint32_t *host_map,
+ const uint32_t *forward_map,
+ const uint32_t buckets,
+ const uint32_t replicas)
+{
+ Memcached* self= memcached2Memcached(shell);
+ memcached_return_t rc;
+
+ if (self == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (host_map == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ memcached_server_distribution_t old= memcached_behavior_get_distribution(self);
+
+ if (memcached_failed(rc =memcached_behavior_set_distribution(self, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET)))
+ {
+ return rc;
+ }
+
+ if (memcached_failed(rc= memcached_virtual_bucket_create(self, host_map, forward_map, buckets, replicas)))
+ {
+ memcached_behavior_set_distribution(self, old);
+ }
+
+ return rc;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+bool memcached_is_consistent_distribution(const memcached_st*);
+bool _is_auto_eject_host(const memcached_st *ptr);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "mem_config.h"
+#include "libmemcached/byteorder.h"
+
+/* Byte swap a 64-bit number. */
+#ifndef swap64
+static inline uint64_t swap64(uint64_t in)
+{
+#ifndef WORDS_BIGENDIAN
+ /* Little endian, flip the bytes around until someone makes a faster/better
+ * way to do this. */
+ uint64_t rv= 0;
+ for (uint8_t x= 0; x < 8; ++x)
+ {
+ rv= (rv << 8) | (in & 0xff);
+ in >>= 8;
+ }
+ return rv;
+#else
+ /* big-endian machines don't need byte swapping */
+ return in;
+#endif // WORDS_BIGENDIAN
+}
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+uint64_t memcached_ntohll(uint64_t value)
+{
+#ifdef HAVE_HTONLL
+ return ntohll(value);
+#else
+ return swap64(value);
+#endif
+}
+
+uint64_t memcached_htonll(uint64_t value)
+{
+#ifdef HAVE_HTONLL
+ return htonll(value);
+#else
+ return swap64(value);
+#endif
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint64_t memcached_ntohll(uint64_t);
+
+uint64_t memcached_htonll(uint64_t);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Change any of the possible callbacks.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <sys/types.h>
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+
+/*
+ These functions provide data and function callback support
+*/
+
+memcached_return_t memcached_callback_set(memcached_st *shell,
+ const memcached_callback_t flag,
+ const void *data)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ switch (flag)
+ {
+ case MEMCACHED_CALLBACK_PREFIX_KEY:
+ {
+ return memcached_set_namespace(*ptr, (char*)data, data ? strlen((char*)data) : 0);
+ }
+
+ case MEMCACHED_CALLBACK_USER_DATA:
+ {
+ ptr->user_data= const_cast<void *>(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;
+ }
+
+ 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:
+ {
+ if (data) // NULL would mean we are disabling.
+ {
+ if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS))
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Delete triggers cannot be used if buffering is enabled"));
+ }
+
+ if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_NOREPLY))
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Delete triggers cannot be used if MEMCACHED_BEHAVIOR_NOREPLY is set"));
+ }
+ }
+
+ memcached_trigger_delete_key_fn func= *(memcached_trigger_delete_key_fn *)&data;
+ ptr->delete_trigger= func;
+ break;
+ }
+
+ case MEMCACHED_CALLBACK_MAX:
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid callback supplied"));
+ }
+
+ return MEMCACHED_SUCCESS;
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
+
+void *memcached_callback_get(memcached_st *shell,
+ const memcached_callback_t flag,
+ memcached_return_t *error)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ memcached_return_t local_error;
+ if (error == NULL)
+ {
+ error = &local_error;
+ }
+
+ if (ptr == NULL)
+ {
+ *error= MEMCACHED_INVALID_ARGUMENTS;
+ return NULL;
+ }
+
+ switch (flag)
+ {
+ case MEMCACHED_CALLBACK_PREFIX_KEY:
+ {
+ *error= MEMCACHED_SUCCESS;
+ if (ptr->_namespace)
+ {
+ return (void *)memcached_array_string(ptr->_namespace);
+ }
+ return NULL;
+ }
+
+ case MEMCACHED_CALLBACK_USER_DATA:
+ {
+ *error= ptr->user_data ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return (void *)ptr->user_data;
+ }
+
+ case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
+ {
+ *error= ptr->on_cleanup ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return *(void **)&ptr->on_cleanup;
+ }
+
+ case MEMCACHED_CALLBACK_CLONE_FUNCTION:
+ {
+ *error= ptr->on_clone ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return *(void **)&ptr->on_clone;
+ }
+
+ 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:
+ break;
+ }
+
+ assert_msg(0, "Invalid callback passed to memcached_callback_get()");
+ *error= MEMCACHED_FAILURE;
+ return NULL;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached Client and Server
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+test_return_t test_MEMCACHED_CALLBACK_DELETE_TRIGGER(memcached_st *);
+
+test_return_t test_MEMCACHED_CALLBACK_DELETE_TRIGGER_and_MEMCACHED_BEHAVIOR_NOREPLY(memcached_st *);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ Common include file for libmemached
+*/
+
+#pragma once
+
+#include <mem_config.h>
+
+#ifdef __cplusplus
+# include <cstddef>
+# include <cstdio>
+# include <cstdlib>
+# include <cstring>
+# include <ctime>
+# include <cctype>
+# include <cerrno>
+# include <climits>
+#else
+# ifdef HAVE_STDDEF_H
+# include <stddef.h>
+# endif
+# ifdef HAVE_STDLIB_H
+# include <stdio.h>
+# endif
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+# include <string.h>
+# ifdef HAVE_TIME_H
+# include <time.h>
+# endif
+# ifdef HAVE_ERRNO_H
+# include <errno.h>
+# endif
+# ifdef HAVE_LIMITS_H
+# include <limits.h>
+# endif
+#endif
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+
+#if defined(_WIN32)
+# include "libmemcached/windows.hpp"
+#endif
+
+#include <libmemcached-1.0/memcached.h>
+#include "libmemcached/watchpoint.h"
+#include "libmemcached/is.h"
+typedef struct memcached_st Memcached;
+
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#else
+# include "libmemcached/poll.h"
+#endif
+
+#ifdef __cplusplus
+memcached_instance_st* memcached_instance_fetch(memcached_st *ptr, uint32_t server_key);
+#endif
+
+/* These are private not to be installed headers */
+#include "libmemcached/error.hpp"
+#include "libmemcached/memory.h"
+#include "libmemcached/io.h"
+#ifdef __cplusplus
+# include "libmemcached/string.hpp"
+# include "libmemcachedprotocol-0.0/binary.h"
+# include "libmemcached/io.hpp"
+# include "libmemcached/udp.hpp"
+# include "libmemcached/do.hpp"
+# include "libmemcached/socket.hpp"
+# include "libmemcached/connect.hpp"
+# include "libmemcached/allocators.hpp"
+# include "libmemcached/hash.hpp"
+# include "libmemcached/quit.hpp"
+# include "libmemcached/instance.hpp"
+# include "libmemcached/server_instance.h"
+# include "libmemcached/server.hpp"
+# include "libmemcached/flag.hpp"
+# include "libmemcached/behavior.hpp"
+# include "libmemcached/sasl.hpp"
+# include "libmemcached/server_list.hpp"
+#endif
+
+#include "libmemcached/internal.h"
+#include "libmemcached/array.h"
+#include "libmemcached/libmemcached_probes.h"
+#include "libmemcached/byteorder.h"
+#include "libmemcached/initialize_query.h"
+
+#ifdef __cplusplus
+# include "libmemcached/response.h"
+# include "libmemcached/namespace.h"
+#else
+# include "libmemcached/virtual_bucket.h"
+#endif
+
+#ifdef __cplusplus
+# include "libmemcached/backtrace.hpp"
+# include "libmemcached/assert.hpp"
+# include "libmemcached/server.hpp"
+# include "libmemcached/key.hpp"
+# include "libmemcached/encoding_key.h"
+# include "libmemcached/result.h"
+# include "libmemcached/version.hpp"
+#endif
+
+#include "libmemcached/continuum.hpp"
+
+#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
+
+#define likely(x) if((x))
+#define unlikely(x) if((x))
+
+#else
+
+#define likely(x) if(__builtin_expect((x) != 0, 1))
+#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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+memcached_return_t run_distribution(memcached_st *ptr);
+
+#ifdef __cplusplus
+static inline void memcached_server_response_increment(memcached_instance_st* instance)
+{
+ instance->events(POLLIN);
+ instance->cursor_active_++;
+}
+#endif
+
+#define memcached_server_response_decrement(A) (A)->cursor_active_--
+#define memcached_server_response_reset(A) (A)->cursor_active_=0
+
+#define memcached_instance_response_increment(A) (A)->cursor_active_++
+#define memcached_instance_response_decrement(A) (A)->cursor_active_--
+#define memcached_instance_response_reset(A) (A)->cursor_active_=0
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+bool memcached_purge(memcached_instance_st*);
+memcached_instance_st* memcached_instance_by_position(const memcached_st *ptr, uint32_t server_key);
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+
+#include <cassert>
+
+#ifndef SOCK_CLOEXEC
+# define SOCK_CLOEXEC 0
+#endif
+
+#ifndef SOCK_NONBLOCK
+# define SOCK_NONBLOCK 0
+#endif
+
+#ifndef FD_CLOEXEC
+# define FD_CLOEXEC 0
+#endif
+
+#ifndef SO_NOSIGPIPE
+# define SO_NOSIGPIPE 0
+#endif
+
+#ifndef TCP_NODELAY
+# define TCP_NODELAY 0
+#endif
+
+#ifndef TCP_KEEPIDLE
+# define TCP_KEEPIDLE 0
+#endif
+
+static memcached_return_t connect_poll(memcached_instance_st* server, const int connection_error)
+{
+ struct pollfd fds[1];
+ fds[0].fd= server->fd;
+ fds[0].events= server->events();
+ fds[0].revents= 0;
+
+ size_t loop_max= 5;
+
+ if (server->root->poll_timeout == 0)
+ {
+ return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT,
+ memcached_literal_param("The time to wait for a connection to be established was set to zero which produces a timeout to every call to poll()."));
+ }
+
+ while (--loop_max) // Should only loop on cases of ERESTART or EINTR
+ {
+ int number_of;
+ if ((number_of= poll(fds, 1, server->root->connect_timeout)) == -1)
+ {
+ int local_errno= get_socket_errno(); // We cache in case closesocket() modifies errno
+ switch (local_errno)
+ {
+#ifdef __linux__
+ case ERESTART:
+#endif
+ case EINTR:
+ continue;
+
+ case EFAULT:
+ case ENOMEM:
+ return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+
+ case EINVAL:
+ return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid"));
+
+ default: // This should not happen
+ break;
+ }
+
+ assert_msg(server->fd != INVALID_SOCKET, "poll() was passed an invalid file descriptor");
+ server->reset_socket();
+ server->state= MEMCACHED_SERVER_STATE_NEW;
+
+ return memcached_set_errno(*server, local_errno, MEMCACHED_AT);
+ }
+
+ if (number_of == 0)
+ {
+ if (connection_error == EINPROGRESS)
+ {
+ int err;
+ socklen_t len= sizeof(err);
+ if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == -1)
+ {
+ return memcached_set_errno(*server, errno, MEMCACHED_AT, memcached_literal_param("getsockopt() error'ed while looking for error connect_poll(EINPROGRESS)"));
+ }
+
+ // If Zero, my hero, we just fail to a generic MEMCACHED_TIMEOUT error
+ if (err != 0)
+ {
+ return memcached_set_errno(*server, err, MEMCACHED_AT, memcached_literal_param("getsockopt() found the error from poll() after connect() returned EINPROGRESS."));
+ }
+ }
+
+ return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_literal_param("(number_of == 0)"));
+ }
+
+ assert (number_of == 1);
+
+ if (fds[0].revents & POLLERR or
+ fds[0].revents & POLLHUP or
+ fds[0].revents & POLLNVAL)
+ {
+ int err;
+ socklen_t len= sizeof (err);
+ if (getsockopt(fds[0].fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == -1)
+ {
+ return memcached_set_errno(*server, errno, MEMCACHED_AT, memcached_literal_param("getsockopt() errored while looking up error state from poll()"));
+ }
+
+ // We check the value to see what happened with the socket.
+ if (err == 0) // Should not happen
+ {
+ return MEMCACHED_SUCCESS;
+ }
+ errno= err;
+
+ return memcached_set_errno(*server, err, MEMCACHED_AT, memcached_literal_param("getsockopt() found the error from poll() during connect."));
+ }
+ assert(fds[0].revents & POLLOUT);
+
+ if (fds[0].revents & POLLOUT and connection_error == EINPROGRESS)
+ {
+ int err;
+ socklen_t len= sizeof(err);
+ if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == -1)
+ {
+ return memcached_set_errno(*server, errno, MEMCACHED_AT);
+ }
+
+ if (err == 0)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ return memcached_set_errno(*server, err, MEMCACHED_AT, memcached_literal_param("getsockopt() found the error from poll() after connect() returned EINPROGRESS."));
+ }
+
+ break; // We only have the loop setup for errno types that require restart
+ }
+
+ // This should only be possible from ERESTART or EINTR;
+ return memcached_set_errno(*server, connection_error, MEMCACHED_AT, memcached_literal_param("connect_poll() was exhausted"));
+}
+
+static memcached_return_t set_hostinfo(memcached_instance_st* server)
+{
+ assert(server->type != MEMCACHED_CONNECTION_UNIX_SOCKET);
+ server->clear_addrinfo();
+
+ char str_port[MEMCACHED_NI_MAXSERV]= { 0 };
+ errno= 0;
+ int length= snprintf(str_port, MEMCACHED_NI_MAXSERV, "%u", uint32_t(server->port()));
+ if (length >= MEMCACHED_NI_MAXSERV or length <= 0 or errno != 0)
+ {
+ return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(NI_MAXSERV)"));
+ }
+
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+
+ hints.ai_family= AF_UNSPEC;
+ if (memcached_is_udp(server->root))
+ {
+ hints.ai_protocol= IPPROTO_UDP;
+ hints.ai_socktype= SOCK_DGRAM;
+ }
+ else
+ {
+ hints.ai_socktype= SOCK_STREAM;
+ hints.ai_protocol= IPPROTO_TCP;
+ }
+
+ assert(server->address_info == NULL);
+ assert(server->address_info_next == NULL);
+ int errcode;
+ assert(server->hostname());
+ switch(errcode= getaddrinfo(server->hostname(), str_port, &hints, &server->address_info))
+ {
+ case 0:
+ server->address_info_next= server->address_info;
+ server->state= MEMCACHED_SERVER_STATE_ADDRINFO;
+ break;
+
+ case EAI_AGAIN:
+ return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_string_make_from_cstr(gai_strerror(errcode)));
+
+ case EAI_SYSTEM:
+ server->clear_addrinfo();
+ return memcached_set_errno(*server, errno, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_SYSTEM)"));
+
+ case EAI_BADFLAGS:
+ server->clear_addrinfo();
+ return memcached_set_error(*server, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_BADFLAGS)"));
+
+ case EAI_MEMORY:
+ server->clear_addrinfo();
+ return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_MEMORY)"));
+
+ default:
+ {
+ server->clear_addrinfo();
+ return memcached_set_error(*server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT, memcached_string_make_from_cstr(gai_strerror(errcode)));
+ }
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+static inline void set_socket_nonblocking(memcached_instance_st* server)
+{
+#if defined(_WIN32)
+ u_long arg= 1;
+ if (ioctlsocket(server->fd, FIONBIO, &arg) == SOCKET_ERROR)
+ {
+ memcached_set_errno(*server, get_socket_errno(), NULL);
+ }
+#else
+ int flags;
+
+ if (SOCK_NONBLOCK == 0)
+ {
+ do
+ {
+ flags= fcntl(server->fd, F_GETFL, 0);
+ } while (flags == -1 && (errno == EINTR || errno == EAGAIN));
+
+ if (flags == -1)
+ {
+ memcached_set_errno(*server, errno, NULL);
+ }
+ else if ((flags & O_NONBLOCK) == 0)
+ {
+ int rval;
+
+ do
+ {
+ rval= fcntl(server->fd, F_SETFL, flags | O_NONBLOCK);
+ } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
+
+ if (rval == -1)
+ {
+ memcached_set_errno(*server, errno, NULL);
+ }
+ }
+ }
+#endif
+}
+
+static bool set_socket_options(memcached_instance_st* server)
+{
+ assert_msg(server->fd != INVALID_SOCKET, "invalid socket was passed to set_socket_options()");
+
+#ifdef HAVE_FCNTL
+ // If SOCK_CLOEXEC exists then we don't need to call the following
+ if (SOCK_CLOEXEC == 0)
+ {
+ if (FD_CLOEXEC != 0)
+ {
+ int flags;
+ do
+ {
+ flags= fcntl(server->fd, F_GETFD, 0);
+ } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
+
+ if (flags != -1)
+ {
+ int rval;
+ do
+ {
+ rval= fcntl (server->fd, F_SETFD, flags | FD_CLOEXEC);
+ } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
+ // we currently ignore the case where rval is -1
+ }
+ }
+ }
+#endif
+
+ if (memcached_is_udp(server->root))
+ {
+ return true;
+ }
+
+#ifdef HAVE_SNDTIMEO
+ if (server->root->snd_timeout > 0)
+ {
+ struct timeval waittime;
+
+ waittime.tv_sec= server->root->snd_timeout / 1000000;
+ waittime.tv_usec= server->root->snd_timeout % 1000000;
+
+ int error= setsockopt(server->fd, SOL_SOCKET, SO_SNDTIMEO,
+ (char*)&waittime, (socklen_t)sizeof(struct timeval));
+ (void)error;
+ assert(error == 0);
+ }
+#endif
+
+#ifdef HAVE_RCVTIMEO
+ if (server->root->rcv_timeout > 0)
+ {
+ struct timeval waittime;
+
+ waittime.tv_sec= server->root->rcv_timeout / 1000000;
+ waittime.tv_usec= server->root->rcv_timeout % 1000000;
+
+ int error= setsockopt(server->fd, SOL_SOCKET, SO_RCVTIMEO,
+ (char*)&waittime, (socklen_t)sizeof(struct timeval));
+ (void)(error);
+ assert(error == 0);
+ }
+#endif
+
+
+#if defined(_WIN32)
+#else
+# if defined(SO_NOSIGPIPE)
+ if (SO_NOSIGPIPE)
+ {
+ int set= 1;
+ int error= setsockopt(server->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
+
+ assert(error == 0);
+
+ // This is not considered a fatal error
+ if (error == -1)
+ {
+#if 0
+ perror("setsockopt(SO_NOSIGPIPE)");
+#endif
+ }
+ }
+# endif // SO_NOSIGPIPE
+#endif // _WIN32
+
+ if (server->root->flags.no_block)
+ {
+ struct linger linger;
+
+ linger.l_onoff= 1;
+ linger.l_linger= 0; /* By default on close() just drop the socket */
+ int error= setsockopt(server->fd, SOL_SOCKET, SO_LINGER,
+ (char*)&linger, (socklen_t)sizeof(struct linger));
+ (void)(error);
+ assert(error == 0);
+ }
+
+ if (TCP_NODELAY)
+ {
+ if (server->root->flags.tcp_nodelay)
+ {
+ int flag= 1;
+
+ int error= setsockopt(server->fd, IPPROTO_TCP, TCP_NODELAY,
+ (char*)&flag, (socklen_t)sizeof(int));
+ (void)(error);
+ assert(error == 0);
+ }
+ }
+
+ if (server->root->flags.tcp_keepalive)
+ {
+ int flag= 1;
+
+ int error= setsockopt(server->fd, SOL_SOCKET, SO_KEEPALIVE,
+ (char*)&flag, (socklen_t)sizeof(int));
+ (void)(error);
+ assert(error == 0);
+ }
+
+ if (TCP_KEEPIDLE)
+ {
+ if (server->root->tcp_keepidle > 0)
+ {
+ int error= setsockopt(server->fd, IPPROTO_TCP, TCP_KEEPIDLE,
+ (char*)&server->root->tcp_keepidle, (socklen_t)sizeof(int));
+ (void)(error);
+ assert(error == 0);
+ }
+ }
+
+ if (server->root->send_size > 0)
+ {
+ int error= setsockopt(server->fd, SOL_SOCKET, SO_SNDBUF,
+ (char*)&server->root->send_size, (socklen_t)sizeof(int));
+ (void)(error);
+ assert(error == 0);
+ }
+
+ if (server->root->recv_size > 0)
+ {
+ int error= setsockopt(server->fd, SOL_SOCKET, SO_RCVBUF,
+ (char*)&server->root->recv_size, (socklen_t)sizeof(int));
+ (void)(error);
+ assert(error == 0);
+ }
+
+ /* libmemcached will always use nonblocking IO to avoid write deadlocks */
+ set_socket_nonblocking(server);
+
+ return true;
+}
+
+static memcached_return_t unix_socket_connect(memcached_instance_st* server)
+{
+#ifndef _WIN32
+ WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
+
+ do {
+ int type= SOCK_STREAM;
+ if (SOCK_CLOEXEC != 0)
+ {
+ type|= SOCK_CLOEXEC;
+ }
+
+ if (SOCK_NONBLOCK != 0)
+ {
+ type|= SOCK_NONBLOCK;
+ }
+
+ if ((server->fd= socket(AF_UNIX, type, 0)) == -1)
+ {
+ return memcached_set_errno(*server, errno, NULL);
+ }
+
+ struct sockaddr_un servAddr;
+
+ memset(&servAddr, 0, sizeof (struct sockaddr_un));
+ servAddr.sun_family= AF_UNIX;
+ if (strlen(server->hostname()) >= sizeof(servAddr.sun_path)) {
+ return memcached_set_error(*server, MEMCACHED_UNIX_SOCKET_PATH_TOO_BIG, MEMCACHED_AT);
+ }
+ strncpy(servAddr.sun_path, server->hostname(), sizeof(servAddr.sun_path)-1); /* Copy filename */
+
+ if (connect(server->fd, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1)
+ {
+ switch (errno)
+ {
+ case EINPROGRESS:
+ case EALREADY:
+ case EAGAIN:
+ server->events(POLLOUT);
+ break;
+
+ case EINTR:
+ server->reset_socket();
+ continue;
+
+ case EISCONN: /* We were spinning waiting on connect */
+ {
+ assert(0); // Programmer error
+ server->reset_socket();
+ continue;
+ }
+
+ default:
+ WATCHPOINT_ERRNO(errno);
+ server->reset_socket();
+ return memcached_set_errno(*server, errno, MEMCACHED_AT);
+ }
+ }
+ } while (0);
+ server->state= MEMCACHED_SERVER_STATE_CONNECTED;
+
+ WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
+
+ return MEMCACHED_SUCCESS;
+#else
+ (void)server;
+ return MEMCACHED_NOT_SUPPORTED;
+#endif
+}
+
+static memcached_return_t network_connect(memcached_instance_st* server)
+{
+ bool timeout_error_occured= false;
+
+ WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
+ WATCHPOINT_ASSERT(server->cursor_active_ == 0);
+
+ /*
+ We want to check both of these because if address_info_next has been fully tried, we want to do a new lookup to make sure we have picked up on any new DNS information.
+ */
+ if (server->address_info == NULL or server->address_info_next == NULL)
+ {
+ WATCHPOINT_ASSERT(server->state == MEMCACHED_SERVER_STATE_NEW);
+ server->address_info_next= NULL;
+ memcached_return_t rc= set_hostinfo(server);
+
+ if (memcached_failed(rc))
+ {
+ return rc;
+ }
+ }
+
+ assert(server->address_info_next);
+ assert(server->address_info);
+
+ /* Create the socket */
+ while (server->address_info_next and server->fd == INVALID_SOCKET)
+ {
+ int type= server->address_info_next->ai_socktype;
+ if (SOCK_CLOEXEC != 0)
+ {
+ type|= SOCK_CLOEXEC;
+ }
+
+ if (SOCK_NONBLOCK != 0)
+ {
+ type|= SOCK_NONBLOCK;
+ }
+
+ server->fd= socket(server->address_info_next->ai_family,
+ type,
+ server->address_info_next->ai_protocol);
+
+ if (int(server->fd) == SOCKET_ERROR)
+ {
+ return memcached_set_errno(*server, get_socket_errno(), NULL);
+ }
+
+ if (set_socket_options(server) == false)
+ {
+ server->reset_socket();
+ return MEMCACHED_CONNECTION_FAILURE;
+ }
+
+ /* connect to server */
+ if ((connect(server->fd, server->address_info_next->ai_addr, server->address_info_next->ai_addrlen) != SOCKET_ERROR))
+ {
+ server->state= MEMCACHED_SERVER_STATE_CONNECTED;
+ return MEMCACHED_SUCCESS;
+ }
+
+ /* An error occurred */
+ int local_error= get_socket_errno();
+ switch (local_error)
+ {
+ case ETIMEDOUT:
+ timeout_error_occured= true;
+ break;
+
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EINPROGRESS: // nonblocking mode - first return
+ case EALREADY: // nonblocking mode - subsequent returns
+ {
+ server->events(POLLOUT);
+ server->state= MEMCACHED_SERVER_STATE_IN_PROGRESS;
+ memcached_return_t rc= connect_poll(server, local_error);
+
+ if (memcached_success(rc))
+ {
+ server->state= MEMCACHED_SERVER_STATE_CONNECTED;
+ return MEMCACHED_SUCCESS;
+ }
+
+ // A timeout here is treated as an error, we will not retry
+ if (rc == MEMCACHED_TIMEOUT)
+ {
+ timeout_error_occured= true;
+ }
+ }
+ break;
+
+ case EISCONN: // we are connected :-)
+ WATCHPOINT_ASSERT(0); // This is a programmer's error
+ break;
+
+ case EINTR: // Special case, we retry ai_addr
+ WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
+ server->reset_socket();
+ continue;
+
+ case ECONNREFUSED:
+ // Probably not running service
+
+ default:
+ memcached_set_errno(*server, local_error, MEMCACHED_AT);
+ break;
+ }
+
+ WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
+ server->reset_socket();
+ server->address_info_next= server->address_info_next->ai_next;
+ }
+
+ WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
+
+ if (timeout_error_occured)
+ {
+ server->reset_socket();
+ }
+
+ WATCHPOINT_STRING("Never got a good file descriptor");
+
+ if (memcached_has_current_error(*server))
+ {
+ return memcached_instance_error_return(server);
+ }
+
+ if (timeout_error_occured and server->state < MEMCACHED_SERVER_STATE_IN_PROGRESS)
+ {
+ return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT,
+ memcached_literal_param("if (timeout_error_occured and server->state < MEMCACHED_SERVER_STATE_IN_PROGRESS)"));
+ }
+
+ return memcached_set_error(*server, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT); /* The last error should be from connect() */
+}
+
+
+/*
+ backoff_handling()
+
+ Based on time/failure count fail the connect without trying. This prevents waiting in a state where
+ we get caught spending cycles just waiting.
+*/
+static memcached_return_t backoff_handling(memcached_instance_st* server, bool& in_timeout)
+{
+ struct timeval curr_time;
+ bool _gettime_success= (gettimeofday(&curr_time, NULL) == 0);
+
+ /*
+ If we hit server_failure_limit then something is completely wrong about the server.
+
+ 1) If autoeject is enabled we do that.
+ 2) If not? We go into timeout again, there is much else to do :(
+ */
+ if (server->server_failure_counter >= server->root->server_failure_limit)
+ {
+ /*
+ We just auto_eject if we hit this point
+ */
+ if (_is_auto_eject_host(server->root))
+ {
+ set_last_disconnected_host(server);
+
+ // Retry dead servers if requested
+ if (_gettime_success and server->root->dead_timeout > 0)
+ {
+ server->next_retry= curr_time.tv_sec +server->root->dead_timeout;
+
+ // We only retry dead servers once before assuming failure again
+ server->server_failure_counter= server->root->server_failure_limit -1;
+ }
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= run_distribution((memcached_st *)server->root)))
+ {
+ return memcached_set_error(*server, rc, MEMCACHED_AT, memcached_literal_param("Backoff handling failed during run_distribution"));
+ }
+
+ return memcached_set_error(*server, MEMCACHED_SERVER_MARKED_DEAD, MEMCACHED_AT);
+ }
+
+ server->state= MEMCACHED_SERVER_STATE_IN_TIMEOUT;
+
+ // Sanity check/setting
+ if (server->next_retry == 0)
+ {
+ server->next_retry= 1;
+ }
+ }
+
+ if (server->state == MEMCACHED_SERVER_STATE_IN_TIMEOUT)
+ {
+ /*
+ If next_retry is less then our current time, then we reset and try everything again.
+ */
+ if (_gettime_success and server->next_retry < curr_time.tv_sec)
+ {
+ server->state= MEMCACHED_SERVER_STATE_NEW;
+ server->server_timeout_counter= 0;
+ }
+ else
+ {
+ return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT);
+ }
+
+ in_timeout= true;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t _memcached_connect(memcached_instance_st* server, const bool set_last_disconnected)
+{
+ assert(server);
+ if (server->fd != INVALID_SOCKET)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ LIBMEMCACHED_MEMCACHED_CONNECT_START();
+
+ bool in_timeout= false;
+ memcached_return_t rc;
+ if (memcached_failed(rc= backoff_handling(server, in_timeout)))
+ {
+ set_last_disconnected_host(server);
+ return rc;
+ }
+
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT and server->root->sasl.callbacks and memcached_is_udp(server->root))
+ {
+ return memcached_set_error(*server, MEMCACHED_INVALID_HOST_PROTOCOL, MEMCACHED_AT, memcached_literal_param("SASL is not supported for UDP connections"));
+ }
+
+ if (server->hostname()[0] == '/')
+ {
+ server->type= MEMCACHED_CONNECTION_UNIX_SOCKET;
+ }
+
+ /* We need to clean up the multi startup piece */
+ switch (server->type)
+ {
+ case MEMCACHED_CONNECTION_UDP:
+ case MEMCACHED_CONNECTION_TCP:
+ rc= network_connect(server);
+
+#if defined(LIBMEMCACHED_WITH_SASL_SUPPORT)
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT)
+ {
+ if (server->fd != INVALID_SOCKET and server->root->sasl.callbacks)
+ {
+ rc= memcached_sasl_authenticate_connection(server);
+ if (memcached_failed(rc) and server->fd != INVALID_SOCKET)
+ {
+ WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
+ server->reset_socket();
+ }
+ }
+ }
+#endif
+ break;
+
+ case MEMCACHED_CONNECTION_UNIX_SOCKET:
+ rc= unix_socket_connect(server);
+ break;
+ }
+
+ if (memcached_success(rc))
+ {
+ server->mark_server_as_clean();
+ memcached_version_instance(server);
+ return rc;
+ }
+ else if (set_last_disconnected)
+ {
+ set_last_disconnected_host(server);
+ if (memcached_has_current_error(*server))
+ {
+ memcached_mark_server_for_timeout(server);
+ assert(memcached_failed(memcached_instance_error_return(server)));
+ }
+ else
+ {
+ memcached_set_error(*server, rc, MEMCACHED_AT);
+ memcached_mark_server_for_timeout(server);
+ }
+
+ LIBMEMCACHED_MEMCACHED_CONNECT_END();
+
+ if (in_timeout)
+ {
+ char buffer[1024];
+ int snprintf_length= snprintf(buffer, sizeof(buffer), "%s:%d", server->hostname(), int(server->port()));
+ return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT, buffer, snprintf_length);
+ }
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_connect(memcached_instance_st* server)
+{
+ return _memcached_connect(server, true);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+memcached_return_t memcached_connect(memcached_instance_st*);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+/* string value */
+struct memcached_continuum_item_st
+{
+ uint32_t index;
+ uint32_t value;
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Configure Scripting Language
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+#ifndef YY_EXTRA_TYPE
+# define YY_EXTRA_TYPE Context*
+#endif
+
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+# define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+#include <libmemcached/common.h>
+#include <libmemcached/csl/server.h>
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Configure Scripting Language
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/csl/common.h>
+#include <libmemcached/csl/context.h>
+
+void Context::abort(const char *error_arg, config_tokentype last_token, const char *last_token_str)
+{
+ rc= MEMCACHED_PARSE_ERROR;
+ (void)last_token;
+
+ if (error_arg)
+ {
+ memcached_set_parser_error(*memc, MEMCACHED_AT, "%s", error_arg);
+ return;
+ }
+
+ if (last_token_str)
+ {
+ memcached_set_parser_error(*memc, MEMCACHED_AT, "%s", last_token_str);
+ return;
+ }
+
+ memcached_set_parser_error(*memc, MEMCACHED_AT, "unknown parsing error");
+}
+
+void Context::error(const char *error_arg, config_tokentype last_token, const char *last_token_str)
+{
+ rc= MEMCACHED_PARSE_ERROR;
+ if (not error_arg)
+ {
+ memcached_set_parser_error(*memc, MEMCACHED_AT, "Unknown error occured during parsing (%s)", last_token_str ? last_token_str : " ");
+ return;
+ }
+
+ if (strcmp(error_arg, "memory exhausted") == 0)
+ {
+ (void)memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_string_make_from_cstr(error_arg));
+ return;
+ }
+
+ // We now test if it is something other then a syntax error, if it we
+ // return a generic message
+ if (strcmp(error_arg, "syntax error") != 0)
+ {
+ memcached_set_parser_error(*memc, MEMCACHED_AT, "Error occured during parsing (%s)", error_arg);
+ return;
+ }
+
+ if (last_token == UNKNOWN_OPTION and begin)
+ {
+ memcached_set_parser_error(*memc, MEMCACHED_AT, "Unknown option: %s", begin);
+ }
+ else if (last_token == UNKNOWN)
+ {
+ memcached_set_parser_error(*memc, MEMCACHED_AT, "Error occured durring parsing, an unknown token was found.");
+ }
+ else
+ {
+ memcached_set_parser_error(*memc, MEMCACHED_AT, "Error occured while parsing (%s)", last_token_str ? last_token_str : " ");
+ }
+}
+
+void Context::hostname(const char *str, size_t size, server_t& server_)
+{
+ size_t copy_length= size_t(NI_MAXHOST) > size ? size : size_t(NI_MAXHOST);
+ memcpy(_hostname, str, copy_length);
+ _hostname[copy_length]= 0;
+
+ server_.port= MEMCACHED_DEFAULT_PORT;
+ server_.weight= 1;
+ server_.c_str= _hostname;
+ server_.size= size;
+}
+
+bool Context::string_buffer(const char *str, size_t size, memcached_string_t& string_)
+{
+ if (memcached_string_set(_string_buffer, str, size))
+ {
+ string_.c_str= memcached_string_value(_string_buffer);
+ string_.size= memcached_string_length(_string_buffer);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Context::set_hash(memcached_hash_t hash)
+{
+ if (_has_hash)
+ {
+ return false;
+ }
+
+ if ((memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, hash)) != MEMCACHED_SUCCESS)
+ {
+ return false;
+ }
+
+ return _has_hash= true;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Configure Scripting Language
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include "libmemcached/csl/common.h"
+#include "libmemcached/csl/parser.h"
+
+class Context
+{
+public:
+ Context(const char *option_string, size_t option_string_length, memcached_st *memc_,
+ memcached_return_t &rc_arg) :
+ previous_token(END),
+ scanner(NULL),
+ buf(option_string),
+ begin(NULL),
+ pos(0),
+ length(option_string_length),
+ memc(memc_),
+ rc(rc_arg),
+ _is_server(false),
+ _end(false),
+ _has_hash(false)
+ {
+ _hostname[0]= 0;
+ init_scanner();
+ rc= MEMCACHED_SUCCESS;
+
+ memc->state.is_parsing= true;
+ memcached_string_create(memc,
+ &_string_buffer,
+ 1024);
+ }
+
+ bool end()
+ {
+ return _end;
+ }
+
+ void start();
+
+ void set_end()
+ {
+ rc= MEMCACHED_SUCCESS;
+ _end= true;
+ }
+
+ bool set_hash(memcached_hash_t hash);
+
+ void set_server()
+ {
+ _is_server= true;
+ }
+
+ void unset_server()
+ {
+ _is_server= false;
+ }
+
+ bool is_server() const
+ {
+ return _is_server;
+ }
+
+ void hostname(const char*, size_t, server_t&);
+
+ bool string_buffer(const char*, size_t, memcached_string_t&);
+
+ const char *hostname() const
+ {
+ return _hostname;
+ }
+
+ void abort(const char *, config_tokentype, const char *);
+ void error(const char *, config_tokentype, const char* );
+
+ ~Context()
+ {
+ memcached_string_free(&_string_buffer);
+ destroy_scanner();
+ memc->state.is_parsing= false;
+ }
+
+ config_tokentype previous_token;
+ void *scanner;
+ const char *buf;
+ const char *begin;
+ size_t pos;
+ size_t length;
+ memcached_st *memc;
+ memcached_return_t &rc;
+
+protected:
+ void init_scanner();
+ void destroy_scanner();
+
+private:
+ bool _is_server;
+ bool _end;
+ char _hostname[NI_MAXHOST];
+ bool _has_hash;
+ memcached_string_st _string_buffer;
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+%{
+
+#include <libmemcached/csl/common.h>
+
+class Context;
+
+%}
+
+%define parse.error verbose
+%define api.pure
+%define api.prefix {config_}
+%define api.value.type {union CONFIG_STYPE}
+%debug
+%defines
+%expect 0
+%lex-param { yyscan_t *scanner }
+%parse-param { class Context *context }
+%parse-param { yyscan_t *scanner }
+%require "2.5"
+%start begin
+%verbose
+
+%{
+
+#include <libmemcached/options.hpp>
+
+#include <libmemcached/csl/context.h>
+#include <libmemcached/csl/symbol.h>
+#include <libmemcached/csl/scanner.h>
+
+#ifndef __INTEL_COMPILER
+# pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+#ifndef __INTEL_COMPILER
+# ifndef __clang__
+# pragma GCC diagnostic ignored "-Wlogical-op"
+# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
+# endif
+#endif
+
+int config_lex(YYSTYPE* lvalp, void* scanner);
+
+#define select_yychar(__context) yychar == UNKNOWN ? ( (__context)->previous_token == END ? UNKNOWN : (__context)->previous_token ) : yychar
+
+#define stryytname(__yytokentype) ((__yytokentype) < YYNTOKENS ) ? yytname[(__yytokentype)] : ""
+
+#define parser_abort(__context, __error_message) do { (__context)->abort((__error_message), config_tokentype(select_yychar(__context)), stryytname(YYTRANSLATE(select_yychar(__context)))); YYABORT; } while (0)
+
+// This is bison calling error.
+inline void __config_error(Context *context, yyscan_t *scanner, const char *error, int last_token, const char *last_token_str)
+{
+ if (not context->end())
+ {
+ context->error(error, config_tokentype(last_token), last_token_str);
+ }
+ else
+ {
+ context->error(error, config_tokentype(last_token), last_token_str);
+ }
+}
+
+#define config_error(__context, __scanner, __error_msg) do { __config_error((__context), (__scanner), (__error_msg), select_yychar(__context), stryytname(YYTRANSLATE(select_yychar(__context)))); } while (0)
+
+
+%}
+
+%token COMMENT
+%token END
+%token CSL_ERROR
+%token RESET
+%token PARSER_DEBUG
+%token INCLUDE
+%token CONFIGURE_FILE
+%token EMPTY_LINE
+%token SERVER
+%token CSL_SOCKET
+%token SERVERS
+%token SERVERS_OPTION
+%token UNKNOWN_OPTION
+%token UNKNOWN
+
+/* All behavior options */
+%token BINARY_PROTOCOL
+%token BUFFER_REQUESTS
+%token CONNECT_TIMEOUT
+%token DISTRIBUTION
+%token HASH
+%token HASH_WITH_NAMESPACE
+%token IO_BYTES_WATERMARK
+%token IO_KEY_PREFETCH
+%token IO_MSG_WATERMARK
+%token KETAMA_HASH
+%token KETAMA_WEIGHTED
+%token NOREPLY
+%token NUMBER_OF_REPLICAS
+%token POLL_TIMEOUT
+%token RANDOMIZE_REPLICA_READ
+%token RCV_TIMEOUT
+%token REMOVE_FAILED_SERVERS
+%token RETRY_TIMEOUT
+%token SND_TIMEOUT
+%token SOCKET_RECV_SIZE
+%token SOCKET_SEND_SIZE
+%token SORT_HOSTS
+%token SUPPORT_CAS
+%token USER_DATA
+%token USE_UDP
+%token VERIFY_KEY
+%token _TCP_KEEPALIVE
+%token _TCP_KEEPIDLE
+%token _TCP_NODELAY
+%token FETCH_VERSION
+
+/* Callbacks */
+%token NAMESPACE
+
+/* Pool */
+%token POOL_MIN
+%token POOL_MAX
+
+/* Hash types */
+%token MD5
+%token CRC
+%token FNV1_64
+%token FNV1A_64
+%token FNV1_32
+%token FNV1A_32
+%token HSIEH
+%token MURMUR
+%token JENKINS
+
+/* Distributions */
+%token CONSISTENT
+%token MODULA
+%token RANDOM
+
+/* Boolean values */
+%token <boolean> CSL_TRUE
+%token <boolean> CSL_FALSE
+
+%nonassoc ','
+%nonassoc '='
+
+%token <number> CSL_FLOAT
+%token <number> NUMBER
+%token <number> PORT
+%token <number> WEIGHT_START
+%token <server> IPADDRESS
+%token <server> HOSTNAME
+%token <string> STRING
+%token <string> QUOTED_STRING
+%token <string> FILE_PATH
+
+%type <behavior> behavior_boolean
+%type <behavior> behavior_number
+%type <distribution> distribution
+%type <hash> hash
+%type <number> optional_port
+%type <number> optional_weight
+%type <string> string
+
+%%
+
+begin:
+ statement
+ | begin ' ' statement
+ ;
+
+statement:
+ expression
+ { }
+ | COMMENT
+ { }
+ | EMPTY_LINE
+ { }
+ | END
+ {
+ context->set_end();
+ YYACCEPT;
+ }
+ | CSL_ERROR
+ {
+ context->rc= MEMCACHED_PARSE_USER_ERROR;
+ parser_abort(context, "ERROR called directly");
+ }
+ | RESET
+ {
+ memcached_reset(context->memc);
+ }
+ | PARSER_DEBUG
+ {
+ yydebug= 1;
+ }
+ | INCLUDE ' ' string
+ {
+ if ((context->rc= memcached_parse_configure_file(*context->memc, $3.c_str, $3.size)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, "Failed to parse configuration file");
+ }
+ }
+ ;
+
+
+expression:
+ SERVER HOSTNAME optional_port optional_weight
+ {
+ if (memcached_failed(context->rc= memcached_server_add_with_weight(context->memc, $2.c_str, $3, uint32_t($4))))
+ {
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "Failed to add server: %s:%u", $2.c_str, uint32_t($3));
+ parser_abort(context, buffer);
+ }
+ context->unset_server();
+ }
+ | SERVER IPADDRESS optional_port optional_weight
+ {
+ if (memcached_failed(context->rc= memcached_server_add_with_weight(context->memc, $2.c_str, $3, uint32_t($4))))
+ {
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "Failed to add server: %s:%u", $2.c_str, uint32_t($3));
+ parser_abort(context, buffer);
+ }
+ context->unset_server();
+ }
+ | CSL_SOCKET string optional_weight
+ {
+ if (memcached_failed(context->rc= memcached_server_add_unix_socket_with_weight(context->memc, $2.c_str, uint32_t($3))))
+ {
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "Failed to add socket: %s", $2.c_str);
+ parser_abort(context, buffer);
+ }
+ }
+ | CONFIGURE_FILE string
+ {
+ memcached_set_configuration_file(context->memc, $2.c_str, $2.size);
+ }
+ | POOL_MIN NUMBER
+ {
+ context->memc->configure.initial_pool_size= uint32_t($2);
+ }
+ | POOL_MAX NUMBER
+ {
+ context->memc->configure.max_pool_size= uint32_t($2);
+ }
+ | behaviors
+ ;
+
+behaviors:
+ NAMESPACE string
+ {
+ if (memcached_callback_get(context->memc, MEMCACHED_CALLBACK_PREFIX_KEY, NULL))
+ {
+ parser_abort(context, "--NAMESPACE can only be called once");
+ }
+
+ if ((context->rc= memcached_set_namespace(*context->memc, $2.c_str, $2.size)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, memcached_last_error_message(context->memc));
+ }
+ }
+ | FETCH_VERSION
+ {
+ memcached_flag(*context->memc, MEMCACHED_FLAG_IS_FETCHING_VERSION, true);
+ }
+ | DISTRIBUTION distribution
+ {
+ // Check to see if DISTRIBUTION has already been set
+ if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $2)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, "--DISTRIBUTION can only be called once");
+ }
+
+ if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $2)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, memcached_last_error_message(context->memc));;
+ }
+ }
+ | DISTRIBUTION distribution ',' hash
+ {
+ // Check to see if DISTRIBUTION has already been set
+ if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $2)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, "--DISTRIBUTION can only be called once");
+ }
+
+ if ((context->rc= memcached_behavior_set_distribution_hash(context->memc, $4)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, "Unable to set the hash for the DISTRIBUTION requested");
+ }
+ }
+ | HASH hash
+ {
+ if (context->set_hash($2) == false)
+ {
+ parser_abort(context, "--HASH can only be set once");
+ }
+ }
+ | behavior_number NUMBER
+ {
+ if ((context->rc= memcached_behavior_set(context->memc, $1, $2)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, "Unable to set behavior");
+ }
+ }
+ | behavior_boolean
+ {
+ if ((context->rc= memcached_behavior_set(context->memc, $1, true)) != MEMCACHED_SUCCESS)
+ {
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "Could not set: %s", libmemcached_string_behavior($1));
+ parser_abort(context, buffer);
+ }
+ }
+ | USER_DATA
+ {
+ }
+ ;
+
+behavior_number:
+ REMOVE_FAILED_SERVERS
+ {
+ $$= MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS;
+ }
+ | CONNECT_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT;
+ }
+ | IO_MSG_WATERMARK
+ {
+ $$= MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK;
+ }
+ | IO_BYTES_WATERMARK
+ {
+ $$= MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK;
+ }
+ | IO_KEY_PREFETCH
+ {
+ $$= MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH;
+ }
+ | NUMBER_OF_REPLICAS
+ {
+ $$= MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS;
+ }
+ | POLL_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_POLL_TIMEOUT;
+ }
+ | RCV_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_RCV_TIMEOUT;
+ }
+ | RETRY_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_RETRY_TIMEOUT;
+ }
+ | SND_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_SND_TIMEOUT;
+ }
+ | SOCKET_RECV_SIZE
+ {
+ $$= MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE;
+ }
+ | SOCKET_SEND_SIZE
+ {
+ $$= MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE;
+ }
+ ;
+
+behavior_boolean:
+ BINARY_PROTOCOL
+ {
+ $$= MEMCACHED_BEHAVIOR_BINARY_PROTOCOL;
+ }
+ | BUFFER_REQUESTS
+ {
+ $$= MEMCACHED_BEHAVIOR_BUFFER_REQUESTS;
+ }
+ | HASH_WITH_NAMESPACE
+ {
+ $$= MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY;
+ }
+ | NOREPLY
+ {
+ $$= MEMCACHED_BEHAVIOR_NOREPLY;
+ }
+ | RANDOMIZE_REPLICA_READ
+ {
+ $$= MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ;
+ }
+ | SORT_HOSTS
+ {
+ $$= MEMCACHED_BEHAVIOR_SORT_HOSTS;
+ }
+ | SUPPORT_CAS
+ {
+ $$= MEMCACHED_BEHAVIOR_SUPPORT_CAS;
+ }
+ | _TCP_NODELAY
+ {
+ $$= MEMCACHED_BEHAVIOR_TCP_NODELAY;
+ }
+ | _TCP_KEEPALIVE
+ {
+ $$= MEMCACHED_BEHAVIOR_TCP_KEEPALIVE;
+ }
+ | _TCP_KEEPIDLE
+ {
+ $$= MEMCACHED_BEHAVIOR_TCP_KEEPIDLE;
+ }
+ | USE_UDP
+ {
+ $$= MEMCACHED_BEHAVIOR_USE_UDP;
+ }
+ | VERIFY_KEY
+ {
+ $$= MEMCACHED_BEHAVIOR_VERIFY_KEY;
+ }
+
+
+optional_port:
+ { $$= MEMCACHED_DEFAULT_PORT;}
+ | PORT
+ { };
+ ;
+
+optional_weight:
+ { $$= 1; }
+ | WEIGHT_START
+ { }
+ ;
+
+hash:
+ MD5
+ {
+ $$= MEMCACHED_HASH_MD5;
+ }
+ | CRC
+ {
+ $$= MEMCACHED_HASH_CRC;
+ }
+ | FNV1_64
+ {
+ $$= MEMCACHED_HASH_FNV1_64;
+ }
+ | FNV1A_64
+ {
+ $$= MEMCACHED_HASH_FNV1A_64;
+ }
+ | FNV1_32
+ {
+ $$= MEMCACHED_HASH_FNV1_32;
+ }
+ | FNV1A_32
+ {
+ $$= MEMCACHED_HASH_FNV1A_32;
+ }
+ | HSIEH
+ {
+ $$= MEMCACHED_HASH_HSIEH;
+ }
+ | MURMUR
+ {
+ $$= MEMCACHED_HASH_MURMUR;
+ }
+ | JENKINS
+ {
+ $$= MEMCACHED_HASH_JENKINS;
+ }
+ ;
+
+string:
+ STRING
+ {
+ $$= $1;
+ }
+ | QUOTED_STRING
+ {
+ $$= $1;
+ }
+ ;
+
+distribution:
+ CONSISTENT
+ {
+ $$= MEMCACHED_DISTRIBUTION_CONSISTENT;
+ }
+ | MODULA
+ {
+ $$= MEMCACHED_DISTRIBUTION_MODULA;
+ }
+ | RANDOM
+ {
+ $$= MEMCACHED_DISTRIBUTION_RANDOM;
+ }
+ ;
+
+%%
+
+void Context::start()
+{
+ config_parse(this, (void **)scanner);
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+%top{
+
+#include <libmemcached/csl/common.h>
+#include <libmemcached/csl/context.h>
+#include <libmemcached/csl/parser.h>
+#include <libmemcached/csl/symbol.h>
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wmissing-declarations"
+#pragma GCC diagnostic ignored "-Wunused-result"
+#pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#endif
+
+#ifdef __clang__
+#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
+#endif
+
+#ifndef __INTEL_COMPILER
+#ifndef __clang__
+#pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+#endif
+
+}
+
+
+%{
+#define PARAM yyget_extra(yyscanner)
+
+#define get_lex_chars(buffer, result, max_size, context) \
+{ \
+ if (context->pos >= context->length) \
+ { \
+ result= YY_NULL; \
+ } \
+ else \
+ { \
+ result= (int)(context->length - context->pos); \
+ (size_t)result > (size_t)max_size ? result= max_size : 0; \
+ memcpy(buffer, context->buf + context->pos, result); \
+ context->pos += result; \
+ } \
+}
+
+#define YY_FATAL_ERROR(msg) \
+{ \
+}
+
+#define YYSTYPE CONFIG_STYPE
+
+#define YY_INPUT(buffer, result, max_size) get_lex_chars(buffer, result, max_size, PARAM)
+
+%}
+
+%option nostdinit
+%option 8bit
+%option warn
+%option bison-bridge
+%option never-interactive
+%option case-insensitive
+%option nodefault
+%option noinput
+%option nounput
+%option noyywrap
+%option perf-report
+%option prefix="config_"
+%option reentrant
+
+%%
+
+
+=|,|[ ] { return yytext[0];}
+
+[[:digit:]]+ { yylval->number= atoi(yytext); return (NUMBER); }
+
+:[[:digit:]]{1,5} { yylval->number= atoi(yytext +1); return PORT; }
+
+"/?"[[:digit:]]{1,5} { yylval->number= atoi(yytext +2); return WEIGHT_START; }
+
+[\t\r\n] ; /* skip whitespace */
+
+
+^#.*$ {
+ return COMMENT;
+ }
+
+"--SERVER=" { yyextra->begin= yytext; yyextra->set_server(); return yyextra->previous_token= SERVER; }
+
+"--SOCKET=" { yyextra->begin= yytext; return yyextra->previous_token= CSL_SOCKET; }
+
+"--BINARY-PROTOCOL" { yyextra->begin= yytext; return yyextra->previous_token= BINARY_PROTOCOL; }
+"--BUFFER-REQUESTS" { yyextra->begin= yytext; return yyextra->previous_token= BUFFER_REQUESTS; }
+"--CONFIGURE-FILE=" { yyextra->begin= yytext; return yyextra->previous_token= CONFIGURE_FILE; }
+"--CONNECT-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= CONNECT_TIMEOUT; }
+"--DISTRIBUTION=" { yyextra->begin= yytext; return yyextra->previous_token= DISTRIBUTION; }
+"--HASH-WITH-NAMESPACE" { yyextra->begin= yytext; return yyextra->previous_token= HASH_WITH_NAMESPACE; }
+"--HASH=" { yyextra->begin= yytext; return yyextra->previous_token= HASH; }
+"--IO-BYTES-WATERMARK=" { yyextra->begin= yytext; return yyextra->previous_token= IO_BYTES_WATERMARK; }
+"--IO-KEY-PREFETCH=" { yyextra->begin= yytext; return yyextra->previous_token= IO_KEY_PREFETCH; }
+"--IO-MSG-WATERMARK=" { yyextra->begin= yytext; return yyextra->previous_token= IO_MSG_WATERMARK; }
+"--NOREPLY" { yyextra->begin= yytext; return yyextra->previous_token= NOREPLY; }
+"--NUMBER-OF-REPLICAS=" { yyextra->begin= yytext; return yyextra->previous_token= NUMBER_OF_REPLICAS; }
+"--POLL-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= POLL_TIMEOUT; }
+"--RANDOMIZE-REPLICA-READ" { yyextra->begin= yytext; return yyextra->previous_token= RANDOMIZE_REPLICA_READ; }
+"--RCV-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= RCV_TIMEOUT; }
+"--REMOVE-FAILED-SERVERS=" { yyextra->begin= yytext; return yyextra->previous_token= REMOVE_FAILED_SERVERS; }
+"--RETRY-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= RETRY_TIMEOUT; }
+"--SND-TIMEOUT=" { yyextra->begin= yytext; return yyextra->previous_token= SND_TIMEOUT; }
+"--SOCKET-RECV-SIZE=" { yyextra->begin= yytext; return yyextra->previous_token= SOCKET_RECV_SIZE; }
+"--SOCKET-SEND-SIZE=" { yyextra->begin= yytext; return yyextra->previous_token= SOCKET_SEND_SIZE; }
+"--SORT-HOSTS" { yyextra->begin= yytext; return yyextra->previous_token= SORT_HOSTS; }
+"--SUPPORT-CAS" { yyextra->begin= yytext; return yyextra->previous_token= SUPPORT_CAS; }
+"--TCP-KEEPALIVE" { yyextra->begin= yytext; return yyextra->previous_token= _TCP_KEEPALIVE; }
+"--TCP-KEEPIDLE" { yyextra->begin= yytext; return yyextra->previous_token= _TCP_KEEPIDLE; }
+"--TCP-NODELAY" { yyextra->begin= yytext; return yyextra->previous_token= _TCP_NODELAY; }
+"--USE-UDP" { yyextra->begin= yytext; return yyextra->previous_token= USE_UDP; }
+"--USER-DATA" { yyextra->begin= yytext; return yyextra->previous_token= USER_DATA; }
+"--VERIFY-KEY" { yyextra->begin= yytext; return yyextra->previous_token= VERIFY_KEY; }
+
+"--POOL-MIN=" { yyextra->begin= yytext; return yyextra->previous_token= POOL_MIN; }
+"--POOL-MAX=" { yyextra->begin= yytext; return yyextra->previous_token= POOL_MAX; }
+
+"--NAMESPACE=" { yyextra->begin= yytext; return yyextra->previous_token= NAMESPACE; }
+
+"--FETCH-VERSION" { yyextra->begin= yytext; return yyextra->previous_token= FETCH_VERSION; }
+
+INCLUDE { yyextra->begin= yytext; return yyextra->previous_token= INCLUDE; }
+RESET { yyextra->begin= yytext; return yyextra->previous_token= RESET; }
+DEBUG { yyextra->begin= yytext; return yyextra->previous_token= PARSER_DEBUG; }
+SERVERS { yyextra->begin= yytext; return yyextra->previous_token= SERVERS; }
+END { yyextra->begin= yytext; return yyextra->previous_token= END; }
+CSL_ERROR { yyextra->begin= yytext; return yyextra->previous_token= CSL_ERROR; }
+
+TRUE { return yyextra->previous_token= CSL_TRUE; }
+FALSE { return yyextra->previous_token= CSL_FALSE; }
+
+
+"--"[[:alnum:]]* {
+ yyextra->begin= yytext;
+ return UNKNOWN_OPTION;
+ }
+
+CONSISTENT { return CONSISTENT; }
+MODULA { return MODULA; }
+RANDOM { return RANDOM; }
+
+MD5 { return MD5; }
+CRC { return CRC; }
+FNV1_64 { return FNV1_64; }
+FNV1A_64 { return FNV1A_64; }
+FNV1_32 { return FNV1_32; }
+FNV1A_32 { return FNV1A_32; }
+HSIEH { return HSIEH; }
+MURMUR { return MURMUR; }
+JENKINS { return JENKINS; }
+
+(([[:digit:]]{1,3}"."){3}([[:digit:]]{1,3})) {
+ yyextra->hostname(yytext, yyleng, yylval->server);
+ return IPADDRESS;
+ }
+
+[[:alnum:]]["."[:alnum:]_-]+[[:alnum:]] {
+ if (yyextra->is_server())
+ {
+ yyextra->hostname(yytext, yyleng, yylval->server);
+
+ return HOSTNAME;
+ }
+
+ yyextra->string_buffer(yytext, yyleng, yylval->string);
+
+ return STRING;
+ }
+
+L?\"(\\.|[^\\"])*\" {
+ yyget_text(yyscanner)[yyleng -1]= 0;
+ yyextra->string_buffer(yytext +1, yyleng -2, yylval->string);
+ return QUOTED_STRING;
+ }
+
+. {
+ yyextra->begin= yytext;
+ return UNKNOWN;
+ }
+
+%%
+
+void Context::init_scanner()
+{
+ yylex_init(&scanner);
+ yyset_extra(this, scanner);
+}
+
+void Context::destroy_scanner()
+{
+ (void)yy_fatal_error; // Removes warning about unused yy_fatal_error()
+ yylex_destroy(scanner);
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Configure Scripting Language
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <cstdlib>
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+struct server_t
+{
+ const char *c_str;
+ size_t size;
+ in_port_t port;
+ uint32_t weight;
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Configure Scripting Language
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libmemcached/csl/common.h>
+
+union CONFIG_STYPE
+{
+ long long number;
+ memcached_string_t string;
+ memcached_string_t option;
+ double double_number;
+ memcached_server_distribution_t distribution;
+ memcached_hash_t hash;
+ memcached_behavior_t behavior;
+ bool boolean;
+ server_t server;
+};
+
+typedef union CONFIG_STYPE CONFIG_STYPE;
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+memcached_return_t memcached_delete(memcached_st *shell, const char *key, size_t key_length,
+ time_t expiration)
+{
+ return memcached_delete_by_key(shell, key, key_length, key, key_length, expiration);
+}
+
+static inline memcached_return_t ascii_delete(memcached_instance_st* instance,
+ uint32_t ,
+ const char *key,
+ const size_t key_length,
+ const bool reply,
+ const bool is_buffering)
+{
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { memcached_literal_param("delete ") },
+ { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
+ { key, key_length },
+ { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
+ { memcached_literal_param("\r\n") }
+ };
+
+ /* Send command header, only flush if we are NOT buffering */
+ return memcached_vdo(instance, vector, 6, is_buffering ? false : true);
+}
+
+static inline memcached_return_t binary_delete(memcached_instance_st* instance,
+ uint32_t server_key,
+ const char *key,
+ const size_t key_length,
+ const bool reply,
+ const bool is_buffering)
+{
+ protocol_binary_request_delete request= {};
+
+ bool should_flush= is_buffering ? false : true;
+
+ initialize_binary_request(instance, request.message.header);
+
+ if (reply)
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
+ }
+ else
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
+ }
+ request.message.header.request.keylen= htons(uint16_t(key_length + memcached_array_size(instance->root->_namespace)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl(uint32_t(key_length + memcached_array_size(instance->root->_namespace)));
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { request.bytes, sizeof(request.bytes) },
+ { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
+ { key, key_length }
+ };
+
+ memcached_return_t rc= memcached_vdo(instance, vector, 4, should_flush);
+
+ if (memcached_has_replicas(instance))
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
+
+ for (uint32_t x= 0; x < memcached_has_replicas(instance); ++x)
+ {
+ ++server_key;
+
+ if (server_key == memcached_server_count(instance->root))
+ {
+ server_key= 0;
+ }
+
+ memcached_instance_st* replica= memcached_instance_fetch(instance->root, server_key);
+
+ if (memcached_success(memcached_vdo(replica, vector, 4, should_flush)))
+ {
+ memcached_server_response_decrement(replica);
+ }
+ }
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_delete_by_key(memcached_st *shell,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ time_t expiration)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ LIBMEMCACHED_MEMCACHED_DELETE_START();
+
+ memcached_return_t rc;
+ if (memcached_fatal(rc= initialize_query(memc, true)))
+ {
+ return rc;
+ }
+
+ if (memcached_fatal(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
+ {
+ return memcached_last_error(memc);
+ }
+
+ if (expiration)
+ {
+ return memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("Memcached server version does not allow expiration of deleted items"));
+ }
+
+ uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
+ memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
+
+ bool is_buffering= memcached_is_buffering(instance->root);
+ bool is_replying= memcached_is_replying(instance->root);
+
+ // If a delete trigger exists, we need a response, so no buffering/noreply
+ if (memc->delete_trigger)
+ {
+ if (is_buffering)
+ {
+ return memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("Delete triggers cannot be used if buffering is enabled"));
+ }
+
+ if (is_replying == false)
+ {
+ return memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("Delete triggers cannot be used if MEMCACHED_BEHAVIOR_NOREPLY is set"));
+ }
+ }
+
+ if (memcached_is_binary(memc))
+ {
+ rc= binary_delete(instance, server_key, key, key_length, is_replying, is_buffering);
+ }
+ else
+ {
+ rc= ascii_delete(instance, server_key, key, key_length, is_replying, is_buffering);
+ }
+
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ if (is_buffering == true)
+ {
+ rc= MEMCACHED_BUFFERED;
+ }
+ else if (is_replying == false)
+ {
+ rc= MEMCACHED_SUCCESS;
+ }
+ else
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+ if (rc == MEMCACHED_DELETED)
+ {
+ rc= MEMCACHED_SUCCESS;
+ if (memc->delete_trigger)
+ {
+ memc->delete_trigger(memc, key, key_length);
+ }
+ }
+ }
+ }
+
+ LIBMEMCACHED_MEMCACHED_DELETE_END();
+ return rc;
+}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static memcached_return_t _vdo_udp(memcached_instance_st* instance,
+ libmemcached_io_vector_st vector[],
+ const size_t count)
+{
+#ifndef __MINGW32__
+ if (vector[0].buffer or vector[0].length)
+ {
+ return memcached_set_error(*instance->root, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
+ memcached_literal_param("UDP messages was attempted, but vector was not setup for it"));
+ }
+
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+
+ increment_udp_message_id(instance);
+ vector[0].buffer= instance->write_buffer;
+ vector[0].length= UDP_DATAGRAM_HEADER_LENGTH;
+
+ msg.msg_iov= (struct iovec*)vector;
+#ifdef __APPLE__
+ msg.msg_iovlen= int(count);
+#else
+ msg.msg_iovlen= count;
+#endif
+
+ uint32_t retry= 5;
+ while (--retry)
+ {
+ ssize_t sendmsg_length= ::sendmsg(instance->fd, &msg, 0);
+ if (sendmsg_length > 0)
+ {
+ break;
+ }
+ else if (sendmsg_length < 0)
+ {
+ if (errno == EMSGSIZE)
+ {
+ return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
+ }
+
+ return memcached_set_errno(*instance, errno, MEMCACHED_AT);
+ }
+ }
+
+ return MEMCACHED_SUCCESS;
+#else
+ (void)instance;
+ (void)vector;
+ (void)count;
+ return MEMCACHED_FAILURE;
+#endif
+}
+
+memcached_return_t memcached_vdo(memcached_instance_st* instance,
+ libmemcached_io_vector_st vector[],
+ const size_t count,
+ const bool with_flush)
+{
+ memcached_return_t rc;
+
+ assert_msg(vector, "Invalid vector passed");
+
+ if (memcached_failed(rc= memcached_connect(instance)))
+ {
+ WATCHPOINT_ERROR(rc);
+ assert_msg(instance->error_messages, "memcached_connect() returned an error but the Instance showed none.");
+ 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.
+ **/
+ bool sent_success;
+ if (memcached_is_udp(instance->root))
+ {
+ sent_success= memcached_success(rc= _vdo_udp(instance, vector, count));
+ } else {
+ sent_success= memcached_io_writev(instance, vector, count, with_flush);
+ }
+ if (sent_success == false)
+ {
+ rc= memcached_last_error(instance->root);
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
+ }
+ memcached_io_reset(instance);
+ }
+ else if (memcached_is_replying(instance->root) && !memcached_is_udp(instance->root))
+ {
+ memcached_server_response_increment(instance);
+ }
+
+ return rc;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+memcached_return_t memcached_vdo(memcached_instance_st*,
+ libmemcached_io_vector_st vector[],
+ const size_t count,
+ const bool with_flush);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ 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 <libmemcached/common.h>
+
+static memcached_return_t ascii_dump(Memcached *memc, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
+{
+ memcached_version(memc);
+ /* MAX_NUMBER_OF_SLAB_CLASSES is defined to 200 in Memcached 1.4.10 */
+ for (uint32_t x= 0; x < 200; x++)
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ int buffer_length= snprintf(buffer, sizeof(buffer), "%u", x);
+ if (size_t(buffer_length) >= sizeof(buffer) or buffer_length < 0)
+ {
+ return memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
+ }
+
+ // @NOTE the hard coded zero means "no limit"
+ libmemcached_io_vector_st vector[]=
+ {
+ { memcached_literal_param("stats cachedump ") },
+ { buffer, size_t(buffer_length) },
+ { memcached_literal_param(" 0\r\n") }
+ };
+
+ // Send message to all servers
+ for (uint32_t server_key= 0; server_key < memcached_server_count(memc); server_key++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
+
+ // skip slabs >63 for server versions >= 1.4.23
+ if (x < 64 || memcached_version_instance_cmp(instance, 1, 4, 23) < 0) {
+ memcached_return_t vdo_rc;
+ if (memcached_failed((vdo_rc= memcached_vdo(instance, vector, 3, true))))
+ {
+ return vdo_rc;
+ }
+ }
+ }
+
+ // Collect the returned items
+ memcached_instance_st* instance;
+ memcached_return_t read_ret= MEMCACHED_SUCCESS;
+ while ((instance= memcached_io_get_readable_server(memc, read_ret)))
+ {
+ memcached_return_t response_rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+ if (response_rc == MEMCACHED_ITEM)
+ {
+ char *string_ptr, *end_ptr;
+
+ string_ptr= buffer;
+ string_ptr+= 5; /* Move past ITEM */
+
+ for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++) {} ;
+
+ char *key= string_ptr;
+ key[(size_t)(end_ptr-string_ptr)]= 0;
+
+ for (uint32_t callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++)
+ {
+ memcached_return_t callback_rc= (*callback[callback_counter])(memc, key, (size_t)(end_ptr-string_ptr), context);
+ if (callback_rc != MEMCACHED_SUCCESS)
+ {
+ // @todo build up a message for the error from the value
+ memcached_set_error(*instance, callback_rc, MEMCACHED_AT);
+ break;
+ }
+ }
+ }
+ else if (response_rc == MEMCACHED_END)
+ {
+ // All items have been returned
+ }
+ else if (response_rc == MEMCACHED_SERVER_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.
+ */
+ assert(response_rc == MEMCACHED_SUCCESS); // Just fail
+ return response_rc;
+ }
+ else if (response_rc == MEMCACHED_CLIENT_ERROR)
+ {
+ /* The maximum number of slabs has changed in the past (currently 1<<6-1),
+ * so ignore any client errors complaining about an illegal slab id.
+ */
+ if (0 == strncmp(buffer, "CLIENT_ERROR Illegal slab id", sizeof("CLIENT_ERROR Illegal slab id") - 1)) {
+ memcached_error_free(*instance);
+ memcached_error_free(*memc);
+ } else {
+ return response_rc;
+ }
+ }
+ else
+ {
+ // IO error of some sort must have occurred
+ return response_rc;
+ }
+ }
+ }
+
+ return memcached_has_current_error(*memc) ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_dump(memcached_st *shell, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(ptr, true)))
+ {
+ return rc;
+ }
+
+ /*
+ No support for Binary protocol yet
+ @todo Fix this so that we just flush, switch to ascii, and then go back to binary.
+ */
+ if (memcached_is_binary(ptr))
+ {
+ return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT, memcached_literal_param("Binary protocol is not supported for memcached_dump()"));
+ }
+
+ return ascii_dump(ptr, callback, context, number_of_callbacks);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <libmemcached/assert.hpp>
+
+static void _set_encoding_key(Memcached& memc, const char *key, size_t key_length)
+{
+ hashkit_key(&memc.hashkit, key, key_length);
+}
+
+memcached_return_t memcached_set_encoding_key(memcached_st* shell, const char *key, size_t key_length)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ _set_encoding_key(*memc, key, key_length);
+ return MEMCACHED_SUCCESS;
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ memcached_string_t memcached_encoding_key(Memcached&);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+#include "libmemcached/assert.hpp"
+
+#include <cerrno>
+#include <cstdarg>
+#include <cstdio>
+
+#define MAX_ERROR_LENGTH 2048
+struct memcached_error_t
+{
+ Memcached *root;
+ uint64_t query_id;
+ struct memcached_error_t *next;
+ memcached_return_t rc;
+ int local_errno;
+ size_t size;
+ char message[MAX_ERROR_LENGTH];
+};
+
+static void _set(memcached_instance_st& server, Memcached& memc)
+{
+ if (server.error_messages and server.error_messages->query_id != server.root->query_id)
+ {
+ memcached_error_free(server);
+ }
+
+ if (memc.error_messages)
+ {
+ if (memc.error_messages->rc == MEMCACHED_TIMEOUT)
+ {
+ server.io_wait_count.timeouts++;
+ }
+
+ memcached_error_t *error= libmemcached_xmalloc(&memc, memcached_error_t);
+ if (error)
+ {
+ memcpy(error, memc.error_messages, sizeof(memcached_error_t));
+ error->next= server.error_messages;
+ server.error_messages= error;
+ }
+ }
+}
+
+#if 0
+static int error_log_fd= -1;
+#endif
+
+static void _set(Memcached& memc, memcached_string_t *str, memcached_return_t &rc, const char *at, int local_errno= 0)
+{
+ if (memc.error_messages && memc.error_messages->query_id != memc.query_id)
+ {
+ memcached_error_free(memc);
+ }
+
+ if (memcached_fatal(rc) or rc == MEMCACHED_CLIENT_ERROR)
+ {
+ // For memory allocation we use our error since it is a bit more specific
+ if (local_errno == ENOMEM and rc == MEMCACHED_ERRNO)
+ {
+ rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
+ {
+ local_errno= ENOMEM;
+ }
+
+ if (rc == MEMCACHED_ERRNO and not local_errno)
+ {
+ local_errno= errno;
+ rc= MEMCACHED_ERRNO;
+ }
+
+ if (rc == MEMCACHED_ERRNO and local_errno == ENOTCONN)
+ {
+ rc= MEMCACHED_CONNECTION_FAILURE;
+ }
+
+ if (rc == MEMCACHED_ERRNO and local_errno == ECONNRESET)
+ {
+ rc= MEMCACHED_CONNECTION_FAILURE;
+ }
+
+ if (local_errno == EINVAL)
+ {
+ rc= MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (local_errno == ECONNREFUSED)
+ {
+ rc= MEMCACHED_CONNECTION_FAILURE;
+ }
+
+ if (rc == MEMCACHED_TIMEOUT)
+ {
+ }
+
+ memcached_error_t *error= libmemcached_xmalloc(&memc, memcached_error_t);
+ if (error == NULL) // Bad business if this happens
+ {
+ assert_msg(error, "libmemcached_xmalloc() failed to allocate a memcached_error_t");
+ return;
+ }
+
+ error->root= &memc;
+ error->query_id= memc.query_id;
+ error->rc= rc;
+ error->local_errno= local_errno;
+
+ // MEMCACHED_CLIENT_ERROR is a special case because it is an error coming from the server
+ if (rc == MEMCACHED_CLIENT_ERROR)
+ {
+ assert(str);
+ assert(str->size);
+ if (str and str->size)
+ {
+ assert(error->local_errno == 0);
+ error->local_errno= 0;
+
+ error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %.*s",
+ error->root,
+ int(str->size), str->c_str);
+ }
+ }
+ else if (local_errno)
+ {
+ const char *errmsg_ptr;
+ char errmsg[MAX_ERROR_LENGTH];
+ errmsg[0]= 0;
+ errmsg_ptr= errmsg;
+
+#if defined(STRERROR_R_CHAR_P) && STRERROR_R_CHAR_P
+ errmsg_ptr= strerror_r(local_errno, errmsg, sizeof(errmsg));
+#elif defined(HAVE_STRERROR_R) && HAVE_STRERROR_R
+ strerror_r(local_errno, errmsg, sizeof(errmsg));
+ errmsg_ptr= errmsg;
+#elif defined(HAVE_STRERROR) && HAVE_STRERROR
+ snprintf(errmsg, sizeof(errmsg), "%s", strerror(local_errno));
+ errmsg_ptr= errmsg;
+#endif
+
+ if (str and str->size and local_errno)
+ {
+ error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s), %.*s -> %s",
+ error->root,
+ memcached_strerror(&memc, rc),
+ errmsg_ptr,
+ memcached_string_printf(*str), at);
+ }
+ else
+ {
+ error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s(%s) -> %s",
+ error->root,
+ memcached_strerror(&memc, rc),
+ errmsg_ptr,
+ at);
+ }
+ }
+ else if (rc == MEMCACHED_PARSE_ERROR and str and str->size)
+ {
+ error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %.*s -> %s",
+ error->root,
+ int(str->size), str->c_str, at);
+ }
+ else if (str and str->size)
+ {
+ error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s, %.*s -> %s",
+ error->root,
+ memcached_strerror(&memc, rc),
+ int(str->size), str->c_str, at);
+ }
+ else
+ {
+ error->size= (int)snprintf(error->message, MAX_ERROR_LENGTH, "(%p) %s -> %s",
+ error->root,
+ memcached_strerror(&memc, rc), at);
+ }
+
+ error->next= memc.error_messages;
+ memc.error_messages= error;
+#if 0
+ if (error_log_fd == -1)
+ {
+ // unlink("/tmp/libmemcachd.log");
+ if ((error_log_fd= open("/tmp/libmemcachd.log", O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0)
+ {
+ perror("open");
+ error_log_fd= -1;
+ }
+ }
+ ::write(error_log_fd, error->message, error->size);
+ ::write(error_log_fd, "\n", 1);
+#endif
+ }
+}
+
+memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, const char *str, size_t length)
+{
+ assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
+ memcached_string_t tmp= { str, length };
+ return memcached_set_error(memc, rc, at, tmp);
+}
+
+memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at, const char *str, size_t length)
+{
+ assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
+ assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a Instance");
+
+ memcached_string_t tmp= { str, length };
+ return memcached_set_error(self, rc, at, tmp);
+}
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+
+memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, memcached_string_t& str)
+{
+ assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
+ if (memcached_fatal(rc))
+ {
+ _set(memc, &str, rc, at);
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_set_parser_error(Memcached& memc,
+ const char *at,
+ const char *format, ...)
+{
+ va_list args;
+
+ char buffer[BUFSIZ];
+ va_start(args, format);
+ int length= vsnprintf(buffer, sizeof(buffer), format, args);
+ va_end(args);
+
+ return memcached_set_error(memc, MEMCACHED_PARSE_ERROR, at, buffer, length);
+}
+
+static inline size_t append_host_to_string(memcached_instance_st& self, char* buffer, const size_t buffer_length)
+{
+ size_t size= 0;
+ switch (self.type)
+ {
+ case MEMCACHED_CONNECTION_TCP:
+ case MEMCACHED_CONNECTION_UDP:
+ size+= snprintf(buffer, buffer_length, " host: %s:%d",
+ self.hostname(), int(self.port()));
+ break;
+
+ case MEMCACHED_CONNECTION_UNIX_SOCKET:
+ size+= snprintf(buffer, buffer_length, " socket: %s",
+ self.hostname());
+ break;
+ }
+
+ return size;
+}
+
+memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at, memcached_string_t& str)
+{
+ assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
+ assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
+ if (memcached_fatal(rc) == false and rc != MEMCACHED_CLIENT_ERROR)
+ {
+ return rc;
+ }
+
+ char hostname_port_message[MAX_ERROR_LENGTH];
+ char* hostname_port_message_ptr= hostname_port_message;
+ int size= 0;
+ if (str.size)
+ {
+ size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ",
+ memcached_string_printf(str));
+ hostname_port_message_ptr+= size;
+ }
+
+ size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
+
+ memcached_string_t error_host= { hostname_port_message, size_t(size) };
+
+ assert_msg(self.root, "Programmer error, root was not set on instance");
+ if (self.root)
+ {
+ _set(*self.root, &error_host, rc, at);
+ _set(self, (*self.root));
+ assert(self.error_messages);
+ assert(self.root->error_messages);
+ assert(self.error_messages->rc == self.root->error_messages->rc);
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_set_error(memcached_instance_st& self, memcached_return_t rc, const char *at)
+{
+ assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_instance_st");
+ if (memcached_fatal(rc) == false)
+ {
+ return rc;
+ }
+
+ char hostname_port[MEMCACHED_NI_MAXHOST +MEMCACHED_NI_MAXSERV + sizeof("host : ")];
+ size_t size= append_host_to_string(self, hostname_port, sizeof(hostname_port));
+
+ memcached_string_t error_host= { hostname_port, size};
+
+ if (self.root)
+ {
+ _set(*self.root, &error_host, rc, at);
+ _set(self, *self.root);
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_set_error(Memcached& self, memcached_return_t rc, const char *at)
+{
+ assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client");
+ if (memcached_fatal(rc) == false)
+ {
+ return rc;
+ }
+
+ _set(self, NULL, rc, at);
+
+ return rc;
+}
+
+memcached_return_t memcached_set_errno(Memcached& self, int local_errno, const char *at, const char *str, size_t length)
+{
+ memcached_string_t tmp= { str, length };
+ return memcached_set_errno(self, local_errno, at, tmp);
+}
+
+memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at, const char *str, size_t length)
+{
+ memcached_string_t tmp= { str, length };
+ return memcached_set_errno(self, local_errno, at, tmp);
+}
+
+memcached_return_t memcached_set_errno(Memcached& self, int local_errno, const char *at)
+{
+ if (local_errno == 0)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ memcached_return_t rc= MEMCACHED_ERRNO;
+ _set(self, NULL, rc, at, local_errno);
+
+ return rc;
+}
+
+memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at, memcached_string_t& str)
+{
+ if (local_errno == 0)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ memcached_return_t rc= MEMCACHED_ERRNO;
+ _set(memc, &str, rc, at, local_errno);
+
+ return rc;
+}
+
+memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at, memcached_string_t& str)
+{
+ if (local_errno == 0)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ char hostname_port_message[MAX_ERROR_LENGTH];
+ char* hostname_port_message_ptr= hostname_port_message;
+ size_t size= 0;
+ if (str.size)
+ {
+ size= snprintf(hostname_port_message_ptr, sizeof(hostname_port_message), "%.*s, ", memcached_string_printf(str));
+ }
+ size+= append_host_to_string(self, hostname_port_message_ptr, sizeof(hostname_port_message) -size);
+
+ memcached_string_t error_host= { hostname_port_message, size };
+
+ memcached_return_t rc= MEMCACHED_ERRNO;
+ if (self.root == NULL)
+ {
+ return rc;
+ }
+
+ _set(*self.root, &error_host, rc, at, local_errno);
+ _set(self, (*self.root));
+
+#if 0
+ if (self.root->error_messages->rc != self.error_messages->rc)
+ {
+ fprintf(stderr, "%s:%d %s != %s\n", __FILE__, __LINE__,
+ memcached_strerror(NULL, self.root->error_messages->rc),
+ memcached_strerror(NULL, self.error_messages->rc));
+ }
+#endif
+
+ return rc;
+}
+
+memcached_return_t memcached_set_errno(memcached_instance_st& self, int local_errno, const char *at)
+{
+ if (local_errno == 0)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ char hostname_port_message[MAX_ERROR_LENGTH];
+ size_t size= append_host_to_string(self, hostname_port_message, sizeof(hostname_port_message));
+
+ memcached_string_t error_host= { hostname_port_message, size };
+
+ memcached_return_t rc= MEMCACHED_ERRNO;
+ if (self.root == NULL)
+ {
+ return rc;
+ }
+
+ _set(*self.root, &error_host, rc, at, local_errno);
+ _set(self, (*self.root));
+
+ return rc;
+}
+
+static void _error_print(const memcached_error_t *error)
+{
+ if (error == NULL)
+ {
+ return;
+ }
+
+ if (error->size == 0)
+ {
+ fprintf(stderr, "\t%s\n", memcached_strerror(NULL, error->rc) );
+ }
+ else
+ {
+ fprintf(stderr, "\t%s %s\n", memcached_strerror(NULL, error->rc), error->message);
+ }
+
+ _error_print(error->next);
+}
+
+void memcached_error_print(const Memcached *shell)
+{
+ const Memcached* self= memcached2Memcached(shell);
+ if (self == NULL)
+ {
+ return;
+ }
+
+ _error_print(self->error_messages);
+
+ for (uint32_t x= 0; x < memcached_server_count(self); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_by_position(self, x);
+
+ _error_print(instance->error_messages);
+ }
+}
+
+static void _error_free(memcached_error_t *error)
+{
+ if (error)
+ {
+ _error_free(error->next);
+
+ libmemcached_free(error->root, error);
+ }
+}
+
+void memcached_error_free(Memcached& self)
+{
+ _error_free(self.error_messages);
+ self.error_messages= NULL;
+}
+
+void memcached_error_free(memcached_instance_st& self)
+{
+ _error_free(self.error_messages);
+ self.error_messages= NULL;
+}
+
+void memcached_error_free(memcached_server_st& self)
+{
+ _error_free(self.error_messages);
+ self.error_messages= NULL;
+}
+
+const char *memcached_error(const memcached_st *memc)
+{
+ return memcached_last_error_message(memc);
+}
+
+const char *memcached_last_error_message(const memcached_st *shell)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ if (memc->error_messages)
+ {
+ if (memc->error_messages->size and memc->error_messages->message[0])
+ {
+ return memc->error_messages->message;
+ }
+
+ return memcached_strerror(memc, memc->error_messages->rc);
+ }
+
+ return memcached_strerror(memc, MEMCACHED_SUCCESS);
+ }
+
+ return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
+}
+
+bool memcached_has_current_error(Memcached &memc)
+{
+ if (memc.error_messages
+ and memc.error_messages->query_id == memc.query_id
+ and memcached_failed(memc.error_messages->rc))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool memcached_has_current_error(memcached_instance_st& server)
+{
+ return memcached_has_current_error(*(server.root));
+}
+
+memcached_return_t memcached_last_error(const memcached_st *shell)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ if (memc->error_messages)
+ {
+ return memc->error_messages->rc;
+ }
+
+ return MEMCACHED_SUCCESS;
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
+
+int memcached_last_error_errno(const memcached_st *shell)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+ if (memc == NULL)
+ {
+ return 0;
+ }
+
+ if (memc->error_messages == NULL)
+ {
+ return 0;
+ }
+
+ return memc->error_messages->local_errno;
+}
+
+const char *memcached_server_error(const memcached_instance_st * server)
+{
+ if (server == NULL)
+ {
+ return NULL;
+ }
+
+ if (server->error_messages == NULL)
+ {
+ return memcached_strerror(server->root, MEMCACHED_SUCCESS);
+ }
+
+ if (server->error_messages->size == 0)
+ {
+ return memcached_strerror(server->root, server->error_messages->rc);
+ }
+
+ return server->error_messages->message;
+}
+
+
+memcached_error_t *memcached_error_copy(const memcached_instance_st& server)
+{
+ if (server.error_messages == NULL)
+ {
+ return NULL;
+ }
+
+ memcached_error_t *error= libmemcached_xmalloc(server.root, memcached_error_t);
+ memcpy(error, server.error_messages, sizeof(memcached_error_t));
+ error->next= NULL;
+
+ return error;
+}
+
+memcached_return_t memcached_server_error_return(const memcached_instance_st * ptr)
+{
+ if (ptr == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (ptr->error_messages)
+ {
+ return ptr->error_messages->rc;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_instance_error_return(memcached_instance_st* instance)
+{
+ if (instance == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (instance->error_messages)
+ {
+ return instance->error_messages->rc;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libmemcached/common.h"
+
+#pragma once
+
+#ifdef __cplusplus
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define MEMCACHED_AT __FILE__ ":" TOSTRING(__LINE__)
+
+memcached_return_t memcached_set_parser_error(Memcached& memc,
+ const char *at,
+ const char *format, ...);
+
+memcached_return_t memcached_set_error(Memcached&, memcached_return_t rc, const char *at);
+
+memcached_return_t memcached_set_error(memcached_instance_st&, memcached_return_t rc, const char *at);
+
+memcached_return_t memcached_set_error(Memcached&, memcached_return_t rc, const char *at, const char *str, size_t length);
+
+memcached_return_t memcached_set_error(memcached_instance_st&, memcached_return_t rc, const char *at, const char *str, size_t length);
+
+memcached_return_t memcached_set_error(Memcached& memc, memcached_return_t rc, const char *at, memcached_string_t& str);
+
+memcached_return_t memcached_set_error(memcached_instance_st&, memcached_return_t rc, const char *at, memcached_string_t& str);
+
+memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at, memcached_string_t& str);
+
+memcached_return_t memcached_set_errno(memcached_instance_st&, int local_errno, const char *at, memcached_string_t& str);
+
+memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at, const char *str, size_t length);
+
+memcached_return_t memcached_set_errno(memcached_instance_st&, int local_errno, const char *at, const char *str, size_t length);
+
+memcached_return_t memcached_set_errno(Memcached& memc, int local_errno, const char *at);
+
+memcached_return_t memcached_set_errno(memcached_instance_st&, int local_errno, const char *at);
+
+bool memcached_has_current_error(Memcached&);
+
+bool memcached_has_current_error(memcached_instance_st&);
+
+void memcached_error_free(Memcached&);
+
+void memcached_error_free(memcached_server_st&);
+
+void memcached_error_free(memcached_instance_st& self);
+
+memcached_error_t *memcached_error_copy(const memcached_instance_st&);
+
+memcached_return_t memcached_instance_error_return(memcached_instance_st*);
+
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static memcached_return_t ascii_exist(Memcached *memc, memcached_instance_st* instance, const char *key, size_t key_length)
+{
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { memcached_literal_param("add ") },
+ { memcached_array_string(memc->_namespace), memcached_array_size(memc->_namespace) },
+ { key, key_length },
+ { memcached_literal_param(" 0") },
+ { memcached_literal_param(" 2678400") },
+ { memcached_literal_param(" 0") },
+ { memcached_literal_param("\r\n") },
+ { memcached_literal_param("\r\n") }
+ };
+
+ /* Send command header */
+ memcached_return_t rc;
+ if (memcached_fatal(rc= memcached_vdo(instance, vector, 9, true)))
+ {
+ return rc;
+ }
+
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+ if (rc == MEMCACHED_NOTSTORED)
+ {
+ rc= MEMCACHED_SUCCESS;
+ }
+
+ if (rc == MEMCACHED_STORED)
+ {
+ rc= MEMCACHED_NOTFOUND;
+ }
+
+ return rc;
+}
+
+static memcached_return_t binary_exist(Memcached *memc, memcached_instance_st* instance, const char *key, size_t key_length)
+{
+ protocol_binary_request_set request= {};
+ size_t send_length= sizeof(request.bytes);
+
+ initialize_binary_request(instance, request.message.header);
+
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_ADD;
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(memc->_namespace)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.extlen= 8;
+ request.message.body.flags= 0;
+ request.message.body.expiration= htonl(2678400);
+
+ request.message.header.request.bodylen= htonl((uint32_t) (key_length
+ +memcached_array_size(memc->_namespace)
+ +request.message.header.request.extlen));
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { request.bytes, send_length },
+ { memcached_array_string(memc->_namespace), memcached_array_size(memc->_namespace) },
+ { key, key_length }
+ };
+
+ /* write the header */
+ memcached_return_t rc;
+ if (memcached_fatal(rc= memcached_vdo(instance, vector, 4, true)))
+ {
+ return rc;
+ }
+
+ rc= memcached_response(instance, NULL, 0, NULL);
+
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ rc= MEMCACHED_NOTFOUND;
+ }
+
+ if (rc == MEMCACHED_DATA_EXISTS)
+ {
+ rc= MEMCACHED_SUCCESS;
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_exist(memcached_st *memc, const char *key, size_t key_length)
+{
+ return memcached_exist_by_key(memc, key, key_length, key, key_length);
+}
+
+memcached_return_t memcached_exist_by_key(memcached_st *shell,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(memc, true)))
+ {
+ return rc;
+ }
+
+ if (memcached_is_udp(memc))
+ {
+ return memcached_set_error(*memc, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
+ }
+
+ uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length);
+ memcached_instance_st* instance= memcached_instance_fetch(memc, server_key);
+
+ if (memcached_is_binary(memc))
+ {
+ rc= binary_exist(memc, instance, key, key_length);
+ }
+ else
+ {
+ rc= ascii_exist(memc, instance, key, key_length);
+ }
+
+ return rc;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+char *memcached_fetch(memcached_st *shell, char *key, size_t *key_length,
+ size_t *value_length,
+ uint32_t *flags,
+ memcached_return_t *error)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ memcached_return_t unused;
+ if (error == NULL)
+ {
+ error= &unused;
+ }
+
+ if (memcached_is_udp(ptr))
+ {
+ if (value_length)
+ {
+ *value_length= 0;
+ }
+
+ if (key_length)
+ {
+ *key_length= 0;
+ }
+
+ if (flags)
+ {
+ *flags= 0;
+ }
+
+ if (key)
+ {
+ *key= 0;
+ }
+
+ *error= MEMCACHED_NOT_SUPPORTED;
+ return NULL;
+ }
+
+ memcached_result_st *result_buffer= &ptr->result;
+ result_buffer= memcached_fetch_result(ptr, result_buffer, error);
+ if (result_buffer == NULL or memcached_failed(*error))
+ {
+ WATCHPOINT_ASSERT(result_buffer == NULL);
+ if (value_length)
+ {
+ *value_length= 0;
+ }
+
+ if (key_length)
+ {
+ *key_length= 0;
+ }
+
+ if (flags)
+ {
+ *flags= 0;
+ }
+
+ if (key)
+ {
+ *key= 0;
+ }
+
+ return NULL;
+ }
+
+ if (value_length)
+ {
+ *value_length= memcached_string_length(&result_buffer->value);
+ }
+
+ if (key)
+ {
+ if (result_buffer->key_length > MEMCACHED_MAX_KEY)
+ {
+ *error= MEMCACHED_KEY_TOO_BIG;
+ if (value_length)
+ {
+ *value_length= 0;
+ }
+
+ if (key_length)
+ {
+ *key_length= 0;
+ }
+
+ if (flags)
+ {
+ *flags= 0;
+ }
+
+ if (key)
+ {
+ *key= 0;
+ }
+
+ return NULL;
+ }
+
+ strncpy(key, result_buffer->item_key, result_buffer->key_length); // For the binary protocol we will cut off the key :(
+ if (key_length)
+ {
+ *key_length= result_buffer->key_length;
+ }
+ }
+
+ if (flags)
+ {
+ *flags= result_buffer->item_flags;
+ }
+
+ return memcached_string_take_value(&result_buffer->value);
+}
+
+memcached_result_st *memcached_fetch_result(memcached_st *ptr,
+ memcached_result_st *result,
+ memcached_return_t *error)
+{
+ memcached_return_t unused;
+ if (error == NULL)
+ {
+ error= &unused;
+ }
+
+ if (ptr == NULL)
+ {
+ *error= MEMCACHED_INVALID_ARGUMENTS;
+ return NULL;
+ }
+
+ if (memcached_is_udp(ptr))
+ {
+ *error= MEMCACHED_NOT_SUPPORTED;
+ return NULL;
+ }
+
+ if (result == NULL)
+ {
+ // If we have already initialized (ie it is in use) our internal, we
+ // create one.
+ if (memcached_is_initialized(&ptr->result))
+ {
+ if ((result= memcached_result_create(ptr, NULL)) == NULL)
+ {
+ *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return NULL;
+ }
+ }
+ else
+ {
+ result= memcached_result_create(ptr, &ptr->result);
+ }
+ }
+
+ *error= MEMCACHED_MAXIMUM_RETURN; // We use this to see if we ever go into the loop
+ memcached_instance_st *server;
+ memcached_return_t read_ret= MEMCACHED_SUCCESS;
+ bool connection_failures= false;
+ while ((server= memcached_io_get_readable_server(ptr, read_ret)))
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ *error= memcached_response(server, buffer, sizeof(buffer), result);
+
+ if (*error == MEMCACHED_IN_PROGRESS)
+ {
+ continue;
+ }
+ else if (*error == MEMCACHED_CONNECTION_FAILURE)
+ {
+ connection_failures= true;
+ continue;
+ }
+ else if (*error == MEMCACHED_SUCCESS)
+ {
+ result->count++;
+ return result;
+ }
+ else if (*error == MEMCACHED_END)
+ {
+ memcached_server_response_reset(server);
+ }
+ else if (*error != MEMCACHED_NOTFOUND)
+ {
+ break;
+ }
+ }
+
+ if (*error == MEMCACHED_NOTFOUND and result->count)
+ {
+ *error= MEMCACHED_END;
+ }
+ else if (*error == MEMCACHED_MAXIMUM_RETURN and result->count)
+ {
+ *error= MEMCACHED_END;
+ }
+ else if (*error == MEMCACHED_MAXIMUM_RETURN) // while() loop was never entered
+ {
+ *error= MEMCACHED_NOTFOUND;
+ }
+ else if (connection_failures)
+ {
+ /*
+ If we have a connection failure to some servers, the caller may
+ wish to treat that differently to getting a definitive NOT_FOUND
+ from all servers, so return MEMCACHED_CONNECTION_FAILURE to allow
+ that.
+ */
+ *error= MEMCACHED_CONNECTION_FAILURE;
+ }
+ else if (*error == MEMCACHED_SUCCESS)
+ {
+ *error= MEMCACHED_END;
+ }
+ else if (result->count == 0)
+ {
+ *error= MEMCACHED_NOTFOUND;
+ }
+
+ /* We have completed reading data */
+ if (memcached_is_allocated(result))
+ {
+ memcached_result_free(result);
+ }
+ else
+ {
+ result->count= 0;
+ memcached_string_reset(&result->value);
+ }
+
+ return NULL;
+}
+
+memcached_return_t memcached_fetch_execute(memcached_st *shell,
+ memcached_execute_fn *callback,
+ void *context,
+ uint32_t number_of_callbacks)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ memcached_result_st *result= &ptr->result;
+ memcached_return_t rc;
+ bool some_errors= false;
+
+ while ((result= memcached_fetch_result(ptr, result, &rc)))
+ {
+ if (memcached_failed(rc) and rc == MEMCACHED_NOTFOUND)
+ {
+ continue;
+ }
+ else if (memcached_failed(rc))
+ {
+ memcached_set_error(*ptr, rc, MEMCACHED_AT);
+ some_errors= true;
+ continue;
+ }
+
+ for (uint32_t x= 0; x < number_of_callbacks; x++)
+ {
+ memcached_return_t ret= (*callback[x])(ptr, result, context);
+ if (memcached_failed(ret))
+ {
+ some_errors= true;
+ memcached_set_error(*ptr, ret, MEMCACHED_AT);
+ break;
+ }
+ }
+ }
+
+ if (some_errors)
+ {
+ return MEMCACHED_SOME_ERRORS;
+ }
+
+ // If we were able to run all keys without issue we return
+ // MEMCACHED_SUCCESS
+ if (memcached_success(rc))
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ return rc;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+bool memcached_flag(const memcached_st& memc, const memcached_flag_t flag)
+{
+ switch (flag)
+ {
+ case MEMCACHED_FLAG_AUTO_EJECT_HOSTS:
+ return memcached_is_auto_eject_hosts(&memc);
+
+ case MEMCACHED_FLAG_BINARY_PROTOCOL:
+ return memcached_is_binary(&memc);
+
+ case MEMCACHED_FLAG_BUFFER_REQUESTS:
+ return memcached_is_buffering(&memc);
+
+ case MEMCACHED_FLAG_HASH_WITH_NAMESPACE:
+ return memcached_is_hash_with_namespace(&memc);
+
+ case MEMCACHED_FLAG_NO_BLOCK:
+ return memcached_is_no_block(&memc);
+
+ case MEMCACHED_FLAG_REPLY:
+ return memcached_is_replying(&memc);
+
+ case MEMCACHED_FLAG_RANDOMIZE_REPLICA_READ:
+ return memcached_is_randomize_replica_read(&memc);
+
+ case MEMCACHED_FLAG_SUPPORT_CAS:
+ return memcached_is_cas(&memc);
+
+ case MEMCACHED_FLAG_TCP_NODELAY:
+ return memcached_is_tcp_nodelay(&memc);
+
+ case MEMCACHED_FLAG_USE_SORT_HOSTS:
+ return memcached_is_use_sort_hosts(&memc);
+
+ case MEMCACHED_FLAG_USE_UDP:
+ return memcached_is_udp(&memc);
+
+ case MEMCACHED_FLAG_VERIFY_KEY:
+ return memcached_is_verify_key(&memc);
+
+ case MEMCACHED_FLAG_TCP_KEEPALIVE:
+ return memcached_is_use_sort_hosts(&memc);
+
+ case MEMCACHED_FLAG_IS_AES:
+ return memcached_is_aes(&memc);
+
+ case MEMCACHED_FLAG_IS_FETCHING_VERSION:
+ return memcached_is_fetching_version(&memc);
+ }
+
+ abort();
+}
+
+void memcached_flag(memcached_st& memc, const memcached_flag_t flag, const bool arg)
+{
+ switch (flag)
+ {
+ case MEMCACHED_FLAG_AUTO_EJECT_HOSTS:
+ memcached_set_auto_eject_hosts(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_BINARY_PROTOCOL:
+ memcached_set_binary(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_BUFFER_REQUESTS:
+ memcached_set_buffering(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_HASH_WITH_NAMESPACE:
+ memcached_set_hash_with_namespace(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_NO_BLOCK:
+ memcached_set_no_block(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_REPLY:
+ memcached_set_replying(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_RANDOMIZE_REPLICA_READ:
+ memcached_set_randomize_replica_read(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_SUPPORT_CAS:
+ memcached_set_cas(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_TCP_NODELAY:
+ memcached_set_tcp_nodelay(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_USE_SORT_HOSTS:
+ memcached_set_use_sort_hosts(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_USE_UDP:
+ memcached_set_udp(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_VERIFY_KEY:
+ memcached_set_verify_key(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_TCP_KEEPALIVE:
+ memcached_set_use_sort_hosts(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_IS_AES:
+ memcached_set_aes(memc, arg);
+ break;
+
+ case MEMCACHED_FLAG_IS_FETCHING_VERSION:
+ memcached_set_fetching_version(memc, arg);
+ break;
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+enum memcached_flag_t
+{
+ MEMCACHED_FLAG_AUTO_EJECT_HOSTS,
+ MEMCACHED_FLAG_BINARY_PROTOCOL,
+ MEMCACHED_FLAG_BUFFER_REQUESTS,
+ MEMCACHED_FLAG_HASH_WITH_NAMESPACE,
+ MEMCACHED_FLAG_NO_BLOCK,
+ MEMCACHED_FLAG_REPLY,
+ MEMCACHED_FLAG_RANDOMIZE_REPLICA_READ,
+ MEMCACHED_FLAG_SUPPORT_CAS,
+ MEMCACHED_FLAG_TCP_NODELAY,
+ MEMCACHED_FLAG_USE_SORT_HOSTS,
+ MEMCACHED_FLAG_USE_UDP,
+ MEMCACHED_FLAG_VERIFY_KEY,
+ MEMCACHED_FLAG_TCP_KEEPALIVE,
+ MEMCACHED_FLAG_IS_AES,
+ MEMCACHED_FLAG_IS_FETCHING_VERSION
+};
+
+bool memcached_flag(const memcached_st&, const memcached_flag_t);
+void memcached_flag(memcached_st&, const memcached_flag_t, const bool);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static memcached_return_t memcached_flush_binary(Memcached *ptr,
+ time_t expiration,
+ const bool reply)
+{
+ protocol_binary_request_flush request= {};
+
+ 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);
+
+ memcached_return_t rc= MEMCACHED_SUCCESS;
+
+ for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
+ initialize_binary_request(instance, request.message.header);
+
+ if (reply)
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
+ }
+ else
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ;
+ }
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { request.bytes, sizeof(request.bytes) }
+ };
+
+ memcached_return_t rrc;
+ if (memcached_failed(rrc= memcached_vdo(instance, vector, 2, true)))
+ {
+ if (instance->error_messages == NULL or instance->root->error_messages == NULL)
+ {
+ memcached_set_error(*instance, rrc, MEMCACHED_AT);
+ }
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+ }
+
+ for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
+
+ if (instance->response_count() > 0)
+ {
+ (void)memcached_response(instance, NULL, 0, NULL);
+ }
+ }
+
+ return rc;
+}
+
+static memcached_return_t memcached_flush_textual(Memcached *ptr,
+ time_t expiration,
+ const bool reply)
+{
+ char buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
+ int send_length= 0;
+ if (expiration)
+ {
+ send_length= snprintf(buffer, sizeof(buffer), "%llu", (unsigned long long)expiration);
+ }
+
+ if (size_t(send_length) >= sizeof(buffer) or send_length < 0)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
+ }
+
+ memcached_return_t rc= MEMCACHED_SUCCESS;
+ for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { memcached_literal_param("flush_all ") },
+ { buffer, size_t(send_length) },
+ { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
+ { memcached_literal_param("\r\n") }
+ };
+
+ memcached_return_t rrc= memcached_vdo(instance, vector, 5, true);
+ if (memcached_success(rrc) and reply == true)
+ {
+ char response_buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ rrc= memcached_response(instance, response_buffer, sizeof(response_buffer), NULL);
+ }
+
+ if (memcached_failed(rrc))
+ {
+ // If an error has already been reported, then don't add to it
+ if (instance->error_messages == NULL or instance->root->error_messages == NULL)
+ {
+ memcached_set_error(*instance, rrc, MEMCACHED_AT);
+ }
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_flush(memcached_st *shell, time_t expiration)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(ptr, true)))
+ {
+ return rc;
+ }
+
+ bool reply= memcached_is_replying(ptr);
+
+ LIBMEMCACHED_MEMCACHED_FLUSH_START();
+ if (memcached_is_binary(ptr))
+ {
+ rc= memcached_flush_binary(ptr, expiration, reply);
+ }
+ else
+ {
+ rc= memcached_flush_textual(ptr, expiration, reply);
+ }
+ LIBMEMCACHED_MEMCACHED_FLUSH_END();
+
+ return rc;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+memcached_return_t memcached_flush_buffers(memcached_st *shell)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ memcached_return_t ret= MEMCACHED_SUCCESS;
+
+ for (uint32_t x= 0; x < memcached_server_count(memc); ++x)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc, x);
+
+ if (instance->write_buffer_offset != 0)
+ {
+ if (instance->fd == INVALID_SOCKET and
+ (ret= memcached_connect(instance)) != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ERROR(ret);
+ return ret;
+ }
+
+ if (memcached_io_write(instance) == false)
+ {
+ ret= MEMCACHED_SOME_ERRORS;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+/*
+ 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 __mget_by_key_real(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ const bool mget_mode);
+char *memcached_get_by_key(memcached_st *shell,
+ const char *group_key,
+ size_t group_key_length,
+ const char *key, size_t key_length,
+ size_t *value_length,
+ uint32_t *flags,
+ memcached_return_t *error)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ memcached_return_t unused;
+ if (error == NULL)
+ {
+ error= &unused;
+ }
+
+ uint64_t query_id= 0;
+ if (ptr)
+ {
+ query_id= ptr->query_id;
+ }
+
+ /* Request the key */
+ *error= __mget_by_key_real(ptr, group_key, group_key_length,
+ (const char * const *)&key, &key_length,
+ 1, false);
+ if (ptr)
+ {
+ assert_msg(ptr->query_id == query_id +1, "Programmer error, the query_id was not incremented.");
+ }
+
+ if (memcached_failed(*error))
+ {
+ if (ptr)
+ {
+ if (memcached_has_current_error(*ptr)) // Find the most accurate error
+ {
+ *error= memcached_last_error(ptr);
+ }
+ }
+
+ if (value_length)
+ {
+ *value_length= 0;
+ }
+
+ return NULL;
+ }
+
+ char *value= memcached_fetch(ptr, NULL, NULL,
+ value_length, flags, error);
+ assert_msg(ptr->query_id == query_id +1, "Programmer error, the query_id was not incremented.");
+
+ /* This is for historical reasons */
+ if (*error == MEMCACHED_END)
+ {
+ *error= MEMCACHED_NOTFOUND;
+ }
+ if (value == NULL)
+ {
+ if (ptr->get_key_failure and *error == MEMCACHED_NOTFOUND)
+ {
+ memcached_result_st key_failure_result;
+ memcached_result_st* result_ptr= memcached_result_create(ptr, &key_failure_result);
+ memcached_return_t rc= ptr->get_key_failure(ptr, key, key_length, result_ptr);
+
+ /* On all failure drop to returning NULL */
+ if (rc == MEMCACHED_SUCCESS or 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(result_ptr)),
+ (memcached_result_length(result_ptr)),
+ 0,
+ (memcached_result_flags(result_ptr)));
+
+ if (rc == MEMCACHED_BUFFERED and latch == 0)
+ {
+ memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
+ }
+ }
+ else
+ {
+ rc= memcached_set(ptr, key, key_length,
+ (memcached_result_value(result_ptr)),
+ (memcached_result_length(result_ptr)),
+ 0,
+ (memcached_result_flags(result_ptr)));
+ }
+
+ if (rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED)
+ {
+ *error= rc;
+ *value_length= memcached_result_length(result_ptr);
+ *flags= memcached_result_flags(result_ptr);
+ char *result_value= memcached_string_take_value(&result_ptr->value);
+ memcached_result_free(result_ptr);
+
+ return result_value;
+ }
+ }
+
+ memcached_result_free(result_ptr);
+ }
+ assert_msg(ptr->query_id == query_id +1, "Programmer error, the query_id was not incremented.");
+
+ return NULL;
+ }
+
+ 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,
+ const uint32_t master_server_key,
+ const bool is_group_key_set,
+ const char * const *keys,
+ const size_t *key_length,
+ const size_t number_of_keys,
+ const bool mget_mode);
+
+static memcached_return_t __mget_by_key_real(memcached_st *ptr,
+ const char *group_key,
+ const size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ const bool mget_mode)
+{
+ bool failures_occured_in_sending= false;
+ const char *get_command= "get";
+ uint8_t get_command_length= 3;
+ unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(ptr, true)))
+ {
+ return rc;
+ }
+
+ if (memcached_is_udp(ptr))
+ {
+ return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
+ }
+
+ LIBMEMCACHED_MEMCACHED_MGET_START();
+
+ if (number_of_keys == 0)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Numbers of keys provided was zero"));
+ }
+
+ if (memcached_failed((rc= memcached_key_test(*ptr, keys, key_length, number_of_keys))))
+ {
+ assert(memcached_last_error(ptr) == rc);
+
+ return rc;
+ }
+
+ bool is_group_key_set= false;
+ if (group_key and group_key_length)
+ {
+ master_server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+ is_group_key_set= true;
+ }
+
+ /*
+ Here is where we pay for the non-block API. We need to remove any data sitting
+ in the queue before we start our get.
+
+ It might be optimum to bounce the connection if count > some number.
+ */
+ for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
+
+ if (instance->response_count())
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+ if (ptr->flags.no_block)
+ {
+ memcached_io_write(instance);
+ }
+
+ while(instance->response_count())
+ {
+ (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
+ }
+ }
+ }
+
+ if (memcached_is_binary(ptr))
+ {
+ return binary_mget_by_key(ptr, master_server_key, is_group_key_set, keys,
+ key_length, number_of_keys, mget_mode);
+ }
+
+ if (ptr->flags.support_cas)
+ {
+ get_command= "gets";
+ get_command_length= 4;
+ }
+
+ /*
+ If a server fails we warn about errors and start all over with sending keys
+ to the server.
+ */
+ WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
+ size_t hosts_connected= 0;
+ for (uint32_t x= 0; x < number_of_keys; x++)
+ {
+ uint32_t server_key;
+
+ if (is_group_key_set)
+ {
+ server_key= master_server_key;
+ }
+ else
+ {
+ server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
+ }
+
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { get_command, get_command_length },
+ { memcached_literal_param(" ") },
+ { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
+ { keys[x], key_length[x] }
+ };
+
+
+ if (instance->response_count() == 0)
+ {
+ rc= memcached_connect(instance);
+
+ if (memcached_failed(rc))
+ {
+ memcached_set_error(*instance, rc, MEMCACHED_AT);
+ continue;
+ }
+ hosts_connected++;
+
+ if ((memcached_io_writev(instance, vector, 1, false)) == false)
+ {
+ failures_occured_in_sending= true;
+ continue;
+ }
+ WATCHPOINT_ASSERT(instance->cursor_active_ == 0);
+ memcached_instance_response_increment(instance);
+ WATCHPOINT_ASSERT(instance->cursor_active_ == 1);
+ }
+
+ {
+ if ((memcached_io_writev(instance, (vector + 1), 3, false)) == false)
+ {
+ memcached_instance_response_reset(instance);
+ failures_occured_in_sending= true;
+ continue;
+ }
+ }
+ }
+
+ if (hosts_connected == 0)
+ {
+ LIBMEMCACHED_MEMCACHED_MGET_END();
+
+ if (memcached_failed(rc))
+ {
+ return rc;
+ }
+
+ return memcached_set_error(*ptr, MEMCACHED_NO_SERVERS, MEMCACHED_AT);
+ }
+
+
+ /*
+ Should we muddle on if some servers are dead?
+ */
+ bool success_happened= false;
+ for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
+
+ if (instance->response_count())
+ {
+ /* We need to do something about non-connnected hosts in the future */
+ if ((memcached_io_write(instance, "\r\n", 2, true)) == -1)
+ {
+ failures_occured_in_sending= true;
+ }
+ else
+ {
+ success_happened= true;
+ }
+ }
+ }
+
+ LIBMEMCACHED_MEMCACHED_MGET_END();
+
+ if (failures_occured_in_sending and success_happened)
+ {
+ return MEMCACHED_SOME_ERRORS;
+ }
+
+ if (success_happened)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ return MEMCACHED_FAILURE; // Complete failure occurred
+}
+
+memcached_return_t memcached_mget_by_key(memcached_st *shell,
+ const char *group_key,
+ size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ return __mget_by_key_real(ptr, group_key, group_key_length, keys, key_length, number_of_keys, true);
+}
+
+memcached_return_t memcached_mget_execute(memcached_st *ptr,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ memcached_execute_fn *callback,
+ void *context,
+ unsigned int number_of_callbacks)
+{
+ return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length,
+ number_of_keys, callback,
+ context, number_of_callbacks);
+}
+
+memcached_return_t memcached_mget_execute_by_key(memcached_st *shell,
+ const char *group_key,
+ size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ memcached_execute_fn *callback,
+ void *context,
+ unsigned int number_of_callbacks)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(ptr, false)))
+ {
+ return rc;
+ }
+
+ if (memcached_is_udp(ptr))
+ {
+ return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
+ }
+
+ if (memcached_is_binary(ptr) == false)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
+ memcached_literal_param("ASCII protocol is not supported for memcached_mget_execute_by_key()"));
+ }
+
+ memcached_callback_st *original_callbacks= ptr->callbacks;
+ memcached_callback_st cb= {
+ callback,
+ context,
+ number_of_callbacks
+ };
+
+ ptr->callbacks= &cb;
+ rc= memcached_mget_by_key(ptr, group_key, group_key_length, keys,
+ key_length, number_of_keys);
+ ptr->callbacks= original_callbacks;
+
+ return rc;
+}
+
+static memcached_return_t simple_binary_mget(memcached_st *ptr,
+ const uint32_t master_server_key,
+ bool is_group_key_set,
+ const char * const *keys,
+ const size_t *key_length,
+ const size_t number_of_keys, const bool mget_mode)
+{
+ memcached_return_t rc= MEMCACHED_NOTFOUND;
+
+ bool flush= (number_of_keys == 1);
+
+ if (memcached_failed(rc= memcached_key_test(*ptr, keys, key_length, number_of_keys)))
+ {
+ return rc;
+ }
+
+ /*
+ If a server fails we warn about errors and start all over with sending keys
+ to the server.
+ */
+ for (uint32_t x= 0; x < number_of_keys; ++x)
+ {
+ uint32_t server_key;
+
+ if (is_group_key_set)
+ {
+ server_key= master_server_key;
+ }
+ else
+ {
+ server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
+ }
+
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
+
+ if (instance->response_count() == 0)
+ {
+ rc= memcached_connect(instance);
+ if (memcached_failed(rc))
+ {
+ continue;
+ }
+ }
+
+ protocol_binary_request_getk request= { }; //= {.bytes= {0}};
+ initialize_binary_request(instance, request.message.header);
+ if (mget_mode)
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ;
+ }
+ else
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
+ }
+
+#if 0
+ {
+ memcached_return_t vk= memcached_validate_key_length(key_length[x], ptr->flags.binary_protocol);
+ if (memcached_failed(rc= memcached_key_test(*memc, (const char **)&key, &key_length, 1)))
+ {
+ memcached_set_error(ptr, vk, MEMCACHED_AT, memcached_literal_param("Key was too long."));
+
+ if (x > 0)
+ {
+ memcached_io_reset(instance);
+ }
+
+ return vk;
+ }
+ }
+#endif
+
+ request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->_namespace)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->_namespace)));
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { request.bytes, sizeof(request.bytes) },
+ { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
+ { keys[x], key_length[x] }
+ };
+
+ if (memcached_io_writev(instance, vector, 3, flush) == false)
+ {
+ 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 and x == ptr->io_key_prefetch) and 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.opcode= PROTOCOL_BINARY_CMD_NOOP;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+ for (uint32_t x= 0; x < memcached_server_count(ptr); ++x)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, x);
+
+ if (instance->response_count())
+ {
+ initialize_binary_request(instance, request.message.header);
+ if ((memcached_io_write(instance) == false) or
+ (memcached_io_write(instance, request.bytes, sizeof(request.bytes), true) == -1))
+ {
+ memcached_instance_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,
+ const size_t number_of_keys)
+{
+ memcached_return_t rc= MEMCACHED_NOTFOUND;
+ uint32_t start= 0;
+ uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
+
+ if (randomize_read)
+ {
+ start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1);
+ }
+
+ /* Loop for each replica */
+ for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica)
+ {
+ bool success= true;
+
+ for (uint32_t x= 0; x < number_of_keys; ++x)
+ {
+ 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 and ((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;
+ }
+
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, server);
+
+ if (instance->response_count() == 0)
+ {
+ rc= memcached_connect(instance);
+
+ if (memcached_failed(rc))
+ {
+ memcached_io_reset(instance);
+ dead_servers[server]= true;
+ success= false;
+ continue;
+ }
+ }
+
+ protocol_binary_request_getk request= {};
+ initialize_binary_request(instance, request.message.header);
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
+ request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->_namespace)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t)(key_length[x] + memcached_array_size(ptr->_namespace)));
+
+ /*
+ * 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_
+ */
+ libmemcached_io_vector_st vector[]=
+ {
+ { request.bytes, sizeof(request.bytes) },
+ { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
+ { keys[x], key_length[x] }
+ };
+
+ if (memcached_io_writev(instance, vector, 3, true) == false)
+ {
+ 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,
+ const uint32_t master_server_key,
+ bool is_group_key_set,
+ const char * const *keys,
+ const size_t *key_length,
+ const size_t number_of_keys,
+ const bool mget_mode)
+{
+ if (ptr->number_of_replicas == 0)
+ {
+ return simple_binary_mget(ptr, master_server_key, is_group_key_set,
+ keys, key_length, number_of_keys, mget_mode);
+ }
+
+ uint32_t* hash= libmemcached_xvalloc(ptr, number_of_keys, uint32_t);
+ bool* dead_servers= libmemcached_xcalloc(ptr, memcached_server_count(ptr), bool);
+
+ if (hash == NULL or dead_servers == NULL)
+ {
+ libmemcached_free(ptr, hash);
+ libmemcached_free(ptr, dead_servers);
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ if (is_group_key_set)
+ {
+ for (size_t x= 0; x < number_of_keys; x++)
+ {
+ hash[x]= master_server_key;
+ }
+ }
+ else
+ {
+ for (size_t x= 0; x < number_of_keys; x++)
+ {
+ hash[x]= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
+ }
+ }
+
+ memcached_return_t rc= replication_binary_mget(ptr, hash, dead_servers, keys,
+ key_length, number_of_keys);
+
+ WATCHPOINT_IFERROR(rc);
+ libmemcached_free(ptr, hash);
+ libmemcached_free(ptr, dead_servers);
+
+ return MEMCACHED_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+
+#include <sys/time.h>
+
+#include <libmemcached/virtual_bucket.h>
+
+uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm)
+{
+ return libhashkit_digest(key, key_length, (hashkit_hash_algorithm_t)hash_algorithm);
+}
+
+static inline uint32_t generate_hash(const Memcached *ptr, const char *key, size_t key_length)
+{
+ return hashkit_digest(&ptr->hashkit, key, key_length);
+}
+
+static uint32_t dispatch_host(const Memcached *ptr, uint32_t hash)
+{
+ switch (ptr->distribution)
+ {
+ case MEMCACHED_DISTRIBUTION_CONSISTENT:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+ {
+ uint32_t num= ptr->ketama.continuum_points_counter;
+ WATCHPOINT_ASSERT(ptr->ketama.continuum);
+
+ memcached_continuum_item_st *begin, *end, *left, *right, *middle;
+ begin= left= ptr->ketama.continuum;
+ end= right= ptr->ketama.continuum + num;
+
+ while (left < right)
+ {
+ middle= left + (right - left) / 2;
+ if (middle->value < hash)
+ left= middle + 1;
+ else
+ right= middle;
+ }
+ if (right == end)
+ right= begin;
+ return right->index;
+ }
+ case MEMCACHED_DISTRIBUTION_MODULA:
+ return hash % memcached_server_count(ptr);
+ case MEMCACHED_DISTRIBUTION_RANDOM:
+ return (uint32_t) random() % memcached_server_count(ptr);
+ case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
+ {
+ return memcached_virtual_bucket_get(ptr, hash);
+ }
+ default:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
+ WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
+ return hash % memcached_server_count(ptr);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ One version is public and will not modify the distribution hash, the other will.
+*/
+static inline uint32_t _generate_hash_wrapper(const Memcached *ptr, const char *key, size_t key_length)
+{
+ WATCHPOINT_ASSERT(memcached_server_count(ptr));
+
+ if (memcached_server_count(ptr) == 1)
+ return 0;
+
+ if (ptr->flags.hash_with_namespace)
+ {
+ size_t temp_length= memcached_array_size(ptr->_namespace) + key_length;
+ char temp[MEMCACHED_MAX_KEY];
+
+ if (temp_length > MEMCACHED_MAX_KEY -1)
+ return 0;
+
+ strncpy(temp, memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace));
+ strncpy(temp + memcached_array_size(ptr->_namespace), key, key_length);
+
+ return generate_hash(ptr, temp, temp_length);
+ }
+ else
+ {
+ return generate_hash(ptr, key, key_length);
+ }
+}
+
+static inline void _regen_for_auto_eject(Memcached *ptr)
+{
+ if (_is_auto_eject_host(ptr) && ptr->ketama.next_distribution_rebuild)
+ {
+ struct timeval now;
+
+ if (gettimeofday(&now, NULL) == 0 and
+ now.tv_sec > ptr->ketama.next_distribution_rebuild)
+ {
+ run_distribution(ptr);
+ }
+ }
+}
+
+void memcached_autoeject(memcached_st *ptr)
+{
+ _regen_for_auto_eject(ptr);
+}
+
+uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length)
+{
+ uint32_t hash= _generate_hash_wrapper(ptr, key, key_length);
+
+ _regen_for_auto_eject(ptr);
+
+ return dispatch_host(ptr, hash);
+}
+
+uint32_t memcached_generate_hash(const memcached_st *shell, const char *key, size_t key_length)
+{
+ const Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ return dispatch_host(ptr, _generate_hash_wrapper(ptr, key, key_length));
+ }
+
+ return UINT32_MAX;
+}
+
+const hashkit_st *memcached_get_hashkit(const memcached_st *shell)
+{
+ const Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ return &ptr->hashkit;
+ }
+
+ return NULL;
+}
+
+memcached_return_t memcached_set_hashkit(memcached_st *shell, hashkit_st *hashk)
+{
+ Memcached* self= memcached2Memcached(shell);
+ if (self)
+ {
+ hashkit_free(&self->hashkit);
+ hashkit_clone(&self->hashkit, hashk);
+
+ return MEMCACHED_SUCCESS;
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
+
+const char * libmemcached_string_hash(memcached_hash_t type)
+{
+ return libhashkit_string_hash((hashkit_hash_algorithm_t)type);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include "libmemcached/assert.hpp"
+
+#include <cmath>
+#include <sys/time.h>
+
+/* Protoypes (static) */
+static memcached_return_t update_continuum(Memcached *ptr);
+
+static int compare_servers(const void *p1, const void *p2)
+{
+ const memcached_instance_st * a= (const memcached_instance_st *)p1;
+ const memcached_instance_st * b= (const memcached_instance_st *)p2;
+
+ int 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 *ptr)
+{
+ if (memcached_server_count(ptr))
+ {
+ qsort(memcached_instance_list(ptr), memcached_server_count(ptr), sizeof(memcached_instance_st), compare_servers);
+ }
+}
+
+
+memcached_return_t run_distribution(Memcached *ptr)
+{
+ if (ptr->flags.use_sort_hosts)
+ {
+ sort_hosts(ptr);
+ }
+
+ switch (ptr->distribution)
+ {
+ case MEMCACHED_DISTRIBUTION_CONSISTENT:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
+ return update_continuum(ptr);
+
+ case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
+ case MEMCACHED_DISTRIBUTION_MODULA:
+ break;
+
+ case MEMCACHED_DISTRIBUTION_RANDOM:
+ srandom((uint32_t) time(NULL));
+ break;
+
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
+ default:
+ assert_msg(0, "Invalid distribution type passed to run_distribution()");
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+static uint32_t ketama_server_hash(const char *key, size_t key_length, uint32_t alignment)
+{
+ unsigned char results[16];
+
+ libhashkit_md5_signature((unsigned char*)key, key_length, results);
+
+ return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
+ | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
+ | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
+ | (results[0 + alignment * 4] & 0xFF);
+}
+
+static int continuum_item_cmp(const void *t1, const void *t2)
+{
+ memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1;
+ memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2;
+
+ /* Why 153? Hmmm... */
+ WATCHPOINT_ASSERT(ct1->value != 153);
+ if (ct1->value == ct2->value)
+ {
+ if (ct1->index == ct2->index)
+ {
+ return 0;
+ }
+ else if (ct1->index > ct2->index)
+ {
+ return 1;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else if (ct1->value > ct2->value)
+ {
+ return 1;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+static memcached_return_t update_continuum(Memcached *ptr)
+{
+ uint32_t continuum_index= 0;
+ uint32_t pointer_counter= 0;
+ uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
+ uint32_t pointer_per_hash= 1;
+ uint32_t live_servers= 0;
+ struct timeval now;
+
+ if (gettimeofday(&now, NULL))
+ {
+ return memcached_set_errno(*ptr, errno, MEMCACHED_AT);
+ }
+
+ memcached_instance_st* list= memcached_instance_list(ptr);
+
+ /* count live servers (those without a retry delay set) */
+ bool is_auto_ejecting= _is_auto_eject_host(ptr);
+ if (is_auto_ejecting)
+ {
+ live_servers= 0;
+ ptr->ketama.next_distribution_rebuild= 0;
+ for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
+ {
+ if (list[host_index].next_retry <= now.tv_sec)
+ {
+ live_servers++;
+ }
+ else
+ {
+ if (ptr->ketama.next_distribution_rebuild == 0 or list[host_index].next_retry < ptr->ketama.next_distribution_rebuild)
+ {
+ ptr->ketama.next_distribution_rebuild= list[host_index].next_retry;
+ }
+ }
+ }
+ }
+ else
+ {
+ live_servers= memcached_server_count(ptr);
+ }
+
+ if (live_servers == 0)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ uint32_t points_per_server = (uint32_t) (memcached_is_weighted_ketama(ptr) ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER);
+ uint32_t continuum_limit = live_servers * points_per_server;
+ uint32_t continuum_extra = MEMCACHED_CONTINUUM_ADDITION * points_per_server;
+
+ if (continuum_limit > ptr->ketama.continuum_count)
+ {
+ memcached_continuum_item_st *new_ptr;
+
+ new_ptr= libmemcached_xrealloc(ptr, ptr->ketama.continuum, continuum_limit + continuum_extra, memcached_continuum_item_st);
+
+ if (new_ptr == 0)
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ ptr->ketama.continuum= new_ptr;
+ ptr->ketama.continuum_count= continuum_limit + continuum_extra;
+ }
+ assert_msg(ptr->ketama.continuum, "Programmer Error, empty ketama continuum");
+
+ uint64_t total_weight= 0;
+ if (memcached_is_weighted_ketama(ptr))
+ {
+ for (uint32_t host_index = 0; host_index < memcached_server_count(ptr); ++host_index)
+ {
+ if (is_auto_ejecting == false or list[host_index].next_retry <= now.tv_sec)
+ {
+ total_weight += list[host_index].weight;
+ }
+ }
+ }
+
+ for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
+ {
+ if (is_auto_ejecting and list[host_index].next_retry > now.tv_sec)
+ {
+ continue;
+ }
+
+ if (memcached_is_weighted_ketama(ptr))
+ {
+ float pct= (float)list[host_index].weight / (float)total_weight;
+ pointer_per_server= (uint32_t) ((::floor((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
+ pointer_per_hash= 4;
+ if (0 && 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);
+ }
+ }
+
+
+ if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY)
+ {
+ for (uint32_t pointer_index= 0;
+ pointer_index < pointer_per_server / pointer_per_hash;
+ pointer_index++)
+ {
+ char sort_host[1 +MEMCACHED_NI_MAXHOST +1 +MEMCACHED_NI_MAXSERV +1 + MEMCACHED_NI_MAXSERV ]= "";
+ int sort_host_length;
+
+ // Spymemcached ketema key format is: hostname/ip:port-index
+ // If hostname is not available then: /ip:port-index
+ sort_host_length= snprintf(sort_host, sizeof(sort_host),
+ "/%s:%u-%u",
+ list[host_index]._hostname,
+ (uint32_t)list[host_index].port(),
+ pointer_index);
+
+ if (size_t(sort_host_length) >= sizeof(sort_host) or sort_host_length < 0)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(sizeof(sort_host))"));
+ }
+
+ if (0 && DEBUG)
+ {
+ fprintf(stdout, "update_continuum: key is %s\n", sort_host);
+ }
+
+ if (memcached_is_weighted_ketama(ptr))
+ {
+ for (uint32_t x= 0; x < pointer_per_hash; x++)
+ {
+ uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
+ ptr->ketama.continuum[continuum_index].index= host_index;
+ ptr->ketama.continuum[continuum_index++].value= value;
+ }
+ }
+ else
+ {
+ uint32_t value= hashkit_digest(&ptr->hashkit, sort_host, (size_t)sort_host_length);
+ ptr->ketama.continuum[continuum_index].index= host_index;
+ ptr->ketama.continuum[continuum_index++].value= value;
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t pointer_index= 1;
+ pointer_index <= pointer_per_server / pointer_per_hash;
+ pointer_index++)
+ {
+ char sort_host[MEMCACHED_NI_MAXHOST +1 +MEMCACHED_NI_MAXSERV +1 +MEMCACHED_NI_MAXSERV]= "";
+ int sort_host_length;
+
+ if (list[host_index].port() == MEMCACHED_DEFAULT_PORT)
+ {
+ sort_host_length= snprintf(sort_host, sizeof(sort_host),
+ "%s-%u",
+ list[host_index]._hostname,
+ pointer_index - 1);
+ }
+ else
+ {
+ sort_host_length= snprintf(sort_host, sizeof(sort_host),
+ "%s:%u-%u",
+ list[host_index]._hostname,
+ (uint32_t)list[host_index].port(),
+ pointer_index - 1);
+ }
+
+ if (size_t(sort_host_length) >= sizeof(sort_host) or sort_host_length < 0)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(sizeof(sort_host)))"));
+ }
+
+ if (memcached_is_weighted_ketama(ptr))
+ {
+ for (uint32_t x = 0; x < pointer_per_hash; x++)
+ {
+ uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
+ ptr->ketama.continuum[continuum_index].index= host_index;
+ ptr->ketama.continuum[continuum_index++].value= value;
+ }
+ }
+ else
+ {
+ uint32_t value= hashkit_digest(&ptr->hashkit, sort_host, (size_t)sort_host_length);
+ ptr->ketama.continuum[continuum_index].index= host_index;
+ ptr->ketama.continuum[continuum_index++].value= value;
+ }
+ }
+ }
+
+ pointer_counter+= pointer_per_server;
+ }
+
+ assert_msg(ptr, "Programmer Error, no valid ptr");
+ assert_msg(ptr->ketama.continuum, "Programmer Error, empty ketama continuum");
+ assert_msg(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE, "invalid size information being given to qsort()");
+ ptr->ketama.continuum_points_counter= pointer_counter;
+ qsort(ptr->ketama.continuum, ptr->ketama.continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
+
+ if (DEBUG)
+ {
+ for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
+ {
+ WATCHPOINT_ASSERT(ptr->ketama.continuum[pointer_index].value <= ptr->ketama.continuum[pointer_index + 1].value);
+ }
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t server_add(Memcached *memc,
+ const memcached_string_t& hostname,
+ in_port_t port,
+ uint32_t weight,
+ memcached_connection_t type)
+{
+ assert_msg(memc, "Programmer mistake, somehow server_add() was passed a NULL memcached_st");
+
+ if (memc->number_of_hosts)
+ {
+ assert(memcached_instance_list(memc));
+ }
+
+ if (memcached_instance_list(memc))
+ {
+ assert(memc->number_of_hosts);
+ }
+
+ uint32_t host_list_size= memc->number_of_hosts +1;
+ memcached_instance_st* new_host_list= libmemcached_xrealloc(memc, memcached_instance_list(memc), host_list_size, memcached_instance_st);
+
+ if (new_host_list == NULL)
+ {
+ return memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+
+ memcached_instance_set(memc, new_host_list, host_list_size);
+ assert(memc->number_of_hosts == host_list_size);
+
+ /* TODO: Check return type */
+ memcached_instance_st* instance= memcached_instance_fetch(memc, memcached_server_count(memc) -1);
+
+ if (__instance_create_with(memc, instance, hostname, port, weight, type) == NULL)
+ {
+ return memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+
+ if (weight > 1)
+ {
+ if (memcached_is_consistent_distribution(memc))
+ {
+ memcached_set_weighted_ketama(memc, true);
+ }
+ }
+
+ return run_distribution(memc);
+}
+
+
+memcached_return_t memcached_server_push(memcached_st *shell, const memcached_server_list_st list)
+{
+ if (list == NULL)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ uint32_t original_host_size= memcached_server_count(ptr);
+ uint32_t count= memcached_server_list_count(list);
+ uint32_t host_list_size= count +original_host_size;
+
+ memcached_instance_st* new_host_list= libmemcached_xrealloc(ptr, memcached_instance_list(ptr), host_list_size, memcached_instance_st);
+
+ if (new_host_list == NULL)
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ memcached_instance_set(ptr, new_host_list, host_list_size);
+
+ ptr->state.is_parsing= true;
+ for (uint32_t x= 0; x < count; ++x, ++original_host_size)
+ {
+ WATCHPOINT_ASSERT(list[x].hostname[0] != 0);
+
+ // We have extended the array, and now we will find it, and use it.
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, original_host_size);
+ WATCHPOINT_ASSERT(instance);
+
+ memcached_string_t hostname= { memcached_string_make_from_cstr(list[x].hostname) };
+ if (__instance_create_with(ptr, instance,
+ hostname,
+ list[x].port, list[x].weight, list[x].type) == NULL)
+ {
+ ptr->state.is_parsing= false;
+ return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+
+ if (list[x].weight > 1)
+ {
+ memcached_set_weighted_ketama(ptr, true);
+ }
+ }
+ ptr->state.is_parsing= false;
+
+ return run_distribution(ptr);
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
+
+memcached_return_t memcached_instance_push(memcached_st *ptr, const struct memcached_instance_st* list, uint32_t number_of_hosts)
+{
+ if (list == NULL)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ uint32_t original_host_size= memcached_server_count(ptr);
+ uint32_t host_list_size= number_of_hosts +original_host_size;
+ memcached_instance_st* new_host_list= libmemcached_xrealloc(ptr, memcached_instance_list(ptr), host_list_size, memcached_instance_st);
+
+ if (new_host_list == NULL)
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ memcached_instance_set(ptr, new_host_list, host_list_size);
+
+ // We don't bother with lookups for this operation
+ ptr->state.is_parsing= true;
+
+ // We use original_host_size since size will now point to the first new
+ // instance allocated.
+ for (uint32_t x= 0; x < number_of_hosts; ++x, ++original_host_size)
+ {
+ WATCHPOINT_ASSERT(list[x]._hostname[0] != 0);
+
+ // We have extended the array, and now we will find it, and use it.
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, original_host_size);
+ WATCHPOINT_ASSERT(instance);
+
+ memcached_string_t hostname= { memcached_string_make_from_cstr(list[x]._hostname) };
+ if (__instance_create_with(ptr, instance,
+ hostname,
+ list[x].port(), list[x].weight, list[x].type) == NULL)
+ {
+ ptr->state.is_parsing= false;
+ return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+
+ if (list[x].weight > 1)
+ {
+ memcached_set_weighted_ketama(ptr, true);
+ }
+ }
+ ptr->state.is_parsing= false;
+
+ 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 *shell,
+ const char *filename,
+ uint32_t weight)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr)
+ {
+ memcached_string_t _filename= { memcached_string_make_from_cstr(filename) };
+ if (memcached_is_valid_filename(_filename) == false)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid filename for socket provided"));
+ }
+
+ return server_add(ptr, _filename, 0, weight, MEMCACHED_CONNECTION_UNIX_SOCKET);
+ }
+
+ return MEMCACHED_FAILURE;
+}
+
+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 *shell,
+ const char *,
+ in_port_t,
+ uint32_t)
+{
+ Memcached* self= memcached2Memcached(shell);
+ if (self)
+ {
+ return memcached_set_error(*self, MEMCACHED_DEPRECATED, MEMCACHED_AT);
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
+
+memcached_return_t memcached_server_add(memcached_st *shell,
+ const char *hostname,
+ in_port_t port)
+{
+ return memcached_server_add_with_weight(shell, hostname, port, 0);
+}
+
+memcached_return_t memcached_server_add_with_weight(memcached_st *shell,
+ const char *hostname,
+ in_port_t port,
+ uint32_t weight)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (port == 0)
+ {
+ port= MEMCACHED_DEFAULT_PORT;
+ }
+
+ size_t hostname_length= hostname ? strlen(hostname) : 0;
+ if (hostname_length == 0)
+ {
+ hostname= "localhost";
+ hostname_length= memcached_literal_param_size("localhost");
+ }
+
+ memcached_string_t _hostname= { hostname, hostname_length };
+
+ if (memcached_is_valid_servername(_hostname) == false)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid hostname provided"));
+ }
+
+ return server_add(ptr, _hostname, port, weight, _hostname.c_str[0] == '/' ? MEMCACHED_CONNECTION_UNIX_SOCKET : MEMCACHED_CONNECTION_TCP);
+}
+
+memcached_return_t memcached_server_add_parsed(memcached_st *ptr,
+ const char *hostname,
+ size_t hostname_length,
+ in_port_t port,
+ uint32_t weight)
+{
+ char buffer[MEMCACHED_NI_MAXHOST]= { 0 };
+
+ memcpy(buffer, hostname, hostname_length);
+ buffer[hostname_length]= 0;
+
+ memcached_string_t _hostname= { buffer, hostname_length };
+
+ return server_add(ptr, _hostname,
+ port,
+ weight,
+ MEMCACHED_CONNECTION_TCP);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+memcached_return_t initialize_query(Memcached *self, bool increment_query_id)
+{
+ if (self == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (increment_query_id)
+ {
+ self->query_id++;
+ }
+
+ if (self->state.is_time_for_rebuild)
+ {
+ memcached_reset(self);
+ }
+
+ if (memcached_server_count(self) == 0)
+ {
+ return memcached_set_error(*self, MEMCACHED_NO_SERVERS, MEMCACHED_AT);
+ }
+
+ memcached_error_free(*self);
+ memcached_result_reset(&self->result);
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t initialize_const_query(const Memcached *self)
+{
+ if (self == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (memcached_server_count(self) == 0)
+ {
+ return MEMCACHED_NO_SERVERS;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+memcached_return_t initialize_query(Memcached *self, bool increment_query_id);
+
+memcached_return_t initialize_const_query(const Memcached *self);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static inline void _server_init(memcached_instance_st* self, Memcached *root,
+ const memcached_string_t& hostname,
+ in_port_t port,
+ uint32_t weight, memcached_connection_t type)
+{
+ self->options.is_shutting_down= false;
+ self->options.is_dead= false;
+ self->options.ready= false;
+ self->_events= 0;
+ self->_revents= 0;
+ self->cursor_active_= 0;
+ self->port_= port;
+ self->fd= INVALID_SOCKET;
+ self->io_bytes_sent= 0;
+ self->request_id= 0;
+ self->server_failure_counter= 0;
+ self->server_failure_counter_query_id= 0;
+ self->server_timeout_counter= 0;
+ self->server_timeout_counter_query_id= 0;
+ self->weight= weight ? weight : 1; // 1 is the default weight value
+ self->io_wait_count.read= 0;
+ self->io_wait_count.write= 0;
+ self->io_wait_count.timeouts= 0;
+ self->io_wait_count._bytes_read= 0;
+ self->major_version= UINT8_MAX;
+ self->micro_version= UINT8_MAX;
+ self->minor_version= UINT8_MAX;
+ self->type= type;
+ self->error_messages= NULL;
+ self->read_ptr= self->read_buffer;
+ self->read_buffer_length= 0;
+ self->write_buffer_offset= 0;
+ self->address_info= NULL;
+ self->address_info_next= NULL;
+
+ self->state= MEMCACHED_SERVER_STATE_NEW;
+ self->next_retry= 0;
+
+ self->root= root;
+ if (root)
+ {
+ self->version= ++root->server_info.version;
+ }
+ else
+ {
+ self->version= UINT_MAX;
+ }
+ self->limit_maxbytes= 0;
+ self->hostname(hostname);
+}
+
+static memcached_instance_st* _server_create(memcached_instance_st* self, const memcached_st *memc)
+{
+ if (self == NULL)
+ {
+ self= libmemcached_xmalloc(memc, memcached_instance_st);
+
+ if (self == NULL)
+ {
+ return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+ }
+
+ self->options.is_allocated= true;
+ }
+ else
+ {
+ self->options.is_allocated= false;
+ }
+
+ self->options.is_initialized= true;
+
+ return self;
+}
+
+void memcached_instance_st::events(short arg)
+{
+ if ((_events | arg) == _events)
+ {
+ return;
+ }
+
+ _events|= arg;
+}
+
+void memcached_instance_st::revents(short arg)
+{
+ if (arg)
+ {
+ options.ready= true;
+ }
+
+ _revents= arg;
+ _events&= short(~arg);
+}
+
+memcached_instance_st* __instance_create_with(memcached_st *memc,
+ memcached_instance_st* self,
+ const memcached_string_t& hostname,
+ const in_port_t port,
+ uint32_t weight,
+ const memcached_connection_t type)
+{
+ if (memcached_is_valid_servername(hostname) == false)
+ {
+ memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid hostname provided"));
+ return NULL;
+ }
+
+ self= _server_create(self, memc);
+
+ if (self == NULL)
+ {
+ return NULL;
+ }
+
+ _server_init(self, const_cast<memcached_st *>(memc), hostname, port, weight, type);
+
+ if (memc and memcached_is_udp(memc))
+ {
+ self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
+ memcached_io_init_udp_header(self, 0);
+ }
+
+ return self;
+}
+
+void __instance_free(memcached_instance_st* self)
+{
+ memcached_quit_server(self, false);
+
+ self->clear_addrinfo();
+ assert(self->address_info_next == NULL);
+
+ memcached_error_free(*self);
+
+ if (memcached_is_allocated(self))
+ {
+ libmemcached_free(self->root, self);
+ }
+ else
+ {
+ self->options.is_initialized= false;
+ }
+}
+
+void memcached_instance_free(memcached_instance_st* self)
+{
+ if (self)
+ {
+ __instance_free(self);
+ }
+}
+
+memcached_return_t memcached_server_cursor(const memcached_st* shell,
+ const memcached_server_fn *callback,
+ void *context,
+ uint32_t number_of_callbacks)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_const_query(memc)))
+ {
+ return rc;
+ }
+
+ size_t errors= 0;
+ for (uint32_t x= 0; x < memcached_instance_list_count(memc); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_by_position(memc, x);
+
+ for (uint32_t y= 0; y < number_of_callbacks; y++)
+ {
+ memcached_return_t ret= (*callback[y])(memc, instance, context);
+
+ if (memcached_failed(ret))
+ {
+ errors++;
+ continue;
+ }
+ }
+ }
+
+ return errors ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_server_execute(memcached_st *memc,
+ memcached_server_execute_fn callback,
+ void *context)
+{
+ if (callback == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ bool some_errors= false;;
+ for (uint32_t x= 0; x < memcached_instance_list_count(memc); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc, x);
+
+ memcached_return_t rc= (*callback)(memc, instance, context);
+ if (rc == MEMCACHED_INVALID_ARGUMENTS)
+ {
+ return rc;
+ }
+ else if (memcached_fatal(rc))
+ {
+ some_errors= true;
+ }
+ }
+
+ (void)some_errors;
+ return MEMCACHED_SUCCESS;
+}
+
+const memcached_instance_st * memcached_server_by_key(memcached_st *shell,
+ const char *key,
+ size_t key_length,
+ memcached_return_t *error)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ memcached_return_t unused;
+ if (error == NULL)
+ {
+ error= &unused;
+ }
+
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_const_query(memc)))
+ {
+ *error= rc;
+ return NULL;
+ }
+
+ if (memcached_failed((memcached_key_test(*memc, (const char **)&key, &key_length, 1))))
+ {
+ *error= memcached_last_error(memc);
+ return NULL;
+ }
+
+ uint32_t server_key= memcached_generate_hash(memc, key, key_length);
+ return memcached_instance_by_position(memc, server_key);
+}
+
+/*
+ If we do not have a valid object to clone from, we toss an error.
+*/
+static memcached_instance_st* memcached_instance_clone(memcached_instance_st* source)
+{
+ /* We just do a normal create if source is missing */
+ if (source == NULL)
+ {
+ return NULL;
+ }
+
+ memcached_string_t hostname_= { memcached_string_make_from_cstr(source->hostname()) };
+ return __instance_create_with(source->root,
+ NULL,
+ hostname_,
+ source->port(), source->weight,
+ source->type);
+}
+
+void set_last_disconnected_host(memcached_instance_st* self)
+{
+ assert(self->root);
+ if (self->root)
+ {
+ if (memcached_server_get_last_disconnect(self->root) and
+ memcached_server_get_last_disconnect(self->root)->version == self->version)
+ {
+ return;
+ }
+
+ // const_cast
+ memcached_st *root= (memcached_st *)self->root;
+
+ memcached_instance_free((memcached_instance_st*)(root->last_disconnected_server));
+
+ // We set is_parsing so that no lookup happens
+ root->state.is_parsing= true;
+ root->last_disconnected_server= memcached_instance_clone(self);
+ root->state.is_parsing= false;
+
+ ((memcached_instance_st*)memcached_server_get_last_disconnect(root))->version= self->version;
+ }
+}
+
+const memcached_instance_st * memcached_server_get_last_disconnect(const memcached_st *shell)
+{
+ const Memcached* self= memcached2Memcached(shell);
+ if (self)
+ {
+ return (const memcached_instance_st *)self->last_disconnected_server;
+ }
+
+ return 0;
+}
+
+void memcached_instance_next_retry(const memcached_instance_st * self, const time_t absolute_time)
+{
+ WATCHPOINT_ASSERT(self);
+ if (self)
+ {
+ ((memcached_instance_st*)self)->next_retry= absolute_time;
+ }
+}
+
+bool memcached_instance_st::valid() const
+{
+ if (fd == INVALID_SOCKET)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool memcached_instance_st::is_shutting_down() const
+{
+ return options.is_shutting_down;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifndef WIN32
+# ifdef HAVE_NETDB_H
+# include <netdb.h>
+# endif
+#endif
+
+#ifdef NI_MAXHOST
+# define MEMCACHED_NI_MAXHOST NI_MAXHOST
+#else
+# define MEMCACHED_NI_MAXHOST 1025
+#endif
+
+#ifdef NI_MAXSERV
+# define MEMCACHED_NI_MAXSERV NI_MAXSERV
+#else
+# define MEMCACHED_NI_MAXSERV 32
+#endif
+
+#include "libmemcached/string.hpp"
+
+// @todo Complete class transformation
+struct memcached_instance_st {
+ in_port_t port() const
+ {
+ return port_;
+ }
+
+ void port(in_port_t arg)
+ {
+ port_= arg;
+ }
+
+ void mark_server_as_clean()
+ {
+ server_failure_counter= 0;
+ server_timeout_counter= 0;
+ next_retry= 0;
+ }
+
+ void disable()
+ {
+ }
+
+ void enable()
+ {
+ }
+
+ bool valid() const;
+
+ bool is_shutting_down() const;
+
+ void start_close_socket();
+ void close_socket();
+ void reset_socket();
+
+ uint32_t response_count() const
+ {
+ return cursor_active_;
+ }
+
+ struct {
+ bool is_allocated;
+ bool is_initialized;
+ bool is_shutting_down;
+ bool is_dead;
+ bool ready;
+ } options;
+
+ short _events;
+ short _revents;
+
+ short events(void)
+ {
+ return _events;
+ }
+
+ short revents(void)
+ {
+ return _revents;
+ }
+
+ const char* hostname()
+ {
+ return _hostname;
+ }
+
+ void hostname(const memcached_string_t& hostname_)
+ {
+ if (hostname_.size)
+ {
+ memcpy(_hostname, hostname_.c_str, hostname_.size);
+ _hostname[hostname_.size]= 0;
+ }
+ else
+ {
+ memcpy(_hostname, memcached_literal_param("localhost"));
+ _hostname[memcached_literal_param_size("localhost")]= 0;
+ }
+ }
+
+ void events(short);
+ void revents(short);
+
+ uint32_t cursor_active_;
+ in_port_t port_;
+ memcached_socket_t fd;
+ uint32_t io_bytes_sent; /* # bytes sent since last read */
+ uint32_t request_id;
+ uint32_t server_failure_counter;
+ uint64_t server_failure_counter_query_id;
+ uint32_t server_timeout_counter;
+ uint64_t server_timeout_counter_query_id;
+ uint32_t weight;
+ uint32_t version;
+ enum memcached_server_state_t state;
+ struct {
+ uint32_t read;
+ uint32_t write;
+ uint32_t timeouts;
+ size_t _bytes_read;
+ } io_wait_count;
+ uint8_t major_version; // Default definition of UINT8_MAX means that it has not been set.
+ uint8_t micro_version; // ditto, and note that this is the third, not second version bit
+ uint8_t minor_version; // ditto
+ memcached_connection_t type;
+ char *read_ptr;
+ size_t read_buffer_length;
+ size_t write_buffer_offset;
+ struct addrinfo *address_info;
+ struct addrinfo *address_info_next;
+ time_t next_retry;
+ struct memcached_st *root;
+ uint64_t limit_maxbytes;
+ struct memcached_error_t *error_messages;
+ char read_buffer[MEMCACHED_MAX_BUFFER];
+ char write_buffer[MEMCACHED_MAX_BUFFER];
+ char _hostname[MEMCACHED_NI_MAXHOST];
+
+ void clear_addrinfo()
+ {
+ if (address_info)
+ {
+ freeaddrinfo(address_info);
+ address_info= NULL;
+ address_info_next= NULL;
+ }
+ }
+};
+
+memcached_instance_st* __instance_create_with(memcached_st *memc,
+ memcached_instance_st* self,
+ const memcached_string_t& _hostname,
+ const in_port_t port,
+ uint32_t weight,
+ const memcached_connection_t type);
+
+memcached_return_t memcached_instance_push(memcached_st *ptr, const memcached_instance_st*, uint32_t);
+
+void __instance_free(memcached_instance_st *);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+void initialize_binary_request(memcached_instance_st* server, protocol_binary_request_header& header)
+{
+ server->request_id++;
+ header.request.magic= PROTOCOL_BINARY_REQ;
+ header.request.opaque= htons(server->request_id);
+}
+
+enum memc_read_or_write {
+ MEM_READ,
+ MEM_WRITE
+};
+
+/**
+ * Try to fill the input buffer for a server with as much
+ * data as possible.
+ *
+ * @param instance the server to pack
+ */
+static bool repack_input_buffer(memcached_instance_st* instance)
+{
+ if (instance->read_ptr != instance->read_buffer)
+ {
+ /* Move all of the data to the beginning of the buffer so
+ ** that we can fit more data into the buffer...
+ */
+ memmove(instance->read_buffer, instance->read_ptr, instance->read_buffer_length);
+ instance->read_ptr= instance->read_buffer;
+ }
+
+ /* There is room in the buffer, try to fill it! */
+ if (instance->read_buffer_length != MEMCACHED_MAX_BUFFER)
+ {
+ do {
+ /* Just try a single read to grab what's available */
+ ssize_t nr;
+ if ((nr= ::recv(instance->fd,
+ instance->read_ptr + instance->read_buffer_length,
+ MEMCACHED_MAX_BUFFER - instance->read_buffer_length,
+ MSG_NOSIGNAL)) <= 0)
+ {
+ if (nr == 0)
+ {
+ memcached_set_error(*instance, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT);
+ }
+ else
+ {
+ switch (get_socket_errno())
+ {
+ case EINTR:
+ continue;
+
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EAGAIN:
+#ifdef __linux
+ case ERESTART:
+#endif
+ break; // No IO is fine, we can just move on
+
+ default:
+ memcached_set_errno(*instance, get_socket_errno(), MEMCACHED_AT);
+ }
+ }
+
+ break;
+ }
+ else // We read data, append to our read buffer
+ {
+ instance->read_buffer_length+= size_t(nr);
+
+ return true;
+ }
+ } while (false);
+ }
+
+ 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 instance the server to star processing iput messages for
+ * @return true if we processed anything, false otherwise
+ */
+static bool process_input_buffer(memcached_instance_st* instance)
+{
+ /*
+ ** We might be able to process some of the response messages if we
+ ** have a callback set up
+ */
+ if (instance->root->callbacks != NULL)
+ {
+ /*
+ * We might have responses... try to read them out and fire
+ * callbacks
+ */
+ memcached_callback_st cb= *instance->root->callbacks;
+
+ memcached_set_processing_input((Memcached *)instance->root, true);
+
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ Memcached *root= (Memcached *)instance->root;
+ memcached_return_t error= memcached_response(instance, buffer, sizeof(buffer), &root->result);
+
+ memcached_set_processing_input(root, false);
+
+ if (error == MEMCACHED_SUCCESS)
+ {
+ for (unsigned int x= 0; x < cb.number_of_callback; x++)
+ {
+ error= (*cb.callback[x])(instance->root, &root->result, cb.context);
+ if (error != MEMCACHED_SUCCESS)
+ {
+ break;
+ }
+ }
+
+ /* @todo what should I do with the error message??? */
+ }
+ /* @todo what should I do with other error messages?? */
+ return true;
+ }
+
+ return false;
+}
+
+static memcached_return_t io_wait(memcached_instance_st* instance,
+ const short events)
+{
+ /*
+ ** 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 (events & POLLOUT)
+ {
+ if (memcached_purge(instance) == false)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+
+ struct pollfd fds;
+ fds.fd= instance->fd;
+ fds.events= events;
+ fds.revents= 0;
+
+ if (fds.events & POLLOUT) /* write */
+ {
+ instance->io_wait_count.write++;
+ }
+ else
+ {
+ instance->io_wait_count.read++;
+ }
+
+ if (instance->root->poll_timeout == 0) // Mimic 0 causes timeout behavior (not all platforms do this)
+ {
+ return memcached_set_error(*instance, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_literal_param("poll_timeout() was set to zero"));
+ }
+
+ size_t loop_max= 5;
+ while (--loop_max) // While loop is for ERESTART or EINTR
+ {
+ int active_fd= poll(&fds, 1, instance->root->poll_timeout);
+
+ if (active_fd >= 1)
+ {
+ assert_msg(active_fd == 1 , "poll() returned an unexpected number of active file descriptors");
+ if (fds.revents & POLLIN or fds.revents & POLLOUT)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ if (fds.revents & POLLHUP)
+ {
+ return memcached_set_error(*instance, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("poll() detected hang up"));
+ }
+
+ if (fds.revents & POLLERR)
+ {
+ int local_errno= EINVAL;
+ int err;
+ socklen_t len= sizeof (err);
+ if (getsockopt(instance->fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == 0)
+ {
+ if (err == 0) // treat this as EINTR
+ {
+ continue;
+ }
+ local_errno= err;
+ }
+ memcached_quit_server(instance, true);
+ return memcached_set_errno(*instance, local_errno, MEMCACHED_AT,
+ memcached_literal_param("poll() returned POLLHUP"));
+ }
+
+ return memcached_set_error(*instance, MEMCACHED_FAILURE, MEMCACHED_AT, memcached_literal_param("poll() returned a value that was not dealt with"));
+ }
+
+ if (active_fd == 0)
+ {
+ return memcached_set_error(*instance, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_literal_param("No active_fd were found"));
+ }
+
+ // Only an error should result in this code being called.
+ int local_errno= get_socket_errno(); // We cache in case memcached_quit_server() modifies errno
+ assert_msg(active_fd == -1 , "poll() returned an unexpected value");
+ switch (local_errno)
+ {
+#ifdef __linux
+ case ERESTART:
+#endif
+ case EINTR:
+ continue;
+
+ case EFAULT:
+ case ENOMEM:
+ memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ break;
+
+ case EINVAL:
+ memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid"));
+ break;
+
+ default:
+ memcached_set_errno(*instance, local_errno, MEMCACHED_AT, memcached_literal_param("poll"));
+ }
+
+ break;
+ }
+
+ memcached_quit_server(instance, true);
+
+ if (memcached_has_error(instance))
+ {
+ return memcached_instance_error_return(instance);
+ }
+
+ return memcached_set_error(*instance, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("number of attempts to call io_wait() failed"));
+}
+
+static bool io_flush(memcached_instance_st* instance,
+ const bool with_flush,
+ memcached_return_t& error)
+{
+ /*
+ ** We might want to purge the input buffer if we haven't consumed
+ ** any output yet... The test for the limits is the purge is inline
+ ** in the purge function to avoid duplicating the logic..
+ */
+ {
+ WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
+
+ if (memcached_purge(instance) == false)
+ {
+ return false;
+ }
+ }
+ char *local_write_ptr= instance->write_buffer;
+ size_t write_length= instance->write_buffer_offset;
+
+ error= MEMCACHED_SUCCESS;
+
+ WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
+
+ /* Looking for memory overflows */
+#if defined(DEBUG)
+ if (write_length == MEMCACHED_MAX_BUFFER)
+ WATCHPOINT_ASSERT(instance->write_buffer == local_write_ptr);
+ WATCHPOINT_ASSERT((instance->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length));
+#endif
+
+ while (write_length)
+ {
+ WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
+ WATCHPOINT_ASSERT(write_length > 0);
+
+ int flags;
+ if (with_flush)
+ {
+ flags= MSG_NOSIGNAL;
+ }
+ else
+ {
+ flags= MSG_NOSIGNAL|MSG_MORE;
+ }
+
+ ssize_t sent_length= ::send(instance->fd, local_write_ptr, write_length, flags);
+ int local_errno= get_socket_errno(); // We cache in case memcached_quit_server() modifies errno
+
+ if (sent_length == SOCKET_ERROR)
+ {
+#if 0 // @todo I should look at why we hit this bit of code hard frequently
+ WATCHPOINT_ERRNO(get_socket_errno());
+ WATCHPOINT_NUMBER(get_socket_errno());
+#endif
+ switch (get_socket_errno())
+ {
+ case ENOBUFS:
+ continue;
+
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ 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(instance) or process_input_buffer(instance))
+ {
+ continue;
+ }
+
+ memcached_return_t rc= io_wait(instance, POLLOUT);
+ if (memcached_success(rc))
+ {
+ continue;
+ }
+ else if (rc == MEMCACHED_TIMEOUT)
+ {
+ return false;
+ }
+
+ memcached_quit_server(instance, true);
+ error= memcached_set_errno(*instance, local_errno, MEMCACHED_AT);
+ return false;
+ }
+ case ENOTCONN:
+ case EPIPE:
+ default:
+ memcached_quit_server(instance, true);
+ error= memcached_set_errno(*instance, local_errno, MEMCACHED_AT);
+ WATCHPOINT_ASSERT(instance->fd == INVALID_SOCKET);
+ return false;
+ }
+ }
+
+ instance->io_bytes_sent+= uint32_t(sent_length);
+
+ local_write_ptr+= sent_length;
+ write_length-= uint32_t(sent_length);
+ }
+
+ WATCHPOINT_ASSERT(write_length == 0);
+ instance->write_buffer_offset= 0;
+
+ return true;
+}
+
+memcached_return_t memcached_io_wait_for_write(memcached_instance_st* instance)
+{
+ return io_wait(instance, POLLOUT);
+}
+
+memcached_return_t memcached_io_wait_for_read(memcached_instance_st* instance)
+{
+ return io_wait(instance, POLLIN);
+}
+
+static memcached_return_t _io_fill(memcached_instance_st* instance)
+{
+ ssize_t data_read;
+ do
+ {
+ data_read= ::recv(instance->fd, instance->read_buffer, MEMCACHED_MAX_BUFFER, MSG_NOSIGNAL);
+ int local_errno= get_socket_errno(); // We cache in case memcached_quit_server() modifies errno
+
+ if (data_read == SOCKET_ERROR)
+ {
+ switch (get_socket_errno())
+ {
+ case EINTR: // We just retry
+ continue;
+
+ case ETIMEDOUT: // OSX
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EAGAIN:
+#ifdef __linux
+ case ERESTART:
+#endif
+ {
+ memcached_return_t io_wait_ret;
+ if (memcached_success(io_wait_ret= io_wait(instance, POLLIN)))
+ {
+ continue;
+ }
+
+ return io_wait_ret;
+ }
+
+ /* fall through */
+
+ case ENOTCONN: // Programmer Error
+ WATCHPOINT_ASSERT(0);
+ // fall through
+ case ENOTSOCK:
+ WATCHPOINT_ASSERT(0);
+ // fall through
+ case EBADF:
+ assert_msg(instance->fd != INVALID_SOCKET, "Programmer error, invalid socket");
+ /* fall through */
+ case EINVAL:
+ case EFAULT:
+ case ECONNREFUSED:
+ default:
+ memcached_quit_server(instance, true);
+ memcached_set_errno(*instance, local_errno, MEMCACHED_AT);
+ break;
+ }
+
+ return memcached_instance_error_return(instance);
+ }
+ else if (data_read == 0)
+ {
+ /*
+ 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(instance, true);
+ return memcached_set_error(*instance, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("::rec() returned zero, server has disconnected"));
+ }
+ instance->io_wait_count._bytes_read+= data_read;
+ } while (data_read <= 0);
+
+ instance->io_bytes_sent= 0;
+ instance->read_buffer_length= (size_t) data_read;
+ instance->read_ptr= instance->read_buffer;
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_io_read(memcached_instance_st* instance,
+ void *buffer, size_t length, ssize_t& nread)
+{
+ assert(memcached_is_udp(instance->root) == false);
+ assert_msg(instance, "Programmer error, memcached_io_read() recieved an invalid Instance"); // Programmer error
+ char *buffer_ptr= static_cast<char *>(buffer);
+
+ if (instance->fd == INVALID_SOCKET)
+ {
+#if 0
+ assert_msg(int(instance->state) <= int(MEMCACHED_SERVER_STATE_ADDRINFO), "Programmer error, invalid socket state");
+#endif
+ return MEMCACHED_CONNECTION_FAILURE;
+ }
+
+ while (length)
+ {
+ if (instance->read_buffer_length == 0)
+ {
+ memcached_return_t io_fill_ret;
+ if (memcached_fatal(io_fill_ret= _io_fill(instance)))
+ {
+ nread= -1;
+ return io_fill_ret;
+ }
+ }
+
+ if (length > 1)
+ {
+ size_t difference= (length > instance->read_buffer_length) ? instance->read_buffer_length : length;
+
+ memcpy(buffer_ptr, instance->read_ptr, difference);
+ length -= difference;
+ instance->read_ptr+= difference;
+ instance->read_buffer_length-= difference;
+ buffer_ptr+= difference;
+ }
+ else
+ {
+ *buffer_ptr= *instance->read_ptr;
+ instance->read_ptr++;
+ instance->read_buffer_length--;
+ buffer_ptr++;
+ break;
+ }
+ }
+
+ nread= ssize_t(buffer_ptr - (char*)buffer);
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_io_slurp(memcached_instance_st* instance)
+{
+ assert_msg(instance, "Programmer error, invalid Instance");
+ assert(memcached_is_udp(instance->root) == false);
+
+ if (instance->fd == INVALID_SOCKET)
+ {
+ assert_msg(int(instance->state) <= int(MEMCACHED_SERVER_STATE_ADDRINFO), "Invalid socket state");
+ return MEMCACHED_CONNECTION_FAILURE;
+ }
+
+ ssize_t data_read;
+ char buffer[MEMCACHED_MAX_BUFFER];
+ do
+ {
+ data_read= ::recv(instance->fd, instance->read_buffer, sizeof(buffer), MSG_NOSIGNAL);
+ if (data_read == SOCKET_ERROR)
+ {
+ switch (get_socket_errno())
+ {
+ case EINTR: // We just retry
+ continue;
+
+ case ETIMEDOUT: // OSX
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EAGAIN:
+#ifdef __linux
+ case ERESTART:
+#endif
+ if (memcached_success(io_wait(instance, POLLIN)))
+ {
+ continue;
+ }
+ return MEMCACHED_IN_PROGRESS;
+
+ /* fall through */
+
+ case ENOTCONN: // Programmer Error
+ case ENOTSOCK:
+ assert(0);
+ /* fall through */
+ case EBADF:
+ assert_msg(instance->fd != INVALID_SOCKET, "Invalid socket state");
+ /* fall through */
+ case EINVAL:
+ case EFAULT:
+ case ECONNREFUSED:
+ default:
+ return MEMCACHED_CONNECTION_FAILURE; // We want this!
+ }
+ }
+ } while (data_read > 0);
+
+ return MEMCACHED_CONNECTION_FAILURE;
+}
+
+static bool _io_write(memcached_instance_st* instance,
+ const void *buffer, size_t length, bool with_flush,
+ size_t& written)
+{
+ assert(instance->fd != INVALID_SOCKET);
+ assert(memcached_is_udp(instance->root) == false);
+
+ const char *buffer_ptr= static_cast<const char *>(buffer);
+
+ const size_t original_length= length;
+
+ while (length)
+ {
+ char *write_ptr;
+ size_t buffer_end= MEMCACHED_MAX_BUFFER;
+ size_t should_write= buffer_end -instance->write_buffer_offset;
+ should_write= (should_write < length) ? should_write : length;
+
+ write_ptr= instance->write_buffer + instance->write_buffer_offset;
+ memcpy(write_ptr, buffer_ptr, should_write);
+ instance->write_buffer_offset+= should_write;
+ buffer_ptr+= should_write;
+ length-= should_write;
+
+ if (instance->write_buffer_offset == buffer_end)
+ {
+ WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
+
+ memcached_return_t rc;
+ if (io_flush(instance, with_flush, rc) == false)
+ {
+ written= original_length -length;
+ return false;
+ }
+ }
+ }
+
+ if (with_flush)
+ {
+ memcached_return_t rc;
+ WATCHPOINT_ASSERT(instance->fd != INVALID_SOCKET);
+ if (io_flush(instance, with_flush, rc) == false)
+ {
+ written= original_length -length;
+ return false;
+ }
+ }
+
+ written= original_length -length;
+
+ return true;
+}
+
+bool memcached_io_write(memcached_instance_st* instance)
+{
+ size_t written;
+ return _io_write(instance, NULL, 0, true, written);
+}
+
+ssize_t memcached_io_write(memcached_instance_st* instance,
+ const void *buffer, const size_t length, const bool with_flush)
+{
+ size_t written;
+
+ if (_io_write(instance, buffer, length, with_flush, written) == false)
+ {
+ return -1;
+ }
+
+ return ssize_t(written);
+}
+
+bool memcached_io_writev(memcached_instance_st* instance,
+ libmemcached_io_vector_st vector[],
+ const size_t number_of, const bool with_flush)
+{
+ ssize_t complete_total= 0;
+ ssize_t total= 0;
+
+ for (size_t x= 0; x < number_of; x++, vector++)
+ {
+ complete_total+= vector->length;
+ if (vector->length)
+ {
+ size_t written;
+ if ((_io_write(instance, vector->buffer, vector->length, false, written)) == false)
+ {
+ return false;
+ }
+ total+= written;
+ }
+ }
+
+ if (with_flush)
+ {
+ if (memcached_io_write(instance) == false)
+ {
+ return false;
+ }
+ }
+
+ return (complete_total == total);
+}
+
+void memcached_instance_st::start_close_socket()
+{
+ if (fd != INVALID_SOCKET)
+ {
+ shutdown(fd, SHUT_WR);
+ options.is_shutting_down= true;
+ }
+}
+
+void memcached_instance_st::reset_socket()
+{
+ if (fd != INVALID_SOCKET)
+ {
+ (void)closesocket(fd);
+ fd= INVALID_SOCKET;
+ }
+}
+
+void memcached_instance_st::close_socket()
+{
+ if (fd != INVALID_SOCKET)
+ {
+ int shutdown_options= SHUT_RD;
+ if (options.is_shutting_down == false)
+ {
+ shutdown_options= SHUT_RDWR;
+ }
+
+ /* in case of death shutdown to avoid blocking at close() */
+ if (shutdown(fd, shutdown_options) == SOCKET_ERROR and get_socket_errno() != ENOTCONN)
+ {
+ WATCHPOINT_NUMBER(fd);
+ WATCHPOINT_ERRNO(get_socket_errno());
+ WATCHPOINT_ASSERT(get_socket_errno());
+ }
+
+ reset_socket();
+ state= MEMCACHED_SERVER_STATE_NEW;
+ }
+
+ state= MEMCACHED_SERVER_STATE_NEW;
+ cursor_active_= 0;
+ io_bytes_sent= 0;
+ write_buffer_offset= size_t(root and memcached_is_udp(root) ? UDP_DATAGRAM_HEADER_LENGTH : 0);
+ read_buffer_length= 0;
+ read_ptr= read_buffer;
+ options.is_shutting_down= false;
+ memcached_server_response_reset(this);
+
+ // We reset the version so that if we end up talking to a different server
+ // we don't have stale server version information.
+ major_version= minor_version= micro_version= UINT8_MAX;
+}
+
+memcached_instance_st* memcached_io_get_readable_server(Memcached *memc, memcached_return_t&)
+{
+#define MAX_SERVERS_TO_POLL 100
+ struct pollfd fds[MAX_SERVERS_TO_POLL];
+ nfds_t host_index= 0;
+
+ for (uint32_t x= 0; x < memcached_server_count(memc) and host_index < MAX_SERVERS_TO_POLL; ++x)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc, x);
+
+ if (instance->read_buffer_length > 0) /* I have data in the buffer */
+ {
+ return instance;
+ }
+
+ if (instance->response_count() > 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_instance_st* instance= memcached_instance_fetch(memc, x);
+
+ if (instance->response_count() > 0)
+ {
+ return instance;
+ }
+ }
+
+ return NULL;
+ }
+
+ int error= poll(fds, host_index, memc->poll_timeout);
+ switch (error)
+ {
+ case -1:
+ memcached_set_errno(*memc, get_socket_errno(), MEMCACHED_AT);
+ /* FALLTHROUGH */
+ case 0:
+ break;
+
+ default:
+ for (nfds_t x= 0; x < host_index; ++x)
+ {
+ if (fds[x].revents & POLLIN)
+ {
+ for (uint32_t y= 0; y < memcached_server_count(memc); ++y)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc, y);
+
+ if (instance->fd == fds[x].fd)
+ {
+ return instance;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ Eventually we will just kill off the server with the problem.
+*/
+void memcached_io_reset(memcached_instance_st* instance)
+{
+ memcached_quit_server(instance, true);
+}
+
+/**
+ * Read a given number of bytes from the server and place it into a specific
+ * buffer. Reset the IO channel on this server if an error occurs.
+ */
+memcached_return_t memcached_safe_read(memcached_instance_st* instance,
+ void *dta,
+ const size_t size)
+{
+ size_t offset= 0;
+ char *data= static_cast<char *>(dta);
+
+ while (offset < size)
+ {
+ ssize_t nread;
+ memcached_return_t rc;
+
+ while (memcached_continue(rc= memcached_io_read(instance, data + offset, size - offset, nread))) { };
+
+ if (memcached_failed(rc))
+ {
+ return rc;
+ }
+
+ offset+= size_t(nread);
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_io_readline(memcached_instance_st* instance,
+ char *buffer_ptr,
+ size_t size,
+ size_t& total_nr)
+{
+ total_nr= 0;
+ bool line_complete= false;
+
+ while (line_complete == false)
+ {
+ if (instance->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(instance, buffer_ptr, 1, nread);
+ if (memcached_failed(rc) and rc == MEMCACHED_IN_PROGRESS)
+ {
+ memcached_quit_server(instance, true);
+ return memcached_set_error(*instance, rc, MEMCACHED_AT);
+ }
+ else if (memcached_failed(rc))
+ {
+ 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 (instance->read_buffer_length and total_nr < size and line_complete == false)
+ {
+ *buffer_ptr = *instance->read_ptr;
+ if (*buffer_ptr == '\n')
+ {
+ line_complete = true;
+ }
+ --instance->read_buffer_length;
+ ++instance->read_ptr;
+ ++total_nr;
+ ++buffer_ptr;
+ }
+
+ if (total_nr == size)
+ {
+ return MEMCACHED_PROTOCOL_ERROR;
+ }
+ }
+
+ return MEMCACHED_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+struct libmemcached_io_vector_st
+{
+ const void *buffer;
+ size_t length;
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+void initialize_binary_request(memcached_instance_st* server, protocol_binary_request_header&);
+
+bool memcached_io_write(memcached_instance_st* ptr);
+
+ssize_t memcached_io_write(memcached_instance_st* ptr,
+ const void *buffer, size_t length, bool with_flush);
+
+bool memcached_io_writev(memcached_instance_st* ptr,
+ libmemcached_io_vector_st vector[],
+ const size_t number_of, const bool with_flush);
+
+memcached_return_t memcached_io_wait_for_write(memcached_instance_st*);
+memcached_return_t memcached_io_wait_for_read(memcached_instance_st*);
+
+void memcached_io_reset(memcached_instance_st* ptr);
+
+memcached_return_t memcached_io_read(memcached_instance_st* ptr,
+ void *buffer, size_t length, ssize_t& nread);
+
+/* Read a line (terminated by '\n') into the buffer */
+memcached_return_t memcached_io_readline(memcached_instance_st* ptr,
+ char *buffer_ptr,
+ size_t size,
+ size_t& total);
+
+/* Read n bytes of data from the server and store them in dta */
+memcached_return_t memcached_safe_read(memcached_instance_st* ptr,
+ void *dta,
+ const size_t size);
+
+memcached_instance_st* memcached_io_get_readable_server(memcached_st *memc, memcached_return_t&);
+
+memcached_return_t memcached_io_slurp(memcached_instance_st* ptr);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+/* These are private */
+#define memcached_is_allocated(__object) ((__object)->options.is_allocated)
+#define memcached_is_encrypted(__object) ((__object)->hashkit._key)
+#define memcached_is_initialized(__object) ((__object)->options.is_initialized)
+#define memcached_is_purging(__object) ((__object)->state.is_purging)
+#define memcached_is_processing_input(__object) ((__object)->state.is_processing_input)
+
+#define memcached_is_aes(__object) ((__object)->flags.is_aes)
+#define memcached_is_udp(__object) ((__object)->flags.use_udp)
+#define memcached_is_verify_key(__object) ((__object)->flags.verify_key)
+#define memcached_is_binary(__object) ((__object)->flags.binary_protocol)
+#define memcached_is_fetching_version(__object) ((__object)->flags.is_fetching_version)
+#define memcached_is_buffering(__object) ((__object)->flags.buffer_requests)
+#define memcached_is_replying(__object) ((__object)->flags.reply)
+#define memcached_is_cas(__object) ((__object)->flags.reply)
+#define memcached_is_randomize_replica_read(__object) ((__object)->flags.randomize_replica_read)
+#define memcached_is_no_block(__object) ((__object)->flags.no_block)
+#define memcached_is_hash_with_namespace(__object) ((__object)->flags.hash_with_namespace)
+#define memcached_is_tcp_nodelay(__object) ((__object)->flags.tcp_nodelay)
+#define memcached_is_auto_eject_hosts(__object) ((__object)->flags.auto_eject_hosts)
+#define memcached_is_use_sort_hosts(__object) ((__object)->flags.use_sort_hosts)
+
+#define memcached_is_ready(__object) ((__object)->options.ready)
+
+#define memcached_is_weighted_ketama(__object) ((__object)->ketama.weighted_)
+
+#define memcached_set_ready(__object, __flag) ((__object)->options.ready= (__flag))
+
+#define memcached_set_aes(__object, __flag) ((__object).flags.is_aes= __flag)
+#define memcached_set_udp(__object, __flag) ((__object).flags.use_udp= __flag)
+#define memcached_set_verify_key(__object, __flag) ((__object).flags.verify_key= __flag)
+#define memcached_set_binary(__object, __flag) ((__object).flags.binary_protocol= __flag)
+#define memcached_set_fetching_version(__object, __flag) ((__object).flags.is_fetching_version= __flag)
+#define memcached_set_buffering(__object, __flag) ((__object).flags.buffer_requests= __flag)
+#define memcached_set_replying(__object, __flag) ((__object).flags.reply= __flag)
+#define memcached_set_cas(__object, __flag) ((__object).flags.reply= __flag)
+#define memcached_set_randomize_replica_read(__object, __flag) ((__object).flags.randomize_replica_read= __flag)
+#define memcached_set_no_block(__object, __flag) ((__object).flags.no_block= __flag)
+#define memcached_set_hash_with_namespace(__object, __flag) ((__object).flags.hash_with_namespace= __flag)
+#define memcached_set_tcp_nodelay(__object, __flag) ((__object).flags.tcp_nodelay= __flag)
+#define memcached_set_auto_eject_hosts(__object, __flag) ((__object).flags.auto_eject_hosts= __flag)
+#define memcached_set_use_sort_hosts(__object, __flag) ((__object).flags.use_sort_hosts= __flag)
+
+#define memcached_has_root(__object) ((__object)->root)
+
+#define memcached_has_error(__object) ((__object)->error_messages)
+
+#define memcached_has_replicas(__object) ((__object)->root->number_of_replicas)
+
+#define memcached_set_processing_input(__object, __value) ((__object)->state.is_processing_input= (__value))
+#define memcached_set_initialized(__object, __value) ((__object)->options.is_initialized= (__value))
+#define memcached_set_allocated(__object, __value) ((__object)->options.is_allocated= (__value))
+
+#define memcached_set_weighted_ketama(__object, __value) ((__object)->ketama.weighted_= (__value))
+
+#define memcached2Memcached(__obj) (__obj)
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static inline memcached_return_t memcached_validate_key_length(size_t key_length, bool)
+{
+ if (key_length == 0)
+ {
+ return MEMCACHED_BAD_KEY_PROVIDED;
+ }
+
+ // No one ever reimplemented MEMCACHED to use keys longer then the original ascii length
+#if 0
+ if (binary)
+ {
+ if (key_length > 0xffff)
+ {
+ return MEMCACHED_BAD_KEY_PROVIDED;
+ }
+ }
+ else
+#endif
+ {
+ if (key_length >= MEMCACHED_MAX_KEY)
+ {
+ return MEMCACHED_BAD_KEY_PROVIDED;
+ }
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_key_test(memcached_st &memc,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys)
+{
+ if (number_of_keys == 0)
+ {
+ return memcached_set_error(memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Numbers of keys provided was zero"));
+ }
+
+ if (keys == NULL or key_length == NULL)
+ {
+ return memcached_set_error(memc, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT, memcached_literal_param("Key was NULL or length of key was zero."));
+ }
+
+ const bool is_binary= memcached_flag(memc, MEMCACHED_FLAG_BINARY_PROTOCOL);
+
+ // If we don't need to verify the key, or we are using the binary protoocol,
+ // we just check the size of the key
+ for (size_t x= 0; x < number_of_keys; ++x)
+ {
+ // We should set binary key, but the memcached server is broken for
+ // longer keys at the moment.
+ memcached_return_t rc= memcached_validate_key_length(*(key_length +x), false /* memc.flags.binary_protocol */);
+ if (memcached_failed(rc))
+ {
+ return memcached_set_error(memc, rc, MEMCACHED_AT, memcached_literal_param("Key provided was too long."));
+ }
+
+ if (memc.flags.verify_key and is_binary == false)
+ {
+ for (size_t y= 0; y < *(key_length +x); ++y)
+ {
+ if ((isgraph(keys[x][y])) == 0)
+ {
+ return memcached_set_error(memc, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT, memcached_literal_param("Key provided had invalid character."));
+ }
+ }
+ }
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+memcached_return_t memcached_key_test(memcached_st& memc,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys);
+
--- /dev/null
+provider libmemcached {
+ probe memcached_delete_start();
+ probe memcached_delete_end();
+ probe memcached_increment_with_initial_start();
+ probe memcached_increment_with_initial_end();
+ probe memcached_decrement_with_initial_start();
+ probe memcached_decrement_with_initial_end();
+ probe memcached_increment_start();
+ probe memcached_increment_end();
+ probe memcached_decrement_start();
+ probe memcached_decrement_end();
+ probe memcached_flush_start();
+ probe memcached_flush_end();
+ probe memcached_set_start();
+ probe memcached_set_end();
+ probe memcached_add_start();
+ probe memcached_add_end();
+ probe memcached_replace_start();
+ probe memcached_replace_end();
+ probe memcached_get_start();
+ probe memcached_get_end();
+ probe memcached_touch_start();
+ probe memcached_touch_end();
+ probe memcached_mget_start();
+ probe memcached_mget_end();
+ probe memcached_connect_start();
+ probe memcached_connect_end();
+ probe memcached_server_add_start();
+ probe memcached_server_add_end();
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+/*
+ * This file contains the definition of the various probes supported by
+ * libmemcached. Currently it only support DTRACE, but just create an
+ * implementation of the following macros to create your own sort of
+ * probing :)
+ */
+
+#ifdef HAVE_DTRACE
+/*
+ * Create the DTrace probes on the system using it (to support both Solaris
+ * and MacOS X
+ */
+#include "libmemcached/dtrace_probes.h"
+
+#else
+/*
+ * Provide dummy macros so that we don't need to clutter the code with
+ * ifdefs when we want to use the probes.
+ */
+
+#define LIBMEMCACHED_MEMCACHED_ADD_END()
+#define LIBMEMCACHED_MEMCACHED_ADD_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_ADD_START()
+#define LIBMEMCACHED_MEMCACHED_ADD_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_CONNECT_END()
+#define LIBMEMCACHED_MEMCACHED_CONNECT_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_CONNECT_START()
+#define LIBMEMCACHED_MEMCACHED_CONNECT_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_DECREMENT_END()
+#define LIBMEMCACHED_MEMCACHED_DECREMENT_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_DECREMENT_START()
+#define LIBMEMCACHED_MEMCACHED_DECREMENT_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_DECREMENT_WITH_INITIAL_END()
+#define LIBMEMCACHED_MEMCACHED_DECREMENT_WITH_INITIAL_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_DECREMENT_WITH_INITIAL_START()
+#define LIBMEMCACHED_MEMCACHED_DECREMENT_WITH_INITIAL_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_DELETE_END()
+#define LIBMEMCACHED_MEMCACHED_DELETE_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_DELETE_START()
+#define LIBMEMCACHED_MEMCACHED_DELETE_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_FLUSH_END()
+#define LIBMEMCACHED_MEMCACHED_FLUSH_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_FLUSH_START()
+#define LIBMEMCACHED_MEMCACHED_FLUSH_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_GET_END()
+#define LIBMEMCACHED_MEMCACHED_GET_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_GET_START()
+#define LIBMEMCACHED_MEMCACHED_GET_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_TOUCH_END()
+#define LIBMEMCACHED_MEMCACHED_TOUCH_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_TOUCH_START()
+#define LIBMEMCACHED_MEMCACHED_TOUCH_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_INCREMENT_END()
+#define LIBMEMCACHED_MEMCACHED_INCREMENT_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_INCREMENT_START()
+#define LIBMEMCACHED_MEMCACHED_INCREMENT_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END()
+#define LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START()
+#define LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_MGET_END()
+#define LIBMEMCACHED_MEMCACHED_MGET_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_MGET_START()
+#define LIBMEMCACHED_MEMCACHED_MGET_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_REPLACE_END()
+#define LIBMEMCACHED_MEMCACHED_REPLACE_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_REPLACE_START()
+#define LIBMEMCACHED_MEMCACHED_REPLACE_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_SERVER_ADD_END()
+#define LIBMEMCACHED_MEMCACHED_SERVER_ADD_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_SERVER_ADD_START()
+#define LIBMEMCACHED_MEMCACHED_SERVER_ADD_START_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_SET_END()
+#define LIBMEMCACHED_MEMCACHED_SET_END_ENABLED() (0)
+#define LIBMEMCACHED_MEMCACHED_SET_START()
+#define LIBMEMCACHED_MEMCACHED_SET_START_ENABLED() (0)
+
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+#include <libmemcached/options.hpp>
+#include <libmemcached/virtual_bucket.h>
+
+static inline bool _memcached_init(Memcached *self)
+{
+ self->state.is_purging= false;
+ self->state.is_processing_input= false;
+ self->state.is_time_for_rebuild= false;
+ self->state.is_parsing= false;
+
+ self->flags.auto_eject_hosts= false;
+ self->flags.binary_protocol= false;
+ self->flags.buffer_requests= false;
+ self->flags.hash_with_namespace= false;
+ self->flags.no_block= false;
+ self->flags.reply= true;
+ self->flags.randomize_replica_read= false;
+ self->flags.support_cas= false;
+ self->flags.tcp_nodelay= false;
+ self->flags.use_sort_hosts= false;
+ self->flags.use_udp= false;
+ self->flags.verify_key= false;
+ self->flags.tcp_keepalive= false;
+ self->flags.is_aes= false;
+ self->flags.is_fetching_version= false;
+
+ self->virtual_bucket= NULL;
+
+ self->distribution= MEMCACHED_DISTRIBUTION_MODULA;
+
+ if (hashkit_create(&self->hashkit) == NULL)
+ {
+ return false;
+ }
+
+ self->server_info.version= 0;
+
+ self->ketama.continuum= NULL;
+ self->ketama.continuum_count= 0;
+ self->ketama.continuum_points_counter= 0;
+ self->ketama.next_distribution_rebuild= 0;
+ self->ketama.weighted_= false;
+
+ self->number_of_hosts= 0;
+ self->servers= NULL;
+ self->last_disconnected_server= NULL;
+
+ self->snd_timeout= 0;
+ self->rcv_timeout= 0;
+ self->server_failure_limit= MEMCACHED_SERVER_FAILURE_LIMIT;
+ self->server_timeout_limit= MEMCACHED_SERVER_TIMEOUT_LIMIT;
+ self->query_id= 1; // 0 is considered invalid
+
+ /* TODO, Document why we picked these defaults */
+ self->io_msg_watermark= 500;
+ self->io_bytes_watermark= 65 * 1024;
+
+ self->tcp_keepidle= 0;
+
+ self->io_key_prefetch= 0;
+ self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
+ self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
+ self->retry_timeout= MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT;
+ self->dead_timeout= MEMCACHED_SERVER_FAILURE_DEAD_TIMEOUT;
+
+ self->send_size= -1;
+ self->recv_size= -1;
+
+ self->user_data= NULL;
+ self->number_of_replicas= 0;
+
+ self->allocators= memcached_allocators_return_default();
+
+ self->on_clone= NULL;
+ self->on_cleanup= NULL;
+ self->get_key_failure= NULL;
+ self->delete_trigger= NULL;
+ self->callbacks= NULL;
+ self->sasl.callbacks= NULL;
+ self->sasl.is_allocated= false;
+
+ self->error_messages= NULL;
+ self->_namespace= NULL;
+ self->configure.initial_pool_size= 1;
+ self->configure.max_pool_size= 1;
+ self->configure.version= -1;
+ self->configure.filename= NULL;
+
+ return true;
+}
+
+static void __memcached_free(Memcached *ptr, bool release_st)
+{
+ /* If we have anything open, lets close it now */
+ send_quit(ptr);
+ memcached_instance_list_free(memcached_instance_list(ptr), memcached_instance_list_count(ptr));
+ memcached_result_free(&ptr->result);
+
+ memcached_virtual_bucket_free(ptr);
+
+ memcached_instance_free((memcached_instance_st*)ptr->last_disconnected_server);
+
+ if (ptr->on_cleanup)
+ {
+ ptr->on_cleanup(ptr);
+ }
+
+ libmemcached_free(ptr, ptr->ketama.continuum);
+ ptr->ketama.continuum= NULL;
+
+ memcached_array_free(ptr->_namespace);
+ ptr->_namespace= NULL;
+
+ memcached_error_free(*ptr);
+
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT and ptr->sasl.callbacks)
+ {
+ memcached_destroy_sasl_auth_data(ptr);
+ }
+
+ if (release_st)
+ {
+ memcached_array_free(ptr->configure.filename);
+ ptr->configure.filename= NULL;
+ }
+
+ hashkit_free(&ptr->hashkit);
+
+ if (memcached_is_allocated(ptr) and release_st)
+ {
+ libmemcached_free(ptr, ptr);
+ }
+}
+
+memcached_st *memcached_create(memcached_st *shell)
+{
+ if (shell)
+ {
+ shell->options.is_allocated= false;
+ }
+ else
+ {
+ shell= (memcached_st *)libmemcached_xmalloc(NULL, memcached_st);
+
+ if (shell == NULL)
+ {
+ return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+ }
+
+ shell->options.is_allocated= true;
+ }
+
+ if (_memcached_init(shell) == false)
+ {
+ memcached_free(shell);
+ return NULL;
+ }
+
+ Memcached* memc= memcached2Memcached(shell);
+ if (memcached_result_create(shell, &memc->result) == NULL)
+ {
+ memcached_free(shell);
+ return NULL;
+ }
+
+ WATCHPOINT_ASSERT_INITIALIZED(&memc->result);
+
+ return shell;
+}
+
+memcached_st *memcached(const char *string, size_t length)
+{
+ if (length == 0 and string)
+ {
+ return NULL;
+ }
+
+ if (length and string == NULL)
+ {
+ return NULL;
+ }
+
+ if (length == 0)
+ {
+ if (bool(getenv("LIBMEMCACHED")))
+ {
+ string= getenv("LIBMEMCACHED");
+ length= string ? strlen(string) : 0;
+ }
+ }
+
+ memcached_st *memc= memcached_create(NULL);
+ if (memc == NULL)
+ {
+ return NULL;
+ }
+
+ if (length == 0 or string == NULL)
+ {
+ return memc;
+ }
+
+ memcached_return_t rc= memcached_parse_configuration(memc, string, length);
+ if (memcached_success(rc) and memcached_parse_filename(memc))
+ {
+ rc= memcached_parse_configure_file(*memc, memcached_parse_filename(memc), memcached_parse_filename_length(memc));
+ }
+
+ if (memcached_failed(rc))
+ {
+ memcached_free(memc);
+ return NULL;
+ }
+
+ return memc;
+}
+
+memcached_return_t memcached_reset(memcached_st *shell)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ WATCHPOINT_ASSERT(ptr);
+ if (ptr == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ bool stored_is_allocated= memcached_is_allocated(ptr);
+ uint64_t query_id= ptr->query_id;
+ __memcached_free(ptr, false);
+ memcached_create(ptr);
+ memcached_set_allocated(ptr, stored_is_allocated);
+ ptr->query_id= query_id;
+
+ if (ptr->configure.filename)
+ {
+ return memcached_parse_configure_file(*ptr, memcached_param_array(ptr->configure.filename));
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+void memcached_servers_reset(memcached_st *shell)
+{
+ Memcached* self= memcached2Memcached(shell);
+ if (self)
+ {
+ libmemcached_free(self, self->ketama.continuum);
+ self->ketama.continuum= NULL;
+ self->ketama.continuum_count= 0;
+ self->ketama.continuum_points_counter= 0;
+
+ memcached_instance_list_free(memcached_instance_list(self), self->number_of_hosts);
+ memcached_instance_set(self, NULL, 0);
+
+ memcached_reset_last_disconnected_server(self);
+ }
+}
+
+void memcached_reset_last_disconnected_server(memcached_st *shell)
+{
+ Memcached* self= memcached2Memcached(shell);
+ if (self)
+ {
+ memcached_instance_free((memcached_instance_st*)self->last_disconnected_server);
+ self->last_disconnected_server= NULL;
+ }
+}
+
+void memcached_free(memcached_st *ptr)
+{
+ if (ptr)
+ {
+ __memcached_free(ptr, true);
+ }
+}
+
+/*
+ clone is the destination, while source is the structure to clone.
+ If source is NULL the call is the same as if a memcached_create() was
+ called.
+*/
+memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
+{
+ if (source == NULL)
+ {
+ return memcached_create(clone);
+ }
+
+ if (clone and memcached_is_allocated(clone))
+ {
+ return NULL;
+ }
+
+ memcached_st *new_clone= memcached_create(clone);
+
+ if (new_clone == NULL)
+ {
+ return NULL;
+ }
+
+ new_clone->flags= source->flags;
+ new_clone->send_size= source->send_size;
+ new_clone->recv_size= source->recv_size;
+ new_clone->poll_timeout= source->poll_timeout;
+ new_clone->connect_timeout= source->connect_timeout;
+ new_clone->retry_timeout= source->retry_timeout;
+ new_clone->dead_timeout= source->dead_timeout;
+ new_clone->distribution= source->distribution;
+
+ if (hashkit_clone(&new_clone->hashkit, &source->hashkit) == NULL)
+ {
+ memcached_free(new_clone);
+ return NULL;
+ }
+
+ new_clone->user_data= source->user_data;
+
+ new_clone->snd_timeout= source->snd_timeout;
+ new_clone->rcv_timeout= source->rcv_timeout;
+
+ new_clone->on_clone= source->on_clone;
+ new_clone->on_cleanup= source->on_cleanup;
+
+ new_clone->allocators= source->allocators;
+
+ new_clone->get_key_failure= source->get_key_failure;
+ new_clone->delete_trigger= source->delete_trigger;
+ new_clone->server_failure_limit= source->server_failure_limit;
+ new_clone->server_timeout_limit= source->server_timeout_limit;
+ new_clone->io_msg_watermark= source->io_msg_watermark;
+ new_clone->io_bytes_watermark= source->io_bytes_watermark;
+ new_clone->io_key_prefetch= source->io_key_prefetch;
+ new_clone->number_of_replicas= source->number_of_replicas;
+ new_clone->tcp_keepidle= source->tcp_keepidle;
+
+ if (memcached_server_count(source))
+ {
+ if (memcached_failed(memcached_push(new_clone, source)))
+ {
+ return NULL;
+ }
+ }
+
+
+ new_clone->_namespace= memcached_array_clone(new_clone, source->_namespace);
+ new_clone->configure.filename= memcached_array_clone(new_clone, source->_namespace);
+ new_clone->configure.version= source->configure.version;
+
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT and source->sasl.callbacks)
+ {
+ if (memcached_failed(memcached_clone_sasl(new_clone, source)))
+ {
+ memcached_free(new_clone);
+ return NULL;
+ }
+ }
+
+ if (memcached_failed(run_distribution(new_clone)))
+ {
+ memcached_free(new_clone);
+
+ return NULL;
+ }
+
+ if (source->on_clone)
+ {
+ source->on_clone(new_clone, source);
+ }
+
+ return new_clone;
+}
+
+void *memcached_get_user_data(const memcached_st *shell)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ return memc->user_data;
+ }
+
+ return NULL;
+}
+
+void *memcached_set_user_data(memcached_st *shell, void *data)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ void *ret= memc->user_data;
+ memc->user_data= data;
+
+ return ret;
+ }
+
+ return NULL;
+}
+
+memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
+{
+ return memcached_instance_push(destination, (memcached_instance_st*)source->servers, source->number_of_hosts);
+}
+
+memcached_instance_st* memcached_instance_fetch(Memcached *ptr, uint32_t server_key)
+{
+ if (ptr == NULL)
+ {
+ return NULL;
+ }
+
+ return &ptr->servers[server_key];
+}
+
+const memcached_instance_st * memcached_server_instance_by_position(const memcached_st *shell, uint32_t server_key)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ return &memc->servers[server_key];
+ }
+
+ return NULL;
+}
+
+memcached_instance_st* memcached_instance_by_position(const memcached_st *shell, uint32_t server_key)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ return &memc->servers[server_key];
+ }
+
+ return NULL;
+}
+
+uint64_t memcached_query_id(const memcached_st *shell)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ return memc->query_id;
+ }
+
+ return 0;
+}
+
+memcached_instance_st* memcached_instance_list(const memcached_st *shell)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ return (memcached_instance_st*)memc->servers;
+ }
+
+ return NULL;
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libmemcached-1.0/memcached.h>
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libmemcached-1.0/memcached.hpp>
+
--- /dev/null
+For your convenience libmemcached contains a copy of protocol_binary.h so that
+you may compile libmemcached without having a memcached server with support
+for the binary protocol installed on your computer. Please do not modify this
+fine, but replace it with a fresh copy from a new distribution if they are
+out of sync.
+
+Trond Norbye
--- /dev/null
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) <2008>, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Summary: Constants used by to implement the binary protocol.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Trond Norbye <trond.norbye@sun.com>
+ */
+
+#ifndef PROTOCOL_BINARY_H
+#define PROTOCOL_BINARY_H
+
+#include <libmemcachedprotocol-0.0/vbucket.h>
+
+/**
+ * \addtogroup Protocol
+ * @{
+ */
+
+/**
+ * This file contains definitions of the constants and packet formats
+ * defined in the binary specification. Please note that you _MUST_ remember
+ * to convert each multibyte field to / from network byte order to / from
+ * host order.
+ */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /**
+ * Definition of the legal "magic" values used in a packet.
+ * See section 3.1 Magic byte
+ */
+ typedef enum {
+ PROTOCOL_BINARY_REQ = 0x80,
+ PROTOCOL_BINARY_RES = 0x81
+ } protocol_binary_magic;
+
+ /**
+ * Definition of the valid response status numbers.
+ * See section 3.2 Response Status
+ */
+ typedef enum {
+ PROTOCOL_BINARY_RESPONSE_SUCCESS = 0x00,
+ PROTOCOL_BINARY_RESPONSE_KEY_ENOENT = 0x01,
+ PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS = 0x02,
+ PROTOCOL_BINARY_RESPONSE_E2BIG = 0x03,
+ PROTOCOL_BINARY_RESPONSE_EINVAL = 0x04,
+ PROTOCOL_BINARY_RESPONSE_NOT_STORED = 0x05,
+ PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL = 0x06,
+ PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET = 0x07,
+ PROTOCOL_BINARY_RESPONSE_AUTH_ERROR = 0x20,
+ PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE = 0x21,
+ PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND = 0x81,
+ PROTOCOL_BINARY_RESPONSE_ENOMEM = 0x82,
+ PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED = 0x83,
+ PROTOCOL_BINARY_RESPONSE_EINTERNAL = 0x84,
+ PROTOCOL_BINARY_RESPONSE_EBUSY = 0x85,
+ PROTOCOL_BINARY_RESPONSE_ETMPFAIL = 0x86
+ } protocol_binary_response_status;
+
+ /**
+ * Defintion of the different command opcodes.
+ * See section 3.3 Command Opcodes
+ */
+ typedef enum {
+ PROTOCOL_BINARY_CMD_GET = 0x00,
+ PROTOCOL_BINARY_CMD_SET = 0x01,
+ PROTOCOL_BINARY_CMD_ADD = 0x02,
+ PROTOCOL_BINARY_CMD_REPLACE = 0x03,
+ PROTOCOL_BINARY_CMD_DELETE = 0x04,
+ PROTOCOL_BINARY_CMD_INCREMENT = 0x05,
+ PROTOCOL_BINARY_CMD_DECREMENT = 0x06,
+ PROTOCOL_BINARY_CMD_QUIT = 0x07,
+ PROTOCOL_BINARY_CMD_FLUSH = 0x08,
+ PROTOCOL_BINARY_CMD_GETQ = 0x09,
+ PROTOCOL_BINARY_CMD_NOOP = 0x0a,
+ PROTOCOL_BINARY_CMD_VERSION = 0x0b,
+ PROTOCOL_BINARY_CMD_GETK = 0x0c,
+ PROTOCOL_BINARY_CMD_GETKQ = 0x0d,
+ PROTOCOL_BINARY_CMD_APPEND = 0x0e,
+ PROTOCOL_BINARY_CMD_PREPEND = 0x0f,
+ PROTOCOL_BINARY_CMD_STAT = 0x10,
+ PROTOCOL_BINARY_CMD_SETQ = 0x11,
+ PROTOCOL_BINARY_CMD_ADDQ = 0x12,
+ PROTOCOL_BINARY_CMD_REPLACEQ = 0x13,
+ PROTOCOL_BINARY_CMD_DELETEQ = 0x14,
+ PROTOCOL_BINARY_CMD_INCREMENTQ = 0x15,
+ PROTOCOL_BINARY_CMD_DECREMENTQ = 0x16,
+ PROTOCOL_BINARY_CMD_QUITQ = 0x17,
+ PROTOCOL_BINARY_CMD_FLUSHQ = 0x18,
+ PROTOCOL_BINARY_CMD_APPENDQ = 0x19,
+ PROTOCOL_BINARY_CMD_PREPENDQ = 0x1a,
+ PROTOCOL_BINARY_CMD_VERBOSITY = 0x1b,
+ PROTOCOL_BINARY_CMD_TOUCH = 0x1c,
+ PROTOCOL_BINARY_CMD_GAT = 0x1d,
+ PROTOCOL_BINARY_CMD_GATQ = 0x1e,
+ PROTOCOL_BINARY_CMD_GATK = 0x23,
+ PROTOCOL_BINARY_CMD_GATKQ = 0x24,
+
+ PROTOCOL_BINARY_CMD_SASL_LIST_MECHS = 0x20,
+ PROTOCOL_BINARY_CMD_SASL_AUTH = 0x21,
+ PROTOCOL_BINARY_CMD_SASL_STEP = 0x22,
+
+ /* These commands are used for range operations and exist within
+ * this header for use in other projects. Range operations are
+ * not expected to be implemented in the memcached server itself.
+ */
+ PROTOCOL_BINARY_CMD_RGET = 0x30,
+ PROTOCOL_BINARY_CMD_RSET = 0x31,
+ PROTOCOL_BINARY_CMD_RSETQ = 0x32,
+ PROTOCOL_BINARY_CMD_RAPPEND = 0x33,
+ PROTOCOL_BINARY_CMD_RAPPENDQ = 0x34,
+ PROTOCOL_BINARY_CMD_RPREPEND = 0x35,
+ PROTOCOL_BINARY_CMD_RPREPENDQ = 0x36,
+ PROTOCOL_BINARY_CMD_RDELETE = 0x37,
+ PROTOCOL_BINARY_CMD_RDELETEQ = 0x38,
+ PROTOCOL_BINARY_CMD_RINCR = 0x39,
+ PROTOCOL_BINARY_CMD_RINCRQ = 0x3a,
+ PROTOCOL_BINARY_CMD_RDECR = 0x3b,
+ PROTOCOL_BINARY_CMD_RDECRQ = 0x3c,
+ /* End Range operations */
+
+ /* VBucket commands */
+ PROTOCOL_BINARY_CMD_SET_VBUCKET = 0x3d,
+ PROTOCOL_BINARY_CMD_GET_VBUCKET = 0x3e,
+ PROTOCOL_BINARY_CMD_DEL_VBUCKET = 0x3f,
+ /* End VBucket commands */
+
+ /* TAP commands */
+ PROTOCOL_BINARY_CMD_TAP_CONNECT = 0x40,
+ PROTOCOL_BINARY_CMD_TAP_MUTATION = 0x41,
+ PROTOCOL_BINARY_CMD_TAP_DELETE = 0x42,
+ PROTOCOL_BINARY_CMD_TAP_FLUSH = 0x43,
+ PROTOCOL_BINARY_CMD_TAP_OPAQUE = 0x44,
+ PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET = 0x45,
+ PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START = 0x46,
+ PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END = 0x47,
+ /* End TAP */
+
+ PROTOCOL_BINARY_CMD_LAST_RESERVED = 0xef,
+
+ /* Scrub the data */
+ PROTOCOL_BINARY_CMD_SCRUB = 0xf0
+ } protocol_binary_command;
+
+ /**
+ * Definition of the data types in the packet
+ * See section 3.4 Data Types
+ */
+ typedef enum {
+ PROTOCOL_BINARY_RAW_BYTES = 0x00
+ } protocol_binary_datatypes;
+
+ /**
+ * Definition of the header structure for a request packet.
+ * See section 2
+ */
+ typedef union {
+ struct {
+ uint8_t magic;
+ uint8_t opcode;
+ uint16_t keylen;
+ uint8_t extlen;
+ uint8_t datatype;
+ uint16_t vbucket;
+ uint32_t bodylen;
+ uint32_t opaque;
+ uint64_t cas;
+ } request;
+ uint8_t bytes[24];
+ } protocol_binary_request_header;
+
+ /**
+ * Definition of the header structure for a response packet.
+ * See section 2
+ */
+ typedef union {
+ struct {
+ uint8_t magic;
+ uint8_t opcode;
+ uint16_t keylen;
+ uint8_t extlen;
+ uint8_t datatype;
+ uint16_t status;
+ uint32_t bodylen;
+ uint32_t opaque;
+ uint64_t cas;
+ } response;
+ uint8_t bytes[24];
+ } protocol_binary_response_header;
+
+ /**
+ * Definition of a request-packet containing no extras
+ */
+ union protocol_binary_request_no_extras {
+ struct {
+ protocol_binary_request_header header;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header)];
+ };
+ typedef union protocol_binary_request_no_extras protocol_binary_request_no_extras;
+
+ /**
+ * Definition of a response-packet containing no extras
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_response_header)];
+ } protocol_binary_response_no_extras;
+
+ /**
+ * Definition of the packet used by the get, getq, getk and getkq command.
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_get;
+ typedef protocol_binary_request_no_extras protocol_binary_request_getq;
+ typedef protocol_binary_request_no_extras protocol_binary_request_getk;
+ typedef protocol_binary_request_no_extras protocol_binary_request_getkq;
+
+ /**
+ * Definition of the packet returned from a successful get, getq, getk and
+ * getkq.
+ * See section 4
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ struct {
+ uint32_t flags;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_response_header) + 4];
+ } protocol_binary_response_get;
+
+ typedef protocol_binary_response_get protocol_binary_response_getq;
+ typedef protocol_binary_response_get protocol_binary_response_getk;
+ typedef protocol_binary_response_get protocol_binary_response_getkq;
+
+ /**
+ * Definition of the packet used by the delete command
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_delete;
+
+ /**
+ * Definition of the packet returned by the delete command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_delete;
+
+ /**
+ * Definition of the packet used by the flush command
+ * See section 4
+ * Please note that the expiration field is optional, so remember to see
+ * check the header.bodysize to see if it is present.
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_flush;
+
+ /**
+ * Definition of the packet returned by the flush command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_flush;
+
+ /**
+ * Definition of the packet used by set, add and replace
+ * See section 4
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t flags;
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 8];
+ } protocol_binary_request_set;
+ typedef protocol_binary_request_set protocol_binary_request_add;
+ typedef protocol_binary_request_set protocol_binary_request_replace;
+
+ /**
+ * Definition of the packet returned by set, add and replace
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_set;
+ typedef protocol_binary_response_no_extras protocol_binary_response_add;
+ typedef protocol_binary_response_no_extras protocol_binary_response_replace;
+
+ /**
+ * Definition of the noop packet
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_noop;
+
+ /**
+ * Definition of the packet returned by the noop command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_noop;
+
+ /**
+ * Definition of the structure used by the increment and decrement
+ * command.
+ * See section 4
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint64_t delta;
+ uint64_t initial;
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 20];
+ } protocol_binary_request_incr;
+ typedef protocol_binary_request_incr protocol_binary_request_decr;
+
+ /**
+ * Definition of the response from an incr or decr command
+ * command.
+ * See section 4
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ struct {
+ uint64_t value;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_response_header) + 8];
+ } protocol_binary_response_incr;
+ typedef protocol_binary_response_incr protocol_binary_response_decr;
+
+ /**
+ * Definition of the quit
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_quit;
+
+ /**
+ * Definition of the packet returned by the quit command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_quit;
+
+ /**
+ * Definition of the packet used by append and prepend command
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_append;
+ typedef protocol_binary_request_no_extras protocol_binary_request_prepend;
+
+ /**
+ * Definition of the packet returned from a successful append or prepend
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_append;
+ typedef protocol_binary_response_no_extras protocol_binary_response_prepend;
+
+ /**
+ * Definition of the packet used by the version command
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_version;
+
+ /**
+ * Definition of the packet returned from a successful version command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_version;
+
+
+ /**
+ * Definition of the packet used by the stats command.
+ * See section 4
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_stats;
+
+ /**
+ * Definition of the packet returned from a successful stats command
+ * See section 4
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_stats;
+
+ /**
+ * Definition of the packet used by the verbosity command
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t level;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_verbosity;
+
+ /**
+ * Definition of the packet returned from the verbosity command
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_verbosity;
+
+ /**
+ * Definition of the packet used by the touch command.
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_touch;
+
+ /**
+ * Definition of the packet returned from the touch command
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_touch;
+
+ /**
+ * Definition of the packet used by the GAT(Q) command.
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ uint32_t expiration;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_gat;
+
+ typedef protocol_binary_request_gat protocol_binary_request_gatq;
+
+ /**
+ * Definition of the packet returned from the GAT(Q)
+ */
+ typedef protocol_binary_response_get protocol_binary_response_gat;
+ typedef protocol_binary_response_get protocol_binary_response_gatq;
+
+
+ /**
+ * Definition of a request for a range operation.
+ * See http://code.google.com/p/memcached/wiki/RangeOps
+ *
+ * These types are used for range operations and exist within
+ * this header for use in other projects. Range operations are
+ * not expected to be implemented in the memcached server itself.
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ struct {
+ uint16_t size;
+ uint8_t reserved;
+ uint8_t flags;
+ uint32_t max_results;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_rangeop;
+
+ typedef protocol_binary_request_rangeop protocol_binary_request_rget;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rset;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rsetq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rappend;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rappendq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rprepend;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rprependq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rdelete;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rdeleteq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rincr;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rincrq;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rdecr;
+ typedef protocol_binary_request_rangeop protocol_binary_request_rdecrq;
+
+
+ /**
+ * Definition of tap commands
+ * See To be written
+ *
+ */
+
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ /**
+ * flags is a bitmask used to set properties for the
+ * the connection. Please In order to be forward compatible
+ * you should set all undefined bits to 0.
+ *
+ * If the bit require extra userdata, it will be stored
+ * in the user-data field of the body (passed to the engine
+ * as enginespeciffic). That means that when you parse the
+ * flags and the engine-specific data, you have to work your
+ * way from bit 0 and upwards to find the correct offset for
+ * the data.
+ *
+ */
+ uint32_t flags;
+
+ /**
+ * Backfill age
+ *
+ * By using this flag you can limit the amount of data being
+ * transmitted. If you don't specify a backfill age, the
+ * server will transmit everything it contains.
+ *
+ * The first 8 bytes in the engine specific data contains
+ * the oldest entry (from epoc) you're interested in.
+ * Specifying a time in the future (for the server you are
+ * connecting to), will cause it to start streaming current
+ * changes.
+ */
+#define TAP_CONNECT_FLAG_BACKFILL 0x01
+ /**
+ * Dump will cause the server to send the data stored on the
+ * server, but disconnect when the keys stored in the server
+ * are transmitted.
+ */
+#define TAP_CONNECT_FLAG_DUMP 0x02
+ /**
+ * The body contains a list of 16 bits words in network byte
+ * order specifying the vbucket ids to monitor. The first 16
+ * bit word contains the number of buckets. The number of 0
+ * means "all buckets"
+ */
+#define TAP_CONNECT_FLAG_LIST_VBUCKETS 0x04
+ /**
+ * The responsibility of the vbuckets is to be transferred
+ * over to the caller when all items are transferred.
+ */
+#define TAP_CONNECT_FLAG_TAKEOVER_VBUCKETS 0x08
+ /**
+ * The tap consumer supports ack'ing of tap messages
+ */
+#define TAP_CONNECT_SUPPORT_ACK 0x10
+ /**
+ * The tap consumer would prefer to just get the keys
+ * back. If the engine supports this it will set
+ * the TAP_FLAG_NO_VALUE flag in each of the
+ * tap packets returned.
+ */
+#define TAP_CONNECT_REQUEST_KEYS_ONLY 0x20
+ /**
+ * The body contains a list of (vbucket_id, last_checkpoint_id)
+ * pairs. This provides the checkpoint support in TAP streams.
+ * The last checkpoint id represents the last checkpoint that
+ * was successfully persisted.
+ */
+#define TAP_CONNECT_CHECKPOINT 0x40
+ /**
+ * The tap consumer is a registered tap client, which means that
+ * the tap server will maintain its checkpoint cursor permanently.
+ */
+#define TAP_CONNECT_REGISTERED_CLIENT 0x80
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 4];
+ } protocol_binary_request_tap_connect;
+
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ struct {
+ uint16_t enginespecific_length;
+ /*
+ * The flag section support the following flags
+ */
+ /**
+ * Request that the consumer send a response packet
+ * for this packet. The opaque field must be preserved
+ * in the response.
+ */
+#define TAP_FLAG_ACK 0x01
+ /**
+ * The value for the key is not included in the packet
+ */
+#define TAP_FLAG_NO_VALUE 0x02
+ uint16_t flags;
+ uint8_t ttl;
+ uint8_t res1;
+ uint8_t res2;
+ uint8_t res3;
+ } tap;
+ struct {
+ uint32_t flags;
+ uint32_t expiration;
+ } item;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 16];
+ } protocol_binary_request_tap_mutation;
+
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ struct {
+ uint16_t enginespecific_length;
+ /**
+ * See the definition of the flags for
+ * protocol_binary_request_tap_mutation for a description
+ * of the available flags.
+ */
+ uint16_t flags;
+ uint8_t ttl;
+ uint8_t res1;
+ uint8_t res2;
+ uint8_t res3;
+ } tap;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + 8];
+ } protocol_binary_request_tap_no_extras;
+
+ typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_delete;
+ typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_flush;
+ typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_opaque;
+ typedef protocol_binary_request_tap_no_extras protocol_binary_request_tap_vbucket_set;
+
+
+ /**
+ * Definition of the packet used by the scrub.
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_scrub;
+
+ /**
+ * Definition of the packet returned from scrub.
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_scrub;
+
+
+ /**
+ * Definition of the packet used by set vbucket
+ */
+ typedef union {
+ struct {
+ protocol_binary_request_header header;
+ struct {
+ vbucket_state_t state;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_request_header) + sizeof(vbucket_state_t)];
+ } protocol_binary_request_set_vbucket;
+ /**
+ * Definition of the packet returned from set vbucket
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_set_vbucket;
+ /**
+ * Definition of the packet used by del vbucket
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_del_vbucket;
+ /**
+ * Definition of the packet returned from del vbucket
+ */
+ typedef protocol_binary_response_no_extras protocol_binary_response_del_vbucket;
+
+ /**
+ * Definition of the packet used by get vbucket
+ */
+ typedef protocol_binary_request_no_extras protocol_binary_request_get_vbucket;
+
+ /**
+ * Definition of the packet returned from get vbucket
+ */
+ typedef union {
+ struct {
+ protocol_binary_response_header header;
+ struct {
+ vbucket_state_t state;
+ } body;
+ } message;
+ uint8_t bytes[sizeof(protocol_binary_response_header) + sizeof(vbucket_state_t)];
+ } protocol_binary_response_get_vbucket;
+
+
+ /**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* PROTOCOL_BINARY_H */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef enum {
+ vbucket_state_active = 1, /**< Actively servicing a vbucket. */
+ vbucket_state_replica, /**< Servicing a vbucket as a replica only. */
+ vbucket_state_pending, /**< Pending active. */
+ vbucket_state_dead /**< Not in use, pending deletion. */
+} vbucket_state_t;
+
+#define is_valid_vbucket_state_t(state) \
+ (state == vbucket_state_active || \
+ state == vbucket_state_replica || \
+ state == vbucket_state_pending || \
+ state == vbucket_state_dead)
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <mem_config.h>
+
+#include <libmemcached/common.h>
+
+#ifdef __cplusplus
+#include <cstddef>
+#include <cstdlib>
+#else
+#include <stddef.h>
+#include <stdlib.h>
+#endif
+
+static inline void libmemcached_free(const memcached_st *self, void *mem)
+{
+ if (self)
+ {
+ self->allocators.free(self, mem, self->allocators.context);
+ }
+ else if (mem)
+ {
+#ifdef __cplusplus
+ std::free(mem);
+#else
+ free(mem);
+#endif
+ }
+}
+
+static inline void *libmemcached_malloc(const memcached_st *self, const size_t size)
+{
+ if (self)
+ {
+ return self->allocators.malloc(self, size, self->allocators.context);
+ }
+
+#ifdef __cplusplus
+ return std::malloc(size);
+#else
+ return malloc(size);
+#endif
+}
+#define libmemcached_xmalloc(__memcachd_st, __type) ((__type *)libmemcached_malloc((__memcachd_st), sizeof(__type)))
+
+static inline void *libmemcached_realloc(const memcached_st *self, void *mem, size_t nmemb, const size_t size)
+{
+ if (self)
+ {
+ return self->allocators.realloc(self, mem, nmemb * size, self->allocators.context);
+ }
+
+#ifdef __cplusplus
+ return std::realloc(mem, size);
+#else
+ return realloc(mem, size);
+#endif
+}
+#define libmemcached_xrealloc(__memcachd_st, __mem, __nelem, __type) ((__type *)libmemcached_realloc((__memcachd_st), (__mem), (__nelem), sizeof(__type)))
+#define libmemcached_xvalloc(__memcachd_st, __nelem, __type) ((__type *)libmemcached_realloc((__memcachd_st), NULL, (__nelem), sizeof(__type)))
+
+static inline void *libmemcached_calloc(const memcached_st *self, size_t nelem, size_t size)
+{
+ if (self)
+ {
+ return self->allocators.calloc(self, nelem, size, self->allocators.context);
+ }
+
+#ifdef __cplusplus
+ return std::calloc(nelem, size);
+#else
+ return calloc(nelem, size);
+#endif
+}
+#define libmemcached_xcalloc(__memcachd_st, __nelem, __type) ((__type *)libmemcached_calloc((__memcachd_st), (__nelem), sizeof(__type)))
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libmemcached/common.h"
+#include "libmemcached/assert.hpp"
+
+memcached_return_t memcached_set_namespace(Memcached& memc, const char *key, size_t key_length)
+{
+ if (key and key_length == 0)
+ {
+ WATCHPOINT_ASSERT(key_length);
+ return memcached_set_error(memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid namespace, namespace string had value but length was 0"));
+ }
+ else if (key_length and key == NULL)
+ {
+ WATCHPOINT_ASSERT(key);
+ return memcached_set_error(memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid namespace, namespace string length was > 1 but namespace string was null "));
+ }
+ else if (key and key_length)
+ {
+ bool orig= memc.flags.verify_key;
+ memc.flags.verify_key= true;
+ if (memcached_failed(memcached_key_test(memc, (const char **)&key, &key_length, 1)))
+ {
+ memc.flags.verify_key= orig;
+ return memcached_last_error(&memc);
+ }
+ memc.flags.verify_key= orig;
+
+ if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1))
+ {
+ return memcached_set_error(memc, MEMCACHED_KEY_TOO_BIG, MEMCACHED_AT);
+ }
+
+ memcached_array_free(memc._namespace);
+ memc._namespace= memcached_strcpy(&memc, key, key_length);
+
+ if (memc._namespace == NULL)
+ {
+ return memcached_set_error(memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+ }
+ else
+ {
+ memcached_array_free(memc._namespace);
+ memc._namespace= NULL;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+const char * memcached_get_namespace(Memcached& memc)
+{
+ if (memc._namespace == NULL)
+ {
+ return NULL;
+ }
+
+ return memcached_array_string(memc._namespace);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+
+memcached_return_t memcached_set_namespace(Memcached&, const char *str, size_t length);
+
+const char * memcached_get_namespace(Memcached&);
+
+#endif // __cplusplus
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <libmemcached/options.hpp>
+
+#include <libmemcached/csl/context.h>
+
+const char *memcached_parse_filename(memcached_st *memc)
+{
+ assert_msg(memc, "Invalid memcached_st");
+ return memcached_array_string(memc->configure.filename);
+}
+
+size_t memcached_parse_filename_length(memcached_st *memc)
+{
+ return memcached_array_size(memc->configure.filename);
+}
+
+static memcached_return_t _parse_file_options(memcached_st& self, memcached_array_st *real_name)
+{
+ FILE *fp= fopen(memcached_array_string(real_name), "r");
+ if (not fp)
+ {
+ memcached_string_t error_message= memcached_array_to_string(real_name);
+ memcached_return_t rc= memcached_set_errno(self, errno, MEMCACHED_AT, error_message);
+ return rc;
+ }
+
+ char buffer[BUFSIZ];
+ memcached_return_t rc= MEMCACHED_INVALID_ARGUMENTS;
+ while (fgets(buffer, sizeof(buffer), fp))
+ {
+ size_t length= strlen(buffer);
+
+ if (length == 1 and buffer[0] == '\n')
+ continue;
+
+ if (memcached_failed(rc= memcached_parse_configuration(&self, buffer, length)))
+ break;
+ }
+ fclose(fp);
+
+ return rc;
+}
+
+memcached_return_t libmemcached_check_configuration(const char *option_string, size_t length, char *error_buffer, size_t error_buffer_size)
+{
+ memcached_st memc, *memc_ptr;
+
+ if (option_string == NULL or length == 0)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (error_buffer and error_buffer_size)
+ {
+ error_buffer[0]= 0;
+ }
+
+ if (not (memc_ptr= memcached_create(&memc)))
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ memcached_return_t rc= memcached_parse_configuration(memc_ptr, option_string, length);
+ if (memcached_failed(rc) and error_buffer and error_buffer_size)
+ {
+ strncpy(error_buffer, memcached_last_error_message(memc_ptr), error_buffer_size);
+ error_buffer[error_buffer_size -1]= 0;
+ }
+
+ bool has_filename= memcached_behavior_get(memc_ptr, MEMCACHED_BEHAVIOR_LOAD_FROM_FILE);
+ if (memcached_success(rc) and has_filename)
+ {
+ assert_msg(memcached_parse_filename(memc_ptr), "Invalid configuration file");
+ assert_msg(memcached_parse_filename_length(memc_ptr), "Invalid configuration file");
+ rc= _parse_file_options(*memc_ptr, memc_ptr->configure.filename);
+
+ if (memcached_failed(rc) and error_buffer and error_buffer_size)
+ {
+ strncpy(error_buffer, memcached_last_error_message(memc_ptr), error_buffer_size);
+ error_buffer[error_buffer_size -1]= 0;
+ }
+ }
+
+ memcached_free(memc_ptr);
+
+ return rc;
+}
+
+memcached_return_t memcached_parse_configuration(memcached_st *self, char const *option_string, size_t length)
+{
+ WATCHPOINT_ASSERT(self);
+ if (not self)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ memcached_return_t rc;
+ Context context(option_string, length, self, rc);
+
+ context.start();
+
+ return rc;
+}
+
+void memcached_set_configuration_file(memcached_st *self, const char *filename, size_t filename_length)
+{
+ assert_msg(filename, "Invalid filename");
+ assert_msg(filename_length, "Invalid filename_length");
+ memcached_array_free(self->configure.filename);
+ self->configure.filename= memcached_strcpy(self, filename, filename_length);
+}
+
+memcached_return_t memcached_parse_configure_file(memcached_st& self, const char *filename, size_t length)
+{
+ if (not filename)
+ {
+ return memcached_set_error(self, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT);
+ }
+
+ WATCHPOINT_ASSERT(self);
+ if (not length)
+ {
+ return memcached_set_error(self, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT);
+ }
+
+ memcached_array_st *tmp_array= memcached_strcpy(&self, filename, length);
+
+ if (not tmp_array)
+ {
+ return memcached_set_error(self, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+
+ memcached_return_t rc= memcached_parse_configure_file(self, *tmp_array);
+ memcached_array_free(tmp_array);
+
+ return rc;
+}
+
+memcached_return_t memcached_parse_configure_file(memcached_st& self, memcached_array_st& filename)
+{
+ WATCHPOINT_ASSERT(memcached_array_size(&filename));
+ if (not memcached_array_size(&filename))
+ {
+ return memcached_set_error(self, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT);
+ }
+
+ return _parse_file_options(self, &filename);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+LIBMEMCACHED_LOCAL
+ void memcached_set_configuration_file(memcached_st *self, const char *filename, size_t filename_length);
+
+LIBMEMCACHED_LOCAL
+ const char *memcached_parse_filename(memcached_st *memc);
+
+LIBMEMCACHED_LOCAL
+ memcached_return_t memcached_parse_configuration(memcached_st *ptr, const char *option_string, size_t length);
+
+LIBMEMCACHED_LOCAL
+ size_t memcached_parse_filename_length(memcached_st *memc);
+
+LIBMEMCACHED_LOCAL
+ memcached_return_t memcached_parse_configure_file(memcached_st&, const char *filename, size_t length);
+
+LIBMEMCACHED_LOCAL
+ memcached_return_t memcached_parse_configure_file(memcached_st&, memcached_array_st& filename);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ I debated about putting this in the client library since it does an
+ action I don't really believe belongs in the library.
+
+ Frankly its too damn useful not to be here though.
+*/
+
+#include <libmemcached/common.h>
+
+memcached_server_list_st memcached_servers_parse(const char *server_strings)
+{
+ char *string;
+ const char *begin_ptr;
+ const char *end_ptr;
+ memcached_server_st *servers= NULL;
+ memcached_return_t rc;
+
+ WATCHPOINT_ASSERT(server_strings);
+
+ end_ptr= server_strings + strlen(server_strings);
+
+ for (begin_ptr= server_strings, string= (char *)index(server_strings, ',');
+ begin_ptr != end_ptr;
+ string= (char *)index(begin_ptr, ','))
+ {
+ char buffer[HUGE_STRING_LEN];
+ char *ptr, *ptr2;
+ uint32_t weight= 0;
+
+ if (string)
+ {
+ memcpy(buffer, begin_ptr, (size_t) (string - begin_ptr));
+ buffer[(unsigned int)(string - begin_ptr)]= 0;
+ begin_ptr= string+1;
+ }
+ else
+ {
+ size_t length= strlen(begin_ptr);
+ memcpy(buffer, begin_ptr, length);
+ buffer[length]= 0;
+ begin_ptr= end_ptr;
+ }
+
+ ptr= index(buffer, ':');
+
+ in_port_t port= 0;
+ if (ptr)
+ {
+ ptr[0]= 0;
+
+ ptr++;
+
+ errno= 0;
+ port= (in_port_t) strtoul(ptr, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ memcached_server_free(servers);
+ return NULL;
+ }
+
+ ptr2= index(ptr, ' ');
+ if (! ptr2)
+ ptr2= index(ptr, ':');
+
+ if (ptr2)
+ {
+ ptr2++;
+ errno= 0;
+ weight= uint32_t(strtoul(ptr2, (char **)NULL, 10));
+ if (errno != 0)
+ {
+ memcached_server_free(servers);
+ return NULL;
+ }
+ }
+ }
+
+ servers= memcached_server_list_append_with_weight(servers, buffer, port, weight, &rc);
+
+ if (isspace(*begin_ptr))
+ {
+ begin_ptr++;
+ }
+ }
+
+ return servers;
+}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2013 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 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: Implementation of poll by using select
+ *
+ */
+
+#include "libmemcached/common.h"
+
+#if defined(_WIN32)
+#include "libmemcached/poll.h"
+
+#include <sys/time.h>
+#include <strings.h>
+
+int poll(struct pollfd fds[], nfds_t nfds, int tmo)
+{
+ fd_set readfds, writefds, errorfds;
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&errorfds);
+
+ int maxfd= 0;
+
+ for (nfds_t x= 0; x < nfds; ++x)
+ {
+ if (fds[x].events & (POLLIN | POLLOUT))
+ {
+#ifndef _WIN32
+ if (fds[x].fd > maxfd)
+ {
+ maxfd= fds[x].fd;
+ }
+#endif
+ if (fds[x].events & POLLIN)
+ {
+ FD_SET(fds[x].fd, &readfds);
+ }
+ if (fds[x].events & POLLOUT)
+ {
+ FD_SET(fds[x].fd, &writefds);
+ }
+ }
+ }
+
+ struct timeval timeout= { .tv_sec = tmo / 1000,
+ .tv_usec= (tmo % 1000) * 1000 };
+ struct timeval *tp= &timeout;
+ if (tmo == -1)
+ {
+ tp= NULL;
+ }
+ int ret= select(maxfd + 1, &readfds, &writefds, &errorfds, tp);
+ if (ret <= 0)
+ {
+ return ret;
+ }
+
+ /* Iterate through all of them because I need to clear the revent map */
+ for (nfds_t x= 0; x < nfds; ++x)
+ {
+ fds[x].revents= 0;
+ if (FD_ISSET(fds[x].fd, &readfds))
+ {
+ fds[x].revents |= POLLIN;
+ }
+ if (FD_ISSET(fds[x].fd, &writefds))
+ {
+ fds[x].revents |= POLLOUT;
+ }
+ if (FD_ISSET(fds[x].fd, &errorfds))
+ {
+ fds[x].revents |= POLLERR;
+ }
+ }
+
+ return ret;
+}
+
+#endif // defined(_WIN32)
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2013 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 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: Implementation of poll by using select
+ *
+ */
+
+#pragma once
+
+#if defined(_WIN32)
+
+#include <winsock2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pollfd
+{
+#if defined(_WIN32)
+ SOCKET fd;
+#else
+ int fd;
+#endif
+ short events;
+ short revents;
+} pollfd_t;
+
+typedef int nfds_t;
+
+#define POLLIN 0x0001
+#define POLLOUT 0x0004
+#define POLLERR 0x0008
+#define POLLHUP 0x010 /* Hung up. */
+#define POLLNVAL 0x020 /* Invalid polling request. */
+
+int poll(struct pollfd fds[], nfds_t nfds, int tmo);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // defined(_WIN32)
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+
+#define memcached_set_purging(__object, __value) ((__object)->state.is_purging= (__value))
+
+class Purge
+{
+public:
+ Purge(Memcached* arg) :
+ _memc(arg)
+ {
+ memcached_set_purging(_memc, true);
+ }
+
+ ~Purge()
+ {
+ memcached_set_purging(_memc, false);
+ }
+
+private:
+ Memcached* _memc;
+};
+
+class PollTimeout
+{
+public:
+ PollTimeout(Memcached* arg) :
+ _timeout(arg->poll_timeout),
+ _origin(arg->poll_timeout)
+ {
+ _origin = 2000;
+ }
+
+ ~PollTimeout()
+ {
+ _origin= _timeout;
+ }
+
+private:
+ int32_t _timeout;
+ int32_t& _origin;
+};
+
+bool memcached_purge(memcached_instance_st* ptr)
+{
+ Memcached *root= (Memcached *)ptr->root;
+
+ if (memcached_is_purging(ptr->root) || /* already purging */
+ (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark &&
+ ptr->io_bytes_sent < ptr->root->io_bytes_watermark) ||
+ (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark &&
+ memcached_server_response_count(ptr) < 2))
+ {
+ return true;
+ }
+
+ /*
+ memcached_io_write and memcached_response may call memcached_purge
+ so we need to be able stop any recursion..
+ */
+ Purge set_purge(root);
+
+ WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+ /*
+ 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) == false)
+ {
+ memcached_io_reset(ptr);
+ memcached_set_error(*ptr, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
+ return false;
+ }
+ WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+
+ bool is_successful= true;
+ uint32_t no_msg= memcached_server_response_count(ptr);
+ if (no_msg > 1)
+ {
+ memcached_result_st result;
+
+ /*
+ * 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
+ */
+ PollTimeout poll_timeout(ptr->root);
+
+ memcached_result_st* result_ptr= memcached_result_create(root, &result);
+ assert(result_ptr);
+
+ for (uint32_t x= 0; x < no_msg - 1; x++)
+ {
+ memcached_result_reset(result_ptr);
+ memcached_return_t rc= memcached_read_one_response(ptr, 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 or rc == MEMCACHED_UNKNOWN_READ_FAILURE or rc == MEMCACHED_READ_FAILURE)
+ {
+ WATCHPOINT_ERROR(rc);
+ is_successful= false;
+ }
+
+ if (ptr->root->callbacks != NULL)
+ {
+ memcached_callback_st cb = *ptr->root->callbacks;
+ if (memcached_success(rc))
+ {
+ for (uint32_t y= 0; y < cb.number_of_callback; y++)
+ {
+ if (memcached_fatal((*cb.callback[y])(ptr->root, result_ptr, cb.context)))
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ memcached_result_free(result_ptr);
+ }
+
+ return is_successful;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+namespace {
+ memcached_return_t send_quit_message(memcached_instance_st* instance)
+ {
+ memcached_return_t rc;
+ if (instance->root->flags.binary_protocol)
+ {
+ protocol_binary_request_quit request= {}; // = {.bytes= {0}};
+
+ initialize_binary_request(instance, request.message.header);
+
+ request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT;
+ request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { request.bytes, sizeof(request.bytes) }
+ };
+
+ rc= memcached_vdo(instance, vector, 1, true);
+ }
+ else
+ {
+ libmemcached_io_vector_st vector[]=
+ {
+ { memcached_literal_param("quit\r\n") }
+ };
+
+ rc= memcached_vdo(instance, vector, 1, true);
+ }
+
+ return rc;
+ }
+
+ void drain_instance(memcached_instance_st* instance)
+ {
+ /* read until socket is closed, or there is an error
+ * closing the socket before all data is read
+ * results in server throwing away all data which is
+ * not read
+ *
+ * In .40 we began to only do this if we had been doing buffered
+ * requests of had replication enabled.
+ */
+ if (instance->root->flags.buffer_requests or instance->root->number_of_replicas)
+ {
+ memcached_io_slurp(instance);
+ }
+
+ /*
+ * 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.
+ */
+ instance->server_failure_counter= 0;
+ instance->server_timeout_counter= 0;
+ }
+}
+
+/*
+ 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_instance_st* instance, bool io_death)
+{
+ if (instance->valid())
+ {
+ if (io_death == false and memcached_is_udp(instance->root) == false and instance->is_shutting_down() == false)
+ {
+ send_quit_message(instance);
+
+ instance->start_close_socket();
+ drain_instance(instance);
+ }
+ }
+
+ instance->close_socket();
+
+ if (io_death and memcached_is_udp(instance->root))
+ {
+ /*
+ If using UDP, we should stop using the server briefly on every IO
+ failure. If using TCP, it may be that the connection went down a
+ short while ago (e.g. the server failed) and we've only just
+ noticed, so we should only set the retry timeout on a connect
+ failure (which doesn't call this method).
+ */
+ memcached_mark_server_for_timeout(instance);
+ }
+}
+
+void send_quit(Memcached *memc)
+{
+ for (uint32_t x= 0; x < memcached_server_count(memc); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc, x);
+
+ memcached_quit_server(instance, false);
+ }
+}
+
+void memcached_quit(memcached_st *shell)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(memc, true)))
+ {
+ return;
+ }
+
+ send_quit(memc);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+void memcached_quit_server(memcached_instance_st* ptr, bool io_death);
+
+void send_quit(memcached_st *ptr);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <libmemcached/string.hpp>
+
+static memcached_return_t textual_value_fetch(memcached_instance_st* instance,
+ char *buffer,
+ memcached_result_st *result)
+{
+ char *next_ptr;
+ ssize_t read_length= 0;
+ size_t value_length;
+
+ WATCHPOINT_ASSERT(instance->root);
+ char *end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
+
+ memcached_result_reset(result);
+
+ char *string_ptr= buffer;
+ string_ptr+= 6; /* "VALUE " */
+
+
+ // Just used for cases of AES decrypt currently
+ memcached_return_t rc= MEMCACHED_SUCCESS;
+
+ /* We load the key */
+ {
+ char *key= result->item_key;
+ result->key_length= 0;
+
+ for (ptrdiff_t prefix_length= memcached_array_size(instance->root->_namespace); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
+ {
+ if (prefix_length == 0)
+ {
+ *key= *string_ptr;
+ key++;
+ result->key_length++;
+ }
+ else
+ prefix_length--;
+ }
+ result->item_key[result->key_length]= 0;
+ }
+
+ if (end_ptr == string_ptr)
+ {
+ goto read_error;
+ }
+
+ /* Flags fetch move past space */
+ string_ptr++;
+ if (end_ptr == string_ptr)
+ {
+ goto read_error;
+ }
+
+ for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++) {};
+ errno= 0;
+ result->item_flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10);
+
+ if (errno != 0 or 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++) {};
+ errno= 0;
+ value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
+
+ if (errno != 0 or 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++) {};
+ errno= 0;
+ result->item_cas= strtoull(next_ptr, &string_ptr, 10);
+ }
+
+ if (errno != 0 or end_ptr < string_ptr)
+ {
+ goto read_error;
+ }
+
+ /* We add two bytes so that we can walk the \r\n */
+ if (memcached_failed(memcached_string_check(&result->value, value_length +2)))
+ {
+ return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+
+ {
+ char *value_ptr= memcached_string_value_mutable(&result->value);
+ /*
+ We read the \r\n into the string since not doing so is more
+ cycles then the waster of memory to do so.
+
+ We are null terminating through, which will most likely make
+ some people lazy about using the return length.
+ */
+ size_t to_read= (value_length) + 2;
+ memcached_return_t rrc= memcached_io_read(instance, value_ptr, to_read, read_length);
+ if (memcached_failed(rrc) and rrc == MEMCACHED_IN_PROGRESS)
+ {
+ memcached_quit_server(instance, true);
+ return memcached_set_error(*instance, MEMCACHED_IN_PROGRESS, MEMCACHED_AT);
+ }
+ else if (memcached_failed(rrc))
+ {
+ return rrc;
+ }
+ }
+
+ if (read_length != (ssize_t)(value_length + 2))
+ {
+ goto read_error;
+ }
+
+ /* This next bit blows the API, but this is internal....*/
+ {
+ char *char_ptr;
+ char_ptr= memcached_string_value_mutable(&result->value);;
+ char_ptr[value_length]= 0;
+ char_ptr[value_length +1]= 0;
+ memcached_string_set_length(&result->value, value_length);
+ }
+
+ if (memcached_is_encrypted(instance->root) and memcached_result_length(result))
+ {
+ hashkit_string_st *destination;
+
+ if ((destination= hashkit_decrypt(&instance->root->hashkit,
+ memcached_result_value(result), memcached_result_length(result))) == NULL)
+ {
+ rc= memcached_set_error(*instance->root, MEMCACHED_FAILURE,
+ MEMCACHED_AT, memcached_literal_param("hashkit_decrypt() failed"));
+ }
+ else
+ {
+ memcached_result_reset_value(result);
+ if (memcached_failed(memcached_result_set_value(result, hashkit_string_c_str(destination), hashkit_string_length(destination))))
+ {
+ rc= memcached_set_error(*instance->root, MEMCACHED_FAILURE,
+ MEMCACHED_AT, memcached_literal_param("hashkit_decrypt() failed"));
+ }
+ }
+
+ if (memcached_failed(rc))
+ {
+ memcached_result_reset(result);
+ }
+ hashkit_string_free(destination);
+ }
+
+ return rc;
+
+read_error:
+ memcached_io_reset(instance);
+
+ return MEMCACHED_PARTIAL_READ;
+}
+
+static memcached_return_t textual_read_one_response(memcached_instance_st* instance,
+ char *buffer, const size_t buffer_length,
+ memcached_result_st *result)
+{
+ size_t total_read;
+ memcached_return_t rc= memcached_io_readline(instance, buffer, buffer_length, total_read);
+
+ if (memcached_failed(rc))
+ {
+ return rc;
+ }
+ assert(total_read);
+
+ switch(buffer[0])
+ {
+ case 'V':
+ {
+ // VALUE
+ if (buffer[1] == 'A' and buffer[2] == 'L' and buffer[3] == 'U' and buffer[4] == 'E') /* VALUE */
+ {
+ /* We add back in one because we will need to search for END */
+ memcached_server_response_increment(instance);
+ return textual_value_fetch(instance, buffer, result);
+ }
+ // VERSION
+ else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'S' and buffer[4] == 'I' and buffer[5] == 'O' and buffer[6] == 'N') /* VERSION */
+ {
+ /* Find the space, and then move one past it to copy version */
+ char *response_ptr= index(buffer, ' ');
+
+ char *endptr;
+ errno= 0;
+ long int version= strtol(response_ptr, &endptr, 10);
+ if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX or version == 0)
+ {
+ instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version"));
+ }
+ instance->major_version= uint8_t(version);
+
+ endptr++;
+ errno= 0;
+ version= strtol(endptr, &endptr, 10);
+ if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX)
+ {
+ instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse minor version"));
+ }
+ instance->minor_version= uint8_t(version);
+
+ endptr++;
+ errno= 0;
+ version= strtol(endptr, &endptr, 10);
+ if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX)
+ {
+ instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
+ }
+ instance->micro_version= uint8_t(version);
+
+ return MEMCACHED_SUCCESS;
+ }
+ }
+ break;
+
+ case 'O':
+ {
+ // OK
+ if (buffer[1] == 'K')
+ {
+ return MEMCACHED_SUCCESS;
+ }
+ }
+ break;
+
+ case 'S':
+ {
+ // STAT
+ if (buffer[1] == 'T' and buffer[2] == 'A' and buffer[3] == 'T') /* STORED STATS */
+ {
+ memcached_server_response_increment(instance);
+ return MEMCACHED_STAT;
+ }
+ // SERVER_ERROR
+ else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'V' and buffer[4] == 'E' and buffer[5] == 'R'
+ and buffer[6] == '_'
+ and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R' )
+ {
+ if (total_read == memcached_literal_param_size("SERVER_ERROR"))
+ {
+ return MEMCACHED_SERVER_ERROR;
+ }
+
+ if (total_read >= memcached_literal_param_size("SERVER_ERROR object too large for cache") and
+ (memcmp(buffer, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
+ {
+ return MEMCACHED_E2BIG;
+ }
+
+ if (total_read >= memcached_literal_param_size("SERVER_ERROR out of memory") and
+ ((memcmp(buffer, memcached_literal_param("SERVER_ERROR out of memory")) == 0) or
+ (memcmp(buffer, memcached_literal_param("SERVER_ERROR Out of memory")) == 0)))
+ {
+ return MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ // Move past the basic error message and whitespace
+ char *startptr= buffer + memcached_literal_param_size("SERVER_ERROR");
+ if (startptr[0] == ' ')
+ {
+ startptr++;
+ }
+
+ char *endptr= startptr;
+ while (*endptr != '\r' && *endptr != '\n') endptr++;
+
+ return memcached_set_error(*instance, MEMCACHED_SERVER_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
+ }
+ // STORED
+ else if (buffer[1] == 'T' and buffer[2] == 'O' and buffer[3] == 'R') // and buffer[4] == 'E' and buffer[5] == 'D')
+ {
+ return MEMCACHED_STORED;
+ }
+ }
+ break;
+
+ case 'D':
+ {
+ // DELETED
+ if (buffer[1] == 'E' and buffer[2] == 'L' and buffer[3] == 'E' and buffer[4] == 'T' and buffer[5] == 'E' and buffer[6] == 'D')
+ {
+ return MEMCACHED_DELETED;
+ }
+ }
+ break;
+
+ case 'N':
+ {
+ // NOT_FOUND
+ if (buffer[1] == 'O' and buffer[2] == 'T'
+ and buffer[3] == '_'
+ and buffer[4] == 'F' and buffer[5] == 'O' and buffer[6] == 'U' and buffer[7] == 'N' and buffer[8] == 'D')
+ {
+ return MEMCACHED_NOTFOUND;
+ }
+ // NOT_STORED
+ else if (buffer[1] == 'O' and buffer[2] == 'T'
+ and buffer[3] == '_'
+ and buffer[4] == 'S' and buffer[5] == 'T' and buffer[6] == 'O' and buffer[7] == 'R' and buffer[8] == 'E' and buffer[9] == 'D')
+ {
+ return MEMCACHED_NOTSTORED;
+ }
+ }
+ break;
+
+ case 'E': /* PROTOCOL ERROR or END */
+ {
+ // END
+ if (buffer[1] == 'N' and buffer[2] == 'D')
+ {
+ return MEMCACHED_END;
+ }
+#if 0
+ // PROTOCOL_ERROR
+ else if (buffer[1] == 'R' and buffer[2] == 'O' and buffer[3] == 'T' and buffer[4] == 'O' and buffer[5] == 'C' and buffer[6] == 'O' and buffer[7] == 'L'
+ and buffer[8] == '_'
+ and buffer[9] == 'E' and buffer[10] == 'R' and buffer[11] == 'R' and buffer[12] == 'O' and buffer[13] == 'R')
+ {
+ return MEMCACHED_PROTOCOL_ERROR;
+ }
+#endif
+ // ERROR
+ else if (buffer[1] == 'R' and buffer[2] == 'R' and buffer[3] == 'O' and buffer[4] == 'R')
+ {
+ return MEMCACHED_ERROR;
+ }
+ // EXISTS
+ else if (buffer[1] == 'X' and buffer[2] == 'I' and buffer[3] == 'S' and buffer[4] == 'T' and buffer[5] == 'S')
+ {
+ return MEMCACHED_DATA_EXISTS;
+ }
+ }
+ break;
+
+ case 'T': /* TOUCHED */
+ {
+ // TOUCHED
+ if (buffer[1] == 'O' and buffer[2] == 'U' and buffer[3] == 'C' and buffer[4] == 'H' and buffer[5] == 'E' and buffer[6] == 'D')
+ {
+ return MEMCACHED_SUCCESS;
+ }
+ }
+ break;
+
+ case 'I': /* ITEM */
+ {
+ // ITEM
+ if (buffer[1] == 'T' and buffer[2] == 'E' and buffer[3] == 'M')
+ {
+ /* We add back in one because we will need to search for END */
+ memcached_server_response_increment(instance);
+ return MEMCACHED_ITEM;
+ }
+ }
+ break;
+
+ case 'C': /* CLIENT ERROR */
+ {
+ // CLIENT_ERROR
+ if (buffer[1] == 'L' and buffer[2] == 'I' and buffer[3] == 'E' and buffer[4] == 'N' and buffer[5] == 'T'
+ and buffer[6] == '_'
+ and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R')
+ {
+ // Move past the basic error message and whitespace
+ char *startptr= buffer + memcached_literal_param_size("CLIENT_ERROR");
+ if (startptr[0] == ' ')
+ {
+ startptr++;
+ }
+
+ char *endptr= startptr;
+ while (*endptr != '\r' && *endptr != '\n') endptr++;
+
+ return memcached_set_error(*instance, MEMCACHED_CLIENT_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
+ }
+ }
+ break;
+
+ case '0': /* INCR/DECR response */
+ case '1': /* INCR/DECR response */
+ case '2': /* INCR/DECR response */
+ case '3': /* INCR/DECR response */
+ case '4': /* INCR/DECR response */
+ case '5': /* INCR/DECR response */
+ case '6': /* INCR/DECR response */
+ case '7': /* INCR/DECR response */
+ case '8': /* INCR/DECR response */
+ case '9': /* INCR/DECR response */
+ {
+ errno= 0;
+ unsigned long long int auto_return_value= strtoull(buffer, (char **)NULL, 10);
+
+ if (auto_return_value == ULLONG_MAX and errno == ERANGE)
+ {
+ result->numeric_value= UINT64_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("Numeric response was out of range"));
+ }
+ else if (errno == EINVAL)
+ {
+ result->numeric_value= UINT64_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("Numeric response was out of range"));
+ }
+ else if (errno != 0)
+ {
+ result->numeric_value= UINT64_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("Numeric response was out of range"));
+ }
+
+ result->numeric_value= uint64_t(auto_return_value);
+
+ WATCHPOINT_STRING(buffer);
+ return MEMCACHED_SUCCESS;
+ }
+
+ default:
+ break;
+ }
+
+ buffer[total_read]= 0;
+#if 0
+ if (total_read >= sizeof("STORSTORED") -1)
+ {
+ fprintf(stderr, "%s:%d '%s', %.*s\n", __FILE__, __LINE__,
+ buffer, MEMCACHED_MAX_BUFFER, instance->read_buffer);
+ assert(memcmp(buffer,"STORSTORED", sizeof("STORSTORED") -1));
+ }
+#endif
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT,
+ buffer, total_read);
+}
+
+static memcached_return_t binary_read_one_response(memcached_instance_st* instance,
+ char *buffer, const size_t buffer_length,
+ memcached_result_st *result)
+{
+ memcached_return_t rc;
+ protocol_binary_response_header header;
+
+ assert(memcached_is_binary(instance->root));
+
+ if ((rc= memcached_safe_read(instance, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ERROR(rc);
+ return rc;
+ }
+
+ if (header.response.magic != PROTOCOL_BINARY_RES)
+ {
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
+ }
+
+ /*
+ ** 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= memcached_ntohll(header.response.cas);
+ uint32_t bodylen= header.response.bodylen;
+
+ if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS or
+ header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE)
+ {
+ switch (header.response.opcode)
+ {
+ case PROTOCOL_BINARY_CMD_GETKQ:
+ /*
+ * We didn't increment the response counter for the GETKQ packet
+ * (only the final NOOP), so we need to increment the counter again.
+ */
+ memcached_server_response_increment(instance);
+ /* fall through */
+ case PROTOCOL_BINARY_CMD_GETK:
+ {
+ uint16_t keylen= header.response.keylen;
+ memcached_result_reset(result);
+ result->item_cas= header.response.cas;
+
+ if ((rc= memcached_safe_read(instance, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ERROR(rc);
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+
+ result->item_flags= ntohl(result->item_flags);
+ bodylen -= header.response.extlen;
+
+ result->key_length= keylen;
+ if (memcached_failed(rc= memcached_safe_read(instance, result->item_key, keylen)))
+ {
+ WATCHPOINT_ERROR(rc);
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+
+ // Only bother with doing this if key_length > 0
+ if (result->key_length)
+ {
+ if (memcached_array_size(instance->root->_namespace) and memcached_array_size(instance->root->_namespace) >= result->key_length)
+ {
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
+ }
+
+ if (memcached_array_size(instance->root->_namespace))
+ {
+ result->key_length-= memcached_array_size(instance->root->_namespace);
+ memmove(result->item_key, result->item_key +memcached_array_size(instance->root->_namespace), result->key_length);
+ }
+ }
+
+ bodylen -= keylen;
+ if (memcached_failed(memcached_string_check(&result->value, bodylen)))
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ char *vptr= memcached_string_value_mutable(&result->value);
+ if (memcached_failed(rc= memcached_safe_read(instance, vptr, bodylen)))
+ {
+ WATCHPOINT_ERROR(rc);
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+
+ memcached_string_set_length(&result->value, bodylen);
+ }
+ break;
+
+ case PROTOCOL_BINARY_CMD_INCREMENT:
+ case PROTOCOL_BINARY_CMD_DECREMENT:
+ {
+ if (bodylen != sizeof(uint64_t))
+ {
+ result->numeric_value= UINT64_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
+ }
+
+ uint64_t val;
+ if ((rc= memcached_safe_read(instance, &val, sizeof(val))) != MEMCACHED_SUCCESS)
+ {
+ result->numeric_value= UINT64_MAX;
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+
+ result->numeric_value= memcached_ntohll(val);
+ }
+ break;
+
+ case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
+ {
+ if (header.response.keylen != 0 || bodylen + 1 > buffer_length)
+ {
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ else
+ {
+ if ((rc= memcached_safe_read(instance, buffer, bodylen)) != MEMCACHED_SUCCESS)
+ {
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ }
+ }
+ break;
+
+ case PROTOCOL_BINARY_CMD_VERSION:
+ {
+ char version_buffer[32]; // @todo document this number
+ memset(version_buffer, 0, sizeof(version_buffer));
+
+ if (memcached_safe_read(instance, version_buffer, bodylen) != MEMCACHED_SUCCESS)
+ {
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+
+ char *endptr;
+ errno= 0;
+ long int version= strtol(version_buffer, &endptr, 10);
+ if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX or version == 0)
+ {
+ instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version"));
+ }
+ instance->major_version= uint8_t(version);
+
+ endptr++;
+ errno= 0;
+ version= strtol(endptr, &endptr, 10);
+ if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX)
+ {
+ instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse minor version"));
+ }
+ instance->minor_version= uint8_t(version);
+
+ endptr++;
+ errno= 0;
+ version= strtol(endptr, &endptr, 10);
+ if (errno != 0 or version == LONG_MIN or version == LONG_MAX or version > UINT8_MAX)
+ {
+ instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version"));
+ }
+ instance->micro_version= uint8_t(version);
+ }
+ break;
+
+ case PROTOCOL_BINARY_CMD_TOUCH:
+ {
+ rc= MEMCACHED_SUCCESS;
+ if (bodylen == 4) // The four byte read is a bug?
+ {
+ char touch_buffer[4]; // @todo document this number
+ rc= memcached_safe_read(instance, touch_buffer, sizeof(touch_buffer));
+#if 0
+ fprintf(stderr, "%s:%d %d %d %d %d %.*s(%d)\n", __FILE__, __LINE__,
+ int(touch_buffer[0]),
+ int(touch_buffer[1]),
+ int(touch_buffer[2]),
+ int(touch_buffer[3]),
+ int(bodylen), touch_buffer, int(bodylen));
+#endif
+ }
+ return memcached_set_error(*instance, rc, MEMCACHED_AT);
+ }
+
+ case PROTOCOL_BINARY_CMD_FLUSH:
+ case PROTOCOL_BINARY_CMD_QUIT:
+ case PROTOCOL_BINARY_CMD_SET:
+ case PROTOCOL_BINARY_CMD_ADD:
+ case PROTOCOL_BINARY_CMD_REPLACE:
+ case PROTOCOL_BINARY_CMD_APPEND:
+ case PROTOCOL_BINARY_CMD_PREPEND:
+ case PROTOCOL_BINARY_CMD_DELETE:
+ {
+ WATCHPOINT_ASSERT(bodylen == 0);
+ return MEMCACHED_SUCCESS;
+ }
+
+ case PROTOCOL_BINARY_CMD_NOOP:
+ {
+ WATCHPOINT_ASSERT(bodylen == 0);
+ return MEMCACHED_END;
+ }
+
+ case PROTOCOL_BINARY_CMD_STAT:
+ {
+ if (bodylen == 0)
+ {
+ return MEMCACHED_END;
+ }
+ else if (bodylen + 1 > buffer_length)
+ {
+ /* not enough space in buffer.. should not happen... */
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ else
+ {
+ size_t keylen= header.response.keylen;
+ memset(buffer, 0, buffer_length);
+ if ((rc= memcached_safe_read(instance, buffer, keylen)) != MEMCACHED_SUCCESS ||
+ (rc= memcached_safe_read(instance, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ERROR(rc);
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ }
+ }
+ break;
+
+ case PROTOCOL_BINARY_CMD_SASL_AUTH:
+ case PROTOCOL_BINARY_CMD_SASL_STEP:
+ {
+ memcached_result_reset(result);
+ result->item_cas= header.response.cas;
+
+ if (memcached_string_check(&result->value,
+ bodylen) != MEMCACHED_SUCCESS)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ char *vptr= memcached_string_value_mutable(&result->value);
+ if ((rc= memcached_safe_read(instance, vptr, bodylen)) != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ERROR(rc);
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+
+ memcached_string_set_length(&result->value, bodylen);
+ }
+ break;
+ default:
+ {
+ /* Command not implemented yet! */
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
+ }
+ }
+ }
+ else if (header.response.bodylen)
+ {
+ /* What should I do with the error message??? just discard it for now */
+ char hole[SMALL_STRING_LEN];
+ while (bodylen > 0)
+ {
+ size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
+ if ((rc= memcached_safe_read(instance, hole, nr)) != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ERROR(rc);
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
+ }
+ 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 MEMCACHED_FETCH_NOTFINISHED;
+
+ default:
+ break;
+ }
+ }
+
+ rc= MEMCACHED_SUCCESS;
+ if (header.response.status != 0)
+ {
+ switch (header.response.status)
+ {
+ case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
+ rc= MEMCACHED_NOTFOUND;
+ break;
+
+ case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
+ rc= MEMCACHED_DATA_EXISTS;
+ break;
+
+ case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
+ rc= MEMCACHED_NOTSTORED;
+ break;
+
+ case PROTOCOL_BINARY_RESPONSE_E2BIG:
+ rc= MEMCACHED_E2BIG;
+ break;
+
+ case PROTOCOL_BINARY_RESPONSE_ENOMEM:
+ rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ break;
+
+ case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE:
+ rc= MEMCACHED_AUTH_CONTINUE;
+ break;
+
+ case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
+ rc= MEMCACHED_AUTH_FAILURE;
+ break;
+
+ case PROTOCOL_BINARY_RESPONSE_EINVAL:
+ case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
+ default:
+ return memcached_set_error(*instance, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static memcached_return_t _read_one_response(memcached_instance_st* instance,
+ char *buffer, const size_t buffer_length,
+ memcached_result_st *result)
+{
+ memcached_server_response_decrement(instance);
+
+ if (result == NULL)
+ {
+ Memcached *root= (Memcached *)instance->root;
+ result = &root->result;
+ }
+
+ memcached_return_t rc;
+ if (memcached_is_binary(instance->root))
+ {
+ do {
+ rc= binary_read_one_response(instance, buffer, buffer_length, result);
+ } while (rc == MEMCACHED_FETCH_NOTFINISHED);
+ }
+ else
+ {
+ rc= textual_read_one_response(instance, buffer, buffer_length, result);
+ }
+
+ if (memcached_fatal(rc))
+ {
+ memcached_io_reset(instance);
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_read_one_response(memcached_instance_st* instance,
+ memcached_result_st *result)
+{
+ char buffer[SMALL_STRING_LEN];
+
+ if (memcached_is_udp(instance->root))
+ {
+ return memcached_set_error(*instance, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
+ }
+
+
+ return _read_one_response(instance, buffer, sizeof(buffer), result);
+}
+
+memcached_return_t memcached_response(memcached_instance_st* instance,
+ memcached_result_st *result)
+{
+ char buffer[1024];
+
+ return memcached_response(instance, buffer, sizeof(buffer), result);
+}
+
+memcached_return_t memcached_response(memcached_instance_st* instance,
+ char *buffer, size_t buffer_length,
+ memcached_result_st *result)
+{
+ if (memcached_is_udp(instance->root))
+ {
+ return memcached_set_error(*instance, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
+ }
+
+ /* We may have old commands in the buffer not sent, first purge */
+ if ((instance->root->flags.no_block) and (memcached_is_processing_input(instance->root) == false))
+ {
+ (void)memcached_io_write(instance);
+ }
+
+ /* Before going into loop wait to see if we have any IO waiting for us */
+ if (0)
+ {
+ memcached_return_t read_rc= memcached_io_wait_for_read(instance);
+ fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, memcached_strerror(NULL, read_rc));
+ }
+
+ /*
+ * The previous implementation purged all pending requests and just
+ * returned the last one. Purge all pending messages to ensure backwards
+ * compatibility.
+ */
+ if (memcached_is_binary(instance->root) == false and memcached_server_response_count(instance) > 1)
+ {
+ memcached_result_st junked_result;
+ memcached_result_st *junked_result_ptr= memcached_result_create(instance->root, &junked_result);
+
+ assert(junked_result_ptr);
+
+ while (memcached_server_response_count(instance) > 1)
+ {
+ memcached_return_t rc= _read_one_response(instance, buffer, buffer_length, junked_result_ptr);
+
+ // @TODO should we return an error on another but a bad read case?
+ if (memcached_fatal(rc))
+ {
+ memcached_result_free(junked_result_ptr);
+ return rc;
+ }
+ }
+ memcached_result_free(junked_result_ptr);
+ }
+
+ return _read_one_response(instance, buffer, buffer_length, result);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+/* Read a single response from the server */
+memcached_return_t memcached_read_one_response(memcached_instance_st* ptr,
+ memcached_result_st *result);
+
+memcached_return_t memcached_response(memcached_instance_st* ptr,
+ memcached_result_st *result);
+
+memcached_return_t memcached_response(memcached_instance_st* ptr,
+ char *buffer, size_t buffer_length,
+ memcached_result_st *result);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/*
+ memcached_result_st are used to internally represent the return values from
+ memcached. We use a structure so that long term as identifiers are added
+ to memcached we will be able to absorb new attributes without having
+ to addjust the entire API.
+*/
+#include <libmemcached/common.h>
+
+static inline void _result_init(memcached_result_st *self,
+ Memcached *memc)
+{
+ self->item_flags= 0;
+ self->item_expiration= 0;
+ self->key_length= 0;
+ self->item_cas= 0;
+ self->root= memc;
+ self->numeric_value= UINT64_MAX;
+ self->count= 0;
+ self->item_key[0]= 0;
+}
+
+memcached_result_st *memcached_result_create(const memcached_st *shell,
+ memcached_result_st *ptr)
+{
+ const Memcached* memc= memcached2Memcached(shell);
+
+ /* Saving malloc calls :) */
+ if (ptr)
+ {
+ ptr->options.is_allocated= false;
+ }
+ else
+ {
+ ptr= libmemcached_xmalloc(memc, memcached_result_st);
+
+ if (not ptr)
+ {
+ return NULL;
+ }
+
+ ptr->options.is_allocated= true;
+ }
+
+ ptr->options.is_initialized= true;
+
+ _result_init(ptr, (memcached_st *)memc);
+
+ WATCHPOINT_SET(ptr->value.options.is_initialized= false);
+ memcached_string_create((memcached_st*)memc, &ptr->value, 0);
+ WATCHPOINT_ASSERT_INITIALIZED(&ptr->value);
+ WATCHPOINT_ASSERT(ptr->value.string == NULL);
+
+ return ptr;
+}
+
+void memcached_result_reset(memcached_result_st *ptr)
+{
+ ptr->key_length= 0;
+ memcached_string_reset(&ptr->value);
+ ptr->item_flags= 0;
+ ptr->item_cas= 0;
+ ptr->item_expiration= 0;
+ ptr->numeric_value= UINT64_MAX;
+}
+
+void memcached_result_free(memcached_result_st *ptr)
+{
+ if (ptr == NULL)
+ {
+ return;
+ }
+
+ memcached_string_free(&ptr->value);
+ ptr->numeric_value= UINT64_MAX;
+
+ if (memcached_is_allocated(ptr))
+ {
+ WATCHPOINT_ASSERT(ptr->root); // Without a root, that means that result was not properly initialized.
+ libmemcached_free(ptr->root, ptr);
+ }
+ else
+ {
+ ptr->count= 0;
+ ptr->options.is_initialized= false;
+ }
+}
+
+void memcached_result_reset_value(memcached_result_st *ptr)
+{
+ memcached_string_reset(&ptr->value);
+}
+
+memcached_return_t memcached_result_set_value(memcached_result_st *ptr,
+ const char *value,
+ size_t length)
+{
+ if (memcached_failed(memcached_string_append(&ptr->value, value, length)))
+ {
+ return memcached_set_errno(*ptr->root, errno, MEMCACHED_AT);
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+const char *memcached_result_key_value(const memcached_result_st *self)
+{
+ return self->key_length ? self->item_key : NULL;
+}
+
+size_t memcached_result_key_length(const memcached_result_st *self)
+{
+ return self->key_length;
+}
+
+const char *memcached_result_value(const memcached_result_st *self)
+{
+ const memcached_string_st *sptr= &self->value;
+ return memcached_string_value(sptr);
+}
+
+size_t memcached_result_length(const memcached_result_st *self)
+{
+ const memcached_string_st *sptr= &self->value;
+ return memcached_string_length(sptr);
+}
+
+char *memcached_result_take_value(memcached_result_st *self)
+{
+ memcached_string_st *sptr= &self->value;
+ return memcached_string_take_value(sptr);
+}
+
+uint32_t memcached_result_flags(const memcached_result_st *self)
+{
+ return self->item_flags;
+}
+
+uint64_t memcached_result_cas(const memcached_result_st *self)
+{
+ return self->item_cas;
+}
+
+void memcached_result_set_flags(memcached_result_st *self, uint32_t flags)
+{
+ self->item_flags= flags;
+}
+
+void memcached_result_set_expiration(memcached_result_st *self, time_t expiration)
+{
+ self->item_expiration= expiration;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+void memcached_result_reset_value(memcached_result_st *ptr);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libmemcached/common.h"
+#include <cassert>
+#include <atomic>
+
+#if defined(LIBMEMCACHED_WITH_SASL_SUPPORT) && LIBMEMCACHED_WITH_SASL_SUPPORT
+
+#if defined(HAVE_LIBSASL) && HAVE_LIBSASL
+#include <sasl/sasl.h>
+#endif
+
+#define CAST_SASL_CB(cb) reinterpret_cast<int(*)()>(reinterpret_cast<intptr_t>(cb))
+
+#include <pthread.h>
+
+void memcached_set_sasl_callbacks(memcached_st *shell,
+ const sasl_callback_t *callbacks)
+{
+ Memcached* self= memcached2Memcached(shell);
+ if (self)
+ {
+ self->sasl.callbacks= const_cast<sasl_callback_t *>(callbacks);
+ self->sasl.is_allocated= false;
+ }
+}
+
+sasl_callback_t *memcached_get_sasl_callbacks(memcached_st *shell)
+{
+ Memcached* self= memcached2Memcached(shell);
+ if (self)
+ {
+ return self->sasl.callbacks;
+ }
+
+ return NULL;
+}
+
+/**
+ * Resolve the names for both ends of a connection
+ * @param fd socket to check
+ * @param laddr local address (out)
+ * @param raddr remote address (out)
+ * @return true on success false otherwise (errno contains more info)
+ */
+static memcached_return_t resolve_names(memcached_instance_st& server, char *laddr, size_t laddr_length, char *raddr, size_t raddr_length)
+{
+ char host[MEMCACHED_NI_MAXHOST];
+ char port[MEMCACHED_NI_MAXSERV];
+ struct sockaddr_storage saddr;
+ socklen_t salen= sizeof(saddr);
+
+ if (getsockname(server.fd, (struct sockaddr *)&saddr, &salen) < 0)
+ {
+ return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
+ }
+
+ if (getnameinfo((struct sockaddr *)&saddr, salen, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) < 0)
+ {
+ return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
+ }
+
+ (void)snprintf(laddr, laddr_length, "%s;%s", host, port);
+ salen= sizeof(saddr);
+
+ if (getpeername(server.fd, (struct sockaddr *)&saddr, &salen) < 0)
+ {
+ return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
+ }
+
+ if (getnameinfo((struct sockaddr *)&saddr, salen, host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) < 0)
+ {
+ return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
+ }
+
+ (void)snprintf(raddr, raddr_length, "%s;%s", host, port);
+
+ return MEMCACHED_SUCCESS;
+}
+
+extern "C" {
+
+static void sasl_shutdown_function()
+{
+ sasl_done();
+}
+
+static std::atomic<int> sasl_startup_state(SASL_OK);
+pthread_mutex_t sasl_startup_state_LOCK= PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t sasl_startup_once= PTHREAD_ONCE_INIT;
+static void sasl_startup_function(void)
+{
+ sasl_startup_state= sasl_client_init(NULL);
+
+ if (sasl_startup_state == SASL_OK)
+ {
+ (void)atexit(sasl_shutdown_function);
+ }
+}
+
+} // extern "C"
+
+memcached_return_t memcached_sasl_authenticate_connection(memcached_instance_st* server)
+{
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ return MEMCACHED_NOT_SUPPORTED;
+ }
+
+ if (server == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ /* SANITY CHECK: SASL can only be used with the binary protocol */
+ if (memcached_is_binary(server->root) == false)
+ {
+ return memcached_set_error(*server, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("memcached_sasl_authenticate_connection() is not supported via the ASCII protocol"));
+ }
+
+ /* Try to get the supported mech from the server. Servers without SASL
+ * support will return UNKNOWN COMMAND, so we can just treat that
+ * as authenticated
+ */
+ protocol_binary_request_no_extras request= { };
+
+ initialize_binary_request(server, request.message.header);
+
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SASL_LIST_MECHS;
+
+ if (memcached_io_write(server, request.bytes, sizeof(request.bytes), true) != sizeof(request.bytes))
+ {
+ return MEMCACHED_WRITE_FAILURE;
+ }
+ assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
+
+ memcached_server_response_increment(server);
+
+ char mech[MEMCACHED_MAX_BUFFER];
+ memcached_return_t rc= memcached_response(server, mech, sizeof(mech), NULL);
+ if (memcached_failed(rc))
+ {
+ if (rc == MEMCACHED_PROTOCOL_ERROR)
+ {
+ /* If the server doesn't support SASL it will return PROTOCOL_ERROR.
+ * This error may also be returned for other errors, but let's assume
+ * that the server don't support SASL and treat it as success and
+ * let the client fail with the next operation if the error was
+ * caused by another problem....
+ */
+ rc= MEMCACHED_SUCCESS;
+ }
+
+ return rc;
+ }
+ assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
+
+ /* set ip addresses */
+ char laddr[MEMCACHED_NI_MAXHOST + MEMCACHED_NI_MAXSERV];
+ char raddr[MEMCACHED_NI_MAXHOST + MEMCACHED_NI_MAXSERV];
+
+ if (memcached_failed(rc= resolve_names(*server, laddr, sizeof(laddr), raddr, sizeof(raddr))))
+ {
+ return rc;
+ }
+
+ int pthread_error;
+ if ((pthread_error= pthread_once(&sasl_startup_once, sasl_startup_function)) != 0)
+ {
+ return memcached_set_errno(*server, pthread_error, MEMCACHED_AT);
+ }
+
+ (void)pthread_mutex_lock(&sasl_startup_state_LOCK);
+ if (sasl_startup_state != SASL_OK)
+ {
+ const char *sasl_error_msg= sasl_errstring(sasl_startup_state, NULL, NULL);
+ return memcached_set_error(*server, MEMCACHED_AUTH_PROBLEM, MEMCACHED_AT,
+ memcached_string_make_from_cstr(sasl_error_msg));
+ }
+ (void)pthread_mutex_unlock(&sasl_startup_state_LOCK);
+
+ sasl_conn_t *conn;
+ int ret;
+ if ((ret= sasl_client_new("memcached", server->_hostname, laddr, raddr, server->root->sasl.callbacks, 0, &conn) ) != SASL_OK)
+ {
+ const char *sasl_error_msg= sasl_errstring(ret, NULL, NULL);
+
+ sasl_dispose(&conn);
+
+ return memcached_set_error(*server, MEMCACHED_AUTH_PROBLEM, MEMCACHED_AT,
+ memcached_string_make_from_cstr(sasl_error_msg));
+ }
+
+ const char *data;
+ const char *chosenmech;
+ unsigned int len;
+ ret= sasl_client_start(conn, mech, NULL, &data, &len, &chosenmech);
+ if (ret != SASL_OK and ret != SASL_CONTINUE)
+ {
+ const char *sasl_error_msg= sasl_errstring(ret, NULL, NULL);
+
+ sasl_dispose(&conn);
+
+ return memcached_set_error(*server, MEMCACHED_AUTH_PROBLEM, MEMCACHED_AT,
+ memcached_string_make_from_cstr(sasl_error_msg));
+ }
+ uint16_t keylen= (uint16_t)strlen(chosenmech);
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SASL_AUTH;
+ request.message.header.request.keylen= htons(keylen);
+ request.message.header.request.bodylen= htonl(len + keylen);
+
+ do {
+ /* send the packet */
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { request.bytes, sizeof(request.bytes) },
+ { chosenmech, keylen },
+ { data, len }
+ };
+
+ assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
+ if (memcached_io_writev(server, vector, 3, true) == false)
+ {
+ rc= MEMCACHED_WRITE_FAILURE;
+ break;
+ }
+ assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
+ memcached_server_response_increment(server);
+
+ /* read the response */
+ assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
+ rc= memcached_response(server, NULL, 0, NULL);
+ if (rc != MEMCACHED_AUTH_CONTINUE)
+ {
+ break;
+ }
+ assert_msg(server->fd != INVALID_SOCKET, "Programmer error, invalid socket");
+
+ ret= sasl_client_step(conn, memcached_result_value(&server->root->result),
+ (unsigned int)memcached_result_length(&server->root->result),
+ NULL, &data, &len);
+
+ if (ret != SASL_OK && ret != SASL_CONTINUE)
+ {
+ rc= MEMCACHED_AUTH_PROBLEM;
+ break;
+ }
+
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SASL_STEP;
+ request.message.header.request.bodylen= htonl(len + keylen);
+ } while (true);
+
+ /* Release resources */
+ sasl_dispose(&conn);
+
+ return memcached_set_error(*server, rc, MEMCACHED_AT);
+}
+
+static int get_username(void *context, int id, const char **result, unsigned int *len)
+{
+ if (!context || !result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME))
+ {
+ return SASL_BADPARAM;
+ }
+
+ *result= (char *)context;
+ if (len)
+ {
+ *len= (unsigned int)strlen(*result);
+ }
+
+ return SASL_OK;
+}
+
+static int get_password(sasl_conn_t *conn, void *context, int id,
+ sasl_secret_t **psecret)
+{
+ if (!conn || ! psecret || id != SASL_CB_PASS)
+ {
+ return SASL_BADPARAM;
+ }
+
+ *psecret= (sasl_secret_t *)context;
+
+ return SASL_OK;
+}
+
+memcached_return_t memcached_set_sasl_auth_data(memcached_st *shell,
+ const char *username,
+ const char *password)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ return MEMCACHED_NOT_SUPPORTED;
+ }
+
+ if (ptr == NULL or username == NULL or password == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1)))
+ {
+ return memcached_set_error(*ptr, ret, MEMCACHED_AT, memcached_literal_param("Unable change to binary protocol which is required for SASL."));
+ }
+
+ memcached_destroy_sasl_auth_data(ptr);
+
+ sasl_callback_t *callbacks= libmemcached_xcalloc(ptr, 4, sasl_callback_t);
+ size_t password_length= strlen(password);
+ size_t username_length= strlen(username);
+ char *name= (char *)libmemcached_malloc(ptr, username_length +1);
+ sasl_secret_t *secret= (sasl_secret_t*)libmemcached_malloc(ptr, password_length +1 + sizeof(sasl_secret_t));
+
+ if (callbacks == NULL or name == NULL or secret == NULL)
+ {
+ libmemcached_free(ptr, callbacks);
+ libmemcached_free(ptr, name);
+ libmemcached_free(ptr, secret);
+ return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+
+ secret->len= password_length;
+ memcpy(secret->data, password, password_length);
+ secret->data[password_length]= 0;
+
+ callbacks[0].id= SASL_CB_USER;
+ callbacks[0].proc= CAST_SASL_CB(get_username);
+ callbacks[0].context= strncpy(name, username, username_length +1);
+ callbacks[1].id= SASL_CB_AUTHNAME;
+ callbacks[1].proc= CAST_SASL_CB(get_username);
+ callbacks[1].context= name;
+ callbacks[2].id= SASL_CB_PASS;
+ callbacks[2].proc= CAST_SASL_CB(get_password);
+ callbacks[2].context= secret;
+ callbacks[3].id= SASL_CB_LIST_END;
+
+ ptr->sasl.callbacks= callbacks;
+ ptr->sasl.is_allocated= true;
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_destroy_sasl_auth_data(memcached_st *shell)
+{
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ return MEMCACHED_NOT_SUPPORTED;
+ }
+
+ Memcached* ptr= memcached2Memcached(shell);
+ if (ptr == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (ptr->sasl.callbacks == NULL)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ if (ptr->sasl.is_allocated)
+ {
+ libmemcached_free(ptr, ptr->sasl.callbacks[0].context);
+ libmemcached_free(ptr, ptr->sasl.callbacks[2].context);
+ libmemcached_free(ptr, (void*)ptr->sasl.callbacks);
+ ptr->sasl.is_allocated= false;
+ }
+
+ ptr->sasl.callbacks= NULL;
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_clone_sasl(memcached_st *clone, const memcached_st *source)
+{
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ return MEMCACHED_NOT_SUPPORTED;
+ }
+
+ if (clone == NULL or source == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (source->sasl.callbacks == NULL)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ /* Hopefully we are using our own callback mechanisms.. */
+ if (source->sasl.callbacks[0].id == SASL_CB_USER &&
+ source->sasl.callbacks[0].proc == CAST_SASL_CB(get_username) &&
+ source->sasl.callbacks[1].id == SASL_CB_AUTHNAME &&
+ source->sasl.callbacks[1].proc == CAST_SASL_CB(get_username) &&
+ source->sasl.callbacks[2].id == SASL_CB_PASS &&
+ source->sasl.callbacks[2].proc == CAST_SASL_CB(get_password) &&
+ source->sasl.callbacks[3].id == SASL_CB_LIST_END)
+ {
+ sasl_secret_t *secret= (sasl_secret_t *)source->sasl.callbacks[2].context;
+ return memcached_set_sasl_auth_data(clone,
+ (const char*)source->sasl.callbacks[0].context,
+ (const char*)secret->data);
+ }
+
+ /*
+ * But we're not. It may work if we know what the user tries to pass
+ * into the list, but if we don't know the ID we don't know how to handle
+ * the context...
+ */
+ ptrdiff_t total= 0;
+
+ while (source->sasl.callbacks[total].id != SASL_CB_LIST_END)
+ {
+ switch (source->sasl.callbacks[total].id)
+ {
+ case SASL_CB_USER:
+ case SASL_CB_AUTHNAME:
+ case SASL_CB_PASS:
+ break;
+ default:
+ /* I don't know how to deal with this... */
+ return MEMCACHED_NOT_SUPPORTED;
+ }
+
+ ++total;
+ }
+
+ sasl_callback_t *callbacks= libmemcached_xcalloc(clone, total +1, sasl_callback_t);
+ if (callbacks == NULL)
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+ memcpy(callbacks, source->sasl.callbacks, (total + 1) * sizeof(sasl_callback_t));
+
+ /* Now update the context... */
+ for (ptrdiff_t x= 0; x < total; ++x)
+ {
+ if (callbacks[x].id == SASL_CB_USER || callbacks[x].id == SASL_CB_AUTHNAME)
+ {
+ callbacks[x].context= (sasl_callback_t*)libmemcached_malloc(clone, strlen((const char*)source->sasl.callbacks[x].context));
+
+ if (callbacks[x].context == NULL)
+ {
+ /* Failed to allocate memory, clean up previously allocated memory */
+ for (ptrdiff_t y= 0; y < x; ++y)
+ {
+ libmemcached_free(clone, clone->sasl.callbacks[y].context);
+ }
+
+ libmemcached_free(clone, callbacks);
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+ strncpy((char*)callbacks[x].context, (const char*)source->sasl.callbacks[x].context, sizeof(callbacks[x].context));
+ }
+ else
+ {
+ sasl_secret_t *src= (sasl_secret_t *)source->sasl.callbacks[x].context;
+ sasl_secret_t *n= (sasl_secret_t*)libmemcached_malloc(clone, src->len + 1 + sizeof(*n));
+ if (n == NULL)
+ {
+ /* Failed to allocate memory, clean up previously allocated memory */
+ for (ptrdiff_t y= 0; y < x; ++y)
+ {
+ libmemcached_free(clone, clone->sasl.callbacks[y].context);
+ }
+
+ libmemcached_free(clone, callbacks);
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+ memcpy(n, src, src->len + 1 + sizeof(*n));
+ callbacks[x].context= n;
+ }
+ }
+
+ clone->sasl.callbacks= callbacks;
+ clone->sasl.is_allocated= true;
+
+ return MEMCACHED_SUCCESS;
+}
+
+#else
+
+void memcached_set_sasl_callbacks(memcached_st *, const sasl_callback_t *)
+{
+}
+
+sasl_callback_t *memcached_get_sasl_callbacks(memcached_st *)
+{
+ return NULL;
+}
+
+memcached_return_t memcached_set_sasl_auth_data(memcached_st *, const char *, const char *)
+{
+ return MEMCACHED_NOT_SUPPORTED;
+}
+
+memcached_return_t memcached_clone_sasl(memcached_st *, const memcached_st *)
+{
+ return MEMCACHED_NOT_SUPPORTED;
+}
+
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+memcached_return_t memcached_clone_sasl(memcached_st *clone, const memcached_st *source);
+
+memcached_return_t memcached_sasl_authenticate_connection(memcached_instance_st* server);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ This is a partial implementation for fetching/creating memcached_server_st objects.
+*/
+#include <libmemcached/common.h>
+
+static inline void _server_init(memcached_server_st *self, Memcached *root,
+ const memcached_string_t& hostname,
+ in_port_t port,
+ uint32_t weight, memcached_connection_t type)
+{
+ self->options.is_shutting_down= false;
+ self->options.is_dead= false;
+ self->number_of_hosts= 0;
+ self->cursor_active= 0;
+ self->port= port;
+ self->io_bytes_sent= 0;
+ self->request_id= 0;
+ self->server_failure_counter= 0;
+ self->server_failure_counter_query_id= 0;
+ self->server_timeout_counter= 0;
+ self->server_timeout_counter_query_id= 0;
+ self->weight= weight ? weight : 1; // 1 is the default weight value
+ self->io_wait_count.read= 0;
+ self->io_wait_count.write= 0;
+ self->io_wait_count.timeouts= 0;
+ self->io_wait_count._bytes_read= 0;
+ self->major_version= UINT8_MAX;
+ self->micro_version= UINT8_MAX;
+ self->minor_version= UINT8_MAX;
+ self->type= type;
+ self->error_messages= NULL;
+
+ self->state= MEMCACHED_SERVER_STATE_NEW;
+ self->next_retry= 0;
+
+ self->root= root;
+ if (root)
+ {
+ self->version= ++root->server_info.version;
+ }
+ else
+ {
+ self->version= UINT_MAX;
+ }
+ self->limit_maxbytes= 0;
+ memcpy(self->hostname, hostname.c_str, hostname.size);
+ self->hostname[hostname.size]= 0;
+}
+
+static memcached_server_st *_server_create(memcached_server_st *self, const Memcached *memc)
+{
+ if (self == NULL)
+ {
+ self= libmemcached_xmalloc(memc, struct memcached_server_st);
+
+ if (self == NULL)
+ {
+ return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+ }
+
+ self->options.is_allocated= true;
+ }
+ else
+ {
+ self->options.is_allocated= false;
+ }
+
+ self->options.is_initialized= true;
+
+ return self;
+}
+
+memcached_server_st *__server_create_with(Memcached *memc,
+ memcached_server_st* allocated_instance,
+ const memcached_string_t& hostname,
+ const in_port_t port,
+ uint32_t weight,
+ const memcached_connection_t type)
+{
+ if (memcached_is_valid_servername(hostname) == false)
+ {
+ memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid hostname provided"));
+ return NULL;
+ }
+
+ allocated_instance= _server_create(allocated_instance, memc);
+
+ if (allocated_instance == NULL)
+ {
+ return NULL;
+ }
+
+ _server_init(allocated_instance, const_cast<Memcached *>(memc), hostname, port, weight, type);
+
+ return allocated_instance;
+}
+
+void __server_free(memcached_server_st *self)
+{
+ memcached_error_free(*self);
+
+ if (memcached_is_allocated(self))
+ {
+ libmemcached_free(self->root, self);
+ }
+ else
+ {
+ self->options.is_initialized= false;
+ }
+}
+
+void memcached_server_free(memcached_server_st *self)
+{
+ if (self == NULL)
+ {
+ return;
+ }
+
+ if (memcached_server_list_count(self))
+ {
+ memcached_server_list_free(self);
+ return;
+ }
+
+ __server_free(self);
+}
+
+void memcached_server_error_reset(memcached_server_st *self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (self == NULL)
+ {
+ return;
+ }
+
+ memcached_error_free(*self);
+}
+
+uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count)
+{
+ WATCHPOINT_ASSERT(servers);
+ if (servers == NULL)
+ {
+ return 0;
+ }
+
+ return servers->number_of_hosts= count;
+}
+
+uint32_t memcached_server_count(const memcached_st *self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (self == NULL)
+ return 0;
+
+ return self->number_of_hosts;
+}
+
+const char *memcached_server_name(const memcached_instance_st * self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (self)
+ {
+ return self->_hostname;
+ }
+
+ return NULL;
+}
+
+in_port_t memcached_server_port(const memcached_instance_st * self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (self == NULL)
+ {
+ return 0;
+ }
+
+ return self->port();
+}
+
+in_port_t memcached_server_srcport(const memcached_instance_st * self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (self == NULL || self->fd == INVALID_SOCKET || (self->type != MEMCACHED_CONNECTION_TCP && self->type != MEMCACHED_CONNECTION_UDP))
+ {
+ return 0;
+ }
+
+ struct sockaddr_in sin;
+ socklen_t addrlen= sizeof(sin);
+ if (getsockname(self->fd, (struct sockaddr*)&sin, &addrlen) != -1)
+ {
+ return ntohs(sin.sin_port);
+ }
+
+ return -1;
+}
+
+uint32_t memcached_server_response_count(const memcached_instance_st * self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (self == NULL)
+ {
+ return 0;
+ }
+
+ return self->cursor_active_;
+}
+
+const char *memcached_server_type(const memcached_instance_st * ptr)
+{
+ if (ptr)
+ {
+ switch (ptr->type)
+ {
+ case MEMCACHED_CONNECTION_TCP:
+ return "TCP";
+
+ case MEMCACHED_CONNECTION_UDP:
+ return "UDP";
+
+ case MEMCACHED_CONNECTION_UNIX_SOCKET:
+ return "SOCKET";
+ }
+ }
+
+ return "UNKNOWN";
+}
+
+uint8_t memcached_server_major_version(const memcached_instance_st * instance)
+{
+ if (instance)
+ {
+ return instance->major_version;
+ }
+
+ return UINT8_MAX;
+}
+
+uint8_t memcached_server_minor_version(const memcached_instance_st * instance)
+{
+ if (instance)
+ {
+ return instance->minor_version;
+ }
+
+ return UINT8_MAX;
+}
+
+uint8_t memcached_server_micro_version(const memcached_instance_st * instance)
+{
+ if (instance)
+ {
+ return instance->micro_version;
+ }
+
+ return UINT8_MAX;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <cassert>
+
+memcached_server_st *__server_create_with(memcached_st *memc,
+ memcached_server_st* self,
+ const memcached_string_t& hostname,
+ const in_port_t port,
+ uint32_t weight,
+ const memcached_connection_t type);
+
+memcached_return_t memcached_server_add_parsed(memcached_st *ptr,
+ const char *hostname,
+ size_t hostname_length,
+ in_port_t port,
+ uint32_t weight);
+
+void __server_free(memcached_server_st *);
+
+static inline bool memcached_is_valid_servername(const memcached_string_t& arg)
+{
+ return (arg.c_str != NULL or arg.size == 0) and arg.size < MEMCACHED_NI_MAXHOST;
+}
+
+static inline bool memcached_is_valid_filename(const memcached_string_t& arg)
+{
+ return arg.c_str != NULL and arg.size > 0 and arg.size < MEMCACHED_NI_MAXHOST;
+}
+
+void memcached_instance_free(memcached_instance_st *);
+
+void set_last_disconnected_host(memcached_instance_st* self);
+
+static inline void memcached_mark_server_for_timeout(memcached_instance_st* server)
+{
+ if (server->state != MEMCACHED_SERVER_STATE_IN_TIMEOUT)
+ {
+ if (server->server_timeout_counter_query_id != server->root->query_id)
+ {
+ server->server_timeout_counter++;
+ server->server_timeout_counter_query_id= server->root->query_id;
+ }
+
+ if (server->server_timeout_counter >= server->root->server_timeout_limit)
+ {
+ struct timeval next_time;
+ if (gettimeofday(&next_time, NULL) == 0)
+ {
+ server->next_retry= next_time.tv_sec +server->root->retry_timeout;
+ }
+ else
+ {
+ server->next_retry= 1; // Setting the value to 1 causes the timeout to occur immediately
+ }
+
+ server->state= MEMCACHED_SERVER_STATE_IN_TIMEOUT;
+ if (server->server_failure_counter_query_id != server->root->query_id)
+ {
+ server->server_failure_counter++;
+ server->server_failure_counter_query_id= server->root->query_id;
+ }
+ set_last_disconnected_host(server);
+ }
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+typedef struct memcached_instance_st* memcached_server_write_instance_st;
+#else
+typedef void* memcached_server_write_instance_st;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef memcached_return_t (*memcached_server_execute_fn)(memcached_st *ptr, memcached_server_write_instance_st server, void *context);
+
+memcached_return_t memcached_server_execute(memcached_st *ptr,
+ memcached_server_execute_fn callback,
+ void *context);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+
+#include <libmemcached/common.h>
+
+memcached_server_list_st
+memcached_server_list_append_with_weight(memcached_server_list_st ptr,
+ const char *hostname, in_port_t port,
+ uint32_t weight,
+ memcached_return_t *error)
+{
+ memcached_return_t unused;
+ if (error == NULL)
+ {
+ error= &unused;
+ }
+
+ if (hostname == NULL)
+ {
+ hostname= "localhost";
+ }
+
+ if (hostname[0] == '/')
+ {
+ port = 0;
+ }
+ else if (port == 0)
+ {
+ port= MEMCACHED_DEFAULT_PORT;
+ }
+
+
+ /* Increment count for hosts */
+ uint32_t count= 1;
+ if (ptr != NULL)
+ {
+ count+= memcached_server_list_count(ptr);
+ }
+
+ memcached_server_list_st new_host_list= (memcached_server_st*)realloc(ptr, sizeof(memcached_server_st) * count);
+ if (new_host_list == NULL)
+ {
+#if 0
+ *error= memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+#endif
+ return NULL;
+ }
+
+ memcached_string_t _hostname= { memcached_string_make_from_cstr(hostname) };
+ /* @todo Check return type */
+ if (__server_create_with(NULL, &new_host_list[count-1], _hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET) == NULL)
+ {
+#if 0
+ *error= memcached_set_errno(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+#endif
+ free(new_host_list);
+ return NULL;
+ }
+
+#if 0
+ // Handset allocated since
+ new_host_list->options.is_allocated= true;
+#endif
+
+ /* Backwards compatibility hack */
+ memcached_servers_set_count(new_host_list, count);
+
+ *error= MEMCACHED_SUCCESS;
+ return new_host_list;
+}
+
+memcached_server_list_st
+memcached_server_list_append(memcached_server_list_st ptr,
+ const char *hostname, in_port_t port,
+ memcached_return_t *error)
+{
+ return memcached_server_list_append_with_weight(ptr, hostname, port, 0, error);
+}
+
+uint32_t memcached_server_list_count(const memcached_server_list_st self)
+{
+ return (self == NULL)
+ ? 0
+ : self->number_of_hosts;
+}
+
+uint32_t memcached_instance_list_count(const memcached_st* self)
+{
+ return (self == NULL)
+ ? 0
+ : self->number_of_hosts;
+}
+
+void memcached_instance_set(memcached_st* memc, memcached_instance_st* list, const uint32_t host_list_size)
+{
+ assert(memc);
+ memc->servers= list;
+ memc->number_of_hosts= host_list_size;
+}
+
+void memcached_server_list_free(memcached_server_list_st self)
+{
+ if (self)
+ {
+ for (uint32_t x= 0; x < memcached_server_list_count(self); x++)
+ {
+ assert_msg(not memcached_is_allocated(&self[x]), "You have called memcached_server_list_free(), but you did not pass it a valid memcached_server_list_st");
+ __server_free(&self[x]);
+ }
+
+ libmemcached_free(self->root, self);
+ }
+}
+
+void memcached_instance_list_free(memcached_instance_st* self, uint32_t instance_count)
+{
+ if (self)
+ {
+ for (uint32_t x= 0; x < instance_count; x++)
+ {
+ assert_msg(memcached_is_allocated(&self[x]) == false, "You have called memcached_server_list_free(), but you did not pass it a valid memcached_server_list_st");
+ __instance_free(&self[x]);
+ }
+
+ libmemcached_free(self->root, self);
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+memcached_instance_st* memcached_instance_list(const memcached_st *);
+
+uint32_t memcached_instance_list_count(const memcached_st*);
+
+uint32_t memcached_servers_set_count(memcached_server_list_st servers, uint32_t count);
+
+void memcached_instance_list_free(memcached_instance_st* self, uint32_t count);
+
+void memcached_instance_set(memcached_st*, memcached_instance_st*, const uint32_t host_list_size);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+/* To hide the platform differences between MS Windows and Unix, I am
+ * going to use the Microsoft way and #define the Microsoft-specific
+ * functions to the unix way. Microsoft use a separate subsystem for sockets,
+ * but Unix normally just use a filedescriptor on the same functions. It is
+ * a lot easier to map back to the unix way with macros than going the other
+ * way without side effect ;-)
+ */
+#if defined(WIN32) || defined(__MINGW32__)
+# include "win32/wrappers.h"
+# define get_socket_errno() WSAGetLastError()
+#else
+# include <unistd.h>
+# define INVALID_SOCKET -1
+# define SOCKET_ERROR -1
+# define closesocket(a) close(a)
+# define get_socket_errno() errno
+#endif
+
+#ifdef __cplusplus
+static inline void memcached_close_socket(memcached_socket_t& socket_fd)
+{
+ closesocket(socket_fd);
+ socket_fd= INVALID_SOCKET;
+}
+#endif
+
+#ifndef HAVE_MSG_NOSIGNAL
+# define MSG_NOSIGNAL 0
+#endif
+
+#ifndef HAVE_MSG_DONTWAIT
+# define MSG_DONTWAIT 0
+#endif
+
+#ifndef HAVE_MSG_MORE
+# define MSG_MORE 0
+#endif
+
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static const char *memcached_stat_keys[] = {
+ "pid",
+ "uptime",
+ "time",
+ "version",
+ "pointer_size",
+ "rusage_user",
+ "rusage_system",
+ "curr_items",
+ "total_items",
+ "bytes",
+ "curr_connections",
+ "total_connections",
+ "connection_structures",
+ "cmd_get",
+ "cmd_set",
+ "get_hits",
+ "get_misses",
+ "evictions",
+ "bytes_read",
+ "bytes_written",
+ "limit_maxbytes",
+ "threads",
+ NULL
+};
+
+struct local_context
+{
+ memcached_stat_fn func;
+ void *context;
+ const char *args;
+ const size_t args_length;
+
+ local_context(memcached_stat_fn func_arg,
+ void *context_arg,
+ const char *args_arg,
+ const size_t args_length_arg) :
+ func(func_arg),
+ context(context_arg),
+ args(args_arg),
+ args_length(args_length_arg)
+ { }
+};
+
+
+static memcached_return_t set_data(memcached_stat_st *memc_stat, const char *key, const char *value)
+{
+
+ if (strlen(key) < 1)
+ {
+ WATCHPOINT_STRING(key);
+ return MEMCACHED_UNKNOWN_STAT_KEY;
+ }
+ else if (strcmp("pid", key) == 0)
+ {
+ errno= 0;
+ int64_t temp= strtoll(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+
+ if (temp <= INT32_MAX and ( sizeof(pid_t) == sizeof(int32_t) ))
+ {
+ memc_stat->pid= pid_t(temp);
+ }
+ else if (temp > -1)
+ {
+ memc_stat->pid= pid_t(temp);
+ }
+ else
+ {
+ // If we got a value less then -1 then something went wrong in the
+ // protocol
+ }
+ }
+ else if (not strcmp("uptime", key))
+ {
+ errno= 0;
+ memc_stat->uptime= strtoul(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("time", key))
+ {
+ errno= 0;
+ memc_stat->time= strtoul(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("version", key))
+ {
+ memcpy(memc_stat->version, value, strlen(value));
+ memc_stat->version[strlen(value)]= 0;
+ }
+ else if (not strcmp("pointer_size", key))
+ {
+ errno= 0;
+ memc_stat->pointer_size= strtoul(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("rusage_user", key))
+ {
+ char *walk_ptr;
+ for (walk_ptr= (char*)value; (!ispunct(*walk_ptr)); walk_ptr++) {};
+ *walk_ptr= 0;
+ walk_ptr++;
+
+ errno= 0;
+ memc_stat->rusage_user_seconds= strtoul(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+
+ errno= 0;
+ memc_stat->rusage_user_microseconds= strtoul(walk_ptr, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("rusage_system", key))
+ {
+ char *walk_ptr;
+ for (walk_ptr= (char*)value; (!ispunct(*walk_ptr)); walk_ptr++) {};
+ *walk_ptr= 0;
+ walk_ptr++;
+
+ errno= 0;
+ memc_stat->rusage_system_seconds= strtoul(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+
+ errno= 0;
+ memc_stat->rusage_system_microseconds= strtoul(walk_ptr, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("curr_items", key))
+ {
+ errno= 0;
+ memc_stat->curr_items= strtoul(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("total_items", key))
+ {
+ errno= 0;
+ memc_stat->total_items= strtoul(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("bytes_read", key))
+ {
+ errno= 0;
+ memc_stat->bytes_read= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("bytes_written", key))
+ {
+ errno= 0;
+ memc_stat->bytes_written= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("bytes", key))
+ {
+ errno= 0;
+ memc_stat->bytes= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("curr_connections", key))
+ {
+ errno= 0;
+ memc_stat->curr_connections= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("total_connections", key))
+ {
+ errno= 0;
+ memc_stat->total_connections= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("connection_structures", key))
+ {
+ errno= 0;
+ memc_stat->connection_structures= strtoul(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("cmd_get", key))
+ {
+ errno= 0;
+ memc_stat->cmd_get= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("cmd_set", key))
+ {
+ errno= 0;
+ memc_stat->cmd_set= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("get_hits", key))
+ {
+ errno= 0;
+ memc_stat->get_hits= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("get_misses", key))
+ {
+ errno= 0;
+ memc_stat->get_misses= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("evictions", key))
+ {
+ errno= 0;
+ memc_stat->evictions= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("limit_maxbytes", key))
+ {
+ errno= 0;
+ memc_stat->limit_maxbytes= strtoull(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if (not strcmp("threads", key))
+ {
+ errno= 0;
+ memc_stat->threads= strtoul(value, (char **)NULL, 10);
+ if (errno != 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+ }
+ else if ((strcmp("delete_misses", key) == 0 or /* New stats in the 1.3 beta */
+ strcmp("delete_hits", key) == 0 or /* Just swallow them for now.. */
+ strcmp("incr_misses", key) == 0 or
+ strcmp("incr_hits", key) == 0 or
+ strcmp("decr_misses", key) == 0 or
+ strcmp("decr_hits", key) == 0 or
+ strcmp("cas_misses", key) == 0 or
+ strcmp("cas_hits", key) == 0 or
+ strcmp("cas_badval", key) == 0 or
+ strcmp("cmd_flush", key) == 0 or
+ strcmp("accepting_conns", key) == 0 or
+ strcmp("listen_disabled_num", key) == 0 or
+ strcmp("conn_yields", key) == 0 or
+ strcmp("auth_cmds", key) == 0 or
+ strcmp("auth_errors", key) == 0 or
+ strcmp("reclaimed", key) == 0) == 0)
+ {
+ WATCHPOINT_STRING(key);
+ /* return MEMCACHED_UNKNOWN_STAT_KEY; */
+ return MEMCACHED_SUCCESS;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+char *memcached_stat_get_value(const memcached_st* shell, memcached_stat_st *memc_stat,
+ const char *key, memcached_return_t *error)
+{
+ memcached_return_t not_used;
+ if (error == NULL)
+ {
+ error= ¬_used;
+ }
+
+ if (memc_stat == NULL)
+ {
+ *error= MEMCACHED_INVALID_ARGUMENTS;
+ return NULL;
+ }
+
+ char buffer[SMALL_STRING_LEN];
+ int length;
+
+ *error= MEMCACHED_SUCCESS;
+
+ if (memcmp("pid", key, sizeof("pid") -1) == 0)
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lld", (signed long long)memc_stat->pid);
+ }
+ else if (not memcmp("uptime", key, sizeof("uptime") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->uptime);
+ }
+ else if (not memcmp("time", key, sizeof("time") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time);
+ }
+ else if (not memcmp("version", key, sizeof("version") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version);
+ }
+ else if (not memcmp("pointer_size", key, sizeof("pointer_size") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->pointer_size);
+ }
+ else if (not memcmp("rusage_user", key, sizeof("rusage_user") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu.%lu", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds);
+ }
+ else if (not memcmp("rusage_system", key, sizeof("rusage_system") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu.%lu", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds);
+ }
+ else if (not memcmp("curr_items", key, sizeof("curr_items") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->curr_items);
+ }
+ else if (not memcmp("total_items", key, sizeof("total_items") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->total_items);
+ }
+ else if (not memcmp("curr_connections", key, sizeof("curr_connections") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->curr_connections);
+ }
+ else if (not memcmp("total_connections", key, sizeof("total_connections") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->total_connections);
+ }
+ else if (not memcmp("connection_structures", key, sizeof("connection_structures") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->connection_structures);
+ }
+ else if (not memcmp("cmd_get", key, sizeof("cmd_get") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get);
+ }
+ else if (not memcmp("cmd_set", key, sizeof("cmd_set") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set);
+ }
+ else if (not memcmp("get_hits", key, sizeof("get_hits") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits);
+ }
+ else if (not memcmp("get_misses", key, sizeof("get_misses") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses);
+ }
+ else if (not memcmp("evictions", key, sizeof("evictions") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions);
+ }
+ else if (not memcmp("bytes_read", key, sizeof("bytes_read") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read);
+ }
+ else if (not memcmp("bytes_written", key, sizeof("bytes_written") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written);
+ }
+ else if (not memcmp("bytes", key, sizeof("bytes") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes);
+ }
+ else if (not memcmp("limit_maxbytes", key, sizeof("limit_maxbytes") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes);
+ }
+ else if (not memcmp("threads", key, sizeof("threads") -1))
+ {
+ length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->threads);
+ }
+ else
+ {
+ Memcached* memc= (Memcached*)memcached2Memcached(shell);
+ *error= memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid key provided"));
+ return NULL;
+ }
+
+ if (length >= SMALL_STRING_LEN || length < 0)
+ {
+ Memcached* memc= (Memcached*)memcached2Memcached(shell);
+ *error= memcached_set_error(*memc, MEMCACHED_FAILURE, MEMCACHED_AT, memcached_literal_param("Internal failure occured with buffer, please report this bug."));
+ return NULL;
+ }
+
+ // User is responsible for free() memory, so use malloc()
+ char *ret= static_cast<char *>(malloc(size_t(length +1)));
+ memcpy(ret, buffer, (size_t) length);
+ ret[length]= '\0';
+
+ return ret;
+}
+
+static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat,
+ const char *args,
+ const size_t args_length,
+ memcached_instance_st* instance,
+ struct local_context *check)
+{
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ protocol_binary_request_stats request= {}; // = {.bytes= {0}};
+ memcached_return_t rc;
+
+ initialize_binary_request(instance, request.message.header);
+
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+ if (args_length)
+ {
+ request.message.header.request.keylen= htons(uint16_t(args_length));
+ request.message.header.request.bodylen= htonl(uint32_t( args_length));
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { request.bytes, sizeof(request.bytes) },
+ { args, args_length }
+ };
+
+ if (memcached_failed(rc = memcached_vdo(instance, vector, 2, true)))
+ {
+ return rc;
+ }
+ }
+ else
+ {
+ libmemcached_io_vector_st vector[]=
+ {
+ { request.bytes, sizeof(request.bytes) }
+ };
+
+ if (memcached_failed(rc = memcached_vdo(instance, vector, 1, true)))
+ {
+ return rc;
+ }
+ }
+
+ memcached_server_response_decrement(instance);
+ while (1)
+ {
+ rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
+
+ if (rc == MEMCACHED_END)
+ {
+ break;
+ }
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ return rc;
+ }
+
+ if (check && check->func)
+ {
+ size_t key_length= strlen(buffer);
+
+ check->func(instance,
+ buffer, key_length,
+ buffer+key_length+1, strlen(buffer+key_length+1),
+ check->context);
+ }
+
+ if (memc_stat)
+ {
+ if ((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
+ {
+ WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+ WATCHPOINT_ASSERT(0);
+ }
+ }
+ }
+
+ /*
+ * memcached_response will decrement the counter, so I need to reset it..
+ * todo: look at this and try to find a better solution.
+ * */
+ instance->cursor_active_= 0;
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat,
+ const char *args,
+ const size_t args_length,
+ memcached_instance_st* instance,
+ struct local_context *check)
+{
+ libmemcached_io_vector_st vector[]=
+ {
+ { memcached_literal_param("stats ") },
+ { args, args_length },
+ { memcached_literal_param("\r\n") }
+ };
+
+ memcached_return_t rc= memcached_vdo(instance, vector, 3, true);
+ if (memcached_success(rc))
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ while ((rc= memcached_response(instance, buffer, sizeof(buffer), NULL)) == MEMCACHED_STAT)
+ {
+ char *string_ptr= buffer;
+ string_ptr+= 5; /* Move past STAT */
+
+ char *end_ptr;
+ for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++) {};
+ char *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++) {};
+ char *value= string_ptr;
+ value[(size_t)(end_ptr -string_ptr)]= 0;
+#if 0
+ bool check_bool= bool(check);
+ bool check_func_bool= bool(check) ? bool(check->func) : false;
+ fprintf(stderr, "%s:%d %s %s %d:%d\n", __FILE__, __LINE__, key, value, check_bool, check_func_bool);
+#endif
+
+ if (check and check->func)
+ {
+ check->func(instance,
+ key, strlen(key),
+ value, strlen(value),
+ check->context);
+ }
+
+ if (memc_stat)
+ {
+ if((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY)
+ {
+ WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+ WATCHPOINT_ASSERT(0);
+ }
+ }
+ }
+ }
+
+ if (rc == MEMCACHED_ERROR)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ if (rc == MEMCACHED_END)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ return rc;
+}
+
+memcached_stat_st *memcached_stat(memcached_st *shell, char *args, memcached_return_t *error)
+{
+ Memcached* self= memcached2Memcached(shell);
+ memcached_return_t unused;
+ if (error == NULL)
+ {
+ error= &unused;
+ }
+
+ if (memcached_failed(*error= initialize_query(self, true)))
+ {
+ return NULL;
+ }
+
+ if (memcached_is_udp(self))
+ {
+ *error= memcached_set_error(*self, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
+ return NULL;
+ }
+
+ memcached_return_t rc;
+ size_t args_length= 0;
+ if (args)
+ {
+ args_length= strlen(args);
+ if (memcached_failed(rc= memcached_key_test(*self, (const char **)&args, &args_length, 1)))
+ {
+ *error= memcached_set_error(*self, rc, MEMCACHED_AT);
+ return NULL;
+ }
+ }
+
+ WATCHPOINT_ASSERT(error);
+
+ memcached_stat_st *stats= libmemcached_xcalloc(self, memcached_server_count(self), memcached_stat_st);
+ if (stats == NULL)
+ {
+ *error= memcached_set_error(*self, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ return NULL;
+ }
+
+ WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
+ rc= MEMCACHED_SUCCESS;
+ for (uint32_t x= 0; x < memcached_server_count(self); x++)
+ {
+ memcached_stat_st* stat_instance= stats +x;
+
+ stat_instance->pid= -1;
+ stat_instance->root= self;
+
+ memcached_instance_st* instance= memcached_instance_fetch(self, x);
+
+ memcached_return_t temp_return;
+ if (memcached_is_binary(self))
+ {
+ temp_return= binary_stats_fetch(stat_instance, args, args_length, instance, NULL);
+ }
+ else
+ {
+ temp_return= ascii_stats_fetch(stat_instance, args, args_length, instance, NULL);
+ }
+
+ // Special case where "args" is invalid
+ if (temp_return == MEMCACHED_INVALID_ARGUMENTS)
+ {
+ rc= MEMCACHED_INVALID_ARGUMENTS;
+ break;
+ }
+
+ if (memcached_failed(temp_return))
+ {
+ 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_st memc;
+
+ memcached_stat_st unused_memc_stat;
+ if (memc_stat == NULL)
+ {
+ memc_stat= &unused_memc_stat;
+ }
+
+ memset(memc_stat, 0, sizeof(memcached_stat_st));
+
+ memcached_st *memc_ptr= memcached_create(&memc);
+ if (memc_ptr == NULL)
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= memcached_server_add(&memc, hostname, port)))
+ {
+ memcached_free(&memc);
+ return rc;
+ }
+
+ if (memcached_success(rc= initialize_query(memc_ptr, true)))
+ {
+ size_t args_length= 0;
+ if (args)
+ {
+ args_length= strlen(args);
+ rc= memcached_key_test(*memc_ptr, (const char **)&args, &args_length, 1);
+ }
+
+ if (memcached_success(rc))
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc_ptr, 0);
+ if (memc.flags.binary_protocol)
+ {
+ rc= binary_stats_fetch(memc_stat, args, args_length, instance, NULL);
+ }
+ else
+ {
+ rc= ascii_stats_fetch(memc_stat, args, args_length, instance, NULL);
+ }
+ }
+ }
+
+ memcached_free(&memc);
+
+ return rc;
+}
+
+/*
+ We make a copy of the keys since at some point in the not so distant future
+ we will add support for "found" keys.
+*/
+char ** memcached_stat_get_keys(memcached_st *shell,
+ memcached_stat_st *,
+ memcached_return_t *error)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ char **list= static_cast<char **>(libmemcached_malloc(memc, sizeof(memcached_stat_keys)));
+ if (list == NULL)
+ {
+ if (error)
+ {
+ *error= memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+
+ return NULL;
+ }
+
+ memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys));
+
+ if (error)
+ {
+ *error= MEMCACHED_SUCCESS;
+ }
+
+ return list;
+ }
+
+ return NULL;
+}
+
+void memcached_stat_free(const memcached_st *, memcached_stat_st *memc_stat)
+{
+ WATCHPOINT_ASSERT(memc_stat); // Be polite, but when debugging catch this as an error
+ if (memc_stat)
+ {
+ libmemcached_free(memc_stat->root, memc_stat);
+ }
+}
+
+static memcached_return_t call_stat_fn(memcached_st *memc,
+ memcached_instance_st* instance,
+ void *context)
+{
+ if (memc)
+ {
+ local_context *check= (struct local_context *)context;
+
+ if (memcached_is_binary(memc))
+ {
+ return binary_stats_fetch(NULL, check->args, check->args_length, instance, check);
+ }
+ else
+ {
+ return ascii_stats_fetch(NULL, check->args, check->args_length, instance, check);
+ }
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
+
+memcached_return_t memcached_stat_execute(memcached_st *shell, const char *args, memcached_stat_fn func, void *context)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ if (memcached_fatal(memcached_version(memc)))
+ {
+ return memcached_last_error(memc);
+ }
+
+ local_context check(func, context, args, args ? strlen(args) : 0);
+
+ return memcached_server_execute(memc, call_stat_fn, (void *)&check);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+
+enum memcached_storage_action_t {
+ SET_OP,
+ REPLACE_OP,
+ ADD_OP,
+ PREPEND_OP,
+ APPEND_OP,
+ CAS_OP
+};
+
+/* Inline this */
+static inline const char *storage_op_string(memcached_storage_action_t verb)
+{
+ switch (verb)
+ {
+ case REPLACE_OP:
+ return "replace ";
+
+ case ADD_OP:
+ return "add ";
+
+ case PREPEND_OP:
+ return "prepend ";
+
+ case APPEND_OP:
+ return "append ";
+
+ case CAS_OP:
+ return "cas ";
+
+ case SET_OP:
+ break;
+ }
+
+ return "set ";
+}
+
+static inline bool can_by_encrypted(const memcached_storage_action_t verb)
+{
+ switch (verb)
+ {
+ case SET_OP:
+ case ADD_OP:
+ case CAS_OP:
+ case REPLACE_OP:
+ return true;
+
+ case APPEND_OP:
+ case PREPEND_OP:
+ break;
+ }
+
+ return false;
+}
+
+static inline uint8_t get_com_code(const memcached_storage_action_t verb, const bool reply)
+{
+ if (reply == false)
+ {
+ switch (verb)
+ {
+ case SET_OP:
+ return PROTOCOL_BINARY_CMD_SETQ;
+
+ case ADD_OP:
+ return PROTOCOL_BINARY_CMD_ADDQ;
+
+ case CAS_OP: /* FALLTHROUGH */
+ case REPLACE_OP:
+ return PROTOCOL_BINARY_CMD_REPLACEQ;
+
+ case APPEND_OP:
+ return PROTOCOL_BINARY_CMD_APPENDQ;
+
+ case PREPEND_OP:
+ return PROTOCOL_BINARY_CMD_PREPENDQ;
+ }
+ }
+
+ switch (verb)
+ {
+ case SET_OP:
+ break;
+
+ case ADD_OP:
+ return PROTOCOL_BINARY_CMD_ADD;
+
+ case CAS_OP: /* FALLTHROUGH */
+ case REPLACE_OP:
+ return PROTOCOL_BINARY_CMD_REPLACE;
+
+ case APPEND_OP:
+ return PROTOCOL_BINARY_CMD_APPEND;
+
+ case PREPEND_OP:
+ return PROTOCOL_BINARY_CMD_PREPEND;
+ }
+
+ return PROTOCOL_BINARY_CMD_SET;
+}
+
+static memcached_return_t memcached_send_binary(Memcached *ptr,
+ memcached_instance_st* server,
+ uint32_t server_key,
+ const char *key,
+ const size_t key_length,
+ const char *value,
+ const size_t value_length,
+ const time_t expiration,
+ const uint32_t flags,
+ const uint64_t cas,
+ const bool flush,
+ const bool reply,
+ memcached_storage_action_t verb)
+{
+ protocol_binary_request_set request= {};
+ size_t send_length= sizeof(request.bytes);
+
+ initialize_binary_request(server, request.message.header);
+
+ request.message.header.request.opcode= get_com_code(verb, reply);
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ if (verb == APPEND_OP or verb == PREPEND_OP)
+ {
+ send_length -= 8; /* append & prepend does not contain extras! */
+ }
+ else
+ {
+ request.message.header.request.extlen= 8;
+ request.message.body.flags= htonl(flags);
+ request.message.body.expiration= htonl((uint32_t)expiration);
+ }
+
+ request.message.header.request.bodylen= htonl((uint32_t) (key_length + memcached_array_size(ptr->_namespace) + value_length +
+ request.message.header.request.extlen));
+
+ if (cas)
+ {
+ request.message.header.request.cas= memcached_htonll(cas);
+ }
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { request.bytes, send_length },
+ { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
+ { key, key_length },
+ { value, value_length }
+ };
+
+ /* write the header */
+ memcached_return_t rc;
+ if ((rc= memcached_vdo(server, vector, 5, flush)) != MEMCACHED_SUCCESS)
+ {
+ assert(memcached_last_error(server->root) != MEMCACHED_SUCCESS);
+ return memcached_last_error(server->root);
+ }
+
+ if (verb == SET_OP and ptr->number_of_replicas > 0)
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
+ WATCHPOINT_STRING("replicating");
+
+ for (uint32_t x= 0; x < ptr->number_of_replicas; x++)
+ {
+ ++server_key;
+ if (server_key == memcached_server_count(ptr))
+ {
+ server_key= 0;
+ }
+
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
+
+ if (memcached_success(memcached_vdo(instance, vector, 5, false)))
+ {
+ memcached_server_response_decrement(instance);
+ }
+ }
+ }
+
+ if (flush == false)
+ {
+ return MEMCACHED_BUFFERED;
+ }
+
+ // No reply always assumes success
+ if (reply == false)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ return memcached_response(server, NULL, 0, NULL);
+}
+
+static memcached_return_t memcached_send_ascii(Memcached *ptr,
+ memcached_instance_st* instance,
+ const char *key,
+ const size_t key_length,
+ const char *value,
+ const size_t value_length,
+ const time_t expiration,
+ const uint32_t flags,
+ const uint64_t cas,
+ const bool flush,
+ const bool reply,
+ const memcached_storage_action_t verb)
+{
+ char flags_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
+ int flags_buffer_length= snprintf(flags_buffer, sizeof(flags_buffer), " %u", flags);
+ if (size_t(flags_buffer_length) >= sizeof(flags_buffer) or flags_buffer_length < 0)
+ {
+ return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
+ }
+
+ char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
+ int expiration_buffer_length= snprintf(expiration_buffer, sizeof(expiration_buffer), " %llu", (unsigned long long)expiration);
+ if (size_t(expiration_buffer_length) >= sizeof(expiration_buffer) or expiration_buffer_length < 0)
+ {
+ return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
+ }
+
+ char value_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
+ int value_buffer_length= snprintf(value_buffer, sizeof(value_buffer), " %llu", (unsigned long long)value_length);
+ if (size_t(value_buffer_length) >= sizeof(value_buffer) or value_buffer_length < 0)
+ {
+ return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
+ }
+
+ char cas_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
+ int cas_buffer_length= 0;
+ if (cas)
+ {
+ cas_buffer_length= snprintf(cas_buffer, sizeof(cas_buffer), " %llu", (unsigned long long)cas);
+ if (size_t(cas_buffer_length) >= sizeof(cas_buffer) or cas_buffer_length < 0)
+ {
+ return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
+ }
+ }
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { storage_op_string(verb), strlen(storage_op_string(verb))},
+ { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
+ { key, key_length },
+ { flags_buffer, size_t(flags_buffer_length) },
+ { expiration_buffer, size_t(expiration_buffer_length) },
+ { value_buffer, size_t(value_buffer_length) },
+ { cas_buffer, size_t(cas_buffer_length) },
+ { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
+ { memcached_literal_param("\r\n") },
+ { value, value_length },
+ { memcached_literal_param("\r\n") }
+ };
+
+ /* Send command header */
+ memcached_return_t rc= memcached_vdo(instance, vector, 12, flush);
+
+ // If we should not reply, return with MEMCACHED_SUCCESS, unless error
+ if (reply == false)
+ {
+ return memcached_success(rc) ? MEMCACHED_SUCCESS : rc;
+ }
+
+ if (flush == false)
+ {
+ return memcached_success(rc) ? MEMCACHED_BUFFERED : rc;
+ }
+
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
+
+ if (rc == MEMCACHED_STORED)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+ }
+
+ assert(memcached_failed(rc));
+#if 0
+ if (memcached_has_error(ptr) == false)
+ {
+ return memcached_set_error(*ptr, rc, MEMCACHED_AT);
+ }
+#endif
+
+ return rc;
+}
+
+static inline memcached_return_t memcached_send(memcached_st *shell,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ const time_t expiration,
+ const uint32_t flags,
+ const uint64_t cas,
+ memcached_storage_action_t verb)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(ptr, true)))
+ {
+ return rc;
+ }
+
+ if (memcached_failed(memcached_key_test(*ptr, (const char **)&key, &key_length, 1)))
+ {
+ return memcached_last_error(ptr);
+ }
+
+ uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
+
+ WATCHPOINT_SET(instance->io_wait_count.read= 0);
+ WATCHPOINT_SET(instance->io_wait_count.write= 0);
+
+ bool flush= true;
+ if (memcached_is_buffering(instance->root) and verb == SET_OP)
+ {
+ flush= false;
+ }
+
+ bool reply= memcached_is_replying(ptr);
+
+ hashkit_string_st* destination= NULL;
+
+ if (memcached_is_encrypted(ptr))
+ {
+ if (can_by_encrypted(verb) == false)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
+ memcached_literal_param("Operation not allowed while encyrption is enabled"));
+ }
+
+ if ((destination= hashkit_encrypt(&ptr->hashkit, value, value_length)) == NULL)
+ {
+ return rc;
+ }
+ value= hashkit_string_c_str(destination);
+ value_length= hashkit_string_length(destination);
+ }
+
+ if (memcached_is_binary(ptr))
+ {
+ rc= memcached_send_binary(ptr, instance, server_key,
+ key, key_length,
+ value, value_length, expiration,
+ flags, cas, flush, reply, verb);
+ }
+ else
+ {
+ rc= memcached_send_ascii(ptr, instance,
+ key, key_length,
+ value, value_length, expiration,
+ flags, cas, flush, reply, verb);
+ }
+
+ hashkit_string_free(destination);
+
+ return rc;
+}
+
+
+memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_SET_START();
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, SET_OP);
+ LIBMEMCACHED_MEMCACHED_SET_END();
+ return rc;
+}
+
+memcached_return_t memcached_add(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_ADD_START();
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, ADD_OP);
+
+ LIBMEMCACHED_MEMCACHED_ADD_END();
+ return rc;
+}
+
+memcached_return_t memcached_replace(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_REPLACE_START();
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, REPLACE_OP);
+ LIBMEMCACHED_MEMCACHED_REPLACE_END();
+ return rc;
+}
+
+memcached_return_t memcached_prepend(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, PREPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_append(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, APPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_cas(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, cas, CAS_OP);
+ return rc;
+}
+
+memcached_return_t memcached_set_by_key(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_SET_START();
+ rc= memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, SET_OP);
+ LIBMEMCACHED_MEMCACHED_SET_END();
+ return rc;
+}
+
+memcached_return_t memcached_add_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_ADD_START();
+ rc= memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, ADD_OP);
+ LIBMEMCACHED_MEMCACHED_ADD_END();
+ return rc;
+}
+
+memcached_return_t memcached_replace_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_REPLACE_START();
+ rc= memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, REPLACE_OP);
+ LIBMEMCACHED_MEMCACHED_REPLACE_END();
+ return rc;
+}
+
+memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ return memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, PREPEND_OP);
+}
+
+memcached_return_t memcached_append_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ return memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, APPEND_OP);
+}
+
+memcached_return_t memcached_cas_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas)
+{
+ return memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, cas, CAS_OP);
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+const char *memcached_strerror(const memcached_st *, memcached_return_t rc)
+{
+ switch (rc)
+ {
+ case MEMCACHED_SUCCESS:
+ return "SUCCESS";
+
+ case MEMCACHED_FAILURE:
+ return "FAILURE";
+
+ case MEMCACHED_HOST_LOOKUP_FAILURE: // getaddrinfo only
+ return "getaddrinfo() or getnameinfo() HOSTNAME LOOKUP FAILURE";
+
+ case MEMCACHED_CONNECTION_FAILURE:
+ return "CONNECTION FAILURE";
+
+ case MEMCACHED_CONNECTION_BIND_FAILURE: // DEPRECATED, see MEMCACHED_HOST_LOOKUP_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_ERROR:
+ return "ERROR was returned by server";
+
+ case MEMCACHED_DATA_EXISTS:
+ return "CONNECTION DATA EXISTS";
+
+ case MEMCACHED_DATA_DOES_NOT_EXIST:
+ return "CONNECTION DATA DOES NOT EXIST";
+
+ case MEMCACHED_NOTSTORED:
+ return "NOT STORED";
+
+ case MEMCACHED_STORED:
+ return "STORED";
+
+ case MEMCACHED_NOTFOUND:
+ return "NOT FOUND";
+
+ case MEMCACHED_MEMORY_ALLOCATION_FAILURE:
+ return "MEMORY ALLOCATION FAILURE";
+
+ case MEMCACHED_PARTIAL_READ:
+ return "PARTIAL READ";
+
+ case MEMCACHED_SOME_ERRORS:
+ return "SOME ERRORS WERE REPORTED";
+
+ case MEMCACHED_NO_SERVERS:
+ return "NO SERVERS DEFINED";
+
+ case MEMCACHED_END:
+ return "SERVER END";
+
+ case MEMCACHED_DELETED:
+ return "SERVER DELETE";
+
+ case MEMCACHED_VALUE:
+ return "SERVER VALUE";
+
+ case MEMCACHED_STAT:
+ return "STAT VALUE";
+
+ case MEMCACHED_ITEM:
+ return "ITEM VALUE";
+
+ case MEMCACHED_ERRNO:
+ return "SYSTEM ERROR";
+
+ case MEMCACHED_FAIL_UNIX_SOCKET:
+ return "COULD NOT OPEN UNIX SOCKET";
+
+ case MEMCACHED_NOT_SUPPORTED:
+ return "ACTION NOT SUPPORTED";
+
+ case MEMCACHED_FETCH_NOTFINISHED:
+ return "FETCH WAS NOT COMPLETED";
+
+ case MEMCACHED_NO_KEY_PROVIDED:
+ return "A KEY LENGTH OF ZERO WAS PROVIDED";
+
+ case MEMCACHED_BUFFERED:
+ return "ACTION QUEUED";
+
+ case MEMCACHED_TIMEOUT:
+ return "A TIMEOUT OCCURRED";
+
+ case MEMCACHED_BAD_KEY_PROVIDED:
+ return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE";
+
+ case MEMCACHED_INVALID_HOST_PROTOCOL:
+ return "THE HOST TRANSPORT PROTOCOL DOES NOT MATCH THAT OF THE CLIENT";
+
+ case MEMCACHED_SERVER_MARKED_DEAD:
+ return "SERVER IS MARKED DEAD";
+
+ case MEMCACHED_UNKNOWN_STAT_KEY:
+ return "ENCOUNTERED AN UNKNOWN STAT KEY";
+
+ case MEMCACHED_E2BIG:
+ return "ITEM TOO BIG";
+
+ case MEMCACHED_INVALID_ARGUMENTS:
+ return "INVALID ARGUMENTS";
+
+ case MEMCACHED_KEY_TOO_BIG:
+ return "KEY RETURNED FROM SERVER WAS TOO LARGE";
+
+ case MEMCACHED_AUTH_PROBLEM:
+ return "FAILED TO SEND AUTHENTICATION TO SERVER";
+
+ case MEMCACHED_AUTH_FAILURE:
+ return "AUTHENTICATION FAILURE";
+
+ case MEMCACHED_AUTH_CONTINUE:
+ return "CONTINUE AUTHENTICATION";
+
+ case MEMCACHED_PARSE_ERROR:
+ return "ERROR OCCURED WHILE PARSING";
+
+ case MEMCACHED_PARSE_USER_ERROR:
+ return "USER INITIATED ERROR OCCURED WHILE PARSING";
+
+ case MEMCACHED_DEPRECATED:
+ return "DEPRECATED";
+
+ case MEMCACHED_IN_PROGRESS:
+ return "OPERATION IN PROCESS";
+
+ case MEMCACHED_SERVER_TEMPORARILY_DISABLED:
+ return "SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY";
+
+ case MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE:
+ return "SERVER FAILED TO ALLOCATE OBJECT";
+
+ case MEMCACHED_UNIX_SOCKET_PATH_TOO_BIG:
+ return "UNIX SOCKET PATH TOO LARGE";
+
+ default:
+ case MEMCACHED_MAXIMUM_RETURN:
+ return "INVALID memcached_return_t";
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+
+inline static memcached_return_t _string_check(memcached_string_st *string, size_t need)
+{
+ if (need && need > (size_t)(string->current_size - (size_t)(string->end - string->string)))
+ {
+ size_t current_offset= (size_t) (string->end - string->string);
+
+ /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
+ size_t adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / MEMCACHED_BLOCK_SIZE;
+ adjust++;
+
+ size_t new_size= sizeof(char) * (size_t)((adjust * MEMCACHED_BLOCK_SIZE) + string->current_size);
+ /* Test for overflow */
+ if (new_size < need)
+ {
+ char error_message[1024];
+ int error_message_length= snprintf(error_message, sizeof(error_message),"Needed %ld, got %ld", (long)need, (long)new_size);
+ return memcached_set_error(*string->root, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, error_message, error_message_length);
+ }
+
+ char *new_value= libmemcached_xrealloc(string->root, string->string, new_size, char);
+
+ if (new_value == NULL)
+ {
+ return memcached_set_error(*string->root, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
+ }
+
+ string->string= new_value;
+ string->end= string->string + current_offset;
+
+ string->current_size+= (MEMCACHED_BLOCK_SIZE * adjust);
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+static inline void _init_string(memcached_string_st *self)
+{
+ self->current_size= 0;
+ self->end= self->string= NULL;
+}
+
+memcached_string_st *memcached_string_create(Memcached *memc, memcached_string_st *self, size_t initial_size)
+{
+ WATCHPOINT_ASSERT(memc);
+
+ /* Saving malloc calls :) */
+ if (self)
+ {
+ WATCHPOINT_ASSERT(self->options.is_initialized == false);
+
+ memcached_set_allocated(self, false);
+ }
+ else
+ {
+ self= libmemcached_xmalloc(memc, memcached_string_st);
+
+ if (self == NULL)
+ {
+ return NULL;
+ }
+
+ memcached_set_allocated(self, true);
+ }
+ self->root= memc;
+
+ _init_string(self);
+
+ if (memcached_failed(_string_check(self, initial_size)))
+ {
+ if (memcached_is_allocated(self))
+ {
+ libmemcached_free(memc, self);
+ }
+
+ return NULL;
+ }
+
+ memcached_set_initialized(self, true);
+
+ WATCHPOINT_ASSERT(self->string == self->end);
+
+ return self;
+}
+
+static memcached_return_t memcached_string_append_null(memcached_string_st& string)
+{
+ if (memcached_failed(_string_check(&string, 1)))
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ *string.end= 0;
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t memcached_string_append_null(memcached_string_st *string)
+{
+ if (memcached_failed(_string_check(string, 1)))
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ *string->end= 0;
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_string_append_character(memcached_string_st *string,
+ char character)
+{
+ if (memcached_failed(_string_check(string, 1)))
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ *string->end= character;
+ string->end++;
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_string_append(memcached_string_st *string,
+ const char *value, size_t length)
+{
+ if (memcached_failed(_string_check(string, length)))
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ 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)
+{
+ if (memcached_string_length(string) == 0)
+ {
+ return NULL;
+ }
+
+ char *c_ptr= static_cast<char *>(libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char)));
+
+ if (c_ptr == NULL)
+ {
+ return NULL;
+ }
+
+ memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string));
+ c_ptr[memcached_string_length(string)]= 0;
+
+ return c_ptr;
+}
+
+bool memcached_string_set(memcached_string_st& string, const char* value, size_t length)
+{
+ memcached_string_reset(&string);
+ if (memcached_success(memcached_string_append(&string, value, length)))
+ {
+ memcached_string_append_null(string);
+ return true;
+ }
+
+ return false;
+}
+
+void memcached_string_reset(memcached_string_st *string)
+{
+ string->end= string->string;
+}
+
+void memcached_string_free(memcached_string_st& ptr)
+{
+ memcached_string_free(&ptr);
+}
+
+void memcached_string_free(memcached_string_st *ptr)
+{
+ if (ptr == NULL)
+ {
+ return;
+ }
+
+ if (ptr->string)
+ {
+ libmemcached_free(ptr->root, ptr->string);
+ }
+
+ if (memcached_is_allocated(ptr))
+ {
+ libmemcached_free(ptr->root, ptr);
+ }
+ else
+ {
+ ptr->options.is_initialized= false;
+ }
+}
+
+memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
+{
+ return _string_check(string, need);
+}
+
+bool memcached_string_resize(memcached_string_st& string, const size_t need)
+{
+ return memcached_success(_string_check(&string, need));
+}
+
+size_t memcached_string_length(const memcached_string_st *self)
+{
+ return size_t(self->end -self->string);
+}
+
+size_t memcached_string_length(const memcached_string_st& self)
+{
+ return size_t(self.end -self.string);
+}
+
+size_t memcached_string_size(const memcached_string_st *self)
+{
+ return self->current_size;
+}
+
+const char *memcached_string_value(const memcached_string_st *self)
+{
+ return self->string;
+}
+
+const char *memcached_string_value(const memcached_string_st& self)
+{
+ return self.string;
+}
+
+char *memcached_string_take_value(memcached_string_st *self)
+{
+ char* value= NULL;
+
+ assert_msg(self, "Invalid memcached_string_st");
+ if (self)
+ {
+ if (memcached_string_length(self))
+ {
+ // If we fail at adding the null, we copy and move on
+ if (memcached_failed(memcached_string_append_null(self)))
+ {
+ return NULL;
+ }
+
+ value= self->string;
+ _init_string(self);
+ }
+ }
+
+ return value;
+}
+
+char *memcached_string_value_mutable(const memcached_string_st *self)
+{
+ return self->string;
+}
+
+char *memcached_string_c_str(memcached_string_st& self)
+{
+ return self.string;
+}
+
+void memcached_string_set_length(memcached_string_st *self, size_t length)
+{
+ self->end= self->string +length;
+}
+
+void memcached_string_set_length(memcached_string_st& self, const size_t length)
+{
+ assert(self.current_size >= length);
+ size_t set_length= length;
+ if (self.current_size > length)
+ {
+ if (memcached_failed(_string_check(&self, length)))
+ {
+ set_length= self.current_size;
+ }
+ }
+ self.end= self.string +set_length;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * libmcachedd client library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include "util/string.hpp"
+
+#define memcached_literal_param util_literal_param
+#define memcached_literal_param_size util_literal_param_size
+#define memcached_string_make_from_cstr util_string_make_from_cstr
+#define memcached_array_length util_array_length
+
+/**
+ Strings are always under our control so we make some assumptions
+ about them.
+
+ 1) is_initialized is always valid.
+ 2) A string once intialized will always be, until free where we
+ unset this flag.
+ 3) A string always has a root.
+*/
+
+memcached_string_st *memcached_string_create(memcached_st *ptr,
+ memcached_string_st *string,
+ size_t initial_size);
+
+memcached_return_t memcached_string_check(memcached_string_st *string, size_t need);
+
+char *memcached_string_c_copy(memcached_string_st *string);
+
+memcached_return_t memcached_string_append_character(memcached_string_st *string,
+ char character);
+
+memcached_return_t memcached_string_append(memcached_string_st *string,
+ const char *value, size_t length);
+
+void memcached_string_reset(memcached_string_st *string);
+
+void memcached_string_free(memcached_string_st *string);
+void memcached_string_free(memcached_string_st&);
+
+size_t memcached_string_length(const memcached_string_st *self);
+size_t memcached_string_length(const memcached_string_st&);
+
+size_t memcached_string_size(const memcached_string_st *self);
+
+const char *memcached_string_value(const memcached_string_st *self);
+const char *memcached_string_value(const memcached_string_st&);
+
+char *memcached_string_take_value(memcached_string_st *self);
+
+char *memcached_string_value_mutable(const memcached_string_st *self);
+
+bool memcached_string_set(memcached_string_st&, const char*, size_t);
+
+void memcached_string_set_length(memcached_string_st *self, size_t length);
+void memcached_string_set_length(memcached_string_st&, const size_t length);
+
+bool memcached_string_resize(memcached_string_st&, const size_t);
+char *memcached_string_c_str(memcached_string_st&);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static memcached_return_t ascii_touch(memcached_instance_st* instance,
+ const char *key, size_t key_length,
+ time_t expiration)
+{
+ char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
+ int expiration_buffer_length= snprintf(expiration_buffer, sizeof(expiration_buffer), " %llu", (unsigned long long)expiration);
+ if (size_t(expiration_buffer_length) >= sizeof(expiration_buffer)+1 or expiration_buffer_length < 0)
+ {
+ return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
+ }
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { memcached_literal_param("touch ") },
+ { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
+ { key, key_length },
+ { expiration_buffer, size_t(expiration_buffer_length) },
+ { memcached_literal_param("\r\n") }
+ };
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= memcached_vdo(instance, vector, 6, true)))
+ {
+ return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
+ }
+
+ return rc;
+}
+
+static memcached_return_t binary_touch(memcached_instance_st* instance,
+ const char *key, size_t key_length,
+ time_t expiration)
+{
+ protocol_binary_request_touch request= {}; //{.bytes= {0}};
+
+ initialize_binary_request(instance, request.message.header);
+
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_TOUCH;
+ request.message.header.request.extlen= 4;
+ request.message.header.request.keylen= htons((uint16_t)(key_length +memcached_array_size(instance->root->_namespace)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t)(key_length +memcached_array_size(instance->root->_namespace) +request.message.header.request.extlen));
+ request.message.body.expiration= htonl((uint32_t) expiration);
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { request.bytes, sizeof(request.bytes) },
+ { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
+ { key, key_length }
+ };
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= memcached_vdo(instance, vector, 4, true)))
+ {
+ return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_touch(memcached_st *ptr,
+ const char *key, size_t key_length,
+ time_t expiration)
+{
+ return memcached_touch_by_key(ptr, key, key_length, key, key_length, expiration);
+}
+
+memcached_return_t memcached_touch_by_key(memcached_st *shell,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ time_t expiration)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ LIBMEMCACHED_MEMCACHED_TOUCH_START();
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(ptr, true)))
+ {
+ return rc;
+ }
+
+ if (memcached_failed(rc= memcached_key_test(*ptr, (const char **)&key, &key_length, 1)))
+ {
+ return memcached_set_error(*ptr, rc, MEMCACHED_AT);
+ }
+
+ uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+ memcached_instance_st* instance= memcached_instance_fetch(ptr, server_key);
+
+ if (ptr->flags.binary_protocol)
+ {
+ rc= binary_touch(instance, key, key_length, expiration);
+ }
+ else
+ {
+ rc= ascii_touch(instance, key, key_length, expiration);
+ }
+
+ if (memcached_failed(rc))
+ {
+ return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while writing touch command to server"));
+ }
+
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
+
+ if (rc == MEMCACHED_SUCCESS or rc == MEMCACHED_NOTFOUND)
+ {
+ return rc;
+ }
+
+ return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while reading response"));
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+/*
+ * 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
+ */
+void increment_udp_message_id(memcached_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));
+}
+
+bool memcached_io_init_udp_header(memcached_instance_st* ptr, const 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;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#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;
+};
+
+bool memcached_io_init_udp_header(memcached_instance_st*, const uint16_t thread_id);
+void increment_udp_message_id(memcached_instance_st*);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libmemcachedutil-1.0/util.h>
+
--- /dev/null
+EXTRA_DIST= libmemcachedutil.ver
+
+lib_LTLIBRARIES=
+
+if BUILD_LIBMEMCACHEDUTIL
+lib_LTLIBRARIES+= libmemcachedutil.la
+endif
+
+libmemcachedutil_la_SOURCES= memcached_pool.c
+libmemcachedutil_la_LDFLAGS= -version-info $(MEMCACHEDUTIL_LIBRARY_VERSION) $(LD_UTIL_VERSION_SCRIPT)
+libmemcachedutil_la_LIBADD= ${top_builddir}/libmemcached/libmemcached.la
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+struct context_st
+{
+ size_t length;
+ const char *buffer;
+};
+
+static memcached_return_t _set_verbosity(const Memcached *,
+ const memcached_instance_st * server,
+ void *context)
+{
+ libmemcached_io_vector_st *vector= (libmemcached_io_vector_st *)context;
+
+ Memcached local_memc;
+ Memcached *memc_ptr= memcached_create(&local_memc);
+
+ memcached_return_t rc= memcached_server_add(memc_ptr, memcached_server_name(server), memcached_server_port(server));
+
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc_ptr, 0);
+
+ rc= memcached_vdo(instance, vector, 2, true);
+
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
+ }
+ }
+
+ memcached_free(memc_ptr);
+
+ return rc;
+}
+
+memcached_return_t memcached_verbosity(memcached_st *shell, uint32_t verbosity)
+{
+ Memcached* ptr= memcached2Memcached(shell);
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(ptr, false)))
+ {
+ return rc;
+ }
+
+ memcached_server_fn callbacks[1];
+
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+ int send_length= snprintf(buffer, sizeof(buffer), "verbosity %u\r\n", verbosity);
+ if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE or send_length < 0)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
+ }
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { NULL, 0 },
+ { buffer, size_t(send_length) },
+ };
+
+ callbacks[0]= _set_verbosity;
+
+ return memcached_server_cursor(ptr, callbacks, vector, 1);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <libmemcached/common.h>
+
+const char * memcached_lib_version(void)
+{
+ return LIBMEMCACHED_VERSION_STRING;
+}
+
+static inline memcached_return_t memcached_version_textual(Memcached *memc)
+{
+ libmemcached_io_vector_st vector[]=
+ {
+ { memcached_literal_param("version\r\n") },
+ };
+
+ uint32_t success= 0;
+ bool errors_happened= false;
+ for (uint32_t x= 0; x < memcached_server_count(memc); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc, x);
+
+ // Optimization, we only fetch version once.
+ if (instance->major_version != UINT8_MAX)
+ {
+ continue;
+ }
+
+ memcached_return_t rrc;
+ if (memcached_failed(rrc= memcached_vdo(instance, vector, 1, true)))
+ {
+ errors_happened= true;
+ (void)memcached_set_error(*instance, rrc, MEMCACHED_AT);
+ continue;
+ }
+ success++;
+ }
+
+ if (success)
+ {
+ // Collect the returned items
+ memcached_instance_st* instance;
+ memcached_return_t readable_error;
+ while ((instance= memcached_io_get_readable_server(memc, readable_error)))
+ {
+ memcached_return_t rrc= memcached_response(instance, NULL);
+ if (memcached_failed(rrc))
+ {
+ errors_happened= true;
+ }
+ }
+ }
+
+ return errors_happened ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
+}
+
+static inline memcached_return_t memcached_version_binary(Memcached *memc)
+{
+ protocol_binary_request_version request= {};
+
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { request.bytes, sizeof(request.bytes) }
+ };
+
+ uint32_t success= 0;
+ bool errors_happened= false;
+ for (uint32_t x= 0; x < memcached_server_count(memc); x++)
+ {
+ memcached_instance_st* instance= memcached_instance_fetch(memc, x);
+
+ initialize_binary_request(instance, request.message.header);
+
+ if (instance->major_version != UINT8_MAX)
+ {
+ continue;
+ }
+
+ memcached_return_t rrc= memcached_vdo(instance, vector, 1, true);
+ if (memcached_failed(rrc))
+ {
+ errors_happened= true;
+ continue;
+ }
+
+ success++;
+ }
+
+ if (success)
+ {
+ // Collect the returned items
+ memcached_instance_st* instance;
+ memcached_return_t readable_error;
+ while ((instance= memcached_io_get_readable_server(memc, readable_error)))
+ {
+ char buffer[32];
+ memcached_return_t rrc= memcached_response(instance, buffer, sizeof(buffer), NULL);
+ if (memcached_failed(rrc))
+ {
+ errors_happened= true;
+ }
+ }
+ }
+
+ return errors_happened ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
+}
+
+static inline void version_ascii_instance(memcached_instance_st* instance)
+{
+ if (instance->major_version != UINT8_MAX)
+ {
+ libmemcached_io_vector_st vector[]=
+ {
+ { memcached_literal_param("version\r\n") },
+ };
+
+ (void)memcached_vdo(instance, vector, 1, false);
+ }
+}
+
+static inline void version_binary_instance(memcached_instance_st* instance)
+{
+ if (instance->major_version != UINT8_MAX)
+ {
+ protocol_binary_request_version request= {};
+
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+ libmemcached_io_vector_st vector[]=
+ {
+ { request.bytes, sizeof(request.bytes) }
+ };
+
+ initialize_binary_request(instance, request.message.header);
+
+ (void)memcached_vdo(instance, vector, 1, false);
+ }
+}
+
+void memcached_version_instance(memcached_instance_st* instance)
+{
+ if (instance)
+ {
+ if (memcached_has_root(instance))
+ {
+ if (memcached_is_fetching_version(instance->root))
+ {
+ if (memcached_is_udp(instance->root) == false)
+ {
+
+ if (memcached_is_binary(instance->root))
+ {
+ version_binary_instance(instance);
+ return;
+ }
+
+ version_ascii_instance(instance);
+ }
+ }
+ }
+ }
+}
+
+int8_t memcached_version_instance_cmp(memcached_instance_st *instance,
+ uint8_t maj, uint8_t min, uint8_t mic)
+{
+ if (!instance || memcached_server_major_version(instance) == UINT8_MAX) {
+ return INT8_MIN;
+ } else {
+ uint32_t sv, cv;
+
+ sv = memcached_server_micro_version(instance)
+ |memcached_server_minor_version(instance) << 8
+ |memcached_server_major_version(instance) << 16
+ ;
+ cv = mic
+ |min << 8
+ |maj << 16
+ ;
+ if (sv < cv) {
+ return -1;
+ }
+ return sv != cv;
+ }
+}
+
+memcached_return_t memcached_version(memcached_st *shell)
+{
+ Memcached* memc= memcached2Memcached(shell);
+ if (memc)
+ {
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(memc, true)))
+ {
+ return rc;
+ }
+
+ if (memcached_is_udp(memc))
+ {
+ return MEMCACHED_NOT_SUPPORTED;
+ }
+
+ if (memcached_is_binary(memc))
+ {
+ return memcached_version_binary(memc);
+ }
+
+ return memcached_version_textual(memc);
+ }
+
+ return MEMCACHED_INVALID_ARGUMENTS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/ All
+ * rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ Common include file for libmemached
+*/
+
+#pragma once
+
+void memcached_version_instance(memcached_instance_st*);
+int8_t memcached_version_instance_cmp(memcached_instance_st*,
+ uint8_t maj, uint8_t min, uint8_t mic);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+struct bucket_t {
+ uint32_t master;
+ uint32_t forward;
+};
+
+struct memcached_virtual_bucket_t {
+ bool has_forward;
+ uint32_t size;
+ uint32_t replicas;
+ struct bucket_t buckets[];
+};
+
+memcached_return_t memcached_virtual_bucket_create(memcached_st *self,
+ const uint32_t *host_map,
+ const uint32_t *forward_map,
+ const uint32_t buckets,
+ const uint32_t replicas)
+{
+ if (self == NULL || host_map == NULL || buckets == 0U)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ memcached_virtual_bucket_free(self);
+
+ struct memcached_virtual_bucket_t *virtual_bucket= (struct memcached_virtual_bucket_t *)malloc(sizeof(struct memcached_virtual_bucket_t) + sizeof(struct bucket_t) *buckets);
+
+ if (virtual_bucket == NULL)
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+
+ virtual_bucket->size= buckets;
+ virtual_bucket->replicas= replicas;
+ self->virtual_bucket= virtual_bucket;
+
+ uint32_t x= 0;
+ for (; x < buckets; x++)
+ {
+ virtual_bucket->buckets[x].master= host_map[x];
+ if (forward_map)
+ {
+ virtual_bucket->buckets[x].forward= forward_map[x];
+ }
+ else
+ {
+ virtual_bucket->buckets[x].forward= 0;
+ }
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+void memcached_virtual_bucket_free(memcached_st *self)
+{
+ if (self)
+ {
+ if (self->virtual_bucket)
+ {
+ free(self->virtual_bucket);
+ self->virtual_bucket= NULL;
+ }
+ }
+}
+
+uint32_t memcached_virtual_bucket_get(const memcached_st *self, uint32_t digest)
+{
+ if (self)
+ {
+ if (self->virtual_bucket)
+ {
+ uint32_t result= (uint32_t) (digest & (self->virtual_bucket->size -1));
+ return self->virtual_bucket->buckets[result].master;
+ }
+
+ return (uint32_t) (digest & (self->number_of_hosts -1));
+ }
+
+ return 0;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+memcached_return_t memcached_virtual_bucket_create(memcached_st *self,
+ const uint32_t *host_map,
+ const uint32_t *forward_map,
+ const uint32_t buckets,
+ const uint32_t replicas);
+
+uint32_t memcached_virtual_bucket_get(const memcached_st *self, uint32_t digest);
+
+void memcached_virtual_bucket_free(memcached_st *self);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#define WATCHPOINT
+#define WATCHPOINT_ERROR(A)
+#define WATCHPOINT_IFERROR(__memcached_return_t) (void)(__memcached_return_t)
+#define WATCHPOINT_STRING(A)
+#define WATCHPOINT_NUMBER(A)
+#define WATCHPOINT_LABELED_NUMBER(A,B)
+#define WATCHPOINT_IF_LABELED_NUMBER(A,B,C)
+#define WATCHPOINT_ERRNO(A)
+#define WATCHPOINT_ASSERT_PRINT(A,B,C)
+#define WATCHPOINT_ASSERT(A) (void)(A)
+#define WATCHPOINT_ASSERT_INITIALIZED(A)
+#define WATCHPOINT_SET(A)
--- /dev/null
+/*
+ * Libmemcached library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+# include <cerrno>
+#else
+# include <errno.h>
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0501
+#endif
+
+#ifdef __MINGW32__
+# if(_WIN32_WINNT >= 0x0501)
+# else
+# undef _WIN32_WINNT
+# define _WIN32_WINNT 0x0501
+# endif /* _WIN32_WINNT >= 0x0501 */
+#endif /* __MINGW32__ */
+
+#if defined(HAVE_WINSOCK2_H) && HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+
+#if defined(HAVE_WS2TCPIP_H) && HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+#endif
+
+#if defined(HAVE_IO_H) && HAVE_IO_H
+# include <io.h>
+#endif
+
+struct sockaddr_un
+{
+ short int sun_family;
+ char sun_path[108];
+};
+
+static inline int translate_windows_error()
+{
+ int local_errno= WSAGetLastError();
+
+ switch(local_errno) {
+ case WSAEINVAL:
+ local_errno= EINPROGRESS;
+ break;
+ case WSAEALREADY:
+ case WSAEWOULDBLOCK:
+ local_errno= EAGAIN;
+ break;
+
+ case WSAECONNREFUSED:
+ local_errno= ECONNREFUSED;
+ break;
+
+ case WSAENETUNREACH:
+ local_errno= ENETUNREACH;
+ break;
+
+ case WSAETIMEDOUT:
+ local_errno= ETIMEDOUT;
+ break;
+
+ case WSAECONNRESET:
+ local_errno= ECONNRESET;
+ break;
+
+ case WSAEADDRINUSE:
+ local_errno= EADDRINUSE;
+ break;
+
+ case WSAEOPNOTSUPP:
+ local_errno= EOPNOTSUPP;
+ break;
+
+ case WSAENOPROTOOPT:
+ local_errno= ENOPROTOOPT;
+ break;
+
+ default:
+ break;
+ }
+
+ return local_errno;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcachedprotocol/common.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+
+static void print_ascii_command(memcached_protocol_client_st *client)
+{
+ if (client->is_verbose)
+ {
+ switch (client->ascii_command)
+ {
+ case SET_CMD:
+ fprintf(stderr, "%s:%d SET_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case ADD_CMD:
+ fprintf(stderr, "%s:%d ADD_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case REPLACE_CMD:
+ fprintf(stderr, "%s:%d REPLACE_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case CAS_CMD:
+ fprintf(stderr, "%s:%d CAS_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case APPEND_CMD:
+ fprintf(stderr, "%s:%d APPEND_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case PREPEND_CMD:
+ fprintf(stderr, "%s:%d PREPEND_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case DELETE_CMD:
+ fprintf(stderr, "%s:%d DELETE_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case INCR_CMD: /* FALLTHROUGH */
+ fprintf(stderr, "%s:%d INCR_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case DECR_CMD:
+ fprintf(stderr, "%s:%d DECR_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case STATS_CMD:
+ fprintf(stderr, "%s:%d STATS_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case FLUSH_ALL_CMD:
+ fprintf(stderr, "%s:%d FLUSH_ALL_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case VERSION_CMD:
+ fprintf(stderr, "%s:%d VERSION_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case QUIT_CMD:
+ fprintf(stderr, "%s:%d QUIT_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case VERBOSITY_CMD:
+ fprintf(stderr, "%s:%d VERBOSITY_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case GET_CMD:
+ fprintf(stderr, "%s:%d GET_CMD\n", __FILE__, __LINE__);
+ break;
+
+ case GETS_CMD:
+ fprintf(stderr, "%s:%d GETS_CMD\n", __FILE__, __LINE__);
+ break;
+
+ default:
+ case UNKNOWN_CMD:
+ fprintf(stderr, "%s:%d UNKNOWN_CMD\n", __FILE__, __LINE__);
+ break;
+
+ }
+ }
+}
+
+/**
+ * Try to parse a key from the string.
+ * @pointer start pointer to a pointer to the string (IN and OUT)
+ * @return length of the string of -1 if this was an illegal key (invalid
+ * characters or invalid length)
+ * @todo add length!
+ */
+static uint16_t parse_ascii_key(char **start)
+{
+ uint16_t len= 0;
+ char *c= *start;
+ /* Strip leading whitespaces */
+ while (isspace(*c))
+ {
+ ++c;
+ }
+
+ *start= c;
+
+ while (*c != '\0' && !isspace(*c) && !iscntrl(*c))
+ {
+ ++c;
+ ++len;
+ }
+
+
+ if (len == 0 || len > 240 || (*c != '\0' && *c != '\r' && iscntrl(*c)))
+ {
+ return 0;
+ }
+
+ return len;
+}
+
+/**
+ * Spool a zero-terminated string
+ * @param client destination
+ * @param text the text to spool
+ * @return status of the spool operation
+ */
+static protocol_binary_response_status raw_response_handler(memcached_protocol_client_st *client, const char *text)
+{
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, text);
+ }
+
+ if (client->root->drain(client) == false)
+ {
+ return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
+ }
+
+ assert(client->output != NULL);
+#if 0
+ if (client->output == NULL)
+ {
+ /* I can write directly to the socket.... */
+ do
+ {
+ size_t num_bytes= len -offset;
+ ssize_t nw= client->root->send(client,
+ client->sock,
+ ptr + offset,
+ num_bytes);
+ if (nw == -1)
+ {
+ if (get_socket_errno() == EWOULDBLOCK)
+ {
+ break;
+ }
+ else if (get_socket_errno() != EINTR)
+ {
+ client->error= errno;
+ return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
+ }
+ }
+ else
+ {
+ offset += (size_t)nw;
+ }
+ } while (offset < len);
+ }
+#endif
+
+ return client->root->spool(client, text, strlen(text));
+}
+
+/**
+ * Send a "CLIENT_ERROR" message back to the client with the correct
+ * format of the command being sent
+ * @param client the client to send the message to
+ */
+static void send_command_usage(memcached_protocol_client_st *client)
+{
+ const char *errmsg[]= {
+ [GET_CMD]= "CLIENT_ERROR: Syntax error: get <key>*\r\n",
+ [GETS_CMD]= "CLIENT_ERROR: Syntax error: gets <key>*\r\n",
+ [SET_CMD]= "CLIENT_ERROR: Syntax error: set <key> <flags> <exptime> <bytes> [noreply]\r\n",
+ [ADD_CMD]= "CLIENT_ERROR: Syntax error: add <key> <flags> <exptime> <bytes> [noreply]\r\n",
+ [REPLACE_CMD]= "CLIENT_ERROR: Syntax error: replace <key> <flags> <exptime> <bytes> [noreply]\r\n",
+ [CAS_CMD]= "CLIENT_ERROR: Syntax error: cas <key> <flags> <exptime> <bytes> <casid> [noreply]\r\n",
+ [APPEND_CMD]= "CLIENT_ERROR: Syntax error: append <key> <flags> <exptime> <bytes> [noreply]\r\n",
+ [PREPEND_CMD]= "CLIENT_ERROR: Syntax error: prepend <key> <flags> <exptime> <bytes> [noreply]\r\n",
+ [DELETE_CMD]= "CLIENT_ERROR: Syntax error: delete_object <key> [noreply]\r\n",
+ [INCR_CMD]= "CLIENT_ERROR: Syntax error: incr <key> <value> [noreply]\r\n",
+ [DECR_CMD]= "CLIENT_ERROR: Syntax error: decr <key> <value> [noreply]\r\n",
+ [STATS_CMD]= "CLIENT_ERROR: Syntax error: stats [key]\r\n",
+ [FLUSH_ALL_CMD]= "CLIENT_ERROR: Syntax error: flush_all [timeout] [noreply]\r\n",
+ [VERSION_CMD]= "CLIENT_ERROR: Syntax error: version\r\n",
+ [QUIT_CMD]="CLIENT_ERROR: Syntax error: quit\r\n",
+
+ [VERBOSITY_CMD]= "CLIENT_ERROR: Syntax error: verbosity <num>\r\n",
+ [UNKNOWN_CMD]= "CLIENT_ERROR: Unknown command\r\n",
+ };
+
+ client->mute = false;
+ raw_response_handler(client, errmsg[client->ascii_command]);
+}
+
+/**
+ * Callback for the VERSION responses
+ * @param cookie client identifier
+ * @param text the length of the body
+ * @param textlen the length of the body
+ */
+static protocol_binary_response_status ascii_version_response_handler(const void *cookie,
+ const void *text,
+ uint32_t textlen)
+{
+ memcached_protocol_client_st *client= (memcached_protocol_client_st*)cookie;
+ raw_response_handler(client, "VERSION ");
+ client->root->spool(client, text, textlen);
+ raw_response_handler(client, "\r\n");
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+/**
+ * Callback for the GET/GETQ/GETK and GETKQ responses
+ * @param cookie client identifier
+ * @param key the key for the item
+ * @param keylen the length of the key
+ * @param body the length of the body
+ * @param bodylen the length of the body
+ * @param flags the flags for the item
+ * @param cas the CAS id for the item
+ */
+static protocol_binary_response_status
+ascii_get_response_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void *body,
+ uint32_t bodylen,
+ uint32_t flags,
+ uint64_t cas)
+{
+ memcached_protocol_client_st *client= (void*)cookie;
+ char buffer[300];
+ strcpy(buffer, "VALUE ");
+ const char *source= key;
+ char *dest= buffer + 6;
+
+ for (int x= 0; x < keylen; ++x)
+ {
+ if (*source != '\0' && !isspace(*source) && !iscntrl(*source))
+ {
+ *dest= *source;
+ }
+ else
+ {
+ return PROTOCOL_BINARY_RESPONSE_EINVAL; /* key constraints in ascii */
+ }
+
+ ++dest;
+ ++source;
+ }
+
+ size_t used= (size_t)(dest - buffer);
+
+ if (client->ascii_command == GETS_CMD)
+ {
+ snprintf(dest, sizeof(buffer) - used, " %u %u %" PRIu64 "\r\n", flags,
+ bodylen, cas);
+ }
+ else
+ {
+ snprintf(dest, sizeof(buffer) - used, " %u %u\r\n", flags, bodylen);
+ }
+
+ client->root->spool(client, buffer, strlen(buffer));
+ client->root->spool(client, body, bodylen);
+ client->root->spool(client, "\r\n", 2);
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+/**
+ * Callback for the STAT responses
+ * @param cookie client identifier
+ * @param key the key for the item
+ * @param keylen the length of the key
+ * @param body the length of the body
+ * @param bodylen the length of the body
+ */
+static protocol_binary_response_status ascii_stat_response_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void *body,
+ uint32_t bodylen)
+{
+
+ memcached_protocol_client_st *client= (void*)cookie;
+
+ if (key != NULL)
+ {
+ raw_response_handler(client, "STAT ");
+ client->root->spool(client, key, keylen);
+ raw_response_handler(client, " ");
+ client->root->spool(client, body, bodylen);
+ raw_response_handler(client, "\r\n");
+ }
+ else
+ {
+ raw_response_handler(client, "END\r\n");
+ }
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+/**
+ * Process a get or a gets request.
+ * @param client the client handle
+ * @param buffer the complete get(s) command
+ * @param end the last character in the command
+ */
+static void ascii_process_gets(memcached_protocol_client_st *client,
+ char *buffer, char *end)
+{
+ char *key= buffer;
+
+ /* Skip command */
+ key += (client->ascii_command == GETS_CMD) ? 5 : 4;
+
+ int num_keys= 0;
+ while (key < end)
+ {
+ uint16_t nkey= parse_ascii_key(&key);
+ if (nkey == 0) /* Invalid key... stop processing this line */
+ {
+ break;
+ }
+
+ (void)client->root->callback->interface.v1.get(client, key, nkey,
+ ascii_get_response_handler);
+ key += nkey;
+ ++num_keys;
+ }
+
+ if (num_keys == 0)
+ {
+ send_command_usage(client);
+ }
+ else
+ {
+ client->root->spool(client, "END\r\n", 5);
+ }
+}
+
+/**
+ * Try to split up the command line "asdf asdf asdf asdf\n" into an
+ * argument vector for easier parsing.
+ * @param start the first character in the command line
+ * @param end the last character in the command line ("\n")
+ * @param vec the vector to insert the pointers into
+ * @size the number of elements in the vector
+ * @return the number of tokens in the vector
+ */
+static int ascii_tokenize_command(char *str, char *end, char **vec, int size)
+{
+ int elem= 0;
+
+ while (str < end)
+ {
+ /* Skip leading blanks */
+ while (str < end && isspace(*str))
+ {
+ ++str;
+ }
+
+ if (str == end)
+ {
+ return elem;
+ }
+
+ vec[elem++]= str;
+ /* find the next non-blank field */
+ while (str < end && !isspace(*str))
+ {
+ ++str;
+ }
+
+ /* zero-terminate it for easier parsing later on */
+ *str= '\0';
+ ++str;
+
+ /* Is the vector full? */
+ if (elem == size)
+ {
+ break;
+ }
+ }
+
+ return elem;
+}
+
+/**
+ * If we for some reasons needs to push the line back to read more
+ * data we have to reverse the tokenization. Just do the brain-dead replace
+ * of all '\0' to ' ' and set the last character to '\n'. We could have used
+ * the vector we created, but then we would have to search for all of the
+ * spaces we ignored...
+ * @param start pointer to the first character in the buffer to recover
+ * @param end pointer to the last character in the buffer to recover
+ */
+static void recover_tokenize_command(char *start, char *end)
+{
+ while (start < end)
+ {
+ if (*start == '\0')
+ *start= ' ';
+ ++start;
+ }
+
+ *end= '\n';
+}
+
+/**
+ * Convert the textual command into a comcode
+ */
+static enum ascii_cmd ascii_to_cmd(char *start, size_t length)
+{
+ struct {
+ const char *cmd;
+ size_t len;
+ enum ascii_cmd cc;
+ } commands[]= {
+ { .cmd= "get", .len= 3, .cc= GET_CMD },
+ { .cmd= "gets", .len= 4, .cc= GETS_CMD },
+ { .cmd= "set", .len= 3, .cc= SET_CMD },
+ { .cmd= "add", .len= 3, .cc= ADD_CMD },
+ { .cmd= "replace", .len= 7, .cc= REPLACE_CMD },
+ { .cmd= "cas", .len= 3, .cc= CAS_CMD },
+ { .cmd= "append", .len= 6, .cc= APPEND_CMD },
+ { .cmd= "prepend", .len= 7, .cc= PREPEND_CMD },
+ { .cmd= "delete_object", .len= 6, .cc= DELETE_CMD },
+ { .cmd= "incr", .len= 4, .cc= INCR_CMD },
+ { .cmd= "decr", .len= 4, .cc= DECR_CMD },
+ { .cmd= "stats", .len= 5, .cc= STATS_CMD },
+ { .cmd= "flush_all", .len= 9, .cc= FLUSH_ALL_CMD },
+ { .cmd= "version", .len= 7, .cc= VERSION_CMD },
+ { .cmd= "quit", .len= 4, .cc= QUIT_CMD },
+ { .cmd= "verbosity", .len= 9, .cc= VERBOSITY_CMD },
+ { .cmd= NULL, .len= 0, .cc= UNKNOWN_CMD }};
+
+ int x= 0;
+ while (commands[x].len > 0) {
+ if (length >= commands[x].len)
+ {
+ if (strncmp(start, commands[x].cmd, commands[x].len) == 0)
+ {
+ /* Potential hit */
+ if (length == commands[x].len || isspace(*(start + commands[x].len)))
+ {
+ return commands[x].cc;
+ }
+ }
+ }
+ ++x;
+ }
+
+ return UNKNOWN_CMD;
+}
+
+/**
+ * Perform a delete_object operation.
+ *
+ * @param client client requesting the deletion
+ * @param tokens the command as a vector
+ * @param ntokens the number of items in the vector
+ */
+static void process_delete(memcached_protocol_client_st *client,
+ char **tokens, int ntokens)
+{
+ char *key= tokens[1];
+ uint16_t nkey;
+
+ if (ntokens != 2 || (nkey= parse_ascii_key(&key)) == 0)
+ {
+ send_command_usage(client);
+ return;
+ }
+
+ if (client->root->callback->interface.v1.delete_object == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return;
+ }
+
+ protocol_binary_response_status rval= client->root->callback->interface.v1.delete_object(client, key, nkey, 0);
+
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
+ {
+ raw_response_handler(client, "DELETED\r\n");
+ }
+ else if (rval == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)
+ {
+ raw_response_handler(client, "NOT_FOUND\r\n");
+ }
+ else
+ {
+ char msg[80];
+ snprintf(msg, sizeof(msg), "SERVER_ERROR: delete_object failed %u\r\n",(uint32_t)rval);
+ raw_response_handler(client, msg);
+ }
+}
+
+static void process_arithmetic(memcached_protocol_client_st *client,
+ char **tokens, int ntokens)
+{
+ char *key= tokens[1];
+ uint16_t nkey;
+
+ if (ntokens != 3 || (nkey= parse_ascii_key(&key)) == 0)
+ {
+ send_command_usage(client);
+ return;
+ }
+
+ uint64_t cas;
+ uint64_t result;
+ errno= 0;
+ uint64_t delta= strtoull(tokens[2], NULL, 10);
+ if (errno != 0)
+ {
+ return; // Error
+ }
+
+ protocol_binary_response_status rval;
+ if (client->ascii_command == INCR_CMD)
+ {
+ if (client->root->callback->interface.v1.increment == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return;
+ }
+ rval= client->root->callback->interface.v1.increment(client,
+ key, nkey,
+ delta, 0,
+ 0,
+ &result,
+ &cas);
+ }
+ else
+ {
+ if (client->root->callback->interface.v1.decrement == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return;
+ }
+ rval= client->root->callback->interface.v1.decrement(client,
+ key, nkey,
+ delta, 0,
+ 0,
+ &result,
+ &cas);
+ }
+
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
+ {
+ char buffer[80];
+ snprintf(buffer, sizeof(buffer), "%"PRIu64"\r\n", result);
+ raw_response_handler(client, buffer);
+ }
+ else
+ {
+ raw_response_handler(client, "NOT_FOUND\r\n");
+ }
+}
+
+/**
+ * Process the stats command (with or without a key specified)
+ * @param key pointer to the first character after "stats"
+ * @param end pointer to the "\n"
+ */
+static void process_stats(memcached_protocol_client_st *client,
+ char *key, char *end)
+{
+ if (client->root->callback->interface.v1.stat == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return;
+ }
+
+ while (isspace(*key))
+ {
+ key++;
+ }
+
+ uint16_t nkey= (uint16_t)(end - key);
+ (void)client->root->callback->interface.v1.stat(client, key, nkey,
+ ascii_stat_response_handler);
+}
+
+static void process_version(memcached_protocol_client_st *client,
+ char **tokens, int ntokens)
+{
+ (void)tokens;
+ if (ntokens != 1)
+ {
+ send_command_usage(client);
+ return;
+ }
+
+ if (client->root->callback->interface.v1.version == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return;
+ }
+
+ client->root->callback->interface.v1.version(client,
+ ascii_version_response_handler);
+}
+
+static void process_flush(memcached_protocol_client_st *client,
+ char **tokens, int ntokens)
+{
+ if (ntokens > 2)
+ {
+ send_command_usage(client);
+ return;
+ }
+
+ if (client->root->callback->interface.v1.flush_object == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return;
+ }
+
+ uint32_t timeout= 0;
+ if (ntokens == 2)
+ {
+ errno= 0;
+ timeout= (uint32_t)strtoul(tokens[1], NULL, 10);
+ if (errno != 0)
+ {
+ return; // Error
+ }
+ }
+
+ protocol_binary_response_status rval;
+ rval= client->root->callback->interface.v1.flush_object(client, timeout);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
+ raw_response_handler(client, "OK\r\n");
+ else
+ raw_response_handler(client, "SERVER_ERROR: internal error\r\n");
+}
+
+/**
+ * Process one of the storage commands
+ * @param client the client performing the operation
+ * @param tokens the command tokens
+ * @param ntokens the number of tokens
+ * @param start pointer to the first character in the line
+ * @param end pointer to the pointer where the last character of this
+ * command is (IN and OUT)
+ * @param length the number of bytes available
+ * @return -1 if an error occurs (and we should just terminate the connection
+ * because we are out of sync)
+ * 0 storage command completed, continue processing
+ * 1 We need more data, so just go ahead and wait for more!
+ */
+static inline int process_storage_command(memcached_protocol_client_st *client,
+ char **tokens, int ntokens, char *start,
+ char **end, ssize_t length)
+{
+ (void)ntokens; /* already checked */
+ char *key= tokens[1];
+ uint16_t nkey= parse_ascii_key(&key);
+ if (nkey == 0)
+ {
+ /* return error */
+ raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
+ return -1;
+ }
+
+ errno= 0;
+ uint32_t flags= (uint32_t)strtoul(tokens[2], NULL, 10);
+ if (errno != 0)
+ {
+ /* return error */
+ raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
+ return -1;
+ }
+
+ uint32_t timeout= (uint32_t)strtoul(tokens[3], NULL, 10);
+ if (errno != 0)
+ {
+ /* return error */
+ raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
+ return -1;
+ }
+
+ unsigned long nbytes= strtoul(tokens[4], NULL, 10);
+ if (errno != 0)
+ {
+ /* return error */
+ raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
+ return -1;
+ }
+
+ /* Do we have all data? */
+ unsigned long need= nbytes + (unsigned long)((*end - start) + 1) + 2; /* \n\r\n */
+ if ((ssize_t)need > length)
+ {
+ /* Keep on reading */
+ recover_tokenize_command(start, *end);
+ return 1;
+ }
+
+ void *data= (*end) + 1;
+ uint64_t cas= 0;
+ uint64_t result_cas;
+ protocol_binary_response_status rval;
+ switch (client->ascii_command)
+ {
+ case SET_CMD:
+ rval= client->root->callback->interface.v1.set(client, key,
+ (uint16_t)nkey,
+ data,
+ (uint32_t)nbytes,
+ flags,
+ timeout, cas,
+ &result_cas);
+ break;
+ case ADD_CMD:
+ rval= client->root->callback->interface.v1.add(client, key,
+ (uint16_t)nkey,
+ data,
+ (uint32_t)nbytes,
+ flags,
+ timeout, &result_cas);
+ break;
+ case CAS_CMD:
+ errno= 0;
+ cas= strtoull(tokens[5], NULL, 10);
+ if (errno != 0)
+ {
+ /* return error */
+ raw_response_handler(client, "CLIENT_ERROR: bad key\r\n");
+ return -1;
+ }
+ /* FALLTHROUGH */
+ case REPLACE_CMD:
+ rval= client->root->callback->interface.v1.replace(client, key,
+ (uint16_t)nkey,
+ data,
+ (uint32_t)nbytes,
+ flags,
+ timeout, cas,
+ &result_cas);
+ break;
+ case APPEND_CMD:
+ rval= client->root->callback->interface.v1.append(client, key,
+ (uint16_t)nkey,
+ data,
+ (uint32_t)nbytes,
+ cas,
+ &result_cas);
+ break;
+ case PREPEND_CMD:
+ rval= client->root->callback->interface.v1.prepend(client, key,
+ (uint16_t)nkey,
+ data,
+ (uint32_t)nbytes,
+ cas,
+ &result_cas);
+ break;
+
+ /* gcc complains if I don't put all of the enums in here.. */
+ case GET_CMD:
+ case GETS_CMD:
+ case DELETE_CMD:
+ case DECR_CMD:
+ case INCR_CMD:
+ case STATS_CMD:
+ case FLUSH_ALL_CMD:
+ case VERSION_CMD:
+ case QUIT_CMD:
+ case VERBOSITY_CMD:
+ case UNKNOWN_CMD:
+ default:
+ abort(); /* impossible */
+ }
+
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS)
+ {
+ raw_response_handler(client, "STORED\r\n");
+ }
+ else
+ {
+ if (client->ascii_command == CAS_CMD)
+ {
+ if (rval == PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS)
+ {
+ raw_response_handler(client, "EXISTS\r\n");
+ }
+ else if (rval == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)
+ {
+ raw_response_handler(client, "NOT_FOUND\r\n");
+ }
+ else
+ {
+ raw_response_handler(client, "NOT_STORED\r\n");
+ }
+ }
+ else
+ {
+ raw_response_handler(client, "NOT_STORED\r\n");
+ }
+ }
+
+ *end += nbytes + 2;
+
+ return 0;
+}
+
+static int process_cas_command(memcached_protocol_client_st *client,
+ char **tokens, int ntokens, char *start,
+ char **end, ssize_t length)
+{
+ if (ntokens != 6)
+ {
+ send_command_usage(client);
+ return false;
+ }
+
+ if (client->root->callback->interface.v1.replace == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return false;
+ }
+
+ return process_storage_command(client, tokens, ntokens, start, end, length);
+}
+
+static int process_set_command(memcached_protocol_client_st *client,
+ char **tokens, int ntokens, char *start,
+ char **end, ssize_t length)
+{
+ if (ntokens != 5)
+ {
+ send_command_usage(client);
+ return false;
+ }
+
+ if (client->root->callback->interface.v1.set == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return false;
+ }
+
+ return process_storage_command(client, tokens, ntokens, start, end, length);
+}
+
+static int process_add_command(memcached_protocol_client_st *client,
+ char **tokens, int ntokens, char *start,
+ char **end, ssize_t length)
+{
+ if (ntokens != 5)
+ {
+ send_command_usage(client);
+ return false;
+ }
+
+ if (client->root->callback->interface.v1.add == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return false;
+ }
+
+ return process_storage_command(client, tokens, ntokens, start, end, length);
+}
+
+static int process_replace_command(memcached_protocol_client_st *client,
+ char **tokens, int ntokens, char *start,
+ char **end, ssize_t length)
+{
+ if (ntokens != 5)
+ {
+ send_command_usage(client);
+ return false;
+ }
+
+ if (client->root->callback->interface.v1.replace == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return false;
+ }
+
+ return process_storage_command(client, tokens, ntokens, start, end, length);
+}
+
+static int process_append_command(memcached_protocol_client_st *client,
+ char **tokens, int ntokens, char *start,
+ char **end, ssize_t length)
+{
+ if (ntokens != 5)
+ {
+ send_command_usage(client);
+ return false;
+ }
+
+ if (client->root->callback->interface.v1.append == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return false;
+ }
+
+ return process_storage_command(client, tokens, ntokens, start, end, length);
+}
+
+static int process_prepend_command(memcached_protocol_client_st *client,
+ char **tokens, int ntokens, char *start,
+ char **end, ssize_t length)
+{
+ if (ntokens != 5)
+ {
+ send_command_usage(client);
+ return false;
+ }
+
+ if (client->root->callback->interface.v1.prepend == NULL)
+ {
+ raw_response_handler(client, "SERVER_ERROR: callback not implemented\r\n");
+ return false;
+ }
+
+ return process_storage_command(client, tokens, ntokens, start, end, length);
+}
+
+/**
+ * The ASCII protocol support is just one giant big hack. Instead of adding
+ * a optimal ascii support, I just convert the ASCII commands to the binary
+ * protocol and calls back into the command handlers for the binary protocol ;)
+ */
+memcached_protocol_event_t memcached_ascii_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr)
+{
+ char *ptr= (char*)client->root->input_buffer;
+ *endptr= ptr;
+
+ do {
+ /* Do we have \n (indicating the command preamble)*/
+ char *end= memchr(ptr, '\n', (size_t)*length);
+ if (end == NULL)
+ {
+ *endptr= ptr;
+ return MEMCACHED_PROTOCOL_READ_EVENT;
+ }
+
+ client->ascii_command= ascii_to_cmd(ptr, (size_t)(*length));
+
+ /* we got all data available, execute the callback! */
+ if (client->root->callback->pre_execute != NULL)
+ {
+ client->root->callback->pre_execute(client, NULL);
+ }
+
+
+ /* A multiget lists all of the keys, and I don't want to have an
+ * avector of let's say 512 pointers to tokenize all of them, so let's
+ * just handle them immediately
+ */
+ if (client->ascii_command == GET_CMD ||
+ client->ascii_command == GETS_CMD)
+ {
+ if (client->root->callback->interface.v1.get != NULL)
+ {
+ ascii_process_gets(client, ptr, end);
+ }
+ else
+ {
+ raw_response_handler(client, "SERVER_ERROR: Command not implemented\n");
+ }
+ }
+ else
+ {
+ /* None of the defined commands takes 10 parameters, so lets just use
+ * that as a maximum limit.
+ */
+ char *tokens[10];
+ int ntokens= ascii_tokenize_command(ptr, end, tokens, 10);
+
+ if (ntokens < 10)
+ {
+ client->mute= strcmp(tokens[ntokens - 1], "noreply") == 0;
+ if (client->mute)
+ {
+ --ntokens; /* processed noreply token*/
+ }
+ }
+
+ int error= 0;
+
+ print_ascii_command(client);
+ switch (client->ascii_command)
+ {
+ case SET_CMD:
+ error= process_set_command(client, tokens, ntokens, ptr, &end, *length);
+ break;
+
+ case ADD_CMD:
+ error= process_add_command(client, tokens, ntokens, ptr, &end, *length);
+ break;
+
+ case REPLACE_CMD:
+ error= process_replace_command(client, tokens, ntokens, ptr, &end, *length);
+ break;
+
+ case CAS_CMD:
+ error= process_cas_command(client, tokens, ntokens, ptr, &end, *length);
+ break;
+
+ case APPEND_CMD:
+ error= process_append_command(client, tokens, ntokens, ptr, &end, *length);
+ break;
+
+ case PREPEND_CMD:
+ error= process_prepend_command(client, tokens, ntokens, ptr, &end, *length);
+ break;
+
+ case DELETE_CMD:
+ process_delete(client, tokens, ntokens);
+ break;
+
+ case INCR_CMD: /* FALLTHROUGH */
+ case DECR_CMD:
+ process_arithmetic(client, tokens, ntokens);
+ break;
+
+ case STATS_CMD:
+ if (client->mute)
+ {
+ send_command_usage(client);
+ }
+ else
+ {
+ recover_tokenize_command(ptr, end);
+ process_stats(client, ptr + 6, end);
+ }
+ break;
+
+ case FLUSH_ALL_CMD:
+ process_flush(client, tokens, ntokens);
+ break;
+
+ case VERSION_CMD:
+ if (client->mute)
+ {
+ send_command_usage(client);
+ }
+ else
+ {
+ process_version(client, tokens, ntokens);
+ }
+ break;
+
+ case QUIT_CMD:
+ if (ntokens != 1 || client->mute)
+ {
+ send_command_usage(client);
+ }
+ else
+ {
+ if (client->root->callback->interface.v1.quit != NULL)
+ {
+ client->root->callback->interface.v1.quit(client);
+ }
+
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
+ break;
+
+ case VERBOSITY_CMD:
+ if (ntokens != 2)
+ {
+ send_command_usage(client);
+ }
+ else
+ {
+ raw_response_handler(client, "OK\r\n");
+ }
+ break;
+
+ case UNKNOWN_CMD:
+ send_command_usage(client);
+ break;
+
+ case GET_CMD:
+ case GETS_CMD:
+ default:
+ /* Should already be handled */
+ abort();
+ }
+
+ if (error == -1)
+ {
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
+ else if (error == 1)
+ {
+ return MEMCACHED_PROTOCOL_READ_EVENT;
+ }
+ }
+
+ if (client->root->callback->post_execute != NULL)
+ {
+ client->root->callback->post_execute(client, NULL);
+ }
+
+ /* Move past \n */
+ ++end;
+ *length -= end - ptr;
+ ptr= end;
+ } while (*length > 0);
+
+ *endptr= ptr;
+ return MEMCACHED_PROTOCOL_READ_EVENT;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+LIBMEMCACHED_LOCAL
+memcached_protocol_event_t memcached_ascii_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcachedprotocol/common.h>
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+
+/*
+** **********************************************************************
+** INTERNAL INTERFACE
+** **********************************************************************
+*/
+
+/**
+ * Send a preformatted packet back to the client. If the connection is in
+ * pedantic mode, it will validate the packet and refuse to send it if it
+ * breaks the specification.
+ *
+ * @param cookie client identification
+ * @param request the original request packet
+ * @param response the packet to send
+ * @return The status of the operation
+ */
+static protocol_binary_response_status raw_response_handler(const void *cookie,
+ protocol_binary_request_header *request,
+ protocol_binary_response_header *response)
+{
+ memcached_protocol_client_st *client= (void*)cookie;
+
+ if (client->root->pedantic &&
+ !memcached_binary_protocol_pedantic_check_response(request, response))
+ {
+ return PROTOCOL_BINARY_RESPONSE_EINVAL;
+ }
+
+ if (client->root->drain(client) == false)
+ {
+ return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
+ }
+
+ size_t len= sizeof(protocol_binary_response_header) + htonl(response->response.bodylen);
+ size_t offset= 0;
+ char *ptr= (void*)response;
+
+ if (client->output == NULL)
+ {
+ /* I can write directly to the socket.... */
+ do
+ {
+ size_t num_bytes= len - offset;
+ ssize_t nw= client->root->send(client,
+ client->sock,
+ ptr + offset,
+ num_bytes);
+ if (nw == -1)
+ {
+ if (get_socket_errno() == EWOULDBLOCK)
+ {
+ break;
+ }
+ else if (get_socket_errno() != EINTR)
+ {
+ client->error= errno;
+ return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
+ }
+ }
+ else
+ {
+ offset += (size_t)nw;
+ }
+ } while (offset < len);
+ }
+
+ return client->root->spool(client, ptr, len - offset);
+}
+
+static void print_cmd(protocol_binary_command cmd)
+{
+ switch (cmd)
+ {
+ case PROTOCOL_BINARY_CMD_GET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_ADD: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_ADD\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_REPLACE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_REPLACE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DELETE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DELETE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_INCREMENT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_INCREMENT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DECREMENT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DECREMENT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_QUIT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_QUIT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_FLUSH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_FLUSH\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GETQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_NOOP: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_NOOP\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_VERSION: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_VERSION\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GETK: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETK\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GETKQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GETKQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_APPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_APPEND\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_PREPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_PREPEND\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_STAT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_STAT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SETQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SETQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_ADDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_ADDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_REPLACEQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_REPLACEQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DELETEQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DELETEQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_INCREMENTQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_INCREMENTQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DECREMENTQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DECREMENTQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_QUITQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_QUITQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_FLUSHQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_FLUSHQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_APPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_APPENDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_PREPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_PREPENDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_VERBOSITY: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_VERBOSITY\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TOUCH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TOUCH\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GAT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GAT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GATQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_LIST_MECHS\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SASL_AUTH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_AUTH\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SASL_STEP: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SASL_STEP\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RGET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RGET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RSET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RSET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RSETQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RSETQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RAPPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RAPPEND\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RAPPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RAPPENDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RPREPEND: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RPREPEND\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RPREPENDQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RPREPENDQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RDELETE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDELETE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RDELETEQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDELETEQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RINCR: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RINCR\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RINCRQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RINCRQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RDECR: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDECR\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_RDECRQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_RDECRQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SET_VBUCKET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SET_VBUCKET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GET_VBUCKET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GET_VBUCKET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_DEL_VBUCKET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_DEL_VBUCKET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_CONNECT: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CONNECT\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_MUTATION: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_MUTATION\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_DELETE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_DELETE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_FLUSH: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_FLUSH\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_OPAQUE: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_OPAQUE\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_START\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_TAP_CHECKPOINT_END\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_LAST_RESERVED: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_LAST_RESERVED\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GATK: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATK\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_GATKQ: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_GATKQ\n", __FILE__, __LINE__); return;
+ case PROTOCOL_BINARY_CMD_SCRUB: fprintf(stderr, "%s:%d PROTOCOL_BINARY_CMD_SCRUB\n", __FILE__, __LINE__); return;
+ default:
+ abort();
+ }
+}
+
+/*
+ * Version 0 of the interface is really low level and protocol specific,
+ * while the version 1 of the interface is more API focused. We need a
+ * way to translate between the command codes on the wire and the
+ * application level interface in V1, so let's just use the V0 of the
+ * interface as a map instead of creating a huuuge switch :-)
+ */
+
+/**
+ * Callback for the GET/GETQ/GETK and GETKQ responses
+ * @param cookie client identifier
+ * @param key the key for the item
+ * @param keylen the length of the key
+ * @param body the length of the body
+ * @param bodylen the length of the body
+ * @param flags the flags for the item
+ * @param cas the CAS id for the item
+ */
+static protocol_binary_response_status get_response_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void *body,
+ uint32_t bodylen,
+ uint32_t flags,
+ uint64_t cas)
+{
+ memcached_protocol_client_st *client= (void*)cookie;
+ uint8_t opcode= client->current_command->request.opcode;
+
+ if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETQ)
+ {
+ keylen= 0;
+ }
+
+ protocol_binary_response_get response= {
+ .message.header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= opcode,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= client->current_command->request.opaque,
+ .cas= memcached_htonll(cas),
+ .keylen= htons(keylen),
+ .extlen= 4,
+ .bodylen= htonl(bodylen + keylen + 4),
+ },
+ };
+
+ response.message.body.flags= htonl(flags);
+
+ protocol_binary_response_status rval;
+ const protocol_binary_response_status success= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ if ((rval= client->root->spool(client, response.bytes, sizeof(response.bytes))) != success ||
+ (rval= client->root->spool(client, key, keylen)) != success ||
+ (rval= client->root->spool(client, body, bodylen)) != success)
+ {
+ return rval;
+ }
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+/**
+ * Callback for the STAT responses
+ * @param cookie client identifier
+ * @param key the key for the item
+ * @param keylen the length of the key
+ * @param body the length of the body
+ * @param bodylen the length of the body
+ */
+static protocol_binary_response_status stat_response_handler(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void *body,
+ uint32_t bodylen)
+{
+
+ memcached_protocol_client_st *client= (void*)cookie;
+
+ protocol_binary_response_no_extras response= {
+ .message.header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= client->current_command->request.opcode,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= client->current_command->request.opaque,
+ .keylen= htons(keylen),
+ .bodylen= htonl(bodylen + keylen),
+ .cas= 0
+ },
+ };
+
+ protocol_binary_response_status rval;
+ const protocol_binary_response_status success= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ if ((rval= client->root->spool(client, response.bytes, sizeof(response.bytes))) != success ||
+ (rval= client->root->spool(client, key, keylen)) != success ||
+ (rval= client->root->spool(client, body, bodylen)) != success)
+ {
+ return rval;
+ }
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+/**
+ * Callback for the VERSION responses
+ * @param cookie client identifier
+ * @param text the length of the body
+ * @param textlen the length of the body
+ */
+static protocol_binary_response_status version_response_handler(const void *cookie,
+ const void *text,
+ uint32_t textlen)
+{
+
+ memcached_protocol_client_st *client= (void*)cookie;
+
+ protocol_binary_response_no_extras response= {
+ .message.header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= client->current_command->request.opcode,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= client->current_command->request.opaque,
+ .bodylen= htonl(textlen),
+ .cas= 0
+ },
+ };
+
+ protocol_binary_response_status rval;
+ const protocol_binary_response_status success= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ if ((rval= client->root->spool(client, response.bytes, sizeof(response.bytes))) != success ||
+ (rval= client->root->spool(client, text, textlen)) != success)
+ {
+ return rval;
+ }
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+/**
+ * Callback for ADD and ADDQ
+ * @param cookie the calling client
+ * @param header the add/addq command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+add_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.add != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+ uint32_t datalen= ntohl(header->request.bodylen) - keylen - 8;
+ protocol_binary_request_add *request= (void*)header;
+ uint32_t flags= ntohl(request->message.body.flags);
+ uint32_t timeout= ntohl(request->message.body.expiration);
+ char *key= ((char*)header) + sizeof(*header) + 8;
+ char *data= key + keylen;
+ uint64_t cas;
+
+ rval= client->root->callback->interface.v1.add(cookie, key, keylen,
+ data, datalen, flags,
+ timeout, &cas);
+
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ header->request.opcode == PROTOCOL_BINARY_CMD_ADD)
+ {
+ /* Send a positive request */
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_ADD,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ .cas= memcached_ntohll(cas)
+ }
+ }
+ };
+ rval= response_handler(cookie, header, (void*)&response);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for DECREMENT and DECREMENTQ
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+decrement_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.decrement != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+ protocol_binary_request_decr *request= (void*)header;
+ uint64_t init= memcached_ntohll(request->message.body.initial);
+ uint64_t delta= memcached_ntohll(request->message.body.delta);
+ uint32_t timeout= ntohl(request->message.body.expiration);
+ void *key= request->bytes + sizeof(request->bytes);
+ uint64_t result;
+ uint64_t cas;
+
+ rval= client->root->callback->interface.v1.decrement(cookie, key, keylen,
+ delta, init, timeout,
+ &result, &cas);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ header->request.opcode == PROTOCOL_BINARY_CMD_DECREMENT)
+ {
+ /* Send a positive request */
+ protocol_binary_response_decr response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_DECREMENT,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ .cas= memcached_ntohll(cas),
+ .bodylen= htonl(8)
+ },
+ .body.value= memcached_htonll(result)
+ }
+ };
+ rval= response_handler(cookie, header, (void*)&response);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for DELETE and DELETEQ
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status delete_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.delete_object != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+ void *key= (header +1);
+ uint64_t cas= memcached_ntohll(header->request.cas);
+ rval= client->root->callback->interface.v1.delete_object(cookie, key, keylen, cas);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ header->request.opcode == PROTOCOL_BINARY_CMD_DELETE)
+ {
+ /* Send a positive request */
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_DELETE,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ }
+ }
+ };
+ rval= response_handler(cookie, header, (void*)&response);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for FLUSH and FLUSHQ
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+flush_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.flush_object != NULL)
+ {
+ protocol_binary_request_flush *flush_object= (void*)header;
+ uint32_t timeout= 0;
+ if (htonl(header->request.bodylen) == 4)
+ {
+ timeout= ntohl(flush_object->message.body.expiration);
+ }
+
+ rval= client->root->callback->interface.v1.flush_object(cookie, timeout);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ header->request.opcode == PROTOCOL_BINARY_CMD_FLUSH)
+ {
+ /* Send a positive request */
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_FLUSH,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ }
+ }
+ };
+ rval= response_handler(cookie, header, (void*)&response);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for GET, GETK, GETQ, GETKQ
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+get_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.get != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+ void *key= (header + 1);
+ rval= client->root->callback->interface.v1.get(cookie, key, keylen,
+ get_response_handler);
+
+ if (rval == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT &&
+ (header->request.opcode == PROTOCOL_BINARY_CMD_GETQ ||
+ header->request.opcode == PROTOCOL_BINARY_CMD_GETKQ))
+ {
+ /* Quiet commands shouldn't respond on cache misses */
+ rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for INCREMENT and INCREMENTQ
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+increment_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.increment != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+ protocol_binary_request_incr *request= (void*)header;
+ uint64_t init= memcached_ntohll(request->message.body.initial);
+ uint64_t delta= memcached_ntohll(request->message.body.delta);
+ uint32_t timeout= ntohl(request->message.body.expiration);
+ void *key= request->bytes + sizeof(request->bytes);
+ uint64_t cas;
+ uint64_t result;
+
+ rval= client->root->callback->interface.v1.increment(cookie, key, keylen,
+ delta, init, timeout,
+ &result, &cas);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ header->request.opcode == PROTOCOL_BINARY_CMD_INCREMENT)
+ {
+ /* Send a positive request */
+ protocol_binary_response_incr response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_INCREMENT,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ .cas= memcached_ntohll(cas),
+ .bodylen= htonl(8)
+ },
+ .body.value= memcached_htonll(result)
+ }
+ };
+
+ rval= response_handler(cookie, header, (void*)&response);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for noop. Inform the v1 interface about the noop packet, and
+ * create and send a packet back to the client
+ *
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler the response handler
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+noop_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.noop != NULL)
+ {
+ client->root->callback->interface.v1.noop(cookie);
+ }
+
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_NOOP,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ }
+ }
+ };
+
+ return response_handler(cookie, header, (void*)&response);
+}
+
+/**
+ * Callback for APPEND and APPENDQ
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+append_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.append != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+ uint32_t datalen= ntohl(header->request.bodylen) - keylen;
+ char *key= (void*)(header +1);
+ char *data= key +keylen;
+ uint64_t cas= memcached_ntohll(header->request.cas);
+ uint64_t result_cas;
+
+ rval= client->root->callback->interface.v1.append(cookie, key, keylen,
+ data, datalen, cas,
+ &result_cas);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ header->request.opcode == PROTOCOL_BINARY_CMD_APPEND)
+ {
+ /* Send a positive request */
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_APPEND,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ .cas= memcached_ntohll(result_cas),
+ },
+ }
+ };
+ rval= response_handler(cookie, header, (void*)&response);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for PREPEND and PREPENDQ
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+prepend_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.prepend != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+ uint32_t datalen= ntohl(header->request.bodylen) - keylen;
+ char *key= (char*)(header + 1);
+ char *data= key + keylen;
+ uint64_t cas= memcached_ntohll(header->request.cas);
+ uint64_t result_cas;
+ rval= client->root->callback->interface.v1.prepend(cookie, key, keylen,
+ data, datalen, cas,
+ &result_cas);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ header->request.opcode == PROTOCOL_BINARY_CMD_PREPEND)
+ {
+ /* Send a positive request */
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_PREPEND,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ .cas= memcached_ntohll(result_cas),
+ },
+ }
+ };
+ rval= response_handler(cookie, header, (void*)&response);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for QUIT and QUITQ. Notify the client and shut down the connection
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+quit_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.quit != NULL)
+ {
+ client->root->callback->interface.v1.quit(cookie);
+ }
+
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_QUIT,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque
+ }
+ }
+ };
+
+ if (header->request.opcode == PROTOCOL_BINARY_CMD_QUIT)
+ {
+ response_handler(cookie, header, (void*)&response);
+ }
+
+ /* I need a better way to signal to close the connection */
+ return PROTOCOL_BINARY_RESPONSE_EINTERNAL;
+}
+
+/**
+ * Callback for REPLACE and REPLACEQ
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+replace_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.replace != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+ uint32_t datalen= ntohl(header->request.bodylen) - keylen - 8;
+ protocol_binary_request_replace *request= (void*)header;
+ uint32_t flags= ntohl(request->message.body.flags);
+ uint32_t timeout= ntohl(request->message.body.expiration);
+ char *key= ((char*)header) + sizeof(*header) + 8;
+ char *data= key + keylen;
+ uint64_t cas= memcached_ntohll(header->request.cas);
+ uint64_t result_cas;
+
+ rval= client->root->callback->interface.v1.replace(cookie, key, keylen,
+ data, datalen, flags,
+ timeout, cas,
+ &result_cas);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ header->request.opcode == PROTOCOL_BINARY_CMD_REPLACE)
+ {
+ /* Send a positive request */
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_REPLACE,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ .cas= memcached_ntohll(result_cas),
+ },
+ }
+ };
+ rval= response_handler(cookie, header, (void*)&response);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for SET and SETQ
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status set_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.set != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+ uint32_t datalen= ntohl(header->request.bodylen) - keylen - 8;
+ protocol_binary_request_replace *request= (void*)header;
+ uint32_t flags= ntohl(request->message.body.flags);
+ uint32_t timeout= ntohl(request->message.body.expiration);
+ char *key= ((char*)header) + sizeof(*header) + 8;
+ char *data= key + keylen;
+ uint64_t cas= memcached_ntohll(header->request.cas);
+ uint64_t result_cas;
+
+
+ rval= client->root->callback->interface.v1.set(cookie, key, keylen,
+ data, datalen, flags,
+ timeout, cas, &result_cas);
+ if (rval == PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ header->request.opcode == PROTOCOL_BINARY_CMD_SET)
+ {
+ /* Send a positive request */
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= PROTOCOL_BINARY_CMD_SET,
+ .status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
+ .opaque= header->request.opaque,
+ .cas= memcached_ntohll(result_cas),
+ },
+ }
+ };
+ rval= response_handler(cookie, header, (void*)&response);
+ }
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for STAT
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+stat_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.stat != NULL)
+ {
+ uint16_t keylen= ntohs(header->request.keylen);
+
+ rval= client->root->callback->interface.v1.stat(cookie,
+ (void*)(header + 1),
+ keylen,
+ stat_response_handler);
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * Callback for VERSION
+ * @param cookie the calling client
+ * @param header the command
+ * @param response_handler not used
+ * @return the result of the operation
+ */
+static protocol_binary_response_status
+version_command_handler(const void *cookie,
+ protocol_binary_request_header *header,
+ memcached_binary_protocol_raw_response_handler response_handler)
+{
+ (void)response_handler;
+ (void)header;
+ protocol_binary_response_status rval;
+
+ memcached_protocol_client_st *client= (void*)cookie;
+ if (client->root->callback->interface.v1.version != NULL)
+ {
+ rval= client->root->callback->interface.v1.version(cookie,
+ version_response_handler);
+ }
+ else
+ {
+ rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ }
+
+ return rval;
+}
+
+/**
+ * The map to remap between the com codes and the v1 logical setting
+ */
+static memcached_binary_protocol_command_handler comcode_v0_v1_remap[256]= {
+ [PROTOCOL_BINARY_CMD_ADDQ]= add_command_handler,
+ [PROTOCOL_BINARY_CMD_ADD]= add_command_handler,
+ [PROTOCOL_BINARY_CMD_APPENDQ]= append_command_handler,
+ [PROTOCOL_BINARY_CMD_APPEND]= append_command_handler,
+ [PROTOCOL_BINARY_CMD_DECREMENTQ]= decrement_command_handler,
+ [PROTOCOL_BINARY_CMD_DECREMENT]= decrement_command_handler,
+ [PROTOCOL_BINARY_CMD_DELETEQ]= delete_command_handler,
+ [PROTOCOL_BINARY_CMD_DELETE]= delete_command_handler,
+ [PROTOCOL_BINARY_CMD_FLUSHQ]= flush_command_handler,
+ [PROTOCOL_BINARY_CMD_FLUSH]= flush_command_handler,
+ [PROTOCOL_BINARY_CMD_GETKQ]= get_command_handler,
+ [PROTOCOL_BINARY_CMD_GETK]= get_command_handler,
+ [PROTOCOL_BINARY_CMD_GETQ]= get_command_handler,
+ [PROTOCOL_BINARY_CMD_GET]= get_command_handler,
+ [PROTOCOL_BINARY_CMD_INCREMENTQ]= increment_command_handler,
+ [PROTOCOL_BINARY_CMD_INCREMENT]= increment_command_handler,
+ [PROTOCOL_BINARY_CMD_NOOP]= noop_command_handler,
+ [PROTOCOL_BINARY_CMD_PREPENDQ]= prepend_command_handler,
+ [PROTOCOL_BINARY_CMD_PREPEND]= prepend_command_handler,
+ [PROTOCOL_BINARY_CMD_QUITQ]= quit_command_handler,
+ [PROTOCOL_BINARY_CMD_QUIT]= quit_command_handler,
+ [PROTOCOL_BINARY_CMD_REPLACEQ]= replace_command_handler,
+ [PROTOCOL_BINARY_CMD_REPLACE]= replace_command_handler,
+ [PROTOCOL_BINARY_CMD_SETQ]= set_command_handler,
+ [PROTOCOL_BINARY_CMD_SET]= set_command_handler,
+ [PROTOCOL_BINARY_CMD_STAT]= stat_command_handler,
+ [PROTOCOL_BINARY_CMD_VERSION]= version_command_handler,
+};
+
+/**
+ * Try to execute a command. Fire the pre/post functions and the specialized
+ * handler function if it's set. If not, the unknown probe should be fired
+ * if it's present.
+ * @param client the client connection to operate on
+ * @param header the command to execute
+ * @return true if success or false if a fatal error occured so that the
+ * connection should be shut down.
+ */
+static protocol_binary_response_status execute_command(memcached_protocol_client_st *client, protocol_binary_request_header *header)
+{
+ if (client->root->pedantic &&
+ memcached_binary_protocol_pedantic_check_request(header))
+ {
+ /* @todo return invalid command packet */
+ }
+
+ /* we got all data available, execute the callback! */
+ if (client->root->callback->pre_execute != NULL)
+ {
+ client->root->callback->pre_execute(client, header);
+ }
+
+ protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
+ uint8_t cc= header->request.opcode;
+
+ if (client->is_verbose)
+ {
+ print_cmd(cc);
+ }
+
+ switch (client->root->callback->interface_version)
+ {
+ case 0:
+ if (client->root->callback->interface.v0.comcode[cc] != NULL)
+ {
+ rval= client->root->callback->interface.v0.comcode[cc](client, header, raw_response_handler);
+ }
+ break;
+
+ case 1:
+ if (comcode_v0_v1_remap[cc] != NULL)
+ {
+ rval= comcode_v0_v1_remap[cc](client, header, raw_response_handler);
+ }
+ break;
+
+ default:
+ /* Unknown interface.
+ * It should be impossible to get here so I'll just call abort
+ * to avoid getting a compiler warning :-)
+ */
+ abort();
+ }
+
+
+ if (rval == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND &&
+ client->root->callback->unknown != NULL)
+ {
+ rval= client->root->callback->unknown(client, header, raw_response_handler);
+ }
+
+ if (rval != PROTOCOL_BINARY_RESPONSE_SUCCESS &&
+ rval != PROTOCOL_BINARY_RESPONSE_EINTERNAL &&
+ rval != PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED)
+ {
+ protocol_binary_response_no_extras response= {
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
+ .opcode= cc,
+ .status= htons(rval),
+ .opaque= header->request.opaque,
+ },
+ }
+ };
+ rval= raw_response_handler(client, header, (void*)&response);
+ }
+
+ if (client->root->callback->post_execute != NULL)
+ {
+ client->root->callback->post_execute(client, header);
+ }
+
+ return rval;
+}
+
+/*
+** **********************************************************************
+** "PROTOECTED" INTERFACE
+** **********************************************************************
+*/
+memcached_protocol_event_t memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr)
+{
+ /* try to parse all of the received packets */
+ protocol_binary_request_header *header;
+ header= (void*)client->root->input_buffer;
+ if (header->request.magic != (uint8_t)PROTOCOL_BINARY_REQ)
+ {
+ client->error= EINVAL;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
+ ssize_t len= *length;
+
+ while (len >= (ssize_t)sizeof(*header) &&
+ (len >= (ssize_t)(sizeof(*header) + ntohl(header->request.bodylen))))
+ {
+ /* I have the complete package */
+ client->current_command= header;
+ protocol_binary_response_status rv= execute_command(client, header);
+
+ if (rv == PROTOCOL_BINARY_RESPONSE_EINTERNAL)
+ {
+ *length= len;
+ *endptr= (void*)header;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
+ else if (rv == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED)
+ {
+ return MEMCACHED_PROTOCOL_PAUSE_EVENT;
+ }
+
+ ssize_t total= (ssize_t)(sizeof(*header) + ntohl(header->request.bodylen));
+ len -= total;
+ if (len > 0)
+ {
+ intptr_t ptr= (intptr_t)header;
+ ptr += total;
+ if ((ptr % 8) == 0)
+ {
+ header= (void*)ptr;
+ }
+ else
+ {
+ /* Fix alignment */
+ memmove(client->root->input_buffer, (void*)ptr, (size_t)len);
+ header= (void*)client->root->input_buffer;
+ }
+ }
+ *length= len;
+ *endptr= (void*)header;
+ }
+
+ return MEMCACHED_PROTOCOL_READ_EVENT;
+}
+
+/*
+** **********************************************************************
+** PUBLIC INTERFACE
+** **********************************************************************
+*/
+memcached_binary_protocol_callback_st *memcached_binary_protocol_get_callbacks(memcached_protocol_st *instance)
+{
+ return instance->callback;
+}
+
+void memcached_binary_protocol_set_callbacks(memcached_protocol_st *instance, memcached_binary_protocol_callback_st *callback)
+{
+ instance->callback= callback;
+}
+
+memcached_binary_protocol_raw_response_handler memcached_binary_protocol_get_raw_response_handler(const void *cookie)
+{
+ (void)cookie;
+ return raw_response_handler;
+}
+
+void memcached_binary_protocol_set_pedantic(memcached_protocol_st *instance, bool enable)
+{
+ instance->pedantic= enable;
+}
+
+bool memcached_binary_protocol_get_pedantic(memcached_protocol_st *instance)
+{
+ return instance->pedantic;
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+LIBMEMCACHED_LOCAL
+bool memcached_binary_protocol_pedantic_check_request(const protocol_binary_request_header *request);
+
+LIBMEMCACHED_LOCAL
+bool memcached_binary_protocol_pedantic_check_response(const protocol_binary_request_header *request,
+ const protocol_binary_response_header *response);
+
+LIBMEMCACHED_LOCAL
+memcached_protocol_event_t memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#include "mem_config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#ifndef NDEBUG
+#include <signal.h>
+#endif
+
+#include <libmemcachedprotocol/common.h>
+
+#ifndef NDEBUG
+const uint64_t redzone_pattern = 0xdeadbeefcafebabe;
+int cache_error = 0;
+#endif
+
+const size_t initial_pool_size = 64;
+
+cache_t* cache_create(const char *name, size_t bufsize, size_t align,
+ cache_constructor_t* constructor,
+ cache_destructor_t* destructor) {
+ cache_t* ret = calloc(1, sizeof(cache_t));
+ size_t name_length= strlen(name);
+ char* nm= calloc(1, (sizeof(char) * name_length) +1);
+ memcpy(nm, name, name_length);
+ void** ptr = calloc(initial_pool_size, bufsize);
+ if (ret == NULL || nm == NULL || ptr == NULL ||
+ pthread_mutex_init(&ret->mutex, NULL) == -1) {
+ free(ret);
+ free(nm);
+ free(ptr);
+ return NULL;
+ }
+
+ ret->name = nm;
+ ret->ptr = ptr;
+ ret->freetotal = initial_pool_size;
+ ret->constructor = constructor;
+ ret->destructor = destructor;
+
+#ifndef NDEBUG
+ ret->bufsize = bufsize + 2 * sizeof(redzone_pattern);
+#else
+ ret->bufsize = bufsize;
+#endif
+
+ (void)align;
+
+ return ret;
+}
+
+static inline void* get_object(void *ptr) {
+#ifndef NDEBUG
+ uint64_t *pre = ptr;
+ return pre + 1;
+#else
+ return ptr;
+#endif
+}
+
+void cache_destroy(cache_t *cache) {
+ while (cache->freecurr > 0) {
+ void *ptr = cache->ptr[--cache->freecurr];
+ if (cache->destructor) {
+ cache->destructor(get_object(ptr), NULL);
+ }
+ free(ptr);
+ }
+ free(cache->name);
+ free(cache->ptr);
+ pthread_mutex_destroy(&cache->mutex);
+}
+
+void* cache_alloc(cache_t *cache) {
+ void *ret;
+ void *object;
+ pthread_mutex_lock(&cache->mutex);
+ if (cache->freecurr > 0) {
+ ret = cache->ptr[--cache->freecurr];
+ object = get_object(ret);
+ } else {
+ object = ret = malloc(cache->bufsize);
+ if (ret != NULL) {
+ object = get_object(ret);
+
+ if (cache->constructor != NULL &&
+ cache->constructor(object, NULL, 0) != 0) {
+ free(ret);
+ object = NULL;
+ }
+ }
+ }
+ pthread_mutex_unlock(&cache->mutex);
+
+#ifndef NDEBUG
+ if (object != NULL) {
+ /* add a simple form of buffer-check */
+ uint64_t *pre = ret;
+ *pre = redzone_pattern;
+ ret = pre+1;
+ memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)),
+ &redzone_pattern, sizeof(redzone_pattern));
+ }
+#endif
+
+ return object;
+}
+
+void cache_free(cache_t *cache, void *ptr) {
+ pthread_mutex_lock(&cache->mutex);
+
+#ifndef NDEBUG
+ /* validate redzone... */
+ if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)),
+ &redzone_pattern, sizeof(redzone_pattern)) != 0) {
+ raise(SIGABRT);
+ cache_error = 1;
+ pthread_mutex_unlock(&cache->mutex);
+ return;
+ }
+ uint64_t *pre = ptr;
+ --pre;
+ if (*pre != redzone_pattern) {
+ raise(SIGABRT);
+ cache_error = -1;
+ pthread_mutex_unlock(&cache->mutex);
+ return;
+ }
+ ptr = pre;
+#endif
+ if (cache->freecurr < cache->freetotal) {
+ cache->ptr[cache->freecurr++] = ptr;
+ } else {
+ /* try to enlarge free connections array */
+ size_t newtotal = cache->freetotal * 2;
+ void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal);
+ if (new_free) {
+ cache->freetotal = newtotal;
+ cache->ptr = new_free;
+ cache->ptr[cache->freecurr++] = ptr;
+ } else {
+ if (cache->destructor) {
+ cache->destructor(ptr, NULL);
+ }
+ free(ptr);
+
+ }
+ }
+ pthread_mutex_unlock(&cache->mutex);
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+#pragma once
+
+#include <pthread.h>
+
+#ifdef HAVE_UMEM_H
+# include <umem.h>
+# define cache_t umem_cache_t
+# define cache_alloc(a) umem_cache_alloc(a, UMEM_DEFAULT)
+# define cache_free(a, b) umem_cache_free(a, b)
+# define cache_create(a,b,c,d,e) umem_cache_create((char*)a, b, c, d, e, NULL, NULL, NULL, 0)
+# define cache_destroy(a) umem_cache_destroy(a);
+#else
+# ifndef NDEBUG
+/* may be used for debug purposes */
+extern int cache_error;
+# endif
+
+/**
+ * Constructor used to initialize allocated objects
+ *
+ * @param obj pointer to the object to initialized.
+ * @param notused1 This parameter is currently not used.
+ * @param notused2 This parameter is currently not used.
+ * @return you should return 0, but currently this is not checked
+ */
+typedef int cache_constructor_t(void* obj, void* notused1, int notused2);
+/**
+ * Destructor used to clean up allocated objects before they are
+ * returned to the operating system.
+ *
+ * @param obj pointer to the object to initialized.
+ * @param notused1 This parameter is currently not used.
+ * @param notused2 This parameter is currently not used.
+ * @return you should return 0, but currently this is not checked
+ */
+typedef void cache_destructor_t(void* obj, void* notused);
+
+/**
+ * Definition of the structure to keep track of the internal details of
+ * the cache allocator. Touching any of these variables results in
+ * undefined behavior.
+ */
+typedef struct {
+ /** Mutex to protect access to the structure */
+ pthread_mutex_t mutex;
+ /** Name of the cache objects in this cache (provided by the caller) */
+ char *name;
+ /** List of pointers to available buffers in this cache */
+ void **ptr;
+ /** The size of each element in this cache */
+ size_t bufsize;
+ /** The capacity of the list of elements */
+ size_t freetotal;
+ /** The current number of free elements */
+ size_t freecurr;
+ /** The constructor to be called each time we allocate more memory */
+ cache_constructor_t* constructor;
+ /** The destructor to be called each time before we release memory */
+ cache_destructor_t* destructor;
+} cache_t;
+
+/**
+ * Create an object cache.
+ *
+ * The object cache will let you allocate objects of the same size. It is fully
+ * MT safe, so you may allocate objects from multiple threads without having to
+ * do any syncrhonization in the application code.
+ *
+ * @param name the name of the object cache. This name may be used for debug purposes
+ * and may help you track down what kind of object you have problems with
+ * (buffer overruns, leakage etc)
+ * @param bufsize the size of each object in the cache
+ * @param align the alignment requirements of the objects in the cache.
+ * @param constructor the function to be called to initialize memory when we need
+ * to allocate more memory from the os.
+ * @param destructor the function to be called before we release the memory back
+ * to the os.
+ * @return a handle to an object cache if successful, NULL otherwise.
+ */
+cache_t* cache_create(const char* name, size_t bufsize, size_t align,
+ cache_constructor_t* constructor,
+ cache_destructor_t* destructor);
+/**
+ * Destroy an object cache.
+ *
+ * Destroy and invalidate an object cache. You should return all buffers allocated
+ * with cache_alloc by using cache_free before calling this function. Not doing
+ * so results in undefined behavior (the buffers may or may not be invalidated)
+ *
+ * @param handle the handle to the object cache to destroy.
+ */
+void cache_destroy(cache_t* handle);
+/**
+ * Allocate an object from the cache.
+ *
+ * @param handle the handle to the object cache to allocate from
+ * @return a pointer to an initialized object from the cache, or NULL if
+ * the allocation cannot be satisfied.
+ */
+void* cache_alloc(cache_t* handle);
+/**
+ * Return an object back to the cache.
+ *
+ * The caller should return the object in an initialized state so that
+ * the object may be returned in an expected state from cache_alloc.
+ *
+ * @param handle handle to the object cache to return the object to
+ * @param ptr pointer to the object to return.
+ */
+void cache_free(cache_t* handle, void* ptr);
+#endif // HAVE_UMEM_H
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include "mem_config.h"
+#include <assert.h>
+
+#include <libmemcachedprotocol-0.0/handler.h>
+#include <libmemcachedprotocol/cache.h>
+#include <libmemcached/byteorder.h>
+#include <libmemcached/socket.hpp>
+
+/*
+ * I don't really need the following two functions as function pointers
+ * in the instance handle, but I don't want to put them in the global
+ * namespace for those linking statically (personally I don't like that,
+ * but some people still do). If it ever shows up as a performance thing
+ * I'll look into optimizing this ;-)
+ */
+typedef bool (*drain_func)(memcached_protocol_client_st *client);
+typedef protocol_binary_response_status (*spool_func)(memcached_protocol_client_st *client,
+ const void *data,
+ size_t length);
+
+/**
+ * Definition of the per instance structure.
+ */
+struct memcached_protocol_st {
+ memcached_binary_protocol_callback_st *callback;
+ memcached_protocol_recv_func recv;
+ memcached_protocol_send_func send;
+
+ /*
+ * I really don't need these as funciton pointers, but I don't want
+ * to clutter the namespace if someone links statically.
+ */
+ drain_func drain;
+ spool_func spool;
+
+ /*
+ * To avoid keeping a buffer in each client all the time I have a
+ * bigger buffer in the instance that I read to initially, and then
+ * I try to parse and execute as much from the buffer. If I wasn't able
+ * to process all data I'll keep that in a per-connection buffer until
+ * the next time I can read from the socket.
+ */
+ uint8_t *input_buffer;
+ size_t input_buffer_size;
+
+ bool pedantic;
+ /* @todo use multiple sized buffers */
+ cache_t *buffer_cache;
+};
+
+struct chunk_st {
+ /* Pointer to the data */
+ char *data;
+ /* The offset to the first byte into the buffer that is used */
+ size_t offset;
+ /* The offset into the buffer for the first free byte */
+ size_t nbytes;
+ /* The number of bytes in the buffer */
+ size_t size;
+ /* Pointer to the next buffer in the chain */
+ struct chunk_st *next;
+};
+
+#define CHUNK_BUFFERSIZE 2048
+
+typedef memcached_protocol_event_t (*process_data)(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr);
+
+enum ascii_cmd {
+ GET_CMD,
+ GETS_CMD,
+ SET_CMD,
+ ADD_CMD,
+ REPLACE_CMD,
+ CAS_CMD,
+ APPEND_CMD,
+ PREPEND_CMD,
+ DELETE_CMD,
+ INCR_CMD,
+ DECR_CMD,
+ STATS_CMD,
+ FLUSH_ALL_CMD,
+ VERSION_CMD,
+ QUIT_CMD,
+ VERBOSITY_CMD,
+ UNKNOWN_CMD
+};
+
+struct memcached_protocol_client_st {
+ bool is_verbose;
+ memcached_protocol_st *root;
+ memcached_socket_t sock;
+ int error;
+
+ /* Linked list of data to send */
+ struct chunk_st *output;
+ struct chunk_st *output_tail;
+
+ /*
+ * While we process input data, this is where we spool incomplete commands
+ * if we need to receive more data....
+ * @todo use the buffercace
+ */
+ uint8_t *input_buffer;
+ size_t input_buffer_size;
+ size_t input_buffer_offset;
+
+ /* The callback to the protocol handler to use (ascii or binary) */
+ process_data work;
+
+ /*
+ * Should the spool data discard the data to send or not? (aka noreply in
+ * the ascii protocol..
+ */
+ bool mute;
+
+ /* Members used by the binary protocol */
+ protocol_binary_request_header *current_command;
+
+ /* Members used by the ascii protocol */
+ enum ascii_cmd ascii_command;
+};
+
+#include "ascii_handler.h"
+#include "binary_handler.h"
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+#include <libmemcachedprotocol/common.h>
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/*
+** **********************************************************************
+** INTERNAL INTERFACE
+** **********************************************************************
+*/
+
+/**
+ * The default function to receive data from the client. This function
+ * just wraps the recv function to receive from a socket.
+ * See man -s3socket recv for more information.
+ *
+ * @param cookie cookie indentifying a client, not used
+ * @param sock socket to read from
+ * @param buf the destination buffer
+ * @param nbytes the number of bytes to read
+ * @return the number of bytes transferred of -1 upon error
+ */
+static ssize_t default_recv(const void *cookie,
+ memcached_socket_t sock,
+ void *buf,
+ size_t nbytes)
+{
+ (void)cookie;
+ return recv(sock, buf, nbytes, 0);
+}
+
+/**
+ * The default function to send data to the server. This function
+ * just wraps the send function to send through a socket.
+ * See man -s3socket send for more information.
+ *
+ * @param cookie cookie indentifying a client, not used
+ * @param sock socket to send to
+ * @param buf the source buffer
+ * @param nbytes the number of bytes to send
+ * @return the number of bytes transferred of -1 upon error
+ */
+static ssize_t default_send(const void *cookie,
+ memcached_socket_t fd,
+ const void *buf,
+ size_t nbytes)
+{
+ (void)cookie;
+ return send(fd, buf, nbytes, MSG_NOSIGNAL);
+}
+
+/**
+ * Try to drain the output buffers without blocking
+ *
+ * @param client the client to drain
+ * @return false if an error occured (connection should be shut down)
+ * true otherwise (please note that there may be more data to
+ * left in the buffer to send)
+ */
+static bool drain_output(struct memcached_protocol_client_st *client)
+{
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d %s mute:%d output:%s length:%d\n", __FILE__, __LINE__, __func__, (int)client->mute,
+ client->output ? "yes" : "no",
+ client->output ? (int)(client->output->nbytes - client->output->offset) : 0);
+ }
+
+ /* Do we have pending data to send? */
+ while (client->output != NULL)
+ {
+ ssize_t len= client->root->send(client,
+ client->sock,
+ client->output->data + client->output->offset,
+ client->output->nbytes - client->output->offset);
+
+ if (len == -1)
+ {
+ if (get_socket_errno() == EWOULDBLOCK)
+ {
+ return true;
+ }
+ else if (get_socket_errno() != EINTR)
+ {
+ client->error= get_socket_errno();
+ return false;
+ }
+ }
+ else
+ {
+ client->output->offset += (size_t)len;
+ if (client->output->offset == client->output->nbytes)
+ {
+ /* This was the complete buffer */
+ struct chunk_st *old= client->output;
+ client->output= client->output->next;
+ if (client->output == NULL)
+ {
+ client->output_tail= NULL;
+ }
+ cache_free(client->root->buffer_cache, old);
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Allocate an output buffer and chain it into the output list
+ *
+ * @param client the client that needs the buffer
+ * @return pointer to the new chunk if the allocation succeeds, NULL otherwise
+ */
+static struct chunk_st *allocate_output_chunk(struct memcached_protocol_client_st *client)
+{
+ struct chunk_st *ret= cache_alloc(client->root->buffer_cache);
+
+ if (ret == NULL)
+ {
+ return NULL;
+ }
+
+ ret->offset= ret->nbytes= 0;
+ ret->next= NULL;
+ ret->size= CHUNK_BUFFERSIZE;
+ ret->data= (void*)(ret + 1);
+ if (client->output == NULL)
+ {
+ client->output= client->output_tail= ret;
+ }
+ else
+ {
+ client->output_tail->next= ret;
+ client->output_tail= ret;
+ }
+
+ return ret;
+}
+
+/**
+ * Spool data into the send-buffer for a client.
+ *
+ * @param client the client to spool the data for
+ * @param data the data to spool
+ * @param length the number of bytes of data to spool
+ * @return PROTOCOL_BINARY_RESPONSE_SUCCESS if success,
+ * PROTOCOL_BINARY_RESPONSE_ENOMEM if we failed to allocate memory
+ */
+static protocol_binary_response_status spool_output(struct memcached_protocol_client_st *client,
+ const void *data,
+ size_t length)
+{
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d %s mute:%d length:%d\n", __FILE__, __LINE__, __func__, (int)client->mute, (int)length);
+ }
+
+ if (client->mute)
+ {
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ }
+
+ size_t offset= 0;
+
+ struct chunk_st *chunk= client->output;
+ while (offset < length)
+ {
+ if (chunk == NULL || (chunk->size - chunk->nbytes) == 0)
+ {
+ if ((chunk= allocate_output_chunk(client)) == NULL)
+ {
+ return PROTOCOL_BINARY_RESPONSE_ENOMEM;
+ }
+ }
+
+ size_t bulk= length - offset;
+ if (bulk > chunk->size - chunk->nbytes)
+ {
+ bulk= chunk->size - chunk->nbytes;
+ }
+
+ memcpy(chunk->data + chunk->nbytes, data, bulk);
+ chunk->nbytes += bulk;
+ offset += bulk;
+ }
+
+ return PROTOCOL_BINARY_RESPONSE_SUCCESS;
+}
+
+/**
+ * Try to determine the protocol used on this connection.
+ * If the first byte contains the magic byte PROTOCOL_BINARY_REQ we should
+ * be using the binary protocol on the connection. I implemented the support
+ * for the ASCII protocol by wrapping into the simple interface (aka v1),
+ * so the implementors needs to provide an implementation of that interface
+ *
+ */
+static memcached_protocol_event_t determine_protocol(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr)
+{
+ if (*client->root->input_buffer == (uint8_t)PROTOCOL_BINARY_REQ)
+ {
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d PROTOCOL: memcached_binary_protocol_process_data\n", __FILE__, __LINE__);
+ }
+ client->work= memcached_binary_protocol_process_data;
+ }
+ else if (client->root->callback->interface_version == 1)
+ {
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d PROTOCOL: memcached_ascii_protocol_process_data\n", __FILE__, __LINE__);
+ }
+
+ /*
+ * The ASCII protocol can only be used if the implementors provide
+ * an implementation for the version 1 of the interface..
+ *
+ * @todo I should allow the implementors to provide an implementation
+ * for version 0 and 1 at the same time and set the preferred
+ * interface to use...
+ */
+ client->work= memcached_ascii_protocol_process_data;
+ }
+ else
+ {
+ if (client->is_verbose)
+ {
+ fprintf(stderr, "%s:%d PROTOCOL: Unsupported protocol\n", __FILE__, __LINE__);
+ }
+
+ /* Let's just output a warning the way it is supposed to look like
+ * in the ASCII protocol...
+ */
+ const char *err= "CLIENT_ERROR: Unsupported protocol\r\n";
+ client->root->spool(client, err, strlen(err));
+ client->root->drain(client);
+
+ return MEMCACHED_PROTOCOL_ERROR_EVENT; /* Unsupported protocol */
+ }
+
+ return client->work(client, length, endptr);
+}
+
+/*
+** **********************************************************************
+** * PUBLIC INTERFACE
+** * See protocol_handler.h for function description
+** **********************************************************************
+*/
+struct memcached_protocol_st *memcached_protocol_create_instance(void)
+{
+ struct memcached_protocol_st *ret= calloc(1, sizeof(*ret));
+ if (ret != NULL)
+ {
+ ret->recv= default_recv;
+ ret->send= default_send;
+ ret->drain= drain_output;
+ ret->spool= spool_output;
+ ret->input_buffer_size= 1 * 1024 * 1024;
+ ret->input_buffer= malloc(ret->input_buffer_size);
+ if (ret->input_buffer == NULL)
+ {
+ free(ret);
+ ret= NULL;
+
+ return NULL;
+ }
+
+ ret->buffer_cache= cache_create("protocol_handler",
+ CHUNK_BUFFERSIZE + sizeof(struct chunk_st),
+ 0, NULL, NULL);
+ if (ret->buffer_cache == NULL)
+ {
+ free(ret->input_buffer);
+ free(ret);
+ ret= NULL;
+ }
+ }
+
+ return ret;
+}
+
+void memcached_protocol_destroy_instance(struct memcached_protocol_st *instance)
+{
+ cache_destroy(instance->buffer_cache);
+ free(instance->input_buffer);
+ free(instance);
+}
+
+struct memcached_protocol_client_st *memcached_protocol_create_client(struct memcached_protocol_st *instance, memcached_socket_t sock)
+{
+ struct memcached_protocol_client_st *ret= calloc(1, sizeof(memcached_protocol_client_st));
+ if (ret != NULL)
+ {
+ ret->root= instance;
+ ret->sock= sock;
+ ret->work= determine_protocol;
+ }
+
+ return ret;
+}
+
+void memcached_protocol_client_destroy(struct memcached_protocol_client_st *client)
+{
+ free(client);
+}
+
+void memcached_protocol_client_set_verbose(struct memcached_protocol_client_st *client, bool arg)
+{
+ if (client)
+ {
+ client->is_verbose= arg;
+ }
+}
+
+memcached_protocol_event_t memcached_protocol_client_work(struct memcached_protocol_client_st *client)
+{
+ /* Try to send data and read from the socket */
+ bool more_data= true;
+ do
+ {
+ ssize_t len= client->root->recv(client,
+ client->sock,
+ client->root->input_buffer + client->input_buffer_offset,
+ client->root->input_buffer_size - client->input_buffer_offset);
+
+ if (len > 0)
+ {
+ /* Do we have the complete packet? */
+ if (client->input_buffer_offset > 0)
+ {
+ memcpy(client->root->input_buffer, client->input_buffer,
+ client->input_buffer_offset);
+ len += (ssize_t)client->input_buffer_offset;
+
+ /* @todo use buffer-cache! */
+ free(client->input_buffer);
+ client->input_buffer_offset= 0;
+ }
+
+ void *endptr;
+ memcached_protocol_event_t events= client->work(client, &len, &endptr);
+ if (events == MEMCACHED_PROTOCOL_ERROR_EVENT)
+ {
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
+
+ if (len > 0)
+ {
+ /* save the data for later on */
+ /* @todo use buffer-cache */
+ client->input_buffer= malloc((size_t)len);
+ if (client->input_buffer == NULL)
+ {
+ client->error= ENOMEM;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
+ memcpy(client->input_buffer, endptr, (size_t)len);
+ client->input_buffer_offset= (size_t)len;
+ more_data= false;
+ }
+ }
+ else if (len == 0)
+ {
+ /* Connection closed */
+ drain_output(client);
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
+ else
+ {
+ if (get_socket_errno() != EWOULDBLOCK)
+ {
+ client->error= get_socket_errno();
+ /* mark this client as terminated! */
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
+ more_data= false;
+ }
+ } while (more_data);
+
+ if (!drain_output(client))
+ {
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ }
+
+ memcached_protocol_event_t ret= MEMCACHED_PROTOCOL_READ_EVENT;
+ if (client->output)
+ {
+ ret|= MEMCACHED_PROTOCOL_READ_EVENT;
+ }
+
+ return ret;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+#include <libmemcachedprotocol/common.h>
+
+#include <sys/types.h>
+
+#define ensure(a) if (!(a)) { return false; }
+
+bool memcached_binary_protocol_pedantic_check_request(const protocol_binary_request_header *request)
+{
+ ensure(request->request.magic == PROTOCOL_BINARY_REQ);
+ ensure(request->request.datatype == PROTOCOL_BINARY_RAW_BYTES);
+
+ ensure(request->bytes[6] == 0);
+ ensure(request->bytes[7] == 0);
+
+ uint8_t opcode= request->request.opcode;
+ uint16_t keylen= ntohs(request->request.keylen);
+ uint8_t extlen= request->request.extlen;
+ uint32_t bodylen= ntohl(request->request.bodylen);
+
+ ensure(bodylen >= (keylen + extlen));
+
+ switch (opcode) {
+ case PROTOCOL_BINARY_CMD_GET:
+ case PROTOCOL_BINARY_CMD_GETK:
+ case PROTOCOL_BINARY_CMD_GETKQ:
+ case PROTOCOL_BINARY_CMD_GETQ:
+ ensure(extlen == 0);
+ ensure(keylen > 0);
+ ensure(keylen == bodylen);
+ ensure(request->request.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_ADD:
+ case PROTOCOL_BINARY_CMD_ADDQ:
+ /* it makes no sense to run add with a cas value */
+ ensure(request->request.cas == 0);
+ /* FALLTHROUGH */
+ case PROTOCOL_BINARY_CMD_SET:
+ case PROTOCOL_BINARY_CMD_SETQ:
+ case PROTOCOL_BINARY_CMD_REPLACE:
+ case PROTOCOL_BINARY_CMD_REPLACEQ:
+ ensure(keylen > 0);
+ ensure(extlen == 8);
+ break;
+
+ case PROTOCOL_BINARY_CMD_DELETE:
+ case PROTOCOL_BINARY_CMD_DELETEQ:
+ ensure(extlen == 0);
+ ensure(keylen > 0);
+ ensure(keylen == bodylen);
+ break;
+
+ case PROTOCOL_BINARY_CMD_INCREMENT:
+ case PROTOCOL_BINARY_CMD_INCREMENTQ:
+ case PROTOCOL_BINARY_CMD_DECREMENT:
+ case PROTOCOL_BINARY_CMD_DECREMENTQ:
+ ensure(extlen == 20);
+ ensure(keylen > 0);
+ ensure(keylen + extlen == bodylen);
+ break;
+
+ case PROTOCOL_BINARY_CMD_QUIT:
+ case PROTOCOL_BINARY_CMD_QUITQ:
+ case PROTOCOL_BINARY_CMD_NOOP:
+ case PROTOCOL_BINARY_CMD_VERSION:
+ ensure(extlen == 0);
+ ensure(keylen == 0);
+ ensure(bodylen == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_FLUSH:
+ case PROTOCOL_BINARY_CMD_FLUSHQ:
+ ensure(extlen == 0 || extlen == 4);
+ ensure(keylen == 0);
+ ensure(bodylen == extlen);
+ break;
+
+ case PROTOCOL_BINARY_CMD_STAT:
+ ensure(extlen == 0);
+ /* May have key, but not value */
+ ensure(keylen == bodylen);
+ break;
+
+ case PROTOCOL_BINARY_CMD_APPEND:
+ case PROTOCOL_BINARY_CMD_APPENDQ:
+ case PROTOCOL_BINARY_CMD_PREPEND:
+ case PROTOCOL_BINARY_CMD_PREPENDQ:
+ ensure(extlen == 0);
+ ensure(keylen > 0);
+ break;
+ default:
+ /* Unknown command */
+ ;
+ }
+
+ return true;
+}
+
+bool memcached_binary_protocol_pedantic_check_response(const protocol_binary_request_header *request,
+ const protocol_binary_response_header *response)
+{
+ ensure(response->response.magic == PROTOCOL_BINARY_RES);
+ ensure(response->response.datatype == PROTOCOL_BINARY_RAW_BYTES);
+ ensure(response->response.opaque == request->request.opaque);
+
+ uint16_t status= ntohs(response->response.status);
+ uint8_t opcode= response->response.opcode;
+
+ if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS)
+ {
+ switch (opcode) {
+ case PROTOCOL_BINARY_CMD_ADDQ:
+ case PROTOCOL_BINARY_CMD_APPENDQ:
+ case PROTOCOL_BINARY_CMD_DECREMENTQ:
+ case PROTOCOL_BINARY_CMD_DELETEQ:
+ case PROTOCOL_BINARY_CMD_FLUSHQ:
+ case PROTOCOL_BINARY_CMD_INCREMENTQ:
+ case PROTOCOL_BINARY_CMD_PREPENDQ:
+ case PROTOCOL_BINARY_CMD_QUITQ:
+ case PROTOCOL_BINARY_CMD_REPLACEQ:
+ case PROTOCOL_BINARY_CMD_SETQ:
+ /* Quiet command shouldn't return on success */
+ return false;
+ default:
+ break;
+ }
+
+ switch (opcode) {
+ case PROTOCOL_BINARY_CMD_ADD:
+ case PROTOCOL_BINARY_CMD_REPLACE:
+ case PROTOCOL_BINARY_CMD_SET:
+ case PROTOCOL_BINARY_CMD_APPEND:
+ case PROTOCOL_BINARY_CMD_PREPEND:
+ ensure(response->response.keylen == 0);
+ ensure(response->response.extlen == 0);
+ ensure(response->response.bodylen == 0);
+ ensure(response->response.cas != 0);
+ break;
+ case PROTOCOL_BINARY_CMD_FLUSH:
+ case PROTOCOL_BINARY_CMD_NOOP:
+ case PROTOCOL_BINARY_CMD_QUIT:
+ case PROTOCOL_BINARY_CMD_DELETE:
+ ensure(response->response.keylen == 0);
+ ensure(response->response.extlen == 0);
+ ensure(response->response.bodylen == 0);
+ ensure(response->response.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_DECREMENT:
+ case PROTOCOL_BINARY_CMD_INCREMENT:
+ ensure(response->response.keylen == 0);
+ ensure(response->response.extlen == 0);
+ ensure(ntohl(response->response.bodylen) == 8);
+ ensure(response->response.cas != 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_STAT:
+ ensure(response->response.extlen == 0);
+ /* key and value exists in all packets except in the terminating */
+ ensure(response->response.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_VERSION:
+ ensure(response->response.keylen == 0);
+ ensure(response->response.extlen == 0);
+ ensure(response->response.bodylen != 0);
+ ensure(response->response.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_GET:
+ case PROTOCOL_BINARY_CMD_GETQ:
+ ensure(response->response.keylen == 0);
+ ensure(response->response.extlen == 4);
+ ensure(response->response.cas != 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_GETK:
+ case PROTOCOL_BINARY_CMD_GETKQ:
+ ensure(response->response.keylen != 0);
+ ensure(response->response.extlen == 4);
+ ensure(response->response.cas != 0);
+ break;
+
+ default:
+ /* Undefined command code */
+ break;
+ }
+ }
+ else
+ {
+ ensure(response->response.cas == 0);
+ ensure(response->response.extlen == 0);
+ if (opcode != PROTOCOL_BINARY_CMD_GETK)
+ {
+ ensure(response->response.keylen == 0);
+ }
+ }
+
+ return true;
+}
--- /dev/null
+
+add_library(libmemcachedutil SHARED
+ ../libmemcached/backtrace.cc
+ flush.cc
+ pid.cc
+ ping.cc
+ pool.cc
+ version.cc
+ )
+add_library(memcachedutil ALIAS libmemcachedutil)
+set_target_properties(libmemcachedutil PROPERTIES LIBRARY_OUTPUT_NAME memcachedutil)
+target_compile_definitions(libmemcachedutil PRIVATE -DBUILDING_LIBMEMCACHED)
+target_link_libraries(libmemcachedutil libmemcached Threads::Threads)
+
+set_target_properties(libmemcachedutil PROPERTIES SOVERSION ${LIBMEMCACHEDUTIL_SO_VERSION})
+install(TARGETS libmemcachedutil EXPORT libmemcachedutil
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+export(EXPORT libmemcachedutil)
+install(EXPORT libmemcachedutil DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake)
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached Utility library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Summary: connects to a host, and then flushes it (memcached_flush(3)).
+ *
+ */
+
+#pragma once
+
+#include "mem_config.h"
+
+#include <cstddef>
+#include <cstdlib>
+#include <cstdio>
+
+#include "libmemcachedutil-1.0/util.h"
+#include "libmemcached/assert.hpp"
+#include "libmemcached/backtrace.hpp"
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Summary: connects to a host, and then flushes it (memcached_flush(3)).
+ *
+ */
+
+#include <libmemcachedutil/common.h>
+
+
+bool libmemcached_util_flush(const char *hostname, in_port_t port, memcached_return_t *ret)
+{
+ memcached_st *memc_ptr= memcached_create(NULL);
+
+ memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
+ if (memcached_success(rc))
+ {
+ rc= memcached_flush(memc_ptr, 0);
+ }
+
+ memcached_free(memc_ptr);
+
+ if (ret)
+ {
+ *ret= rc;
+ }
+
+ return memcached_success(rc);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Summary: connects to a host, and determines what its pid is
+ *
+ */
+
+#include <libmemcachedutil/common.h>
+
+
+// Never look at the stat object directly.
+
+
+pid_t libmemcached_util_getpid(const char *hostname, in_port_t port, memcached_return_t *ret)
+{
+ pid_t pid= -1;
+
+ memcached_return_t unused;
+ if (ret == NULL)
+ {
+ ret= &unused;
+ }
+
+ memcached_st *memc_ptr= memcached_create(NULL);
+ if (memc_ptr == NULL)
+ {
+ *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return -1;
+ }
+
+ memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
+ if (memcached_success(rc))
+ {
+ memcached_stat_st *stat= memcached_stat(memc_ptr, NULL, &rc);
+ if (memcached_success(rc) and stat and stat->pid != -1)
+ {
+ pid= stat->pid;
+ }
+ else if (memcached_success(rc))
+ {
+ rc= MEMCACHED_UNKNOWN_STAT_KEY; // Something went wrong if this happens
+ }
+ else if (rc == MEMCACHED_SOME_ERRORS) // Generic answer, we will now find the specific reason (if one exists)
+ {
+ const memcached_instance_st * instance= memcached_server_instance_by_position(memc_ptr, 0);
+
+ assert_msg(instance and memcached_server_error(instance), " ");
+ if (instance and memcached_server_error(instance))
+ {
+ rc= memcached_server_error_return(instance);
+ }
+ }
+
+ memcached_stat_free(memc_ptr, stat);
+ }
+ memcached_free(memc_ptr);
+
+ *ret= rc;
+
+ return pid;
+}
+
+pid_t libmemcached_util_getpid2(const char *hostname, in_port_t port, const char *username, const char *password, memcached_return_t *ret)
+{
+ if (username == NULL)
+ {
+ return libmemcached_util_getpid(hostname, port, ret);
+ }
+
+ pid_t pid= -1;
+
+ memcached_return_t unused;
+ if (not ret)
+ ret= &unused;
+
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ *ret= MEMCACHED_NOT_SUPPORTED;
+ return pid;
+ }
+
+ memcached_st *memc_ptr= memcached_create(NULL);
+ if (not memc_ptr)
+ {
+ *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return -1;
+ }
+
+ if (memcached_failed(*ret= memcached_set_sasl_auth_data(memc_ptr, username, password)))
+ {
+ memcached_free(memc_ptr);
+ return false;
+ }
+
+
+ memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
+ if (memcached_success(rc))
+ {
+ memcached_stat_st *stat= memcached_stat(memc_ptr, NULL, &rc);
+ if (memcached_success(rc) and stat and stat->pid != -1)
+ {
+ pid= stat->pid;
+ }
+ else if (memcached_success(rc))
+ {
+ rc= MEMCACHED_UNKNOWN_STAT_KEY; // Something went wrong if this happens
+ }
+ else if (rc == MEMCACHED_SOME_ERRORS) // Generic answer, we will now find the specific reason (if one exists)
+ {
+ const memcached_instance_st * instance=
+ memcached_server_instance_by_position(memc_ptr, 0);
+
+#if 0
+ assert_msg(instance and instance->error_messages, " ");
+#endif
+ if (instance and memcached_server_error(instance))
+ {
+ rc= memcached_server_error_return(instance);
+ }
+ }
+
+ memcached_stat_free(memc_ptr, stat);
+ }
+ memcached_free(memc_ptr);
+
+ *ret= rc;
+
+ return pid;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Summary: connects to a host, and makes sure it is alive.
+ *
+ */
+
+#include <libmemcachedutil/common.h>
+
+bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret)
+{
+ memcached_return_t unused;
+ if (ret == NULL)
+ {
+ ret= &unused;
+ }
+
+ memcached_st *memc_ptr= memcached_create(NULL);
+ if (memc_ptr == NULL)
+ {
+ *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return false;
+ }
+
+ if (memcached_success((*ret= memcached_behavior_set(memc_ptr, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, 400000))))
+ {
+ memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
+ if (memcached_success(rc))
+ {
+ rc= memcached_version(memc_ptr);
+ }
+
+ if (memcached_failed(rc) and rc == MEMCACHED_SOME_ERRORS)
+ {
+ const memcached_instance_st * instance=
+ memcached_server_instance_by_position(memc_ptr, 0);
+
+ assert_msg(instance and memcached_server_error(instance), " ");
+ if (instance and memcached_server_error(instance))
+ {
+ rc= memcached_server_error_return(instance);
+ }
+ }
+
+ *ret= rc;
+ }
+ memcached_free(memc_ptr);
+
+ return memcached_success(*ret);
+}
+
+bool libmemcached_util_ping2(const char *hostname, in_port_t port, const char *username, const char *password, memcached_return_t *ret)
+{
+ if (username == NULL)
+ {
+ return libmemcached_util_ping(hostname, port, ret);
+ }
+
+ memcached_return_t unused;
+ if (not ret)
+ ret= &unused;
+
+ if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
+ {
+ *ret= MEMCACHED_NOT_SUPPORTED;
+ return false;
+ }
+
+ memcached_st *memc_ptr= memcached_create(NULL);
+ if (not memc_ptr)
+ {
+ *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return false;
+ }
+
+ if (memcached_failed(*ret= memcached_set_sasl_auth_data(memc_ptr, username, password)))
+ {
+ memcached_free(memc_ptr);
+ return false;
+ }
+
+ memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port);
+ if (memcached_success(rc))
+ {
+ rc= memcached_version(memc_ptr);
+ }
+
+ if (memcached_failed(rc) and rc == MEMCACHED_SOME_ERRORS)
+ {
+ const memcached_instance_st * instance=
+ memcached_server_instance_by_position(memc_ptr, 0);
+
+ assert_msg(instance and memcached_server_error(instance), " ");
+ if (instance and memcached_server_error(instance))
+ {
+ rc= memcached_server_error_return(instance);
+ }
+ }
+ memcached_free(memc_ptr);
+
+ *ret= rc;
+
+ return memcached_success(rc);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcachedutil/common.h>
+
+#include <cassert>
+#include <cerrno>
+#include <pthread.h>
+#include <memory>
+
+struct memcached_pool_st
+{
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ memcached_st *master;
+ memcached_st **server_pool;
+ int firstfree;
+ const uint32_t size;
+ uint32_t current_size;
+ bool _owns_master;
+ struct timespec _timeout;
+
+ memcached_pool_st(memcached_st *master_arg, size_t max_arg) :
+ master(master_arg),
+ server_pool(NULL),
+ firstfree(-1),
+ size(uint32_t(max_arg)),
+ current_size(0),
+ _owns_master(false)
+ {
+ pthread_mutex_init(&mutex, NULL);
+ pthread_cond_init(&cond, NULL);
+ _timeout.tv_sec= 5;
+ _timeout.tv_nsec= 0;
+ }
+
+ const struct timespec& timeout() const
+ {
+ return _timeout;
+ }
+
+ bool release(memcached_st*, memcached_return_t& rc);
+
+ memcached_st *fetch(memcached_return_t& rc);
+ memcached_st *fetch(const struct timespec&, memcached_return_t& rc);
+
+ bool init(uint32_t initial);
+
+ ~memcached_pool_st()
+ {
+ for (int x= 0; x <= firstfree; ++x)
+ {
+ memcached_free(server_pool[x]);
+ server_pool[x]= NULL;
+ }
+
+ int error;
+ if ((error= pthread_mutex_destroy(&mutex)) != 0)
+ {
+ assert_vmsg(error != 0, "pthread_mutex_destroy() %s(%d)", strerror(error), error);
+ }
+
+ if ((error= pthread_cond_destroy(&cond)) != 0)
+ {
+ assert_vmsg(error != 0, "pthread_cond_destroy() %s", strerror(error));
+ }
+
+ delete [] server_pool;
+ if (_owns_master)
+ {
+ memcached_free(master);
+ }
+ }
+
+ void increment_version()
+ {
+ ++master->configure.version;
+ }
+
+ bool compare_version(const memcached_st *arg) const
+ {
+ return (arg->configure.version == version());
+ }
+
+ int32_t version() const
+ {
+ return master->configure.version;
+ }
+};
+
+
+/**
+ * Grow the connection pool by creating a connection structure and clone the
+ * original memcached handle.
+ */
+static bool grow_pool(memcached_pool_st* pool)
+{
+ assert(pool);
+
+ memcached_st *obj;
+ if (not (obj= memcached_clone(NULL, pool->master)))
+ {
+ return false;
+ }
+
+ pool->server_pool[++pool->firstfree]= obj;
+ pool->current_size++;
+ obj->configure.version= pool->version();
+
+ return true;
+}
+
+bool memcached_pool_st::init(uint32_t initial)
+{
+ server_pool= new (std::nothrow) memcached_st *[size];
+ if (server_pool == NULL)
+ {
+ return false;
+ }
+
+ /*
+ Try to create the initial size of the pool. An allocation failure at
+ this time is not fatal..
+ */
+ for (unsigned int x= 0; x < initial; ++x)
+ {
+ if (grow_pool(this) == false)
+ {
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+static inline memcached_pool_st *_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
+{
+ if (initial == 0 or max == 0 or (initial > max))
+ {
+ return NULL;
+ }
+
+ memcached_pool_st *object= new (std::nothrow) memcached_pool_st(master, max);
+ if (object == NULL)
+ {
+ return NULL;
+ }
+
+ /*
+ Try to create the initial size of the pool. An allocation failure at
+ this time is not fatal..
+ */
+ if (not object->init(initial))
+ {
+ delete object;
+ return NULL;
+ }
+
+ return object;
+}
+
+memcached_pool_st *memcached_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
+{
+ return _pool_create(master, initial, max);
+}
+
+memcached_pool_st * memcached_pool(const char *option_string, size_t option_string_length)
+{
+ memcached_st *memc= memcached(option_string, option_string_length);
+
+ if (memc == NULL)
+ {
+ return NULL;
+ }
+
+ memcached_pool_st *self= memcached_pool_create(memc, memc->configure.initial_pool_size, memc->configure.max_pool_size);
+ if (self == NULL)
+ {
+ memcached_free(memc);
+ return NULL;
+ }
+
+ self->_owns_master= true;
+
+ return self;
+}
+
+memcached_st* memcached_pool_destroy(memcached_pool_st* pool)
+{
+ if (pool == NULL)
+ {
+ return NULL;
+ }
+
+ // Legacy that we return the original structure
+ memcached_st *ret= NULL;
+ if (pool->_owns_master)
+ { }
+ else
+ {
+ ret= pool->master;
+ }
+
+ delete pool;
+
+ return ret;
+}
+
+memcached_st* memcached_pool_st::fetch(memcached_return_t& rc)
+{
+ static struct timespec relative_time= { 0, 0 };
+ return fetch(relative_time, rc);
+}
+
+memcached_st* memcached_pool_st::fetch(const struct timespec& relative_time, memcached_return_t& rc)
+{
+ rc= MEMCACHED_SUCCESS;
+
+ int error;
+ if ((error= pthread_mutex_lock(&mutex)) != 0)
+ {
+ rc= MEMCACHED_IN_PROGRESS;
+ return NULL;
+ }
+
+ memcached_st *ret= NULL;
+ do
+ {
+ if (firstfree > -1)
+ {
+ ret= server_pool[firstfree--];
+ }
+ else if (current_size == size)
+ {
+ if (relative_time.tv_sec == 0 and relative_time.tv_nsec == 0)
+ {
+ error= pthread_mutex_unlock(&mutex);
+ rc= MEMCACHED_NOTFOUND;
+
+ return NULL;
+ }
+
+ struct timespec time_to_wait= {0, 0};
+ time_to_wait.tv_sec= time(NULL) +relative_time.tv_sec;
+ time_to_wait.tv_nsec= relative_time.tv_nsec;
+
+ int thread_ret;
+ if ((thread_ret= pthread_cond_timedwait(&cond, &mutex, &time_to_wait)) != 0)
+ {
+ int unlock_error;
+ if ((unlock_error= pthread_mutex_unlock(&mutex)) != 0)
+ {
+ assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
+ }
+
+ if (thread_ret == ETIMEDOUT)
+ {
+ rc= MEMCACHED_TIMEOUT;
+ }
+ else
+ {
+ errno= thread_ret;
+ rc= MEMCACHED_ERRNO;
+ }
+
+ return NULL;
+ }
+ }
+ else if (grow_pool(this) == false)
+ {
+ int unlock_error;
+ if ((unlock_error= pthread_mutex_unlock(&mutex)) != 0)
+ {
+ assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
+ }
+
+ return NULL;
+ }
+ } while (ret == NULL);
+
+ if ((error= pthread_mutex_unlock(&mutex)) != 0)
+ {
+ assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
+ }
+
+ return ret;
+}
+
+bool memcached_pool_st::release(memcached_st *released, memcached_return_t& rc)
+{
+ rc= MEMCACHED_SUCCESS;
+ if (released == NULL)
+ {
+ rc= MEMCACHED_INVALID_ARGUMENTS;
+ return false;
+ }
+
+ int error;
+ if ((error= pthread_mutex_lock(&mutex)))
+ {
+ rc= MEMCACHED_IN_PROGRESS;
+ return false;
+ }
+
+ /*
+ Someone updated the behavior on the object, so we clone a new memcached_st with the new settings. If we fail to clone, we keep the old one around.
+ */
+ if (compare_version(released) == false)
+ {
+ memcached_st *memc;
+ if ((memc= memcached_clone(NULL, master)))
+ {
+ memcached_free(released);
+ released= memc;
+ }
+ }
+
+ server_pool[++firstfree]= released;
+
+ if (firstfree == 0 and current_size == size)
+ {
+ /* we might have people waiting for a connection.. wake them up :-) */
+ if ((error= pthread_cond_broadcast(&cond)) != 0)
+ {
+ assert_vmsg(error != 0, "pthread_cond_broadcast() %s", strerror(error));
+ }
+ }
+
+ if ((error= pthread_mutex_unlock(&mutex)) != 0)
+ {
+ }
+
+ return true;
+}
+
+memcached_st* memcached_pool_fetch(memcached_pool_st* pool, struct timespec* relative_time, memcached_return_t* rc)
+{
+ if (pool == NULL)
+ {
+ return NULL;
+ }
+
+ memcached_return_t unused;
+ if (rc == NULL)
+ {
+ rc= &unused;
+ }
+
+ if (relative_time == NULL)
+ {
+ return pool->fetch(*rc);
+ }
+
+ return pool->fetch(*relative_time, *rc);
+}
+
+memcached_st* memcached_pool_pop(memcached_pool_st* pool,
+ bool block,
+ memcached_return_t *rc)
+{
+ if (pool == NULL)
+ {
+ return NULL;
+ }
+
+ memcached_return_t unused;
+ if (rc == NULL)
+ {
+ rc= &unused;
+ }
+
+ memcached_st *memc;
+ if (block)
+ {
+ memc= pool->fetch(pool->timeout(), *rc);
+ }
+ else
+ {
+ memc= pool->fetch(*rc);
+ }
+
+ return memc;
+}
+
+memcached_return_t memcached_pool_release(memcached_pool_st* pool, memcached_st *released)
+{
+ if (pool == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ memcached_return_t rc;
+
+ (void) pool->release(released, rc);
+
+ return rc;
+}
+
+memcached_return_t memcached_pool_push(memcached_pool_st* pool, memcached_st *released)
+{
+ return memcached_pool_release(pool, released);
+}
+
+
+memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool,
+ memcached_behavior_t flag,
+ uint64_t data)
+{
+ if (pool == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ int error;
+ if ((error= pthread_mutex_lock(&pool->mutex)))
+ {
+ return MEMCACHED_IN_PROGRESS;
+ }
+
+ /* update the master */
+ memcached_return_t rc= memcached_behavior_set(pool->master, flag, data);
+ if (memcached_failed(rc))
+ {
+ if ((error= pthread_mutex_unlock(&pool->mutex)) != 0)
+ {
+ assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
+ }
+ return rc;
+ }
+
+ pool->increment_version();
+ /* update the clones */
+ for (int xx= 0; xx <= pool->firstfree; ++xx)
+ {
+ if (memcached_success(memcached_behavior_set(pool->server_pool[xx], flag, data)))
+ {
+ pool->server_pool[xx]->configure.version= pool->version();
+ }
+ else
+ {
+ memcached_st *memc;
+ if ((memc= memcached_clone(NULL, pool->master)))
+ {
+ memcached_free(pool->server_pool[xx]);
+ pool->server_pool[xx]= memc;
+ /* 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....
+ */
+ }
+ }
+ }
+
+ if ((error= pthread_mutex_unlock(&pool->mutex)) != 0)
+ {
+ assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool,
+ memcached_behavior_t flag,
+ uint64_t *value)
+{
+ if (pool == NULL)
+ {
+ return MEMCACHED_INVALID_ARGUMENTS;
+ }
+
+ int error;
+ if ((error= pthread_mutex_lock(&pool->mutex)))
+ {
+ return MEMCACHED_IN_PROGRESS;
+ }
+
+ *value= memcached_behavior_get(pool->master, flag);
+
+ if ((error= pthread_mutex_unlock(&pool->mutex)) != 0)
+ {
+ assert_vmsg(error != 0, "pthread_mutex_unlock() %s", strerror(error));
+ }
+
+ return MEMCACHED_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcachedutil/common.h>
+#include <cassert>
+
+struct local_context
+{
+ uint8_t major_version;
+ uint8_t minor_version;
+ uint8_t micro_version;
+
+ bool truth;
+};
+
+static memcached_return_t check_server_version(const memcached_st *,
+ const memcached_instance_st * instance,
+ void *context)
+{
+ /* Do Nothing */
+ struct local_context *check= (struct local_context *)context;
+
+ if (memcached_server_major_version(instance) != UINT8_MAX) {
+ uint32_t sv, cv;
+
+ sv = memcached_server_micro_version(instance)
+ |memcached_server_minor_version(instance) << 8
+ |memcached_server_major_version(instance) << 16
+ ;
+ cv = check->micro_version
+ |check->minor_version << 8
+ |check->major_version << 16;
+
+ if (sv >= cv) {
+ return MEMCACHED_SUCCESS;
+ }
+ }
+
+ check->truth= false;
+
+ return MEMCACHED_FAILURE;
+}
+
+bool libmemcached_util_version_check(memcached_st *memc,
+ uint8_t major_version,
+ uint8_t minor_version,
+ uint8_t micro_version)
+{
+ if (memcached_failed(memcached_version(memc)))
+ {
+ return false;
+ }
+
+ struct local_context check= { major_version, minor_version, micro_version, true };
+
+ memcached_server_fn callbacks[1];
+ callbacks[0]= check_server_version;
+ memcached_server_cursor(memc, callbacks, (void *)&check, 1);
+
+ return check.truth;
+}
--- /dev/null
+
+file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/tmp_chroot)
+file(WRITE ${CMAKE_BINARY_DIR}/libtool
+"#!/bin/bash
+shift
+exec $@
+")
+if(UNIX)
+ if(EXISTS ${CMAKE_BINARY_DIR}/libtool)
+ execute_process(COMMAND chmod +x ${CMAKE_BINARY_DIR}/libtool)
+ endif()
+endif()
+
+add_library(libtest STATIC
+ alarm.cc
+ binaries.cc
+ client.cc
+ cmdline.cc
+ collection.cc
+ comparison.cc
+ core.cc
+ cpu.cc
+ dns.cc
+ dream.cc
+ drizzled.cc
+ exception.cc
+ exception/fatal.cc
+ formatter.cc
+ framework.cc
+ gearmand.cc
+ has.cc
+ http.cc
+ is_local.cc
+ killpid.cc
+ libtool.cc
+ main.cc
+ memcached.cc
+ port.cc
+ result.cc
+ runner.cc
+ server.cc
+ server_container.cc
+ signal.cc
+ socket.cc
+ strerror.cc
+ timer.cc
+ tmpfile.cc
+ vchar.cc
+ )
+set_target_properties(libtest PROPERTIES LIBRARY_OUTPUT_NAME test)
+target_compile_definitions(libtest PRIVATE
+ BUILDING_LIBTEST=1
+ LIBTEST_TEMP=\"${CMAKE_BINARY_DIR}/tmp_chroot\"
+
+ DRIZZLED_BINARY=\"drizzled\"
+ GEARMAND_BINARY=\"gearmand\"
+ MEMCACHED_BINARY=\"${MEMCACHED_BINARY}\"
+ HAVE_MEMCACHED_BINARY=1
+ )
+target_link_libraries(libtest PRIVATE Threads::Threads ${CMAKE_DL_LIBS})
+
+add_executable(wait wait.cc dream.cc)
+
+add_executable(core_count core_count.cc cpu.cc)
+
+add_executable(backtrace backtrace_test.cc ../libmemcached/backtrace.cc)
+target_link_libraries(backtrace PRIVATE ${CMAKE_DL_LIBS})
+
+configure_file(yatlcon.h.in yatlcon.h @ONLY)
+configure_file(version.h.in version.h @ONLY)
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/common.h>
+
+#include <sys/time.h>
+#include <cstdlib>
+
+namespace libtest {
+
+static const struct timeval default_it_value= { 600, 0 };
+static const struct timeval default_it_interval= { 0, 0 };
+static const struct itimerval defualt_timer= { default_it_interval, default_it_value };
+
+static const struct itimerval cancel_timer= { default_it_interval, default_it_interval };
+
+
+void set_alarm()
+{
+ if (setitimer(ITIMER_VIRTUAL, &defualt_timer, NULL) == -1)
+ {
+ Error << "setitimer() failed";
+ }
+}
+
+void set_alarm(long tv_sec, long tv_usec)
+{
+ // For the moment use any value to YATL_ALARM to cancel alarming.
+ if (getenv("YATL_ALARM"))
+ {
+ errno= 0;
+ tv_sec= strtol(getenv("YATL_ALARM"), (char **) NULL, 10);
+
+ if (errno != 0)
+ {
+ FATAL("Bad value for YATL_ALARM");
+ }
+ else if (tv_sec == 0)
+ {
+ cancel_alarm();
+ }
+ }
+
+#ifdef __APPLE__
+ struct timeval it_value= { time_t(tv_sec), suseconds_t(tv_usec) };
+#else
+ struct timeval it_value= { tv_sec, tv_usec };
+#endif
+
+ struct itimerval timer= { default_it_interval, it_value };
+
+ if (setitimer(ITIMER_VIRTUAL, &timer, NULL) == -1)
+ {
+ Error << "setitimer() failed";
+ }
+}
+
+void cancel_alarm()
+{
+ if (setitimer(ITIMER_VIRTUAL, &cancel_timer, NULL) == -1)
+ {
+ Error << "setitimer() failed";
+ }
+}
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+void set_alarm(long tv_sec, long tv_usec);
+void set_alarm();
+void cancel_alarm();
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <cerrno>
+#include <csignal>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+#include "libmemcached/backtrace.hpp"
+
+class Test {
+public:
+ Test()
+ {
+ }
+
+ void call_backtrace()
+ {
+ std::cerr << __func__ << std::endl;
+ custom_backtrace();
+ }
+};
+
+void SIGSEGV_handler(int sig_num, siginfo_t* info, void* ucontext)
+{
+ std::cerr << __func__ << std::endl;
+ (void)sig_num;
+ (void)info;
+ (void)ucontext;
+
+ custom_backtrace();
+}
+
+int raise_SIGSEGV()
+{
+ std::cerr << std::endl << "Calling backtrace()" << std::endl;
+ custom_backtrace();
+ std::cerr << std::endl << "Calling raise()" << std::endl;
+ return raise(SIGSEGV);
+}
+
+int layer4()
+{
+ return raise_SIGSEGV();
+}
+
+int layer3()
+{
+ return layer4();
+}
+
+int layer2()
+{
+ return layer3();
+}
+
+int layer1()
+{
+ return layer2();
+}
+
+int main(int, char **)
+{
+ Test t;
+
+ t.call_backtrace();
+
+ struct sigaction sigact;
+
+ sigact.sa_sigaction= SIGSEGV_handler;
+ sigact.sa_flags= SA_RESTART | SA_SIGINFO;
+
+ if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) != 0)
+ {
+ std::cerr << "error setting signal handler for " << strsignal(SIGSEGV) << "(" << SIGSEGV << ")" << std::endl;
+
+ exit(EXIT_FAILURE);
+ }
+
+ int ret= layer1();
+ if (ret)
+ {
+ std::cerr << "raise() " << strerror(errno) << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+namespace libtest {
+
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <libtest/blobslap_worker.h>
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+namespace libtest {
+
+class BlobslapWorker : public Server
+{
+private:
+public:
+ BlobslapWorker(in_port_t port_arg) :
+ Server("localhost", port_arg, "benchmark/blobslap_worker", true)
+ {
+ set_pid_file();
+ }
+
+ pid_t get_pid(bool error_is_ok)
+ {
+ if (pid_file().empty())
+ {
+ Error << "pid_file was empty";
+ return -1;
+ }
+
+ Wait wait(pid_file(), 0);
+
+ if (error_is_ok and not wait.successful())
+ {
+ Error << "Pidfile was not found:" << pid_file();
+ return -1;
+ }
+
+ std::stringstream error_message;
+ pid_t ret= get_pid_from_file(pid_file(), error_message);
+
+ if (error_is_ok and is_pid_valid(ret) == false)
+ {
+ Error << error_message.str();
+ }
+
+ return ret;
+ }
+
+ bool ping()
+ {
+ if (pid_file().empty())
+ {
+ Error << "No pid file available";
+ return false;
+ }
+
+ Wait wait(pid_file(), 0);
+ if (not wait.successful())
+ {
+ Error << "Pidfile was not found:" << pid_file();
+ return false;
+ }
+
+ std::stringstream error_message;
+ pid_t local_pid= get_pid_from_file(pid_file(), error_message);
+ if (is_pid_valid(local_pid) == false)
+ {
+ Error << error_message.str();
+ return false;
+ }
+
+ // Use kill to determine is the process exist
+ if (::kill(local_pid, 0) == 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ const char *name()
+ {
+ return "blobslap_worker";
+ };
+
+ bool has_port_option() const
+ {
+ return true;
+ }
+
+ bool has_log_file_option() const
+ {
+ return true;
+ }
+
+ bool is_libtool()
+ {
+ return true;
+ }
+
+ bool build();
+};
+
+
+#include <sstream>
+
+bool BlobslapWorker::build()
+{
+ return true;
+}
+
+Server *build_blobslap_worker(in_port_t try_port)
+{
+ return new BlobslapWorker(try_port);
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+Server *build_blobslap_worker(in_port_t try_port);
+
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* (test_callback_create_fn)(libtest::server_startup_st&, test_return_t&);
+typedef bool test_callback_destroy_fn(void *);
+typedef enum test_return_t (test_callback_fn)(void *);
+typedef enum test_return_t (test_callback_runner_fn)(test_callback_fn*, void *);
+typedef enum test_return_t (test_callback_error_fn)(const test_return_t, void *);
+
+#ifdef __cplusplus
+}
+#endif
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <string>
+
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#endif
+
+#ifndef HAVE_MSG_NOSIGNAL
+# define MSG_NOSIGNAL 0
+#endif
+
+namespace libtest {
+
+SimpleClient::SimpleClient(const std::string& hostname_, in_port_t port_) :
+ _is_connected(false),
+ _hostname(hostname_),
+ _port(port_),
+ sock_fd(INVALID_SOCKET),
+ requested_message(1)
+ {
+ }
+
+bool SimpleClient::ready(int event_)
+{
+ struct pollfd fds[1];
+ fds[0].fd= sock_fd;
+ fds[0].events= event_;
+ fds[0].revents= 0;
+
+ int timeout= 5000;
+ if (_is_connected == false)
+ {
+ timeout= timeout * 30;
+ }
+
+ int ready_fds= poll(fds, 1, timeout);
+
+ if (ready_fds == -1)
+ {
+ _error= strerror(errno);
+ return false;
+ }
+ else if (ready_fds == 1)
+ {
+ if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL))
+ {
+ int err;
+ socklen_t len= sizeof (err);
+ // We replace errno with err if getsockopt() passes, but err has been
+ // set.
+ if (getsockopt(fds[0].fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0)
+ {
+ // We check the value to see what happened wth the socket.
+ if (err == 0)
+ {
+ _error= "getsockopt() returned no error but poll() indicated one existed";
+ return false;
+ }
+ errno= err;
+ }
+ _error= strerror(errno);
+
+ return false;
+ }
+
+ _is_connected= true;
+ if (fds[0].revents & event_)
+ {
+ return true;
+ }
+ }
+
+ fatal_assert(ready_fds == 0);
+ _error= "TIMEOUT";
+
+ return false;
+}
+
+struct addrinfo* SimpleClient::lookup()
+{
+ struct addrinfo *ai= NULL;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_socktype= SOCK_STREAM;
+ hints.ai_protocol= IPPROTO_TCP;
+
+ libtest::vchar_t service;
+ service.resize(NI_MAXSERV);
+ (void)snprintf(&service[0], service.size(), "%d", _port);
+
+ int getaddrinfo_error;
+ if ((getaddrinfo_error= getaddrinfo(_hostname.c_str(), &service[0], &hints, &ai)) != 0)
+ {
+ if (getaddrinfo_error != EAI_SYSTEM)
+ {
+ _error= gai_strerror(getaddrinfo_error);
+ return NULL;
+ }
+ else
+ {
+ _error= strerror(getaddrinfo_error);
+ return NULL;
+ }
+ }
+
+ return ai;
+}
+
+SimpleClient::~SimpleClient()
+{
+ close_socket();
+}
+
+void SimpleClient::close_socket()
+{
+ if (sock_fd != INVALID_SOCKET)
+ {
+ close(sock_fd);
+ sock_fd= INVALID_SOCKET;
+ }
+}
+
+bool SimpleClient::instance_connect()
+{
+ _is_connected= false;
+ struct addrinfo *ai;
+ if ((ai= lookup()))
+ {
+ {
+ struct addrinfo* address_info_next= ai;
+
+ while (address_info_next and sock_fd == INVALID_SOCKET)
+ {
+ if ((sock_fd= socket(address_info_next->ai_family, address_info_next->ai_socktype, address_info_next->ai_protocol)) != SOCKET_ERROR)
+ {
+ if (connect(sock_fd, address_info_next->ai_addr, address_info_next->ai_addrlen) == SOCKET_ERROR)
+ {
+ switch (errno)
+ {
+ case EINTR:
+ close_socket();
+ continue;
+
+ case EINPROGRESS: // nonblocking mode - first return
+ case EALREADY: // nonblocking mode - subsequent returns
+ continue; // Jump to while() and continue on
+
+
+ case ECONNREFUSED:
+ default:
+ break;
+ }
+
+ close_socket();
+ _error= strerror(errno);
+ }
+ }
+ else
+ {
+ FATAL(strerror(errno));
+ }
+ address_info_next= address_info_next->ai_next;
+ }
+
+ freeaddrinfo(ai);
+ }
+
+ if (sock_fd == INVALID_SOCKET)
+ {
+ fatal_assert(_error.size());
+ }
+
+ return bool(sock_fd != INVALID_SOCKET);
+ }
+
+ return false;
+}
+
+bool SimpleClient::is_valid()
+{
+ _error.clear();
+ if (sock_fd == INVALID_SOCKET)
+ {
+ return instance_connect();
+ }
+
+ return true;
+}
+
+bool SimpleClient::message(const char* ptr, const size_t len)
+{
+ if (is_valid())
+ {
+ if (ready(POLLOUT))
+ {
+ off_t offset= 0;
+ do
+ {
+ ssize_t nw= send(sock_fd, ptr + offset, len - offset, MSG_NOSIGNAL);
+ if (nw == -1)
+ {
+ if (errno != EINTR)
+ {
+ _error= strerror(errno);
+ return false;
+ }
+ }
+ else
+ {
+ offset += nw;
+ }
+ } while (offset < ssize_t(len));
+
+ return true;
+ }
+ }
+
+ fatal_assert(_error.size());
+
+ return false;
+}
+
+bool SimpleClient::send_message(const std::string& arg)
+{
+ if (message(arg.c_str(), arg.size()) == true)
+ {
+ return message("\r\n", 2);
+ }
+
+ return false;
+}
+
+bool SimpleClient::send_data(const libtest::vchar_t& message_, libtest::vchar_t& response_)
+{
+ requested_message++;
+ if (message(&message_[0], message_.size()))
+ {
+ return response(response_);
+ }
+
+ return false;
+}
+
+bool SimpleClient::send_message(const std::string& message_, std::string& response_)
+{
+ requested_message++;
+ if (send_message(message_))
+ {
+ return response(response_);
+ }
+
+ return false;
+}
+
+bool SimpleClient::response(libtest::vchar_t& response_)
+{
+ response_.clear();
+
+ if (is_valid())
+ {
+ if (ready(POLLIN))
+ {
+ bool more= true;
+ char buffer[2];
+ buffer[1]= 0;
+ do
+ {
+ ssize_t nr= recv(sock_fd, buffer, 1, MSG_NOSIGNAL);
+ if (nr == -1)
+ {
+ if (errno != EINTR)
+ {
+ _error= strerror(errno);
+ return false;
+ }
+ }
+ else if (nr == 0)
+ {
+ close_socket();
+ more= false;
+ }
+ else
+ {
+ response_.reserve(response_.size() + nr +1);
+ fatal_assert(nr == 1);
+ if (buffer[0] == '\n')
+ {
+ more= false;
+ }
+ response_.insert(response_.end(), buffer, buffer +nr);
+ }
+ } while (more);
+
+ return response_.size();
+ }
+ }
+
+ fatal_assert(_error.size());
+ return false;
+}
+
+bool SimpleClient::response(std::string& response_)
+{
+ response_.clear();
+
+ if (is_valid())
+ {
+ if (ready(POLLIN))
+ {
+ bool more= true;
+ char buffer[2];
+ buffer[1]= 0;
+ do
+ {
+ ssize_t nr= recv(sock_fd, buffer, 1, MSG_NOSIGNAL);
+ if (nr == -1)
+ {
+ if (errno != EINTR)
+ {
+ _error= strerror(errno);
+ return false;
+ }
+ }
+ else if (nr == 0)
+ {
+ close_socket();
+ more= false;
+ }
+ else
+ {
+ fatal_assert(nr == 1);
+ if (buffer[0] == '\n')
+ {
+ more= false;
+ }
+ response_.append(buffer);
+ }
+ } while (more);
+
+ return response_.size();
+ }
+ }
+
+ fatal_assert(_error.size());
+ return false;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+class SimpleClient {
+public:
+ SimpleClient(const std::string& hostname_, in_port_t port_);
+ ~SimpleClient();
+
+ bool send_data(const libtest::vchar_t&, libtest::vchar_t&);
+ bool send_message(const std::string&);
+ bool send_message(const std::string&, std::string&);
+ bool response(std::string&);
+ bool response(libtest::vchar_t&);
+
+ bool is_valid();
+
+ const std::string& error() const
+ {
+ return _error;
+ }
+
+ bool is_error() const
+ {
+ return _error.size() ? true : false;
+ }
+
+private: // Methods
+ void close_socket();
+ bool instance_connect();
+ struct addrinfo* lookup();
+ bool message(const char* ptr, const size_t len);
+ bool ready(int event_);
+
+private:
+ bool _is_connected;
+ std::string _hostname;
+ in_port_t _port;
+ int sock_fd;
+ std::string _error;
+ int requested_message;
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include "libtest/common.h"
+
+using namespace libtest;
+
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <fcntl.h>
+#include <fstream>
+#include <memory>
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#endif
+#ifdef HAVE_SPAWN_H
+# include <spawn.h>
+#endif
+#include <sstream>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <stdexcept>
+
+#ifndef __USE_GNU
+static char **environ= NULL;
+#endif
+
+#ifndef FD_CLOEXEC
+# define FD_CLOEXEC 0
+#endif
+
+namespace {
+
+ std::string print_argv(libtest::vchar_ptr_t& built_argv)
+ {
+ std::stringstream arg_buffer;
+
+ for (vchar_ptr_t::iterator iter= built_argv.begin();
+ iter != built_argv.end();
+ ++iter)
+ {
+ if (*iter)
+ {
+ arg_buffer << *iter << " ";
+ }
+ }
+
+ return arg_buffer.str();
+ }
+
+#if 0
+ std::string print_argv(char** argv)
+ {
+ std::stringstream arg_buffer;
+
+ for (char** ptr= argv; *ptr; ++ptr)
+ {
+ arg_buffer << *ptr << " ";
+ }
+
+ return arg_buffer.str();
+ }
+#endif
+
+ static Application::error_t int_to_error_t(int arg)
+ {
+ switch (arg)
+ {
+ case 127:
+ return Application::INVALID_POSIX_SPAWN;
+
+ case 0:
+ return Application::SUCCESS;
+
+ case 1:
+ return Application::FAILURE;
+
+ default:
+ return Application::UNKNOWN;
+ }
+ }
+}
+
+namespace libtest {
+
+Application::Application(const std::string& arg, const bool _use_libtool_arg) :
+ _use_libtool(_use_libtool_arg),
+ _use_valgrind(false),
+ _use_gdb(false),
+ _use_ptrcheck(false),
+ _will_fail(false),
+ _argc(0),
+ _exectuble(arg),
+ stdin_fd(STDIN_FILENO),
+ stdout_fd(STDOUT_FILENO),
+ stderr_fd(STDERR_FILENO),
+ _pid(-1),
+ _status(0),
+ _app_exit_state(UNINITIALIZED)
+ {
+ if (_use_libtool)
+ {
+ if (libtool() == NULL)
+ {
+ FATAL("libtool requested, but no libtool was found");
+ }
+ }
+
+ // Find just the name of the application with no path
+ {
+ size_t found= arg.find_last_of("/\\");
+ if (found)
+ {
+ _exectuble_name= arg.substr(found +1);
+ }
+ else
+ {
+ _exectuble_name= arg;
+ }
+ }
+
+ if (_use_libtool and getenv("PWD"))
+ {
+ _exectuble_with_path+= getenv("PWD");
+ _exectuble_with_path+= "/";
+ }
+ _exectuble_with_path+= _exectuble;
+ }
+
+Application::~Application()
+{
+ murder();
+ delete_argv();
+}
+
+Application::error_t Application::run(const char *args[])
+{
+ stdin_fd.reset();
+ stdout_fd.reset();
+ stderr_fd.reset();
+ _stdout_buffer.clear();
+ _stderr_buffer.clear();
+
+ posix_spawn_file_actions_t file_actions;
+ posix_spawn_file_actions_init(&file_actions);
+
+ stdin_fd.dup_for_spawn(file_actions);
+ stdout_fd.dup_for_spawn(file_actions);
+ stderr_fd.dup_for_spawn(file_actions);
+
+ posix_spawnattr_t spawnattr;
+ posix_spawnattr_init(&spawnattr);
+
+ short flags= 0;
+
+ // Child should not block signals
+ flags |= POSIX_SPAWN_SETSIGMASK;
+
+ sigset_t mask;
+ sigemptyset(&mask);
+
+ fatal_assert(posix_spawnattr_setsigmask(&spawnattr, &mask) == 0);
+
+#if defined(POSIX_SPAWN_USEVFORK) || defined(__linux__)
+ // Use USEVFORK on linux
+ flags |= POSIX_SPAWN_USEVFORK;
+#endif
+
+ flags |= POSIX_SPAWN_SETPGROUP;
+ fatal_assert(posix_spawnattr_setpgroup(&spawnattr, 0) == 0);
+
+ fatal_assert(posix_spawnattr_setflags(&spawnattr, flags) == 0);
+
+ create_argv(args);
+
+ int spawn_ret;
+ if (_use_gdb)
+ {
+ std::string gdb_run_file= create_tmpfile(_exectuble_name);
+ std::fstream file_stream;
+ file_stream.open(gdb_run_file.c_str(), std::fstream::out | std::fstream::trunc);
+
+ _gdb_filename= create_tmpfile(_exectuble_name);
+ file_stream
+ << "set logging redirect on" << std::endl
+ << "set logging file " << _gdb_filename << std::endl
+ << "set logging overwrite on" << std::endl
+ << "set logging on" << std::endl
+ << "set environment LIBTEST_IN_GDB=1" << std::endl
+ << "run " << arguments() << std::endl
+ << "thread apply all bt" << std::endl
+ << "quit" << std::endl;
+
+ fatal_assert(file_stream.good());
+ file_stream.close();
+
+ if (_use_libtool)
+ {
+ // libtool --mode=execute gdb -f -x binary
+ char *argv[]= {
+ const_cast<char *>(libtool()),
+ const_cast<char *>("--mode=execute"),
+ const_cast<char *>("gdb"),
+ const_cast<char *>("-batch"),
+ const_cast<char *>("-f"),
+ const_cast<char *>("-x"),
+ const_cast<char *>(gdb_run_file.c_str()),
+ const_cast<char *>(_exectuble_with_path.c_str()),
+ 0};
+
+ spawn_ret= posix_spawnp(&_pid, libtool(), &file_actions, &spawnattr, argv, environ);
+ }
+ else
+ {
+ // gdb binary
+ char *argv[]= {
+ const_cast<char *>("gdb"),
+ const_cast<char *>("-batch"),
+ const_cast<char *>("-f"),
+ const_cast<char *>("-x"),
+ const_cast<char *>(gdb_run_file.c_str()),
+ const_cast<char *>(_exectuble_with_path.c_str()),
+ 0};
+ spawn_ret= posix_spawnp(&_pid, "gdb", &file_actions, &spawnattr, argv, environ);
+ }
+ }
+ else
+ {
+ spawn_ret= posix_spawn(&_pid, built_argv[0], &file_actions, &spawnattr, &built_argv[0], environ);
+ }
+
+ posix_spawn_file_actions_destroy(&file_actions);
+ posix_spawnattr_destroy(&spawnattr);
+
+ stdin_fd.close(Application::Pipe::READ);
+ stdout_fd.close(Application::Pipe::WRITE);
+ stderr_fd.close(Application::Pipe::WRITE);
+
+ if (spawn_ret != 0)
+ {
+ if (_will_fail == false)
+ {
+ std::string sb;
+ char buf[1024];
+
+ std::for_each(built_argv.begin(), built_argv.end()-1, [&sb](const char *a) {
+ if (sb.size()) {
+ sb.append(" ");
+ }
+ sb.append(a);
+ });
+ Error << strerror(spawn_ret) << "(" << spawn_ret << "): " << sb << " cwd:" << getcwd(buf, sizeof(buf)-1);
+ }
+ _pid= -1;
+ return Application::INVALID_POSIX_SPAWN;
+ }
+
+ assert(_pid != -1);
+ if (_pid == -1)
+ {
+ return Application::INVALID_POSIX_SPAWN;
+ }
+
+#if 0
+ app_thread_st* _app_thread= new app_thread_st(_pid, _status, built_argv[0], _app_exit_state);
+ int error;
+ if ((error= pthread_create(&_thread, NULL, &app_thread, _app_thread)) != 0)
+ {
+ Error << "pthread_create() died during pthread_create(" << strerror(error) << ")";
+ return Application::FAILURE;
+ }
+#endif
+
+ return Application::SUCCESS;
+}
+
+bool Application::check() const
+{
+ if (_pid > 1 and kill(_pid, 0) == 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void Application::murder()
+{
+ if (check())
+ {
+ int count= 5;
+ while ((count--) > 0 and check())
+ {
+ if (kill(_pid, SIGTERM) == 0)
+ {
+ join();
+ }
+ else
+ {
+ Error << "kill(pid, SIGTERM) failed after kill with error of " << strerror(errno);
+ continue;
+ }
+
+ break;
+ }
+
+ // If for whatever reason it lives, kill it hard
+ if (check())
+ {
+ Error << "using SIGKILL, things will likely go poorly from this point";
+ (void)kill(_pid, SIGKILL);
+ }
+ }
+ slurp();
+}
+
+// false means that no data was returned
+bool Application::slurp()
+{
+ struct pollfd fds[2];
+ fds[0].fd= stdout_fd.fd();
+ fds[0].events= POLLRDNORM;
+ fds[0].revents= 0;
+ fds[1].fd= stderr_fd.fd();
+ fds[1].events= POLLRDNORM;
+ fds[1].revents= 0;
+
+ int active_fd;
+ if ((active_fd= poll(fds, 2, 0)) == -1)
+ {
+ int error;
+ switch ((error= errno))
+ {
+#ifdef __linux
+ case ERESTART:
+#endif
+ case EINTR:
+ break;
+
+ case EFAULT:
+ case ENOMEM:
+ FATAL(strerror(error));
+ break;
+
+ case EINVAL:
+ FATAL("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid");
+ break;
+
+ default:
+ FATAL(strerror(error));
+ break;
+ }
+
+ return false;
+ }
+
+ if (active_fd == 0)
+ {
+ return false;
+ }
+
+ bool data_was_read= false;
+ if (fds[0].revents & POLLRDNORM)
+ {
+ if (stdout_fd.read(_stdout_buffer) == true)
+ {
+ data_was_read= true;
+ }
+ }
+
+ if (fds[1].revents & POLLRDNORM)
+ {
+ if (stderr_fd.read(_stderr_buffer) == true)
+ {
+ data_was_read= true;
+ }
+ }
+
+ return data_was_read;
+}
+
+std::pair<std::string, std::string> Application::output()
+{
+ slurp();
+ return {
+ std::string {
+ stdout_result().data(),
+ stdout_result().size()
+ },
+ std::string {
+ stderr_result().data(),
+ stderr_result().size()
+ }
+ };
+
+}
+
+Application::error_t Application::join()
+{
+ pid_t waited_pid= waitpid(_pid, &_status, WUNTRACED);
+ slurp();
+ if (waited_pid == _pid and WIFEXITED(_status) == false)
+ {
+ /*
+ What we are looking for here is how the exit status happened.
+ - 127 means that posix_spawn() itself had an error.
+ - If WEXITSTATUS is positive we need to see if it is a signal that we sent to kill the process. If not something bad happened in the process itself.
+ - Finally something has happened that we don't currently understand.
+ */
+ if (WEXITSTATUS(_status) == 127)
+ {
+ _app_exit_state= Application::INVALID_POSIX_SPAWN;
+ std::string error_string("posix_spawn() failed pid:");
+ error_string+= _pid;
+ error_string+= " name:";
+ error_string+= print_argv(built_argv);
+ if (stderr_result_length())
+ {
+ error_string+= " stderr: ";
+ error_string+= stderr_c_str();
+ }
+ throw std::logic_error(error_string);
+ }
+ else if (WIFSIGNALED(_status))
+ {
+ if (WTERMSIG(_status) != SIGTERM and WTERMSIG(_status) != SIGHUP)
+ {
+ slurp();
+ _app_exit_state= Application::INVALID_POSIX_SPAWN;
+ std::string error_string(print_argv(built_argv));
+ error_string+= " was killed by signal ";
+ error_string+= strsignal(WTERMSIG(_status));
+
+ if (stdout_result_length())
+ {
+ error_string+= " stdout: ";
+ error_string+= stdout_c_str();
+ }
+
+ if (stderr_result_length())
+ {
+ error_string+= " stderr: ";
+ error_string+= stderr_c_str();
+ }
+
+ throw std::runtime_error(error_string);
+ }
+
+ // If we terminted it on purpose then it counts as a success.
+#if defined(DEBUG)
+ if (DEBUG)
+ {
+ Out << "waitpid() application terminated at request"
+ << " pid:" << _pid
+ << " name:" << built_argv[0];
+ }
+#endif
+ }
+ else
+ {
+ _app_exit_state= Application::UNKNOWN;
+ Error << "Unknown logic state at exit:" << WEXITSTATUS(_status)
+ << " pid:" << _pid
+ << " name:" << built_argv[0];
+ }
+ }
+ else if (waited_pid == _pid and WIFEXITED(_status))
+ {
+ _app_exit_state= int_to_error_t(WEXITSTATUS(_status));
+ }
+ else if (waited_pid == -1)
+ {
+ std::string error_string;
+ if (stdout_result_length())
+ {
+ error_string+= " stdout: ";
+ error_string+= stdout_c_str();
+ }
+
+ if (stderr_result_length())
+ {
+ error_string+= " stderr: ";
+ error_string+= stderr_c_str();
+ }
+ Error << "waitpid() returned errno:" << strerror(errno) << " " << error_string;
+ _app_exit_state= Application::UNKNOWN;
+ }
+ else
+ {
+ _app_exit_state= Application::UNKNOWN;
+ throw std::logic_error("waitpid() returned an unknown value");
+ }
+
+ return _app_exit_state;
+}
+
+void Application::add_long_option(const std::string& name, const std::string& option_value)
+{
+ std::string arg(name);
+ arg+= option_value;
+ _options.push_back(std::make_pair(arg, std::string()));
+}
+
+void Application::add_option(const std::string& arg)
+{
+ _options.push_back(std::make_pair(arg, std::string()));
+}
+
+void Application::add_option(const std::string& name, const std::string& value)
+{
+ _options.push_back(std::make_pair(name, value));
+}
+
+Application::Pipe::Pipe(int arg) :
+ _std_fd(arg)
+{
+ _pipe_fd[READ]= -1;
+ _pipe_fd[WRITE]= -1;
+ _open[READ]= false;
+ _open[WRITE]= false;
+}
+
+int Application::Pipe::Pipe::fd()
+{
+ if (_std_fd == STDOUT_FILENO)
+ {
+ return _pipe_fd[READ];
+ }
+ else if (_std_fd == STDERR_FILENO)
+ {
+ return _pipe_fd[READ];
+ }
+
+ return _pipe_fd[WRITE]; // STDIN_FILENO
+}
+
+
+bool Application::Pipe::read(libtest::vchar_t& arg)
+{
+ fatal_assert(_std_fd == STDOUT_FILENO or _std_fd == STDERR_FILENO);
+
+ bool data_was_read= false;
+
+ libtest::vchar_t buffer;
+ buffer.resize(1024);
+ ssize_t read_length;
+ while ((read_length= ::read(_pipe_fd[READ], &buffer[0], buffer.size())))
+ {
+ if (read_length == -1)
+ {
+ switch(errno)
+ {
+ case EAGAIN:
+ break;
+
+ default:
+ Error << strerror(errno);
+ break;
+ }
+
+ break;
+ }
+
+ data_was_read= true;
+ arg.reserve(read_length +1);
+ for (size_t x= 0; x < size_t(read_length); ++x)
+ {
+ arg.push_back(buffer[x]);
+ }
+ // @todo Suck up all errput code here
+ }
+
+ return data_was_read;
+}
+
+void Application::Pipe::nonblock()
+{
+ int flags;
+ do
+ {
+ flags= fcntl(_pipe_fd[READ], F_GETFL, 0);
+ } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
+
+ if (flags == -1)
+ {
+ Error << "fcntl(F_GETFL) " << strerror(errno);
+ throw strerror(errno);
+ }
+
+ int rval;
+ do
+ {
+ rval= fcntl(_pipe_fd[READ], F_SETFL, flags | O_NONBLOCK);
+ } while (rval == -1 and (errno == EINTR or errno == EAGAIN));
+
+ if (rval == -1)
+ {
+ Error << "fcntl(F_SETFL) " << strerror(errno);
+ throw strerror(errno);
+ }
+}
+
+void Application::Pipe::reset()
+{
+ close(READ);
+ close(WRITE);
+
+#ifdef HAVE_PIPE2
+ if (pipe2(_pipe_fd, O_NONBLOCK|O_CLOEXEC) == -1)
+#endif
+ {
+ if (pipe(_pipe_fd) == -1)
+ {
+ FATAL(strerror(errno));
+ }
+
+ // Since either pipe2() was not found/called we set the pipe directly
+ nonblock();
+ cloexec();
+ }
+ _open[0]= true;
+ _open[1]= true;
+}
+
+void Application::Pipe::cloexec()
+{
+ //if (SOCK_CLOEXEC == 0)
+ {
+ if (FD_CLOEXEC)
+ {
+ int flags;
+ do
+ {
+ flags= fcntl(_pipe_fd[WRITE], F_GETFD, 0);
+ } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
+
+ if (flags == -1)
+ {
+ Error << "fcntl(F_GETFD) " << strerror(errno);
+ throw strerror(errno);
+ }
+
+ int rval;
+ do
+ {
+ rval= fcntl(_pipe_fd[WRITE], F_SETFD, flags | FD_CLOEXEC);
+ } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
+
+ if (rval == -1)
+ {
+ Error << "fcntl(F_SETFD) " << strerror(errno);
+ throw strerror(errno);
+ }
+ }
+ }
+}
+
+Application::Pipe::~Pipe()
+{
+ if (_pipe_fd[0] != -1)
+ {
+ ::close(_pipe_fd[0]);
+ }
+
+ if (_pipe_fd[1] != -1)
+ {
+ ::close(_pipe_fd[1]);
+ }
+}
+
+void Application::Pipe::dup_for_spawn(posix_spawn_file_actions_t& file_actions)
+{
+ int type= STDIN_FILENO == _std_fd ? 0 : 1;
+
+ int ret;
+ if ((ret= posix_spawn_file_actions_adddup2(&file_actions, _pipe_fd[type], _std_fd )) < 0)
+ {
+ FATAL("posix_spawn_file_actions_adddup2(%s)", strerror(ret));
+ }
+
+ if ((ret= posix_spawn_file_actions_addclose(&file_actions, _pipe_fd[type])) < 0)
+ {
+ FATAL("posix_spawn_file_actions_addclose(%s)", strerror(ret));
+ }
+}
+
+void Application::Pipe::close(const close_t& arg)
+{
+ int type= int(arg);
+
+ if (_open[type])
+ {
+ if (::close(_pipe_fd[type]) == -1)
+ {
+ Error << "close(" << strerror(errno) << ")";
+ }
+ _open[type]= false;
+ _pipe_fd[type]= -1;
+ }
+}
+
+void Application::create_argv(const char *args[])
+{
+ delete_argv();
+ if (_use_libtool)
+ {
+ assert(libtool());
+ vchar::append(built_argv, libtool());
+ vchar::append(built_argv, "--mode=execute");
+ }
+
+ if (_use_valgrind)
+ {
+ /*
+ valgrind --error-exitcode=1 --leak-check=yes --track-fds=yes --malloc-fill=A5 --free-fill=DE
+ */
+ vchar::append(built_argv, "valgrind");
+ vchar::append(built_argv, "--error-exitcode=1");
+ vchar::append(built_argv, "--leak-check=yes");
+#if 0
+ vchar::append(built_argv, "--show-reachable=yes"));
+#endif
+ vchar::append(built_argv, "--track-fds=yes");
+#if 0
+ built_argv[x++]= strdup("--track-origin=yes");
+#endif
+ vchar::append(built_argv, "--malloc-fill=A5");
+ vchar::append(built_argv, "--free-fill=DE");
+
+ std::string log_file= create_tmpfile("valgrind");
+ libtest::vchar_t buffer;
+ buffer.resize(1024);
+ int length= snprintf(&buffer[0], buffer.size(), "--log-file=%s", log_file.c_str());
+ fatal_assert(length > 0 and size_t(length) < buffer.size());
+ vchar::append(built_argv, &buffer[0]);
+ }
+ else if (_use_ptrcheck)
+ {
+ /*
+ valgrind --error-exitcode=1 --tool=exp-ptrcheck --log-file=
+ */
+ vchar::append(built_argv, "valgrind");
+ vchar::append(built_argv, "--error-exitcode=1");
+ vchar::append(built_argv, "--tool=exp-ptrcheck");
+ std::string log_file= create_tmpfile("ptrcheck");
+ libtest::vchar_t buffer;
+ buffer.resize(1024);
+ int length= snprintf(&buffer[0], buffer.size(), "--log-file=%s", log_file.c_str());
+ fatal_assert(length > 0 and size_t(length) < buffer.size());
+ vchar::append(built_argv, &buffer[0]);
+ }
+ else if (_use_gdb)
+ {
+ vchar::append(built_argv, "gdb");
+ }
+
+ vchar::append(built_argv, _exectuble_with_path.c_str());
+
+ for (Options::const_iterator iter= _options.begin(); iter != _options.end(); ++iter)
+ {
+ vchar::append(built_argv, (*iter).first.c_str());
+ if ((*iter).second.empty() == false)
+ {
+ vchar::append(built_argv, (*iter).second.c_str());
+ }
+ }
+
+ if (args)
+ {
+ for (const char **ptr= args; *ptr; ++ptr)
+ {
+ vchar::append(built_argv, *ptr);
+ }
+ }
+ built_argv.push_back(nullptr);
+}
+
+std::string Application::print()
+{
+ return print_argv(built_argv);
+}
+
+std::string Application::arguments()
+{
+ std::stringstream arg_buffer;
+
+ // Skip printing out the libtool reference
+ for (size_t x= _use_libtool ? 2 : 0; x < _argc; ++x)
+ {
+ if (built_argv[x])
+ {
+ arg_buffer << built_argv[x] << " ";
+ }
+ }
+
+ return arg_buffer.str();
+}
+
+void Application::delete_argv()
+{
+ std::for_each(built_argv.begin(), built_argv.end(), FreeFromVector());
+
+ built_argv.clear();
+ _argc= 0;
+}
+
+
+int exec_cmdline(const std::string& command, const char *args[], bool use_libtool)
+{
+ Application app(command, use_libtool);
+
+ Application::error_t ret= app.run(args);
+
+ if (Application::SUCCESS == ret) {
+ ret = app.join();
+ }
+
+ if (ret != Application::SUCCESS)
+ {
+ auto out = app.output();
+ Error << command << " stdout: " << out.first;
+ Error << command << " stderr: " << out.second;
+ }
+
+ return int(ret);
+}
+
+} // namespace exec_cmdline
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <spawn.h>
+
+// http://www.gnu.org/software/automake/manual/automake.html#Using-the-TAP-test-protocol
+#ifndef EXIT_SKIP
+# define EXIT_SKIP 77
+#endif
+
+#ifndef EXIT_FATAL
+# define EXIT_FATAL 99
+#endif
+
+#ifndef EX_NOEXEC
+# define EX_NOEXEC 126
+#endif
+
+#ifndef EX_NOTFOUND
+# define EX_NOTFOUND 127
+#endif
+
+namespace libtest {
+
+class Application {
+private:
+ typedef std::vector< std::pair<std::string, std::string> > Options;
+
+public:
+
+ enum error_t {
+ SUCCESS= EXIT_SUCCESS,
+ FAILURE= EXIT_FAILURE,
+ UNINITIALIZED,
+ SIGTERM_KILLED,
+ UNKNOWN,
+ UNKNOWN_SIGNAL,
+ INVALID_POSIX_SPAWN= 127
+ };
+
+ static const char* toString(error_t arg)
+ {
+ switch (arg)
+ {
+ case Application::SUCCESS:
+ return "EXIT_SUCCESS";
+
+ case Application::UNINITIALIZED:
+ return "UNINITIALIZED";
+
+ case Application::SIGTERM_KILLED:
+ return "Exit happened via SIGTERM";
+
+ case Application::FAILURE:
+ return "EXIT_FAILURE";
+
+ case Application::UNKNOWN_SIGNAL:
+ return "Exit happened via a signal which was not SIGTERM";
+
+ case Application::INVALID_POSIX_SPAWN:
+ return "127: Invalid call to posix_spawn()";
+
+ case Application::UNKNOWN:
+ default:
+ break;
+ }
+
+ return "EXIT_UNKNOWN";
+ }
+
+ class Pipe {
+ public:
+ Pipe(int);
+ ~Pipe();
+
+ int fd();
+
+ enum close_t {
+ READ= 0,
+ WRITE= 1
+ };
+
+ void reset();
+ void close(const close_t& arg);
+ void dup_for_spawn(posix_spawn_file_actions_t& file_actions);
+
+ void nonblock();
+ void cloexec();
+ bool read(libtest::vchar_t&);
+
+ private:
+ const int _std_fd;
+ int _pipe_fd[2];
+ bool _open[2];
+ };
+
+public:
+ Application(const std::string& arg, const bool _use_libtool_arg= false);
+
+ virtual ~Application();
+
+ void add_option(const std::string&);
+ void add_option(const std::string&, const std::string&);
+ void add_long_option(const std::string& option_name, const std::string& option_value);
+ error_t run(const char *args[]= NULL);
+ Application::error_t join();
+
+ libtest::vchar_t stdout_result() const
+ {
+ return _stdout_buffer;
+ }
+
+ size_t stdout_result_length() const
+ {
+ return _stdout_buffer.size();
+ }
+
+ const char* stdout_c_str() const
+ {
+ return &_stdout_buffer[0];
+ }
+
+ libtest::vchar_t stderr_result() const
+ {
+ return _stderr_buffer;
+ }
+
+ const char* stderr_c_str() const
+ {
+ return &_stderr_buffer[0];
+ }
+
+ size_t stderr_result_length() const
+ {
+ return _stderr_buffer.size();
+ }
+
+ std::string print();
+
+ void use_valgrind(bool arg)
+ {
+ _use_valgrind= arg;
+ }
+
+ bool check() const;
+
+ bool slurp();
+ std::pair<std::string, std::string> output();
+ void murder();
+
+ void clear()
+ {
+ slurp();
+ _stdout_buffer.clear();
+ _stderr_buffer.clear();
+ }
+
+ void use_gdb(bool arg)
+ {
+ _use_gdb= arg;
+ }
+
+ void use_ptrcheck(bool arg)
+ {
+ _use_ptrcheck= arg;
+ }
+
+ std::string arguments();
+
+ std::string gdb_filename()
+ {
+ return _gdb_filename;
+ }
+
+ pid_t pid() const
+ {
+ return _pid;
+ }
+
+ void will_fail()
+ {
+ _will_fail= true;
+ }
+
+private:
+ void create_argv(const char *args[]);
+ void delete_argv();
+ void add_to_build_argv(const char*);
+
+private:
+ const bool _use_libtool;
+ bool _use_valgrind;
+ bool _use_gdb;
+ bool _use_ptrcheck;
+ bool _will_fail;
+ size_t _argc;
+ std::string _exectuble_name;
+ std::string _exectuble;
+ std::string _exectuble_with_path;
+ std::string _gdb_filename;
+ Options _options;
+ Pipe stdin_fd;
+ Pipe stdout_fd;
+ Pipe stderr_fd;
+ libtest::vchar_ptr_t built_argv;
+ pid_t _pid;
+ libtest::vchar_t _stdout_buffer;
+ libtest::vchar_t _stderr_buffer;
+ int _status;
+ pthread_t _thread;
+ error_t _app_exit_state;
+};
+
+static inline std::ostream& operator<<(std::ostream& output, const enum Application::error_t &arg)
+{
+ return output << Application::toString(arg);
+}
+
+int exec_cmdline(const std::string& executable, const char *args[], bool use_libtool= false);
+
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/common.h>
+
+// @todo possibly have this code fork off so if it fails nothing goes bad
+static test_return_t runner_code(libtest::Framework* frame,
+ test_st* run,
+ libtest::Timer& _timer)
+{ // Runner Code
+
+ assert(frame->runner());
+ assert(run->test_fn);
+
+ test_return_t return_code;
+ try
+ {
+ _timer.reset();
+ assert(frame);
+ assert(frame->runner());
+ assert(run->test_fn);
+ return_code= frame->runner()->main(run->test_fn, frame->creators_ptr());
+ }
+ // Special case where check for the testing of the exception
+ // system.
+ catch (const libtest::fatal& e)
+ {
+ if (libtest::fatal::is_disabled())
+ {
+ libtest::fatal::increment_disabled_counter();
+ return_code= TEST_SUCCESS;
+ }
+ else
+ {
+ throw;
+ }
+ }
+
+ _timer.sample();
+
+ return return_code;
+}
+
+namespace libtest {
+
+Collection::Collection(Framework* frame_arg,
+ collection_st* arg) :
+ _name(arg->name),
+ _pre(arg->pre),
+ _post(arg->post),
+ _tests(arg->tests),
+ _frame(frame_arg),
+ _success(0),
+ _skipped(0),
+ _failed(0),
+ _total(0),
+ _formatter(frame_arg->name(), _name)
+{
+ fatal_assert(arg);
+}
+
+test_return_t Collection::exec()
+{
+ if (test_success(_frame->runner()->setup(_pre, _frame->creators_ptr())))
+ {
+ for (test_st *run= _tests; run->name; run++)
+ {
+ formatter()->push_testcase(run->name);
+ if (_frame->match(run->name))
+ {
+ formatter()->skipped();
+ continue;
+ }
+ _total++;
+
+ test_return_t return_code;
+ try
+ {
+ if (run->requires_flush)
+ {
+ if (test_failed(_frame->runner()->flush(_frame->creators_ptr())))
+ {
+ Error << "frame->runner()->flush(creators_ptr)";
+ _skipped++;
+ formatter()->skipped();
+ continue;
+ }
+ }
+
+ set_alarm();
+
+ try
+ {
+ return_code= runner_code(_frame, run, _timer);
+ }
+ catch (...)
+ {
+ cancel_alarm();
+
+ throw;
+ }
+ libtest::cancel_alarm();
+ }
+ catch (const libtest::fatal& e)
+ {
+ _failed++;
+ formatter()->failed();
+ stream::make_cerr err(e.file(), e.line(), e.func());
+ err << e.what();
+ for (auto server : _frame->servers().servers)
+ {
+ auto output = server->output();
+ if (output.first.size())
+ {
+ err << "Server(" << server->port() << ") stdout:\n" << output.first << "\n";
+ }
+ if (output.second.size())
+ {
+ err << "Server(" << server->port() << ") stderr:\n" << output.second << "\n";
+ }
+ }
+ throw;
+ }
+
+ switch (return_code)
+ {
+ case TEST_SUCCESS:
+ _success++;
+ formatter()->success(_timer);
+ break;
+
+ case TEST_FAILURE:
+ _failed++;
+ formatter()->failed();
+ for (auto server : _frame->servers().servers)
+ {
+ auto output = server->output();
+ if (output.first.size())
+ {
+ Out << "Server(" << server->port() << ") stdout:\n" << output.first << "\n";
+ }
+ if (output.second.size())
+ {
+ Out << "Server(" << server->port() << ") stderr:\n" << output.second << "\n";
+ }
+ }
+ break;
+
+ case TEST_SKIPPED:
+ _skipped++;
+ formatter()->skipped();
+ break;
+
+ default:
+ FATAL("invalid return code");
+ }
+#if 0
+ @TODO add code here to allow for a collection to define a method to reset to allow tests to continue.
+#endif
+ }
+
+ (void) _frame->runner()->teardown(_post, _frame->creators_ptr());
+ }
+
+ if (_failed == 0 and _skipped == 0 and _success)
+ {
+ return TEST_SUCCESS;
+ }
+
+ if (_failed)
+ {
+ return TEST_FAILURE;
+ }
+
+ fatal_assert(_skipped or _success == 0);
+
+ return TEST_SKIPPED;
+}
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libtest/formatter.hpp>
+
+#include <libtest/timer.hpp>
+
+namespace { class Framework; }
+
+
+/**
+ A structure which describes a collection of test cases.
+*/
+struct collection_st {
+ const char *name;
+ test_callback_fn *pre;
+ test_callback_fn *post;
+ struct test_st *tests;
+};
+
+namespace libtest {
+
+class Collection {
+public:
+ Collection(libtest::Framework*, collection_st*);
+
+ test_return_t exec();
+
+ const char* name()
+ {
+ return _name.c_str();
+ }
+
+ uint32_t success()
+ {
+ return _success;
+ }
+
+ uint32_t skipped()
+ {
+ return _skipped;
+ }
+
+ uint32_t failed()
+ {
+ return _failed;
+ }
+
+ uint32_t total()
+ {
+ return _total;
+ }
+
+ libtest::Formatter* formatter()
+ {
+ return &_formatter;
+ }
+
+private:
+ std::string _name;
+ test_callback_fn *_pre;
+ test_callback_fn *_post;
+ struct test_st *_tests;
+ libtest::Framework* _frame;
+ uint32_t _success;
+ uint32_t _skipped;
+ uint32_t _failed;
+ uint32_t _total;
+ libtest::Timer _timer;
+ libtest::Formatter _formatter;
+
+private:
+ Collection( const Collection& );
+ const Collection& operator=( const Collection& );
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ Common include file for libtest
+*/
+
+#pragma once
+
+#include <cassert>
+#include <cerrno>
+#include <cstdlib>
+#include <sstream>
+#include <string>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+#ifdef HAVE_FNMATCH_H
+# include <fnmatch.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#if defined(WIN32)
+# include "win32/wrappers.h"
+# define get_socket_errno() WSAGetLastError()
+#else
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+# define INVALID_SOCKET -1
+# define SOCKET_ERROR -1
+# define closesocket(a) close(a)
+# define get_socket_errno() errno
+#endif
+
+#include <libtest/test.hpp>
+
+#include <libtest/is_pid.hpp>
+
+#include <libtest/gearmand.h>
+#include <libtest/blobslap_worker.h>
+#include <libtest/memcached.h>
+#include <libtest/drizzled.h>
+
+#include <libtest/libtool.hpp>
+#include <libtest/killpid.h>
+#include <libtest/signal.h>
+#include <libtest/dns.hpp>
+#include <libtest/formatter.hpp>
+
+struct FreeFromVector
+{
+ template <class T>
+ void operator() ( T* ptr) const
+ {
+ if (ptr)
+ {
+ free(ptr);
+ ptr= NULL;
+ }
+ }
+};
+
+struct DeleteFromVector
+{
+ template <class T>
+ void operator() ( T* ptr) const
+ {
+ delete ptr;
+ ptr= NULL;
+ }
+};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+namespace libtest {
+
+bool jenkins_is_caller(void)
+{
+ if (bool(getenv("JENKINS_HOME")))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool gdb_is_caller(void)
+{
+ if (bool(getenv("LOG_COMPILER")) and strstr(getenv("LOG_COMPILER"), "gdb"))
+ {
+ return true;
+ }
+
+ if (bool(getenv("LIBTEST_IN_GDB")))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool helgrind_is_caller(void)
+{
+ if (bool(getenv("LOG_COMPILER")) and strstr(getenv("LOG_COMPILER"), "helgrind"))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool _in_valgrind(const char*, int, const char*)
+{
+ if (valgrind_is_caller())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <typeinfo>
+
+#if defined(HAVE_LIBMEMCACHED) && HAVE_LIBMEMCACHED
+#include <libmemcached-1.0/memcached.h>
+#include <libmemcachedutil-1.0/ostream.hpp>
+#include <libtest/memcached.hpp>
+#endif
+
+#if defined(HAVE_LIBGEARMAN) && HAVE_LIBGEARMAN
+#include <libgearman-1.0/ostream.hpp>
+#endif
+
+namespace libtest {
+
+LIBTEST_API
+bool jenkins_is_caller(void);
+
+LIBTEST_API
+bool gdb_is_caller(void);
+
+LIBTEST_API
+bool _in_valgrind(const char *file, int line, const char *func);
+
+LIBTEST_API
+bool helgrind_is_caller(void);
+
+template <class T_comparable>
+bool _compare_truth(const char *file, int line, const char *func, T_comparable __expected, const char *assertation_label)
+{
+ if (__expected == false)
+ {
+ libtest::stream::make_cerr(file, line, func) << "Assertation \"" << assertation_label << "\"";
+ return false;
+ }
+
+ return true;
+}
+
+template <class T1_comparable, class T2_comparable>
+bool _compare(const char *file, int line, const char *func, const T1_comparable& __expected, const T2_comparable& __actual, bool use_io)
+{
+ if (__expected != __actual)
+ {
+ if (use_io)
+ {
+ libtest::stream::make_cerr(file, line, func) << "Expected \"" << __expected << "\" got \"" << __actual << "\"";
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+template <class T1_comparable, class T2_comparable>
+bool _compare_strcmp(const char *file, int line, const char *func, const T1_comparable *__expected, const T2_comparable *__actual)
+{
+ if (__expected == NULL)
+ {
+ FATAL("Expected value was NULL, programmer error");
+ }
+
+ if (__actual == NULL)
+ {
+ libtest::stream::make_cerr(file, line, func) << "Expected " << __expected << " but got NULL";
+ return false;
+ }
+
+ if (strncmp(__expected, __actual, strlen(__expected)))
+ {
+ libtest::stream::make_cerr(file, line, func) << "Expected " << __expected << " passed \"" << __actual << "\"";
+ return false;
+ }
+
+ return true;
+}
+
+template <class T_comparable>
+bool _compare_zero(const char *file, int line, const char *func, T_comparable __actual)
+{
+ if (T_comparable(0) != __actual)
+ {
+ libtest::stream::make_cerr(file, line, func) << "Expected 0 got \"" << __actual << "\"";
+ return false;
+ }
+
+ return true;
+}
+
+template <class T1_comparable, class T2_comparable>
+bool _ne_compare(const char *file, int line, const char *func, T1_comparable __expected, T2_comparable __actual, bool io_error= true)
+{
+ if (__expected == __actual)
+ {
+ if (io_error)
+ {
+ libtest::stream::make_cerr(file, line, func) << "Expected \"" << __expected << "\" got \"" << __actual << "\"";
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+template <class T_comparable, class T_expression_string>
+bool _assert_truth(const char *file, int line, const char *func, T_comparable __truth, T_expression_string __expression, const char* __explain= NULL)
+{
+ if (__truth)
+ {
+ return true;
+ }
+
+ if (__explain)
+ {
+ libtest::stream::make_cerr(file, line, func) << "Assertion \"" << __expression << "\" warning:" << __explain;
+ }
+
+ return false;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+
+namespace libtest {
+
+void create_core(void)
+{
+#if defined(__APPLE__) && __APPLE__
+ if (__APPLE__)
+ {
+ return;
+ }
+#endif
+ if (getenv("YATL_COREDUMP"))
+ {
+ pid_t pid= fork();
+
+ if (pid == 0)
+ {
+ abort();
+ }
+ else
+ {
+ while (waitpid(pid, NULL, 0) != pid) {};
+ }
+ }
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+LIBTEST_API
+void create_core(void);
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <cstdlib>
+#include <fcntl.h>
+#include <getopt.h>
+#include <iostream>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libtest/cpu.hpp>
+
+static void version_command(const char *command_name, int major_version, int minor_version)
+{
+ std::cout << command_name << " " << major_version << "." << minor_version << std::endl;
+}
+
+static void help_command(const char *command_name,
+ int major_version, int minor_version,
+ const struct option *long_options)
+{
+ std::cout << command_name << " " << major_version << "." << minor_version << std::endl;
+ std::cout << "Prints the number of cores found on the local host." << std::endl << std::endl;
+
+ for (uint32_t x= 0; long_options[x].name; x++)
+ {
+ std::cout << "\t --" << long_options[x].name << char(long_options[x].has_arg ? '=' : ' ') << std::endl;
+ }
+
+ std::cout << std::endl;
+}
+
+enum {
+ OPT_HELP,
+ OPT_VERSION
+};
+
+static void options_parse(int argc, char *argv[])
+{
+ static struct option long_options[]=
+ {
+ { "version", no_argument, NULL, OPT_VERSION},
+ { "help", no_argument, NULL, OPT_HELP},
+ {0, 0, 0, 0},
+ };
+
+ bool opt_version= false;
+ bool opt_help= false;
+ int option_index= 0;
+
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
+ if (option_rv == -1)
+ {
+ break;
+ }
+
+ switch (option_rv)
+ {
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_VERSION: /* --version or -v */
+ opt_version= true;
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(EXIT_FAILURE);
+
+ default:
+ help_command(argv[0], 1, 0, long_options);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (opt_version)
+ {
+ version_command(argv[0], 1, 0);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(argv[0], 1, 0, long_options);
+ exit(EXIT_SUCCESS);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ options_parse(argc, argv);
+
+ std::cout << libtest::number_of_cpus() << std::endl;
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <unistd.h>
+
+#pragma GCC diagnostic ignored "-Wundef"
+
+#if defined(HAVE_LINUX_SYSCTL_H) && HAVE_LINUX_SYSCTL_H
+#include <linux/sysctl.h>
+#elif defined(HAVE_SYS_SYSCTL_H) && HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
+namespace libtest {
+
+size_t number_of_cpus()
+{
+ size_t number_of_cpu= 1;
+#if defined(__linux) && __linux
+ number_of_cpu= sysconf(_SC_NPROCESSORS_ONLN);
+#elif defined(HAVE_SYS_SYSCTL_H) && defined(CTL_HW) && defined(HW_NCPU) && defined(HW_AVAILCPU) && defined(HW_NCPU)
+ int mib[4];
+ size_t len= sizeof(number_of_cpu);
+
+ /* set the mib for hw.ncpu */
+ mib[0] = CTL_HW;
+ mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
+
+ /* get the number of CPUs from the system */
+ sysctl(mib, 2, &number_of_cpu, &len, NULL, 0);
+
+ if (number_of_cpu < 1)
+ {
+ mib[1]= HW_NCPU;
+ sysctl(mib, 2, &number_of_cpu, &len, NULL, 0 );
+
+ if (number_of_cpu < 1 )
+ {
+ number_of_cpu = 1;
+ }
+ }
+#else
+ // Guessing number of CPU
+#endif
+
+ return number_of_cpu;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+size_t number_of_cpus();
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+namespace libtest {
+
+bool lookup(const char* host)
+{
+ bool success= false;
+ assert(host and host[0]);
+ if (host and host[0])
+ {
+ struct addrinfo *addrinfo= NULL;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype= SOCK_STREAM;
+ hints.ai_protocol= IPPROTO_TCP;
+
+ int limit= 5;
+ while (--limit and success == false)
+ {
+ if (addrinfo)
+ {
+ freeaddrinfo(addrinfo);
+ addrinfo= NULL;
+ }
+
+ int ret;
+ if ((ret= getaddrinfo(host, "echo", &hints, &addrinfo)) == 0)
+ {
+ success= true;
+ break;
+ }
+
+ switch (ret)
+ {
+ case EAI_AGAIN:
+ continue;
+
+ case EAI_NONAME:
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ if (addrinfo)
+ {
+ freeaddrinfo(addrinfo);
+ }
+ }
+
+ return success;
+}
+
+
+bool check_dns()
+{
+ if (valgrind_is_caller())
+ {
+ return false;
+ }
+
+ if (lookup("exist.gearman.info") == false)
+ {
+ return false;
+ }
+
+ if (lookup("does_not_exist.gearman.info")) // This should fail, if it passes,...
+ {
+ fatal_assert("Your service provider sucks and is providing bogus DNS. You might be in an airport.");
+ }
+
+ return true;
+}
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+bool check_dns();
+bool lookup(const char*);
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+namespace libtest {
+
+void dream(time_t tv_sec, long tv_nsec)
+{
+#if defined(WIN32)
+ if (tv_sec == 0 and tv_nsec)
+ {
+ tv_sec++;
+ }
+ sleep(tv_sec);
+#else
+ struct timespec requested;
+ requested.tv_sec= tv_sec;
+ requested.tv_nsec= tv_nsec;
+ nanosleep(&requested, NULL);
+#endif
+}
+
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+void dream(time_t tv_sec, long tv_nsec= 0);
+
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <libtest/drizzled.h>
+
+#include "util/instance.hpp"
+#include "util/operation.hpp"
+
+using namespace datadifferential;
+using namespace libtest;
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <signal.h>
+#include <sstream>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+#if defined(HAVE_LIBDRIZZLE) && HAVE_LIBDRIZZLE
+# include <libdrizzle-5.1/drizzle_client.h>
+#endif
+
+using namespace libtest;
+
+namespace libtest {
+bool ping_drizzled(const in_port_t _port)
+{
+ (void)(_port);
+#if defined(HAVE_LIBDRIZZLE) && HAVE_LIBDRIZZLE
+ if (HAVE_LIBDRIZZLE)
+ {
+ drizzle_st *drizzle= drizzle_create(getenv("MYSQL_SERVER"),
+ getenv("MYSQL_PORT") ? atoi("MYSQL_PORT") : DRIZZLE_DEFAULT_TCP_PORT,
+ getenv("MYSQL_USER"),
+ getenv("MYSQL_PASSWORD"),
+ getenv("MYSQL_SCHEMA"), 0);
+
+ if (drizzle == NULL)
+ {
+ return false;
+ }
+
+ bool success= false;
+
+ drizzle_return_t rc;
+ if ((rc= drizzle_connect(drizzle)) == DRIZZLE_RETURN_OK)
+ {
+ drizzle_result_st *result= drizzle_ping(drizzle, &rc);
+ success= bool(result);
+ drizzle_result_free(result);
+ }
+
+ if (success == true)
+ { }
+ else if (rc != DRIZZLE_RETURN_OK)
+ {
+ Error << drizzle_error(drizzle) << " localhost:" << _port;
+ }
+
+ drizzle_quit(drizzle);
+
+ return success;
+ }
+#endif
+
+ return false;
+}
+} // namespace libtest
+
+class Drizzle : public libtest::Server
+{
+private:
+public:
+ Drizzle(const std::string& host_arg, in_port_t port_arg) :
+ libtest::Server(host_arg, port_arg, DRIZZLED_BINARY, false)
+ {
+ set_pid_file();
+ }
+
+ bool ping()
+ {
+ size_t limit= 5;
+ while (_app.check() and --limit)
+ {
+ if (ping_drizzled(_port))
+ {
+ return true;
+ }
+ libtest::dream(1, 0);
+ }
+
+ return false;
+ }
+
+ const char *name()
+ {
+ return "drizzled";
+ };
+
+ void log_file_option(Application&, const std::string&)
+ {
+ }
+
+ bool has_log_file_option() const
+ {
+ return true;
+ }
+
+ bool broken_pid_file()
+ {
+ return true;
+ }
+
+ bool is_libtool()
+ {
+ return false;
+ }
+
+ bool has_syslog() const
+ {
+ return true;
+ }
+
+ bool has_port_option() const
+ {
+ return true;
+ }
+
+ void port_option(Application& app, in_port_t arg)
+ {
+ if (arg > 0)
+ {
+ libtest::vchar_t buffer;
+ buffer.resize(1024);
+ snprintf(&buffer[1024], buffer.size(), "--drizzle-protocol.port=%d", int(arg));
+ app.add_option(&buffer[1024]);
+ }
+ }
+
+ bool build();
+};
+
+bool Drizzle::build()
+{
+ if (getuid() == 0 or geteuid() == 0)
+ {
+ add_option("--user=root");
+ }
+
+ add_option("--verbose=INSPECT");
+#if 0
+ add_option("--datadir=var/drizzle");
+#endif
+
+ return true;
+}
+
+namespace libtest {
+
+libtest::Server *build_drizzled(const char *hostname, in_port_t try_port)
+{
+ return new Drizzle(hostname, try_port);
+}
+
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <arpa/inet.h>
+
+namespace libtest { struct Server; }
+
+namespace libtest {
+
+libtest::Server *build_drizzled(const char *hostname, in_port_t try_port);
+
+bool ping_drizzled(const in_port_t);
+
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+enum test_return_t {
+ TEST_SUCCESS,
+ TEST_FAILURE,
+ TEST_SKIPPED
+};
+
+
+static inline bool test_success(test_return_t rc)
+{
+ return (rc == TEST_SUCCESS);
+}
+
+static inline bool test_failed(test_return_t rc)
+{
+ return (rc != TEST_SUCCESS);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+#include <cstdarg>
+
+namespace libtest {
+
+exception::exception(const char *file_arg, int line_arg, const char *func_arg):
+ std::exception(),
+ _line(line_arg),
+ _file(file_arg),
+ _func(func_arg),
+ _error_message(NULL),
+ _error_message_size(0)
+{
+}
+
+#ifndef __INTEL_COMPILER
+# pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+void exception::init(va_list args_)
+{
+ const char *format= va_arg(args_, const char *);
+ int error_message_length= vasprintf(&_error_message, format, args_);
+ assert(error_message_length != -1);
+ if (error_message_length > 0)
+ {
+ _error_message_size= error_message_length +1;
+ }
+}
+
+exception::~exception() throw()
+{
+ if (_error_message)
+ {
+ free(_error_message);
+ }
+}
+
+void exception::what(size_t length_, const char* message_)
+{
+ if (length_ > 0 and message_)
+ {
+ char *ptr= (char*) realloc(_error_message, length_ +1);
+ if (ptr)
+ {
+ _error_message= ptr;
+ memcpy(_error_message, message_, length_);
+ _error_message[length_]= 0;
+ }
+ }
+}
+
+exception::exception(const exception& other) :
+ std::exception(),
+ _line(other._line),
+ _file(other._file),
+ _func(other._func),
+ _error_message_size(0)
+{
+ if (other.length() > 0)
+ {
+ _error_message= (char*) malloc(other.length() +1);
+ if (_error_message)
+ {
+ memcpy(_error_message, other._error_message, other.length());
+ _error_message_size= other.length();
+ }
+ }
+}
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+class exception : public std::exception
+{
+public:
+ exception(const char *file, int line, const char *func);
+
+ exception( const exception& );
+
+ virtual ~exception() throw();
+
+ virtual const char* what() const throw()
+ {
+ if (_error_message)
+ {
+ return _error_message;
+ }
+
+ return "";
+ }
+
+ void what(size_t, const char*);
+
+ size_t length() const
+ {
+ return _error_message_size;
+ }
+
+ int line() const
+ {
+ return _line;
+ }
+
+ const char* file() const
+ {
+ return _file;
+ }
+
+ const char* func() const
+ {
+ return _func;
+ }
+
+protected:
+ void init(va_list);
+
+private:
+ int _line;
+ const char* _file;
+ const char* _func;
+ char* _error_message;
+ size_t _error_message_size;
+};
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include "libtest/exception.hpp"
+
+namespace libtest {
+
+class disconnected : public libtest::exception
+{
+public:
+ disconnected(const char *file, int line, const char *func, const std::string&, const unsigned port, ...);
+
+ disconnected(const disconnected&);
+
+ // The following are just for unittesting the exception class
+ static bool is_disabled();
+ static void disable();
+ static void enable();
+ static uint32_t disabled_counter();
+ static void increment_disabled_counter();
+
+private:
+ in_port_t _port;
+ char _instance[BUFSIZ];
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+#include "libtest/exception.hpp"
+#include <cstdarg>
+
+namespace libtest {
+
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+fatal::fatal(const char *file_arg, int line_arg, const char *func_arg, ...) :
+ libtest::exception(file_arg, line_arg, func_arg)
+{
+ va_list args;
+ va_start(args, func_arg);
+ init(args);
+ va_end(args);
+}
+
+fatal::fatal( const fatal& other ) :
+ libtest::exception(other)
+{
+}
+
+static bool _disabled= false;
+static uint32_t _counter= 0;
+
+bool fatal::is_disabled() throw()
+{
+ return _disabled;
+}
+
+void fatal::disable() throw()
+{
+ _counter= 0;
+ _disabled= true;
+}
+
+void fatal::enable() throw()
+{
+ _counter= 0;
+ _disabled= false;
+}
+
+uint32_t fatal::disabled_counter() throw()
+{
+ return _counter;
+}
+
+void fatal::increment_disabled_counter() throw()
+{
+ _counter++;
+}
+
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+disconnected::disconnected(const char *file_arg, int line_arg, const char *func_arg,
+ const std::string& instance, const unsigned port, ...) :
+ libtest::exception(file_arg, line_arg, func_arg),
+ _port(port)
+{
+ va_list args;
+ va_start(args, port);
+ const char *format= va_arg(args, const char *);
+ char last_error[BUFSIZ];
+ (void)vsnprintf(last_error, sizeof(last_error), format, args);
+ va_end(args);
+
+ char buffer_error[BUFSIZ];
+ int error_length= snprintf(buffer_error, sizeof(buffer_error), "%s:%u %s", instance.c_str(), uint32_t(port), last_error);
+
+ if (error_length > 0)
+ {
+ what(size_t(error_length), buffer_error);
+ }
+}
+
+disconnected::disconnected(const disconnected& other):
+ libtest::exception(other),
+ _port(other._port)
+{
+ strncpy(_instance, other._instance, BUFSIZ);
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+class fatal : public libtest::exception
+{
+public:
+ fatal(const char *file, int line, const char *func, ...);
+
+ fatal(const fatal&);
+
+ // The following are just for unittesting the exception class
+ static bool is_disabled() throw();
+ static void disable() throw();
+ static void enable() throw();
+ static uint32_t disabled_counter() throw();
+ static void increment_disabled_counter() throw();
+
+ test_return_t return_code() const
+ {
+ return TEST_SKIPPED;
+ }
+
+private:
+};
+
+} // namespace libtest
+
+#define FATAL(...) \
+do \
+{ \
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, __VA_ARGS__); \
+} while (0)
+
+#define FATAL_IF(__expression, ...) \
+do \
+{ \
+ if ((__expression)) { \
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, (#__expression)); \
+ } \
+} while (0)
+
+#define FATAL_IF_(__expression, ...) \
+do \
+{ \
+ if ((__expression)) { \
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, __VA_ARGS__); \
+ } \
+} while (0)
+
+#define fatal_assert(__assert) if((__assert)) {} else { throw libtest::fatal(LIBYATL_DEFAULT_PARAM, #__assert); }
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <libtest/failed.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace libtest {
+
+struct failed_st {
+ failed_st(const std::string& collection_arg, const std::string& test_arg) :
+ collection(collection_arg),
+ test(test_arg)
+ { }
+
+ std::string collection;
+ std::string test;
+};
+
+typedef std::vector<failed_st> Failures;
+
+class Failed
+{
+private:
+ Failures failures;
+
+public:
+ void push(const char *collection, const char *test)
+ {
+ failures.push_back(failed_st(collection, test));
+ }
+
+ void print_failed_test(void)
+ {
+ for (Failures::iterator iter= failures.begin(); iter != failures.end(); ++iter)
+ {
+ Error << "\t" << (*iter).collection << " " << (*iter).test;
+ }
+ }
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/common.h>
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <ostream>
+
+namespace libtest {
+
+std::string& escape4XML(std::string const& arg, std::string& escaped_string)
+{
+ escaped_string.clear();
+
+ escaped_string+= '"';
+ for (std::string::const_iterator x= arg.begin(), end= arg.end(); x != end; ++x)
+ {
+ unsigned char c= *x;
+ if (c == '&')
+ {
+ escaped_string+= "&";
+ }
+ else if (c == '>')
+ {
+ escaped_string+= ">";
+ }
+ else if (c == '<')
+ {
+ escaped_string+= "<";
+ }
+ else if (c == '\'')
+ {
+ escaped_string+= "'"; break;
+ }
+ else if (c == '"')
+ {
+ escaped_string+= """;
+ }
+ else if (c == ' ')
+ {
+ escaped_string+= ' ';
+ }
+ else if (isalnum(c))
+ {
+ escaped_string+= c;
+ }
+ else
+ {
+ char const* const hexdig= "0123456789ABCDEF";
+ escaped_string+= "&#x";
+ escaped_string+= hexdig[c >> 4];
+ escaped_string+= hexdig[c & 0xF];
+ escaped_string+= ';';
+ }
+ }
+ escaped_string+= '"';
+
+ return escaped_string;
+}
+
+class TestCase {
+public:
+ TestCase(const std::string& arg):
+ _name(arg),
+ _result(TEST_FAILURE)
+ {
+ }
+
+ const std::string& name() const
+ {
+ return _name;
+ }
+
+ test_return_t result() const
+ {
+ return _result;
+ }
+
+ void result(test_return_t arg)
+ {
+ _result= arg;
+ }
+
+ void result(test_return_t arg, const libtest::Timer& timer_)
+ {
+ _result= arg;
+ _timer= timer_;
+ }
+
+ const libtest::Timer& timer() const
+ {
+ return _timer;
+ }
+
+ void timer(libtest::Timer& arg)
+ {
+ _timer= arg;
+ }
+
+private:
+ std::string _name;
+ test_return_t _result;
+ libtest::Timer _timer;
+};
+
+Formatter::Formatter(const std::string& frame_name, const std::string& arg)
+{
+ _suite_name= frame_name;
+ _suite_name+= ".";
+ _suite_name+= arg;
+}
+
+Formatter::~Formatter()
+{
+ std::for_each(_testcases.begin(), _testcases.end(), DeleteFromVector());
+ _testcases.clear();
+}
+
+TestCase* Formatter::current()
+{
+ return _testcases.back();
+}
+
+void Formatter::skipped()
+{
+ assert(current());
+ current()->result(TEST_SKIPPED);
+
+ Out
+ << "[ " << test_strerror(current()->result()) << " ]"
+ << "\t\t"
+ << name() << "." << current()->name()
+ ;
+
+ reset();
+}
+
+void Formatter::failed()
+{
+ assert(current());
+ current()->result(TEST_FAILURE);
+
+ Out
+ << "[ " << test_strerror(current()->result()) << " ]"
+ << "\t\t"
+ << name() << "." << current()->name()
+ ;
+
+ reset();
+}
+
+void Formatter::success(const libtest::Timer& timer_)
+{
+ assert(current());
+ current()->result(TEST_SUCCESS, timer_);
+
+ Out
+ << "[ " << test_strerror(current()->result()) << " ]"
+ << "\t"
+ << current()->timer()
+ << "\t"
+ << name() << "." << current()->name()
+ ;
+
+ reset();
+}
+
+void Formatter::xml(libtest::Framework& framework_, std::ofstream& output)
+{
+ std::string escaped_string;
+
+ output << "<testsuites name="
+ << escape4XML(framework_.name(), escaped_string) << ">" << std::endl;
+
+ for (Suites::iterator framework_iter= framework_.suites().begin();
+ framework_iter != framework_.suites().end();
+ ++framework_iter)
+ {
+ output << "\t<testsuite name="
+ << escape4XML((*framework_iter)->name(), escaped_string)
+#if 0
+ << " classname=\"\" package=\"\""
+#endif
+ << ">" << std::endl;
+
+ for (TestCases::iterator case_iter= (*framework_iter)->formatter()->testcases().begin();
+ case_iter != (*framework_iter)->formatter()->testcases().end();
+ ++case_iter)
+ {
+ output << "\t\t<testcase name="
+ << escape4XML((*case_iter)->name(), escaped_string)
+ << " time=\""
+ << (*case_iter)->timer().elapsed_milliseconds()
+ << "\"";
+
+ switch ((*case_iter)->result())
+ {
+ case TEST_SKIPPED:
+ output << ">" << std::endl;
+ output << "\t\t <skipped/>" << std::endl;
+ output << "\t\t</testcase>" << std::endl;
+ break;
+
+ case TEST_FAILURE:
+ output << ">" << std::endl;
+ output << "\t\t <failure message=\"\" type=\"\"/>"<< std::endl;
+ output << "\t\t</testcase>" << std::endl;
+ break;
+
+ case TEST_SUCCESS:
+ output << "/>" << std::endl;
+ break;
+ }
+ }
+ output << "\t</testsuite>" << std::endl;
+ }
+ output << "</testsuites>" << std::endl;
+}
+
+void Formatter::push_testcase(const std::string& arg)
+{
+ assert(_suite_name.empty() == false);
+ TestCase* _current_testcase= new TestCase(arg);
+ _testcases.push_back(_current_testcase);
+
+ assert(current());
+
+ Echo
+ << "\t\t\t"
+ << name() << "." << current()->name()
+ << "... \r"
+ ;
+}
+
+void Formatter::reset()
+{
+}
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <string>
+
+namespace libtest { class Framework; }
+
+
+namespace libtest {
+
+class TestCase;
+typedef std::vector<libtest::TestCase*> TestCases;
+
+class Formatter {
+public:
+ Formatter(const std::string& frame_name, const std::string& arg);
+
+ ~Formatter();
+
+ void skipped();
+
+ void failed();
+
+ void success(const libtest::Timer&);
+
+ void push_testcase(const std::string&);
+
+ const std::string& name() const
+ {
+ return _suite_name;
+ }
+
+ TestCases& testcases()
+ {
+ return _testcases;
+ }
+
+ static void xml(libtest::Framework&, std::ofstream&);
+
+private:
+ void reset();
+
+ TestCase* current();
+
+private:
+ std::string _suite_name;
+ TestCases _testcases;
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/common.h>
+#include <libtest/collection.h>
+#include <libtest/signal.h>
+
+#include <algorithm>
+#include <fnmatch.h>
+#include <iostream>
+
+namespace libtest {
+
+Framework::Framework(libtest::SignalThread& signal_,
+ const std::string& name_,
+ const std::string& only_run_arg,
+ const std::string& wildcard_arg) :
+ _total(0),
+ _success(0),
+ _skipped(0),
+ _failed(0),
+ _create(NULL),
+ _destroy(NULL),
+ _on_error(NULL),
+ _runner(NULL),
+ _socket(false),
+ _creators_ptr(NULL),
+ _signal(signal_),
+ _only_run(only_run_arg),
+ _wildcard(wildcard_arg),
+ _name(name_)
+{
+ get_world(this);
+}
+
+void Framework::collections(collection_st collections_[])
+{
+ for (collection_st *next= collections_; next and next->name; next++)
+ {
+ _collection.push_back(new Collection(this, next));
+ }
+}
+
+Framework::~Framework()
+{
+ if (_destroy and _destroy(_creators_ptr))
+ {
+ Error << "Failure in _destroy(), some resources may not have been cleaned up.";
+ }
+
+ _servers.shutdown();
+
+ delete _runner;
+
+ std::for_each(_collection.begin(), _collection.end(), DeleteFromVector());
+ _collection.clear();
+}
+
+bool Framework::match(const char* arg)
+{
+ if (_wildcard.empty() == false and fnmatch(_wildcard.c_str(), arg, 0))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void Framework::exec()
+{
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end() and (_signal.is_shutdown() == false);
+ ++iter)
+ {
+ if (*iter)
+ {
+ if (_only_run.empty() == false and
+ fnmatch(_only_run.c_str(), (*iter)->name(), 0))
+ {
+ continue;
+ }
+
+ _total++;
+
+ try {
+ switch ((*iter)->exec())
+ {
+ case TEST_FAILURE:
+ _failed++;
+ break;
+
+ case TEST_SKIPPED:
+ _skipped++;
+ break;
+
+ // exec() can return SUCCESS, but that doesn't mean that some tests did
+ // not fail or get skipped.
+ case TEST_SUCCESS:
+ _success++;
+ break;
+ }
+ }
+ catch (const libtest::fatal& e)
+ {
+ _failed++;
+ stream::cerr(e.file(), e.line(), e.func()) << e.what();
+ }
+ catch (const libtest::disconnected& e)
+ {
+ _failed++;
+ Error << "Unhandled disconnection occurred:" << e.what();
+ throw;
+ }
+ catch (...)
+ {
+ _failed++;
+ throw;
+ }
+ }
+ }
+
+ void xml(const std::string& testsuites_name, std::ostream& output);
+}
+
+uint32_t Framework::sum_total()
+{
+ uint32_t count= 0;
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end();
+ ++iter)
+ {
+ count+= (*iter)->total();
+ }
+
+ return count;
+}
+
+uint32_t Framework::sum_success()
+{
+ uint32_t count= 0;
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end();
+ ++iter)
+ {
+ count+= (*iter)->success();
+ }
+
+ return count;
+}
+
+uint32_t Framework::sum_skipped()
+{
+ uint32_t count= 0;
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end();
+ ++iter)
+ {
+ count+= (*iter)->skipped();
+ }
+
+ return count;
+}
+
+uint32_t Framework::sum_failed()
+{
+ uint32_t count= 0;
+ for (std::vector<Collection*>::iterator iter= _collection.begin();
+ iter != _collection.end();
+ ++iter)
+ {
+ count+= (*iter)->failed();
+ }
+
+ return count;
+}
+
+libtest::Runner *Framework::runner()
+{
+ if (_runner == NULL)
+ {
+ _runner= new Runner;
+ }
+ _runner->set_servers(_servers);
+
+ return _runner;
+}
+
+test_return_t Framework::create()
+{
+ test_return_t rc= TEST_SUCCESS;
+ if (_create)
+ {
+ _creators_ptr= _create(_servers, rc);
+ }
+
+ return rc;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libtest/signal.h>
+
+/**
+ Framework 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.
+*/
+
+#include <vector>
+
+namespace { class Collection; }
+typedef std::vector<libtest::Collection*> Suites;
+
+namespace libtest {
+
+class Framework {
+public:
+
+public:
+ test_return_t create();
+
+ const std::string& name() const
+ {
+ return _name;
+ }
+
+ void create(test_callback_create_fn* arg)
+ {
+ _create= arg;
+ }
+
+ void destroy(test_callback_destroy_fn* arg)
+ {
+ _destroy= arg;
+ }
+
+ void collections(collection_st arg[]);
+
+ void set_on_error(test_callback_error_fn *arg)
+ {
+ _on_error= arg;
+ }
+
+ test_return_t on_error(const enum test_return_t, void *);
+
+ void set_socket()
+ {
+ _servers.set_socket();
+ }
+
+ void set_sasl(const std::string& username_arg, const std::string& password_arg)
+ {
+ _servers.set_sasl(username_arg, password_arg);
+ }
+
+ libtest::server_startup_st& servers()
+ {
+ return _servers;
+ }
+
+ void set_runner(libtest::Runner *arg)
+ {
+ _runner= arg;
+ }
+
+ libtest::Runner *runner();
+
+ void exec();
+
+ libtest::Collection& collection();
+
+ virtual ~Framework();
+
+ Framework(libtest::SignalThread&,
+ const std::string&,
+ const std::string&,
+ const std::string&);
+
+ bool match(const char* arg);
+
+ void *creators_ptr()
+ {
+ return _creators_ptr;
+ }
+
+ libtest::SignalThread& signal()
+ {
+ return _signal;
+ }
+
+ uint32_t sum_total();
+ uint32_t sum_success();
+ uint32_t sum_skipped();
+ uint32_t sum_failed();
+
+ size_t size()
+ {
+ return _collection.size();
+ }
+
+ uint32_t total() const
+ {
+ return _total;
+ }
+
+ uint32_t success() const
+ {
+ return _success;
+ }
+
+ uint32_t skipped() const
+ {
+ return _skipped;
+ }
+
+ uint32_t failed() const
+ {
+ return _failed;
+ }
+
+ Suites& suites()
+ {
+ return _collection;
+ }
+
+private:
+ uint32_t _total;
+ uint32_t _success;
+ uint32_t _skipped;
+ uint32_t _failed;
+
+ /* These methods are called outside of any collection call. */
+ test_callback_create_fn *_create;
+ test_callback_destroy_fn *_destroy;
+
+ /**
+ If an error occurs during the test, this is called.
+ */
+ test_callback_error_fn *_on_error;
+
+ /**
+ Runner represents the callers for the tests. If not implemented we will use
+ a set of default implementations.
+ */
+ libtest::Runner *_runner;
+
+ libtest::server_startup_st _servers;
+ bool _socket;
+ void *_creators_ptr;
+ unsigned long int _servers_to_run;
+ Suites _collection;
+ libtest::SignalThread& _signal;
+ std::string _only_run;
+ std::string _wildcard;
+ std::string _name;
+
+private:
+ Framework( const Framework& );
+ const Framework& operator=( const Framework& );
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <libtest/gearmand.h>
+
+using namespace libtest;
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <signal.h>
+#include <sstream>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+using namespace libtest;
+
+class Gearmand : public libtest::Server
+{
+private:
+public:
+ Gearmand(const std::string& host_arg, in_port_t port_arg, bool libtool_, const char* binary);
+
+ bool ping()
+ {
+ reset_error();
+
+ if (out_of_ban_killed())
+ {
+ return false;
+ }
+
+ SimpleClient client(_hostname, _port);
+
+ std::string response;
+ bool ret= client.send_message("version", response);
+
+ if (client.is_error())
+ {
+ error(client.error());
+ }
+
+ return ret;
+ }
+
+ const char *name()
+ {
+ return "gearmand";
+ };
+
+ void log_file_option(Application& app, const std::string& arg)
+ {
+ if (arg.empty() == false)
+ {
+ std::string buffer("--log-file=");
+ buffer+= arg;
+ app.add_option("--verbose=DEBUG");
+ app.add_option(buffer);
+ }
+ }
+
+ bool has_log_file_option() const
+ {
+ return true;
+ }
+
+ bool is_libtool()
+ {
+ return true;
+ }
+
+ bool has_syslog() const
+ {
+ return false; // --syslog.errmsg-enable
+ }
+
+ bool has_port_option() const
+ {
+ return true;
+ }
+
+ bool build();
+};
+
+Gearmand::Gearmand(const std::string& host_arg, in_port_t port_arg, bool libtool_, const char* binary_arg) :
+ libtest::Server(host_arg, port_arg, binary_arg, libtool_)
+{
+ set_pid_file();
+}
+
+bool Gearmand::build()
+{
+ if (getuid() == 0 or geteuid() == 0)
+ {
+ add_option("-u", "root");
+ }
+
+ add_option("--listen=localhost");
+
+ return true;
+}
+
+namespace libtest {
+
+libtest::Server *build_gearmand(const char *hostname, in_port_t try_port, const char* binary)
+{
+ if (binary == NULL)
+ {
+#if defined(HAVE_GEARMAND_BINARY)
+# if defined(GEARMAND_BINARY)
+ if (HAVE_GEARMAND_BINARY)
+ {
+ binary= GEARMAND_BINARY;
+ }
+# endif
+#endif
+ }
+
+ if (binary == NULL)
+ {
+ return NULL;
+ }
+
+ bool is_libtool_script= true;
+
+ if (binary[0] == '/')
+ {
+ is_libtool_script= false;
+ }
+
+ return new Gearmand(hostname, try_port, is_libtool_script, binary);
+}
+
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest { struct Server; }
+
+namespace libtest {
+
+libtest::Server *build_gearmand(const char *hostname, in_port_t try_port, const char* binary= NULL);
+
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* How we make all of this work :) */
+ LIBTEST_API
+ void get_world(libtest::Framework *world);
+
+#ifdef __cplusplus
+}
+#endif
+
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <unistd.h>
+
+namespace libtest {
+
+bool has_libmemcached_sasl(void)
+{
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+ return LIBMEMCACHED_WITH_SASL_SUPPORT;
+#else
+ return false;
+#endif
+}
+
+bool has_libmemcached(void)
+{
+#if defined(HAVE_LIBMEMCACHED) && HAVE_LIBMEMCACHED
+ if (HAVE_LIBMEMCACHED)
+ {
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+bool has_libdrizzle(void)
+{
+#if defined(HAVE_LIBDRIZZLE) && HAVE_LIBDRIZZLE
+ if (HAVE_LIBDRIZZLE)
+ {
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+bool has_postgres_support(void)
+{
+ char *getenv_ptr;
+ if (bool((getenv_ptr= getenv("POSTGRES_IS_RUNNING_AND_SETUP"))))
+ {
+ (void)(getenv_ptr);
+#if defined(HAVE_LIBPQ) && HAVE_LIBPQ
+ if (HAVE_LIBPQ)
+ {
+ return true;
+ }
+#endif
+ }
+
+ return false;
+}
+
+
+bool has_gearmand()
+{
+#if defined(GEARMAND_BINARY) && defined(HAVE_GEARMAND_BINARY) && HAVE_GEARMAND_BINARY
+ if (HAVE_GEARMAND_BINARY)
+ {
+ std::stringstream arg_buffer;
+
+ char *getenv_ptr;
+ if (bool((getenv_ptr= getenv("PWD"))) and
+ ((strcmp(GEARMAND_BINARY, "./gearmand/gearmand") == 0) or (strcmp(GEARMAND_BINARY, "gearmand/gearmand") == 0)))
+ {
+ arg_buffer << getenv_ptr;
+ arg_buffer << "/";
+ }
+ arg_buffer << GEARMAND_BINARY;
+
+ if (access(arg_buffer.str().c_str(), X_OK) == 0)
+ {
+ return true;
+ }
+ }
+#endif
+
+ return false;
+}
+
+bool has_drizzled()
+{
+#if defined(DRIZZLED_BINARY) && defined(HAVE_DRIZZLED_BINARY) && HAVE_DRIZZLED_BINARY
+ if (HAVE_DRIZZLED_BINARY)
+ {
+ if (access(DRIZZLED_BINARY, X_OK) == 0)
+ {
+ return true;
+ }
+ }
+#endif
+
+ return false;
+}
+
+bool has_mysqld()
+{
+#if defined(MYSQLD_BINARY) && defined(HAVE_MYSQLD_BUILD) && HAVE_MYSQLD_BUILD
+ if (HAVE_MYSQLD_BUILD)
+ {
+ if (access(MYSQLD_BINARY, X_OK) == 0)
+ {
+ return true;
+ }
+ }
+#endif
+
+ return false;
+}
+
+static char memcached_binary_path[FILENAME_MAX];
+
+static void initialize_memcached_binary_path()
+{
+ memcached_binary_path[0]= 0;
+
+#if defined(MEMCACHED_BINARY) && defined(HAVE_MEMCACHED_BINARY) && HAVE_MEMCACHED_BINARY
+ if (HAVE_MEMCACHED_BINARY)
+ {
+ std::stringstream arg_buffer;
+
+ char *getenv_ptr;
+ if (bool((getenv_ptr= getenv("PWD"))) and strcmp(MEMCACHED_BINARY, "memcached/memcached") == 0)
+ {
+ arg_buffer << getenv_ptr;
+ arg_buffer << "/";
+ }
+ arg_buffer << MEMCACHED_BINARY;
+
+ if (access(arg_buffer.str().c_str(), X_OK) == 0)
+ {
+ strncpy(memcached_binary_path, arg_buffer.str().c_str(), FILENAME_MAX-1);
+ }
+ }
+#endif
+}
+
+static pthread_once_t memcached_binary_once= PTHREAD_ONCE_INIT;
+static void initialize_memcached_binary(void)
+{
+ int ret;
+ if ((ret= pthread_once(&memcached_binary_once, initialize_memcached_binary_path)) != 0)
+ {
+ FATAL(strerror(ret));
+ }
+}
+
+bool has_memcached()
+{
+ initialize_memcached_binary();
+
+ if (memcached_binary_path[0] and (strlen(memcached_binary_path) > 0))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+const char* memcached_binary()
+{
+ initialize_memcached_binary();
+
+ if (memcached_binary_path[0])
+ {
+ return memcached_binary_path;
+ }
+
+ return NULL;
+}
+
+const char *gearmand_binary()
+{
+#if defined(GEARMAND_BINARY)
+ return GEARMAND_BINARY;
+#else
+ return NULL;
+#endif
+}
+
+const char *drizzled_binary()
+{
+#if defined(DRIZZLED_BINARY)
+ return DRIZZLED_BINARY;
+#else
+ return NULL;
+#endif
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+LIBTEST_API
+bool has_libmemcached_sasl(void);
+
+LIBTEST_API
+bool has_libmemcached();
+
+LIBTEST_API
+bool has_libdrizzle();
+
+LIBTEST_API
+bool has_postgres_support();
+
+LIBTEST_API
+bool has_memcached();
+
+LIBTEST_API
+bool has_memcached_sasl();
+
+LIBTEST_API
+bool has_gearmand();
+
+LIBTEST_API
+bool has_drizzled();
+
+LIBTEST_API
+bool has_mysqld();
+
+LIBTEST_API
+const char* memcached_binary();
+
+LIBTEST_API
+const char *gearmand_binary();
+
+LIBTEST_API
+const char *drizzled_binary();
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/common.h>
+
+#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
+#include <curl/curl.h>
+#else
+class CURL;
+#endif
+
+
+static void cleanup_curl(void)
+{
+#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
+ curl_global_cleanup();
+#endif
+}
+
+static void initialize_curl_startup()
+{
+#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
+ if (curl_global_init(CURL_GLOBAL_ALL))
+ {
+ FATAL("curl_global_init(CURL_GLOBAL_ALL) failed");
+ }
+#endif
+
+ if (atexit(cleanup_curl))
+ {
+ FATAL("atexit() failed");
+ }
+}
+
+static pthread_once_t start_key_once= PTHREAD_ONCE_INIT;
+static void initialize_curl(void)
+{
+ int ret;
+ if ((ret= pthread_once(&start_key_once, initialize_curl_startup)) != 0)
+ {
+ FATAL(strerror(ret));
+ }
+}
+
+namespace libtest {
+namespace http {
+
+#define YATL_USERAGENT "YATL/1.0"
+
+static size_t http_get_result_callback(void *ptr, size_t size, size_t nmemb, void *data)
+{
+ vchar_t *_body= (vchar_t*)data;
+
+ _body->resize(size * nmemb);
+ memcpy(&(*_body)[0], ptr, _body->size());
+
+ return _body->size();
+}
+
+static void init(CURL *curl, const std::string& url)
+{
+ (void)http_get_result_callback;
+ (void)curl;
+ (void)url;
+#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
+ if (HAVE_LIBCURL)
+ {
+ assert(curl);
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, YATL_USERAGENT);
+ }
+#endif
+}
+
+HTTP::HTTP(const std::string& url_arg) :
+ _url(url_arg),
+ _response(0)
+{
+ initialize_curl();
+}
+
+bool GET::execute()
+{
+ (void)init;
+
+#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
+ if (HAVE_LIBCURL)
+ {
+ CURL *curl= curl_easy_init();
+
+ init(curl, url());
+
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_callback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&_body);
+
+ CURLcode retref= curl_easy_perform(curl);
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response);
+
+ curl_easy_cleanup(curl);
+
+ return bool(retref == CURLE_OK);
+ }
+#endif
+
+ return false;
+}
+
+bool POST::execute()
+{
+#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
+ if (HAVE_LIBCURL)
+ {
+ CURL *curl= curl_easy_init();;
+
+ init(curl, url());
+
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, _body.size());
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (void *)&_body[0]);
+
+ CURLcode retref= curl_easy_perform(curl);
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response);
+
+ curl_easy_cleanup(curl);
+
+ return bool(retref == CURLE_OK);
+ }
+#endif
+
+ return false;
+}
+
+bool TRACE::execute()
+{
+#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
+ if (HAVE_LIBCURL)
+ {
+ CURL *curl= curl_easy_init();;
+
+ init(curl, url());
+
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "TRACE");
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_callback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&_body[0]);
+
+ CURLcode retref= curl_easy_perform(curl);
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response);
+
+ curl_easy_cleanup(curl);
+
+ return retref == CURLE_OK;
+ }
+#endif
+
+ return false;
+}
+
+bool HEAD::execute()
+{
+#if defined(HAVE_LIBCURL) && HAVE_LIBCURL
+ if (HAVE_LIBCURL)
+ {
+ CURL *curl= curl_easy_init();
+
+ init(curl, url());
+
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD");
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_callback);
+
+ CURLcode retref= curl_easy_perform(curl);
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, _response);
+
+ curl_easy_cleanup(curl);
+
+ return retref == CURLE_OK;
+ }
+#endif
+
+ return false;
+}
+
+} // namespace http
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libtest/vchar.hpp>
+
+namespace libtest {
+namespace http {
+
+class HTTP {
+public:
+
+ HTTP(const std::string& url_arg);
+
+ virtual bool execute()= 0;
+
+ virtual ~HTTP()
+ { }
+
+ const std::string& url() const
+ {
+ return _url;
+ }
+
+ long response()
+ {
+ return _response;
+ }
+
+private:
+ std::string _url;
+
+protected:
+ long _response;
+};
+
+class GET: public HTTP {
+public:
+
+ GET(const std::string& url_arg) :
+ HTTP(url_arg)
+ {
+ }
+
+ bool execute();
+
+private:
+ libtest::vchar_t _body;
+};
+
+class POST: public HTTP {
+public:
+
+ POST(const std::string& url_arg,
+ const vchar_t& post_arg) :
+ HTTP(url_arg),
+ _post(post_arg)
+ {
+ }
+
+ bool execute();
+
+private:
+ libtest::vchar_t _post;
+ libtest::vchar_t _body;
+};
+
+class TRACE: public HTTP {
+public:
+
+ TRACE(const std::string& url_arg,
+ const vchar_t& body_arg) :
+ HTTP(url_arg),
+ _body(body_arg)
+ {
+ }
+
+ bool execute();
+
+private:
+ libtest::vchar_t _body;
+};
+
+class HEAD: public HTTP {
+public:
+
+ HEAD(const std::string& url_arg) :
+ HTTP(url_arg)
+ {
+ }
+
+ bool execute();
+
+private:
+};
+
+} // namespace http
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+
+namespace libtest {
+
+bool test_is_local()
+{
+ return (getenv("LIBTEST_LOCAL"));
+}
+
+static bool _is_massive= false;
+void is_massive(bool arg)
+{
+ _is_massive= arg;
+}
+
+bool is_massive()
+{
+ return _is_massive;
+}
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+LIBTEST_API
+bool test_is_local();
+
+LIBTEST_API
+void is_massive(bool);
+
+LIBTEST_API
+bool is_massive();
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+static inline bool is_pid_valid(const pid_t pid)
+{
+ return (pid > 1) ? true : false;
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+
+#include <libtest/killpid.h>
+#include <libtest/stream.h>
+
+using namespace libtest;
+
+bool kill_pid(pid_t pid_arg)
+{
+ assert(pid_arg > 0);
+ if (pid_arg < 1)
+ {
+ Error << "Invalid pid:" << pid_arg;
+ return false;
+ }
+
+ if ((::kill(pid_arg, SIGTERM) == -1))
+ {
+ switch (errno)
+ {
+ case EPERM:
+ Error << "Does someone else have a process running locally for " << int(pid_arg) << "?";
+ return false;
+
+ case ESRCH:
+ Error << "Process " << int(pid_arg) << " not found.";
+ return false;
+
+ default:
+ case EINVAL:
+ Error << "kill() " << strerror(errno);
+ return false;
+ }
+ }
+
+ {
+ uint32_t this_wait= 0;
+ uint32_t timeout= 20; // This number should be high enough for valgrind startup (which is slow)
+ uint32_t waited;
+ uint32_t retry;
+
+ for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
+ {
+ int status= 0;
+ if (waitpid(pid_arg, &status, WNOHANG) == 0)
+ {
+ break;
+ }
+ else if (errno == ECHILD)
+ {
+ // Server has already gone away
+ break;
+ }
+ else if (waited >= timeout)
+ {
+ // Timeout failed
+ kill(pid_arg, SIGKILL);
+ break;
+ }
+
+ this_wait= retry * retry / 3 + 1;
+ libtest::dream(this_wait, 0);
+ }
+ }
+
+ return true;
+}
+
+bool check_pid(const std::string &filename)
+{
+ if (filename.empty())
+ {
+ return false;
+ }
+
+ FILE *fp;
+ if ((fp= fopen(filename.c_str(), "r")))
+ {
+ libtest::vchar_t pid_buffer;
+ pid_buffer.resize(1024);
+
+ char *ptr= fgets(&pid_buffer[0], int(pid_buffer.size()), fp);
+ fclose(fp);
+
+ if (ptr)
+ {
+ pid_t pid= (pid_t)atoi(&pid_buffer[0]);
+ if (pid > 0)
+ {
+ return (::kill(pid, 0) == 0);
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool kill_file(const std::string &filename)
+{
+ if (filename.empty())
+ {
+ return true;
+ }
+
+ FILE *fp;
+ if ((fp= fopen(filename.c_str(), "r")))
+ {
+ libtest::vchar_t pid_buffer;
+ pid_buffer.resize(1024);
+
+ char *ptr= fgets(&pid_buffer[0], int(pid_buffer.size()), fp);
+ fclose(fp);
+
+ if (ptr)
+ {
+ pid_t pid= (pid_t)atoi(&pid_buffer[0]);
+ if (pid != 0)
+ {
+ bool ret= kill_pid(pid);
+ unlink(filename.c_str()); // If this happens we may be dealing with a dead server that left its pid file.
+
+ return ret;
+ }
+ }
+ }
+
+ return false;
+}
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define LIBTEST_AT __FILE__ ":" TOSTRING(__LINE__)
+
+pid_t get_pid_from_file(const std::string &filename, std::stringstream& error_message)
+{
+ pid_t ret= -1;
+
+ if (filename.empty())
+ {
+ error_message << LIBTEST_AT << " empty pid file";
+ return ret;
+ }
+
+ FILE *fp;
+ if ((fp= fopen(filename.c_str(), "r")))
+ {
+ libtest::vchar_t pid_buffer;
+ pid_buffer.resize(1024);
+
+ char *ptr= fgets(&pid_buffer[0], int(pid_buffer.size()), fp);
+ if (ptr)
+ {
+ ret= (pid_t)atoi(&pid_buffer[0]);
+ if (ret < 1)
+ {
+ error_message << LIBTEST_AT << " Invalid pid was read from file " << filename;
+ }
+ }
+ else
+ {
+ error_message << LIBTEST_AT << " File " << filename << " was empty ";
+ }
+
+ fclose(fp);
+
+ return ret;
+ }
+ else
+ {
+ libtest::vchar_t buffer;
+ buffer.resize(1024);
+ char *current_directory= getcwd(&buffer[0], buffer.size());
+ error_message << "Error while opening " << current_directory << "/" << filename << " " << strerror(errno);
+ }
+
+ return ret;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+bool kill_pid(pid_t pid_arg);
+
+bool kill_file(const std::string &filename);
+
+bool check_pid(const std::string &filename);
+
+pid_t get_pid_from_file(const std::string &filename, std::stringstream& error_message);
+
+static inline bool check_pid(pid_t pid_arg)
+{
+ return (pid_arg > 1);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+#include <string>
+
+char _libtool[1024]= { 0 };
+
+namespace libtest {
+
+const char *libtool(void)
+{
+ if (_libtool[0] == 0)
+ {
+ std::string libtool_buffer;
+ if (getenv("PWD"))
+ {
+ libtool_buffer+= getenv("PWD");
+ libtool_buffer+= "/";
+ }
+ else
+ {
+ libtool_buffer+= "./";
+ }
+
+ libtool_buffer+= "libtool";
+ if (access(libtool_buffer.c_str(), R_OK | W_OK | X_OK))
+ {
+ Error << "Could not find libtool via access(" << libtool_buffer << ") :" << strerror(errno);
+ return NULL;
+ }
+
+ snprintf(_libtool, sizeof(_libtool), "%s", libtool_buffer.c_str());
+ }
+
+ return _libtool;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+const char *libtool(void);
+
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+# include <cstdarg>
+# include <cstddef>
+# include <cstdio>
+# include <cstdlib>
+# include <cstring>
+#else
+# include <stdarg.h>
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#if defined(WIN32)
+# include <malloc.h>
+#else
+# include <alloca.h>
+#endif
+
+#ifndef __PRETTY_FUNCTION__
+# define __PRETTY_FUNCTION__ __func__
+#endif
+
+#ifndef EXIT_SKIP
+# define EXIT_SKIP 77
+#endif
+
+#ifndef YATL_FULL
+# define YATL_FULL 0
+#endif
+
+#ifndef FAIL
+# define FAIL(__message_format, ...)
+#endif
+
+#ifndef SKIP
+# define SKIP(__message_format, ...)
+#endif
+
+#include <libtest/valgrind.h>
+
+static inline size_t yatl_strlen(const char *s)
+{
+ if (s)
+ {
+ return strlen(s);
+ }
+
+ return (size_t)(0);
+}
+
+static inline int yatl_strcmp(const char *s1, const char *s2, size_t *s1_length, size_t *s2_length)
+{
+ *s1_length= yatl_strlen(s1);
+ *s2_length= yatl_strlen(s2);
+
+ if (*s1_length == 0 && *s1_length == *s2_length)
+ {
+ return 0;
+ }
+
+ if (*s1_length == 0 && *s2_length)
+ {
+ return 1;
+ }
+
+ if (*s1_length && *s2_length == 0)
+ {
+ return 1;
+ }
+
+ return strcmp(s1, s2);
+}
+
+#define SKIP_IF(__expression) \
+do \
+{ \
+ if ((__expression)) { \
+ if (YATL_FULL) { \
+ SKIP(#__expression); \
+ } \
+ fprintf(stdout, "\n%s:%d: %s SKIP '!(%s)'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression); \
+ exit(EXIT_SKIP); \
+ } \
+} while (0)
+
+#define SKIP_IF_(__expression, ...) \
+do \
+{ \
+ if ((__expression)) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ SKIP(#__expression, buffer); \
+ } \
+ fprintf(stdout, "\n%s:%d: %s SKIP '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer); \
+ exit(EXIT_SKIP); \
+ } \
+} while (0)
+
+#define SKIP_UNLESS(__expression) \
+do \
+{ \
+ if (! (__expression)) { \
+ if (YATL_FULL) { \
+ SKIP(#__expression); \
+ } \
+ fprintf(stdout, "\n%s:%d: %s SKIP '(%s)'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression); \
+ exit(EXIT_SKIP); \
+ } \
+} while (0)
+
+#define SKIP_UNLESS_(__expression, ...) \
+do \
+{ \
+ if (! (__expression)) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ SKIP(#__expression, buffer); \
+ } \
+ fprintf(stdout, "\n%s:%d: %s SKIP '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer); \
+ exit(EXIT_SKIP); \
+ } \
+} while (0)
+
+#define ASSERT_TRUE(__expression) \
+do \
+{ \
+ if (! (__expression)) { \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%s'", #__expression); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression);\
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_FALSE(__expression) \
+do \
+{ \
+ if ((__expression)) { \
+ if (YATL_FULL) { \
+ FAIL("Assertion '!%s'", #__expression); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '!%s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression);\
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_NULL_(__expression, ...) \
+do \
+{ \
+ if ((__expression) != NULL) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%s' != NULL [ %s ]", #__expression, buffer);\
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%s' != NULL [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer);\
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_NOT_NULL(__expression) \
+do \
+{ \
+ if ((__expression) == NULL) { \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%s' == NULL", #__expression,);\
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%s' == NULL\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression,);\
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_NOT_NULL_(__expression, ...) \
+do \
+{ \
+ if ((__expression) == NULL) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%s' == NULL [ %s ]", #__expression, buffer);\
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%s' == NULL [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer);\
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_TRUE_(__expression, ...) \
+do \
+{ \
+ if (! (__expression)) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%s' [ %s ]", #__expression, buffer); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer); \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_EQ(__expected, __actual) \
+do \
+{ \
+ if ((__expected) != (__actual)) { \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%s' != '%s'", #__expected, #__actual); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%s' != '%s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expected, #__actual); \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_EQ_(__expected, __actual, ...) \
+do \
+{ \
+ if ((__expected) != (__actual)) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%s' != '%s' [ %s ]", #__expected, #__actual, buffer); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%s' != '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expected, #__actual, buffer); \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_STREQ(__expected_str, __actual_str) \
+do \
+{ \
+ size_t __expected_length; \
+ size_t __actual_length; \
+ int ret= yatl_strcmp(__expected_str, __actual_str, &__expected_length, &__actual_length); \
+ if (ret) { \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%.*s' != '%.*s'\n", \
+ (int)(__expected_length), (__expected_str), \
+ (int)__actual_length, (__actual_str)) ; \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%.*s' != '%.*s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, \
+ (int)(__expected_length), (__expected_str), \
+ (int)__actual_length, (__actual_str)) ; \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_STREQ_(__expected_str, __actual_str, ...) \
+do \
+{ \
+ size_t __expected_length; \
+ size_t __actual_length; \
+ int ret= yatl_strcmp(__expected_str, __actual_str, &__expected_length, &__actual_length); \
+ if (ret) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ ask= snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%.*s' != '%.*s' [ %.*s ]", \
+ (int)(__expected_length), (__expected_str), \
+ (int)(__actual_length), (__actual_str), \
+ (int)(ask), buffer); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%.*s' != '%.*s' [ %.*s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, \
+ (int)(__expected_length), (__expected_str), \
+ (int)(__actual_length), (__actual_str), \
+ (int)(ask), buffer); \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_STRNE(__expected_str, __actual_str) \
+do \
+{ \
+ size_t __expected_length; \
+ size_t __actual_length; \
+ int ret= yatl_strcmp(__expected_str, __actual_str, &__expected_length, &__actual_length); \
+ if (ret == 0) { \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%.*s' == '%.*s'", \
+ (int)(__expected_length), (__expected_str), \
+ (int)__actual_length, (__actual_str)) ; \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%.*s' == '%.*s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, \
+ (int)(__expected_length), (__expected_str), \
+ (int)__actual_length, (__actual_str)) ; \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_STRNE_(__expected_str, __actual_str, ...) \
+do \
+{ \
+ size_t __expected_length; \
+ size_t __actual_length; \
+ int ret= yatl_strcmp(__expected_str, __actual_str, &__expected_length, &__actual_length); \
+ if (ret == 0) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ ask= snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%.*s' == '%.*s' [ %.*s ]", \
+ (int)(__expected_length), (__expected_str), \
+ (int)(__actual_length), (__actual_str), \
+ (int)(ask), buffer); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%.*s' == '%.*s' [ %.*s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, \
+ (int)(__expected_length), (__expected_str), \
+ (int)(__actual_length), (__actual_str), \
+ (int)(ask), buffer); \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_NEQ(__expected, __actual) \
+do \
+{ \
+ if ((__expected) == (__actual)) { \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%s' == '%s'", #__expected, #__actual); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%s' == '%s'\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expected, #__actual); \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_NEQ_(__expected, __actual, ...) \
+do \
+{ \
+ if ((__expected) == (__actual)) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ FAIL("Assertion '%s' == '%s' [ %s ]", #__expected, #__actual, buffer); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '%s' == '%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expected, #__actual, buffer); \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+#define ASSERT_FALSE_(__expression, ...) \
+do \
+{ \
+ if ((__expression)) { \
+ size_t ask= snprintf(0, 0, __VA_ARGS__); \
+ ask++; \
+ char *buffer= (char*)alloca(sizeof(char) * ask); \
+ snprintf(buffer, ask, __VA_ARGS__); \
+ if (YATL_FULL) { \
+ FAIL("Assertion '!%s' [ %s ]", #__expression, buffer); \
+ } \
+ fprintf(stderr, "\n%s:%d: %s Assertion '!%s' [ %s ]\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, #__expression, buffer); \
+ exit(EXIT_FAILURE); \
+ } \
+} while (0)
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <fnmatch.h>
+#include <iostream>
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#include <fstream>
+#include <memory>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <signal.h>
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+#if __cplusplus >= 201103L
+# define UNIQUE_PTR std::unique_ptr
+#else
+# define UNIQUE_PTR std::auto_ptr
+#endif
+
+using namespace libtest;
+
+static void stats_print(libtest::Framework *frame)
+{
+ if (frame->failed() == 0 and frame->success() == 0)
+ {
+ return;
+ }
+
+ Outn();
+ Out << "Collections\t\t\t\t\t" << frame->total();
+ Out << "\tFailed\t\t\t\t\t" << frame->failed();
+ Out << "\tSkipped\t\t\t\t\t" << frame->skipped();
+ Out << "\tSucceeded\t\t\t\t" << frame->success();
+ Outn();
+ Out << "Tests\t\t\t\t\t" << frame->sum_total();
+ Out << "\tFailed\t\t\t\t" << frame->sum_failed();
+ Out << "\tSkipped\t\t\t\t" << frame->sum_skipped();
+ Out << "\tSucceeded\t\t\t" << frame->sum_success();
+}
+
+#include <getopt.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ bool opt_massive= false;
+ unsigned long int opt_repeat= 1; // Run all tests once
+ bool opt_quiet= false;
+ std::string collection_to_run;
+ std::string wildcard;
+ std::string binary_name;
+
+ const char *just_filename= rindex(argv[0], '/');
+ if (just_filename)
+ {
+ just_filename++;
+ }
+ else
+ {
+ just_filename= argv[0];
+ }
+
+ if (just_filename[0] == 'l' and just_filename[1] == 't' and just_filename[2] == '-')
+ {
+ just_filename+= 3;
+ }
+ binary_name.append(just_filename);
+
+ /*
+ Valgrind does not currently work reliably, or sometimes at all, on OSX
+ - Fri Jun 15 11:24:07 EDT 2012
+ */
+#if defined(__APPLE__) && __APPLE__
+ if (valgrind_is_caller())
+ {
+ return EXIT_SKIP;
+ }
+#endif
+
+ // Options parsing
+ {
+ enum long_option_t {
+ OPT_LIBYATL_VERSION,
+ OPT_LIBYATL_MATCH_COLLECTION,
+ OPT_LIBYATL_MASSIVE,
+ OPT_LIBYATL_QUIET,
+ OPT_LIBYATL_MATCH_WILDCARD,
+ OPT_LIBYATL_REPEAT
+ };
+
+ static struct option long_options[]=
+ {
+ { "version", no_argument, NULL, OPT_LIBYATL_VERSION },
+ { "quiet", no_argument, NULL, OPT_LIBYATL_QUIET },
+ { "repeat", required_argument, NULL, OPT_LIBYATL_REPEAT },
+ { "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION },
+ { "wildcard", required_argument, NULL, OPT_LIBYATL_MATCH_WILDCARD },
+ { "massive", no_argument, NULL, OPT_LIBYATL_MASSIVE },
+ { 0, 0, 0, 0 }
+ };
+
+ int option_index= 0;
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
+ if (option_rv == -1)
+ {
+ break;
+ }
+
+ switch (option_rv)
+ {
+ case OPT_LIBYATL_VERSION:
+ break;
+
+ case OPT_LIBYATL_QUIET:
+ opt_quiet= true;
+ break;
+
+ case OPT_LIBYATL_REPEAT:
+ errno= 0;
+ opt_repeat= strtoul(optarg, (char **) NULL, 10);
+ if (errno != 0)
+ {
+ Error << "unknown value passed to --repeat: `" << optarg << "`";
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_LIBYATL_MATCH_COLLECTION:
+ collection_to_run= optarg;
+ break;
+
+ case OPT_LIBYATL_MATCH_WILDCARD:
+ wildcard= optarg;
+ break;
+
+ case OPT_LIBYATL_MASSIVE:
+ opt_massive= true;
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ Error << "unknown option to getopt_long()";
+ exit(EXIT_FAILURE);
+
+ default:
+ break;
+ }
+ }
+ }
+
+ srandom((unsigned int)time(NULL));
+
+ errno= 0;
+ if (bool(getenv("YATL_REPEAT")))
+ {
+ errno= 0;
+ opt_repeat= strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10);
+ if (errno != 0)
+ {
+ Error << "ENV YATL_REPEAT passed an invalid value: `" << getenv("YATL_REPEAT") << "`";
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if ((bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "0") == 0)) or opt_quiet)
+ {
+ opt_quiet= true;
+ }
+ else if (getenv("JENKINS_URL"))
+ {
+ if (bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "1") == 0))
+ { }
+ else
+ {
+ opt_quiet= true;
+ }
+ }
+
+ if ((bool(getenv("YATL_RUN_MASSIVE_TESTS"))) or opt_massive)
+ {
+ opt_massive= true;
+ }
+
+ if (opt_quiet)
+ {
+ close(STDOUT_FILENO);
+ }
+
+ if (opt_massive)
+ {
+ is_massive(opt_massive);
+ }
+
+ libtest::vchar_t tmp_directory;
+ tmp_directory.resize(1024);
+ if (getenv("LIBTEST_TMP"))
+ {
+ snprintf(&tmp_directory[0], tmp_directory.size(), "%s", getenv("LIBTEST_TMP"));
+ }
+ else
+ {
+ snprintf(&tmp_directory[0], tmp_directory.size(), "%s", LIBTEST_TEMP);
+ }
+
+ if (chdir(&tmp_directory[0]) == -1)
+ {
+ libtest::vchar_t getcwd_buffer;
+ getcwd_buffer.resize(1024);
+ char *dir= getcwd(&getcwd_buffer[0], getcwd_buffer.size());
+
+ Error << "Unable to chdir() from " << dir << " to " << &tmp_directory[0] << " errno:" << strerror(errno);
+ return EXIT_FAILURE;
+ }
+
+ if (getenv("YATL_COLLECTION_TO_RUN"))
+ {
+ if (strlen(getenv("YATL_COLLECTION_TO_RUN")))
+ {
+ collection_to_run= getenv("YATL_COLLECTION_TO_RUN");
+ }
+ }
+
+ if (collection_to_run.compare("none") == 0)
+ {
+ return EXIT_SUCCESS;
+ }
+
+ if (collection_to_run.empty() == false)
+ {
+ Out << "Only testing " << collection_to_run;
+ }
+
+ int exit_code;
+
+ try
+ {
+ do
+ {
+ exit_code= EXIT_SUCCESS;
+ fatal_assert(sigignore(SIGPIPE) == 0);
+
+ libtest::SignalThread signal;
+ if (signal.setup() == false)
+ {
+ Error << "Failed to setup signals";
+ return EXIT_FAILURE;
+ }
+
+ UNIQUE_PTR<libtest::Framework> frame(new libtest::Framework(signal, binary_name, collection_to_run, wildcard));
+
+ // Run create(), bail on error.
+ {
+ switch (frame->create())
+ {
+ case TEST_SUCCESS:
+ break;
+
+ case TEST_SKIPPED:
+ SKIP("SKIP was returned from framework create()");
+ break;
+
+ case TEST_FAILURE:
+ std::cerr << "Could not call frame->create()" << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ frame->exec();
+
+ if (signal.is_shutdown() == false)
+ {
+ signal.set_shutdown(SHUTDOWN_GRACEFUL);
+ }
+
+ shutdown_t status= signal.get_shutdown();
+ if (status == SHUTDOWN_FORCED)
+ {
+ Out << "Tests were aborted.";
+ exit_code= EXIT_FAILURE;
+ }
+ else if (frame->failed())
+ {
+ Out << "Some test failed.";
+ exit_code= EXIT_FAILURE;
+ }
+ else if (frame->skipped() and frame->failed() and frame->success())
+ {
+ Out << "Some tests were skipped.";
+ }
+ else if (frame->success() and (frame->failed() == 0))
+ {
+ Out;
+ Out << "All tests completed successfully.";
+ }
+
+ stats_print(frame.get());
+
+ std::ofstream xml_file;
+ std::string file_name;
+ file_name.append(&tmp_directory[0]);
+ file_name.append(frame->name());
+ file_name.append(".xml");
+ xml_file.open(file_name.c_str(), std::ios::trunc);
+ libtest::Formatter::xml(*frame, xml_file);
+
+ Outn(); // Generate a blank to break up the messages if make check/test has been run
+ } while (exit_code == EXIT_SUCCESS and --opt_repeat);
+ }
+ catch (const libtest::__skipped& e)
+ {
+ return EXIT_SKIP;
+ }
+ catch (const libtest::__failure& e)
+ {
+ libtest::stream::make_cout(e.file(), e.line(), e.func()) << e.what();
+ exit_code= EXIT_FAILURE;
+ }
+ catch (const libtest::fatal& e)
+ {
+ std::cerr << "FATAL:" << e.what() << std::endl;
+ exit_code= EXIT_FAILURE;
+ }
+ catch (const libtest::disconnected& e)
+ {
+ std::cerr << "Unhandled disconnection occurred:" << e.what() << std::endl;
+ exit_code= EXIT_FAILURE;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "std::exception:" << e.what() << std::endl;
+ exit_code= EXIT_FAILURE;
+ }
+ catch (char const* s)
+ {
+ std::cerr << "Exception:" << s << std::endl;
+ exit_code= EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ std::cerr << "Unknown exception halted execution." << std::endl;
+ exit_code= EXIT_FAILURE;
+ }
+
+ return exit_code;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include "libtest/common.h"
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <libtest/server.h>
+#include <libtest/wait.h>
+
+#include <libtest/memcached.h>
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+namespace libtest {
+
+class Memcached : public libtest::Server
+{
+ std::string _username;
+ std::string _password;
+
+public:
+ Memcached(const std::string& host_arg,
+ const in_port_t port_arg,
+ const bool is_socket_arg,
+ const std::string& username_arg,
+ const std::string& password_arg) :
+ libtest::Server(host_arg, port_arg,
+ memcached_binary(), false, is_socket_arg),
+ _username(username_arg),
+ _password(password_arg)
+ { }
+
+ Memcached(const std::string& host_arg, const in_port_t port_arg, const bool is_socket_arg) :
+ libtest::Server(host_arg, port_arg,
+ memcached_binary(), false, is_socket_arg)
+ {
+ set_pid_file();
+ }
+
+ virtual const char *sasl() const
+ {
+ return "-S";
+ }
+
+ bool is_sasl() const
+ {
+ return _username.size() && _password.size();
+ }
+
+ const std::string& password() const
+ {
+ return _password;
+ }
+
+ const std::string& username() const
+ {
+ return _username;
+ }
+
+ bool wait_for_pidfile() const
+ {
+ Wait wait(pid(), 4);
+
+ return wait.successful();
+ }
+
+ bool ping()
+ {
+ if (out_of_ban_killed())
+ {
+ return false;
+ }
+
+ if (is_socket() or is_sasl())
+ {
+ return _app.check();
+ }
+
+ SimpleClient client(_hostname, _port);
+
+ std::string response;
+ return client.send_message("version", response);
+ }
+
+ const char *name()
+ {
+ return "memcached";
+ };
+
+ const char *executable()
+ {
+ return memcached_binary();
+ }
+
+ bool is_libtool()
+ {
+ return false;
+ }
+
+ virtual void pid_file_option(Application& app, const std::string& arg)
+ {
+ if (arg.empty() == false)
+ {
+ app.add_option("-P", arg);
+ }
+ }
+
+ const char *socket_file_option() const
+ {
+ return "-s ";
+ }
+
+ virtual void port_option(Application& app, in_port_t arg)
+ {
+ char buffer[30];
+ snprintf(buffer, sizeof(buffer), "%d", int(arg));
+ app.add_option("-p", buffer);
+
+ if(!is_sasl())
+ {
+ app.add_option("-U", buffer);
+ }
+ }
+
+ bool has_port_option() const
+ {
+ return true;
+ }
+
+ bool has_socket_file_option() const
+ {
+ return has_socket();
+ }
+
+ void socket_file_option(Application& app, const std::string& socket_arg)
+ {
+ if (socket_arg.empty() == false)
+ {
+ app.add_option("-s", socket_arg);
+ }
+ }
+
+ bool broken_socket_cleanup()
+ {
+ return true;
+ }
+
+ // Memcached's pidfile is broken
+ bool broken_pid_file()
+ {
+ return true;
+ }
+
+ bool build();
+};
+
+
+#include <sstream>
+
+bool Memcached::build()
+{
+ if (getuid() == 0 or geteuid() == 0)
+ {
+ add_option("-u", "root");
+ }
+
+ add_option("-l", "localhost");
+#ifdef __APPLE__
+#else
+ add_option("-m", "128");
+ add_option("-M");
+#endif
+
+ if (is_sasl())
+ {
+ add_option(sasl());
+ }
+
+ //add_option("-vvv");
+
+ return true;
+}
+
+libtest::Server *build_memcached(const std::string& hostname, const in_port_t try_port)
+{
+ if (has_memcached())
+ {
+ return new Memcached(hostname, try_port, false);
+ }
+
+ return NULL;
+}
+
+libtest::Server *build_memcached_socket(const std::string& socket_file, const in_port_t try_port)
+{
+ if (has_memcached())
+ {
+ return new Memcached(socket_file, try_port, true);
+ }
+
+ return NULL;
+}
+
+libtest::Server *build_memcached_sasl(const std::string &hostname, const in_port_t try_port, const std::string &username, const std::string &password)
+{
+ if (has_memcached())
+ {
+ return new Memcached(hostname, try_port, false, username, password);
+ }
+
+ return NULL;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+libtest::Server *build_memcached(const std::string& hostname, const in_port_t try_port);
+
+libtest::Server *build_memcached_socket(const std::string& socket_file, const in_port_t try_port);
+
+libtest::Server *build_memcached_sasl(const std::string &hostname, const in_port_t try_port, const std::string &username, const std::string &password);
+
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#if defined(HAVE_LIBMEMCACHED) && HAVE_LIBMEMCACHED
+inline bool operator== (const memcached_st& memc, const memcached_return_t rc)
+{
+ if (memcached_last_error(const_cast<memcached_st *>(&memc)) == rc)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+inline bool operator!= (const memcached_st& memc, memcached_return_t rc)
+{
+ if (memcached_last_error(const_cast<memcached_st *>(&memc)) != rc)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+inline bool operator== (memcached_st* const memc, memcached_return_t rc)
+{
+ if (memcached_last_error(memc) == rc)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+inline bool operator!= (memcached_st* const memc, memcached_return_t rc)
+{
+ if (memcached_last_error(memc) != rc)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+inline bool operator!= (memcached_return_t rc, const memcached_st& memc)
+{
+ if (memcached_last_error(const_cast<memcached_st *>(&memc)) != rc)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+inline bool operator!= (memcached_return_t rc, memcached_st* const memc)
+{
+ if (memcached_last_error(memc) != rc)
+ {
+ return true;
+ }
+
+ return false;
+}
+#endif
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ Structures for generic tests.
+*/
+
+#include <cstdio>
+#include <poll.h>
+
+void print_poll(pollfd& fds)
+{
+ if (fds.revents & POLLERR)
+ {
+ fprintf(stderr, "\tPOLLERR\n");
+ }
+
+ if (fds.revents & POLLHUP)
+ {
+ fprintf(stderr, "\tPOLLHUP\n");
+ }
+
+ if (fds.revents & POLLIN)
+ {
+ fprintf(stderr, "\tPOLLIN\n");
+ }
+
+ if (fds.revents & POLLIN)
+ {
+ fprintf(stderr, "\tPOLLIN\n");
+ }
+
+ if (fds.revents & POLLNVAL)
+ {
+ fprintf(stderr, "\tPOLLNVAL\n");
+ }
+
+ if (fds.revents & POLLOUT)
+ {
+ fprintf(stderr, "\tPOLLOUT\n");
+ }
+
+ if (fds.revents & POLLPRI)
+ {
+ fprintf(stderr, "\tPOLLPRI\n");
+ }
+
+ if (fds.revents & POLLRDBAND)
+ {
+ fprintf(stderr, "\tPOLLPRI\n");
+ }
+
+ if (fds.revents & POLLRDNORM)
+ {
+ fprintf(stderr, "\tPOLLRDNORM\n");
+ }
+
+ if (fds.revents & POLLWRBAND)
+ {
+ fprintf(stderr, "\tPOLLWRBAND\n");
+ }
+
+ if (fds.revents & POLLWRNORM)
+ {
+ fprintf(stderr, "\tPOLLWRNORM\n");
+ }
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <fnmatch.h>
+#include <iostream>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <utility>
+#include <vector>
+
+#include <signal.h>
+
+#include <libtest/signal.h>
+
+#ifndef SOCK_CLOEXEC
+# define SOCK_CLOEXEC 0
+#endif
+
+#ifndef SOCK_NONBLOCK
+# define SOCK_NONBLOCK 0
+#endif
+
+#ifndef FD_CLOEXEC
+# define FD_CLOEXEC 0
+#endif
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+using namespace libtest;
+
+struct socket_st {
+ typedef std::vector< std::pair< int, in_port_t> > socket_port_t;
+ socket_port_t _pair;
+ in_port_t last_port;
+
+ socket_st():
+ last_port(0)
+ { }
+
+ void release(in_port_t _arg)
+ {
+ for (socket_port_t::iterator iter= _pair.begin();
+ iter != _pair.end();
+ ++iter)
+ {
+ if ((*iter).second == _arg)
+ {
+ shutdown((*iter).first, SHUT_RDWR);
+ close((*iter).first);
+ }
+ }
+ }
+
+ ~socket_st()
+ {
+ for (socket_port_t::iterator iter= _pair.begin();
+ iter != _pair.end();
+ ++iter)
+ {
+ shutdown((*iter).first, SHUT_RDWR);
+ close((*iter).first);
+ }
+ }
+};
+
+static socket_st all_socket_fd;
+
+static in_port_t global_port= 0;
+
+namespace libtest {
+
+in_port_t default_port()
+{
+ if (global_port == 0)
+ {
+ global_port= get_free_port();
+ }
+
+ return global_port;
+}
+
+void release_port(in_port_t arg)
+{
+ all_socket_fd.release(arg);
+}
+
+in_port_t get_free_port()
+{
+ const in_port_t default_port= in_port_t(-1);
+
+ int retries= 1024;
+
+ in_port_t ret_port;
+ while (--retries)
+ {
+ ret_port= default_port;
+ int sd;
+ if ((sd= socket(AF_INET, SOCK_STREAM, 0)) != SOCKET_ERROR)
+ {
+ int optval= 1;
+ if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != SOCKET_ERROR)
+ {
+ struct sockaddr_in sin;
+ sin.sin_port= 0;
+ sin.sin_addr.s_addr= 0;
+ sin.sin_addr.s_addr= INADDR_ANY;
+ sin.sin_family= AF_INET;
+
+ int bind_ret;
+ do
+ {
+ if ((bind_ret= bind(sd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in) )) != SOCKET_ERROR)
+ {
+ socklen_t addrlen= sizeof(sin);
+
+ if (getsockname(sd, (struct sockaddr *)&sin, &addrlen) != -1)
+ {
+ ret_port= sin.sin_port;
+ }
+ }
+ else
+ {
+ if (errno != EADDRINUSE)
+ {
+ Error << strerror(errno);
+ }
+ }
+
+ if (errno == EADDRINUSE)
+ {
+ libtest::dream(2, 0);
+ }
+ } while (bind_ret == -1 and errno == EADDRINUSE);
+
+ all_socket_fd._pair.push_back(std::make_pair(sd, ret_port));
+ }
+ else
+ {
+ Error << strerror(errno);
+ }
+ }
+ else
+ {
+ Error << strerror(errno);
+ }
+
+ if (ret_port == default_port)
+ {
+ Error << "no ret_port set:" << strerror(errno);
+ }
+ else if (ret_port > 1024 and ret_port != all_socket_fd.last_port)
+ {
+ break;
+ }
+ }
+
+ // We handle the case where if we max out retries, we still abort.
+ if (retries == 0)
+ {
+ FATAL("No port could be found, exhausted retry");
+ }
+
+ if (ret_port == 0)
+ {
+ FATAL("No port could be found");
+ }
+
+ if (ret_port == default_port)
+ {
+ FATAL("No port could be found");
+ }
+
+ if (ret_port <= 1024)
+ {
+ FATAL("No port could be found, though some where available below or at 1024");
+ }
+
+ all_socket_fd.last_port= ret_port;
+ release_port(ret_port);
+
+ return ret_port;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ Structures for generic tests.
+*/
+
+#pragma once
+
+#define LIBTEST_FAIL_PORT 23
+
+namespace libtest {
+
+LIBTEST_API
+in_port_t default_port();
+
+LIBTEST_API
+in_port_t get_free_port();
+
+LIBTEST_API
+void release_port(in_port_t arg);
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+#include <cstdarg>
+
+namespace libtest {
+
+__test_result::__test_result(const char *file_arg, int line_arg, const char *func_arg):
+ libtest::exception(file_arg, line_arg, func_arg)
+ {
+ }
+
+__success::__success(const char *file_arg, int line_arg, const char *func_arg):
+ __test_result(file_arg, line_arg, func_arg)
+{
+}
+
+__skipped::__skipped(const char *file_arg, int line_arg, const char *func_arg, ...):
+ __test_result(file_arg, line_arg, func_arg)
+{
+ va_list args;
+ va_start(args, func_arg);
+ init(args);
+ va_end(args);
+}
+
+__skipped::__skipped(const __skipped& other) :
+ __test_result(other)
+{
+}
+
+__failure::__failure(const char *file_arg, int line_arg, const char *func_arg, ...) :
+ __test_result(file_arg, line_arg, func_arg)
+{
+ va_list args;
+ va_start(args, func_arg);
+ init(args);
+ va_end(args);
+}
+
+__failure::__failure(const __failure& other) :
+ __test_result(other)
+{
+}
+
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libtest/result/base.hpp>
+#include <libtest/result/fail.hpp>
+#include <libtest/result/skip.hpp>
+#include <libtest/result/success.hpp>
+
+#define _SUCCESS throw libtest::__success(LIBYATL_DEFAULT_PARAM)
+
+#define SKIP(...) \
+do \
+{ \
+ throw libtest::__skipped(LIBYATL_DEFAULT_PARAM, __VA_ARGS__); \
+} while (0)
+
+#define FAIL(...) \
+do \
+{ \
+ throw libtest::__failure(LIBYATL_DEFAULT_PARAM, __VA_ARGS__); \
+} while (0)
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include "libtest/exception.hpp"
+#include "libtest/error.h"
+
+namespace libtest {
+
+class __test_result : public libtest::exception
+{
+public:
+ __test_result(const char *file, int line, const char *func);
+
+ virtual test_return_t return_code() const= 0;
+
+private:
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+class __failure : public __test_result
+{
+public:
+ __failure(const char *file, int line, const char *func, ...);
+
+ __failure(const __failure&);
+
+ test_return_t return_code() const
+ {
+ return TEST_FAILURE;
+ }
+
+private:
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+class __skipped : public __test_result
+{
+public:
+ __skipped(const char *file, int line, const char *func, ...);
+
+ __skipped(const __skipped&);
+
+ test_return_t return_code() const
+ {
+ return TEST_SKIPPED;
+ }
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+class __success : public __test_result
+{
+public:
+ __success(const char *file, int line, const char *func);
+
+ const char* what() const throw()
+ {
+ return "SUCCESS";
+ }
+
+ test_return_t return_code() const
+ {
+ return TEST_SUCCESS;
+ }
+
+private:
+};
+
+} // namespace libtest
--- /dev/null
+set logging on
+set logging overwrite on
+set environment LIBTEST_IN_GDB=1
+set ASAN_OPTIONS=abort_on_error=1
+run
+thread apply all bt
+quit
--- /dev/null
+set logging on
+set logging overwrite on
+set environment LIBTEST_IN_GDB=1
+#set ASAN_OPTIONS=abort_on_error=1
+handle SIGVTALRM stop
+run
+thread apply all bt
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+namespace libtest {
+
+Runner::Runner() :
+ _servers(NULL)
+{
+}
+
+test_return_t Runner::main(test_callback_fn* func, void *object)
+{
+ test_return_t ret;
+ try {
+ ret= run(func, object);
+ }
+ catch (const libtest::__skipped& e)
+ {
+ ret= TEST_SKIPPED;
+ }
+ catch (const libtest::__failure& e)
+ {
+ libtest::stream::make_cerr(e.file(), e.line(), e.func()) << e.what();
+ ret= TEST_FAILURE;
+ }
+ catch (const libtest::__success&)
+ {
+ ret= TEST_SUCCESS;
+ }
+ catch (const libtest::fatal&)
+ {
+ throw;
+ }
+ catch (const std::exception& e)
+ {
+ libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << e.what();
+ throw;
+ }
+ catch (...)
+ {
+ libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << "Unknown exception thrown";
+ throw;
+ }
+
+ return ret;
+}
+
+test_return_t Runner::setup(test_callback_fn* func, void *object)
+{
+ test_return_t ret;
+ try {
+ ret= pre(func, object);
+ }
+ catch (const libtest::__skipped& e)
+ {
+ ret= TEST_SKIPPED;
+ }
+ catch (const libtest::__failure& e)
+ {
+ libtest::stream::make_cout(e.file(), e.line(), e.func()) << e.what();
+ ret= TEST_FAILURE;
+ }
+ catch (const libtest::__success&)
+ {
+ ret= TEST_SUCCESS;
+ }
+ catch (const libtest::fatal& e)
+ {
+ throw;
+ }
+ catch (const std::exception& e)
+ {
+ libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << e.what();
+ throw;
+ }
+ catch (...)
+ {
+ libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << "Unknown exception thrown";
+ throw;
+ }
+
+ return ret;
+}
+
+test_return_t Runner::teardown(test_callback_fn* func, void *object)
+{
+ test_return_t ret;
+ try {
+ ret= post(func, object);
+ }
+ catch (const libtest::__skipped& e)
+ {
+ ret= TEST_SKIPPED;
+ }
+ catch (const libtest::__failure& e)
+ {
+ libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << e.what();
+ ret= TEST_FAILURE;
+ }
+ catch (const libtest::__success&)
+ {
+ ret= TEST_SUCCESS;
+ }
+ catch (const libtest::fatal& e)
+ {
+ throw;
+ }
+ catch (const std::exception& e)
+ {
+ libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << e.what();
+ throw;
+ }
+ catch (...)
+ {
+ libtest::stream::make_cerr(LIBYATL_DEFAULT_PARAM) << "Unknown exception thrown";
+ throw;
+ }
+
+ return ret;
+}
+
+test_return_t Runner::flush(void*)
+{
+ return TEST_SUCCESS;
+}
+
+test_return_t Runner::run(test_callback_fn* func, void *object)
+{
+ if (func)
+ {
+ return func(object);
+ }
+
+ return TEST_SUCCESS;
+}
+
+test_return_t Runner::pre(test_callback_fn* func, void *object)
+{
+ if (func)
+ {
+ return func(object);
+ }
+
+ return TEST_SUCCESS;
+}
+
+test_return_t Runner::post(test_callback_fn* func, void *object)
+{
+ if (func)
+ {
+ return func(object);
+ }
+
+ return TEST_SUCCESS;
+}
+
+void Runner::set_servers(libtest::server_startup_st& arg)
+{
+ _servers= &arg;
+}
+
+bool Runner::check()
+{
+ return _servers ? _servers->check() : true;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+namespace libtest {
+
+/**
+ Structure which houses the actual callers for the test cases contained in
+ the collections.
+*/
+class Runner {
+public:
+ test_return_t main(test_callback_fn* func, void *object);
+ test_return_t setup(test_callback_fn* func, void *object);
+ test_return_t teardown(test_callback_fn* func, void *object);
+
+ Runner();
+
+ void set_servers(libtest::server_startup_st& arg);
+
+ bool check();
+
+ virtual ~Runner() { }
+
+ virtual test_return_t flush(void*);
+ virtual test_return_t run(test_callback_fn* func, void *object);
+ virtual test_return_t pre(test_callback_fn* func, void *object);
+ virtual test_return_t post(test_callback_fn* func, void *object);
+
+private:
+ libtest::server_startup_st* _servers;
+
+private:
+ Runner( const Runner& );
+ const Runner& operator=( const Runner& );
+};
+
+} // namespace Runner
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/common.h>
+
+#include <cassert>
+#include <cerrno>
+#include <climits>
+#include <cstdlib>
+#include <iostream>
+#include <string>
+
+#include <algorithm>
+#include <functional>
+#include <locale>
+#include <unistd.h>
+
+// trim from end
+static inline std::string &rtrim(std::string &s)
+{
+ s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
+ return s;
+}
+
+#include <libtest/server.h>
+#include <libtest/stream.h>
+#include <libtest/killpid.h>
+
+namespace libtest {
+
+std::ostream& operator<<(std::ostream& output, const Server &arg)
+{
+ if (arg.is_socket())
+ {
+ output << arg.hostname();
+ }
+ else
+ {
+ output << arg.hostname() << ":" << arg.port();
+ }
+
+ if (arg.has_pid())
+ {
+ output << " Pid:" << arg.pid();
+ }
+
+ if (arg.has_socket())
+ {
+ output << " Socket:" << arg.socket();
+ }
+
+ if (arg.running().empty() == false)
+ {
+ output << " Exec:" << arg.running();
+ }
+
+ return output; // for multiple << operators
+}
+
+#ifdef __GLIBC__
+namespace {
+
+class Buffer
+{
+public:
+ Buffer(char *b) : b_(b) {}
+ ~Buffer() { if (b_) free(b_); }
+ char* buf() { return b_; }
+private:
+ char *b_;
+};
+
+}
+#endif // __GLIBC__
+
+#define MAGIC_MEMORY 123570
+
+Server::Server(const std::string& host_arg, const in_port_t port_arg,
+ const std::string& executable, const bool _is_libtool,
+ bool is_socket_arg) :
+ _magic(MAGIC_MEMORY),
+ _is_socket(is_socket_arg),
+ _port(port_arg),
+ _hostname(host_arg),
+ _app(executable, _is_libtool),
+ out_of_ban_killed_(false),
+ _timeout(40)
+{
+}
+
+Server::~Server()
+{
+ kill();
+}
+
+bool Server::check()
+{
+ _app.clear();
+ return _app.check();
+}
+
+bool Server::validate()
+{
+ return _magic == MAGIC_MEMORY;
+}
+
+// If the server exists, kill it
+bool Server::cycle()
+{
+ uint32_t limit= 3;
+
+ // Try to ping, and kill the server #limit number of times
+ while (--limit and
+ is_pid_valid(_app.pid()))
+ {
+ if (kill())
+ {
+ Log << "Killed existing server," << *this;
+ dream(0, 50000);
+ continue;
+ }
+ }
+
+ // For whatever reason we could not kill it, and we reached limit
+ if (limit == 0)
+ {
+ Error << "Reached limit, could not kill server";
+ return false;
+ }
+
+ return true;
+}
+
+bool Server::wait_for_pidfile() const
+{
+ Wait wait(pid_file(), 4);
+
+ return wait.successful();
+}
+
+bool Server::init(const char *argv[])
+{
+ if (argv)
+ {
+ for (const char **ptr= argv; *ptr ; ++ptr)
+ {
+ if (ptr)
+ {
+ add_option(*ptr);
+ }
+ }
+ }
+
+ return build();
+}
+
+bool Server::has_pid() const
+{
+ return (_app.pid() > 1);
+}
+
+
+bool Server::start()
+{
+ if (getenv("YATL_GDB_SERVER"))
+ {
+ _app.use_gdb(true);
+ }
+
+ if (port() == LIBTEST_FAIL_PORT)
+ {
+ throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
+ hostname(), port(), "Called failure");
+ }
+
+ if (getenv("YATL_PTRCHECK_SERVER"))
+ {
+ _app.use_ptrcheck(true);
+ }
+ else if (getenv("YATL_VALGRIND_SERVER"))
+ {
+ _app.use_valgrind(true);
+ }
+
+ out_of_ban_killed(false);
+ if (args(_app) == false)
+ {
+ throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
+ hostname(), port(), "Could not build command()");
+ }
+
+ libtest::release_port(_port);
+
+ Application::error_t ret;
+ if (Application::SUCCESS != (ret= _app.run()))
+ {
+ throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
+ hostname(), port(), "Application::run() %s", libtest::Application::toString(ret));
+ return false;
+ }
+ _running= _app.print();
+
+ if (valgrind_is_caller())
+ {
+ dream(5, 50000);
+ }
+
+ size_t repeat= 5;
+ _app.slurp();
+ while (--repeat)
+ {
+ if (pid_file().empty() == false)
+ {
+ Wait wait(pid_file(), 8);
+
+ if (wait.successful() == false)
+ {
+ if (_app.check())
+ {
+ _app.slurp();
+ continue;
+ }
+
+#ifdef __GLIBC__
+ Buffer buf( get_current_dir_name());
+ char *getcwd_buf= buf.buf();
+#else
+ libtest::vchar_t buf;
+ buf.resize(PATH_MAX);
+ char *getcwd_buf= getcwd(&buf[0], buf.size());
+#endif // __GLIBC__
+ throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
+ hostname(), port(),
+ "Unable to open pidfile in %s for: %s stderr:%s",
+ getcwd_buf ? getcwd_buf : "",
+ _running.c_str(),
+ _app.stderr_c_str());
+ }
+ }
+ }
+
+ bool pinged= false;
+ uint32_t this_wait= 0;
+ {
+ uint32_t waited;
+ uint32_t retry;
+
+ for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
+ {
+ if (_app.check() == false)
+ {
+ break;
+ }
+
+ if ((pinged= ping()) == true)
+ {
+ break;
+ }
+ else if (waited >= _timeout)
+ {
+ break;
+ }
+
+ this_wait= retry * retry / 3 + 1;
+ libtest::dream(this_wait, 0);
+ }
+ }
+
+ if (pinged == false)
+ {
+#if 0
+ Error << "Failed to ping(" << _app.pid() << ") wait: " << this_wait << " " << hostname() << ":" << port() << " run:" << _running << " " << error();
+#endif
+
+ // If we happen to have a pid file, lets try to kill it
+ if ((pid_file().empty() == false) and (access(pid_file().c_str(), R_OK) == 0))
+ {
+ _app.slurp();
+ if (kill_file(pid_file()) == false)
+ {
+ throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
+ hostname(), port(),
+ "Failed to kill off server, waited: %u after startup occurred, when pinging failed: %.*s stderr:%.*s",
+ this_wait,
+ int(_running.size()), _running.c_str(),
+ int(_app.stderr_result_length()), _app.stderr_c_str());
+ }
+ else
+ {
+ throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
+ hostname(), port(),
+ "Failed native ping(), pid: %d was alive: %s waited: %u server started, having pid_file. exec: %.*s stderr:%.*s",
+ int(_app.pid()),
+ _app.check() ? "true" : "false",
+ this_wait,
+ int(_running.size()), _running.c_str(),
+ int(_app.stderr_result_length()), _app.stderr_c_str());
+ }
+ }
+ else
+ {
+ throw libtest::disconnected(LIBYATL_DEFAULT_PARAM,
+ hostname(), port(),
+ "Failed native ping(), pid: %d is alive: %s waited: %u server started. exec: %.*s stderr:%.*s",
+ int(_app.pid()),
+ _app.check() ? "true" : "false",
+ this_wait,
+ int(_running.size()), _running.c_str(),
+ int(_app.stderr_result_length()), _app.stderr_c_str());
+ }
+ _running.clear();
+
+ return false;
+ }
+
+ return has_pid();
+}
+
+void Server::reset_pid()
+{
+ _running.clear();
+ _pid_file.clear();
+}
+
+pid_t Server::pid() const
+{
+ return _app.pid();
+}
+
+void Server::add_option(const std::string& arg)
+{
+ _options.push_back(std::make_pair(arg, std::string()));
+}
+
+void Server::add_option(const std::string& name_, const std::string& value_)
+{
+ _options.push_back(std::make_pair(name_, value_));
+}
+
+bool Server::set_socket_file()
+{
+ libtest::vchar_t file_buffer;
+ file_buffer.resize(FILENAME_MAX);
+ file_buffer[0]= 0;
+
+ if (broken_pid_file())
+ {
+ snprintf(&file_buffer[0], file_buffer.size(), "/tmp/%s.socketXXXXXX", name());
+ }
+ else
+ {
+ snprintf(&file_buffer[0], file_buffer.size(), "var/run/%s.socketXXXXXX", name());
+ }
+
+ int fd;
+ if ((fd= mkstemp(&file_buffer[0])) == -1)
+ {
+ perror(&file_buffer[0]);
+ return false;
+ }
+ close(fd);
+ unlink(&file_buffer[0]);
+
+ _socket= &file_buffer[0];
+
+ return true;
+}
+
+bool Server::set_pid_file()
+{
+ libtest::vchar_t file_buffer;
+ file_buffer.resize(FILENAME_MAX);
+ file_buffer[0]= 0;
+
+ if (broken_pid_file())
+ {
+ snprintf(&file_buffer[0], file_buffer.size(), "/tmp/%s.pidXXXXXX", name());
+ }
+ else
+ {
+ snprintf(&file_buffer[0], file_buffer.size(), "var/run/%s.pidXXXXXX", name());
+ }
+
+ int fd;
+ if ((fd= mkstemp(&file_buffer[0])) == -1)
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", &file_buffer[0], strerror(errno));
+ }
+ close(fd);
+ unlink(&file_buffer[0]);
+
+ _pid_file= &file_buffer[0];
+
+ return true;
+}
+
+bool Server::set_log_file()
+{
+ libtest::vchar_t file_buffer;
+ file_buffer.resize(FILENAME_MAX);
+ file_buffer[0]= 0;
+
+ snprintf(&file_buffer[0], file_buffer.size(), "var/log/%s.logXXXXXX", name());
+ int fd;
+ if ((fd= mkstemp(&file_buffer[0])) == -1)
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", &file_buffer[0], strerror(errno));
+ }
+ close(fd);
+
+ _log_file= &file_buffer[0];
+
+ return true;
+}
+
+bool Server::args(Application& app)
+{
+
+ // Set a log file if it was requested (and we can)
+ if (has_log_file_option())
+ {
+ set_log_file();
+ log_file_option(app, _log_file);
+ }
+
+ if (getenv("LIBTEST_SYSLOG") and has_syslog())
+ {
+ app.add_option("--syslog");
+ }
+
+ // Update pid_file
+ {
+ if (_pid_file.empty() and set_pid_file() == false)
+ {
+ return false;
+ }
+
+ pid_file_option(app, pid_file());
+ }
+
+ if (has_socket_file_option())
+ {
+ if (set_socket_file() == false)
+ {
+ return false;
+ }
+
+ socket_file_option(app, _socket);
+ }
+
+ if (has_port_option())
+ {
+ port_option(app, _port);
+ }
+
+ for (Options::const_iterator iter= _options.begin(); iter != _options.end(); ++iter)
+ {
+ if ((*iter).first.empty() == false)
+ {
+ if ((*iter).second.empty() == false)
+ {
+ app.add_option((*iter).first, (*iter).second);
+ }
+ else
+ {
+ app.add_option((*iter).first);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool Server::kill()
+{
+ if (check_pid(_app.pid())) // If we kill it, reset
+ {
+ _app.murder();
+ if (broken_pid_file() and pid_file().empty() == false)
+ {
+ unlink(pid_file().c_str());
+ }
+
+ if (broken_socket_cleanup() and has_socket() and not socket().empty())
+ {
+ unlink(socket().c_str());
+ }
+
+ reset_pid();
+
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libtest/cmdline.h>
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string>
+#include <unistd.h>
+#include <vector>
+
+namespace libtest {
+
+struct Server {
+private:
+ typedef std::vector< std::pair<std::string, std::string> > Options;
+
+private:
+ uint64_t _magic;
+ bool _is_socket;
+ std::string _socket;
+ std::string _sasl;
+ std::string _pid_file;
+ std::string _log_file;
+ std::string _base_command; // executable command which include libtool, valgrind, gdb, etc
+ std::string _running; // Current string being used for system()
+
+protected:
+ in_port_t _port;
+ std::string _hostname;
+ std::string _extra_args;
+
+public:
+ Server(const std::string& hostname, const in_port_t port_arg,
+ const std::string& executable, const bool _is_libtool,
+ const bool is_socket_arg= false);
+
+ virtual ~Server();
+
+ virtual const char *name()= 0;
+ virtual bool is_libtool()= 0;
+
+ virtual bool has_socket_file_option() const
+ {
+ return false;
+ }
+
+ virtual void socket_file_option(Application& app, const std::string& socket_arg)
+ {
+ if (socket_arg.empty() == false)
+ {
+ std::string buffer("--socket=");
+ buffer+= socket_arg;
+ app.add_option(buffer);
+ }
+ }
+
+ virtual bool has_log_file_option() const
+ {
+ return false;
+ }
+
+ virtual void log_file_option(Application& app, const std::string& arg)
+ {
+ if (arg.empty() == false)
+ {
+ std::string buffer("--log-file=");
+ buffer+= arg;
+ app.add_option(buffer);
+ }
+ }
+
+ virtual void pid_file_option(Application& app, const std::string& arg)
+ {
+ if (arg.empty() == false)
+ {
+ std::string buffer("--pid-file=");
+ buffer+= arg;
+ app.add_option(buffer);
+ }
+ }
+
+ virtual bool has_port_option() const
+ {
+ return false;
+ }
+
+ virtual void port_option(Application& app, in_port_t arg)
+ {
+ if (arg > 0)
+ {
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "--port=%d", int(arg));
+ app.add_option(buffer);
+ }
+ }
+
+ virtual bool broken_socket_cleanup()
+ {
+ return false;
+ }
+
+ virtual bool broken_pid_file()
+ {
+ return false;
+ }
+
+ const std::string& pid_file() const
+ {
+ return _pid_file;
+ }
+
+ const std::string& base_command() const
+ {
+ return _base_command;
+ }
+
+ const std::string& log_file() const
+ {
+ return _log_file;
+ }
+
+ const std::string& hostname() const
+ {
+ return _hostname;
+ }
+
+ const std::string& socket() const
+ {
+ return _socket;
+ }
+
+ bool has_socket() const
+ {
+ return _is_socket;
+ }
+
+ bool cycle();
+
+ virtual bool ping()= 0;
+
+ bool init(const char *argv[]);
+ virtual bool build()= 0;
+
+ void add_option(const std::string&);
+ void add_option(const std::string&, const std::string&);
+
+ in_port_t port() const
+ {
+ return _port;
+ }
+
+ bool has_port() const
+ {
+ return (_port != 0);
+ }
+
+ virtual bool has_syslog() const
+ {
+ return false;
+ }
+
+ // Reset a server if another process has killed the server
+ void reset()
+ {
+ _pid_file.clear();
+ _log_file.clear();
+ }
+
+ std::pair<std::string, std::string> output()
+ {
+ return _app.output();
+ }
+
+ pid_t pid() const;
+
+ bool has_pid() const;
+
+ virtual bool has_pid_file() const
+ {
+ return true;
+ }
+
+ const std::string& error()
+ {
+ return _error;
+ }
+
+ void error(std::string arg)
+ {
+ _error= arg;
+ }
+
+ void reset_error()
+ {
+ _error.clear();
+ }
+
+ virtual bool wait_for_pidfile() const;
+
+ bool check_pid(pid_t pid_arg) const
+ {
+ return (pid_arg > 1);
+ }
+
+ bool is_socket() const
+ {
+ return _is_socket;
+ }
+
+ const std::string running() const
+ {
+ return _running;
+ }
+
+ bool check();
+
+ std::string log_and_pid();
+
+ bool kill();
+ bool start();
+ bool command(libtest::Application& app);
+
+ bool validate();
+
+ void out_of_ban_killed(bool arg)
+ {
+ out_of_ban_killed_= arg;
+ }
+
+ bool out_of_ban_killed()
+ {
+ return out_of_ban_killed_;
+ }
+
+ void timeout(uint32_t timeout_)
+ {
+ _timeout= timeout_;
+ }
+
+protected:
+ bool set_pid_file();
+ Options _options;
+ Application _app;
+
+private:
+ bool is_helgrind() const;
+ bool is_valgrind() const;
+ bool is_debug() const;
+ bool set_log_file();
+ bool set_socket_file();
+ void reset_pid();
+ bool out_of_ban_killed_;
+ bool args(Application&);
+
+ std::string _error;
+ uint32_t _timeout; // This number should be high enough for valgrind startup (which is slow)
+};
+
+std::ostream& operator<<(std::ostream& output, const libtest::Server &arg);
+
+} // namespace libtest
+
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include "libtest/common.h"
+
+#include <cerrno>
+#include <cstdlib>
+#include <iostream>
+
+#include <algorithm>
+#include <functional>
+#include <locale>
+
+// trim from end
+static inline std::string &rtrim(std::string &s)
+{
+ s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
+ return s;
+}
+
+namespace libtest {
+
+Server* server_startup_st::last()
+{
+ return servers.back();
+}
+
+void server_startup_st::push_server(Server *arg)
+{
+ servers.push_back(arg);
+
+ std::string server_config_string;
+ if (arg->has_socket())
+ {
+ server_config_string+= "--socket=";
+ server_config_string+= '"';
+ server_config_string+= arg->socket();
+ server_config_string+= '"';
+ server_config_string+= " ";
+ }
+ else
+ {
+ libtest::vchar_t port_str;
+ port_str.resize(NI_MAXSERV);
+ snprintf(&port_str[0], port_str.size(), "%u", int(arg->port()));
+
+ server_config_string+= "--server=";
+ server_config_string+= arg->hostname();
+ server_config_string+= ":";
+ server_config_string+= &port_str[0];
+ server_config_string+= " ";
+ }
+
+ server_list+= server_config_string;
+}
+
+Server* server_startup_st::pop_server()
+{
+ Server *tmp= servers.back();
+ servers.pop_back();
+ return tmp;
+}
+
+// host_to_shutdown => host number to shutdown in array
+bool server_startup_st::shutdown(uint32_t host_to_shutdown)
+{
+ if (servers.size() > host_to_shutdown)
+ {
+ Server* tmp= servers[host_to_shutdown];
+
+ if (tmp and tmp->kill() == false)
+ { }
+ else
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void server_startup_st::clear()
+{
+ std::for_each(servers.begin(), servers.end(), DeleteFromVector());
+ servers.clear();
+}
+
+bool server_startup_st::check() const
+{
+ bool success= true;
+ for (std::vector<Server *>::const_iterator iter= servers.begin(); iter != servers.end(); ++iter)
+ {
+ if ((*iter)->check() == false)
+ {
+ success= false;
+ }
+ }
+
+ return success;
+}
+
+bool server_startup_st::shutdown()
+{
+ bool success= true;
+ for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); ++iter)
+ {
+ if ((*iter)->has_pid() and (*iter)->kill() == false)
+ {
+ Error << "Unable to kill:" << *(*iter);
+ success= false;
+ }
+ }
+
+ return success;
+}
+
+void server_startup_st::restart()
+{
+ for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); ++iter)
+ {
+ Server *server = *iter;
+
+ if (server->check()) {
+ server->kill();
+ }
+ server->start();
+ }
+}
+
+#define MAGIC_MEMORY 123575
+server_startup_st::server_startup_st() :
+ _magic(MAGIC_MEMORY),
+ _socket(false),
+ _sasl(false),
+ udp(0),
+ _servers_to_run(5)
+{ }
+
+server_startup_st::~server_startup_st()
+{
+ clear();
+}
+
+bool server_startup_st::validate()
+{
+ return _magic == MAGIC_MEMORY;
+}
+
+bool server_startup(server_startup_st& construct, const std::string& server_type, in_port_t try_port, const char *argv[])
+{
+ return construct.start_server(server_type, try_port, argv);
+}
+
+libtest::Server* server_startup_st::create(const std::string& server_type, in_port_t try_port, const bool is_socket)
+{
+ libtest::Server *server= NULL;
+
+ if (is_socket == false)
+ {
+ if (try_port <= 0)
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "was passed the invalid port number %d", int(try_port));
+ }
+ }
+
+ if (is_socket)
+ {
+ if (server_type.compare("memcached") == 0)
+ {
+ server= build_memcached_socket("localhost", try_port);
+ }
+ else
+ {
+ Error << "Socket is not support for server: " << server_type;
+ return NULL;
+ }
+ }
+ else if (server_type.compare("gearmand") == 0)
+ {
+ server= build_gearmand("localhost", try_port);
+ }
+ else if (server_type.compare("hostile-gearmand") == 0)
+ {
+ server= build_gearmand("localhost", try_port, "gearmand/hostile_gearmand");
+ }
+ else if (server_type.compare("drizzled") == 0)
+ {
+ if (has_drizzled())
+ {
+ if (has_libdrizzle())
+ {
+ server= build_drizzled("localhost", try_port);
+ }
+ }
+ }
+ else if (server_type.compare("blobslap_worker") == 0)
+ {
+ if (has_gearmand())
+ {
+#ifdef GEARMAND_BLOBSLAP_WORKER
+ if (GEARMAND_BLOBSLAP_WORKER)
+ {
+ if (HAVE_LIBGEARMAN)
+ {
+ server= build_blobslap_worker(try_port);
+ }
+ }
+#endif // GEARMAND_BLOBSLAP_WORKER
+ }
+ }
+ else if (server_type.compare("memcached") == 0)
+ {
+ if (has_memcached())
+ {
+ server= build_memcached("localhost", try_port);
+ }
+ }
+ else if (server_type == "memcached-sasl")
+ {
+ server = build_memcached_sasl("localhost", try_port, _username, _password);
+ }
+
+ return server;
+}
+
+class ServerPtr {
+public:
+ ServerPtr(libtest::Server* server_):
+ _server(server_)
+ { }
+
+ ~ServerPtr()
+ {
+ delete _server;
+ }
+
+ void reset()
+ {
+ delete _server;
+ _server= NULL;
+ }
+
+ libtest::Server* release(libtest::Server* server_= NULL)
+ {
+ libtest::Server* tmp= _server;
+ _server= server_;
+ return tmp;
+ }
+
+ libtest::Server* operator->() const
+ {
+ return _server;
+ }
+
+ libtest::Server* operator&() const
+ {
+ return _server;
+ }
+
+private:
+ libtest::Server* _server;
+};
+
+bool server_startup_st::_start_server(const bool is_socket,
+ const std::string& server_type,
+ in_port_t try_port,
+ const char *argv[])
+{
+ try {
+ ServerPtr server(create(server_type, try_port, is_socket));
+
+ if (&server == NULL)
+ {
+ Error << "Could not allocate server: " << server_type;
+ return false;
+ }
+
+ /*
+ We will now cycle the server we have created.
+ */
+ if (server->cycle() == false)
+ {
+ Error << "Could not start up server " << &server;
+ return false;
+ }
+
+ server->init(argv);
+
+#if 0
+ if (false)
+ {
+ Out << "Pausing for startup, hit return when ready.";
+ std::string gdb_command= server->base_command();
+ getchar();
+ }
+ else
+#endif
+
+ if (server->start() == false)
+ {
+ return false;
+ }
+ else
+ {
+ {
+#ifdef DEBUG
+ if (DEBUG)
+ {
+ Outn();
+ Out << "STARTING SERVER(pid:" << server->pid() << "): " << server->running();
+ }
+#endif
+ }
+ }
+
+ push_server(server.release());
+
+ if (is_socket and &server)
+ {
+ set_default_socket(server->socket().c_str());
+ }
+ }
+ catch (const libtest::disconnected& err)
+ {
+ if (fatal::is_disabled() == false and try_port != LIBTEST_FAIL_PORT)
+ {
+ stream::cerr(err.file(), err.line(), err.func()) << err.what();
+ return false;
+ }
+ }
+ catch (const libtest::__test_result& err)
+ {
+ stream::cerr(err.file(), err.line(), err.func()) << err.what();
+ return false;
+ }
+ catch (const std::exception& err)
+ {
+ Error << err.what();
+ return false;
+ }
+ catch (...)
+ {
+ Error << "error occured while creating server: " << server_type;
+ return false;
+ }
+
+ return true;
+}
+
+bool server_startup_st::start_server(const std::string& server_type, in_port_t try_port, const char *argv[])
+{
+ return _start_server(false, server_type, try_port, argv);
+}
+
+bool server_startup_st::start_socket_server(const std::string& server_type, const in_port_t try_port, const char *argv[])
+{
+ return _start_server(true, server_type, try_port, argv);
+}
+
+std::string server_startup_st::option_string() const
+{
+ std::string temp= server_list;
+ rtrim(temp);
+ return temp;
+}
+
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string>
+#include <unistd.h>
+#include <vector>
+
+namespace libtest {
+
+class server_startup_st
+{
+private:
+ uint64_t _magic;
+ std::string server_list;
+ bool _socket;
+ bool _sasl;
+ std::string _username;
+ std::string _password;
+
+public:
+
+ uint8_t udp;
+ std::vector<Server *> servers;
+
+ server_startup_st();
+ ~server_startup_st();
+
+ bool validate();
+
+ bool start_socket_server(const std::string& server_type, const in_port_t try_port, const char *argv[]);
+ bool start_server(const std::string& server_type, const in_port_t try_port, const char *argv[]);
+
+ uint32_t count() const
+ {
+ return uint32_t(servers.size());
+ }
+
+ void restart();
+
+ std::string option_string() const;
+
+ const std::string& password() const
+ {
+ return _password;
+ }
+
+ const std::string& username() const
+ {
+ return _username;
+ }
+
+ bool socket()
+ {
+ return _socket;
+ }
+
+ bool sasl()
+ {
+ return _sasl;
+ }
+
+ void set_socket()
+ {
+ _socket= true;
+ }
+
+ void set_sasl(const std::string& username_arg, const std::string& password_arg)
+ {
+ _sasl= true;
+ _username= username_arg;
+ _password= password_arg;
+ }
+
+
+ // Just remove everything after shutdown
+ void clear();
+
+ bool shutdown();
+ bool shutdown(uint32_t number_of_host);
+
+ bool check() const;
+
+ void push_server(Server *);
+ Server* last();
+ Server *pop_server();
+
+ Server* create(const std::string& server_type, in_port_t try_port, const bool is_socket);
+
+ unsigned long int servers_to_run() const
+ {
+ return _servers_to_run;
+ }
+
+ void set_servers_to_run(unsigned long int arg)
+ {
+ _servers_to_run= arg;
+ }
+
+private:
+ bool _start_server(const bool is_socket,
+ const std::string& server_type,
+ const in_port_t try_port,
+ const char *argv[]);
+
+private:
+ unsigned long int _servers_to_run;
+};
+
+bool server_startup(server_startup_st&, const std::string&, in_port_t try_port, const char *argv[]);
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+#include <csignal>
+
+#include <libtest/signal.h>
+
+using namespace libtest;
+
+#define MAGIC_MEMORY 123569
+
+bool SignalThread::is_shutdown()
+{
+ bool ret;
+ pthread_mutex_lock(&shutdown_mutex);
+ ret= bool(__shutdown != SHUTDOWN_RUNNING);
+ pthread_mutex_unlock(&shutdown_mutex);
+
+ return ret;
+}
+
+void SignalThread::set_shutdown(shutdown_t arg)
+{
+ pthread_mutex_lock(&shutdown_mutex);
+ __shutdown= arg;
+ pthread_mutex_unlock(&shutdown_mutex);
+
+ if (arg == SHUTDOWN_GRACEFUL)
+ {
+ if (pthread_kill(thread, SIGUSR2) == 0)
+ {
+ void *retval;
+ pthread_join(thread, &retval);
+ }
+ }
+}
+
+shutdown_t SignalThread::get_shutdown()
+{
+ shutdown_t local;
+ pthread_mutex_lock(&shutdown_mutex);
+ local= __shutdown;
+ pthread_mutex_unlock(&shutdown_mutex);
+
+ return local;
+}
+
+void SignalThread::post()
+{
+ sem_post(&lock);
+}
+
+void SignalThread::test()
+{
+ assert(magic_memory == MAGIC_MEMORY);
+ if (bool(getenv("LIBTEST_IN_GDB")) == false)
+ {
+ assert(sigismember(&set, SIGALRM));
+ assert(sigismember(&set, SIGABRT));
+ assert(sigismember(&set, SIGQUIT));
+ assert(sigismember(&set, SIGINT));
+ assert(sigismember(&set, SIGVTALRM));
+ }
+ assert(sigismember(&set, SIGUSR2));
+}
+
+bool SignalThread::unblock()
+{
+ int error;
+ if ((error= pthread_sigmask(SIG_UNBLOCK, &set, NULL)) != 0)
+ {
+ Error << "While trying to reset signal mask to original set, pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")";
+ return false;
+ }
+
+ return true;
+}
+
+SignalThread::~SignalThread()
+{
+ if (is_shutdown() == false)
+ {
+ set_shutdown(SHUTDOWN_GRACEFUL);
+ }
+
+#if 0
+ if (pthread_equal(thread, pthread_self()) != 0 and (pthread_kill(thread, 0) == ESRCH) == true)
+ {
+ void *retval;
+ pthread_join(thread, &retval);
+ }
+#endif
+ sem_destroy(&lock);
+
+ unblock();
+}
+
+extern "C" {
+
+static void *sig_thread(void *arg)
+{
+ SignalThread *context= (SignalThread*)arg;
+
+ context->test();
+ context->post();
+
+ while (context->get_shutdown() == SHUTDOWN_RUNNING)
+ {
+ int sig;
+
+ if (context->wait(sig) == -1)
+ {
+ Error << "sigwait() returned errno:" << strerror(errno);
+ continue;
+ }
+
+ switch (sig)
+ {
+ case SIGALRM:
+ case SIGVTALRM:
+ Error << strsignal(sig);
+ if (gdb_is_caller())
+ {
+ abort();
+ }
+ exit(EXIT_FAILURE);
+
+ case SIGABRT:
+ case SIGUSR2:
+ case SIGINT:
+ case SIGQUIT:
+ if (context->is_shutdown() == false)
+ {
+ context->set_shutdown(SHUTDOWN_FORCED);
+ }
+ break;
+ case SIGPIPE:
+ {
+ Error << "Ignoring SIGPIPE";
+ }
+ break;
+
+ case 0:
+ Error << "Inside of gdb";
+ break;
+
+ default:
+ Error << "Signal handling thread got unexpected signal " << strsignal(sig);
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+}
+
+SignalThread::SignalThread() :
+ magic_memory(MAGIC_MEMORY),
+ thread(pthread_self())
+{
+ pthread_mutex_init(&shutdown_mutex, NULL);
+ sigemptyset(&set);
+ if (bool(getenv("LIBTEST_IN_GDB")) == false)
+ {
+ sigaddset(&set, SIGALRM);
+ sigaddset(&set, SIGABRT);
+ sigaddset(&set, SIGQUIT);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGVTALRM);
+ }
+ sigaddset(&set, SIGPIPE);
+
+ sigaddset(&set, SIGUSR2);
+
+ sem_init(&lock, 0, 0);
+
+ sigemptyset(&original_set);
+ pthread_sigmask(SIG_BLOCK, NULL, &original_set);
+}
+
+
+bool SignalThread::setup()
+{
+ set_shutdown(SHUTDOWN_RUNNING);
+
+ if (sigismember(&original_set, SIGQUIT))
+ {
+ Error << strsignal(SIGQUIT) << " has been previously set.";
+ }
+
+ if (sigismember(&original_set, SIGINT))
+ {
+ Error << strsignal(SIGINT) << " has been previously set.";
+ }
+
+ if (sigismember(&original_set, SIGVTALRM))
+ {
+ Error << strsignal(SIGVTALRM) << " has been previously set.";
+ }
+
+ if (sigismember(&original_set, SIGUSR2))
+ {
+ Error << strsignal(SIGUSR2) << " has been previously set.";
+ }
+
+ int error;
+ if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
+ {
+ Error << "pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")";
+ return false;
+ }
+
+ if ((error= pthread_create(&thread, NULL, &sig_thread, this)) != 0)
+ {
+ Error << "pthread_create() died during pthread_create(" << strerror(error) << ")";
+ return false;
+ }
+
+ sem_wait(&lock);
+
+ return true;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+
+enum shutdown_t {
+ SHUTDOWN_RUNNING,
+ SHUTDOWN_GRACEFUL,
+ SHUTDOWN_FORCED
+};
+
+namespace libtest {
+
+class SignalThread {
+ sigset_t set;
+ sem_t lock;
+ uint64_t magic_memory;
+ volatile shutdown_t __shutdown;
+ pthread_mutex_t shutdown_mutex;
+ pthread_t thread;
+ sigset_t original_set;
+
+public:
+
+ SignalThread();
+ ~SignalThread();
+
+ void test();
+ void post();
+ bool setup();
+ bool unblock();
+
+ int wait(int& sig)
+ {
+ return sigwait(&set, &sig);
+ }
+
+ void set_shutdown(shutdown_t arg);
+ bool is_shutdown();
+ shutdown_t get_shutdown();
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/test.hpp>
+
+#include <cstdlib>
+#include <unistd.h>
+
+using namespace libtest;
+
+
+static void *world_create(server_startup_st&, test_return_t& rc)
+{
+ rc= TEST_SKIPPED;
+
+ return NULL;
+}
+
+void get_world(libtest::Framework *world)
+{
+ world->create(world_create);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+static char global_socket[1024]= { 0 };
+
+namespace libtest {
+
+const char *default_socket()
+{
+ if (global_socket[0] == 0)
+ {
+ return NULL;
+ }
+
+ return global_socket;
+}
+
+void set_default_socket(const char *socket)
+{
+ if (socket)
+ {
+ strncpy(global_socket, socket, sizeof(global_socket)-1);
+ }
+}
+
+}
--- /dev/null
+
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+namespace libtest {
+
+const char *default_socket();
+
+void set_default_socket(const char *socket);
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <iostream>
+#include <cassert>
+#include <sstream>
+#include <ctime>
+#include <ostream>
+
+namespace libtest {
+namespace stream {
+
+namespace detail {
+
+template<class Ch, class Tr, class A>
+ class channel {
+ private:
+
+ public:
+ typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
+
+ public:
+ void operator()(const stream_buffer& s, std::ostream& _out,
+ const char* filename, int line_number, const char* func)
+ {
+ if (filename)
+ {
+ _out
+ << filename
+ << ":"
+ << line_number
+ << ": in "
+ << func << "() "
+ << s.str()
+ << std::endl;
+ }
+ else
+ {
+ _out
+ << s.str()
+ << std::endl;
+ }
+ }
+ };
+
+template<class Ch, class Tr, class A>
+ class channelln {
+ private:
+
+ public:
+ typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
+
+ public:
+ void operator()(const stream_buffer& s, std::ostream& _out,
+ const char* filename, int line_number, const char* func)
+ {
+ if (filename)
+ {
+ _out
+ << std::endl
+ << filename
+ << ":"
+ << line_number
+ << ": in "
+ << func << "() "
+ << s.str()
+ << std::endl;
+ }
+ else
+ {
+ _out
+ << std::endl
+ << s.str()
+ << std::endl;
+ }
+ }
+ };
+
+template<class Ch, class Tr, class A>
+ class channelfl {
+ private:
+
+ public:
+ typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
+
+ public:
+ void operator()(const stream_buffer& s, std::ostream& _out,
+ const char* filename, int line_number, const char* func)
+ {
+ if (filename)
+ {
+ _out
+ << filename
+ << ":"
+ << line_number
+ << ": in "
+ << func << "() "
+ << s.str()
+ << std::flush;
+ }
+ else
+ {
+ _out
+ << s.str()
+ << std::flush;
+ }
+ }
+ };
+
+template<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> >
+ class log {
+ private:
+ typedef OutputPolicy<Ch, Tr, A> output_policy;
+
+ private:
+ std::ostream& _out;
+ const char *_filename;
+ int _line_number;
+ const char *_func;
+
+ public:
+ log(std::ostream& out_arg, const char* filename, int line_number, const char* func) :
+ _out(out_arg),
+ _filename(filename),
+ _line_number(line_number),
+ _func(func)
+ { }
+
+ virtual ~log()
+ {
+ output_policy()(arg, _out, _filename, _line_number, _func);
+ }
+
+ public:
+ template<class T>
+ log &operator<<(const T &x)
+ {
+ arg << x;
+ return *this;
+ }
+
+ private:
+ typename output_policy::stream_buffer arg;
+
+ private:
+ log( const log& );
+ const log& operator=( const log& );
+ };
+} // namespace detail
+
+class make_cerr : public detail::log<detail::channelln> {
+public:
+ make_cerr(const char* filename, int line_number, const char* func) :
+ detail::log<detail::channelln>(std::cerr, filename, line_number, func)
+ { }
+
+private:
+ make_cerr( const make_cerr& );
+ const make_cerr& operator=( const make_cerr& );
+};
+
+class cerr : public detail::log<detail::channel> {
+public:
+ cerr(const char* filename, int line_number, const char* func) :
+ detail::log<detail::channel>(std::cout, filename, line_number, func)
+ { }
+
+private:
+ cerr( const cerr& );
+ const cerr& operator=( const cerr& );
+};
+
+class clog : public detail::log<detail::channel> {
+public:
+ clog(const char* filename, int line_number, const char* func) :
+ detail::log<detail::channel>(std::clog, filename, line_number, func)
+ { }
+
+private:
+ clog( const clog& );
+ const clog& operator=( const clog& );
+};
+
+class make_cout : public detail::log<detail::channelln> {
+public:
+ make_cout(const char* filename, int line_number, const char* func) :
+ detail::log<detail::channelln>(std::cout, filename, line_number, func)
+ { }
+
+private:
+ make_cout( const make_cout& );
+ const make_cout& operator=( const make_cout& );
+};
+
+class cout : public detail::log<detail::channel> {
+public:
+ cout(const char* filename, int line_number, const char* func) :
+ detail::log<detail::channel>(std::cout, filename, line_number, func)
+ { }
+
+private:
+ cout( const cout& );
+ const cout& operator=( const cout& );
+};
+
+class cecho : public detail::log<detail::channelfl> {
+public:
+ cecho(const char* filename, int line_number, const char* func) :
+ detail::log<detail::channelfl>(std::cout, filename, line_number, func)
+ { }
+
+private:
+ cecho( const cecho& );
+ const cecho& operator=( const cecho& );
+};
+
+} // namespace stream
+
+#define Error stream::cerr(__FILE__, __LINE__, __func__)
+
+#define Echo stream::cecho(NULL, __LINE__, __func__)
+
+#define Out stream::cout(NULL, __LINE__, __func__)
+
+#define Outn() stream::cout(NULL, __LINE__, __func__) << " "
+
+#define Log stream::clog(NULL, __LINE__, __func__)
+
+#define Logn() stream::clog(NULL, __LINE__, __func__) << " "
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+namespace libtest {
+
+const char *test_strerror(test_return_t code)
+{
+ switch (code) {
+ case TEST_SUCCESS:
+ return "ok";
+
+ case TEST_FAILURE:
+ return "failed";
+
+ case TEST_SKIPPED:
+ return "skipped";
+ }
+
+ FATAL("No port could be found");
+}
+
+} // namespace libtest
+
+
+std::ostream& operator<<(std::ostream& output, const enum test_return_t &arg)
+{
+ output << libtest::test_strerror(arg);
+ return output;
+}
+
+std::ostream& operator<<(std::ostream& output, const std::vector<char> &arg)
+{
+ output << "std::vector<char>:" << arg.size();
+ return output;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <vector>
+#include <iostream>
+
+namespace libtest {
+
+/**
+ @note Friendly print function for errors.
+*/
+LIBTEST_API
+const char *test_strerror(test_return_t code);
+
+} // namespace libtest
+
+std::ostream& operator<<(std::ostream& output, const enum test_return_t &arg);
+std::ostream& operator<<(std::ostream& output, const std::vector<char> &arg);
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include "util/string.hpp"
+
+#define test_literal_param util_literal_param
+#define test_literal_compare_param util_literal_compare_param
+#define test_literal_param_size util_literal_param_size
+#define test_string_make_from_cstr util_string_make_from_cstr
+#define test_string_make_from_array util_string_make_from_array
+#define test_array_length util_array_length
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+#include <libtest/lite.h>
+
+/**
+ A structure describing the test case.
+*/
+struct test_st {
+ const char *name;
+ bool requires_flush;
+ test_callback_fn *test_fn;
+};
+
+#define test_assert_errno(A) \
+do \
+{ \
+ if ((A)) { \
+ fprintf(stderr, "\n%s:%d: Assertion failed for %s: ", __FILE__, __LINE__, __func__);\
+ perror(#A); \
+ fprintf(stderr, "\n"); \
+ libtest::create_core(); \
+ assert((A)); \
+ } \
+} while (0)
+
+#define test_truth(A) \
+do \
+{ \
+ if (! (A)) { \
+ fprintf(stderr, "\n%s:%d: Assertion \"%s\" failed, in %s\n", __FILE__, __LINE__, #A, __func__);\
+ libtest::create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
+#define test_true(A) \
+do \
+{ \
+ if (! (A)) { \
+ fprintf(stderr, "\n%s:%d: Assertion \"%s\" failed, in %s\n", __FILE__, __LINE__, #A, __func__);\
+ libtest::create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
+#define test_true_got(A, B) test_true(A);
+#define test_true_hint(A, B) test_true(A);
+
+#define test_compare_hint(A, B, C) test_compare(A, B);
+#define test_compare_got(A, B, C) test_compare(A, B);
+
+#define test_skip(__expected, __actual) \
+do \
+{ \
+ if (libtest::_compare(__FILE__, __LINE__, __func__, ((__expected)), ((__actual)), false) == false) \
+ { \
+ return TEST_SKIPPED; \
+ } \
+} while (0)
+
+#define test_skip_valgrind() \
+do \
+{ \
+ if (libtest::_in_valgrind(__FILE__, __LINE__, __func__)) \
+ { \
+ return TEST_SKIPPED; \
+ } \
+} while (0)
+
+#define test_fail(A) \
+do \
+{ \
+ if (1) { \
+ fprintf(stderr, "\n%s:%d: Failed with %s, in %s\n", __FILE__, __LINE__, #A, __func__);\
+ libtest::create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
+
+#define test_false(A) \
+do \
+{ \
+ if ((A)) { \
+ fprintf(stderr, "\n%s:%d: Assertion failed %s, in %s\n", __FILE__, __LINE__, #A, __func__);\
+ libtest::create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
+#define test_false_with(A,B) \
+do \
+{ \
+ if ((A)) { \
+ fprintf(stderr, "\n%s:%d: Assertion failed %s with %s\n", __FILE__, __LINE__, #A, (B));\
+ libtest::create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
+#define test_ne_compare(__expected, __actual) \
+do \
+{ \
+ if (libtest::_ne_compare(__FILE__, __LINE__, __func__, ((__expected)), ((__actual)), true) == false) \
+ { \
+ libtest::create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
+#define test_compare(__expected, __actual) \
+do \
+{ \
+ if (libtest::_compare(__FILE__, __LINE__, __func__, ((__expected)), ((__actual)), true) == false) \
+ { \
+ libtest::create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
+#define test_zero(__actual) \
+do \
+{ \
+ if (libtest::_compare_zero(__FILE__, __LINE__, __func__, ((__actual))) == false) \
+ { \
+ libtest::create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
+#define test_null test_zero
+
+#define test_compare_warn(__expected, __actual) \
+do \
+{ \
+ void(libtest::_compare(__FILE__, __LINE__, __func__, (__expected), (__actual)), true); \
+} while (0)
+
+#define test_warn(__truth, __explain) \
+do \
+{ \
+ void(libtest::_assert_truth(__FILE__, __LINE__, __func__, bool((__truth)), #__truth, __explain)); \
+} while (0)
+
+#define test_strcmp(__expected, __actual) \
+do \
+{ \
+ void(libtest::_compare_strcmp(__FILE__, __LINE__, __func__, (__expected), (__actual))); \
+} while (0)
+
+#define test_memcmp(A,B,C) \
+do \
+{ \
+ if ((A) == NULL or (B) == NULL or memcmp((A), (B), (C))) \
+ { \
+ fprintf(stderr, "\n%s:%d: %.*s -> %.*s\n", __FILE__, __LINE__, (int)(C), (char *)(A), (int)(C), (char *)(B)); \
+ libtest::create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
+#define test_return_if(__test_return_t) \
+do \
+{ \
+ if ((__test_return_t) != TEST_SUCCESS) \
+ { \
+ return __test_return_t; \
+ } \
+} while (0)
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ Structures for generic tests.
+*/
+
+#pragma once
+
+#ifndef YATL_FULL
+# define YATL_FULL 1
+#endif
+
+#ifndef __PRETTY_FUNCTION__
+# define __PRETTY_FUNCTION__ __func__
+#endif
+
+#define YATL_STRINGIFY(x) #x
+#define YATL_TOSTRING(x) YATL_STRINGIFY(x)
+#define YATL_AT __FILE__ ":" YATL_TOSTRING(__LINE__)
+#define YATL_AT_PARAM __func__, AT
+#define YATL_UNIQUE __FILE__ ":" YATL_TOSTRING(__LINE__) "_unique"
+#define YATL_UNIQUE_FUNC_NAME __FILE__ ":" YATL_TOSTRING(__LINE__) "_unique_func"
+
+#define LIBYATL_DEFAULT_PARAM __FILE__, __LINE__, __PRETTY_FUNCTION__
+
+#include <cstdio>
+#include <cstdlib>
+#include <arpa/inet.h>
+
+#include <libtest/visibility.h>
+#include <libtest/version.h>
+
+#include <libtest/vchar.hpp>
+#include <libtest/error.h>
+#include <libtest/exception.hpp>
+#include <libtest/exception/disconnected.hpp>
+#include <libtest/exception/fatal.hpp>
+#include <libtest/result.hpp>
+
+#include <libtest/has.hpp>
+#include <libtest/error.h>
+#include <libtest/strerror.h>
+#include <libtest/timer.hpp>
+#include <libtest/alarm.h>
+#include <libtest/stream.h>
+#include <libtest/comparison.hpp>
+#include <libtest/server.h>
+#include <libtest/server_container.h>
+#include <libtest/wait.h>
+#include <libtest/callbacks.h>
+#include <libtest/test.h>
+#include <libtest/dream.h>
+#include <libtest/core.h>
+#include <libtest/runner.h>
+#include <libtest/port.h>
+#include <libtest/is_local.hpp>
+#include <libtest/socket.hpp>
+#include <libtest/collection.h>
+#include <libtest/framework.h>
+#include <libtest/get.h>
+#include <libtest/cmdline.h>
+#include <libtest/string.hpp>
+#include <libtest/binaries.h>
+#include <libtest/http.hpp>
+#include <libtest/cpu.hpp>
+#include <libtest/tmpfile.hpp>
+#include <libtest/client.hpp>
+#include <libtest/thread.hpp>
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <pthread.h>
+
+#if __cplusplus < 201103L
+# define noexcept(a)
+#endif
+
+namespace libtest
+{
+namespace thread
+{
+
+class Mutex
+{
+public:
+ Mutex() :
+ _err(0)
+ {
+ _err= pthread_mutex_init(&_mutex, NULL);
+ }
+
+ ~Mutex() noexcept(false)
+ {
+ if ((_err= pthread_mutex_destroy(&_mutex)))
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_destroy: %s", strerror(_err));
+ }
+ }
+
+ pthread_mutex_t* handle()
+ {
+ if (_err != 0)
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_mutex_init: %s", strerror(_err));
+ }
+
+ return &_mutex;
+ }
+
+private:
+ int _err;
+ pthread_mutex_t _mutex;
+};
+
+class ScopedLock
+{
+public:
+ ScopedLock(Mutex& mutex_) :
+ _mutex(mutex_)
+ {
+ init();
+ }
+
+ ~ScopedLock() noexcept(false)
+ {
+ int err;
+ if ((err= pthread_mutex_unlock(_mutex.handle())))
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_mutex_unlock: %s", strerror(err));
+ }
+ }
+
+ Mutex* handle()
+ {
+ return &_mutex;
+ }
+
+private:
+ void init()
+ {
+ int err;
+ if ((err= pthread_mutex_lock(_mutex.handle())))
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_mutex_lock: %s", strerror(err));
+ }
+ }
+
+private:
+ Mutex& _mutex;
+};
+
+class Condition
+{
+public:
+ Condition()
+ {
+ int err;
+ if ((err= pthread_cond_init(&_cond, NULL)))
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_mutex_init: %s", strerror(err));
+ }
+ }
+
+ ~Condition() noexcept(false)
+ {
+ int err;
+ if ((err= pthread_cond_destroy(&_cond)))
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_destroy: %s", strerror(err));
+ }
+ }
+
+ void broadcast()
+ {
+ int err;
+ if ((err= pthread_cond_broadcast(&_cond)))
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_broadcast: %s", strerror(err));
+ }
+ }
+
+ void signal()
+ {
+ int err;
+ if ((err= pthread_cond_signal(&_cond)))
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_broadcast: %s", strerror(err));
+ }
+ }
+
+ void wait(ScopedLock& lock_)
+ {
+ int err;
+ if ((err= pthread_cond_wait(&_cond, lock_.handle()->handle())))
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_cond_wait: %s", strerror(err));
+ }
+ }
+
+private:
+ pthread_cond_t _cond;
+};
+
+class Barrier
+{
+public:
+ explicit Barrier(uint32_t count):
+ _threshold(count),
+ _count(count),
+ _generation(0)
+ {
+ if (_count == 0)
+ {
+ fatal_assert("Zero is an invalid value");
+ }
+ }
+
+ ~Barrier()
+ {
+ }
+
+ bool wait()
+ {
+ ScopedLock l(_mutex);
+ uint32_t gen = _generation;
+
+ if (--_count == 0)
+ {
+ _generation++;
+ _count = _threshold;
+ _cond.broadcast();
+
+ return true;
+ }
+
+ while (gen == _generation)
+ {
+ _cond.wait(l);
+ }
+
+ return false;
+ }
+
+private:
+ Mutex _mutex;
+ Condition _cond;
+ uint32_t _threshold;
+ uint32_t _count;
+ uint32_t _generation;
+};
+
+class Thread
+{
+private:
+ typedef void *(*start_routine_fn) (void *);
+
+public:
+ template <class Function,class Arg1>
+ Thread(Function func, Arg1 arg):
+ _joined(false),
+ _func((start_routine_fn)func),
+ _context(arg)
+ {
+ int err;
+ if ((err= pthread_create(&_thread, NULL, entry_func, (void*)this)))
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_create: %s", strerror(err));
+ }
+ _owner= pthread_self();
+ }
+
+ bool running() const
+ {
+ return (pthread_kill(_thread, 0) == 0);
+ }
+
+ bool detached()
+ {
+ if (EDEADLK == pthread_join(_thread, NULL))
+ {
+ return true;
+ }
+
+ /* Result of pthread_join was EINVAL == detached thread */
+ return false;
+ }
+
+ bool join()
+ {
+ if (_thread == pthread_self())
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "Thread cannot join on itself");
+ }
+
+ if (_owner != pthread_self())
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "Attempt made by a non-owner thead to join on thread");
+ }
+
+ bool ret= false;
+ {
+ ScopedLock l(_join_mutex);
+ if (_joined == false)
+ {
+ int err;
+ if ((err= pthread_join(_thread, NULL)))
+ {
+ switch(err)
+ {
+ case EINVAL:
+ break;
+
+ case ESRCH:
+ ret= true;
+ break;
+
+ case EDEADLK:
+ default:
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "pthread_join: %s", strerror(err));
+ }
+ }
+ else
+ {
+ ret= true;
+ }
+
+ _joined= true;
+ }
+ }
+
+ return ret;
+ }
+
+ ~Thread()
+ {
+ join();
+ }
+
+protected:
+ void run()
+ {
+ _func(_context);
+ }
+
+private:
+ static void * entry_func(void* This)
+ {
+ ((Thread *)This)->run();
+ return NULL;
+ }
+
+private:
+ bool _joined;
+ pthread_t _thread;
+ pthread_t _owner;
+ start_routine_fn _func;
+ void* _context;
+ Mutex _join_mutex;
+};
+
+} // namespace thread
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/timer.hpp>
+
+#include <ctime>
+#include <iomanip>
+
+#ifdef __MACH__
+# include <mach/clock.h>
+# include <mach/mach.h>
+#else
+# include <sys/time.h>
+#endif
+
+namespace libtest {
+
+Timer::Timer()
+{
+ _begin.tv_sec= 0;
+ _begin.tv_nsec= 0;
+ _end.tv_sec= 0;
+ _end.tv_nsec= 0;
+}
+
+void Timer::reset()
+{
+ _end.tv_sec= 0;
+ _end.tv_nsec= 0;
+ _time(_begin);
+}
+
+void Timer::sample()
+{
+ _time(_end);
+}
+
+void Timer::offset(int64_t minutes_arg, int64_t seconds_arg, int64_t nanoseconds)
+{
+ reset();
+ _end= _begin;
+ _end.tv_sec+= (minutes_arg * 60) +seconds_arg;
+ _end.tv_nsec+= nanoseconds;
+}
+
+int64_t Timer::minutes()
+{
+ struct timespec result;
+ difference(result);
+ return int64_t(result.tv_sec / 60);
+}
+
+uint64_t Timer::elapsed_milliseconds() const
+{
+ struct timespec temp;
+ difference(temp);
+
+ return temp.tv_sec*1000 +temp.tv_nsec/1000000;
+}
+
+void Timer::difference(struct timespec& arg) const
+{
+ if ((_end.tv_nsec -_begin.tv_nsec) < 0)
+ {
+ arg.tv_sec= _end.tv_sec -_begin.tv_sec -1;
+ arg.tv_nsec= 1000000000 +_end.tv_nsec -_begin.tv_nsec;
+
+ }
+ else
+ {
+ arg.tv_sec= _end.tv_sec -_begin.tv_sec;
+ arg.tv_nsec= _end.tv_nsec -_begin.tv_nsec;
+ }
+}
+
+void Timer::_time(struct timespec& ts)
+{
+#ifdef __MACH__ // OSX lacks clock_gettime()
+ clock_serv_t _clock_serv;
+ mach_timespec_t _mach_timespec;
+ host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &_clock_serv);
+ clock_get_time(_clock_serv, &_mach_timespec);
+ mach_port_deallocate(mach_task_self(), _clock_serv);
+ ts.tv_sec= _mach_timespec.tv_sec;
+ ts.tv_nsec= _mach_timespec.tv_nsec;
+#elif defined(_WIN32)
+ ts.tv_sec= time(NULL);
+ ts.tv_nsec= 0;
+#else
+ clock_gettime(CLOCK_REALTIME, &ts);
+#endif
+}
+
+std::ostream& operator<<(std::ostream& output, const libtest::Timer& arg)
+{
+ struct timespec temp;
+ arg.difference(temp);
+
+ if (temp.tv_sec > 60)
+ {
+ output << temp.tv_sec / 60;
+ output << "." << temp.tv_sec % 60;
+ }
+ else
+ {
+ output << temp.tv_sec;
+ }
+
+ output << ":";
+ output << std::setfill('0') << std::setw(9) << temp.tv_nsec;
+
+ return output;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <cstdlib>
+#include <ctime>
+#include <iostream>
+
+
+namespace libtest {
+
+class Timer {
+public:
+
+ Timer();
+
+ void reset();
+
+ void sample();
+
+ void offset(int64_t minutes_arg, int64_t seconds_arg, int64_t nanoseconds);
+
+ int64_t minutes();
+
+ uint64_t elapsed_milliseconds() const;
+
+ void difference(struct timespec& arg) const;
+
+private:
+ void _time(struct timespec& ts);
+
+private:
+ struct timespec _begin;
+ struct timespec _end;
+};
+
+std::ostream& operator<<(std::ostream& output, const libtest::Timer& arg);
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/common.h>
+
+namespace libtest {
+
+std::string create_tmpfile(const std::string& name, int& fd)
+{
+ libtest::vchar_t file_buffer;
+ file_buffer.resize(FILENAME_MAX);
+ file_buffer[0]= 0;
+
+ int length= snprintf(&file_buffer[0], file_buffer.size(), "var/tmp/%s.XXXXXX", name.c_str());
+ fatal_assert(length > 0);
+
+ if ((fd= mkstemp(&file_buffer[0])) == -1)
+ {
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "mkstemp() failed on %s with %s", &file_buffer[0], strerror(errno));
+ }
+
+ return &file_buffer[0];
+}
+
+std::string create_tmpfile(const std::string& name)
+{
+ int fd;
+ std::string ret_file= create_tmpfile(name, fd);
+ close(fd);
+ unlink(ret_file.c_str());
+
+ return ret_file.c_str();
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libtest/common.h>
+
+namespace libtest {
+
+std::string create_tmpfile(const std::string&, int&);
+std::string create_tmpfile(const std::string&);
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <libtest/yatl.h>
+
+#if defined(HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H) && HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H
+# include <libmemcached-1.0/types/return.h>
+#endif
+
+#if defined(HAVE_LIBGEARMAN_1_0_RETURN_H) && HAVE_LIBGEARMAN_1_0_RETURN_H
+# include <libgearman-1.0/return.h>
+#endif
+
+#include <cstdlib>
+#include <unistd.h>
+
+using namespace libtest;
+
+static std::string testing_service;
+
+// Used to track setups where we see if failure is happening
+static uint32_t fatal_calls= 0;
+
+static test_return_t getenv_TEST(void *)
+{
+#if 0
+ for (char **ptr= environ; *ptr; ptr++)
+ {
+ Error << *ptr;
+ }
+#endif
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t LIBTOOL_COMMAND_test(void *)
+{
+ test_true(getenv("LIBTOOL_COMMAND"));
+ return TEST_SUCCESS;
+}
+
+static test_return_t VALGRIND_COMMAND_test(void *)
+{
+ test_true(getenv("VALGRIND_COMMAND"));
+ return TEST_SUCCESS;
+}
+
+static test_return_t HELGRIND_COMMAND_test(void *)
+{
+ test_true(getenv("HELGRIND_COMMAND"));
+ return TEST_SUCCESS;
+}
+
+static test_return_t GDB_COMMAND_test(void *)
+{
+ test_true(getenv("GDB_COMMAND"));
+ return TEST_SUCCESS;
+}
+
+static test_return_t test_success_equals_one_test(void *)
+{
+ test_skip(HAVE_LIBMEMCACHED, 1);
+#if defined(HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H) && HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H
+ test_zero(MEMCACHED_SUCCESS);
+#endif
+ return TEST_SUCCESS;
+}
+
+static test_return_t test_success_test(void *)
+{
+ return TEST_SUCCESS;
+}
+
+static test_return_t test_throw_success_TEST(void *)
+{
+ try {
+ _SUCCESS;
+ }
+ catch (const libtest::__success&)
+ {
+ return TEST_SUCCESS;
+ }
+ catch (...)
+ {
+ return TEST_FAILURE;
+ }
+
+ return TEST_FAILURE;
+}
+
+static test_return_t test_throw_skip_macro_TEST(void *)
+{
+ try {
+ SKIP_IF(true);
+ }
+ catch (const libtest::__skipped&)
+ {
+ return TEST_SUCCESS;
+ }
+ catch (...)
+ {
+ FAIL("SLIP_IF() failed to throw libtest::_skipped");
+ }
+
+ FAIL("SLIP_IF() failed to throw");
+
+ return TEST_FAILURE;
+}
+
+static test_return_t test_throw_skip_unless_macro_TEST(void *)
+{
+ try {
+ SKIP_UNLESS(false);
+ }
+ catch (const libtest::__skipped&)
+ {
+ return TEST_SUCCESS;
+ }
+ catch (...)
+ {
+ FAIL("SLIP_UNLESS() failed to throw libtest::_skipped");
+ }
+
+ FAIL("SLIP_UNLESS() failed to throw");
+
+ return TEST_FAILURE;
+}
+
+static test_return_t test_throw_skip_TEST(void *)
+{
+ try {
+ throw libtest::__skipped(LIBYATL_DEFAULT_PARAM, "basic test");
+ }
+ catch (const libtest::__skipped&)
+ {
+ return TEST_SUCCESS;
+ }
+ catch (...)
+ {
+ FAIL("SLIP_IF() failed to throw libtest::_skipped");
+ }
+
+ FAIL("SLIP_IF() failed to throw");
+
+ return TEST_FAILURE;
+}
+
+static test_return_t test_throw_fail_TEST(void *)
+{
+ try {
+ FAIL("test message!");
+ }
+ catch (const libtest::__failure& e)
+ {
+ std::string compare_message("test message!");
+ test_zero(compare_message.compare(e.what()));
+ return TEST_SUCCESS;
+ }
+ catch (...)
+ {
+ return TEST_FAILURE;
+ }
+
+ return TEST_FAILURE;
+}
+#pragma GCC diagnostic ignored "-Wstack-protector"
+
+#ifdef __clang__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wformat-security"
+#endif
+
+static test_return_t ASSERT_FALSE__TEST(void *)
+{
+ try {
+ ASSERT_FALSE(true);
+ }
+ catch (const libtest::__failure& e)
+ {
+ ASSERT_STREQ(e.what(), "Assertion '!true'");
+ return TEST_SUCCESS;
+ }
+ catch (...)
+ {
+ return TEST_FAILURE;
+ }
+
+ return TEST_FAILURE;
+}
+
+#ifdef __clang__
+# pragma GCC diagnostic pop
+#endif
+
+static test_return_t ASSERT_NEQ_FAIL_TEST(void *)
+{
+ try {
+ ASSERT_NEQ(1,1);
+ }
+ catch (const libtest::__failure& e)
+ {
+ ASSERT_STREQ(e.what(), "Assertion '1' == '1'");
+ return TEST_SUCCESS;
+ }
+ catch (...)
+ {
+ return TEST_FAILURE;
+ }
+
+ return TEST_FAILURE;
+}
+
+static test_return_t ASSERT_NEQ_TEST(void *)
+{
+ ASSERT_NEQ(1,0);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t ASSERT_FALSE_TEST(void *)
+{
+ try {
+ FAIL(__func__);
+ }
+ catch (const libtest::__failure& e)
+ {
+ ASSERT_STREQ(e.what(), __func__);
+ return TEST_SUCCESS;
+ }
+ catch (...)
+ {
+ return TEST_FAILURE;
+ }
+
+ return TEST_FAILURE;
+}
+
+static test_return_t test_failure_test(void *)
+{
+ return TEST_SKIPPED; // Only run this when debugging
+
+ ASSERT_EQ(1, 2);
+ return TEST_SUCCESS;
+}
+
+static test_return_t local_test(void *)
+{
+ if (getenv("LIBTEST_LOCAL"))
+ {
+ test_true(test_is_local());
+ }
+ else
+ {
+ test_false(test_is_local());
+ }
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t local_not_test(void *)
+{
+ return TEST_SKIPPED;
+
+ std::string temp;
+
+ const char *ptr;
+ if ((ptr= getenv("LIBTEST_LOCAL")) == NULL)
+ {
+ temp.append(ptr);
+ }
+
+ // unsetenv() will cause issues with valgrind
+ _compare(__FILE__, __LINE__, __func__, 0, unsetenv("LIBTEST_LOCAL"), true);
+ ASSERT_EQ(0, unsetenv("LIBTEST_LOCAL"));
+ test_false(test_is_local());
+
+ ASSERT_EQ(0, setenv("LIBTEST_LOCAL", "1", 1));
+ test_true(test_is_local());
+
+ if (temp.empty())
+ {
+ ASSERT_EQ(0, unsetenv("LIBTEST_LOCAL"));
+ }
+ else
+ {
+ char *old_string= strdup(temp.c_str());
+ ASSERT_EQ(0, setenv("LIBTEST_LOCAL", old_string, 1));
+ }
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_exists_test(void *)
+{
+ ASSERT_EQ(0, access("var", R_OK | W_OK | X_OK));
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_tmp_exists_test(void *)
+{
+ ASSERT_EQ(0, access("var/tmp", R_OK | W_OK | X_OK));
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_run_exists_test(void *)
+{
+ ASSERT_EQ(0, access("var/run", R_OK | W_OK | X_OK));
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_log_exists_test(void *)
+{
+ ASSERT_EQ(0, access("var/log", R_OK | W_OK | X_OK));
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_drizzle_exists_test(void *)
+{
+ ASSERT_EQ(0, access("var/drizzle", R_OK | W_OK | X_OK));
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_tmp_test(void *)
+{
+ FILE *file= fopen("var/tmp/junk", "w+");
+ test_true(file);
+ fclose(file);
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_run_test(void *)
+{
+ FILE *file= fopen("var/run/junk", "w+");
+ test_true(file);
+ fclose(file);
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_log_test(void *)
+{
+ FILE *file= fopen("var/log/junk", "w+");
+ test_true(file);
+ fclose(file);
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_drizzle_test(void *)
+{
+ FILE *file= fopen("var/drizzle/junk", "w+");
+ test_true(file);
+ fclose(file);
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_tmp_rm_test(void *)
+{
+ test_true(unlink("var/tmp/junk") == 0);
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_run_rm_test(void *)
+{
+ test_true(unlink("var/run/junk") == 0);
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_log_rm_test(void *)
+{
+ test_true(unlink("var/log/junk") == 0);
+ return TEST_SUCCESS;
+}
+
+static test_return_t var_drizzle_rm_test(void *)
+{
+ test_true(unlink("var/drizzle/junk") == 0);
+ return TEST_SUCCESS;
+}
+
+static test_return_t _compare_test_return_t_test(void *)
+{
+ ASSERT_EQ(TEST_SUCCESS, TEST_SUCCESS);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t _compare_memcached_return_t_test(void *)
+{
+ test_skip(HAVE_LIBMEMCACHED, true);
+#if defined(HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H) && HAVE_LIBMEMCACHED_1_0_TYPES_RETURN_H
+ ASSERT_EQ(MEMCACHED_SUCCESS, MEMCACHED_SUCCESS);
+#endif
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t _compare_gearman_return_t_test(void *)
+{
+ test_skip(HAVE_LIBGEARMAN, true);
+#if defined(HAVE_LIBGEARMAN_1_0_RETURN_H) && HAVE_LIBGEARMAN_1_0_RETURN_H
+ ASSERT_EQ(GEARMAN_SUCCESS, GEARMAN_SUCCESS);
+#endif
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t drizzled_cycle_test(void *object)
+{
+ server_startup_st *servers= (server_startup_st*)object;
+ test_true(servers and servers->validate());
+
+#if defined(HAVE_GEARMAND_BINARY) && HAVE_GEARMAND_BINARY
+ test_true(has_drizzled());
+#endif
+
+ test_skip(true, has_drizzled());
+
+ test_skip(true, server_startup(*servers, "drizzled", get_free_port(), NULL));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t gearmand_cycle_test(void *object)
+{
+ server_startup_st *servers= (server_startup_st*)object;
+ test_true(servers and servers->validate());
+
+ test_skip(true, has_gearmand());
+ test_skip(true, server_startup(*servers, "gearmand", get_free_port(), NULL));
+ servers->clear();
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t skip_shim(bool a, bool b)
+{
+ test_skip(a, b);
+ return TEST_SUCCESS;
+}
+
+static test_return_t test_skip_true_TEST(void*)
+{
+ ASSERT_EQ(true, true);
+ ASSERT_EQ(false, false);
+ ASSERT_EQ(TEST_SUCCESS, skip_shim(true, true));
+ ASSERT_EQ(TEST_SUCCESS, skip_shim(false, false));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t test_skip_false_TEST(void*)
+{
+ ASSERT_EQ(TEST_SKIPPED, skip_shim(true, false));
+ ASSERT_EQ(TEST_SKIPPED, skip_shim(false, true));
+ return TEST_SUCCESS;
+}
+
+static test_return_t server_startup_fail_TEST(void *object)
+{
+ server_startup_st *servers= (server_startup_st*)object;
+ test_true(servers);
+
+ fatal::disable();
+ ASSERT_EQ(servers->start_server(testing_service, LIBTEST_FAIL_PORT, NULL), true);
+ fatal::enable();
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t server_startup_TEST(void *object)
+{
+ server_startup_st *servers= (server_startup_st*)object;
+ test_true(servers);
+
+ ASSERT_EQ(servers->start_server(testing_service, get_free_port(), NULL), true);
+
+ test_true(servers->last());
+ pid_t last_pid= servers->last()->pid();
+
+ ASSERT_EQ(servers->last()->pid(), last_pid);
+ test_true(last_pid > 1);
+ ASSERT_EQ(kill(last_pid, 0), 0);
+
+ test_true(servers->shutdown());
+#if 0
+ ASSERT_EQ(servers->last()->pid(), -1);
+ ASSERT_EQ(kill(last_pid, 0), -1);
+#endif
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t socket_server_startup_TEST(void *object)
+{
+ server_startup_st *servers= (server_startup_st*)object;
+ test_true(servers);
+
+ test_true(servers->start_socket_server(testing_service, get_free_port(), NULL));
+
+ return TEST_SUCCESS;
+}
+
+#if 0
+static test_return_t memcached_sasl_test(void *object)
+{
+ server_startup_st *servers= (server_startup_st*)object;
+ test_true(servers);
+
+ test_skip(false, bool(getenv("LOG_COMPILER")));
+
+ if (MEMCACHED_SASL_BINARY)
+ {
+ if (HAVE_LIBMEMCACHED)
+ {
+ test_true(has_memcached_sasl());
+ test_true(server_startup(*servers, "memcached-sasl", get_free_port(), NULL));
+
+ return TEST_SUCCESS;
+ }
+ }
+
+ return TEST_SKIPPED;
+}
+#endif
+
+static test_return_t application_true_BINARY(void *)
+{
+ test_skip(0, access("/usr/bin/true", X_OK ));
+ Application true_app("/usr/bin/true");
+
+ ASSERT_EQ(Application::SUCCESS, true_app.run());
+ ASSERT_EQ(Application::SUCCESS, true_app.join());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t application_gdb_true_BINARY2(void *)
+{
+ test_skip(0, access("/usr/bin/gdb", X_OK ));
+ test_skip(0, access("/usr/bin/true", X_OK ));
+
+ Application true_app("/usr/bin/true");
+ true_app.use_gdb(true);
+
+ ASSERT_EQ(Application::SUCCESS, true_app.run());
+ ASSERT_EQ(Application::SUCCESS, true_app.join());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t application_gdb_true_BINARY(void *)
+{
+ test_skip(0, access("/usr/bin/gdb", X_OK ));
+ test_skip(0, access("/usr/bin/true", X_OK ));
+
+ Application true_app("/usr/bin/true");
+ true_app.use_gdb(true);
+
+ const char *args[]= { "--fubar", 0 };
+ ASSERT_EQ(Application::SUCCESS, true_app.run(args));
+ ASSERT_EQ(Application::SUCCESS, true_app.join());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t application_true_fubar_BINARY(void *)
+{
+ test_skip(0, access("/usr/bin/true", X_OK ));
+ Application true_app("/usr/bin/true");
+
+ const char *args[]= { "--fubar", 0 };
+ ASSERT_EQ(Application::SUCCESS, true_app.run(args));
+ ASSERT_EQ(Application::SUCCESS, true_app.join());
+ test_zero(true_app.stdout_result().size());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t application_doesnotexist_BINARY(void *)
+{
+
+ test_skip_valgrind();
+ Application true_app("doesnotexist");
+ true_app.will_fail();
+
+ const char *args[]= { "--fubar", 0 };
+#if defined(__APPLE__) && __APPLE__
+ ASSERT_EQ(Application::INVALID_POSIX_SPAWN, true_app.run(args));
+#elif defined(__FreeBSD__) && __FreeBSD__
+ ASSERT_EQ(Application::INVALID_POSIX_SPAWN, true_app.run(args));
+#else
+ Application::error_t rc = true_app.run(args);
+ if (Application::SUCCESS == rc) {
+ ASSERT_EQ(Application::INVALID_POSIX_SPAWN, true_app.join());
+ } else {
+ ASSERT_EQ(Application::INVALID_POSIX_SPAWN, rc);
+ }
+#endif
+
+ test_zero(true_app.stdout_result().size());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t GET_TEST(void *)
+{
+ libtest::http::GET get("http://foo.example.com/");
+
+ ASSERT_EQ(false, get.execute());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t POST_TEST(void *)
+{
+ libtest::vchar_t body;
+ libtest::http::POST post("http://foo.example.com/", body);
+
+ ASSERT_EQ(false, post.execute());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t TRACE_TEST(void *)
+{
+ libtest::vchar_t body;
+ libtest::http::TRACE trace("http://foo.example.com/", body);
+
+ ASSERT_EQ(false, trace.execute());
+
+ return TEST_SUCCESS;
+}
+
+
+static test_return_t vchar_t_TEST(void *)
+{
+ libtest::vchar_t response;
+ libtest::make_vector(response, test_literal_param("fubar\n"));
+ ASSERT_EQ(response, response);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t vchar_t_make_append_TEST(void *)
+{
+ libtest::vchar_t hostname;
+ libtest::vchar::make(hostname, 23);
+ libtest::vchar::append(hostname, ".com");
+ ASSERT_EQ(28, hostname.size());
+ ASSERT_EQ(0, hostname[27]);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t vchar_t_compare_neg_TEST(void *)
+{
+ libtest::vchar_t response;
+ libtest::vchar_t response2;
+ libtest::make_vector(response, test_literal_param("fubar\n"));
+ libtest::make_vector(response2, test_literal_param(__func__));
+ test_true(response != response2);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t application_echo_fubar_BINARY(void *)
+{
+ if (0)
+ {
+ test_skip(0, access("/bin/echo", X_OK ));
+ Application true_app("/bin/echo");
+
+ const char *args[]= { "fubar", 0 };
+ ASSERT_EQ(Application::SUCCESS, true_app.run(args));
+
+ while (true_app.slurp() == false) {} ;
+
+ libtest::vchar_t response;
+ make_vector(response, test_literal_param("fubar\n"));
+ ASSERT_EQ(response, true_app.stdout_result());
+ }
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t application_echo_fubar_BINARY2(void *)
+{
+ if (0)
+ {
+ test_skip(0, access("/bin/echo", X_OK ));
+ Application true_app("/bin/echo");
+
+ true_app.add_option("fubar");
+
+ ASSERT_EQ(Application::SUCCESS, true_app.run());
+ ASSERT_EQ(Application::SUCCESS, true_app.join());
+
+ libtest::vchar_t response;
+ make_vector(response, test_literal_param("fubar\n"));
+ ASSERT_EQ(response, true_app.stdout_result());
+ }
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t echo_fubar_BINARY(void *)
+{
+ const char *args[]= { "fubar", 0 };
+ ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("/bin/echo", args));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t core_count_BINARY(void *)
+{
+ const char *args[]= { 0 };
+
+ ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/core-count", args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t wait_BINARY(void *)
+{
+ const char *args[]= { "--quiet", 0 };
+
+ ASSERT_EQ(EXIT_FAILURE, exec_cmdline("libtest/wait", args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t wait_help_BINARY(void *)
+{
+ const char *args[]= { "--quiet", "--help", 0 };
+
+ ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t wait_version_BINARY(void *)
+{
+ const char *args[]= { "--quiet", "--version", 0 };
+
+ ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t wait_services_BINARY(void *)
+{
+ test_skip(0, access("/etc/services", R_OK ));
+
+ const char *args[]= { "--quiet", "/etc/services", 0 };
+
+ ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t wait_services_BINARY2(void *)
+{
+ test_skip(0, access("/etc/services", R_OK ));
+
+ const char *args[]= { "/etc/services", 0 };
+
+ ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("libtest/wait", args, true));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t wait_services_appliction_TEST(void *)
+{
+ test_skip(0, access("/etc/services", R_OK ));
+ test_skip(0, access("/usr/bin/gdb", X_OK ));
+ test_skip(0, access("libtest/wait", X_OK ));
+
+ libtest::Application wait_app("libtest/wait", true);
+ wait_app.use_gdb(true);
+
+ const char *args[]= { "/etc/services", 0 };
+ ASSERT_EQ(Application::SUCCESS, wait_app.run(args));
+ ASSERT_EQ(Application::SUCCESS, wait_app.join());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t gdb_wait_services_appliction_TEST(void *)
+{
+ test_skip(true, false);
+#if defined(__APPLE__) && __APPLE__
+ test_skip(0, __APPLE__);
+#endif
+
+ test_skip(0, access("/etc/services", R_OK ));
+ test_skip(0, access("/usr/bin/gdb", X_OK ));
+ test_skip(0, access("libtest/wait", X_OK ));
+
+ libtest::Application wait_app("libtest/wait", true);
+ wait_app.use_gdb(true);
+
+ const char *args[]= { "/etc/services", 0 };
+ ASSERT_EQ(Application::SUCCESS, wait_app.run(args));
+ ASSERT_EQ(Application::SUCCESS, wait_app.join());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t gdb_abort_services_appliction_TEST(void *)
+{
+ test_skip(0, access("/usr/bin/gdb", X_OK ));
+ test_skip(0, access("libtest/abort", X_OK ));
+ test_skip(true, false);
+
+#if defined(__APPLE__) && __APPLE__
+ test_skip(0, __APPLE__);
+#endif
+
+ libtest::Application abort_app("libtest/abort", true);
+ abort_app.use_gdb(true);
+
+ ASSERT_EQ(Application::SUCCESS, abort_app.run());
+ ASSERT_EQ(Application::SUCCESS, abort_app.join());
+
+ std::string gdb_filename= abort_app.gdb_filename();
+ test_skip(0, access(gdb_filename.c_str(), R_OK ));
+ const char *args[]= { "SIGABRT", gdb_filename.c_str(), 0 };
+ ASSERT_EQ(EXIT_SUCCESS, exec_cmdline("grep", args));
+
+ // Sanity test
+ args[0]= "THIS_WILL_NOT_BE_FOUND";
+ ASSERT_EQ(EXIT_FAILURE, exec_cmdline("grep", args));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t get_free_port_TEST(void *)
+{
+ in_port_t ret_port;
+ test_true((ret_port= get_free_port()));
+ test_true(get_free_port() != default_port());
+ test_true(get_free_port() != get_free_port());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t fatal_TEST(void *)
+{
+ ASSERT_EQ(fatal_calls++, fatal::disabled_counter());
+ throw libtest::fatal(LIBYATL_DEFAULT_PARAM, "Testing va_args based fatal(): %d", 10);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t number_of_cpus_TEST(void *)
+{
+ test_true(number_of_cpus() >= 1);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t check_dns_TEST(void *)
+{
+ test_warn(libtest::check_dns(), "Broken DNS server/no DNS server found");
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t Timer_TEST(void *)
+{
+ int64_t minutes= random() % 50;
+ minutes++;
+
+ Timer check;
+
+ check.reset();
+ check.offset(minutes, 2, 200);
+
+ ASSERT_EQ(check.minutes(), minutes);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t lookup_true_TEST(void *)
+{
+ test_warn(libtest::lookup("exist.gearman.info"), "dns is not currently working");
+ return TEST_SUCCESS;
+}
+
+static test_return_t lookup_false_TEST(void *)
+{
+ SKIP_IF_(libtest::lookup("does_not_exist.gearman.info"),
+ "Broken DNS server detected");
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t create_tmpfile_TEST(void *)
+{
+ test_skip(0, access("/usr/bin/touch", X_OK ));
+ std::string tmp= create_tmpfile(__func__);
+ ASSERT_EQ(-1, access(tmp.c_str(), R_OK));
+ ASSERT_EQ(-1, access(tmp.c_str(), F_OK));
+
+ Application touch_app("/usr/bin/touch");
+ const char *args[]= { tmp.c_str(), 0 };
+ ASSERT_EQ(Application::SUCCESS, touch_app.run(args));
+ ASSERT_EQ(Application::SUCCESS, touch_app.join());
+
+ ASSERT_EQ(0, access(tmp.c_str(), R_OK));
+ ASSERT_EQ(0, unlink(tmp.c_str()));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t fatal_message_TEST(void *)
+{
+ ASSERT_EQ(fatal_calls++, fatal::disabled_counter());
+ FATAL("Fatal test");
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t default_port_TEST(void *)
+{
+ in_port_t ret_port= default_port();
+ ASSERT_EQ(ret_port, libtest::default_port());
+ ASSERT_EQ(ret_port, libtest::default_port());
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t check_for_VALGRIND(void *)
+{
+ test_skip_valgrind();
+ return TEST_SUCCESS;
+}
+
+static test_return_t check_for_gearman(void *)
+{
+ test_skip(true, HAVE_LIBGEARMAN);
+ test_skip(true, has_gearmand());
+#if defined(HAVE_GEARMAND_BINARY) && HAVE_GEARMAND_BINARY
+ if (GEARMAND_BINARY)
+ {
+ if (strcmp(GEARMAND_BINARY, "./gearmand/gearmand"))
+ {
+ test_zero(access(GEARMAND_BINARY, X_OK ));
+ }
+ }
+ else
+ {
+ return TEST_SKIPPED;
+ }
+#endif
+
+ testing_service= "gearmand";
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t check_for_drizzle(void *)
+{
+ test_skip(true, has_drizzled());
+
+ testing_service= "drizzled";
+
+ return TEST_SUCCESS;
+}
+
+
+test_st drizzled_tests[] ={
+ {"drizzled startup-shutdown", 0, drizzled_cycle_test },
+ {0, 0, 0}
+};
+
+test_st gearmand_tests[] ={
+#if 0
+ {"pause", 0, pause_test },
+#endif
+ {"gearmand startup-shutdown", 0, gearmand_cycle_test },
+ {"_compare(gearman_return_t)", 0, _compare_gearman_return_t_test },
+ {"server_startup(fail)", 0, server_startup_fail_TEST },
+ {0, 0, 0}
+};
+
+static test_return_t clear_servers(void* object)
+{
+ server_startup_st *servers= (server_startup_st*)object;
+ test_true(servers);
+ servers->clear();
+
+ testing_service.clear();
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t check_for_memcached(void* object)
+{
+ test_skip(true, has_memcached());
+
+ server_startup_st *servers= (server_startup_st*)object;
+ test_true(servers);
+ servers->clear();
+
+ testing_service= "memcached";
+
+ return TEST_SUCCESS;
+}
+
+test_st memcached_TESTS[] ={
+ {"memcached startup-shutdown", 0, server_startup_TEST },
+ {"memcached(socket file) startup-shutdown", 0, socket_server_startup_TEST },
+ {"_compare(memcached_return_t)", 0, _compare_memcached_return_t_test },
+ {"server_startup(fail)", 0, server_startup_fail_TEST },
+ {0, 0, 0}
+};
+
+test_st test_skip_TESTS[] ={
+ {"true, true", 0, test_skip_true_TEST },
+ {"true, false", 0, test_skip_false_TEST },
+ {0, 0, 0}
+};
+
+test_st environment_tests[] ={
+ {"getenv()", 0, getenv_TEST },
+ {"LIBTOOL_COMMAND", 0, LIBTOOL_COMMAND_test },
+ {"VALGRIND_COMMAND", 0, VALGRIND_COMMAND_test },
+ {"HELGRIND_COMMAND", 0, HELGRIND_COMMAND_test },
+ {"GDB_COMMAND", 0, GDB_COMMAND_test },
+ {0, 0, 0}
+};
+
+test_st tests_log[] ={
+ {"TEST_SUCCESS", false, test_success_test },
+ {"TEST_FAILURE", false, test_failure_test },
+ {"TEST_SUCCESS == 0", false, test_success_equals_one_test },
+ {"SUCCESS", false, test_throw_success_TEST },
+ {"libtest::__skipped", false, test_throw_skip_TEST },
+ {"SKIP_IF", false, test_throw_skip_macro_TEST },
+ {"SKIP_UNLESS", false, test_throw_skip_unless_macro_TEST },
+ {"FAIL", false, test_throw_fail_TEST },
+ {"ASSERT_FALSE_", false, ASSERT_FALSE__TEST },
+ {"ASSERT_FALSE", false, ASSERT_FALSE_TEST },
+ {"ASSERT_NEQ", false, ASSERT_NEQ_TEST },
+ {"ASSERT_NEQ FAIL", false, ASSERT_NEQ_FAIL_TEST },
+ {0, 0, 0}
+};
+
+test_st local_log[] ={
+ {"test_is_local()", 0, local_test },
+ {"test_is_local(NOT)", 0, local_not_test },
+ {0, 0, 0}
+};
+
+test_st directories_tests[] ={
+ {"var exists", 0, var_exists_test },
+ {"var/tmp exists", 0, var_tmp_exists_test },
+ {"var/run exists", 0, var_run_exists_test },
+ {"var/log exists", 0, var_log_exists_test },
+ {"var/drizzle exists", 0, var_drizzle_exists_test },
+ {"var/tmp", 0, var_tmp_test },
+ {"var/run", 0, var_run_test },
+ {"var/log", 0, var_log_test },
+ {"var/drizzle", 0, var_drizzle_test },
+ {"var/tmp rm", 0, var_tmp_rm_test },
+ {"var/run rm", 0, var_run_rm_test },
+ {"var/log rm", 0, var_log_rm_test },
+ {"var/drizzle rm", 0, var_drizzle_rm_test },
+ {0, 0, 0}
+};
+
+test_st comparison_tests[] ={
+ {"_compare(test_return_t)", 0, _compare_test_return_t_test },
+ {0, 0, 0}
+};
+
+test_st cmdline_tests[] ={
+ {"echo fubar", 0, echo_fubar_BINARY },
+ {"core-count", 0, core_count_BINARY },
+ {"wait --quiet", 0, wait_BINARY },
+ {"wait --quiet --help", 0, wait_help_BINARY },
+ {"wait --quiet --version", 0, wait_version_BINARY },
+ {"wait --quiet /etc/services", 0, wait_services_BINARY },
+ {"wait /etc/services", 0, wait_services_BINARY2 },
+ {"wait /etc/services", 0, wait_services_appliction_TEST },
+ {"gdb wait /etc/services", 0, gdb_wait_services_appliction_TEST },
+ {"gdb abort", 0, gdb_abort_services_appliction_TEST },
+ {0, 0, 0}
+};
+
+test_st get_free_port_TESTS[] ={
+ {"get_free_port()", 0, get_free_port_TEST },
+ {"default_port()", 0, default_port_TEST },
+ {0, 0, 0}
+};
+
+test_st fatal_message_TESTS[] ={
+ {"libtest::fatal", 0, fatal_TEST },
+ {"fatal_message()", 0, fatal_message_TEST },
+ {0, 0, 0}
+};
+
+test_st number_of_cpus_TESTS[] ={
+ {"libtest::number_of_cpus()", 0, number_of_cpus_TEST },
+ {0, 0, 0}
+};
+
+test_st create_tmpfile_TESTS[] ={
+ {"libtest::create_tmpfile()", 0, create_tmpfile_TEST },
+ {0, 0, 0}
+};
+
+test_st timer_TESTS[] ={
+ {"libtest::Timer", 0, Timer_TEST },
+ {0, 0, 0}
+};
+
+test_st dns_TESTS[] ={
+ {"libtest::lookup(true)", 0, lookup_true_TEST },
+ {"libtest::lookup(false)", 0, lookup_false_TEST },
+ {"libtest::check_dns()", 0, check_dns_TEST },
+ {0, 0, 0}
+};
+
+test_st application_tests[] ={
+ {"vchar_t", 0, vchar_t_TEST },
+ {"vchar_t make() append()", 0, vchar_t_make_append_TEST },
+ {"vchar_t compare()", 0, vchar_t_compare_neg_TEST },
+ {"true", 0, application_true_BINARY },
+ {"gbd true --fubar", 0, application_gdb_true_BINARY },
+ {"gbd true", 0, application_gdb_true_BINARY2 },
+ {"true --fubar", 0, application_true_fubar_BINARY },
+ {"doesnotexist --fubar", 0, application_doesnotexist_BINARY },
+ {"echo fubar", 0, application_echo_fubar_BINARY },
+ {"echo fubar (as option)", 0, application_echo_fubar_BINARY2 },
+ {0, 0, 0}
+};
+
+static test_return_t check_for_curl(void *)
+{
+ test_skip_valgrind();
+ test_skip(true, HAVE_LIBCURL);
+ return TEST_SUCCESS;
+}
+
+static test_return_t disable_fatal_exception(void *)
+{
+ fatal_calls= 0;
+ fatal::disable();
+ return TEST_SUCCESS;
+}
+
+static test_return_t enable_fatal_exception(void *)
+{
+ fatal::enable();
+ return TEST_SUCCESS;
+}
+
+test_st http_tests[] ={
+ {"GET", 0, GET_TEST },
+ {"POST", 0, POST_TEST },
+ {"TRACE", 0, TRACE_TEST },
+ {0, 0, 0}
+};
+
+collection_st collection[] ={
+ {"environment", 0, 0, environment_tests},
+ {"return values", 0, 0, tests_log},
+ {"test_skip()", 0, 0, test_skip_TESTS },
+ {"local", 0, 0, local_log},
+ {"directories", 0, 0, directories_tests},
+ {"comparison", 0, 0, comparison_tests},
+ {"gearmand", check_for_gearman, clear_servers, gearmand_tests},
+ {"memcached", check_for_memcached, clear_servers, memcached_TESTS },
+ {"drizzled", check_for_drizzle, clear_servers, drizzled_tests},
+ {"cmdline", 0, 0, cmdline_tests},
+ {"application", 0, 0, application_tests},
+ {"http", check_for_curl, 0, http_tests},
+ {"http", check_for_curl, 0, http_tests},
+ {"get_free_port()", 0, 0, get_free_port_TESTS },
+ {"fatal", disable_fatal_exception, enable_fatal_exception, fatal_message_TESTS },
+ {"number_of_cpus()", 0, 0, number_of_cpus_TESTS },
+ {"create_tmpfile()", 0, 0, create_tmpfile_TESTS },
+ {"dns", check_for_VALGRIND, 0, dns_TESTS },
+ {"libtest::Timer", 0, 0, timer_TESTS },
+ {0, 0, 0, 0}
+};
+
+static void *world_create(server_startup_st& servers, test_return_t&)
+{
+ return &servers;
+}
+
+void get_world(libtest::Framework *world)
+{
+ world->collections(collection);
+ world->create(world_create);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+static inline bool valgrind_is_caller(void)
+{
+ if (getenv("LOG_COMPILER") && strstr(getenv("LOG_COMPILER"), "valgrind"))
+ {
+ if (strstr(getenv("LOG_COMPILER"), "--tool") == NULL)
+ {
+ return true;
+ }
+
+ if (strstr(getenv("LOG_COMPILER"), "--tool=memcheck"))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+#include <libtest/common.h>
+
+/* Use this for string generation */
+static const char ALPHANUMERICS[]=
+ "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
+
+#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
+
+static size_t get_alpha_num(void)
+{
+ return (size_t)random() % ALPHANUMERICS_SIZE;
+}
+
+namespace libtest {
+
+int random_alpha_num(void)
+{
+ return ALPHANUMERICS[get_alpha_num()];
+}
+
+static std::string printer(const char *str, size_t length)
+{
+ std::ostringstream buf;
+ for (size_t x= 0; x < length; x++)
+ {
+ if (isprint(str[x]))
+ {
+ buf << str[x];
+ }
+ else
+ {
+ buf << "(" << int(str[x]) << ")";
+ }
+ }
+
+ return buf.str();
+}
+
+namespace vchar {
+
+int compare(libtest::vchar_t& arg, const char *str, size_t length)
+{
+ if (arg.size() == length and (memcmp(&arg[0], str, length) == 0))
+ {
+ return 0;
+ }
+ else if (arg.size() > length)
+ {
+ return 1;
+ }
+
+ return -1;
+}
+
+void make(libtest::vchar_t& arg)
+{
+ size_t length= rand() % 1024;
+ make(arg, length);
+}
+
+void make(libtest::vchar_t& arg, size_t length)
+{
+ arg.reserve(length);
+ for (uint32_t x= 0; x < length; ++x)
+ {
+ arg.push_back(ALPHANUMERICS[get_alpha_num()]);
+ }
+}
+
+void chomp(libtest::vchar_t& arg)
+{
+ while(arg.size())
+ {
+ if (arg.back() == 0)
+ {
+ arg.pop_back();
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+void append(libtest::vchar_ptr_t& arg, const char* ptr)
+{
+ if (ptr)
+ {
+ char* new_ptr= strdup(ptr);
+ if (new_ptr == NULL)
+ {
+ FATAL("UNABLE to allocate %s(%p)", ptr, ptr);
+ }
+
+ arg.push_back(new_ptr);
+ }
+}
+
+void append(libtest::vchar_t& arg, const char* ptr)
+{
+ if (ptr)
+ {
+ size_t length= strlen(ptr);
+ ASSERT_TRUE(length);
+ arg.reserve(length);
+ do
+ {
+ arg.push_back(*ptr);
+ ++ptr;
+ } while (*ptr);
+
+ arg.push_back(0);
+ }
+}
+
+} // namespace vchar
+
+void make_vector(libtest::vchar_t& arg, const char *str, size_t length)
+{
+ arg.resize(length);
+ memcpy(&arg[0], str, length);
+}
+
+std::ostream& operator<<(std::ostream& output, const libtest::vchar_t& arg)
+{
+ std::string tmp= libtest::printer(arg.data(), arg.size());
+ output << tmp << "[" << arg.size() << "]";
+
+ return output;
+}
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <cstring>
+#include <iostream>
+#include <ostream>
+#include <sstream>
+#include <vector>
+
+namespace libtest {
+
+int random_alpha_num(void);
+
+typedef std::vector<char*> vchar_ptr_t;
+typedef std::vector<char> vchar_t;
+
+void make_vector(libtest::vchar_t& arg, const char *str, size_t length);
+
+namespace vchar {
+
+int compare(libtest::vchar_t& arg, const char *str, size_t length);
+void chomp(libtest::vchar_t& arg);
+void make(libtest::vchar_t& arg);
+void make(libtest::vchar_t& arg, size_t length);
+void append(libtest::vchar_ptr_t& arg, const char*);
+void append(libtest::vchar_t& arg, const char*);
+
+} // namespace vchar
+
+#define vchar_param(__arg) (&__arg[0]), (__arg.size())
+#define vchar_printf(__arg) int(__arg.size()), (&__arg[0])
+
+std::ostream& operator<<(std::ostream& output, const libtest::vchar_t& arg);
+
+} // namespace libtest
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#define LIBTEST_VERSION @LIBTEST_VERSION@
+#define LIBTEST_VERSION_STRING "@LIBTEST_VERSION@"
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#if defined(BUILDING_LIBTEST)
+# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
+# define LIBTEST_API __attribute__ ((visibility("default")))
+# define LIBTEST_LOCAL __attribute__ ((visibility("default")))
+# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+# define LIBTEST_API __global
+# define LIBTEST_LOCAL __global
+# elif defined(_MSC_VER)
+# define LIBTEST_API extern __declspec(dllexport)
+# define LIBTEST_LOCAL extern __declspec(dllexport)
+# else
+# define LIBTEST_API
+# define LIBTEST_LOCAL
+# endif
+#else
+# if defined(BUILDING_LIBTEST)
+# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
+# define LIBTEST_API __attribute__ ((visibility("default")))
+# define LIBTEST_LOCAL __attribute__ ((visibility("hidden")))
+# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+# define LIBTEST_API __global
+# define LIBTEST_LOCAL __hidden
+# elif defined(_MSC_VER)
+# define LIBTEST_API extern __declspec(dllexport)
+# define LIBTEST_LOCAL
+# else
+# define LIBTEST_API
+# define LIBTEST_LOCAL
+# endif /* defined(HAVE_VISIBILITY) */
+# else /* defined(BUILDING_LIBTEST) */
+# if defined(_MSC_VER)
+# define LIBTEST_API extern __declspec(dllimport)
+# define LIBTEST_LOCAL
+# else
+# define LIBTEST_API
+# define LIBTEST_LOCAL
+# endif /* defined(_MSC_VER) */
+# endif /* defined(BUILDING_LIBTEST) */
+#endif /* defined(BUILDING_LIBTESTINTERNAL) */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libtest/yatlcon.h"
+
+#include <cstdlib>
+#include <fcntl.h>
+#include <getopt.h>
+#include <iostream>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libtest/wait.h>
+
+static void version_command(const char *command_name, int major_version, int minor_version)
+{
+ std::cout << command_name << " " << major_version << "." << minor_version << std::endl;
+}
+
+static void help_command(const char *command_name,
+ int major_version, int minor_version,
+ const struct option *long_options)
+{
+ std::cout << command_name << " " << major_version << "." << minor_version << std::endl;
+ std::cout << "Current options. A '=' means the option takes a value." << std::endl << std::endl;
+
+ for (uint32_t x= 0; long_options[x].name; x++)
+ {
+ std::cout << "\t --" << long_options[x].name << char(long_options[x].has_arg ? '=' : ' ') << std::endl;
+ }
+
+ std::cout << std::endl;
+}
+
+static void close_stdio(void)
+{
+ int fd;
+ if ((fd = open("/dev/null", O_RDWR, 0)) < 0)
+ {
+ return;
+ }
+ else
+ {
+ if (dup2(fd, STDIN_FILENO) < 0)
+ {
+ return;
+ }
+
+ if (dup2(fd, STDOUT_FILENO) < 0)
+ {
+ return;
+ }
+
+ if (dup2(fd, STDERR_FILENO) < 0)
+ {
+ return;
+ }
+
+ if (fd > STDERR_FILENO)
+ {
+ close(fd);
+ }
+ }
+}
+
+enum {
+ OPT_HELP,
+ OPT_QUIET,
+ OPT_VERSION
+};
+
+static void options_parse(int argc, char *argv[])
+{
+ static struct option long_options[]=
+ {
+ { "version", no_argument, NULL, OPT_VERSION},
+ { "help", no_argument, NULL, OPT_HELP},
+ { "quiet", no_argument, NULL, OPT_QUIET},
+ {0, 0, 0, 0},
+ };
+
+ bool opt_version= false;
+ bool opt_help= false;
+ bool opt_quiet= false;
+ int option_index= 0;
+
+ while (1)
+ {
+ int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
+ if (option_rv == -1)
+ {
+ break;
+ }
+
+ switch (option_rv)
+ {
+ case OPT_HELP: /* --help or -h */
+ opt_help= true;
+ break;
+
+ case OPT_VERSION: /* --version or -v */
+ opt_version= true;
+ break;
+
+ case OPT_QUIET:
+ opt_quiet= true;
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(EXIT_FAILURE);
+
+ default:
+ help_command(argv[0], 1, 0, long_options);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (opt_quiet)
+ {
+ close_stdio();
+ }
+
+ if (opt_version)
+ {
+ version_command(argv[0], 1, 0);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_help)
+ {
+ help_command(argv[0], 1, 0, long_options);
+ exit(EXIT_SUCCESS);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc == 1)
+ {
+ return EXIT_FAILURE;
+ }
+
+ options_parse(argc, argv);
+
+ int ret= EXIT_FAILURE;
+ while (optind < argc)
+ {
+ libtest::Wait wait(argv[optind++]);
+
+ if (wait.successful() == false)
+ {
+ return EXIT_FAILURE;
+ }
+
+ ret= EXIT_SUCCESS;
+ }
+
+ return ret;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <string>
+#include <signal.h>
+
+#include <libtest/dream.h>
+
+namespace libtest {
+
+class Wait
+{
+public:
+
+ Wait(const std::string &filename, uint32_t timeout= 6) :
+ _successful(false)
+ {
+ uint32_t waited;
+ uint32_t this_wait;
+ uint32_t retry;
+
+ if (filename.empty())
+ {
+ _successful= false;
+ return;
+ }
+
+ for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
+ {
+ if (access(filename.c_str(), R_OK) == 0)
+ {
+ _successful= true;
+ break;
+ }
+ else if (waited >= timeout)
+ {
+ break;
+ }
+
+ this_wait= retry * retry / 3 + 1;
+ libtest::dream(0, this_wait * 10000000);
+ }
+ }
+
+ Wait(const pid_t &_pid_arg, uint32_t timeout= 6) :
+ _successful(false)
+ {
+ uint32_t waited;
+ uint32_t this_wait;
+ uint32_t retry;
+
+ for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
+ {
+ if (kill(_pid_arg, 0) == 0)
+ {
+ _successful= true;
+ break;
+ }
+ else if (waited >= timeout)
+ {
+ break;
+ }
+
+ this_wait= retry * retry / 3 + 1;
+ libtest::dream(0, this_wait * 10000000);
+ }
+ }
+
+ bool successful() const
+ {
+ return _successful;
+ }
+
+private:
+ bool _successful;
+};
+
+} // namespace libtest
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifndef YATL_FULL
+# define YATL_FULL 1
+#endif
+
+#include <libtest/test.hpp>
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential YATL (i.e. libtest) library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#pragma once
+
+#include "@AUTOHEADER_FILE@"
+
+#ifndef LIBTEST_TEMP
+# define LIBTEST_TEMP "/tmp"
+#endif
+
+#define HAVE_LIBMEMCACHED 1
--- /dev/null
+#pragma once
+
+#cmakedefine01 LIBMEMCACHED_WITH_SASL_SUPPORT
+
+#define LIBMEMCACHED_WITH_SASL_PWDB "@LIBMEMCACHED_WITH_SASL_PWDB@"
+#define LIBMEMCACHED_WITH_SASL_CONF "@LIBMEMCACHED_WITH_SASL_CONF@"
+
+#cmakedefine HAVE_C_STDATOMIC 1
+#cmakedefine HAVE_CXX_STDATOMIC 1
+
+#cmakedefine HAVE_ARPA_INET_H 1
+#cmakedefine HAVE_DLFCN_H 1
+#cmakedefine HAVE_DTRACE 1
+#cmakedefine HAVE_ERRNO_H 1
+#cmakedefine HAVE_EXECINFO_H 1
+#cmakedefine HAVE_FCNTL 1
+#cmakedefine HAVE_FCNTL_H 1
+#cmakedefine HAVE_FNV64_HASH 1
+#cmakedefine HAVE_GETLINE
+#cmakedefine HAVE_HSIEH_HASH 1
+#cmakedefine HAVE_HTONLL 1
+#cmakedefine HAVE_IN_PORT_T 1
+#cmakedefine HAVE_IO_H 1
+#cmakedefine HAVE_LIBEVENT 1
+#cmakedefine HAVE_LIBSASL 1
+#cmakedefine HAVE_LIBUUID 1
+#cmakedefine HAVE_LIMITS_H 1
+#cmakedefine HAVE_MSG_DONTWAIT 1
+#cmakedefine HAVE_MSG_MORE 1
+#cmakedefine HAVE_MSG_NOSIGNAL 1
+#cmakedefine HAVE_MURMUR_HASH 1
+#cmakedefine HAVE_NETDB_H 1
+#cmakedefine HAVE_POLL_H 1
+#cmakedefine HAVE_RCVTIMEO 1
+#cmakedefine HAVE_SASL_SASL_H 1
+#cmakedefine HAVE_SHARED_ENABLED 1
+#cmakedefine HAVE_SNDTIMEO 1
+#cmakedefine HAVE_STDDEF_H 1
+#cmakedefine HAVE_STDLIB_H 1
+#cmakedefine HAVE_STRERROR 1
+#cmakedefine HAVE_STRERROR_R 1
+#cmakedefine HAVE_STRINGS_H 1
+#cmakedefine HAVE_SYS_SOCKET_H 1
+#cmakedefine HAVE_SYS_TIME_H 1
+#cmakedefine HAVE_SYS_TYPES_H 1
+#cmakedefine HAVE_SYS_WAIT_H 1
+#cmakedefine HAVE_SYS_UN_H 1
+#cmakedefine HAVE_TIME_H 1
+#cmakedefine HAVE_UMEM_H 1
+#cmakedefine HAVE_UNISTD_H 1
+#cmakedefine HAVE_VISIBILITY 1
+#cmakedefine HAVE_WINSOCK2_H 1
+#cmakedefine HAVE_WS2TCPIP_H 1
+
+#cmakedefine HAVE_ABI____CXA_DEMANGLE 1
+#cmakedefine HAVE_GCC_ABI_DEMANGLE 1
+
+#cmakedefine HAVE_CINTTYPES 1
+#cmakedefine HAVE_CSTDINT 1
+#if defined(__cplusplus)
+# if defined HAVE_CINTTYPES
+# include <cinttypes>
+# elif defined HAVE_CSTDINT
+# include <cstdint>
+# endif
+#else
+# include <inttypes.h>
+#endif
+
+#define HAVE_LIBMEMCACHED 1
--- /dev/null
+/* $Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $ */
+/* $NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $ */
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2010
+ * Stewart Smith
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <mem_config.h>
+
+#if defined __SUNPRO_C || defined __DECC || defined __HP_cc
+# pragma ident "@(#)$Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $"
+# pragma ident "$NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $"
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/select.h>
+
+#include <util/daemon.hpp>
+
+#include <iostream>
+
+namespace datadifferential {
+namespace util {
+
+pid_t parent_pid;
+
+extern "C"
+{
+
+static void sigusr1_handler(int sig)
+{
+ if (sig == SIGUSR1)
+ {
+ _exit(EXIT_SUCCESS);
+ }
+}
+
+}
+
+bool daemon_is_ready(bool close_io)
+{
+ if (kill(parent_pid, SIGUSR1) == -1)
+ {
+ perror("kill");
+ return false;
+ }
+
+ if (close_io == false)
+ {
+ return true;;
+ }
+
+ int fd;
+ if ((fd = open("/dev/null", O_RDWR, 0)) < 0)
+ {
+ perror("open");
+ return false;
+ }
+ else
+ {
+ if (dup2(fd, STDIN_FILENO) < 0)
+ {
+ perror("dup2 stdin");
+ return false;
+ }
+
+ if (dup2(fd, STDOUT_FILENO) < 0)
+ {
+ perror("dup2 stdout");
+ return false;
+ }
+
+ if (dup2(fd, STDERR_FILENO) < 0)
+ {
+ perror("dup2 stderr");
+ return false;
+ }
+
+ if (fd > STDERR_FILENO)
+ {
+ if (close(fd) < 0)
+ {
+ perror("close");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+bool daemonize(bool is_chdir, bool wait_sigusr1)
+{
+ struct sigaction new_action;
+
+ new_action.sa_handler= sigusr1_handler;
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags= 0;
+ sigaction(SIGUSR1, &new_action, NULL);
+
+ parent_pid= getpid();
+
+ pid_t child= fork();
+
+ switch (child)
+ {
+ case -1:
+ return false;
+
+ case 0:
+ break;
+
+ default:
+ if (wait_sigusr1)
+ {
+ /* parent */
+ int exit_code= EXIT_FAILURE;
+ int status;
+ while (waitpid(child, &status, 0) != child)
+ { }
+
+ if (WIFEXITED(status))
+ {
+ exit_code= WEXITSTATUS(status);
+ }
+ if (WIFSIGNALED(status))
+ {
+ exit_code= EXIT_FAILURE;
+ }
+ _exit(exit_code);
+ }
+ else
+ {
+ _exit(EXIT_SUCCESS);
+ }
+ }
+
+ /* child */
+ if (setsid() == -1)
+ {
+ perror("setsid");
+ return false;
+ }
+
+ if (is_chdir)
+ {
+ if (chdir("/") < 0)
+ {
+ perror("chdir");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* $Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $ */
+/* $NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $ */
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2010
+ * Stewart Smith
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace datadifferential {
+namespace util {
+
+bool daemon_is_ready(bool close_io);
+bool daemonize(bool is_chdir= true, bool wait_sigusr1= true);
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * DataDifferential Utility Library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include "mem_config.h"
+
+#include "util/instance.hpp"
+
+#include <cstdio>
+#include <iostream>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <sstream>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef INVALID_SOCKET
+# define INVALID_SOCKET -1
+#endif
+
+#ifndef SOCKET_ERROR
+# define SOCKET_ERROR -1
+#endif
+
+#ifndef get_socket_errno
+# define get_socket_errno() errno
+#endif
+
+#ifndef closesocket
+# define closesocket(a) close(a)
+#endif
+
+
+namespace datadifferential {
+namespace util {
+
+Instance::Instance(const std::string& hostname_arg, const std::string& service_arg) :
+ _host(hostname_arg),
+ _service(service_arg),
+ _sockfd(INVALID_SOCKET),
+ state(NOT_WRITING),
+ _addrinfo(0),
+ _addrinfo_next(0),
+ _finish_fn(NULL),
+ _operations()
+ {
+ }
+
+Instance::Instance(const std::string& hostname_arg, const in_port_t port_arg) :
+ _host(hostname_arg),
+ _sockfd(INVALID_SOCKET),
+ state(NOT_WRITING),
+ _addrinfo(0),
+ _addrinfo_next(0),
+ _finish_fn(NULL),
+ _operations()
+ {
+ char tmp[BUFSIZ];
+ snprintf(tmp, sizeof(tmp), "%u", static_cast<unsigned int>(port_arg));
+ _service= tmp;
+ }
+
+Instance::~Instance()
+{
+ close_socket();
+ free_addrinfo();
+ for (Operation::vector::iterator iter= _operations.begin(); iter != _operations.end(); ++iter)
+ {
+ delete *iter;
+ }
+ _operations.clear();
+
+ delete _finish_fn;
+}
+
+bool Instance::run()
+{
+ while (not _operations.empty())
+ {
+ Operation::vector::value_type operation= _operations.back();
+
+ switch (state)
+ {
+ case NOT_WRITING:
+ {
+ free_addrinfo();
+
+ struct addrinfo ai;
+ memset(&ai, 0, sizeof(struct addrinfo));
+ ai.ai_socktype= SOCK_STREAM;
+ ai.ai_protocol= IPPROTO_TCP;
+
+ int ret= getaddrinfo(_host.c_str(), _service.c_str(), &ai, &_addrinfo);
+ if (ret)
+ {
+ std::stringstream message;
+ message << "Failed to connect on " << _host.c_str() << ":" << _service.c_str() << " with " << gai_strerror(ret);
+ _last_error= message.str();
+ return false;
+ }
+ }
+ _addrinfo_next= _addrinfo;
+ state= CONNECT;
+ break;
+
+ case NEXT_CONNECT_ADDRINFO:
+ if (_addrinfo_next->ai_next == NULL)
+ {
+ std::stringstream message;
+ message << "Error connecting to " << _host.c_str() << "." << std::endl;
+ _last_error= message.str();
+ return false;
+ }
+ _addrinfo_next= _addrinfo_next->ai_next;
+ /* fall through */
+
+ case CONNECT:
+ close_socket();
+
+ _sockfd= socket(_addrinfo_next->ai_family,
+ _addrinfo_next->ai_socktype,
+ _addrinfo_next->ai_protocol);
+ if (_sockfd == INVALID_SOCKET)
+ {
+ perror("socket");
+ continue;
+ }
+
+ if (connect(_sockfd, _addrinfo_next->ai_addr, _addrinfo_next->ai_addrlen) < 0)
+ {
+ switch(errno)
+ {
+ case EAGAIN:
+ case EINTR:
+ state= CONNECT;
+ break;
+
+ case EINPROGRESS:
+ state= CONNECTING;
+ break;
+
+ case ECONNREFUSED:
+ case ENETUNREACH:
+ case ETIMEDOUT:
+ default:
+ state= NEXT_CONNECT_ADDRINFO;
+ break;
+ }
+ }
+ else
+ {
+ state= CONNECTING;
+ }
+ break;
+
+ case CONNECTING:
+ // Add logic for poll() for nonblocking.
+ state= CONNECTED;
+ break;
+
+ case CONNECTED:
+ case WRITING:
+ {
+ size_t packet_length= operation->size();
+ const char *packet= operation->ptr();
+
+ while(packet_length)
+ {
+ ssize_t write_size= send(_sockfd, packet, packet_length, 0);
+
+ if (write_size < 0)
+ {
+ switch(errno)
+ {
+ default:
+ std::cerr << "Failed dureng send(" << strerror(errno) << ")" << std::endl;
+ break;
+ }
+ }
+
+ packet_length-= static_cast<size_t>(write_size);
+ packet+= static_cast<size_t>(write_size);
+ }
+ }
+ state= READING;
+ break;
+
+ case READING:
+ if (operation->has_response())
+ {
+ ssize_t read_length;
+
+ do
+ {
+ char buffer[BUFSIZ];
+ read_length= ::recv(_sockfd, buffer, sizeof(buffer), 0);
+
+ if (read_length < 0)
+ {
+ switch(errno)
+ {
+ default:
+ _last_error.clear();
+ _last_error+= "Error occured while reading data from ";
+ _last_error+= _host;
+ return false;
+ }
+ }
+ else if (read_length == 0)
+ {
+ _last_error.clear();
+ _last_error+= "Socket was shutdown while reading from ";
+ _last_error+= _host;
+
+ return false;
+ }
+
+ operation->push(buffer, static_cast<size_t>(read_length));
+
+ } while (more_to_read());
+ } // end has_response
+
+ state= FINISHED;
+ break;
+
+ case FINISHED:
+ std::string response;
+ bool success= operation->response(response);
+ if (_finish_fn)
+ {
+ if (not _finish_fn->call(success, response))
+ {
+ // Error was sent from _finish_fn
+ return false;
+ }
+ }
+
+ if (operation->reconnect())
+ {
+ }
+ _operations.pop_back();
+ delete operation;
+
+ state= CONNECTED;
+ break;
+ } // end switch
+ }
+
+ return true;
+} // end run()
+
+bool Instance::more_to_read() const
+{
+ struct pollfd fds;
+ fds.fd= _sockfd;
+ fds.events = POLLIN;
+
+ if (poll(&fds, 1, 5) < 1) // Default timeout is 5
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void Instance::close_socket()
+{
+ if (_sockfd == INVALID_SOCKET)
+ {
+ return;
+ }
+
+ /* in case of death shutdown to avoid blocking at close() */
+ if (shutdown(_sockfd, SHUT_RDWR) == SOCKET_ERROR && get_socket_errno() != ENOTCONN)
+ {
+ perror("shutdown");
+ }
+ else if (closesocket(_sockfd) == SOCKET_ERROR)
+ {
+ perror("close");
+ }
+
+ _sockfd= INVALID_SOCKET;
+}
+
+void Instance::free_addrinfo()
+{
+ if (_addrinfo == NULL)
+ {
+ return;
+ }
+
+ freeaddrinfo(_addrinfo);
+ _addrinfo= NULL;
+ _addrinfo_next= NULL;
+}
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * DataDifferential Utility Library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <cassert>
+#include <cerrno>
+#include <cstddef>
+#include <cstdio>
+#include <netinet/in.h>
+#include <string>
+#include <sys/socket.h>
+
+#include "util/operation.hpp"
+
+struct addrinfo;
+
+namespace datadifferential {
+namespace util {
+
+class Instance
+{
+private:
+ enum connection_state_t {
+ NOT_WRITING,
+ NEXT_CONNECT_ADDRINFO,
+ CONNECT,
+ CONNECTING,
+ CONNECTED,
+ WRITING,
+ READING,
+ FINISHED
+ };
+ std::string _last_error;
+
+public: // Callbacks
+ class Finish {
+
+ public:
+ virtual ~Finish() { }
+
+ virtual bool call(const bool, const std::string &)= 0;
+ };
+
+
+public:
+ Instance(const std::string& hostname_arg, const std::string& service_arg);
+
+ Instance(const std::string& hostname_arg, const in_port_t port_arg);
+
+ ~Instance();
+
+ bool run();
+
+ void set_finish(Finish *arg)
+ {
+ _finish_fn= arg;
+ }
+
+ void push(util::Operation *next)
+ {
+ _operations.push_back(next);
+ }
+
+private:
+ void close_socket();
+
+ void free_addrinfo();
+
+ bool more_to_read() const;
+
+ std::string _host;
+ std::string _service;
+ int _sockfd;
+ connection_state_t state;
+ struct addrinfo *_addrinfo;
+ struct addrinfo *_addrinfo_next;
+ Finish *_finish_fn;
+ Operation::vector _operations;
+};
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential Utility library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <cerrno>
+#include <cstdarg>
+#include <cstdio>
+#include <fcntl.h>
+#include <iostream>
+#include <string>
+#include <syslog.h>
+
+#define UTIL_MAX_ERROR_SIZE 2048
+
+namespace datadifferential {
+namespace util {
+
+/** Verbosity levels.
+ */
+enum verbose_t
+{
+ // Logging this will cause shutdown
+ VERBOSE_FATAL= LOG_EMERG, // syslog:LOG_EMERG
+
+ VERBOSE_ALERT= LOG_ALERT, // syslog:LOG_ALERT
+ VERBOSE_CRITICAL= LOG_CRIT, // syslog:LOG_CRIT
+
+ VERBOSE_ERROR= LOG_ERR, // syslog:LOG_ERR
+
+ VERBOSE_WARN= LOG_WARNING, // syslog:LOG_WARNING
+
+ VERBOSE_NOTICE= LOG_NOTICE, // syslog:LOG_NOTICE
+
+ VERBOSE_INFO= LOG_INFO, // syslog:LOG_INFO
+
+ VERBOSE_DEBUG= LOG_DEBUG // syslog:LOG_DEBUG
+};
+
+#ifndef __INTEL_COMPILER
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+
+struct log_info_st
+{
+ std::string name;
+ std::string filename;
+ int fd;
+ bool opt_syslog;
+ bool opt_file;
+ bool init_success;
+
+ log_info_st(const std::string& name_arg, const std::string &filename_arg, bool syslog_arg) :
+ name(name_arg),
+ filename(filename_arg),
+ fd(-1),
+ opt_syslog(syslog_arg),
+ opt_file(false),
+ init_success(false)
+ {
+ if (opt_syslog)
+ {
+ openlog(name.c_str(), LOG_PID | LOG_NDELAY, LOG_USER);
+ }
+
+ init();
+ }
+
+ void init()
+ {
+ if (filename.size())
+ {
+ if (filename.compare("stderr") == 0)
+ {
+ fd= STDERR_FILENO;
+ }
+ else
+ {
+ fd= open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ if (opt_syslog)
+ {
+ char buffer[1024];
+ char *getcwd_ret= getcwd(buffer, sizeof(buffer));
+ syslog(LOG_ERR, "Could not open log file \"%.*s\", from \"%s\", open failed with (%s)",
+ int(filename.size()), filename.c_str(),
+ getcwd_ret,
+ strerror(errno));
+ }
+ std::cerr << "Could not open log file for writing, switching to stderr." << std::endl;
+
+ fd= STDERR_FILENO;
+ }
+ }
+
+ opt_file= true;
+ }
+
+ init_success= true;
+ }
+
+ bool initialized() const
+ {
+ return init_success;
+ }
+
+ int file() const
+ {
+ return fd;
+ }
+
+ void write(verbose_t verbose, const char *format, ...)
+ {
+ if (opt_file or opt_syslog)
+ {
+ va_list args;
+ va_start(args, format);
+ char mesg[BUFSIZ];
+ int mesg_length= vsnprintf(mesg, sizeof(mesg), format, args);
+ va_end(args);
+
+ if (opt_file)
+ {
+ char buffer[UTIL_MAX_ERROR_SIZE];
+ int buffer_length= snprintf(buffer, sizeof(buffer), "%7s %.*s\n", verbose_name(verbose), mesg_length, mesg);
+ if (::write(file(), buffer, buffer_length) == -1)
+ {
+ std::cerr << "Could not write to log file." << std::endl;
+ syslog(LOG_EMERG, "gearmand could not open log file %s, got error %s", filename.c_str(), strerror(errno));
+ }
+
+ }
+
+ if (opt_syslog)
+ {
+ syslog(int(verbose), "%7s %.*s", verbose_name(verbose), mesg_length, mesg);
+ }
+ }
+ }
+
+ ~log_info_st()
+ {
+ if (fd != -1 and fd != STDERR_FILENO)
+ {
+ close(fd);
+ }
+
+ if (opt_syslog)
+ {
+ closelog();
+ }
+ }
+
+private:
+ const char *verbose_name(verbose_t verbose)
+ {
+ switch (verbose)
+ {
+ case VERBOSE_FATAL:
+ return "FATAL";
+
+ case VERBOSE_ALERT:
+ return "ALERT";
+
+ case VERBOSE_CRITICAL:
+ return "CRITICAL";
+
+ case VERBOSE_ERROR:
+ return "ERROR";
+
+ case VERBOSE_WARN:
+ return "WARNING";
+
+ case VERBOSE_NOTICE:
+ return "NOTICE";
+
+ case VERBOSE_INFO:
+ return "INFO";
+
+ case VERBOSE_DEBUG:
+ return "DEBUG";
+
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+ }
+};
+
+} // namespace util
+} // namespace datadifferential
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * DataDifferential Utility Library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "mem_config.h"
+
+#include "util/logfile.hpp"
+
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace datadifferential {
+namespace util {
+
+Logfile::Logfile(const std::string &arg) :
+ _filename(arg)
+{
+ time_t tmp= time(NULL);
+ _log_file << "shutdown: " << ctime(&tmp) << std::endl;
+}
+
+Logfile::~Logfile()
+{
+ if (not _filename.empty())
+ {
+ _log_file.close();
+ if (access(_filename.c_str(), F_OK) == -1)
+ { }
+ else if (unlink(_filename.c_str()) == -1)
+ { }
+ }
+}
+
+bool Logfile::open()
+{
+ if (_filename.empty())
+ {
+ _log_file.open("/dev/stderr");
+ return true;
+ }
+
+ _log_file.open(_filename.c_str());
+ if (not _log_file.good())
+ {
+ return false;
+ }
+
+ time_t tmp= time(NULL);
+ _log_file << "startup: " << ctime(&tmp) << std::endl;
+
+ return true;
+}
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * DataDifferential Utility Library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <string>
+#include <fstream>
+
+namespace datadifferential {
+namespace util {
+
+class Logfile
+{
+public:
+ Logfile(const std::string &arg);
+
+ ~Logfile();
+
+ std::ofstream &log()
+ {
+ return _log_file;
+ }
+
+ bool open();
+
+private:
+ const std::string _filename;
+ std::ofstream _log_file;
+};
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * DataDifferential Utility Library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <mem_config.h>
+
+#include "util/operation.hpp"
+#include <string>
+
+namespace datadifferential {
+namespace util {
+
+bool Operation::response(std::string &arg)
+{
+ if (_response.empty())
+ {
+ return false;
+ }
+
+ if (not memcmp("OK\r\n", &_response[0], 3))
+ { }
+ else if (not memcmp("OK ", &_response[0], 3))
+ {
+ arg.append(&_response[3], _response.size() -3);
+ }
+ else if (not memcmp("ERR ", &_response[0], 4))
+ {
+ arg.append(&_response[4], _response.size() -4);
+ return false;
+ }
+ else
+ {
+ arg.append(&_response[0], _response.size());
+ }
+
+ return true;
+}
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * DataDifferential Utility Library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+#include <cstring>
+#include <iosfwd>
+#include <vector>
+
+namespace datadifferential {
+namespace util {
+
+class Operation {
+ typedef std::vector<char> Packet;
+
+public:
+ typedef std::vector<Operation *> vector;
+
+ Operation(const char *command, size_t command_length, bool expect_response= true) :
+ _expect_response(expect_response),
+ packet(),
+ _response()
+ {
+ packet.resize(command_length);
+ memcpy(&packet[0], command, command_length);
+ }
+
+ ~Operation()
+ { }
+
+ size_t size() const
+ {
+ return packet.size();
+ }
+
+ const char* ptr() const
+ {
+ return &(packet)[0];
+ }
+
+ bool has_response() const
+ {
+ return _expect_response;
+ }
+
+ void push(const char *buffer, size_t buffer_size)
+ {
+ size_t response_size= _response.size();
+ _response.resize(response_size +buffer_size);
+ memcpy(&_response[0] +response_size, buffer, buffer_size);
+ }
+
+ // Return false on error
+ bool response(std::string &);
+
+ bool reconnect() const
+ {
+ return false;
+ }
+
+private:
+ bool _expect_response;
+ Packet packet;
+ Packet _response;
+};
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * DataDifferential Utility Library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "mem_config.h"
+
+#include "util/pidfile.hpp"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <fcntl.h>
+#include <iostream>
+#include <sstream>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+extern "C" {
+
+ char pid_file[1024 * 4]= { 0 };
+
+ static void remove_pidfile(void)
+ {
+ if (pid_file[0])
+ {
+ if (unlink(pid_file) == -1)
+ {
+ std::cerr << "Could not remove pidfile: " << pid_file << "(" << strerror(errno) << ")" << std::endl;
+ }
+
+ pid_file[0]= 0;
+ }
+ }
+
+}
+
+namespace datadifferential {
+namespace util {
+
+Pidfile::Pidfile(const std::string &arg) :
+ _last_errno(0),
+ _filename(arg)
+{
+}
+
+
+Pidfile::~Pidfile()
+{
+ if (not _filename.empty())
+ {
+ if (access(_filename.c_str(), F_OK) == -1)
+ {
+ std::stringstream error_stream;
+ error_stream << "Could not access the pid file: " << _filename << "(" << strerror(errno) << ")";
+ _error_message= error_stream.str();
+ }
+ else if (unlink(_filename.c_str()) == -1)
+ {
+ std::stringstream error_stream;
+ error_stream << "Could not remove the pid file: " << _filename << "(" << strerror(errno) << ")";
+ _error_message= error_stream.str();
+ }
+ }
+ pid_file[0]= 0;
+}
+
+bool Pidfile::create()
+{
+ if (_filename.empty())
+ {
+ return true;
+ }
+
+ if (access(_filename.c_str(), F_OK) == 0)
+ {
+ if (unlink(_filename.c_str()) == -1)
+ {
+ std::stringstream error_stream;
+ error_stream << "Unable to remove exisiting file:" << _filename << "(" << strerror(errno) << ")";
+ _error_message= error_stream.str();
+
+ return false;
+ }
+ }
+
+ int oflags= O_CREAT|O_WRONLY|O_TRUNC;
+#ifdef HAVE_O_CLOEXEC
+ oflags= oflags | O_CLOEXEC;
+#endif
+
+ int file;
+ if ((file = open(_filename.c_str(), oflags, S_IRWXU|S_IRGRP|S_IROTH)) < 0)
+ {
+ std::stringstream error_stream;
+ error_stream << "Could not open pid file for writing: " << _filename << "(" << strerror(errno) << ")";
+ _error_message= error_stream.str();
+
+ return false;
+ }
+
+ char buffer[BUFSIZ];
+ unsigned long temp= static_cast<unsigned long>(getpid());
+ int length= snprintf(buffer, sizeof(buffer), "%lu\n", temp);
+ if (write(file, buffer, length) != length)
+ {
+ std::stringstream error_stream;
+ error_stream << "Could not write pid to file: " << _filename << "(" << strerror(errno) << ")";
+ _error_message= error_stream.str();
+ close(file);
+
+ return false;
+ }
+
+ if (close(file) < 0)
+ {
+ _error_message+= "Could not close() file after writing pid to it: ";
+ _error_message+= _filename;
+ return false;
+ }
+ snprintf(pid_file, sizeof(pid_file), "%s", _filename.c_str());
+ atexit(remove_pidfile);
+
+ return true;
+}
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * DataDifferential Utility Library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <string>
+
+namespace datadifferential {
+namespace util {
+
+class Pidfile
+{
+public:
+ Pidfile(const std::string &arg);
+
+ ~Pidfile();
+
+ const std::string &error_message()
+ {
+ return _error_message;
+ }
+
+ bool create();
+
+private:
+ int _last_errno;
+ const std::string _filename;
+ std::string _error_message;
+};
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential Utility library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <mem_config.h>
+
+#include <cassert>
+#include <cerrno>
+#include <csignal>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+#include <util/signal.hpp>
+
+namespace datadifferential {
+namespace util {
+
+#define MAGIC_MEMORY 123569
+
+bool SignalThread::is_shutdown()
+{
+ bool ret;
+ pthread_mutex_lock(&shutdown_mutex);
+ ret= bool(__shutdown != SHUTDOWN_RUNNING);
+ pthread_mutex_unlock(&shutdown_mutex);
+
+ return ret;
+}
+
+void SignalThread::set_shutdown(shutdown_t arg)
+{
+ pthread_mutex_lock(&shutdown_mutex);
+ __shutdown= arg;
+ pthread_mutex_unlock(&shutdown_mutex);
+
+ if (arg == SHUTDOWN_GRACEFUL)
+ {
+ if (pthread_kill(thread, SIGUSR2) == 0)
+ {
+ void *retval;
+ pthread_join(thread, &retval);
+ }
+ }
+}
+
+shutdown_t SignalThread::get_shutdown()
+{
+ shutdown_t local;
+ pthread_mutex_lock(&shutdown_mutex);
+ local= __shutdown;
+ pthread_mutex_unlock(&shutdown_mutex);
+
+ return local;
+}
+
+void SignalThread::post()
+{
+ sem_post(&lock);
+}
+
+void SignalThread::test()
+{
+ assert(magic_memory == MAGIC_MEMORY);
+ assert(sigismember(&set, SIGABRT));
+ assert(sigismember(&set, SIGINT));
+ assert(sigismember(&set, SIGQUIT));
+ assert(sigismember(&set, SIGTERM));
+ assert(sigismember(&set, SIGUSR2));
+}
+
+void SignalThread::sighup(signal_callback_fn* arg)
+{
+ _sighup= arg;
+}
+
+void SignalThread::sighup()
+{
+ if (_sighup)
+ {
+ _sighup();
+ }
+}
+
+SignalThread::~SignalThread()
+{
+ if (not is_shutdown())
+ {
+ set_shutdown(SHUTDOWN_GRACEFUL);
+ }
+
+#if 0
+ if (pthread_equal(thread, pthread_self()) != 0 and (pthread_kill(thread, 0) == ESRCH) == true)
+ {
+ void *retval;
+ pthread_join(thread, &retval);
+ }
+#endif
+ sem_destroy(&lock);
+}
+
+extern "C" {
+
+static void *sig_thread(void *arg)
+{
+ SignalThread *context= (SignalThread*)arg;
+
+ context->test();
+ context->post();
+
+ while (context->get_shutdown() == SHUTDOWN_RUNNING)
+ {
+ int sig;
+
+ if (context->wait(sig) == -1)
+ {
+ std::cerr << "sigwait() returned errno:" << strerror(errno) << std::endl;
+ continue;
+ }
+
+ switch (sig)
+ {
+ case SIGUSR2:
+ break;
+
+ case SIGHUP:
+ context->sighup();
+ break;
+
+ case SIGABRT:
+ case SIGINT:
+ case SIGQUIT:
+ case SIGTERM:
+ if (context->is_shutdown() == false)
+ {
+ context->set_shutdown(SHUTDOWN_FORCED);
+ }
+
+ if (context->exit_on_signal())
+ {
+ exit(EXIT_SUCCESS);
+ }
+
+ break;
+
+ default:
+ std::cerr << "Signal handling thread got unexpected signal " << strsignal(sig) << std::endl;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+}
+
+SignalThread::SignalThread(bool exit_on_signal_arg) :
+ _exit_on_signal(exit_on_signal_arg),
+ magic_memory(MAGIC_MEMORY),
+ __shutdown(SHUTDOWN_RUNNING),
+ thread(pthread_self()),
+ _sighup(NULL)
+{
+ pthread_mutex_init(&shutdown_mutex, NULL);
+ sigemptyset(&set);
+
+ sigaddset(&set, SIGABRT);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGQUIT);
+ sigaddset(&set, SIGTERM);
+ sigaddset(&set, SIGUSR2);
+
+ sem_init(&lock, 0, 0);
+}
+
+
+bool SignalThread::setup()
+{
+ set_shutdown(SHUTDOWN_RUNNING);
+
+ int error;
+ if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
+ {
+ std::cerr << "pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")" << std::endl;
+ return false;
+ }
+
+ if ((error= pthread_create(&thread, NULL, &sig_thread, this)) != 0)
+ {
+ std::cerr << "pthread_create() died during pthread_create(" << strerror(error) << ")" << std::endl;
+ return false;
+ }
+
+ sem_wait(&lock);
+
+ return true;
+}
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Data Differential Utility library
+ *
+ * Copyright (C) 2012 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <pthread.h>
+#include <semaphore.h>
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (signal_callback_fn)();
+
+#ifdef __cplusplus
+}
+#endif
+
+namespace datadifferential {
+namespace util {
+
+enum shutdown_t {
+ SHUTDOWN_RUNNING,
+ SHUTDOWN_GRACEFUL,
+ SHUTDOWN_FORCED
+};
+
+class SignalThread {
+ bool _exit_on_signal;
+ sigset_t set;
+ sem_t lock;
+ uint64_t magic_memory;
+ volatile shutdown_t __shutdown;
+ pthread_mutex_t shutdown_mutex;
+
+public:
+
+ SignalThread(bool exit_on_signal_arg= false);
+
+ void test();
+ void post();
+ bool setup();
+
+ bool exit_on_signal()
+ {
+ return _exit_on_signal;
+ }
+
+ int wait(int& sig)
+ {
+ return sigwait(&set, &sig);
+ }
+
+ ~SignalThread();
+
+ void set_shutdown(shutdown_t arg);
+ bool is_shutdown();
+ shutdown_t get_shutdown();
+
+ void sighup();
+ void sighup(signal_callback_fn* arg);
+
+private:
+ pthread_t thread;
+ signal_callback_fn* _sighup;
+};
+
+} /* namespace util */
+} /* namespace datadifferential */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * DataDifferential Utility Library
+ *
+ * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/*
+ Simple defines
+*/
+
+#include <cstring>
+#include <cstddef>
+
+#pragma once
+
+#define util_literal_param(X) (X), (static_cast<size_t>((sizeof(X) - 1)))
+#define util_literal_param_size(X) static_cast<size_t>(sizeof(X) - 1)
+
+#define util_literal_compare_param(X) (static_cast<size_t>((sizeof(X) - 1))), (X)
+
+#define util_string_make_from_cstr(X) (X), ((X) ? strlen(X) : 0)
+
+#define util_string_make_from_array(__array) (__array), (strlen(__array))
+
+#define util_array_length(__array) sizeof(__array)/sizeof(&__array)
+
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2010 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: "Implementation" of the function we don't have on windows
+ * to avoid a bunch of ifdefs in the rest of the code
+ *
+ */
+#pragma once
+
+#include <inttypes.h>
+
+/*
+ * One of the Windows headers define interface as a macro, but that
+ * is causing problems with the member named "interface" in some of the
+ * structs.
+ */
+#undef interface
+
+#undef malloc
+#undef realloc
+
+
+/*
+ * WinSock use a separate range for error codes. Let's just map to the
+ * WinSock ones.
+ */
+#ifndef EADDRINUSE
+# define EADDRINUSE WSAEADDRINUSE
+#endif
+
+#ifndef EWOULDBLOCK
+# define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+
+#ifndef EINPROGRESS
+# define EINPROGRESS WSAEINPROGRESS
+#endif
+
+#ifndef EALREADY
+# define EALREADY WSAEALREADY
+#endif
+
+#ifndef EISCONN
+# define EISCONN WSAEISCONN
+#endif
+
+#ifndef ENOTCONN
+# define ENOTCONN WSAENOTCONN
+#endif
+
+#ifndef ENOBUFS
+# define ENOBUFS WSAENOBUFS
+#endif
+
+#ifndef SHUT_RDWR
+# define SHUT_RDWR SD_BOTH
+#endif
+
+/* EAI_SYSTEM isn't defined anywhere... just set it to... 11? */
+#ifndef EAI_SYSTEM
+# define EAI_SYSTEM 11
+#endif
+
+/* Best effort mapping of functions to alternative functions */
+#define index(a,b) strchr(a,b)
+#define rindex(a,b) strrchr(a,b)
+#define random() rand()
+#define srandom(a) while (false) {}
+#define kill(a, b) while (false) {}
+#define fork() (-1)
+#define waitpid(a,b,c) (-1)
+#define fnmatch(a,b,c) (-1)
+#define sleep(a) Sleep(a*1000)
add_executable(cycle cycle.cc)
target_link_libraries(cycle PRIVATE libtest Threads::Threads)
-target_include_directories(cycle PRIVATE ..)
add_test(cycle cycle)
add_executable(parser parser.cc)
target_link_libraries(parser PRIVATE libtest libmemcached)
-target_include_directories(parser PRIVATE ..)
add_test(parser parser)
add_executable(failure failure.cc)
add_executable(testhashkit hashkit_functions.cc)
target_link_libraries(testhashkit PRIVATE libtest libhashkit)
-target_include_directories(testhashkit PRIVATE ..)
add_test(testhashkit testhashkit)
add_executable(hash_plus hash_plus.cc)
target_link_libraries(hash_plus PRIVATE libtest libhashkit)
-target_include_directories(hash_plus PRIVATE ..)
add_test(testhashplus hash_plus)
foreach(CLIENT IN LISTS CLIENTS)
libmemcachedutil
libtest
)
- target_include_directories(test${CLIENT} PRIVATE ..)
add_test(test${CLIENT} test${CLIENT})
endif()
endforeach()
+++ /dev/null
-# vim:ft=automake
-# Copyright (C) 2012 Data Differential
-# All rights reserved.
-#
-# Use and distribution licensed under the BSD license. See
-# the COPYING file in the parent directory for full text.
-#
-# included from Top Level Makefile.am
-# All paths should be given relative to the root
-
-
-tests_memcapable_SOURCES= tests/memcapable.cc
-tests_memcapable_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memcapable_DEPENDENCIES= clients/memcapable
-tests_memcapable_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memcapable
-noinst_PROGRAMS+= tests/memcapable
-
-tests_memstat_SOURCES= tests/memstat.cc
-tests_memstat_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memstat_DEPENDENCIES= clients/memstat
-tests_memstat_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memstat
-noinst_PROGRAMS+= tests/memstat
-
-tests_memcp_SOURCES= tests/memcp.cc
-tests_memcp_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memcp_DEPENDENCIES= clients/memcp
-tests_memcp_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memcp
-noinst_PROGRAMS+= tests/memcp
-
-tests_memflush_SOURCES= tests/memflush.cc
-tests_memflush_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memflush_DEPENDENCIES= clients/memflush
-tests_memflush_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memflush
-noinst_PROGRAMS+= tests/memflush
-
-tests_memrm_SOURCES= tests/memrm.cc
-tests_memrm_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memrm_DEPENDENCIES= clients/memrm
-tests_memrm_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memrm
-noinst_PROGRAMS+= tests/memrm
-
-tests_memexist_SOURCES= tests/memexist.cc
-tests_memexist_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memexist_DEPENDENCIES= clients/memexist
-tests_memexist_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memexist
-noinst_PROGRAMS+= tests/memexist
-
-tests_memtouch_SOURCES= tests/memtouch.cc
-tests_memtouch_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memtouch_DEPENDENCIES= clients/memtouch
-tests_memtouch_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memtouch
-noinst_PROGRAMS+= tests/memtouch
-
-tests_memcat_SOURCES= tests/memcat.cc
-tests_memcat_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memcat_DEPENDENCIES= clients/memcat
-tests_memcat_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memcat
-noinst_PROGRAMS+= tests/memcat
-
-tests_memping_SOURCES= tests/memping.cc
-tests_memping_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memping_DEPENDENCIES= clients/memping
-tests_memping_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memping
-noinst_PROGRAMS+= tests/memping
-
-tests_memerror_SOURCES= tests/memerror.cc
-tests_memerror_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memerror_DEPENDENCIES= clients/memerror
-tests_memerror_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memerror
-noinst_PROGRAMS+= tests/memerror
-
-tests_memslap_SOURCES= tests/memslap.cc
-tests_memslap_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memslap_DEPENDENCIES= clients/memslap
-tests_memslap_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memslap
-noinst_PROGRAMS+= tests/memslap
-
-test-memslap: tests/memslap
- @tests/memslap
-
-gdb-memslap: tests/memslap
- @$(GDB_COMMAND) tests/memslap
-
-tests_memdump_SOURCES= tests/memdump.cc
-tests_memdump_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
-EXTRA_tests_memdump_DEPENDENCIES= clients/memdump
-tests_memdump_LDADD= libtest/libtest.la $(TESTS_LDADDS)
-check_PROGRAMS+= tests/memdump
-noinst_PROGRAMS+= tests/memdump
-
-test-memcp: tests/memcp
- tests/memcp
-
-gdb-memcp: tests/memcp
- @$(GDB_COMMAND) tests/memcp
-
-test-memstat: tests/memstat
- tests/memstat
-
-test-memerror: tests/memerror
- tests/memerror
-
-test-memtouch: tests/memtouch
- tests/memtouch
-
-test-memping: tests/memping
- tests/memping
-
-valgrind-memerror: tests/memerror
- @$(VALGRIND_COMMAND) tests/memerror
-
-valgrind-memtouch: tests/memtouch
- @$(VALGRIND_COMMAND) tests/memtouch
-
-test-memdump: tests/memdump
- tests/memdump
-
-gdb-memdump: tests/memdump
- @$(GDB_COMMAND) tests/memdump
-
-valgrind-memdump: tests/memdump
- @$(VALGRIND_COMMAND) tests/memdump
add_executable(internals internals.cc string.cc)
target_link_libraries(internals PRIVATE libtest libmemcachedinternal Threads::Threads)
-target_include_directories(internals PRIVATE ../..)
add_test(internals internals)
add_executable(testsasl
libtest
Threads::Threads
)
-target_include_directories(testsasl PRIVATE ../..)
add_test(testsasl testsasl)
add_executable(atomsmasher atomsmasher.cc)
libmemcachedutil
libtest
)
- target_include_directories(${TEST} PRIVATE ../..)
add_test(${TEST} ${TEST})
endforeach()
Threads::Threads
${LIBUUID_LIBRARIES}
)
- target_include_directories(${TEST} PRIVATE ../.. ${LIBUUID_INCLUDEDIR})
+ target_include_directories(${TEST} PRIVATE ${LIBUUID_INCLUDEDIR})
add_test(${TEST} ${TEST})
endforeach()
#include <sys/stat.h>
#include <unistd.h>
#include <ctime>
-#include <clients/generator.h>
-#include <clients/execute.h>
+#include <bin/generator.h>
+#include <bin/execute.h>
#include <libtest/server.h>
#include <tests/libmemcached-1.0/fetch_all_results.h>
#include "tests/libmemcached-1.0/callback_counter.h"
-#include "clients/generator.h"
-#include "clients/execute.h"
+#include "bin/generator.h"
+#include "bin/execute.h"
#include "tests/memc.hpp"
#include <libtest/server.h>
-#include "clients/generator.h"
+#include "bin/generator.h"
#define SMALL_STRING_LEN 1024
void get_world(libtest::Framework* world)
{
- executable= "./clients/memcapable";
+ executable= "./src/bin/memcapable";
world->collections(collection);
world->create(world_create);
}
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable("clients/memcat");
+static std::string executable("src/bin/memcat");
static test_return_t help_test(void *)
{
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable("./clients/memcp");
+static std::string executable("./src/bin/memcp");
static test_return_t help_test(void *)
{
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable("./clients/memdump");
+static std::string executable("./src/bin/memdump");
static test_return_t help_test(void *)
{
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable("./clients/memerror");
+static std::string executable("./src/bin/memerror");
static test_return_t help_TEST(void *)
{
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable("./clients/memexist");
+static std::string executable("./src/bin/memexist");
static test_return_t help_test(void *)
{
void get_world(libtest::Framework* world)
{
- executable= "./clients/memflush";
+ executable= "./src/bin/memflush";
world->collections(collection);
world->create(world_create);
}
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable("clients/memping");
+static std::string executable("src/bin/memping");
static test_return_t help_test(void *)
{
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable("./clients/memrm");
+static std::string executable("./src/bin/memrm");
static test_return_t quiet_test(void *)
{
void get_world(libtest::Framework* world)
{
- executable= "./clients/memslap";
+ executable= "./src/bin/memslap";
world->collections(collection);
world->create(world_create);
}
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
-static std::string executable("./clients/memstat");
+static std::string executable("./src/bin/memstat");
static test_return_t help_test(void *)
{
void get_world(libtest::Framework* world)
{
- executable= "./clients/memtouch";
+ executable= "./src/bin/memtouch";
world->collections(collection);
world->create(world_create);
}
+++ /dev/null
-/* $Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $ */
-/* $NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $ */
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- * Copyright (c) 2010
- * Stewart Smith
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <mem_config.h>
-
-#if defined __SUNPRO_C || defined __DECC || defined __HP_cc
-# pragma ident "@(#)$Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $"
-# pragma ident "$NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $"
-#endif
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <unistd.h>
-#include <sys/select.h>
-
-#include <util/daemon.hpp>
-
-#include <iostream>
-
-namespace datadifferential {
-namespace util {
-
-pid_t parent_pid;
-
-extern "C"
-{
-
-static void sigusr1_handler(int sig)
-{
- if (sig == SIGUSR1)
- {
- _exit(EXIT_SUCCESS);
- }
-}
-
-}
-
-bool daemon_is_ready(bool close_io)
-{
- if (kill(parent_pid, SIGUSR1) == -1)
- {
- perror("kill");
- return false;
- }
-
- if (close_io == false)
- {
- return true;;
- }
-
- int fd;
- if ((fd = open("/dev/null", O_RDWR, 0)) < 0)
- {
- perror("open");
- return false;
- }
- else
- {
- if (dup2(fd, STDIN_FILENO) < 0)
- {
- perror("dup2 stdin");
- return false;
- }
-
- if (dup2(fd, STDOUT_FILENO) < 0)
- {
- perror("dup2 stdout");
- return false;
- }
-
- if (dup2(fd, STDERR_FILENO) < 0)
- {
- perror("dup2 stderr");
- return false;
- }
-
- if (fd > STDERR_FILENO)
- {
- if (close(fd) < 0)
- {
- perror("close");
- return false;
- }
- }
- }
-
- return true;
-}
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
-
-bool daemonize(bool is_chdir, bool wait_sigusr1)
-{
- struct sigaction new_action;
-
- new_action.sa_handler= sigusr1_handler;
- sigemptyset(&new_action.sa_mask);
- new_action.sa_flags= 0;
- sigaction(SIGUSR1, &new_action, NULL);
-
- parent_pid= getpid();
-
- pid_t child= fork();
-
- switch (child)
- {
- case -1:
- return false;
-
- case 0:
- break;
-
- default:
- if (wait_sigusr1)
- {
- /* parent */
- int exit_code= EXIT_FAILURE;
- int status;
- while (waitpid(child, &status, 0) != child)
- { }
-
- if (WIFEXITED(status))
- {
- exit_code= WEXITSTATUS(status);
- }
- if (WIFSIGNALED(status))
- {
- exit_code= EXIT_FAILURE;
- }
- _exit(exit_code);
- }
- else
- {
- _exit(EXIT_SUCCESS);
- }
- }
-
- /* child */
- if (setsid() == -1)
- {
- perror("setsid");
- return false;
- }
-
- if (is_chdir)
- {
- if (chdir("/") < 0)
- {
- perror("chdir");
- return false;
- }
- }
-
- return true;
-}
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* $Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $ */
-/* $NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $ */
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- * Copyright (c) 2010
- * Stewart Smith
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#pragma once
-
-namespace datadifferential {
-namespace util {
-
-bool daemon_is_ready(bool close_io);
-bool daemonize(bool is_chdir= true, bool wait_sigusr1= true);
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * DataDifferential Utility Library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include "mem_config.h"
-
-#include "util/instance.hpp"
-
-#include <cstdio>
-#include <iostream>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <poll.h>
-#include <sstream>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifndef INVALID_SOCKET
-# define INVALID_SOCKET -1
-#endif
-
-#ifndef SOCKET_ERROR
-# define SOCKET_ERROR -1
-#endif
-
-#ifndef get_socket_errno
-# define get_socket_errno() errno
-#endif
-
-#ifndef closesocket
-# define closesocket(a) close(a)
-#endif
-
-
-namespace datadifferential {
-namespace util {
-
-Instance::Instance(const std::string& hostname_arg, const std::string& service_arg) :
- _host(hostname_arg),
- _service(service_arg),
- _sockfd(INVALID_SOCKET),
- state(NOT_WRITING),
- _addrinfo(0),
- _addrinfo_next(0),
- _finish_fn(NULL),
- _operations()
- {
- }
-
-Instance::Instance(const std::string& hostname_arg, const in_port_t port_arg) :
- _host(hostname_arg),
- _sockfd(INVALID_SOCKET),
- state(NOT_WRITING),
- _addrinfo(0),
- _addrinfo_next(0),
- _finish_fn(NULL),
- _operations()
- {
- char tmp[BUFSIZ];
- snprintf(tmp, sizeof(tmp), "%u", static_cast<unsigned int>(port_arg));
- _service= tmp;
- }
-
-Instance::~Instance()
-{
- close_socket();
- free_addrinfo();
- for (Operation::vector::iterator iter= _operations.begin(); iter != _operations.end(); ++iter)
- {
- delete *iter;
- }
- _operations.clear();
-
- delete _finish_fn;
-}
-
-bool Instance::run()
-{
- while (not _operations.empty())
- {
- Operation::vector::value_type operation= _operations.back();
-
- switch (state)
- {
- case NOT_WRITING:
- {
- free_addrinfo();
-
- struct addrinfo ai;
- memset(&ai, 0, sizeof(struct addrinfo));
- ai.ai_socktype= SOCK_STREAM;
- ai.ai_protocol= IPPROTO_TCP;
-
- int ret= getaddrinfo(_host.c_str(), _service.c_str(), &ai, &_addrinfo);
- if (ret)
- {
- std::stringstream message;
- message << "Failed to connect on " << _host.c_str() << ":" << _service.c_str() << " with " << gai_strerror(ret);
- _last_error= message.str();
- return false;
- }
- }
- _addrinfo_next= _addrinfo;
- state= CONNECT;
- break;
-
- case NEXT_CONNECT_ADDRINFO:
- if (_addrinfo_next->ai_next == NULL)
- {
- std::stringstream message;
- message << "Error connecting to " << _host.c_str() << "." << std::endl;
- _last_error= message.str();
- return false;
- }
- _addrinfo_next= _addrinfo_next->ai_next;
- /* fall through */
-
- case CONNECT:
- close_socket();
-
- _sockfd= socket(_addrinfo_next->ai_family,
- _addrinfo_next->ai_socktype,
- _addrinfo_next->ai_protocol);
- if (_sockfd == INVALID_SOCKET)
- {
- perror("socket");
- continue;
- }
-
- if (connect(_sockfd, _addrinfo_next->ai_addr, _addrinfo_next->ai_addrlen) < 0)
- {
- switch(errno)
- {
- case EAGAIN:
- case EINTR:
- state= CONNECT;
- break;
-
- case EINPROGRESS:
- state= CONNECTING;
- break;
-
- case ECONNREFUSED:
- case ENETUNREACH:
- case ETIMEDOUT:
- default:
- state= NEXT_CONNECT_ADDRINFO;
- break;
- }
- }
- else
- {
- state= CONNECTING;
- }
- break;
-
- case CONNECTING:
- // Add logic for poll() for nonblocking.
- state= CONNECTED;
- break;
-
- case CONNECTED:
- case WRITING:
- {
- size_t packet_length= operation->size();
- const char *packet= operation->ptr();
-
- while(packet_length)
- {
- ssize_t write_size= send(_sockfd, packet, packet_length, 0);
-
- if (write_size < 0)
- {
- switch(errno)
- {
- default:
- std::cerr << "Failed dureng send(" << strerror(errno) << ")" << std::endl;
- break;
- }
- }
-
- packet_length-= static_cast<size_t>(write_size);
- packet+= static_cast<size_t>(write_size);
- }
- }
- state= READING;
- break;
-
- case READING:
- if (operation->has_response())
- {
- ssize_t read_length;
-
- do
- {
- char buffer[BUFSIZ];
- read_length= ::recv(_sockfd, buffer, sizeof(buffer), 0);
-
- if (read_length < 0)
- {
- switch(errno)
- {
- default:
- _last_error.clear();
- _last_error+= "Error occured while reading data from ";
- _last_error+= _host;
- return false;
- }
- }
- else if (read_length == 0)
- {
- _last_error.clear();
- _last_error+= "Socket was shutdown while reading from ";
- _last_error+= _host;
-
- return false;
- }
-
- operation->push(buffer, static_cast<size_t>(read_length));
-
- } while (more_to_read());
- } // end has_response
-
- state= FINISHED;
- break;
-
- case FINISHED:
- std::string response;
- bool success= operation->response(response);
- if (_finish_fn)
- {
- if (not _finish_fn->call(success, response))
- {
- // Error was sent from _finish_fn
- return false;
- }
- }
-
- if (operation->reconnect())
- {
- }
- _operations.pop_back();
- delete operation;
-
- state= CONNECTED;
- break;
- } // end switch
- }
-
- return true;
-} // end run()
-
-bool Instance::more_to_read() const
-{
- struct pollfd fds;
- fds.fd= _sockfd;
- fds.events = POLLIN;
-
- if (poll(&fds, 1, 5) < 1) // Default timeout is 5
- {
- return false;
- }
-
- return true;
-}
-
-void Instance::close_socket()
-{
- if (_sockfd == INVALID_SOCKET)
- {
- return;
- }
-
- /* in case of death shutdown to avoid blocking at close() */
- if (shutdown(_sockfd, SHUT_RDWR) == SOCKET_ERROR && get_socket_errno() != ENOTCONN)
- {
- perror("shutdown");
- }
- else if (closesocket(_sockfd) == SOCKET_ERROR)
- {
- perror("close");
- }
-
- _sockfd= INVALID_SOCKET;
-}
-
-void Instance::free_addrinfo()
-{
- if (_addrinfo == NULL)
- {
- return;
- }
-
- freeaddrinfo(_addrinfo);
- _addrinfo= NULL;
- _addrinfo_next= NULL;
-}
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * DataDifferential Utility Library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <cassert>
-#include <cerrno>
-#include <cstddef>
-#include <cstdio>
-#include <netinet/in.h>
-#include <string>
-#include <sys/socket.h>
-
-#include "util/operation.hpp"
-
-struct addrinfo;
-
-namespace datadifferential {
-namespace util {
-
-class Instance
-{
-private:
- enum connection_state_t {
- NOT_WRITING,
- NEXT_CONNECT_ADDRINFO,
- CONNECT,
- CONNECTING,
- CONNECTED,
- WRITING,
- READING,
- FINISHED
- };
- std::string _last_error;
-
-public: // Callbacks
- class Finish {
-
- public:
- virtual ~Finish() { }
-
- virtual bool call(const bool, const std::string &)= 0;
- };
-
-
-public:
- Instance(const std::string& hostname_arg, const std::string& service_arg);
-
- Instance(const std::string& hostname_arg, const in_port_t port_arg);
-
- ~Instance();
-
- bool run();
-
- void set_finish(Finish *arg)
- {
- _finish_fn= arg;
- }
-
- void push(util::Operation *next)
- {
- _operations.push_back(next);
- }
-
-private:
- void close_socket();
-
- void free_addrinfo();
-
- bool more_to_read() const;
-
- std::string _host;
- std::string _service;
- int _sockfd;
- connection_state_t state;
- struct addrinfo *_addrinfo;
- struct addrinfo *_addrinfo_next;
- Finish *_finish_fn;
- Operation::vector _operations;
-};
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential Utility library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <cerrno>
-#include <cstdarg>
-#include <cstdio>
-#include <fcntl.h>
-#include <iostream>
-#include <string>
-#include <syslog.h>
-
-#define UTIL_MAX_ERROR_SIZE 2048
-
-namespace datadifferential {
-namespace util {
-
-/** Verbosity levels.
- */
-enum verbose_t
-{
- // Logging this will cause shutdown
- VERBOSE_FATAL= LOG_EMERG, // syslog:LOG_EMERG
-
- VERBOSE_ALERT= LOG_ALERT, // syslog:LOG_ALERT
- VERBOSE_CRITICAL= LOG_CRIT, // syslog:LOG_CRIT
-
- VERBOSE_ERROR= LOG_ERR, // syslog:LOG_ERR
-
- VERBOSE_WARN= LOG_WARNING, // syslog:LOG_WARNING
-
- VERBOSE_NOTICE= LOG_NOTICE, // syslog:LOG_NOTICE
-
- VERBOSE_INFO= LOG_INFO, // syslog:LOG_INFO
-
- VERBOSE_DEBUG= LOG_DEBUG // syslog:LOG_DEBUG
-};
-
-#ifndef __INTEL_COMPILER
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-#endif
-
-struct log_info_st
-{
- std::string name;
- std::string filename;
- int fd;
- bool opt_syslog;
- bool opt_file;
- bool init_success;
-
- log_info_st(const std::string& name_arg, const std::string &filename_arg, bool syslog_arg) :
- name(name_arg),
- filename(filename_arg),
- fd(-1),
- opt_syslog(syslog_arg),
- opt_file(false),
- init_success(false)
- {
- if (opt_syslog)
- {
- openlog(name.c_str(), LOG_PID | LOG_NDELAY, LOG_USER);
- }
-
- init();
- }
-
- void init()
- {
- if (filename.size())
- {
- if (filename.compare("stderr") == 0)
- {
- fd= STDERR_FILENO;
- }
- else
- {
- fd= open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
- if (fd == -1)
- {
- if (opt_syslog)
- {
- char buffer[1024];
- char *getcwd_ret= getcwd(buffer, sizeof(buffer));
- syslog(LOG_ERR, "Could not open log file \"%.*s\", from \"%s\", open failed with (%s)",
- int(filename.size()), filename.c_str(),
- getcwd_ret,
- strerror(errno));
- }
- std::cerr << "Could not open log file for writing, switching to stderr." << std::endl;
-
- fd= STDERR_FILENO;
- }
- }
-
- opt_file= true;
- }
-
- init_success= true;
- }
-
- bool initialized() const
- {
- return init_success;
- }
-
- int file() const
- {
- return fd;
- }
-
- void write(verbose_t verbose, const char *format, ...)
- {
- if (opt_file or opt_syslog)
- {
- va_list args;
- va_start(args, format);
- char mesg[BUFSIZ];
- int mesg_length= vsnprintf(mesg, sizeof(mesg), format, args);
- va_end(args);
-
- if (opt_file)
- {
- char buffer[UTIL_MAX_ERROR_SIZE];
- int buffer_length= snprintf(buffer, sizeof(buffer), "%7s %.*s\n", verbose_name(verbose), mesg_length, mesg);
- if (::write(file(), buffer, buffer_length) == -1)
- {
- std::cerr << "Could not write to log file." << std::endl;
- syslog(LOG_EMERG, "gearmand could not open log file %s, got error %s", filename.c_str(), strerror(errno));
- }
-
- }
-
- if (opt_syslog)
- {
- syslog(int(verbose), "%7s %.*s", verbose_name(verbose), mesg_length, mesg);
- }
- }
- }
-
- ~log_info_st()
- {
- if (fd != -1 and fd != STDERR_FILENO)
- {
- close(fd);
- }
-
- if (opt_syslog)
- {
- closelog();
- }
- }
-
-private:
- const char *verbose_name(verbose_t verbose)
- {
- switch (verbose)
- {
- case VERBOSE_FATAL:
- return "FATAL";
-
- case VERBOSE_ALERT:
- return "ALERT";
-
- case VERBOSE_CRITICAL:
- return "CRITICAL";
-
- case VERBOSE_ERROR:
- return "ERROR";
-
- case VERBOSE_WARN:
- return "WARNING";
-
- case VERBOSE_NOTICE:
- return "NOTICE";
-
- case VERBOSE_INFO:
- return "INFO";
-
- case VERBOSE_DEBUG:
- return "DEBUG";
-
- default:
- break;
- }
-
- return "UNKNOWN";
- }
-};
-
-} // namespace util
-} // namespace datadifferential
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * DataDifferential Utility Library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "mem_config.h"
-
-#include "util/logfile.hpp"
-
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <fcntl.h>
-#include <fstream>
-#include <iostream>
-#include <sstream>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-namespace datadifferential {
-namespace util {
-
-Logfile::Logfile(const std::string &arg) :
- _filename(arg)
-{
- time_t tmp= time(NULL);
- _log_file << "shutdown: " << ctime(&tmp) << std::endl;
-}
-
-Logfile::~Logfile()
-{
- if (not _filename.empty())
- {
- _log_file.close();
- if (access(_filename.c_str(), F_OK) == -1)
- { }
- else if (unlink(_filename.c_str()) == -1)
- { }
- }
-}
-
-bool Logfile::open()
-{
- if (_filename.empty())
- {
- _log_file.open("/dev/stderr");
- return true;
- }
-
- _log_file.open(_filename.c_str());
- if (not _log_file.good())
- {
- return false;
- }
-
- time_t tmp= time(NULL);
- _log_file << "startup: " << ctime(&tmp) << std::endl;
-
- return true;
-}
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * DataDifferential Utility Library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <string>
-#include <fstream>
-
-namespace datadifferential {
-namespace util {
-
-class Logfile
-{
-public:
- Logfile(const std::string &arg);
-
- ~Logfile();
-
- std::ofstream &log()
- {
- return _log_file;
- }
-
- bool open();
-
-private:
- const std::string _filename;
- std::ofstream _log_file;
-};
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * DataDifferential Utility Library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <mem_config.h>
-
-#include "util/operation.hpp"
-#include <string>
-
-namespace datadifferential {
-namespace util {
-
-bool Operation::response(std::string &arg)
-{
- if (_response.empty())
- {
- return false;
- }
-
- if (not memcmp("OK\r\n", &_response[0], 3))
- { }
- else if (not memcmp("OK ", &_response[0], 3))
- {
- arg.append(&_response[3], _response.size() -3);
- }
- else if (not memcmp("ERR ", &_response[0], 4))
- {
- arg.append(&_response[4], _response.size() -4);
- return false;
- }
- else
- {
- arg.append(&_response[0], _response.size());
- }
-
- return true;
-}
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * DataDifferential Utility Library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-
-#include <cstring>
-#include <iosfwd>
-#include <vector>
-
-namespace datadifferential {
-namespace util {
-
-class Operation {
- typedef std::vector<char> Packet;
-
-public:
- typedef std::vector<Operation *> vector;
-
- Operation(const char *command, size_t command_length, bool expect_response= true) :
- _expect_response(expect_response),
- packet(),
- _response()
- {
- packet.resize(command_length);
- memcpy(&packet[0], command, command_length);
- }
-
- ~Operation()
- { }
-
- size_t size() const
- {
- return packet.size();
- }
-
- const char* ptr() const
- {
- return &(packet)[0];
- }
-
- bool has_response() const
- {
- return _expect_response;
- }
-
- void push(const char *buffer, size_t buffer_size)
- {
- size_t response_size= _response.size();
- _response.resize(response_size +buffer_size);
- memcpy(&_response[0] +response_size, buffer, buffer_size);
- }
-
- // Return false on error
- bool response(std::string &);
-
- bool reconnect() const
- {
- return false;
- }
-
-private:
- bool _expect_response;
- Packet packet;
- Packet _response;
-};
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * DataDifferential Utility Library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "mem_config.h"
-
-#include "util/pidfile.hpp"
-
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <cerrno>
-#include <fcntl.h>
-#include <iostream>
-#include <sstream>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-extern "C" {
-
- char pid_file[1024 * 4]= { 0 };
-
- static void remove_pidfile(void)
- {
- if (pid_file[0])
- {
- if (unlink(pid_file) == -1)
- {
- std::cerr << "Could not remove pidfile: " << pid_file << "(" << strerror(errno) << ")" << std::endl;
- }
-
- pid_file[0]= 0;
- }
- }
-
-}
-
-namespace datadifferential {
-namespace util {
-
-Pidfile::Pidfile(const std::string &arg) :
- _last_errno(0),
- _filename(arg)
-{
-}
-
-
-Pidfile::~Pidfile()
-{
- if (not _filename.empty())
- {
- if (access(_filename.c_str(), F_OK) == -1)
- {
- std::stringstream error_stream;
- error_stream << "Could not access the pid file: " << _filename << "(" << strerror(errno) << ")";
- _error_message= error_stream.str();
- }
- else if (unlink(_filename.c_str()) == -1)
- {
- std::stringstream error_stream;
- error_stream << "Could not remove the pid file: " << _filename << "(" << strerror(errno) << ")";
- _error_message= error_stream.str();
- }
- }
- pid_file[0]= 0;
-}
-
-bool Pidfile::create()
-{
- if (_filename.empty())
- {
- return true;
- }
-
- if (access(_filename.c_str(), F_OK) == 0)
- {
- if (unlink(_filename.c_str()) == -1)
- {
- std::stringstream error_stream;
- error_stream << "Unable to remove exisiting file:" << _filename << "(" << strerror(errno) << ")";
- _error_message= error_stream.str();
-
- return false;
- }
- }
-
- int oflags= O_CREAT|O_WRONLY|O_TRUNC;
-#ifdef HAVE_O_CLOEXEC
- oflags= oflags | O_CLOEXEC;
-#endif
-
- int file;
- if ((file = open(_filename.c_str(), oflags, S_IRWXU|S_IRGRP|S_IROTH)) < 0)
- {
- std::stringstream error_stream;
- error_stream << "Could not open pid file for writing: " << _filename << "(" << strerror(errno) << ")";
- _error_message= error_stream.str();
-
- return false;
- }
-
- char buffer[BUFSIZ];
- unsigned long temp= static_cast<unsigned long>(getpid());
- int length= snprintf(buffer, sizeof(buffer), "%lu\n", temp);
- if (write(file, buffer, length) != length)
- {
- std::stringstream error_stream;
- error_stream << "Could not write pid to file: " << _filename << "(" << strerror(errno) << ")";
- _error_message= error_stream.str();
- close(file);
-
- return false;
- }
-
- if (close(file) < 0)
- {
- _error_message+= "Could not close() file after writing pid to it: ";
- _error_message+= _filename;
- return false;
- }
- snprintf(pid_file, sizeof(pid_file), "%s", _filename.c_str());
- atexit(remove_pidfile);
-
- return true;
-}
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * DataDifferential Utility Library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <string>
-
-namespace datadifferential {
-namespace util {
-
-class Pidfile
-{
-public:
- Pidfile(const std::string &arg);
-
- ~Pidfile();
-
- const std::string &error_message()
- {
- return _error_message;
- }
-
- bool create();
-
-private:
- int _last_errno;
- const std::string _filename;
- std::string _error_message;
-};
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential Utility library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <mem_config.h>
-
-#include <cassert>
-#include <cerrno>
-#include <csignal>
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-
-#include <util/signal.hpp>
-
-namespace datadifferential {
-namespace util {
-
-#define MAGIC_MEMORY 123569
-
-bool SignalThread::is_shutdown()
-{
- bool ret;
- pthread_mutex_lock(&shutdown_mutex);
- ret= bool(__shutdown != SHUTDOWN_RUNNING);
- pthread_mutex_unlock(&shutdown_mutex);
-
- return ret;
-}
-
-void SignalThread::set_shutdown(shutdown_t arg)
-{
- pthread_mutex_lock(&shutdown_mutex);
- __shutdown= arg;
- pthread_mutex_unlock(&shutdown_mutex);
-
- if (arg == SHUTDOWN_GRACEFUL)
- {
- if (pthread_kill(thread, SIGUSR2) == 0)
- {
- void *retval;
- pthread_join(thread, &retval);
- }
- }
-}
-
-shutdown_t SignalThread::get_shutdown()
-{
- shutdown_t local;
- pthread_mutex_lock(&shutdown_mutex);
- local= __shutdown;
- pthread_mutex_unlock(&shutdown_mutex);
-
- return local;
-}
-
-void SignalThread::post()
-{
- sem_post(&lock);
-}
-
-void SignalThread::test()
-{
- assert(magic_memory == MAGIC_MEMORY);
- assert(sigismember(&set, SIGABRT));
- assert(sigismember(&set, SIGINT));
- assert(sigismember(&set, SIGQUIT));
- assert(sigismember(&set, SIGTERM));
- assert(sigismember(&set, SIGUSR2));
-}
-
-void SignalThread::sighup(signal_callback_fn* arg)
-{
- _sighup= arg;
-}
-
-void SignalThread::sighup()
-{
- if (_sighup)
- {
- _sighup();
- }
-}
-
-SignalThread::~SignalThread()
-{
- if (not is_shutdown())
- {
- set_shutdown(SHUTDOWN_GRACEFUL);
- }
-
-#if 0
- if (pthread_equal(thread, pthread_self()) != 0 and (pthread_kill(thread, 0) == ESRCH) == true)
- {
- void *retval;
- pthread_join(thread, &retval);
- }
-#endif
- sem_destroy(&lock);
-}
-
-extern "C" {
-
-static void *sig_thread(void *arg)
-{
- SignalThread *context= (SignalThread*)arg;
-
- context->test();
- context->post();
-
- while (context->get_shutdown() == SHUTDOWN_RUNNING)
- {
- int sig;
-
- if (context->wait(sig) == -1)
- {
- std::cerr << "sigwait() returned errno:" << strerror(errno) << std::endl;
- continue;
- }
-
- switch (sig)
- {
- case SIGUSR2:
- break;
-
- case SIGHUP:
- context->sighup();
- break;
-
- case SIGABRT:
- case SIGINT:
- case SIGQUIT:
- case SIGTERM:
- if (context->is_shutdown() == false)
- {
- context->set_shutdown(SHUTDOWN_FORCED);
- }
-
- if (context->exit_on_signal())
- {
- exit(EXIT_SUCCESS);
- }
-
- break;
-
- default:
- std::cerr << "Signal handling thread got unexpected signal " << strsignal(sig) << std::endl;
- break;
- }
- }
-
- return NULL;
-}
-
-}
-
-SignalThread::SignalThread(bool exit_on_signal_arg) :
- _exit_on_signal(exit_on_signal_arg),
- magic_memory(MAGIC_MEMORY),
- __shutdown(SHUTDOWN_RUNNING),
- thread(pthread_self()),
- _sighup(NULL)
-{
- pthread_mutex_init(&shutdown_mutex, NULL);
- sigemptyset(&set);
-
- sigaddset(&set, SIGABRT);
- sigaddset(&set, SIGINT);
- sigaddset(&set, SIGQUIT);
- sigaddset(&set, SIGTERM);
- sigaddset(&set, SIGUSR2);
-
- sem_init(&lock, 0, 0);
-}
-
-
-bool SignalThread::setup()
-{
- set_shutdown(SHUTDOWN_RUNNING);
-
- int error;
- if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
- {
- std::cerr << "pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")" << std::endl;
- return false;
- }
-
- if ((error= pthread_create(&thread, NULL, &sig_thread, this)) != 0)
- {
- std::cerr << "pthread_create() died during pthread_create(" << strerror(error) << ")" << std::endl;
- return false;
- }
-
- sem_wait(&lock);
-
- return true;
-}
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Data Differential Utility library
- *
- * Copyright (C) 2012 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#pragma once
-
-#include <pthread.h>
-#include <semaphore.h>
-
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void (signal_callback_fn)();
-
-#ifdef __cplusplus
-}
-#endif
-
-namespace datadifferential {
-namespace util {
-
-enum shutdown_t {
- SHUTDOWN_RUNNING,
- SHUTDOWN_GRACEFUL,
- SHUTDOWN_FORCED
-};
-
-class SignalThread {
- bool _exit_on_signal;
- sigset_t set;
- sem_t lock;
- uint64_t magic_memory;
- volatile shutdown_t __shutdown;
- pthread_mutex_t shutdown_mutex;
-
-public:
-
- SignalThread(bool exit_on_signal_arg= false);
-
- void test();
- void post();
- bool setup();
-
- bool exit_on_signal()
- {
- return _exit_on_signal;
- }
-
- int wait(int& sig)
- {
- return sigwait(&set, &sig);
- }
-
- ~SignalThread();
-
- void set_shutdown(shutdown_t arg);
- bool is_shutdown();
- shutdown_t get_shutdown();
-
- void sighup();
- void sighup(signal_callback_fn* arg);
-
-private:
- pthread_t thread;
- signal_callback_fn* _sighup;
-};
-
-} /* namespace util */
-} /* namespace datadifferential */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * DataDifferential Utility Library
- *
- * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-/*
- Simple defines
-*/
-
-#include <cstring>
-#include <cstddef>
-
-#pragma once
-
-#define util_literal_param(X) (X), (static_cast<size_t>((sizeof(X) - 1)))
-#define util_literal_param_size(X) static_cast<size_t>(sizeof(X) - 1)
-
-#define util_literal_compare_param(X) (static_cast<size_t>((sizeof(X) - 1))), (X)
-
-#define util_string_make_from_cstr(X) (X), ((X) ? strlen(X) : 0)
-
-#define util_string_make_from_array(__array) (__array), (strlen(__array))
-
-#define util_array_length(__array) sizeof(__array)/sizeof(&__array)
-
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2010 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: "Implementation" of the function we don't have on windows
- * to avoid a bunch of ifdefs in the rest of the code
- *
- */
-#pragma once
-
-#include <inttypes.h>
-
-/*
- * One of the Windows headers define interface as a macro, but that
- * is causing problems with the member named "interface" in some of the
- * structs.
- */
-#undef interface
-
-#undef malloc
-#undef realloc
-
-
-/*
- * WinSock use a separate range for error codes. Let's just map to the
- * WinSock ones.
- */
-#ifndef EADDRINUSE
-# define EADDRINUSE WSAEADDRINUSE
-#endif
-
-#ifndef EWOULDBLOCK
-# define EWOULDBLOCK WSAEWOULDBLOCK
-#endif
-
-#ifndef EINPROGRESS
-# define EINPROGRESS WSAEINPROGRESS
-#endif
-
-#ifndef EALREADY
-# define EALREADY WSAEALREADY
-#endif
-
-#ifndef EISCONN
-# define EISCONN WSAEISCONN
-#endif
-
-#ifndef ENOTCONN
-# define ENOTCONN WSAENOTCONN
-#endif
-
-#ifndef ENOBUFS
-# define ENOBUFS WSAENOBUFS
-#endif
-
-#ifndef SHUT_RDWR
-# define SHUT_RDWR SD_BOTH
-#endif
-
-/* EAI_SYSTEM isn't defined anywhere... just set it to... 11? */
-#ifndef EAI_SYSTEM
-# define EAI_SYSTEM 11
-#endif
-
-/* Best effort mapping of functions to alternative functions */
-#define index(a,b) strchr(a,b)
-#define rindex(a,b) strrchr(a,b)
-#define random() rand()
-#define srandom(a) while (false) {}
-#define kill(a, b) while (false) {}
-#define fork() (-1)
-#define waitpid(a,b,c) (-1)
-#define fnmatch(a,b,c) (-1)
-#define sleep(a) Sleep(a*1000)