From: Brian Aker Date: Thu, 28 Apr 2011 00:30:03 +0000 (-0700) Subject: Merge in code for C++ compiling of libmemcached. X-Git-Tag: 0.51~12 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=67456d74f5bd4f354a360d70da503dc58cbe5971;hp=86be0943416087ba738c28ddbde8cdcbd62ad777;p=awesomized%2Flibmemcached Merge in code for C++ compiling of libmemcached. --- diff --git a/ChangeLog b/ChangeLog index 933decf3..43d3eef6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -0.49 +0.49 Thu Apr 14 08:43:37 PDT 2011 * Fix calls to auto methods so that if value is not passed in nothing bad happens. * New parser calls for generating memcached_st objects. * New error system. diff --git a/Makefile.am b/Makefile.am index 80b2c03e..2c276016 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,6 +35,8 @@ EXTRA_DIST= \ include libtest/include.am include libmemcached/include.am +include libmemcached/protocol/include.am +include libmemcached/util/include.am include clients/include.am include libhashkit/include.am include tests/include.am @@ -93,6 +95,4 @@ lcov-clean: clean find . -name '*.gcno' | xargs rm -f find . -name '*.gcda' | xargs rm -f -CLEANFILES+= config/top.h - - +DISTCLEANFILES+= config/top.h diff --git a/clients/execute.c b/clients/execute.c deleted file mode 100644 index 0beaae4b..00000000 --- a/clients/execute.c +++ /dev/null @@ -1,131 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - -/* - Execute a memcached_set() a set of pairs. - Return the number of rows set. -*/ - -#include "config.h" -#include "execute.h" - -unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of) -{ - memcached_return_t rc; - unsigned int x; - unsigned int pairs_sent; - - for (x= 0, pairs_sent= 0; x < number_of; x++) - { - rc= memcached_set(memc, pairs[x].key, pairs[x].key_length, - pairs[x].value, pairs[x].value_length, - 0, 0); - if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) - fprintf(stderr, "Failured on insert of %.*s\n", - (unsigned int)pairs[x].key_length, pairs[x].key); - else - pairs_sent++; - } - - return pairs_sent; -} - -/* - Execute a memcached_get() on a set of pairs. - Return the number of rows retrieved. -*/ -unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of) -{ - memcached_return_t rc; - unsigned int x; - unsigned int retrieved; - - - for (retrieved= 0,x= 0; x < number_of; x++) - { - char *value; - size_t value_length; - uint32_t flags; - unsigned int fetch_key; - - fetch_key= (unsigned int)((unsigned int)random() % number_of); - - value= memcached_get(memc, pairs[fetch_key].key, pairs[fetch_key].key_length, - &value_length, &flags, &rc); - - if (rc != MEMCACHED_SUCCESS) - fprintf(stderr, "Failured on read of %.*s\n", - (unsigned int)pairs[fetch_key].key_length, pairs[fetch_key].key); - else - retrieved++; - - free(value); - } - - return retrieved; -} - -/** - * Callback function to count the number of results - */ -static memcached_return_t callback_counter(const memcached_st *ptr, - memcached_result_st *result, - void *context) -{ - (void)ptr; - (void)result; - unsigned int *counter= (unsigned int *)context; - *counter= *counter + 1; - - return MEMCACHED_SUCCESS; -} - -/** - * Try to run a large mget to get all of the keys - * @param memc memcached handle - * @param keys the keys to get - * @param key_length the length of the keys - * @param number_of the number of keys to try to get - * @return the number of keys received - */ -unsigned int execute_mget(memcached_st *memc, - const char * const *keys, - size_t *key_length, - unsigned int number_of) -{ - unsigned int retrieved= 0; - memcached_execute_fn callbacks[1]= { [0]= &callback_counter }; - memcached_return_t rc; - rc= memcached_mget_execute(memc, keys, key_length, - (size_t)number_of, callbacks, &retrieved, 1); - - if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_NOTFOUND || - rc == MEMCACHED_BUFFERED || rc == MEMCACHED_END) - { - rc= memcached_fetch_execute(memc, callbacks, (void *)&retrieved, 1); - if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_END) - { - fprintf(stderr, "Failed to execute mget: %s\n", - memcached_strerror(memc, rc)); - memcached_quit(memc); - return 0; - } - } - else - { - fprintf(stderr, "Failed to execute mget: %s\n", - memcached_strerror(memc, rc)); - memcached_quit(memc); - return 0; - } - - return retrieved; -} diff --git a/clients/execute.cc b/clients/execute.cc new file mode 100644 index 00000000..7f89f773 --- /dev/null +++ b/clients/execute.cc @@ -0,0 +1,131 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ + +/* + Execute a memcached_set() a set of pairs. + Return the number of rows set. +*/ + +#include "config.h" +#include "execute.h" + +unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of) +{ + memcached_return_t rc; + unsigned int x; + unsigned int pairs_sent; + + for (x= 0, pairs_sent= 0; x < number_of; x++) + { + rc= memcached_set(memc, pairs[x].key, pairs[x].key_length, + pairs[x].value, pairs[x].value_length, + 0, 0); + if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) + fprintf(stderr, "Failured on insert of %.*s\n", + (unsigned int)pairs[x].key_length, pairs[x].key); + else + pairs_sent++; + } + + return pairs_sent; +} + +/* + Execute a memcached_get() on a set of pairs. + Return the number of rows retrieved. +*/ +unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of) +{ + memcached_return_t rc; + unsigned int x; + unsigned int retrieved; + + + for (retrieved= 0,x= 0; x < number_of; x++) + { + char *value; + size_t value_length; + uint32_t flags; + unsigned int fetch_key; + + fetch_key= (unsigned int)((unsigned int)random() % number_of); + + value= memcached_get(memc, pairs[fetch_key].key, pairs[fetch_key].key_length, + &value_length, &flags, &rc); + + if (rc != MEMCACHED_SUCCESS) + fprintf(stderr, "Failured on read of %.*s\n", + (unsigned int)pairs[fetch_key].key_length, pairs[fetch_key].key); + else + retrieved++; + + free(value); + } + + return retrieved; +} + +/** + * Callback function to count the number of results + */ +static memcached_return_t callback_counter(const memcached_st *ptr, + memcached_result_st *result, + void *context) +{ + (void)ptr; + (void)result; + unsigned int *counter= (unsigned int *)context; + *counter= *counter + 1; + + return MEMCACHED_SUCCESS; +} + +/** + * Try to run a large mget to get all of the keys + * @param memc memcached handle + * @param keys the keys to get + * @param key_length the length of the keys + * @param number_of the number of keys to try to get + * @return the number of keys received + */ +unsigned int execute_mget(memcached_st *memc, + const char * const *keys, + size_t *key_length, + unsigned int number_of) +{ + unsigned int retrieved= 0; + memcached_execute_fn callbacks[]= { callback_counter }; + memcached_return_t rc; + rc= memcached_mget_execute(memc, keys, key_length, + (size_t)number_of, callbacks, &retrieved, 1); + + if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_NOTFOUND || + rc == MEMCACHED_BUFFERED || rc == MEMCACHED_END) + { + rc= memcached_fetch_execute(memc, callbacks, (void *)&retrieved, 1); + if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_END) + { + fprintf(stderr, "Failed to execute mget: %s\n", + memcached_strerror(memc, rc)); + memcached_quit(memc); + return 0; + } + } + else + { + fprintf(stderr, "Failed to execute mget: %s\n", + memcached_strerror(memc, rc)); + memcached_quit(memc); + return 0; + } + + return retrieved; +} diff --git a/clients/execute.h b/clients/execute.h index 176c6fff..05678c4d 100644 --- a/clients/execute.h +++ b/clients/execute.h @@ -9,17 +9,22 @@ * */ -#ifndef CLIENTS_EXECUTE_H -#define CLIENTS_EXECUTE_H +#pragma once #include #include "libmemcached/memcached.h" -#include "generator.h" +#include "clients/generator.h" + +#ifdef __cplusplus +extern "C" { +#endif unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of); unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of); unsigned int execute_mget(memcached_st *memc, const char * const *keys, size_t *key_length, unsigned int number_of); -#endif +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/clients/generator.c b/clients/generator.c deleted file mode 100644 index 80b398b2..00000000 --- a/clients/generator.c +++ /dev/null @@ -1,96 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "generator.h" - -/* Use this for string generation */ -static const char ALPHANUMERICS[]= - "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz"; - -#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1) - -static size_t get_alpha_num(void) -{ - return (size_t)random() % ALPHANUMERICS_SIZE; -} - -static void get_random_string(char *buffer, size_t size) -{ - char *buffer_ptr= buffer; - - while (--size) - *buffer_ptr++= ALPHANUMERICS[get_alpha_num()]; - *buffer_ptr++= ALPHANUMERICS[get_alpha_num()]; -} - -void pairs_free(pairs_st *pairs) -{ - uint32_t x; - - if (! pairs) - return; - - /* We free until we hit the null pair we stores during creation */ - for (x= 0; pairs[x].key; x++) - { - free(pairs[x].key); - if (pairs[x].value) - free(pairs[x].value); - } - - free(pairs); -} - -pairs_st *pairs_generate(uint64_t number_of, size_t value_length) -{ - unsigned int x; - pairs_st *pairs; - - pairs= (pairs_st*)calloc((size_t)number_of + 1, sizeof(pairs_st)); - - if (!pairs) - goto error; - - for (x= 0; x < number_of; x++) - { - pairs[x].key= (char *)calloc(100, sizeof(char)); - if (!pairs[x].key) - goto error; - get_random_string(pairs[x].key, 100); - pairs[x].key_length= 100; - - if (value_length) - { - pairs[x].value= (char *)calloc(value_length, sizeof(char)); - if (!pairs[x].value) - goto error; - get_random_string(pairs[x].value, value_length); - pairs[x].value_length= value_length; - } - else - { - pairs[x].value= NULL; - pairs[x].value_length= 0; - } - } - - return pairs; -error: - fprintf(stderr, "Memory Allocation failure in pairs_generate.\n"); - exit(0); -} diff --git a/clients/generator.cc b/clients/generator.cc new file mode 100644 index 00000000..80b398b2 --- /dev/null +++ b/clients/generator.cc @@ -0,0 +1,96 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "generator.h" + +/* Use this for string generation */ +static const char ALPHANUMERICS[]= + "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz"; + +#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1) + +static size_t get_alpha_num(void) +{ + return (size_t)random() % ALPHANUMERICS_SIZE; +} + +static void get_random_string(char *buffer, size_t size) +{ + char *buffer_ptr= buffer; + + while (--size) + *buffer_ptr++= ALPHANUMERICS[get_alpha_num()]; + *buffer_ptr++= ALPHANUMERICS[get_alpha_num()]; +} + +void pairs_free(pairs_st *pairs) +{ + uint32_t x; + + if (! pairs) + return; + + /* We free until we hit the null pair we stores during creation */ + for (x= 0; pairs[x].key; x++) + { + free(pairs[x].key); + if (pairs[x].value) + free(pairs[x].value); + } + + free(pairs); +} + +pairs_st *pairs_generate(uint64_t number_of, size_t value_length) +{ + unsigned int x; + pairs_st *pairs; + + pairs= (pairs_st*)calloc((size_t)number_of + 1, sizeof(pairs_st)); + + if (!pairs) + goto error; + + for (x= 0; x < number_of; x++) + { + pairs[x].key= (char *)calloc(100, sizeof(char)); + if (!pairs[x].key) + goto error; + get_random_string(pairs[x].key, 100); + pairs[x].key_length= 100; + + if (value_length) + { + pairs[x].value= (char *)calloc(value_length, sizeof(char)); + if (!pairs[x].value) + goto error; + get_random_string(pairs[x].value, value_length); + pairs[x].value_length= value_length; + } + else + { + pairs[x].value= NULL; + pairs[x].value_length= 0; + } + } + + return pairs; +error: + fprintf(stderr, "Memory Allocation failure in pairs_generate.\n"); + exit(0); +} diff --git a/clients/generator.h b/clients/generator.h index 196e71b2..e60bfb38 100644 --- a/clients/generator.h +++ b/clients/generator.h @@ -13,8 +13,7 @@ Code to generate data to be pushed into memcached */ -#ifndef __GENERATOR_H__ -#define __GENERATOR_H__ +#pragma once typedef struct pairs_st pairs_st; @@ -25,7 +24,13 @@ struct pairs_st { size_t value_length; }; +#ifdef __cplusplus +extern "C" { +#endif + pairs_st *pairs_generate(uint64_t number_of, size_t value_length); void pairs_free(pairs_st *pairs); +#ifdef __cplusplus +} // extern "C" #endif diff --git a/clients/include.am b/clients/include.am index 07d49a70..05b1ed7e 100644 --- a/clients/include.am +++ b/clients/include.am @@ -2,10 +2,10 @@ # included from Top Level Makefile.am # All paths should be given relative to the root -CLIENTS_LDADDS = \ - $(LIBM) \ - clients/libutilities.la \ - libmemcached/libmemcached.la +CLIENTS_LDADDS= \ + $(LIBM) \ + clients/libutilities.la \ + libmemcached/libmemcached.la if HAVE_SASL CLIENTS_LDADDS+= $(LIBSASL) @@ -44,53 +44,52 @@ noinst_HEADERS+= \ clients/utilities.h noinst_LTLIBRARIES+= clients/libutilities.la -clients_libutilities_la_SOURCES= clients/utilities.c +clients_libutilities_la_SOURCES= clients/utilities.cc noinst_LTLIBRARIES+= clients/libgenexec.la -clients_libgenexec_la_SOURCES= clients/generator.c clients/execute.c +clients_libgenexec_la_SOURCES= clients/generator.cc clients/execute.cc -clients_memcat_SOURCES= clients/memcat.c +clients_memcat_SOURCES= clients/memcat.cc clients_memcat_LDADD= $(CLIENTS_LDADDS) clients_memparse_SOURCES= clients/memparse.cc clients_memparse_LDADD= $(CLIENTS_LDADDS) -clients_memcp_SOURCES= clients/memcp.c +clients_memcp_SOURCES= clients/memcp.cc clients_memcp_LDADD= $(CLIENTS_LDADDS) -clients_memdump_SOURCES= clients/memdump.c +clients_memdump_SOURCES= clients/memdump.cc clients_memdump_LDADD= $(CLIENTS_LDADDS) -clients_memstat_SOURCES= clients/memstat.c +clients_memstat_SOURCES= clients/memstat.cc clients_memstat_LDADD= $(CLIENTS_LDADDS) -clients_memrm_SOURCES= clients/memrm.c +clients_memrm_SOURCES= clients/memrm.cc clients_memrm_LDADD= $(CLIENTS_LDADDS) -clients_memflush_SOURCES= clients/memflush.c +clients_memflush_SOURCES= clients/memflush.cc clients_memflush_LDADD= $(CLIENTS_LDADDS) -clients_memerror_SOURCES= clients/memerror.c +clients_memerror_SOURCES= clients/memerror.cc clients_memerror_LDADD= $(CLIENTS_LDADDS) -clients_memslap_SOURCES = clients/memslap.c +clients_memslap_SOURCES = clients/memslap.cc clients_memslap_LDADD = $(PTHREAD_LIBS) clients/libgenexec.la $(CLIENTS_LDADDS) clients_memaslap_SOURCES= \ - clients/memaslap.c \ - clients/ms_conn.c \ - clients/ms_setting.c \ - clients/ms_sigsegv.c \ - clients/ms_stats.c \ - clients/ms_task.c \ - clients/ms_thread.c + clients/memaslap.c \ + clients/ms_conn.c \ + clients/ms_setting.c \ + clients/ms_sigsegv.c \ + clients/ms_stats.c \ + clients/ms_task.c \ + clients/ms_thread.c clients_memaslap_LDADD= $(LTLIBEVENT) clients/libgenexec.la $(CLIENTS_LDADDS) -clients_memcapable_SOURCES= clients/memcapable.c +clients_memcapable_SOURCES= \ + clients/memcapable.cc \ + libmemcached/byteorder.cc clients_memcapable_LDADD= $(CLIENTS_LDADDS) -if BUILD_BYTEORDER -clients_memcapable_LDADD+= libmemcached/libbyteorder.la -endif test-start-server: clients/memflush --servers=localhost diff --git a/clients/memcapable.c b/clients/memcapable.c deleted file mode 100644 index 69d2557e..00000000 --- a/clients/memcapable.c +++ /dev/null @@ -1,2087 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - -/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ -#undef NDEBUG -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "utilities.h" - -#ifdef linux -/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to - * optimize the conversion functions, but the prototypes generate warnings - * from gcc. The conversion methods isn't the bottleneck for my app, so - * just remove the warnings by undef'ing the optimization .. - */ -#undef ntohs -#undef ntohl -#endif - -/* Should we generate coredumps when we enounter an error (-c) */ -static bool do_core= false; -/* connection to the server */ -static memcached_socket_t sock; -/* Should the output from test failures be verbose or quiet? */ -static bool verbose= false; - -/* The number of seconds to wait for an IO-operation */ -static int timeout= 2; - -/* - * Instead of having to cast between the different datatypes we create - * a union of all of the different types of pacages we want to send. - * A lot of the different commands use the same packet layout, so I'll - * just define the different types I need. The typedefs only contain - * the header of the message, so we need some space for keys and body - * To avoid to have to do multiple writes, lets add a chunk of memory - * to use. 1k should be more than enough for header, key and body. - */ -typedef union -{ - protocol_binary_request_no_extras plain; - protocol_binary_request_flush flush; - protocol_binary_request_incr incr; - protocol_binary_request_set set; - char bytes[1024]; -} command; - -typedef union -{ - protocol_binary_response_no_extras plain; - protocol_binary_response_incr incr; - protocol_binary_response_decr decr; - char bytes[1024]; -} response; - -enum test_return -{ - TEST_SKIP, TEST_PASS, TEST_PASS_RECONNECT, TEST_FAIL -}; - -/** - * Try to get an addrinfo struct for a given port on a given host - */ -static struct addrinfo *lookuphost(const char *hostname, const char *port) -{ - struct addrinfo *ai= 0; - struct addrinfo hints= {.ai_family=AF_UNSPEC, - .ai_protocol=IPPROTO_TCP, - .ai_socktype=SOCK_STREAM}; - int error= getaddrinfo(hostname, port, &hints, &ai); - - if (error != 0) - { - if (error != EAI_SYSTEM) - fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error)); - else - perror("getaddrinfo()"); - } - - return ai; -} - -/** - * Set the socket in nonblocking mode - * @return -1 if failure, the socket otherwise - */ -static memcached_socket_t set_noblock(void) -{ -#ifdef WIN32 - u_long arg = 1; - if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR) - { - perror("Failed to set nonblocking io"); - closesocket(sock); - return INVALID_SOCKET; - } -#else - int flags= fcntl(sock, F_GETFL, 0); - if (flags == -1) - { - perror("Failed to get socket flags"); - closesocket(sock); - return INVALID_SOCKET; - } - - if ((flags & O_NONBLOCK) != O_NONBLOCK) - { - if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) - { - perror("Failed to set socket to nonblocking mode"); - closesocket(sock); - return INVALID_SOCKET; - } - } -#endif - return sock; -} - -/** - * Try to open a connection to the server - * @param hostname the name of the server to connect to - * @param port the port number (or service) to connect to - * @return positive integer if success, -1 otherwise - */ -static memcached_socket_t connect_server(const char *hostname, const char *port) -{ - struct addrinfo *ai= lookuphost(hostname, port); - sock= INVALID_SOCKET; - if (ai != NULL) - { - if ((sock= socket(ai->ai_family, ai->ai_socktype, - ai->ai_protocol)) != INVALID_SOCKET) - { - if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR) - { - fprintf(stderr, "Failed to connect socket: %s\n", - strerror(get_socket_errno())); - closesocket(sock); - sock= INVALID_SOCKET; - } - else - { - sock= set_noblock(); - } - } - else - fprintf(stderr, "Failed to create socket: %s\n", - strerror(get_socket_errno())); - - freeaddrinfo(ai); - } - - return sock; -} - -static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len) -{ - ssize_t ret; - - if (direction == POLLOUT) - ret= send(fd, buf, len, 0); - else - ret= recv(fd, buf, len, 0); - - if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK) { - struct pollfd fds= { - .events= direction, - .fd= fd - }; - - int err= poll(&fds, 1, timeout * 1000); - - if (err == 1) - { - if (direction == POLLOUT) - ret= send(fd, buf, len, 0); - else - ret= recv(fd, buf, len, 0); - } - else if (err == 0) - { - errno= ETIMEDOUT; - } - else - { - perror("Failed to poll"); - return -1; - } - } - - return ret; -} - -/** - * Ensure that an expression is true. If it isn't print out a message similar - * to assert() and create a coredump if the user wants that. If not an error - * message is returned. - * - */ -static enum test_return ensure(bool val, const char *expression, const char *file, int line) -{ - if (!val) - { - if (verbose) - fprintf(stderr, "\n%s:%d: %s", file, line, expression); - - if (do_core) - abort(); - - return TEST_FAIL; - } - - return TEST_PASS; -} - -#define verify(expression) do { if (ensure(expression, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0) -#define execute(expression) do { if (ensure(expression == TEST_PASS, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0) - -/** - * Send a chunk of memory over the socket (retry if the call is iterrupted - */ -static enum test_return retry_write(const void* buf, size_t len) -{ - size_t offset= 0; - const char* ptr= buf; - - do - { - size_t num_bytes= len - offset; - ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes); - if (nw == -1) - verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN); - else - offset+= (size_t)nw; - } while (offset < len); - - return TEST_PASS; -} - -/** - * Resend a packet to the server (All fields in the command header should - * be in network byte order) - */ -static enum test_return resend_packet(command *cmd) -{ - size_t length= sizeof (protocol_binary_request_no_extras) + - ntohl(cmd->plain.message.header.request.bodylen); - - execute(retry_write(cmd, length)); - return TEST_PASS; -} - -/** - * Send a command to the server. The command header needs to be updated - * to network byte order - */ -static enum test_return send_packet(command *cmd) -{ - /* Fix the byteorder of the header */ - cmd->plain.message.header.request.keylen= - ntohs(cmd->plain.message.header.request.keylen); - cmd->plain.message.header.request.bodylen= - ntohl(cmd->plain.message.header.request.bodylen); - cmd->plain.message.header.request.cas= - ntohll(cmd->plain.message.header.request.cas); - - execute(resend_packet(cmd)); - return TEST_PASS; -} - -/** - * Read a fixed length chunk of data from the server - */ -static enum test_return retry_read(void *buf, size_t len) -{ - size_t offset= 0; - do - { - ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset); - switch (nr) { - case -1 : - fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno)); - verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN); - break; - case 0: - return TEST_FAIL; - default: - offset+= (size_t)nr; - } - } while (offset < len); - - return TEST_PASS; -} - -/** - * Receive a response from the server and conver the fields in the header - * to local byte order - */ -static enum test_return recv_packet(response *rsp) -{ - execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras))); - - /* Fix the byte order in the packet header */ - rsp->plain.message.header.response.keylen= - ntohs(rsp->plain.message.header.response.keylen); - rsp->plain.message.header.response.status= - ntohs(rsp->plain.message.header.response.status); - rsp->plain.message.header.response.bodylen= - ntohl(rsp->plain.message.header.response.bodylen); - rsp->plain.message.header.response.cas= - ntohll(rsp->plain.message.header.response.cas); - - size_t bodysz= rsp->plain.message.header.response.bodylen; - if (bodysz > 0) - execute(retry_read(rsp->bytes + sizeof (protocol_binary_response_no_extras), bodysz)); - - return TEST_PASS; -} - -/** - * Create a storage command (add, set, replace etc) - * - * @param cmd destination buffer - * @param cc the storage command to create - * @param key the key to store - * @param keylen the length of the key - * @param dta the data to store with the key - * @param dtalen the length of the data to store with the key - * @param flags the flags to store along with the key - * @param exptime the expiry time for the key - */ -static void storage_command(command *cmd, - uint8_t cc, - const void* key, - size_t keylen, - const void* dta, - size_t dtalen, - uint32_t flags, - uint32_t exptime) -{ - /* all of the storage commands use the same command layout */ - protocol_binary_request_set *request= &cmd->set; - - memset(request, 0, sizeof (*request)); - request->message.header.request.magic= PROTOCOL_BINARY_REQ; - request->message.header.request.opcode= cc; - request->message.header.request.keylen= (uint16_t)keylen; - request->message.header.request.extlen= 8; - request->message.header.request.bodylen= (uint32_t)(keylen + 8 + dtalen); - request->message.header.request.opaque= 0xdeadbeef; - request->message.body.flags= flags; - request->message.body.expiration= exptime; - - off_t key_offset= sizeof (protocol_binary_request_no_extras) + 8; - memcpy(cmd->bytes + key_offset, key, keylen); - if (dta != NULL) - memcpy(cmd->bytes + key_offset + keylen, dta, dtalen); -} - -/** - * Create a basic command to send to the server - * @param cmd destination buffer - * @param cc the command to create - * @param key the key to store - * @param keylen the length of the key - * @param dta the data to store with the key - * @param dtalen the length of the data to store with the key - */ -static void raw_command(command *cmd, - uint8_t cc, - const void* key, - size_t keylen, - const void* dta, - size_t dtalen) -{ - /* all of the storage commands use the same command layout */ - memset(cmd, 0, sizeof (*cmd)); - cmd->plain.message.header.request.magic= PROTOCOL_BINARY_REQ; - cmd->plain.message.header.request.opcode= cc; - cmd->plain.message.header.request.keylen= (uint16_t)keylen; - cmd->plain.message.header.request.bodylen= (uint32_t)(keylen + dtalen); - cmd->plain.message.header.request.opaque= 0xdeadbeef; - - off_t key_offset= sizeof (protocol_binary_request_no_extras); - - if (key != NULL) - memcpy(cmd->bytes + key_offset, key, keylen); - - if (dta != NULL) - memcpy(cmd->bytes + key_offset + keylen, dta, dtalen); -} - -/** - * Create the flush command - * @param cmd destination buffer - * @param cc the command to create (FLUSH/FLUSHQ) - * @param exptime when to flush - * @param use_extra to force using of the extra field? - */ -static void flush_command(command *cmd, - uint8_t cc, uint32_t exptime, bool use_extra) -{ - memset(cmd, 0, sizeof (cmd->flush)); - cmd->flush.message.header.request.magic= PROTOCOL_BINARY_REQ; - cmd->flush.message.header.request.opcode= cc; - cmd->flush.message.header.request.opaque= 0xdeadbeef; - - if (exptime != 0 || use_extra) - { - cmd->flush.message.header.request.extlen= 4; - cmd->flush.message.body.expiration= htonl(exptime); - cmd->flush.message.header.request.bodylen= 4; - } -} - -/** - * Create a incr/decr command - * @param cc the cmd to create (FLUSH/FLUSHQ) - * @param key the key to operate on - * @param keylen the number of bytes in the key - * @param delta the number to add/subtract - * @param initial the initial value if the key doesn't exist - * @param exptime when the key should expire if it isn't set - */ -static void arithmetic_command(command *cmd, - uint8_t cc, - const void* key, - size_t keylen, - uint64_t delta, - uint64_t initial, - uint32_t exptime) -{ - memset(cmd, 0, sizeof (cmd->incr)); - cmd->incr.message.header.request.magic= PROTOCOL_BINARY_REQ; - cmd->incr.message.header.request.opcode= cc; - cmd->incr.message.header.request.keylen= (uint16_t)keylen; - cmd->incr.message.header.request.extlen= 20; - cmd->incr.message.header.request.bodylen= (uint32_t)(keylen + 20); - cmd->incr.message.header.request.opaque= 0xdeadbeef; - cmd->incr.message.body.delta= htonll(delta); - cmd->incr.message.body.initial= htonll(initial); - cmd->incr.message.body.expiration= htonl(exptime); - - off_t key_offset= sizeof (protocol_binary_request_no_extras) + 20; - memcpy(cmd->bytes + key_offset, key, keylen); -} - -/** - * Validate the response header from the server - * @param rsp the response to check - * @param cc the expected command - * @param status the expected status - */ -static enum test_return do_validate_response_header(response *rsp, - uint8_t cc, uint16_t status) -{ - verify(rsp->plain.message.header.response.magic == PROTOCOL_BINARY_RES); - verify(rsp->plain.message.header.response.opcode == cc); - verify(rsp->plain.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES); - verify(rsp->plain.message.header.response.status == status); - verify(rsp->plain.message.header.response.opaque == 0xdeadbeef); - - if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) - { - switch (cc) { - case PROTOCOL_BINARY_CMD_ADDQ: - case PROTOCOL_BINARY_CMD_APPENDQ: - case PROTOCOL_BINARY_CMD_DECREMENTQ: - case PROTOCOL_BINARY_CMD_DELETEQ: - case PROTOCOL_BINARY_CMD_FLUSHQ: - case PROTOCOL_BINARY_CMD_INCREMENTQ: - case PROTOCOL_BINARY_CMD_PREPENDQ: - case PROTOCOL_BINARY_CMD_QUITQ: - case PROTOCOL_BINARY_CMD_REPLACEQ: - case PROTOCOL_BINARY_CMD_SETQ: - verify("Quiet command shouldn't return on success" == NULL); - default: - break; - } - - switch (cc) { - case PROTOCOL_BINARY_CMD_ADD: - case PROTOCOL_BINARY_CMD_REPLACE: - case PROTOCOL_BINARY_CMD_SET: - case PROTOCOL_BINARY_CMD_APPEND: - case PROTOCOL_BINARY_CMD_PREPEND: - verify(rsp->plain.message.header.response.keylen == 0); - verify(rsp->plain.message.header.response.extlen == 0); - verify(rsp->plain.message.header.response.bodylen == 0); - verify(rsp->plain.message.header.response.cas != 0); - break; - case PROTOCOL_BINARY_CMD_FLUSH: - case PROTOCOL_BINARY_CMD_NOOP: - case PROTOCOL_BINARY_CMD_QUIT: - case PROTOCOL_BINARY_CMD_DELETE: - verify(rsp->plain.message.header.response.keylen == 0); - verify(rsp->plain.message.header.response.extlen == 0); - verify(rsp->plain.message.header.response.bodylen == 0); - verify(rsp->plain.message.header.response.cas == 0); - break; - - case PROTOCOL_BINARY_CMD_DECREMENT: - case PROTOCOL_BINARY_CMD_INCREMENT: - verify(rsp->plain.message.header.response.keylen == 0); - verify(rsp->plain.message.header.response.extlen == 0); - verify(rsp->plain.message.header.response.bodylen == 8); - verify(rsp->plain.message.header.response.cas != 0); - break; - - case PROTOCOL_BINARY_CMD_STAT: - verify(rsp->plain.message.header.response.extlen == 0); - /* key and value exists in all packets except in the terminating */ - verify(rsp->plain.message.header.response.cas == 0); - break; - - case PROTOCOL_BINARY_CMD_VERSION: - verify(rsp->plain.message.header.response.keylen == 0); - verify(rsp->plain.message.header.response.extlen == 0); - verify(rsp->plain.message.header.response.bodylen != 0); - verify(rsp->plain.message.header.response.cas == 0); - break; - - case PROTOCOL_BINARY_CMD_GET: - case PROTOCOL_BINARY_CMD_GETQ: - verify(rsp->plain.message.header.response.keylen == 0); - verify(rsp->plain.message.header.response.extlen == 4); - verify(rsp->plain.message.header.response.cas != 0); - break; - - case PROTOCOL_BINARY_CMD_GETK: - case PROTOCOL_BINARY_CMD_GETKQ: - verify(rsp->plain.message.header.response.keylen != 0); - verify(rsp->plain.message.header.response.extlen == 4); - verify(rsp->plain.message.header.response.cas != 0); - break; - - default: - /* Undefined command code */ - break; - } - } - else - { - verify(rsp->plain.message.header.response.cas == 0); - verify(rsp->plain.message.header.response.extlen == 0); - if (cc != PROTOCOL_BINARY_CMD_GETK) - { - verify(rsp->plain.message.header.response.keylen == 0); - } - } - - return TEST_PASS; -} - -/* We call verify(validate_response_header), but that macro - * expects a boolean expression, and the function returns - * an enum.... Let's just create a macro to avoid cluttering - * the code with all of the == TEST_PASS ;-) - */ -#define validate_response_header(a,b,c) \ - do_validate_response_header(a,b,c) == TEST_PASS - - -static enum test_return send_binary_noop(void) -{ - command cmd; - raw_command(&cmd, PROTOCOL_BINARY_CMD_NOOP, NULL, 0, NULL, 0); - execute(send_packet(&cmd)); - return TEST_PASS; -} - -static enum test_return receive_binary_noop(void) -{ - response rsp; - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_NOOP, - PROTOCOL_BINARY_RESPONSE_SUCCESS)); - return TEST_PASS; -} - -static enum test_return test_binary_noop(void) -{ - execute(send_binary_noop()); - execute(receive_binary_noop()); - return TEST_PASS; -} - -static enum test_return test_binary_quit_impl(uint8_t cc) -{ - command cmd; - response rsp; - raw_command(&cmd, cc, NULL, 0, NULL, 0); - - execute(send_packet(&cmd)); - if (cc == PROTOCOL_BINARY_CMD_QUIT) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_QUIT, - PROTOCOL_BINARY_RESPONSE_SUCCESS)); - } - - /* Socket should be closed now, read should return EXIT_SUCCESS */ - verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0); - - return TEST_PASS_RECONNECT; -} - -static enum test_return test_binary_quit(void) -{ - return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT); -} - -static enum test_return test_binary_quitq(void) -{ - return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ); -} - -static enum test_return test_binary_set_impl(const char* key, uint8_t cc) -{ - command cmd; - response rsp; - - uint64_t value= 0xdeadbeefdeadcafe; - storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0); - - /* set should always work */ - for (int ii= 0; ii < 10; ii++) - { - if (ii == 0) - execute(send_packet(&cmd)); - else - execute(resend_packet(&cmd)); - - if (cc == PROTOCOL_BINARY_CMD_SET) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - } - else - execute(test_binary_noop()); - } - - /* - * We need to get the current CAS id, and at this time we haven't - * verified that we have a working get - */ - if (cc == PROTOCOL_BINARY_CMD_SETQ) - { - cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET; - execute(resend_packet(&cmd)); - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET, - PROTOCOL_BINARY_RESPONSE_SUCCESS)); - cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ; - } - - /* try to set with the correct CAS value */ - cmd.plain.message.header.request.cas= - htonll(rsp.plain.message.header.response.cas); - execute(resend_packet(&cmd)); - if (cc == PROTOCOL_BINARY_CMD_SET) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - } - else - execute(test_binary_noop()); - - /* try to set with an incorrect CAS value */ - cmd.plain.message.header.request.cas= - htonll(rsp.plain.message.header.response.cas - 1); - execute(resend_packet(&cmd)); - execute(send_binary_noop()); - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS)); - execute(receive_binary_noop()); - - return TEST_PASS; -} - -static enum test_return test_binary_set(void) -{ - return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET); -} - -static enum test_return test_binary_setq(void) -{ - return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ); -} - -static enum test_return test_binary_add_impl(const char* key, uint8_t cc) -{ - command cmd; - response rsp; - uint64_t value= 0xdeadbeefdeadcafe; - storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0); - - /* first add should work, rest of them should fail (even with cas - as wildcard */ - for (int ii=0; ii < 10; ii++) - { - if (ii == 0) - execute(send_packet(&cmd)); - else - execute(resend_packet(&cmd)); - - if (cc == PROTOCOL_BINARY_CMD_ADD || ii > 0) - { - uint16_t expected_result; - if (ii == 0) - expected_result= PROTOCOL_BINARY_RESPONSE_SUCCESS; - else - expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS; - - execute(send_binary_noop()); - execute(recv_packet(&rsp)); - execute(receive_binary_noop()); - verify(validate_response_header(&rsp, cc, expected_result)); - } - else - execute(test_binary_noop()); - } - - return TEST_PASS; -} - -static enum test_return test_binary_add(void) -{ - return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD); -} - -static enum test_return test_binary_addq(void) -{ - return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ); -} - -static enum test_return binary_set_item(const char *key, const char *value) -{ - command cmd; - response rsp; - storage_command(&cmd, PROTOCOL_BINARY_CMD_SET, key, strlen(key), - value, strlen(value), 0, 0); - execute(send_packet(&cmd)); - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET, - PROTOCOL_BINARY_RESPONSE_SUCCESS)); - return TEST_PASS; -} - -static enum test_return test_binary_replace_impl(const char* key, uint8_t cc) -{ - command cmd; - response rsp; - uint64_t value= 0xdeadbeefdeadcafe; - storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0); - - /* first replace should fail, successive should succeed (when the - item is added! */ - for (int ii= 0; ii < 10; ii++) - { - if (ii == 0) - execute(send_packet(&cmd)); - else - execute(resend_packet(&cmd)); - - if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0) - { - uint16_t expected_result; - if (ii == 0) - expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT; - else - expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS; - - execute(send_binary_noop()); - execute(recv_packet(&rsp)); - execute(receive_binary_noop()); - verify(validate_response_header(&rsp, cc, expected_result)); - - if (ii == 0) - execute(binary_set_item(key, key)); - } - else - execute(test_binary_noop()); - } - - /* verify that replace with CAS value works! */ - cmd.plain.message.header.request.cas= - htonll(rsp.plain.message.header.response.cas); - execute(resend_packet(&cmd)); - - if (cc == PROTOCOL_BINARY_CMD_REPLACE) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - } - else - execute(test_binary_noop()); - - /* try to set with an incorrect CAS value */ - cmd.plain.message.header.request.cas= - htonll(rsp.plain.message.header.response.cas - 1); - execute(resend_packet(&cmd)); - execute(send_binary_noop()); - execute(recv_packet(&rsp)); - execute(receive_binary_noop()); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS)); - - return TEST_PASS; -} - -static enum test_return test_binary_replace(void) -{ - return test_binary_replace_impl("test_binary_replace", PROTOCOL_BINARY_CMD_REPLACE); -} - -static enum test_return test_binary_replaceq(void) -{ - return test_binary_replace_impl("test_binary_replaceq", PROTOCOL_BINARY_CMD_REPLACEQ); -} - -static enum test_return test_binary_delete_impl(const char *key, uint8_t cc) -{ - command cmd; - response rsp; - raw_command(&cmd, cc, key, strlen(key), NULL, 0); - - /* The delete shouldn't work the first time, because the item isn't there */ - execute(send_packet(&cmd)); - execute(send_binary_noop()); - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)); - execute(receive_binary_noop()); - execute(binary_set_item(key, key)); - - /* The item should be present now, resend*/ - execute(resend_packet(&cmd)); - if (cc == PROTOCOL_BINARY_CMD_DELETE) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - } - - execute(test_binary_noop()); - - return TEST_PASS; -} - -static enum test_return test_binary_delete(void) -{ - return test_binary_delete_impl("test_binary_delete", PROTOCOL_BINARY_CMD_DELETE); -} - -static enum test_return test_binary_deleteq(void) -{ - return test_binary_delete_impl("test_binary_deleteq", PROTOCOL_BINARY_CMD_DELETEQ); -} - -static enum test_return test_binary_get_impl(const char *key, uint8_t cc) -{ - command cmd; - response rsp; - - raw_command(&cmd, cc, key, strlen(key), NULL, 0); - execute(send_packet(&cmd)); - execute(send_binary_noop()); - - if (cc == PROTOCOL_BINARY_CMD_GET || cc == PROTOCOL_BINARY_CMD_GETK) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)); - } - - execute(receive_binary_noop()); - - execute(binary_set_item(key, key)); - execute(resend_packet(&cmd)); - execute(send_binary_noop()); - - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - execute(receive_binary_noop()); - - return TEST_PASS; -} - -static enum test_return test_binary_get(void) -{ - return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET); -} - -static enum test_return test_binary_getk(void) -{ - return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK); -} - -static enum test_return test_binary_getq(void) -{ - return test_binary_get_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ); -} - -static enum test_return test_binary_getkq(void) -{ - return test_binary_get_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ); -} - -static enum test_return test_binary_incr_impl(const char* key, uint8_t cc) -{ - command cmd; - response rsp; - arithmetic_command(&cmd, cc, key, strlen(key), 1, 0, 0); - - uint64_t ii; - for (ii= 0; ii < 10; ++ii) - { - if (ii == 0) - execute(send_packet(&cmd)); - else - execute(resend_packet(&cmd)); - - if (cc == PROTOCOL_BINARY_CMD_INCREMENT) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - verify(ntohll(rsp.incr.message.body.value) == ii); - } - else - execute(test_binary_noop()); - } - - /* @todo add incorrect CAS */ - return TEST_PASS; -} - -static enum test_return test_binary_incr(void) -{ - return test_binary_incr_impl("test_binary_incr", PROTOCOL_BINARY_CMD_INCREMENT); -} - -static enum test_return test_binary_incrq(void) -{ - return test_binary_incr_impl("test_binary_incrq", PROTOCOL_BINARY_CMD_INCREMENTQ); -} - -static enum test_return test_binary_decr_impl(const char* key, uint8_t cc) -{ - command cmd; - response rsp; - arithmetic_command(&cmd, cc, key, strlen(key), 1, 9, 0); - - int ii; - for (ii= 9; ii > -1; --ii) - { - if (ii == 9) - execute(send_packet(&cmd)); - else - execute(resend_packet(&cmd)); - - if (cc == PROTOCOL_BINARY_CMD_DECREMENT) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - verify(ntohll(rsp.decr.message.body.value) == (uint64_t)ii); - } - else - execute(test_binary_noop()); - } - - /* decr 0 should not wrap */ - execute(resend_packet(&cmd)); - if (cc == PROTOCOL_BINARY_CMD_DECREMENT) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - verify(ntohll(rsp.decr.message.body.value) == 0); - } - else - { - /* @todo get the value and verify! */ - - } - - /* @todo add incorrect cas */ - execute(test_binary_noop()); - return TEST_PASS; -} - -static enum test_return test_binary_decr(void) -{ - return test_binary_decr_impl("test_binary_decr", - PROTOCOL_BINARY_CMD_DECREMENT); -} - -static enum test_return test_binary_decrq(void) -{ - return test_binary_decr_impl("test_binary_decrq", - PROTOCOL_BINARY_CMD_DECREMENTQ); -} - -static enum test_return test_binary_version(void) -{ - command cmd; - response rsp; - raw_command(&cmd, PROTOCOL_BINARY_CMD_VERSION, NULL, 0, NULL, 0); - - execute(send_packet(&cmd)); - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_VERSION, - PROTOCOL_BINARY_RESPONSE_SUCCESS)); - - return TEST_PASS; -} - -static enum test_return test_binary_flush_impl(const char *key, uint8_t cc) -{ - command cmd; - response rsp; - - for (int ii= 0; ii < 2; ++ii) - { - execute(binary_set_item(key, key)); - flush_command(&cmd, cc, 0, ii == 0); - execute(send_packet(&cmd)); - - if (cc == PROTOCOL_BINARY_CMD_FLUSH) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - } - else - execute(test_binary_noop()); - - raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0); - execute(send_packet(&cmd)); - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET, - PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)); - } - - return TEST_PASS; -} - -static enum test_return test_binary_flush(void) -{ - return test_binary_flush_impl("test_binary_flush", PROTOCOL_BINARY_CMD_FLUSH); -} - -static enum test_return test_binary_flushq(void) -{ - return test_binary_flush_impl("test_binary_flushq", PROTOCOL_BINARY_CMD_FLUSHQ); -} - -static enum test_return test_binary_concat_impl(const char *key, uint8_t cc) -{ - command cmd; - response rsp; - const char *value; - - if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ) - value="hello"; - else - value=" world"; - - execute(binary_set_item(key, value)); - - if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ) - value=" world"; - else - value="hello"; - - raw_command(&cmd, cc, key, strlen(key), value, strlen(value)); - execute(send_packet(&cmd)); - if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_PREPEND) - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); - } - else - execute(test_binary_noop()); - - raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0); - execute(send_packet(&cmd)); - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET, - PROTOCOL_BINARY_RESPONSE_SUCCESS)); - verify(rsp.plain.message.header.response.bodylen - 4 == 11); - verify(memcmp(rsp.bytes + 28, "hello world", 11) == 0); - - return TEST_PASS; -} - -static enum test_return test_binary_append(void) -{ - return test_binary_concat_impl("test_binary_append", PROTOCOL_BINARY_CMD_APPEND); -} - -static enum test_return test_binary_prepend(void) -{ - return test_binary_concat_impl("test_binary_prepend", PROTOCOL_BINARY_CMD_PREPEND); -} - -static enum test_return test_binary_appendq(void) -{ - return test_binary_concat_impl("test_binary_appendq", PROTOCOL_BINARY_CMD_APPENDQ); -} - -static enum test_return test_binary_prependq(void) -{ - return test_binary_concat_impl("test_binary_prependq", PROTOCOL_BINARY_CMD_PREPENDQ); -} - -static enum test_return test_binary_stat(void) -{ - command cmd; - response rsp; - - raw_command(&cmd, PROTOCOL_BINARY_CMD_STAT, NULL, 0, NULL, 0); - execute(send_packet(&cmd)); - - do - { - execute(recv_packet(&rsp)); - verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_STAT, - PROTOCOL_BINARY_RESPONSE_SUCCESS)); - } while (rsp.plain.message.header.response.keylen != 0); - - return TEST_PASS; -} - -static enum test_return send_string(const char *cmd) -{ - execute(retry_write(cmd, strlen(cmd))); - return TEST_PASS; -} - -static enum test_return receive_line(char *buffer, size_t size) -{ - size_t offset= 0; - while (offset < size) - { - execute(retry_read(buffer + offset, 1)); - if (buffer[offset] == '\n') - { - if (offset + 1 < size) - { - buffer[offset + 1]= '\0'; - return TEST_PASS; - } - else - return TEST_FAIL; - } - ++offset; - } - - return TEST_FAIL; -} - -static enum test_return receive_response(const char *msg) { - char buffer[80]; - execute(receive_line(buffer, sizeof(buffer))); - if (strcmp(msg, buffer) != 0) { - fprintf(stderr, "[%s]\n", buffer); - } - verify(strcmp(msg, buffer) == 0); - return TEST_PASS; -} - -static enum test_return receive_error_response(void) -{ - char buffer[80]; - execute(receive_line(buffer, sizeof(buffer))); - verify(strncmp(buffer, "ERROR", 5) == 0 || - strncmp(buffer, "CLIENT_ERROR", 12) == 0 || - strncmp(buffer, "SERVER_ERROR", 12) == 0); - return TEST_PASS; -} - -static enum test_return test_ascii_quit(void) -{ - /* Verify that quit handles unknown options */ - execute(send_string("quit foo bar\r\n")); - execute(receive_error_response()); - - /* quit doesn't support noreply */ - execute(send_string("quit noreply\r\n")); - execute(receive_error_response()); - - /* Verify that quit works */ - execute(send_string("quit\r\n")); - - /* Socket should be closed now, read should return EXIT_SUCCESS */ - char buffer[80]; - verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0); - return TEST_PASS_RECONNECT; - -} - -static enum test_return test_ascii_version(void) -{ - /* Verify that version command handles unknown options */ - execute(send_string("version foo bar\r\n")); - execute(receive_error_response()); - - /* version doesn't support noreply */ - execute(send_string("version noreply\r\n")); - execute(receive_error_response()); - - /* Verify that verify works */ - execute(send_string("version\r\n")); - char buffer[256]; - execute(receive_line(buffer, sizeof(buffer))); - verify(strncmp(buffer, "VERSION ", 8) == 0); - - return TEST_PASS; -} - -static enum test_return test_ascii_verbosity(void) -{ - /* This command does not adhere to the spec! */ - execute(send_string("verbosity foo bar my\r\n")); - execute(receive_error_response()); - - execute(send_string("verbosity noreply\r\n")); - execute(receive_error_response()); - - execute(send_string("verbosity 0 noreply\r\n")); - execute(test_ascii_version()); - - execute(send_string("verbosity\r\n")); - execute(receive_error_response()); - - execute(send_string("verbosity 1\r\n")); - execute(receive_response("OK\r\n")); - - execute(send_string("verbosity 0\r\n")); - execute(receive_response("OK\r\n")); - - return TEST_PASS; -} - - - -static enum test_return test_ascii_set_impl(const char* key, bool noreply) -{ - /* @todo add tests for bogus format! */ - char buffer[1024]; - snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : ""); - execute(send_string(buffer)); - - if (!noreply) - execute(receive_response("STORED\r\n")); - - return test_ascii_version(); -} - -static enum test_return test_ascii_set(void) -{ - return test_ascii_set_impl("test_ascii_set", false); -} - -static enum test_return test_ascii_set_noreply(void) -{ - return test_ascii_set_impl("test_ascii_set_noreply", true); -} - -static enum test_return test_ascii_add_impl(const char* key, bool noreply) -{ - /* @todo add tests for bogus format! */ - char buffer[1024]; - snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : ""); - execute(send_string(buffer)); - - if (!noreply) - execute(receive_response("STORED\r\n")); - - execute(send_string(buffer)); - - if (!noreply) - execute(receive_response("NOT_STORED\r\n")); - - return test_ascii_version(); -} - -static enum test_return test_ascii_add(void) -{ - return test_ascii_add_impl("test_ascii_add", false); -} - -static enum test_return test_ascii_add_noreply(void) -{ - return test_ascii_add_impl("test_ascii_add_noreply", true); -} - -static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata) -{ - char buffer[1024]; - - execute(receive_line(buffer, sizeof(buffer))); - verify(strncmp(buffer, "VALUE ", 6) == 0); - char *end= strchr(buffer + 6, ' '); - verify(end != NULL); - *end= '\0'; - *key= strdup(buffer + 6); - verify(*key != NULL); - char *ptr= end + 1; - - unsigned long val= strtoul(ptr, &end, 10); /* flags */ - verify(ptr != end); - verify(val == 0); - verify(end != NULL); - *ndata = (ssize_t)strtoul(end, &end, 10); /* size */ - verify(ptr != end); - verify(end != NULL); - while (*end != '\n' && isspace(*end)) - ++end; - verify(*end == '\n'); - - *value= malloc((size_t)*ndata); - verify(*value != NULL); - - execute(retry_read(*value, (size_t)*ndata)); - - execute(retry_read(buffer, 2)); - verify(memcmp(buffer, "\r\n", 2) == 0); - - return TEST_PASS; -} - -static enum test_return ascii_get_value(const char *key, const char *value) -{ - - char buffer[1024]; - size_t datasize= strlen(value); - - verify(datasize < sizeof(buffer)); - execute(receive_line(buffer, sizeof(buffer))); - verify(strncmp(buffer, "VALUE ", 6) == 0); - verify(strncmp(buffer + 6, key, strlen(key)) == 0); - char *ptr= buffer + 6 + strlen(key) + 1; - char *end; - - unsigned long val= strtoul(ptr, &end, 10); /* flags */ - verify(ptr != end); - verify(val == 0); - verify(end != NULL); - val= strtoul(end, &end, 10); /* size */ - verify(ptr != end); - verify(val == datasize); - verify(end != NULL); - while (*end != '\n' && isspace(*end)) - ++end; - verify(*end == '\n'); - - execute(retry_read(buffer, datasize)); - verify(memcmp(buffer, value, datasize) == 0); - - execute(retry_read(buffer, 2)); - verify(memcmp(buffer, "\r\n", 2) == 0); - - return TEST_PASS; -} - -static enum test_return ascii_get_item(const char *key, const char *value, - bool exist) -{ - char buffer[1024]; - size_t datasize= 0; - if (value != NULL) - datasize= strlen(value); - - verify(datasize < sizeof(buffer)); - snprintf(buffer, sizeof(buffer), "get %s\r\n", key); - execute(send_string(buffer)); - - if (exist) - execute(ascii_get_value(key, value)); - - execute(retry_read(buffer, 5)); - verify(memcmp(buffer, "END\r\n", 5) == 0); - - return TEST_PASS; -} - -static enum test_return ascii_gets_value(const char *key, const char *value, - unsigned long *cas) -{ - - char buffer[1024]; - size_t datasize= strlen(value); - - verify(datasize < sizeof(buffer)); - execute(receive_line(buffer, sizeof(buffer))); - verify(strncmp(buffer, "VALUE ", 6) == 0); - verify(strncmp(buffer + 6, key, strlen(key)) == 0); - char *ptr= buffer + 6 + strlen(key) + 1; - char *end; - - unsigned long val= strtoul(ptr, &end, 10); /* flags */ - verify(ptr != end); - verify(val == 0); - verify(end != NULL); - val= strtoul(end, &end, 10); /* size */ - verify(ptr != end); - verify(val == datasize); - verify(end != NULL); - *cas= strtoul(end, &end, 10); /* cas */ - verify(ptr != end); - verify(val == datasize); - verify(end != NULL); - - while (*end != '\n' && isspace(*end)) - ++end; - verify(*end == '\n'); - - execute(retry_read(buffer, datasize)); - verify(memcmp(buffer, value, datasize) == 0); - - execute(retry_read(buffer, 2)); - verify(memcmp(buffer, "\r\n", 2) == 0); - - return TEST_PASS; -} - -static enum test_return ascii_gets_item(const char *key, const char *value, - bool exist, unsigned long *cas) -{ - char buffer[1024]; - size_t datasize= 0; - if (value != NULL) - datasize= strlen(value); - - verify(datasize < sizeof(buffer)); - snprintf(buffer, sizeof(buffer), "gets %s\r\n", key); - execute(send_string(buffer)); - - if (exist) - execute(ascii_gets_value(key, value, cas)); - - execute(retry_read(buffer, 5)); - verify(memcmp(buffer, "END\r\n", 5) == 0); - - return TEST_PASS; -} - -static enum test_return ascii_set_item(const char *key, const char *value) -{ - char buffer[300]; - size_t len= strlen(value); - snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len); - execute(send_string(buffer)); - execute(retry_write(value, len)); - execute(send_string("\r\n")); - execute(receive_response("STORED\r\n")); - return TEST_PASS; -} - -static enum test_return test_ascii_replace_impl(const char* key, bool noreply) -{ - char buffer[1024]; - snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : ""); - execute(send_string(buffer)); - - if (noreply) - execute(test_ascii_version()); - else - execute(receive_response("NOT_STORED\r\n")); - - execute(ascii_set_item(key, "value")); - execute(ascii_get_item(key, "value", true)); - - - execute(send_string(buffer)); - - if (noreply) - execute(test_ascii_version()); - else - execute(receive_response("STORED\r\n")); - - return test_ascii_version(); -} - -static enum test_return test_ascii_replace(void) -{ - return test_ascii_replace_impl("test_ascii_replace", false); -} - -static enum test_return test_ascii_replace_noreply(void) -{ - return test_ascii_replace_impl("test_ascii_replace_noreply", true); -} - -static enum test_return test_ascii_cas_impl(const char* key, bool noreply) -{ - char buffer[1024]; - unsigned long cas; - - execute(ascii_set_item(key, "value")); - execute(ascii_gets_item(key, "value", true, &cas)); - - snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : ""); - execute(send_string(buffer)); - - if (noreply) - execute(test_ascii_version()); - else - execute(receive_response("STORED\r\n")); - - /* reexecute the same command should fail due to illegal cas */ - execute(send_string(buffer)); - - if (noreply) - execute(test_ascii_version()); - else - execute(receive_response("EXISTS\r\n")); - - return test_ascii_version(); -} - -static enum test_return test_ascii_cas(void) -{ - return test_ascii_cas_impl("test_ascii_cas", false); -} - -static enum test_return test_ascii_cas_noreply(void) -{ - return test_ascii_cas_impl("test_ascii_cas_noreply", true); -} - -static enum test_return test_ascii_delete_impl(const char *key, bool noreply) -{ - execute(ascii_set_item(key, "value")); - - execute(send_string("delete\r\n")); - execute(receive_error_response()); - /* BUG: the server accepts delete a b */ - execute(send_string("delete a b c d e\r\n")); - execute(receive_error_response()); - - char buffer[1024]; - snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : ""); - execute(send_string(buffer)); - - if (noreply) - execute(test_ascii_version()); - else - execute(receive_response("DELETED\r\n")); - - execute(ascii_get_item(key, "value", false)); - execute(send_string(buffer)); - if (noreply) - execute(test_ascii_version()); - else - execute(receive_response("NOT_FOUND\r\n")); - - return TEST_PASS; -} - -static enum test_return test_ascii_delete(void) -{ - return test_ascii_delete_impl("test_ascii_delete", false); -} - -static enum test_return test_ascii_delete_noreply(void) -{ - return test_ascii_delete_impl("test_ascii_delete_noreply", true); -} - -static enum test_return test_ascii_get(void) -{ - execute(ascii_set_item("test_ascii_get", "value")); - - execute(send_string("get\r\n")); - execute(receive_error_response()); - execute(ascii_get_item("test_ascii_get", "value", true)); - execute(ascii_get_item("test_ascii_get_notfound", "value", false)); - - return TEST_PASS; -} - -static enum test_return test_ascii_gets(void) -{ - execute(ascii_set_item("test_ascii_gets", "value")); - - execute(send_string("gets\r\n")); - execute(receive_error_response()); - unsigned long cas; - execute(ascii_gets_item("test_ascii_gets", "value", true, &cas)); - execute(ascii_gets_item("test_ascii_gets_notfound", "value", false, &cas)); - - return TEST_PASS; -} - -static enum test_return test_ascii_mget(void) -{ - const uint32_t nkeys= 5; - const char * const keys[]= { - "test_ascii_mget1", - "test_ascii_mget2", - /* test_ascii_mget_3 does not exist :) */ - "test_ascii_mget4", - "test_ascii_mget5", - "test_ascii_mget6" - }; - - for (uint32_t x= 0; x < nkeys; ++x) - execute(ascii_set_item(keys[x], "value")); - - /* Ask for a key that doesn't exist as well */ - execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 " - "test_ascii_mget4 test_ascii_mget5 " - "test_ascii_mget6\r\n")); - - char *returned[nkeys]; - - for (uint32_t x= 0; x < nkeys; ++x) - { - ssize_t nbytes = 0; - char *v= NULL; - execute(ascii_get_unknown_value(&returned[x], &v, &nbytes)); - verify(nbytes == 5); - verify(memcmp(v, "value", 5) == 0); - free(v); - } - - char buffer[5]; - execute(retry_read(buffer, 5)); - verify(memcmp(buffer, "END\r\n", 5) == 0); - - /* verify that we got all the keys we expected */ - for (uint32_t x= 0; x < nkeys; ++x) - { - bool found= false; - for (uint32_t y= 0; y < nkeys; ++y) - { - if (strcmp(keys[x], returned[y]) == 0) - { - found = true; - break; - } - } - verify(found); - } - - for (uint32_t x= 0; x < nkeys; ++x) - free(returned[x]); - - return TEST_PASS; -} - -static enum test_return test_ascii_incr_impl(const char* key, bool noreply) -{ - char cmd[300]; - snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : ""); - - execute(ascii_set_item(key, "0")); - for (int x= 1; x < 11; ++x) - { - execute(send_string(cmd)); - - if (noreply) - execute(test_ascii_version()); - else - { - char buffer[80]; - execute(receive_line(buffer, sizeof(buffer))); - int val= atoi(buffer); - verify(val == x); - } - } - - execute(ascii_get_item(key, "10", true)); - - return TEST_PASS; -} - -static enum test_return test_ascii_incr(void) -{ - return test_ascii_incr_impl("test_ascii_incr", false); -} - -static enum test_return test_ascii_incr_noreply(void) -{ - return test_ascii_incr_impl("test_ascii_incr_noreply", true); -} - -static enum test_return test_ascii_decr_impl(const char* key, bool noreply) -{ - char cmd[300]; - snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : ""); - - execute(ascii_set_item(key, "9")); - for (int x= 8; x > -1; --x) - { - execute(send_string(cmd)); - - if (noreply) - execute(test_ascii_version()); - else - { - char buffer[80]; - execute(receive_line(buffer, sizeof(buffer))); - int val= atoi(buffer); - verify(val == x); - } - } - - execute(ascii_get_item(key, "0", true)); - - /* verify that it doesn't wrap */ - execute(send_string(cmd)); - if (noreply) - execute(test_ascii_version()); - else - { - char buffer[80]; - execute(receive_line(buffer, sizeof(buffer))); - } - execute(ascii_get_item(key, "0", true)); - - return TEST_PASS; -} - -static enum test_return test_ascii_decr(void) -{ - return test_ascii_decr_impl("test_ascii_decr", false); -} - -static enum test_return test_ascii_decr_noreply(void) -{ - return test_ascii_decr_impl("test_ascii_decr_noreply", true); -} - - -static enum test_return test_ascii_flush_impl(const char *key, bool noreply) -{ -#if 0 - /* Verify that the flush_all command handles unknown options */ - /* Bug in the current memcached server! */ - execute(send_string("flush_all foo bar\r\n")); - execute(receive_error_response()); -#endif - - execute(ascii_set_item(key, key)); - execute(ascii_get_item(key, key, true)); - - if (noreply) - { - execute(send_string("flush_all noreply\r\n")); - execute(test_ascii_version()); - } - else - { - execute(send_string("flush_all\r\n")); - execute(receive_response("OK\r\n")); - } - - execute(ascii_get_item(key, key, false)); - - return TEST_PASS; -} - -static enum test_return test_ascii_flush(void) -{ - return test_ascii_flush_impl("test_ascii_flush", false); -} - -static enum test_return test_ascii_flush_noreply(void) -{ - return test_ascii_flush_impl("test_ascii_flush_noreply", true); -} - -static enum test_return test_ascii_concat_impl(const char *key, - bool append, - bool noreply) -{ - const char *value; - - if (append) - value="hello"; - else - value=" world"; - - execute(ascii_set_item(key, value)); - - if (append) - value=" world"; - else - value="hello"; - - char cmd[400]; - snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n", - append ? "append" : "prepend", - key, (unsigned int)strlen(value), noreply ? " noreply" : "", - value); - execute(send_string(cmd)); - - if (noreply) - execute(test_ascii_version()); - else - execute(receive_response("STORED\r\n")); - - execute(ascii_get_item(key, "hello world", true)); - - snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n", - append ? "append" : "prepend", - key, (unsigned int)strlen(value), noreply ? " noreply" : "", - value); - execute(send_string(cmd)); - - if (noreply) - execute(test_ascii_version()); - else - execute(receive_response("NOT_STORED\r\n")); - - return TEST_PASS; -} - -static enum test_return test_ascii_append(void) -{ - return test_ascii_concat_impl("test_ascii_append", true, false); -} - -static enum test_return test_ascii_prepend(void) -{ - return test_ascii_concat_impl("test_ascii_prepend", false, false); -} - -static enum test_return test_ascii_append_noreply(void) -{ - return test_ascii_concat_impl("test_ascii_append_noreply", true, true); -} - -static enum test_return test_ascii_prepend_noreply(void) -{ - return test_ascii_concat_impl("test_ascii_prepend_noreply", false, true); -} - -static enum test_return test_ascii_stat(void) -{ - execute(send_string("stats noreply\r\n")); - execute(receive_error_response()); - execute(send_string("stats\r\n")); - char buffer[1024]; - do { - execute(receive_line(buffer, sizeof(buffer))); - } while (strcmp(buffer, "END\r\n") != 0); - - return TEST_PASS_RECONNECT; -} - -typedef enum test_return(*TEST_FUNC)(void); - -struct testcase -{ - const char *description; - TEST_FUNC function; -}; - -struct testcase testcases[]= { - { "ascii quit", test_ascii_quit }, - { "ascii version", test_ascii_version }, - { "ascii verbosity", test_ascii_verbosity }, - { "ascii set", test_ascii_set }, - { "ascii set noreply", test_ascii_set_noreply }, - { "ascii get", test_ascii_get }, - { "ascii gets", test_ascii_gets }, - { "ascii mget", test_ascii_mget }, - { "ascii flush", test_ascii_flush }, - { "ascii flush noreply", test_ascii_flush_noreply }, - { "ascii add", test_ascii_add }, - { "ascii add noreply", test_ascii_add_noreply }, - { "ascii replace", test_ascii_replace }, - { "ascii replace noreply", test_ascii_replace_noreply }, - { "ascii cas", test_ascii_cas }, - { "ascii cas noreply", test_ascii_cas_noreply }, - { "ascii delete", test_ascii_delete }, - { "ascii delete noreply", test_ascii_delete_noreply }, - { "ascii incr", test_ascii_incr }, - { "ascii incr noreply", test_ascii_incr_noreply }, - { "ascii decr", test_ascii_decr }, - { "ascii decr noreply", test_ascii_decr_noreply }, - { "ascii append", test_ascii_append }, - { "ascii append noreply", test_ascii_append_noreply }, - { "ascii prepend", test_ascii_prepend }, - { "ascii prepend noreply", test_ascii_prepend_noreply }, - { "ascii stat", test_ascii_stat }, - { "binary noop", test_binary_noop }, - { "binary quit", test_binary_quit }, - { "binary quitq", test_binary_quitq }, - { "binary set", test_binary_set }, - { "binary setq", test_binary_setq }, - { "binary flush", test_binary_flush }, - { "binary flushq", test_binary_flushq }, - { "binary add", test_binary_add }, - { "binary addq", test_binary_addq }, - { "binary replace", test_binary_replace }, - { "binary replaceq", test_binary_replaceq }, - { "binary delete", test_binary_delete }, - { "binary deleteq", test_binary_deleteq }, - { "binary get", test_binary_get }, - { "binary getq", test_binary_getq }, - { "binary getk", test_binary_getk }, - { "binary getkq", test_binary_getkq }, - { "binary incr", test_binary_incr }, - { "binary incrq", test_binary_incrq }, - { "binary decr", test_binary_decr }, - { "binary decrq", test_binary_decrq }, - { "binary version", test_binary_version }, - { "binary append", test_binary_append }, - { "binary appendq", test_binary_appendq }, - { "binary prepend", test_binary_prepend }, - { "binary prependq", test_binary_prependq }, - { "binary stat", test_binary_stat }, - { NULL, NULL} -}; - -const int ascii_tests = 1; -const int binary_tests = 2; - -struct test_type_st -{ - bool ascii; - bool binary; -}; - -int main(int argc, char **argv) -{ - static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"}; - struct test_type_st tests= { true, true }; - int total= 0; - int failed= 0; - const char *hostname= "localhost"; - const char *port= "11211"; - int cmd; - bool prompt= false; - const char *testname= NULL; - - - - while ((cmd= getopt(argc, argv, "t:vch:p:PT:?ab")) != EOF) - { - switch (cmd) { - case 'a': - tests.ascii= true; - tests.binary= false; - break; - case 'b': - tests.ascii= false; - tests.binary= true; - break; - case 't': - timeout= atoi(optarg); - if (timeout == 0) - { - fprintf(stderr, "Invalid timeout. Please specify a number for -t\n"); - return EXIT_FAILURE; - } - break; - case 'v': verbose= true; - break; - case 'c': do_core= true; - break; - case 'h': hostname= optarg; - break; - case 'p': port= optarg; - break; - case 'P': prompt= true; - break; - case 'T': testname= optarg; - break; - default: - fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n" - "\t-c\tGenerate coredump if a test fails\n" - "\t-v\tVerbose test output (print out the assertion)\n" - "\t-t n\tSet the timeout for io-operations to n seconds\n" - "\t-P\tPrompt the user before starting a test.\n" - "\t\t\t\"skip\" will skip the test\n" - "\t\t\t\"quit\" will terminate memcapable\n" - "\t\t\tEverything else will start the test\n" - "\t-T n\tJust run the test named n\n" - "\t-a\tOnly test the ascii protocol\n" - "\t-b\tOnly test the binary protocol\n", - argv[0]); - return EXIT_FAILURE; - } - } - - initialize_sockets(); - sock= connect_server(hostname, port); - if (sock == INVALID_SOCKET) - { - fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", - hostname, port, strerror(get_socket_errno())); - return EXIT_FAILURE; - } - - for (int ii= 0; testcases[ii].description != NULL; ++ii) - { - if (testname != NULL && strcmp(testcases[ii].description, testname) != 0) - continue; - - if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) || - (testcases[ii].description[0] == 'b' && (tests.binary) == 0)) - { - continue; - } - ++total; - fprintf(stdout, "%-40s", testcases[ii].description); - fflush(stdout); - - if (prompt) - { - fprintf(stdout, "\nPress when you are ready? "); - char buffer[80] = {0}; - if (fgets(buffer, sizeof(buffer), stdin) != NULL) { - if (strncmp(buffer, "skip", 4) == 0) - { - fprintf(stdout, "%-40s%s\n", testcases[ii].description, - status_msg[TEST_SKIP]); - fflush(stdout); - continue; - } - if (strncmp(buffer, "quit", 4) == 0) - exit(0); - } - - fprintf(stdout, "%-40s", testcases[ii].description); - fflush(stdout); - } - - bool reconnect= false; - enum test_return ret= testcases[ii].function(); - if (ret == TEST_FAIL) - { - reconnect= true; - ++failed; - if (verbose) - fprintf(stderr, "\n"); - } - else if (ret == TEST_PASS_RECONNECT) - reconnect= true; - - fprintf(stderr, "%s\n", status_msg[ret]); - if (reconnect) - { - closesocket(sock); - if ((sock= connect_server(hostname, port)) == INVALID_SOCKET) - { - fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", - hostname, port, strerror(get_socket_errno())); - fprintf(stderr, "%d of %d tests failed\n", failed, total); - return EXIT_FAILURE; - } - } - } - - closesocket(sock); - if (failed == 0) - fprintf(stdout, "All tests passed\n"); - else - fprintf(stderr, "%d of %d tests failed\n", failed, total); - - return (failed == 0) ? 0 : 1; -} diff --git a/clients/memcapable.cc b/clients/memcapable.cc new file mode 100644 index 00000000..baac28b2 --- /dev/null +++ b/clients/memcapable.cc @@ -0,0 +1,2098 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ + +/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ +#undef NDEBUG + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "utilities.h" + +#ifdef linux +/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to + * optimize the conversion functions, but the prototypes generate warnings + * from gcc. The conversion methods isn't the bottleneck for my app, so + * just remove the warnings by undef'ing the optimization .. + */ +#undef ntohs +#undef ntohl +#endif + +/* Should we generate coredumps when we enounter an error (-c) */ +static bool do_core= false; +/* connection to the server */ +static memcached_socket_t sock; +/* Should the output from test failures be verbose or quiet? */ +static bool verbose= false; + +/* The number of seconds to wait for an IO-operation */ +static int timeout= 2; + +/* + * Instead of having to cast between the different datatypes we create + * a union of all of the different types of pacages we want to send. + * A lot of the different commands use the same packet layout, so I'll + * just define the different types I need. The typedefs only contain + * the header of the message, so we need some space for keys and body + * To avoid to have to do multiple writes, lets add a chunk of memory + * to use. 1k should be more than enough for header, key and body. + */ +typedef union +{ + protocol_binary_request_no_extras plain; + protocol_binary_request_flush flush; + protocol_binary_request_incr incr; + protocol_binary_request_set set; + char bytes[1024]; +} command; + +typedef union +{ + protocol_binary_response_no_extras plain; + protocol_binary_response_incr incr; + protocol_binary_response_decr decr; + char bytes[1024]; +} response; + +enum test_return +{ + TEST_SKIP, TEST_PASS, TEST_PASS_RECONNECT, TEST_FAIL +}; + +/** + * Try to get an addrinfo struct for a given port on a given host + */ +static struct addrinfo *lookuphost(const char *hostname, const char *port) +{ + struct addrinfo *ai= 0; + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family=AF_UNSPEC; + hints.ai_protocol=IPPROTO_TCP; + hints.ai_socktype=SOCK_STREAM; + + int error= getaddrinfo(hostname, port, &hints, &ai); + if (error != 0) + { + if (error != EAI_SYSTEM) + fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error)); + else + perror("getaddrinfo()"); + } + + return ai; +} + +/** + * Set the socket in nonblocking mode + * @return -1 if failure, the socket otherwise + */ +static memcached_socket_t set_noblock(void) +{ +#ifdef WIN32 + u_long arg = 1; + if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR) + { + perror("Failed to set nonblocking io"); + closesocket(sock); + return INVALID_SOCKET; + } +#else + int flags= fcntl(sock, F_GETFL, 0); + if (flags == -1) + { + perror("Failed to get socket flags"); + closesocket(sock); + return INVALID_SOCKET; + } + + if ((flags & O_NONBLOCK) != O_NONBLOCK) + { + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) + { + perror("Failed to set socket to nonblocking mode"); + closesocket(sock); + return INVALID_SOCKET; + } + } +#endif + return sock; +} + +/** + * Try to open a connection to the server + * @param hostname the name of the server to connect to + * @param port the port number (or service) to connect to + * @return positive integer if success, -1 otherwise + */ +static memcached_socket_t connect_server(const char *hostname, const char *port) +{ + struct addrinfo *ai= lookuphost(hostname, port); + sock= INVALID_SOCKET; + if (ai != NULL) + { + if ((sock= socket(ai->ai_family, ai->ai_socktype, + ai->ai_protocol)) != INVALID_SOCKET) + { + if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR) + { + fprintf(stderr, "Failed to connect socket: %s\n", + strerror(get_socket_errno())); + closesocket(sock); + sock= INVALID_SOCKET; + } + else + { + sock= set_noblock(); + } + } + else + fprintf(stderr, "Failed to create socket: %s\n", + strerror(get_socket_errno())); + + freeaddrinfo(ai); + } + + return sock; +} + +static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len) +{ + ssize_t ret; + + if (direction == POLLOUT) + { + ret= send(fd, buf, len, 0); + } + else + { + ret= recv(fd, buf, len, 0); + } + + if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK) + { + struct pollfd fds; + memset(&fds, 0, sizeof(struct pollfd)); + fds.events= direction; + fds.fd= fd; + + int err= poll(&fds, 1, timeout * 1000); + if (err == 1) + { + if (direction == POLLOUT) + { + ret= send(fd, buf, len, 0); + } + else + { + ret= recv(fd, buf, len, 0); + } + } + else if (err == 0) + { + errno= ETIMEDOUT; + } + else + { + perror("Failed to poll"); + return -1; + } + } + + return ret; +} + +/** + * Ensure that an expression is true. If it isn't print out a message similar + * to assert() and create a coredump if the user wants that. If not an error + * message is returned. + * + */ +static enum test_return ensure(bool val, const char *expression, const char *file, int line) +{ + if (!val) + { + if (verbose) + fprintf(stderr, "\n%s:%d: %s", file, line, expression); + + if (do_core) + abort(); + + return TEST_FAIL; + } + + return TEST_PASS; +} + +#define verify(expression) do { if (ensure(expression, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0) +#define execute(expression) do { if (ensure(expression == TEST_PASS, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0) + +/** + * Send a chunk of memory over the socket (retry if the call is iterrupted + */ +static enum test_return retry_write(const void* buf, size_t len) +{ + size_t offset= 0; + const char* ptr= static_cast(buf); + + do + { + size_t num_bytes= len - offset; + ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes); + if (nw == -1) + verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN); + else + offset+= (size_t)nw; + } while (offset < len); + + return TEST_PASS; +} + +/** + * Resend a packet to the server (All fields in the command header should + * be in network byte order) + */ +static enum test_return resend_packet(command *cmd) +{ + size_t length= sizeof (protocol_binary_request_no_extras) + + ntohl(cmd->plain.message.header.request.bodylen); + + execute(retry_write(cmd, length)); + return TEST_PASS; +} + +/** + * Send a command to the server. The command header needs to be updated + * to network byte order + */ +static enum test_return send_packet(command *cmd) +{ + /* Fix the byteorder of the header */ + cmd->plain.message.header.request.keylen= + ntohs(cmd->plain.message.header.request.keylen); + cmd->plain.message.header.request.bodylen= + ntohl(cmd->plain.message.header.request.bodylen); + cmd->plain.message.header.request.cas= + ntohll(cmd->plain.message.header.request.cas); + + execute(resend_packet(cmd)); + return TEST_PASS; +} + +/** + * Read a fixed length chunk of data from the server + */ +static enum test_return retry_read(void *buf, size_t len) +{ + size_t offset= 0; + do + { + ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset); + switch (nr) { + case -1 : + fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno)); + verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN); + break; + case 0: + return TEST_FAIL; + default: + offset+= (size_t)nr; + } + } while (offset < len); + + return TEST_PASS; +} + +/** + * Receive a response from the server and conver the fields in the header + * to local byte order + */ +static enum test_return recv_packet(response *rsp) +{ + execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras))); + + /* Fix the byte order in the packet header */ + rsp->plain.message.header.response.keylen= + ntohs(rsp->plain.message.header.response.keylen); + rsp->plain.message.header.response.status= + ntohs(rsp->plain.message.header.response.status); + rsp->plain.message.header.response.bodylen= + ntohl(rsp->plain.message.header.response.bodylen); + rsp->plain.message.header.response.cas= + ntohll(rsp->plain.message.header.response.cas); + + size_t bodysz= rsp->plain.message.header.response.bodylen; + if (bodysz > 0) + execute(retry_read(rsp->bytes + sizeof (protocol_binary_response_no_extras), bodysz)); + + return TEST_PASS; +} + +/** + * Create a storage command (add, set, replace etc) + * + * @param cmd destination buffer + * @param cc the storage command to create + * @param key the key to store + * @param keylen the length of the key + * @param dta the data to store with the key + * @param dtalen the length of the data to store with the key + * @param flags the flags to store along with the key + * @param exptime the expiry time for the key + */ +static void storage_command(command *cmd, + uint8_t cc, + const void* key, + size_t keylen, + const void* dta, + size_t dtalen, + uint32_t flags, + uint32_t exptime) +{ + /* all of the storage commands use the same command layout */ + protocol_binary_request_set *request= &cmd->set; + + memset(request, 0, sizeof (*request)); + request->message.header.request.magic= PROTOCOL_BINARY_REQ; + request->message.header.request.opcode= cc; + request->message.header.request.keylen= (uint16_t)keylen; + request->message.header.request.extlen= 8; + request->message.header.request.bodylen= (uint32_t)(keylen + 8 + dtalen); + request->message.header.request.opaque= 0xdeadbeef; + request->message.body.flags= flags; + request->message.body.expiration= exptime; + + off_t key_offset= sizeof (protocol_binary_request_no_extras) + 8; + memcpy(cmd->bytes + key_offset, key, keylen); + if (dta != NULL) + memcpy(cmd->bytes + key_offset + keylen, dta, dtalen); +} + +/** + * Create a basic command to send to the server + * @param cmd destination buffer + * @param cc the command to create + * @param key the key to store + * @param keylen the length of the key + * @param dta the data to store with the key + * @param dtalen the length of the data to store with the key + */ +static void raw_command(command *cmd, + uint8_t cc, + const void* key, + size_t keylen, + const void* dta, + size_t dtalen) +{ + /* all of the storage commands use the same command layout */ + memset(cmd, 0, sizeof (*cmd)); + cmd->plain.message.header.request.magic= PROTOCOL_BINARY_REQ; + cmd->plain.message.header.request.opcode= cc; + cmd->plain.message.header.request.keylen= (uint16_t)keylen; + cmd->plain.message.header.request.bodylen= (uint32_t)(keylen + dtalen); + cmd->plain.message.header.request.opaque= 0xdeadbeef; + + off_t key_offset= sizeof (protocol_binary_request_no_extras); + + if (key != NULL) + memcpy(cmd->bytes + key_offset, key, keylen); + + if (dta != NULL) + memcpy(cmd->bytes + key_offset + keylen, dta, dtalen); +} + +/** + * Create the flush command + * @param cmd destination buffer + * @param cc the command to create (FLUSH/FLUSHQ) + * @param exptime when to flush + * @param use_extra to force using of the extra field? + */ +static void flush_command(command *cmd, + uint8_t cc, uint32_t exptime, bool use_extra) +{ + memset(cmd, 0, sizeof (cmd->flush)); + cmd->flush.message.header.request.magic= PROTOCOL_BINARY_REQ; + cmd->flush.message.header.request.opcode= cc; + cmd->flush.message.header.request.opaque= 0xdeadbeef; + + if (exptime != 0 || use_extra) + { + cmd->flush.message.header.request.extlen= 4; + cmd->flush.message.body.expiration= htonl(exptime); + cmd->flush.message.header.request.bodylen= 4; + } +} + +/** + * Create a incr/decr command + * @param cc the cmd to create (FLUSH/FLUSHQ) + * @param key the key to operate on + * @param keylen the number of bytes in the key + * @param delta the number to add/subtract + * @param initial the initial value if the key doesn't exist + * @param exptime when the key should expire if it isn't set + */ +static void arithmetic_command(command *cmd, + uint8_t cc, + const void* key, + size_t keylen, + uint64_t delta, + uint64_t initial, + uint32_t exptime) +{ + memset(cmd, 0, sizeof (cmd->incr)); + cmd->incr.message.header.request.magic= PROTOCOL_BINARY_REQ; + cmd->incr.message.header.request.opcode= cc; + cmd->incr.message.header.request.keylen= (uint16_t)keylen; + cmd->incr.message.header.request.extlen= 20; + cmd->incr.message.header.request.bodylen= (uint32_t)(keylen + 20); + cmd->incr.message.header.request.opaque= 0xdeadbeef; + cmd->incr.message.body.delta= htonll(delta); + cmd->incr.message.body.initial= htonll(initial); + cmd->incr.message.body.expiration= htonl(exptime); + + off_t key_offset= sizeof (protocol_binary_request_no_extras) + 20; + memcpy(cmd->bytes + key_offset, key, keylen); +} + +/** + * Validate the response header from the server + * @param rsp the response to check + * @param cc the expected command + * @param status the expected status + */ +static enum test_return do_validate_response_header(response *rsp, + uint8_t cc, uint16_t status) +{ + verify(rsp->plain.message.header.response.magic == PROTOCOL_BINARY_RES); + verify(rsp->plain.message.header.response.opcode == cc); + verify(rsp->plain.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES); + verify(rsp->plain.message.header.response.status == status); + verify(rsp->plain.message.header.response.opaque == 0xdeadbeef); + + if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) + { + switch (cc) { + case PROTOCOL_BINARY_CMD_ADDQ: + case PROTOCOL_BINARY_CMD_APPENDQ: + case PROTOCOL_BINARY_CMD_DECREMENTQ: + case PROTOCOL_BINARY_CMD_DELETEQ: + case PROTOCOL_BINARY_CMD_FLUSHQ: + case PROTOCOL_BINARY_CMD_INCREMENTQ: + case PROTOCOL_BINARY_CMD_PREPENDQ: + case PROTOCOL_BINARY_CMD_QUITQ: + case PROTOCOL_BINARY_CMD_REPLACEQ: + case PROTOCOL_BINARY_CMD_SETQ: + verify("Quiet command shouldn't return on success" == NULL); + default: + break; + } + + switch (cc) { + case PROTOCOL_BINARY_CMD_ADD: + case PROTOCOL_BINARY_CMD_REPLACE: + case PROTOCOL_BINARY_CMD_SET: + case PROTOCOL_BINARY_CMD_APPEND: + case PROTOCOL_BINARY_CMD_PREPEND: + verify(rsp->plain.message.header.response.keylen == 0); + verify(rsp->plain.message.header.response.extlen == 0); + verify(rsp->plain.message.header.response.bodylen == 0); + verify(rsp->plain.message.header.response.cas != 0); + break; + case PROTOCOL_BINARY_CMD_FLUSH: + case PROTOCOL_BINARY_CMD_NOOP: + case PROTOCOL_BINARY_CMD_QUIT: + case PROTOCOL_BINARY_CMD_DELETE: + verify(rsp->plain.message.header.response.keylen == 0); + verify(rsp->plain.message.header.response.extlen == 0); + verify(rsp->plain.message.header.response.bodylen == 0); + verify(rsp->plain.message.header.response.cas == 0); + break; + + case PROTOCOL_BINARY_CMD_DECREMENT: + case PROTOCOL_BINARY_CMD_INCREMENT: + verify(rsp->plain.message.header.response.keylen == 0); + verify(rsp->plain.message.header.response.extlen == 0); + verify(rsp->plain.message.header.response.bodylen == 8); + verify(rsp->plain.message.header.response.cas != 0); + break; + + case PROTOCOL_BINARY_CMD_STAT: + verify(rsp->plain.message.header.response.extlen == 0); + /* key and value exists in all packets except in the terminating */ + verify(rsp->plain.message.header.response.cas == 0); + break; + + case PROTOCOL_BINARY_CMD_VERSION: + verify(rsp->plain.message.header.response.keylen == 0); + verify(rsp->plain.message.header.response.extlen == 0); + verify(rsp->plain.message.header.response.bodylen != 0); + verify(rsp->plain.message.header.response.cas == 0); + break; + + case PROTOCOL_BINARY_CMD_GET: + case PROTOCOL_BINARY_CMD_GETQ: + verify(rsp->plain.message.header.response.keylen == 0); + verify(rsp->plain.message.header.response.extlen == 4); + verify(rsp->plain.message.header.response.cas != 0); + break; + + case PROTOCOL_BINARY_CMD_GETK: + case PROTOCOL_BINARY_CMD_GETKQ: + verify(rsp->plain.message.header.response.keylen != 0); + verify(rsp->plain.message.header.response.extlen == 4); + verify(rsp->plain.message.header.response.cas != 0); + break; + + default: + /* Undefined command code */ + break; + } + } + else + { + verify(rsp->plain.message.header.response.cas == 0); + verify(rsp->plain.message.header.response.extlen == 0); + if (cc != PROTOCOL_BINARY_CMD_GETK) + { + verify(rsp->plain.message.header.response.keylen == 0); + } + } + + return TEST_PASS; +} + +/* We call verify(validate_response_header), but that macro + * expects a boolean expression, and the function returns + * an enum.... Let's just create a macro to avoid cluttering + * the code with all of the == TEST_PASS ;-) + */ +#define validate_response_header(a,b,c) \ + do_validate_response_header(a,b,c) == TEST_PASS + + +static enum test_return send_binary_noop(void) +{ + command cmd; + raw_command(&cmd, PROTOCOL_BINARY_CMD_NOOP, NULL, 0, NULL, 0); + execute(send_packet(&cmd)); + return TEST_PASS; +} + +static enum test_return receive_binary_noop(void) +{ + response rsp; + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_NOOP, + PROTOCOL_BINARY_RESPONSE_SUCCESS)); + return TEST_PASS; +} + +static enum test_return test_binary_noop(void) +{ + execute(send_binary_noop()); + execute(receive_binary_noop()); + return TEST_PASS; +} + +static enum test_return test_binary_quit_impl(uint8_t cc) +{ + command cmd; + response rsp; + raw_command(&cmd, cc, NULL, 0, NULL, 0); + + execute(send_packet(&cmd)); + if (cc == PROTOCOL_BINARY_CMD_QUIT) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_QUIT, + PROTOCOL_BINARY_RESPONSE_SUCCESS)); + } + + /* Socket should be closed now, read should return EXIT_SUCCESS */ + verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0); + + return TEST_PASS_RECONNECT; +} + +static enum test_return test_binary_quit(void) +{ + return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT); +} + +static enum test_return test_binary_quitq(void) +{ + return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ); +} + +static enum test_return test_binary_set_impl(const char* key, uint8_t cc) +{ + command cmd; + response rsp; + + uint64_t value= 0xdeadbeefdeadcafe; + storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0); + + /* set should always work */ + for (int ii= 0; ii < 10; ii++) + { + if (ii == 0) + execute(send_packet(&cmd)); + else + execute(resend_packet(&cmd)); + + if (cc == PROTOCOL_BINARY_CMD_SET) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + } + else + execute(test_binary_noop()); + } + + /* + * We need to get the current CAS id, and at this time we haven't + * verified that we have a working get + */ + if (cc == PROTOCOL_BINARY_CMD_SETQ) + { + cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET; + execute(resend_packet(&cmd)); + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET, + PROTOCOL_BINARY_RESPONSE_SUCCESS)); + cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ; + } + + /* try to set with the correct CAS value */ + cmd.plain.message.header.request.cas= + htonll(rsp.plain.message.header.response.cas); + execute(resend_packet(&cmd)); + if (cc == PROTOCOL_BINARY_CMD_SET) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + } + else + execute(test_binary_noop()); + + /* try to set with an incorrect CAS value */ + cmd.plain.message.header.request.cas= + htonll(rsp.plain.message.header.response.cas - 1); + execute(resend_packet(&cmd)); + execute(send_binary_noop()); + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS)); + execute(receive_binary_noop()); + + return TEST_PASS; +} + +static enum test_return test_binary_set(void) +{ + return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET); +} + +static enum test_return test_binary_setq(void) +{ + return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ); +} + +static enum test_return test_binary_add_impl(const char* key, uint8_t cc) +{ + command cmd; + response rsp; + uint64_t value= 0xdeadbeefdeadcafe; + storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0); + + /* first add should work, rest of them should fail (even with cas + as wildcard */ + for (int ii=0; ii < 10; ii++) + { + if (ii == 0) + execute(send_packet(&cmd)); + else + execute(resend_packet(&cmd)); + + if (cc == PROTOCOL_BINARY_CMD_ADD || ii > 0) + { + uint16_t expected_result; + if (ii == 0) + expected_result= PROTOCOL_BINARY_RESPONSE_SUCCESS; + else + expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS; + + execute(send_binary_noop()); + execute(recv_packet(&rsp)); + execute(receive_binary_noop()); + verify(validate_response_header(&rsp, cc, expected_result)); + } + else + execute(test_binary_noop()); + } + + return TEST_PASS; +} + +static enum test_return test_binary_add(void) +{ + return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD); +} + +static enum test_return test_binary_addq(void) +{ + return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ); +} + +static enum test_return binary_set_item(const char *key, const char *value) +{ + command cmd; + response rsp; + storage_command(&cmd, PROTOCOL_BINARY_CMD_SET, key, strlen(key), + value, strlen(value), 0, 0); + execute(send_packet(&cmd)); + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET, + PROTOCOL_BINARY_RESPONSE_SUCCESS)); + return TEST_PASS; +} + +static enum test_return test_binary_replace_impl(const char* key, uint8_t cc) +{ + command cmd; + response rsp; + uint64_t value= 0xdeadbeefdeadcafe; + storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0); + + /* first replace should fail, successive should succeed (when the + item is added! */ + for (int ii= 0; ii < 10; ii++) + { + if (ii == 0) + execute(send_packet(&cmd)); + else + execute(resend_packet(&cmd)); + + if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0) + { + uint16_t expected_result; + if (ii == 0) + expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT; + else + expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS; + + execute(send_binary_noop()); + execute(recv_packet(&rsp)); + execute(receive_binary_noop()); + verify(validate_response_header(&rsp, cc, expected_result)); + + if (ii == 0) + execute(binary_set_item(key, key)); + } + else + execute(test_binary_noop()); + } + + /* verify that replace with CAS value works! */ + cmd.plain.message.header.request.cas= + htonll(rsp.plain.message.header.response.cas); + execute(resend_packet(&cmd)); + + if (cc == PROTOCOL_BINARY_CMD_REPLACE) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + } + else + execute(test_binary_noop()); + + /* try to set with an incorrect CAS value */ + cmd.plain.message.header.request.cas= + htonll(rsp.plain.message.header.response.cas - 1); + execute(resend_packet(&cmd)); + execute(send_binary_noop()); + execute(recv_packet(&rsp)); + execute(receive_binary_noop()); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS)); + + return TEST_PASS; +} + +static enum test_return test_binary_replace(void) +{ + return test_binary_replace_impl("test_binary_replace", PROTOCOL_BINARY_CMD_REPLACE); +} + +static enum test_return test_binary_replaceq(void) +{ + return test_binary_replace_impl("test_binary_replaceq", PROTOCOL_BINARY_CMD_REPLACEQ); +} + +static enum test_return test_binary_delete_impl(const char *key, uint8_t cc) +{ + command cmd; + response rsp; + raw_command(&cmd, cc, key, strlen(key), NULL, 0); + + /* The delete shouldn't work the first time, because the item isn't there */ + execute(send_packet(&cmd)); + execute(send_binary_noop()); + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)); + execute(receive_binary_noop()); + execute(binary_set_item(key, key)); + + /* The item should be present now, resend*/ + execute(resend_packet(&cmd)); + if (cc == PROTOCOL_BINARY_CMD_DELETE) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + } + + execute(test_binary_noop()); + + return TEST_PASS; +} + +static enum test_return test_binary_delete(void) +{ + return test_binary_delete_impl("test_binary_delete", PROTOCOL_BINARY_CMD_DELETE); +} + +static enum test_return test_binary_deleteq(void) +{ + return test_binary_delete_impl("test_binary_deleteq", PROTOCOL_BINARY_CMD_DELETEQ); +} + +static enum test_return test_binary_get_impl(const char *key, uint8_t cc) +{ + command cmd; + response rsp; + + raw_command(&cmd, cc, key, strlen(key), NULL, 0); + execute(send_packet(&cmd)); + execute(send_binary_noop()); + + if (cc == PROTOCOL_BINARY_CMD_GET || cc == PROTOCOL_BINARY_CMD_GETK) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)); + } + + execute(receive_binary_noop()); + + execute(binary_set_item(key, key)); + execute(resend_packet(&cmd)); + execute(send_binary_noop()); + + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + execute(receive_binary_noop()); + + return TEST_PASS; +} + +static enum test_return test_binary_get(void) +{ + return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET); +} + +static enum test_return test_binary_getk(void) +{ + return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK); +} + +static enum test_return test_binary_getq(void) +{ + return test_binary_get_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ); +} + +static enum test_return test_binary_getkq(void) +{ + return test_binary_get_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ); +} + +static enum test_return test_binary_incr_impl(const char* key, uint8_t cc) +{ + command cmd; + response rsp; + arithmetic_command(&cmd, cc, key, strlen(key), 1, 0, 0); + + uint64_t ii; + for (ii= 0; ii < 10; ++ii) + { + if (ii == 0) + execute(send_packet(&cmd)); + else + execute(resend_packet(&cmd)); + + if (cc == PROTOCOL_BINARY_CMD_INCREMENT) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + verify(ntohll(rsp.incr.message.body.value) == ii); + } + else + execute(test_binary_noop()); + } + + /* @todo add incorrect CAS */ + return TEST_PASS; +} + +static enum test_return test_binary_incr(void) +{ + return test_binary_incr_impl("test_binary_incr", PROTOCOL_BINARY_CMD_INCREMENT); +} + +static enum test_return test_binary_incrq(void) +{ + return test_binary_incr_impl("test_binary_incrq", PROTOCOL_BINARY_CMD_INCREMENTQ); +} + +static enum test_return test_binary_decr_impl(const char* key, uint8_t cc) +{ + command cmd; + response rsp; + arithmetic_command(&cmd, cc, key, strlen(key), 1, 9, 0); + + int ii; + for (ii= 9; ii > -1; --ii) + { + if (ii == 9) + execute(send_packet(&cmd)); + else + execute(resend_packet(&cmd)); + + if (cc == PROTOCOL_BINARY_CMD_DECREMENT) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + verify(ntohll(rsp.decr.message.body.value) == (uint64_t)ii); + } + else + execute(test_binary_noop()); + } + + /* decr 0 should not wrap */ + execute(resend_packet(&cmd)); + if (cc == PROTOCOL_BINARY_CMD_DECREMENT) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + verify(ntohll(rsp.decr.message.body.value) == 0); + } + else + { + /* @todo get the value and verify! */ + + } + + /* @todo add incorrect cas */ + execute(test_binary_noop()); + return TEST_PASS; +} + +static enum test_return test_binary_decr(void) +{ + return test_binary_decr_impl("test_binary_decr", + PROTOCOL_BINARY_CMD_DECREMENT); +} + +static enum test_return test_binary_decrq(void) +{ + return test_binary_decr_impl("test_binary_decrq", + PROTOCOL_BINARY_CMD_DECREMENTQ); +} + +static enum test_return test_binary_version(void) +{ + command cmd; + response rsp; + raw_command(&cmd, PROTOCOL_BINARY_CMD_VERSION, NULL, 0, NULL, 0); + + execute(send_packet(&cmd)); + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_VERSION, + PROTOCOL_BINARY_RESPONSE_SUCCESS)); + + return TEST_PASS; +} + +static enum test_return test_binary_flush_impl(const char *key, uint8_t cc) +{ + command cmd; + response rsp; + + for (int ii= 0; ii < 2; ++ii) + { + execute(binary_set_item(key, key)); + flush_command(&cmd, cc, 0, ii == 0); + execute(send_packet(&cmd)); + + if (cc == PROTOCOL_BINARY_CMD_FLUSH) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + } + else + execute(test_binary_noop()); + + raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0); + execute(send_packet(&cmd)); + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET, + PROTOCOL_BINARY_RESPONSE_KEY_ENOENT)); + } + + return TEST_PASS; +} + +static enum test_return test_binary_flush(void) +{ + return test_binary_flush_impl("test_binary_flush", PROTOCOL_BINARY_CMD_FLUSH); +} + +static enum test_return test_binary_flushq(void) +{ + return test_binary_flush_impl("test_binary_flushq", PROTOCOL_BINARY_CMD_FLUSHQ); +} + +static enum test_return test_binary_concat_impl(const char *key, uint8_t cc) +{ + command cmd; + response rsp; + const char *value; + + if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ) + value="hello"; + else + value=" world"; + + execute(binary_set_item(key, value)); + + if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ) + value=" world"; + else + value="hello"; + + raw_command(&cmd, cc, key, strlen(key), value, strlen(value)); + execute(send_packet(&cmd)); + if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_PREPEND) + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); + } + else + execute(test_binary_noop()); + + raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0); + execute(send_packet(&cmd)); + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET, + PROTOCOL_BINARY_RESPONSE_SUCCESS)); + verify(rsp.plain.message.header.response.bodylen - 4 == 11); + verify(memcmp(rsp.bytes + 28, "hello world", 11) == 0); + + return TEST_PASS; +} + +static enum test_return test_binary_append(void) +{ + return test_binary_concat_impl("test_binary_append", PROTOCOL_BINARY_CMD_APPEND); +} + +static enum test_return test_binary_prepend(void) +{ + return test_binary_concat_impl("test_binary_prepend", PROTOCOL_BINARY_CMD_PREPEND); +} + +static enum test_return test_binary_appendq(void) +{ + return test_binary_concat_impl("test_binary_appendq", PROTOCOL_BINARY_CMD_APPENDQ); +} + +static enum test_return test_binary_prependq(void) +{ + return test_binary_concat_impl("test_binary_prependq", PROTOCOL_BINARY_CMD_PREPENDQ); +} + +static enum test_return test_binary_stat(void) +{ + command cmd; + response rsp; + + raw_command(&cmd, PROTOCOL_BINARY_CMD_STAT, NULL, 0, NULL, 0); + execute(send_packet(&cmd)); + + do + { + execute(recv_packet(&rsp)); + verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_STAT, + PROTOCOL_BINARY_RESPONSE_SUCCESS)); + } while (rsp.plain.message.header.response.keylen != 0); + + return TEST_PASS; +} + +static enum test_return send_string(const char *cmd) +{ + execute(retry_write(cmd, strlen(cmd))); + return TEST_PASS; +} + +static enum test_return receive_line(char *buffer, size_t size) +{ + size_t offset= 0; + while (offset < size) + { + execute(retry_read(buffer + offset, 1)); + if (buffer[offset] == '\n') + { + if (offset + 1 < size) + { + buffer[offset + 1]= '\0'; + return TEST_PASS; + } + else + return TEST_FAIL; + } + ++offset; + } + + return TEST_FAIL; +} + +static enum test_return receive_response(const char *msg) { + char buffer[80]; + execute(receive_line(buffer, sizeof(buffer))); + if (strcmp(msg, buffer) != 0) { + fprintf(stderr, "[%s]\n", buffer); + } + verify(strcmp(msg, buffer) == 0); + return TEST_PASS; +} + +static enum test_return receive_error_response(void) +{ + char buffer[80]; + execute(receive_line(buffer, sizeof(buffer))); + verify(strncmp(buffer, "ERROR", 5) == 0 || + strncmp(buffer, "CLIENT_ERROR", 12) == 0 || + strncmp(buffer, "SERVER_ERROR", 12) == 0); + return TEST_PASS; +} + +static enum test_return test_ascii_quit(void) +{ + /* Verify that quit handles unknown options */ + execute(send_string("quit foo bar\r\n")); + execute(receive_error_response()); + + /* quit doesn't support noreply */ + execute(send_string("quit noreply\r\n")); + execute(receive_error_response()); + + /* Verify that quit works */ + execute(send_string("quit\r\n")); + + /* Socket should be closed now, read should return EXIT_SUCCESS */ + char buffer[80]; + verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0); + return TEST_PASS_RECONNECT; + +} + +static enum test_return test_ascii_version(void) +{ + /* Verify that version command handles unknown options */ + execute(send_string("version foo bar\r\n")); + execute(receive_error_response()); + + /* version doesn't support noreply */ + execute(send_string("version noreply\r\n")); + execute(receive_error_response()); + + /* Verify that verify works */ + execute(send_string("version\r\n")); + char buffer[256]; + execute(receive_line(buffer, sizeof(buffer))); + verify(strncmp(buffer, "VERSION ", 8) == 0); + + return TEST_PASS; +} + +static enum test_return test_ascii_verbosity(void) +{ + /* This command does not adhere to the spec! */ + execute(send_string("verbosity foo bar my\r\n")); + execute(receive_error_response()); + + execute(send_string("verbosity noreply\r\n")); + execute(receive_error_response()); + + execute(send_string("verbosity 0 noreply\r\n")); + execute(test_ascii_version()); + + execute(send_string("verbosity\r\n")); + execute(receive_error_response()); + + execute(send_string("verbosity 1\r\n")); + execute(receive_response("OK\r\n")); + + execute(send_string("verbosity 0\r\n")); + execute(receive_response("OK\r\n")); + + return TEST_PASS; +} + + + +static enum test_return test_ascii_set_impl(const char* key, bool noreply) +{ + /* @todo add tests for bogus format! */ + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : ""); + execute(send_string(buffer)); + + if (!noreply) + execute(receive_response("STORED\r\n")); + + return test_ascii_version(); +} + +static enum test_return test_ascii_set(void) +{ + return test_ascii_set_impl("test_ascii_set", false); +} + +static enum test_return test_ascii_set_noreply(void) +{ + return test_ascii_set_impl("test_ascii_set_noreply", true); +} + +static enum test_return test_ascii_add_impl(const char* key, bool noreply) +{ + /* @todo add tests for bogus format! */ + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : ""); + execute(send_string(buffer)); + + if (!noreply) + execute(receive_response("STORED\r\n")); + + execute(send_string(buffer)); + + if (!noreply) + execute(receive_response("NOT_STORED\r\n")); + + return test_ascii_version(); +} + +static enum test_return test_ascii_add(void) +{ + return test_ascii_add_impl("test_ascii_add", false); +} + +static enum test_return test_ascii_add_noreply(void) +{ + return test_ascii_add_impl("test_ascii_add_noreply", true); +} + +static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata) +{ + char buffer[1024]; + + execute(receive_line(buffer, sizeof(buffer))); + verify(strncmp(buffer, "VALUE ", 6) == 0); + char *end= strchr(buffer + 6, ' '); + verify(end != NULL); + *end= '\0'; + *key= strdup(buffer + 6); + verify(*key != NULL); + char *ptr= end + 1; + + unsigned long val= strtoul(ptr, &end, 10); /* flags */ + verify(ptr != end); + verify(val == 0); + verify(end != NULL); + *ndata = (ssize_t)strtoul(end, &end, 10); /* size */ + verify(ptr != end); + verify(end != NULL); + while (*end != '\n' && isspace(*end)) + ++end; + verify(*end == '\n'); + + *value= static_cast(malloc((size_t)*ndata)); + verify(*value != NULL); + + execute(retry_read(*value, (size_t)*ndata)); + + execute(retry_read(buffer, 2)); + verify(memcmp(buffer, "\r\n", 2) == 0); + + return TEST_PASS; +} + +static enum test_return ascii_get_value(const char *key, const char *value) +{ + + char buffer[1024]; + size_t datasize= strlen(value); + + verify(datasize < sizeof(buffer)); + execute(receive_line(buffer, sizeof(buffer))); + verify(strncmp(buffer, "VALUE ", 6) == 0); + verify(strncmp(buffer + 6, key, strlen(key)) == 0); + char *ptr= buffer + 6 + strlen(key) + 1; + char *end; + + unsigned long val= strtoul(ptr, &end, 10); /* flags */ + verify(ptr != end); + verify(val == 0); + verify(end != NULL); + val= strtoul(end, &end, 10); /* size */ + verify(ptr != end); + verify(val == datasize); + verify(end != NULL); + while (*end != '\n' && isspace(*end)) + ++end; + verify(*end == '\n'); + + execute(retry_read(buffer, datasize)); + verify(memcmp(buffer, value, datasize) == 0); + + execute(retry_read(buffer, 2)); + verify(memcmp(buffer, "\r\n", 2) == 0); + + return TEST_PASS; +} + +static enum test_return ascii_get_item(const char *key, const char *value, + bool exist) +{ + char buffer[1024]; + size_t datasize= 0; + if (value != NULL) + datasize= strlen(value); + + verify(datasize < sizeof(buffer)); + snprintf(buffer, sizeof(buffer), "get %s\r\n", key); + execute(send_string(buffer)); + + if (exist) + execute(ascii_get_value(key, value)); + + execute(retry_read(buffer, 5)); + verify(memcmp(buffer, "END\r\n", 5) == 0); + + return TEST_PASS; +} + +static enum test_return ascii_gets_value(const char *key, const char *value, + unsigned long *cas) +{ + + char buffer[1024]; + size_t datasize= strlen(value); + + verify(datasize < sizeof(buffer)); + execute(receive_line(buffer, sizeof(buffer))); + verify(strncmp(buffer, "VALUE ", 6) == 0); + verify(strncmp(buffer + 6, key, strlen(key)) == 0); + char *ptr= buffer + 6 + strlen(key) + 1; + char *end; + + unsigned long val= strtoul(ptr, &end, 10); /* flags */ + verify(ptr != end); + verify(val == 0); + verify(end != NULL); + val= strtoul(end, &end, 10); /* size */ + verify(ptr != end); + verify(val == datasize); + verify(end != NULL); + *cas= strtoul(end, &end, 10); /* cas */ + verify(ptr != end); + verify(val == datasize); + verify(end != NULL); + + while (*end != '\n' && isspace(*end)) + ++end; + verify(*end == '\n'); + + execute(retry_read(buffer, datasize)); + verify(memcmp(buffer, value, datasize) == 0); + + execute(retry_read(buffer, 2)); + verify(memcmp(buffer, "\r\n", 2) == 0); + + return TEST_PASS; +} + +static enum test_return ascii_gets_item(const char *key, const char *value, + bool exist, unsigned long *cas) +{ + char buffer[1024]; + size_t datasize= 0; + if (value != NULL) + datasize= strlen(value); + + verify(datasize < sizeof(buffer)); + snprintf(buffer, sizeof(buffer), "gets %s\r\n", key); + execute(send_string(buffer)); + + if (exist) + execute(ascii_gets_value(key, value, cas)); + + execute(retry_read(buffer, 5)); + verify(memcmp(buffer, "END\r\n", 5) == 0); + + return TEST_PASS; +} + +static enum test_return ascii_set_item(const char *key, const char *value) +{ + char buffer[300]; + size_t len= strlen(value); + snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len); + execute(send_string(buffer)); + execute(retry_write(value, len)); + execute(send_string("\r\n")); + execute(receive_response("STORED\r\n")); + return TEST_PASS; +} + +static enum test_return test_ascii_replace_impl(const char* key, bool noreply) +{ + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : ""); + execute(send_string(buffer)); + + if (noreply) + execute(test_ascii_version()); + else + execute(receive_response("NOT_STORED\r\n")); + + execute(ascii_set_item(key, "value")); + execute(ascii_get_item(key, "value", true)); + + + execute(send_string(buffer)); + + if (noreply) + execute(test_ascii_version()); + else + execute(receive_response("STORED\r\n")); + + return test_ascii_version(); +} + +static enum test_return test_ascii_replace(void) +{ + return test_ascii_replace_impl("test_ascii_replace", false); +} + +static enum test_return test_ascii_replace_noreply(void) +{ + return test_ascii_replace_impl("test_ascii_replace_noreply", true); +} + +static enum test_return test_ascii_cas_impl(const char* key, bool noreply) +{ + char buffer[1024]; + unsigned long cas; + + execute(ascii_set_item(key, "value")); + execute(ascii_gets_item(key, "value", true, &cas)); + + snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : ""); + execute(send_string(buffer)); + + if (noreply) + execute(test_ascii_version()); + else + execute(receive_response("STORED\r\n")); + + /* reexecute the same command should fail due to illegal cas */ + execute(send_string(buffer)); + + if (noreply) + execute(test_ascii_version()); + else + execute(receive_response("EXISTS\r\n")); + + return test_ascii_version(); +} + +static enum test_return test_ascii_cas(void) +{ + return test_ascii_cas_impl("test_ascii_cas", false); +} + +static enum test_return test_ascii_cas_noreply(void) +{ + return test_ascii_cas_impl("test_ascii_cas_noreply", true); +} + +static enum test_return test_ascii_delete_impl(const char *key, bool noreply) +{ + execute(ascii_set_item(key, "value")); + + execute(send_string("delete\r\n")); + execute(receive_error_response()); + /* BUG: the server accepts delete a b */ + execute(send_string("delete a b c d e\r\n")); + execute(receive_error_response()); + + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : ""); + execute(send_string(buffer)); + + if (noreply) + execute(test_ascii_version()); + else + execute(receive_response("DELETED\r\n")); + + execute(ascii_get_item(key, "value", false)); + execute(send_string(buffer)); + if (noreply) + execute(test_ascii_version()); + else + execute(receive_response("NOT_FOUND\r\n")); + + return TEST_PASS; +} + +static enum test_return test_ascii_delete(void) +{ + return test_ascii_delete_impl("test_ascii_delete", false); +} + +static enum test_return test_ascii_delete_noreply(void) +{ + return test_ascii_delete_impl("test_ascii_delete_noreply", true); +} + +static enum test_return test_ascii_get(void) +{ + execute(ascii_set_item("test_ascii_get", "value")); + + execute(send_string("get\r\n")); + execute(receive_error_response()); + execute(ascii_get_item("test_ascii_get", "value", true)); + execute(ascii_get_item("test_ascii_get_notfound", "value", false)); + + return TEST_PASS; +} + +static enum test_return test_ascii_gets(void) +{ + execute(ascii_set_item("test_ascii_gets", "value")); + + execute(send_string("gets\r\n")); + execute(receive_error_response()); + unsigned long cas; + execute(ascii_gets_item("test_ascii_gets", "value", true, &cas)); + execute(ascii_gets_item("test_ascii_gets_notfound", "value", false, &cas)); + + return TEST_PASS; +} + +static enum test_return test_ascii_mget(void) +{ + const uint32_t nkeys= 5; + const char * const keys[]= { + "test_ascii_mget1", + "test_ascii_mget2", + /* test_ascii_mget_3 does not exist :) */ + "test_ascii_mget4", + "test_ascii_mget5", + "test_ascii_mget6" + }; + + for (uint32_t x= 0; x < nkeys; ++x) + execute(ascii_set_item(keys[x], "value")); + + /* Ask for a key that doesn't exist as well */ + execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 " + "test_ascii_mget4 test_ascii_mget5 " + "test_ascii_mget6\r\n")); + + char *returned[nkeys]; + + for (uint32_t x= 0; x < nkeys; ++x) + { + ssize_t nbytes = 0; + char *v= NULL; + execute(ascii_get_unknown_value(&returned[x], &v, &nbytes)); + verify(nbytes == 5); + verify(memcmp(v, "value", 5) == 0); + free(v); + } + + char buffer[5]; + execute(retry_read(buffer, 5)); + verify(memcmp(buffer, "END\r\n", 5) == 0); + + /* verify that we got all the keys we expected */ + for (uint32_t x= 0; x < nkeys; ++x) + { + bool found= false; + for (uint32_t y= 0; y < nkeys; ++y) + { + if (strcmp(keys[x], returned[y]) == 0) + { + found = true; + break; + } + } + verify(found); + } + + for (uint32_t x= 0; x < nkeys; ++x) + free(returned[x]); + + return TEST_PASS; +} + +static enum test_return test_ascii_incr_impl(const char* key, bool noreply) +{ + char cmd[300]; + snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : ""); + + execute(ascii_set_item(key, "0")); + for (int x= 1; x < 11; ++x) + { + execute(send_string(cmd)); + + if (noreply) + execute(test_ascii_version()); + else + { + char buffer[80]; + execute(receive_line(buffer, sizeof(buffer))); + int val= atoi(buffer); + verify(val == x); + } + } + + execute(ascii_get_item(key, "10", true)); + + return TEST_PASS; +} + +static enum test_return test_ascii_incr(void) +{ + return test_ascii_incr_impl("test_ascii_incr", false); +} + +static enum test_return test_ascii_incr_noreply(void) +{ + return test_ascii_incr_impl("test_ascii_incr_noreply", true); +} + +static enum test_return test_ascii_decr_impl(const char* key, bool noreply) +{ + char cmd[300]; + snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : ""); + + execute(ascii_set_item(key, "9")); + for (int x= 8; x > -1; --x) + { + execute(send_string(cmd)); + + if (noreply) + execute(test_ascii_version()); + else + { + char buffer[80]; + execute(receive_line(buffer, sizeof(buffer))); + int val= atoi(buffer); + verify(val == x); + } + } + + execute(ascii_get_item(key, "0", true)); + + /* verify that it doesn't wrap */ + execute(send_string(cmd)); + if (noreply) + execute(test_ascii_version()); + else + { + char buffer[80]; + execute(receive_line(buffer, sizeof(buffer))); + } + execute(ascii_get_item(key, "0", true)); + + return TEST_PASS; +} + +static enum test_return test_ascii_decr(void) +{ + return test_ascii_decr_impl("test_ascii_decr", false); +} + +static enum test_return test_ascii_decr_noreply(void) +{ + return test_ascii_decr_impl("test_ascii_decr_noreply", true); +} + + +static enum test_return test_ascii_flush_impl(const char *key, bool noreply) +{ +#if 0 + /* Verify that the flush_all command handles unknown options */ + /* Bug in the current memcached server! */ + execute(send_string("flush_all foo bar\r\n")); + execute(receive_error_response()); +#endif + + execute(ascii_set_item(key, key)); + execute(ascii_get_item(key, key, true)); + + if (noreply) + { + execute(send_string("flush_all noreply\r\n")); + execute(test_ascii_version()); + } + else + { + execute(send_string("flush_all\r\n")); + execute(receive_response("OK\r\n")); + } + + execute(ascii_get_item(key, key, false)); + + return TEST_PASS; +} + +static enum test_return test_ascii_flush(void) +{ + return test_ascii_flush_impl("test_ascii_flush", false); +} + +static enum test_return test_ascii_flush_noreply(void) +{ + return test_ascii_flush_impl("test_ascii_flush_noreply", true); +} + +static enum test_return test_ascii_concat_impl(const char *key, + bool append, + bool noreply) +{ + const char *value; + + if (append) + value="hello"; + else + value=" world"; + + execute(ascii_set_item(key, value)); + + if (append) + value=" world"; + else + value="hello"; + + char cmd[400]; + snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n", + append ? "append" : "prepend", + key, (unsigned int)strlen(value), noreply ? " noreply" : "", + value); + execute(send_string(cmd)); + + if (noreply) + execute(test_ascii_version()); + else + execute(receive_response("STORED\r\n")); + + execute(ascii_get_item(key, "hello world", true)); + + snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n", + append ? "append" : "prepend", + key, (unsigned int)strlen(value), noreply ? " noreply" : "", + value); + execute(send_string(cmd)); + + if (noreply) + execute(test_ascii_version()); + else + execute(receive_response("NOT_STORED\r\n")); + + return TEST_PASS; +} + +static enum test_return test_ascii_append(void) +{ + return test_ascii_concat_impl("test_ascii_append", true, false); +} + +static enum test_return test_ascii_prepend(void) +{ + return test_ascii_concat_impl("test_ascii_prepend", false, false); +} + +static enum test_return test_ascii_append_noreply(void) +{ + return test_ascii_concat_impl("test_ascii_append_noreply", true, true); +} + +static enum test_return test_ascii_prepend_noreply(void) +{ + return test_ascii_concat_impl("test_ascii_prepend_noreply", false, true); +} + +static enum test_return test_ascii_stat(void) +{ + execute(send_string("stats noreply\r\n")); + execute(receive_error_response()); + execute(send_string("stats\r\n")); + char buffer[1024]; + do { + execute(receive_line(buffer, sizeof(buffer))); + } while (strcmp(buffer, "END\r\n") != 0); + + return TEST_PASS_RECONNECT; +} + +typedef enum test_return(*TEST_FUNC)(void); + +struct testcase +{ + const char *description; + TEST_FUNC function; +}; + +struct testcase testcases[]= { + { "ascii quit", test_ascii_quit }, + { "ascii version", test_ascii_version }, + { "ascii verbosity", test_ascii_verbosity }, + { "ascii set", test_ascii_set }, + { "ascii set noreply", test_ascii_set_noreply }, + { "ascii get", test_ascii_get }, + { "ascii gets", test_ascii_gets }, + { "ascii mget", test_ascii_mget }, + { "ascii flush", test_ascii_flush }, + { "ascii flush noreply", test_ascii_flush_noreply }, + { "ascii add", test_ascii_add }, + { "ascii add noreply", test_ascii_add_noreply }, + { "ascii replace", test_ascii_replace }, + { "ascii replace noreply", test_ascii_replace_noreply }, + { "ascii cas", test_ascii_cas }, + { "ascii cas noreply", test_ascii_cas_noreply }, + { "ascii delete", test_ascii_delete }, + { "ascii delete noreply", test_ascii_delete_noreply }, + { "ascii incr", test_ascii_incr }, + { "ascii incr noreply", test_ascii_incr_noreply }, + { "ascii decr", test_ascii_decr }, + { "ascii decr noreply", test_ascii_decr_noreply }, + { "ascii append", test_ascii_append }, + { "ascii append noreply", test_ascii_append_noreply }, + { "ascii prepend", test_ascii_prepend }, + { "ascii prepend noreply", test_ascii_prepend_noreply }, + { "ascii stat", test_ascii_stat }, + { "binary noop", test_binary_noop }, + { "binary quit", test_binary_quit }, + { "binary quitq", test_binary_quitq }, + { "binary set", test_binary_set }, + { "binary setq", test_binary_setq }, + { "binary flush", test_binary_flush }, + { "binary flushq", test_binary_flushq }, + { "binary add", test_binary_add }, + { "binary addq", test_binary_addq }, + { "binary replace", test_binary_replace }, + { "binary replaceq", test_binary_replaceq }, + { "binary delete", test_binary_delete }, + { "binary deleteq", test_binary_deleteq }, + { "binary get", test_binary_get }, + { "binary getq", test_binary_getq }, + { "binary getk", test_binary_getk }, + { "binary getkq", test_binary_getkq }, + { "binary incr", test_binary_incr }, + { "binary incrq", test_binary_incrq }, + { "binary decr", test_binary_decr }, + { "binary decrq", test_binary_decrq }, + { "binary version", test_binary_version }, + { "binary append", test_binary_append }, + { "binary appendq", test_binary_appendq }, + { "binary prepend", test_binary_prepend }, + { "binary prependq", test_binary_prependq }, + { "binary stat", test_binary_stat }, + { NULL, NULL} +}; + +const int ascii_tests = 1; +const int binary_tests = 2; + +struct test_type_st +{ + bool ascii; + bool binary; +}; + +int main(int argc, char **argv) +{ + static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"}; + struct test_type_st tests= { true, true }; + int total= 0; + int failed= 0; + const char *hostname= "localhost"; + const char *port= "11211"; + int cmd; + bool prompt= false; + const char *testname= NULL; + + + + while ((cmd= getopt(argc, argv, "t:vch:p:PT:?ab")) != EOF) + { + switch (cmd) { + case 'a': + tests.ascii= true; + tests.binary= false; + break; + case 'b': + tests.ascii= false; + tests.binary= true; + break; + case 't': + timeout= atoi(optarg); + if (timeout == 0) + { + fprintf(stderr, "Invalid timeout. Please specify a number for -t\n"); + return EXIT_FAILURE; + } + break; + case 'v': verbose= true; + break; + case 'c': do_core= true; + break; + case 'h': hostname= optarg; + break; + case 'p': port= optarg; + break; + case 'P': prompt= true; + break; + case 'T': testname= optarg; + break; + default: + fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n" + "\t-c\tGenerate coredump if a test fails\n" + "\t-v\tVerbose test output (print out the assertion)\n" + "\t-t n\tSet the timeout for io-operations to n seconds\n" + "\t-P\tPrompt the user before starting a test.\n" + "\t\t\t\"skip\" will skip the test\n" + "\t\t\t\"quit\" will terminate memcapable\n" + "\t\t\tEverything else will start the test\n" + "\t-T n\tJust run the test named n\n" + "\t-a\tOnly test the ascii protocol\n" + "\t-b\tOnly test the binary protocol\n", + argv[0]); + return EXIT_FAILURE; + } + } + + initialize_sockets(); + sock= connect_server(hostname, port); + if (sock == INVALID_SOCKET) + { + fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", + hostname, port, strerror(get_socket_errno())); + return EXIT_FAILURE; + } + + for (int ii= 0; testcases[ii].description != NULL; ++ii) + { + if (testname != NULL && strcmp(testcases[ii].description, testname) != 0) + continue; + + if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) || + (testcases[ii].description[0] == 'b' && (tests.binary) == 0)) + { + continue; + } + ++total; + fprintf(stdout, "%-40s", testcases[ii].description); + fflush(stdout); + + if (prompt) + { + fprintf(stdout, "\nPress when you are ready? "); + char buffer[80] = {0}; + if (fgets(buffer, sizeof(buffer), stdin) != NULL) { + if (strncmp(buffer, "skip", 4) == 0) + { + fprintf(stdout, "%-40s%s\n", testcases[ii].description, + status_msg[TEST_SKIP]); + fflush(stdout); + continue; + } + if (strncmp(buffer, "quit", 4) == 0) + exit(0); + } + + fprintf(stdout, "%-40s", testcases[ii].description); + fflush(stdout); + } + + bool reconnect= false; + enum test_return ret= testcases[ii].function(); + if (ret == TEST_FAIL) + { + reconnect= true; + ++failed; + if (verbose) + fprintf(stderr, "\n"); + } + else if (ret == TEST_PASS_RECONNECT) + reconnect= true; + + fprintf(stderr, "%s\n", status_msg[ret]); + if (reconnect) + { + closesocket(sock); + if ((sock= connect_server(hostname, port)) == INVALID_SOCKET) + { + fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", + hostname, port, strerror(get_socket_errno())); + fprintf(stderr, "%d of %d tests failed\n", failed, total); + return EXIT_FAILURE; + } + } + } + + closesocket(sock); + if (failed == 0) + fprintf(stdout, "All tests passed\n"); + else + fprintf(stderr, "%d of %d tests failed\n", failed, total); + + return (failed == 0) ? 0 : 1; +} diff --git a/clients/memcat.c b/clients/memcat.c deleted file mode 100644 index 3f0d92b4..00000000 --- a/clients/memcat.c +++ /dev/null @@ -1,242 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "utilities.h" - -#define PROGRAM_NAME "memcat" -#define PROGRAM_DESCRIPTION "Cat a set of key values to stdout." - - -/* Prototypes */ -void options_parse(int argc, char *argv[]); - -static int opt_binary= 0; -static int opt_verbose= 0; -static int opt_displayflag= 0; -static char *opt_servers= NULL; -static char *opt_hash= NULL; -static char *opt_username; -static char *opt_passwd; -static char *opt_file; - -int main(int argc, char *argv[]) -{ - memcached_st *memc; - char *string; - size_t string_length; - uint32_t flags; - memcached_return_t rc; - memcached_server_st *servers; - - int return_code= 0; - - options_parse(argc, argv); - initialize_sockets(); - - if (!opt_servers) - { - char *temp; - - if ((temp= getenv("MEMCACHED_SERVERS"))) - opt_servers= strdup(temp); - else - { - fprintf(stderr, "No Servers provided\n"); - exit(1); - } - } - - memc= memcached_create(NULL); - process_hash_option(memc, opt_hash); - - servers= memcached_servers_parse(opt_servers); - - memcached_server_push(memc, servers); - memcached_server_list_free(servers); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, - (uint64_t)opt_binary); - - if (!initialize_sasl(memc, opt_username, opt_passwd)) - { - memcached_free(memc); - return EXIT_FAILURE; - } - - while (optind < argc) - { - string= memcached_get(memc, argv[optind], strlen(argv[optind]), - &string_length, &flags, &rc); - if (rc == MEMCACHED_SUCCESS) - { - if (opt_displayflag) - { - if (opt_verbose) - printf("key: %s\nflags: ", argv[optind]); - printf("%x\n", flags); - } - else - { - if (opt_verbose) - { - printf("key: %s\nflags: %x\nlength: %zu\nvalue: ", - argv[optind], flags, string_length); - } - - if (opt_file) - { - FILE *fp; - size_t written; - - fp= fopen(opt_file, "w"); - if (!fp) - { - perror("fopen"); - return_code= -1; - break; - } - - written= fwrite(string, 1, string_length, fp); - if (written != string_length) - { - fprintf(stderr, "error writing file (written %zu, should be %zu)\n", written, string_length); - return_code= -1; - break; - } - - if (fclose(fp)) - { - fprintf(stderr, "error closing file\n"); - return_code= -1; - break; - } - } - else - { - printf("%.*s\n", (int)string_length, string); - } - free(string); - } - } - else if (rc != MEMCACHED_NOTFOUND) - { - fprintf(stderr, "memcat: %s: memcache error %s", - argv[optind], memcached_strerror(memc, rc)); - if (memcached_last_error_errno(memc)) - { - fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); - } - fprintf(stderr, "\n"); - - return_code= -1; - break; - } - else // Unknown Issue - { - fprintf(stderr, "memcat: %s not found\n", argv[optind]); - return_code= -1; - } - optind++; - } - - memcached_free(memc); - - if (opt_servers) - free(opt_servers); - if (opt_hash) - free(opt_hash); - - shutdown_sasl(); - - return return_code; -} - - -void options_parse(int argc, char *argv[]) -{ - int option_index= 0; - int option_rv; - - memcached_programs_help_st help_options[]= - { - {0}, - }; - - static struct option long_options[]= - { - {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, - {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, - {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, - {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, - {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG}, - {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH}, - {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, - {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, - {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, - {(OPTIONSTRING)"file", required_argument, NULL, OPT_FILE}, - {0, 0, 0, 0}, - }; - - while (1) - { - option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); - if (option_rv == -1) break; - switch (option_rv) - { - case 0: - break; - case OPT_BINARY: - opt_binary = 1; - break; - case OPT_VERBOSE: /* --verbose or -v */ - opt_verbose = OPT_VERBOSE; - break; - case OPT_DEBUG: /* --debug or -d */ - opt_verbose = OPT_DEBUG; - break; - case OPT_VERSION: /* --version or -V */ - version_command(PROGRAM_NAME); - break; - case OPT_HELP: /* --help or -h */ - help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); - break; - case OPT_SERVERS: /* --servers or -s */ - opt_servers= strdup(optarg); - break; - case OPT_HASH: - opt_hash= strdup(optarg); - break; - case OPT_USERNAME: - opt_username= optarg; - break; - case OPT_PASSWD: - opt_passwd= optarg; - break; - case OPT_FILE: - opt_file= optarg; - break; - case '?': - /* getopt_long already printed an error message. */ - exit(1); - default: - abort(); - } - } -} diff --git a/clients/memcat.cc b/clients/memcat.cc new file mode 100644 index 00000000..12df3479 --- /dev/null +++ b/clients/memcat.cc @@ -0,0 +1,242 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "utilities.h" + +#define PROGRAM_NAME "memcat" +#define PROGRAM_DESCRIPTION "Cat a set of key values to stdout." + + +/* Prototypes */ +void options_parse(int argc, char *argv[]); + +static int opt_binary= 0; +static int opt_verbose= 0; +static int opt_displayflag= 0; +static char *opt_servers= NULL; +static char *opt_hash= NULL; +static char *opt_username; +static char *opt_passwd; +static char *opt_file; + +int main(int argc, char *argv[]) +{ + memcached_st *memc; + char *string; + size_t string_length; + uint32_t flags; + memcached_return_t rc; + memcached_server_st *servers; + + int return_code= 0; + + options_parse(argc, argv); + initialize_sockets(); + + if (!opt_servers) + { + char *temp; + + if ((temp= getenv("MEMCACHED_SERVERS"))) + opt_servers= strdup(temp); + else + { + fprintf(stderr, "No Servers provided\n"); + exit(1); + } + } + + memc= memcached_create(NULL); + process_hash_option(memc, opt_hash); + + servers= memcached_servers_parse(opt_servers); + + memcached_server_push(memc, servers); + memcached_server_list_free(servers); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, + (uint64_t)opt_binary); + + if (!initialize_sasl(memc, opt_username, opt_passwd)) + { + memcached_free(memc); + return EXIT_FAILURE; + } + + while (optind < argc) + { + string= memcached_get(memc, argv[optind], strlen(argv[optind]), + &string_length, &flags, &rc); + if (rc == MEMCACHED_SUCCESS) + { + if (opt_displayflag) + { + if (opt_verbose) + printf("key: %s\nflags: ", argv[optind]); + printf("%x\n", flags); + } + else + { + if (opt_verbose) + { + printf("key: %s\nflags: %x\nlength: %lu\nvalue: ", + argv[optind], flags, (unsigned long)string_length); + } + + if (opt_file) + { + FILE *fp; + size_t written; + + fp= fopen(opt_file, "w"); + if (!fp) + { + perror("fopen"); + return_code= -1; + break; + } + + written= fwrite(string, 1, string_length, fp); + if (written != string_length) + { + fprintf(stderr, "error writing file (written %lu, should be %lu)\n", (unsigned long)written, (unsigned long)string_length); + return_code= -1; + break; + } + + if (fclose(fp)) + { + fprintf(stderr, "error closing file\n"); + return_code= -1; + break; + } + } + else + { + printf("%.*s\n", (int)string_length, string); + } + free(string); + } + } + else if (rc != MEMCACHED_NOTFOUND) + { + fprintf(stderr, "memcat: %s: memcache error %s", + argv[optind], memcached_strerror(memc, rc)); + if (memcached_last_error_errno(memc)) + { + fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); + } + fprintf(stderr, "\n"); + + return_code= -1; + break; + } + else // Unknown Issue + { + fprintf(stderr, "memcat: %s not found\n", argv[optind]); + return_code= -1; + } + optind++; + } + + memcached_free(memc); + + if (opt_servers) + free(opt_servers); + if (opt_hash) + free(opt_hash); + + shutdown_sasl(); + + return return_code; +} + + +void options_parse(int argc, char *argv[]) +{ + int option_index= 0; + int option_rv; + + memcached_programs_help_st help_options[]= + { + {0}, + }; + + static struct option long_options[]= + { + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, + {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG}, + {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH}, + {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, + {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, + {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, + {(OPTIONSTRING)"file", required_argument, NULL, OPT_FILE}, + {0, 0, 0, 0}, + }; + + while (1) + { + option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + if (option_rv == -1) break; + switch (option_rv) + { + case 0: + break; + case OPT_BINARY: + opt_binary = 1; + break; + case OPT_VERBOSE: /* --verbose or -v */ + opt_verbose = OPT_VERBOSE; + break; + case OPT_DEBUG: /* --debug or -d */ + opt_verbose = OPT_DEBUG; + break; + case OPT_VERSION: /* --version or -V */ + version_command(PROGRAM_NAME); + break; + case OPT_HELP: /* --help or -h */ + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); + break; + case OPT_SERVERS: /* --servers or -s */ + opt_servers= strdup(optarg); + break; + case OPT_HASH: + opt_hash= strdup(optarg); + break; + case OPT_USERNAME: + opt_username= optarg; + break; + case OPT_PASSWD: + opt_passwd= optarg; + break; + case OPT_FILE: + opt_file= optarg; + break; + case '?': + /* getopt_long already printed an error message. */ + exit(1); + default: + abort(); + } + } +} diff --git a/clients/memcp.c b/clients/memcp.c deleted file mode 100644 index bf3828ae..00000000 --- a/clients/memcp.c +++ /dev/null @@ -1,317 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include - -#include "client_options.h" -#include "utilities.h" - -#define PROGRAM_NAME "memcp" -#define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster." - -/* Prototypes */ -static void options_parse(int argc, char *argv[]); - -static int opt_binary=0; -static int opt_verbose= 0; -static char *opt_servers= NULL; -static char *opt_hash= NULL; -static int opt_method= OPT_SET; -static uint32_t opt_flags= 0; -static time_t opt_expires= 0; -static char *opt_username; -static char *opt_passwd; - -static long strtol_wrapper(const char *nptr, int base, bool *error) -{ - long val; - char *endptr; - - errno= 0; /* To distinguish success/failure after call */ - val= strtol(nptr, &endptr, base); - - /* Check for various possible errors */ - - if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) - || (errno != 0 && val == 0)) - { - *error= true; - return EXIT_SUCCESS; - } - - if (endptr == nptr) - { - *error= true; - return EXIT_SUCCESS; - } - - *error= false; - return val; -} - -int main(int argc, char *argv[]) -{ - memcached_st *memc; - memcached_return_t rc; - memcached_server_st *servers; - - int return_code= 0; - - options_parse(argc, argv); - initialize_sockets(); - - memc= memcached_create(NULL); - process_hash_option(memc, opt_hash); - - if (!opt_servers) - { - char *temp; - - if ((temp= getenv("MEMCACHED_SERVERS"))) - { - opt_servers= strdup(temp); - } - else - { - fprintf(stderr, "No Servers provided\n"); - exit(1); - } - } - - if (opt_servers) - servers= memcached_servers_parse(opt_servers); - else - servers= memcached_servers_parse(argv[--argc]); - - memcached_server_push(memc, servers); - memcached_server_list_free(servers); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, - (uint64_t)opt_binary); - if (!initialize_sasl(memc, opt_username, opt_passwd)) - { - memcached_free(memc); - return EXIT_FAILURE; - } - - while (optind < argc) - { - struct stat sbuf; - int fd; - char *ptr; - ssize_t read_length; - char *file_buffer_ptr; - - fd= open(argv[optind], O_RDONLY); - if (fd < 0) - { - fprintf(stderr, "memcp: %s: %s\n", argv[optind], strerror(errno)); - optind++; - continue; - } - - (void)fstat(fd, &sbuf); - - ptr= rindex(argv[optind], '/'); - if (ptr) - ptr++; - else - ptr= argv[optind]; - - if (opt_verbose) - { - static const char *opstr[] = { "set", "add", "replace" }; - printf("op: %s\nsource file: %s\nlength: %zu\n" - "key: %s\nflags: %x\nexpires: %llu\n", - opstr[opt_method - OPT_SET], argv[optind], (size_t)sbuf.st_size, - ptr, opt_flags, (unsigned long long)opt_expires); - } - - if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL) - { - fprintf(stderr, "malloc: %s\n", strerror(errno)); - exit(1); - } - - if ((read_length= read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1) - { - fprintf(stderr, "read: %s\n", strerror(errno)); - exit(1); - } - - if (read_length != sbuf.st_size) - { - fprintf(stderr, "Failure reading from file\n"); - exit(1); - } - - if (opt_method == OPT_ADD) - rc= memcached_add(memc, ptr, strlen(ptr), - file_buffer_ptr, (size_t)sbuf.st_size, - opt_expires, opt_flags); - else if (opt_method == OPT_REPLACE) - rc= memcached_replace(memc, ptr, strlen(ptr), - file_buffer_ptr, (size_t)sbuf.st_size, - opt_expires, opt_flags); - else - rc= memcached_set(memc, ptr, strlen(ptr), - file_buffer_ptr, (size_t)sbuf.st_size, - opt_expires, opt_flags); - - if (rc != MEMCACHED_SUCCESS) - { - fprintf(stderr, "memcp: %s: memcache error %s", - ptr, memcached_strerror(memc, rc)); - if (memcached_last_error_errno(memc)) - fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); - fprintf(stderr, "\n"); - - return_code= -1; - } - - free(file_buffer_ptr); - close(fd); - optind++; - } - - memcached_free(memc); - - if (opt_servers) - free(opt_servers); - if (opt_hash) - free(opt_hash); - shutdown_sasl(); - - return return_code; -} - -static void options_parse(int argc, char *argv[]) -{ - int option_index= 0; - int option_rv; - - memcached_programs_help_st help_options[]= - { - {0}, - }; - - static struct option long_options[]= - { - {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, - {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, - {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, - {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, - {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG}, - {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE}, - {(OPTIONSTRING)"set", no_argument, NULL, OPT_SET}, - {(OPTIONSTRING)"add", no_argument, NULL, OPT_ADD}, - {(OPTIONSTRING)"replace", no_argument, NULL, OPT_REPLACE}, - {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH}, - {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, - {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, - {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, - {0, 0, 0, 0}, - }; - - while (1) - { - option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); - - if (option_rv == -1) break; - - switch (option_rv) - { - case 0: - break; - case OPT_BINARY: - opt_binary = 1; - break; - case OPT_VERBOSE: /* --verbose or -v */ - opt_verbose = OPT_VERBOSE; - break; - case OPT_DEBUG: /* --debug or -d */ - opt_verbose = OPT_DEBUG; - break; - case OPT_VERSION: /* --version or -V */ - version_command(PROGRAM_NAME); - break; - case OPT_HELP: /* --help or -h */ - help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); - break; - case OPT_SERVERS: /* --servers or -s */ - opt_servers= strdup(optarg); - break; - case OPT_FLAG: /* --flag */ - { - bool strtol_error; - opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error); - if (strtol_error == true) - { - fprintf(stderr, "Bad value passed via --flag\n"); - exit(1); - } - break; - } - case OPT_EXPIRE: /* --expire */ - { - bool strtol_error; - opt_expires= (time_t)strtol_wrapper(optarg, 16, &strtol_error); - if (strtol_error == true) - { - fprintf(stderr, "Bad value passed via --flag\n"); - exit(1); - } - } - case OPT_SET: - opt_method= OPT_SET; - break; - case OPT_REPLACE: - opt_method= OPT_REPLACE; - break; - case OPT_ADD: - opt_method= OPT_ADD; - break; - case OPT_HASH: - opt_hash= strdup(optarg); - break; - case OPT_USERNAME: - opt_username= optarg; - break; - case OPT_PASSWD: - opt_passwd= optarg; - break; - case '?': - /* getopt_long already printed an error message. */ - exit(1); - default: - abort(); - } - } -} diff --git a/clients/memcp.cc b/clients/memcp.cc new file mode 100644 index 00000000..3869242b --- /dev/null +++ b/clients/memcp.cc @@ -0,0 +1,317 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + +#include "client_options.h" +#include "utilities.h" + +#define PROGRAM_NAME "memcp" +#define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster." + +/* Prototypes */ +static void options_parse(int argc, char *argv[]); + +static int opt_binary=0; +static int opt_verbose= 0; +static char *opt_servers= NULL; +static char *opt_hash= NULL; +static int opt_method= OPT_SET; +static uint32_t opt_flags= 0; +static time_t opt_expires= 0; +static char *opt_username; +static char *opt_passwd; + +static long strtol_wrapper(const char *nptr, int base, bool *error) +{ + long val; + char *endptr; + + errno= 0; /* To distinguish success/failure after call */ + val= strtol(nptr, &endptr, base); + + /* Check for various possible errors */ + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) + || (errno != 0 && val == 0)) + { + *error= true; + return EXIT_SUCCESS; + } + + if (endptr == nptr) + { + *error= true; + return EXIT_SUCCESS; + } + + *error= false; + return val; +} + +int main(int argc, char *argv[]) +{ + memcached_st *memc; + memcached_return_t rc; + memcached_server_st *servers; + + int return_code= 0; + + options_parse(argc, argv); + initialize_sockets(); + + memc= memcached_create(NULL); + process_hash_option(memc, opt_hash); + + if (!opt_servers) + { + char *temp; + + if ((temp= getenv("MEMCACHED_SERVERS"))) + { + opt_servers= strdup(temp); + } + else + { + fprintf(stderr, "No Servers provided\n"); + exit(1); + } + } + + if (opt_servers) + servers= memcached_servers_parse(opt_servers); + else + servers= memcached_servers_parse(argv[--argc]); + + memcached_server_push(memc, servers); + memcached_server_list_free(servers); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, + (uint64_t)opt_binary); + if (!initialize_sasl(memc, opt_username, opt_passwd)) + { + memcached_free(memc); + return EXIT_FAILURE; + } + + while (optind < argc) + { + struct stat sbuf; + int fd; + char *ptr; + ssize_t read_length; + char *file_buffer_ptr; + + fd= open(argv[optind], O_RDONLY); + if (fd < 0) + { + fprintf(stderr, "memcp: %s: %s\n", argv[optind], strerror(errno)); + optind++; + continue; + } + + (void)fstat(fd, &sbuf); + + ptr= rindex(argv[optind], '/'); + if (ptr) + ptr++; + else + ptr= argv[optind]; + + if (opt_verbose) + { + static const char *opstr[] = { "set", "add", "replace" }; + printf("op: %s\nsource file: %s\nlength: %lu\n" + "key: %s\nflags: %x\nexpires: %lu\n", + opstr[opt_method - OPT_SET], argv[optind], (unsigned long)sbuf.st_size, + ptr, opt_flags, (unsigned long)opt_expires); + } + + if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL) + { + fprintf(stderr, "malloc: %s\n", strerror(errno)); + exit(1); + } + + if ((read_length= read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1) + { + fprintf(stderr, "read: %s\n", strerror(errno)); + exit(1); + } + + if (read_length != sbuf.st_size) + { + fprintf(stderr, "Failure reading from file\n"); + exit(1); + } + + if (opt_method == OPT_ADD) + rc= memcached_add(memc, ptr, strlen(ptr), + file_buffer_ptr, (size_t)sbuf.st_size, + opt_expires, opt_flags); + else if (opt_method == OPT_REPLACE) + rc= memcached_replace(memc, ptr, strlen(ptr), + file_buffer_ptr, (size_t)sbuf.st_size, + opt_expires, opt_flags); + else + rc= memcached_set(memc, ptr, strlen(ptr), + file_buffer_ptr, (size_t)sbuf.st_size, + opt_expires, opt_flags); + + if (rc != MEMCACHED_SUCCESS) + { + fprintf(stderr, "memcp: %s: memcache error %s", + ptr, memcached_strerror(memc, rc)); + if (memcached_last_error_errno(memc)) + fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); + fprintf(stderr, "\n"); + + return_code= -1; + } + + free(file_buffer_ptr); + close(fd); + optind++; + } + + memcached_free(memc); + + if (opt_servers) + free(opt_servers); + if (opt_hash) + free(opt_hash); + shutdown_sasl(); + + return return_code; +} + +static void options_parse(int argc, char *argv[]) +{ + int option_index= 0; + int option_rv; + + memcached_programs_help_st help_options[]= + { + {0}, + }; + + static struct option long_options[]= + { + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, + {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG}, + {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE}, + {(OPTIONSTRING)"set", no_argument, NULL, OPT_SET}, + {(OPTIONSTRING)"add", no_argument, NULL, OPT_ADD}, + {(OPTIONSTRING)"replace", no_argument, NULL, OPT_REPLACE}, + {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH}, + {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, + {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, + {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, + {0, 0, 0, 0}, + }; + + while (1) + { + option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + + if (option_rv == -1) break; + + switch (option_rv) + { + case 0: + break; + case OPT_BINARY: + opt_binary = 1; + break; + case OPT_VERBOSE: /* --verbose or -v */ + opt_verbose = OPT_VERBOSE; + break; + case OPT_DEBUG: /* --debug or -d */ + opt_verbose = OPT_DEBUG; + break; + case OPT_VERSION: /* --version or -V */ + version_command(PROGRAM_NAME); + break; + case OPT_HELP: /* --help or -h */ + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); + break; + case OPT_SERVERS: /* --servers or -s */ + opt_servers= strdup(optarg); + break; + case OPT_FLAG: /* --flag */ + { + bool strtol_error; + opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error); + if (strtol_error == true) + { + fprintf(stderr, "Bad value passed via --flag\n"); + exit(1); + } + break; + } + case OPT_EXPIRE: /* --expire */ + { + bool strtol_error; + opt_expires= (time_t)strtol_wrapper(optarg, 16, &strtol_error); + if (strtol_error == true) + { + fprintf(stderr, "Bad value passed via --flag\n"); + exit(1); + } + } + case OPT_SET: + opt_method= OPT_SET; + break; + case OPT_REPLACE: + opt_method= OPT_REPLACE; + break; + case OPT_ADD: + opt_method= OPT_ADD; + break; + case OPT_HASH: + opt_hash= strdup(optarg); + break; + case OPT_USERNAME: + opt_username= optarg; + break; + case OPT_PASSWD: + opt_passwd= optarg; + break; + case '?': + /* getopt_long already printed an error message. */ + exit(1); + default: + abort(); + } + } +} diff --git a/clients/memdump.c b/clients/memdump.c deleted file mode 100644 index 0e81dad4..00000000 --- a/clients/memdump.c +++ /dev/null @@ -1,183 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "client_options.h" -#include "utilities.h" - -#define PROGRAM_NAME "memdump" -#define PROGRAM_DESCRIPTION "Dump all values from one or many servers." - -/* Prototypes */ -static void options_parse(int argc, char *argv[]); - -static int opt_binary=0; -static int opt_verbose= 0; -static char *opt_servers= NULL; -static char *opt_hash= NULL; -static char *opt_username; -static char *opt_passwd; - -/* Print the keys and counter how many were found */ -static memcached_return_t key_printer(const memcached_st *ptr, - const char *key, size_t key_length, - void *context) -{ - (void)ptr;(void)context; - printf("%.*s\n", (uint32_t)key_length, key); - - return MEMCACHED_SUCCESS; -} - -int main(int argc, char *argv[]) -{ - memcached_st *memc; - memcached_return_t rc; - memcached_server_st *servers; - memcached_dump_fn callbacks[1]; - - callbacks[0]= &key_printer; - - options_parse(argc, argv); - - memc= memcached_create(NULL); - process_hash_option(memc, opt_hash); - - if (!opt_servers) - { - char *temp; - - if ((temp= getenv("MEMCACHED_SERVERS"))) - opt_servers= strdup(temp); - else - { - fprintf(stderr, "No Servers provided\n"); - exit(1); - } - } - - if (opt_servers) - servers= memcached_servers_parse(opt_servers); - else - servers= memcached_servers_parse(argv[--argc]); - - memcached_server_push(memc, servers); - memcached_server_list_free(servers); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, - (uint64_t)opt_binary); - if (!initialize_sasl(memc, opt_username, opt_passwd)) - { - memcached_free(memc); - return EXIT_FAILURE; - } - - rc= memcached_dump(memc, callbacks, NULL, 1); - - if (rc != MEMCACHED_SUCCESS) - { - fprintf(stderr, "memdump: memcache error %s", memcached_strerror(memc, rc)); - if (memcached_last_error_errno(memc)) - fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); - fprintf(stderr, "\n"); - } - - memcached_free(memc); - - if (opt_servers) - free(opt_servers); - if (opt_hash) - free(opt_hash); - - shutdown_sasl(); - - return EXIT_SUCCESS; -} - -static void options_parse(int argc, char *argv[]) -{ - int option_index= 0; - int option_rv; - - static struct option long_options[]= - { - {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, - {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, - {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, - {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, - {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH}, - {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, - {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, - {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, - {0, 0, 0, 0} - }; - - while (1) - { - option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); - - if (option_rv == -1) break; - - switch (option_rv) - { - case 0: - break; - case OPT_BINARY: - opt_binary = 1; - break; - case OPT_VERBOSE: /* --verbose or -v */ - opt_verbose = OPT_VERBOSE; - break; - case OPT_DEBUG: /* --debug or -d */ - opt_verbose = OPT_DEBUG; - break; - case OPT_VERSION: /* --version or -V */ - version_command(PROGRAM_NAME); - break; - case OPT_HELP: /* --help or -h */ - help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL); - break; - case OPT_SERVERS: /* --servers or -s */ - opt_servers= strdup(optarg); - break; - case OPT_HASH: - opt_hash= strdup(optarg); - break; - case OPT_USERNAME: - opt_username= optarg; - break; - case OPT_PASSWD: - opt_passwd= optarg; - break; - case '?': - /* getopt_long already printed an error message. */ - exit(1); - default: - abort(); - } - } -} diff --git a/clients/memdump.cc b/clients/memdump.cc new file mode 100644 index 00000000..0e81dad4 --- /dev/null +++ b/clients/memdump.cc @@ -0,0 +1,183 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "client_options.h" +#include "utilities.h" + +#define PROGRAM_NAME "memdump" +#define PROGRAM_DESCRIPTION "Dump all values from one or many servers." + +/* Prototypes */ +static void options_parse(int argc, char *argv[]); + +static int opt_binary=0; +static int opt_verbose= 0; +static char *opt_servers= NULL; +static char *opt_hash= NULL; +static char *opt_username; +static char *opt_passwd; + +/* Print the keys and counter how many were found */ +static memcached_return_t key_printer(const memcached_st *ptr, + const char *key, size_t key_length, + void *context) +{ + (void)ptr;(void)context; + printf("%.*s\n", (uint32_t)key_length, key); + + return MEMCACHED_SUCCESS; +} + +int main(int argc, char *argv[]) +{ + memcached_st *memc; + memcached_return_t rc; + memcached_server_st *servers; + memcached_dump_fn callbacks[1]; + + callbacks[0]= &key_printer; + + options_parse(argc, argv); + + memc= memcached_create(NULL); + process_hash_option(memc, opt_hash); + + if (!opt_servers) + { + char *temp; + + if ((temp= getenv("MEMCACHED_SERVERS"))) + opt_servers= strdup(temp); + else + { + fprintf(stderr, "No Servers provided\n"); + exit(1); + } + } + + if (opt_servers) + servers= memcached_servers_parse(opt_servers); + else + servers= memcached_servers_parse(argv[--argc]); + + memcached_server_push(memc, servers); + memcached_server_list_free(servers); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, + (uint64_t)opt_binary); + if (!initialize_sasl(memc, opt_username, opt_passwd)) + { + memcached_free(memc); + return EXIT_FAILURE; + } + + rc= memcached_dump(memc, callbacks, NULL, 1); + + if (rc != MEMCACHED_SUCCESS) + { + fprintf(stderr, "memdump: memcache error %s", memcached_strerror(memc, rc)); + if (memcached_last_error_errno(memc)) + fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); + fprintf(stderr, "\n"); + } + + memcached_free(memc); + + if (opt_servers) + free(opt_servers); + if (opt_hash) + free(opt_hash); + + shutdown_sasl(); + + return EXIT_SUCCESS; +} + +static void options_parse(int argc, char *argv[]) +{ + int option_index= 0; + int option_rv; + + static struct option long_options[]= + { + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, + {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH}, + {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, + {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, + {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, + {0, 0, 0, 0} + }; + + while (1) + { + option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + + if (option_rv == -1) break; + + switch (option_rv) + { + case 0: + break; + case OPT_BINARY: + opt_binary = 1; + break; + case OPT_VERBOSE: /* --verbose or -v */ + opt_verbose = OPT_VERBOSE; + break; + case OPT_DEBUG: /* --debug or -d */ + opt_verbose = OPT_DEBUG; + break; + case OPT_VERSION: /* --version or -V */ + version_command(PROGRAM_NAME); + break; + case OPT_HELP: /* --help or -h */ + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL); + break; + case OPT_SERVERS: /* --servers or -s */ + opt_servers= strdup(optarg); + break; + case OPT_HASH: + opt_hash= strdup(optarg); + break; + case OPT_USERNAME: + opt_username= optarg; + break; + case OPT_PASSWD: + opt_passwd= optarg; + break; + case '?': + /* getopt_long already printed an error message. */ + exit(1); + default: + abort(); + } + } +} diff --git a/clients/memerror.c b/clients/memerror.c deleted file mode 100644 index c30dd2e9..00000000 --- a/clients/memerror.c +++ /dev/null @@ -1,102 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "utilities.h" - -#define PROGRAM_NAME "memerror" -#define PROGRAM_DESCRIPTION "Translate a memcached errror code into a string." - - -/* Prototypes */ -void options_parse(int argc, char *argv[]); - -static int opt_verbose= 0; - -int main(int argc, char *argv[]) -{ - unsigned long value; - options_parse(argc, argv); - - if (argc != 2) - return EXIT_FAILURE; - - value= strtoul(argv[1], (char **) NULL, 10); - - if (value < MEMCACHED_MAXIMUM_RETURN) - { - printf("%s\n", memcached_strerror(NULL, (memcached_return_t)value)); - } - else - { - fprintf(stderr, "Unknown Error Code\n"); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} - - -void options_parse(int argc, char *argv[]) -{ - int option_index= 0; - int option_rv; - - memcached_programs_help_st help_options[]= - { - {0}, - }; - - static struct option long_options[]= - { - {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, - {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, - {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, - {0, 0, 0, 0}, - }; - - while (1) - { - option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); - if (option_rv == -1) break; - switch (option_rv) - { - case 0: - break; - case OPT_VERBOSE: /* --verbose or -v */ - opt_verbose = OPT_VERBOSE; - break; - case OPT_DEBUG: /* --debug or -d */ - opt_verbose = OPT_DEBUG; - break; - case OPT_VERSION: /* --version or -V */ - version_command(PROGRAM_NAME); - break; - case OPT_HELP: /* --help or -h */ - help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); - break; - case '?': - /* getopt_long already printed an error message. */ - exit(1); - default: - abort(); - } - } -} diff --git a/clients/memerror.cc b/clients/memerror.cc new file mode 100644 index 00000000..c30dd2e9 --- /dev/null +++ b/clients/memerror.cc @@ -0,0 +1,102 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "utilities.h" + +#define PROGRAM_NAME "memerror" +#define PROGRAM_DESCRIPTION "Translate a memcached errror code into a string." + + +/* Prototypes */ +void options_parse(int argc, char *argv[]); + +static int opt_verbose= 0; + +int main(int argc, char *argv[]) +{ + unsigned long value; + options_parse(argc, argv); + + if (argc != 2) + return EXIT_FAILURE; + + value= strtoul(argv[1], (char **) NULL, 10); + + if (value < MEMCACHED_MAXIMUM_RETURN) + { + printf("%s\n", memcached_strerror(NULL, (memcached_return_t)value)); + } + else + { + fprintf(stderr, "Unknown Error Code\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + + +void options_parse(int argc, char *argv[]) +{ + int option_index= 0; + int option_rv; + + memcached_programs_help_st help_options[]= + { + {0}, + }; + + static struct option long_options[]= + { + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {0, 0, 0, 0}, + }; + + while (1) + { + option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + if (option_rv == -1) break; + switch (option_rv) + { + case 0: + break; + case OPT_VERBOSE: /* --verbose or -v */ + opt_verbose = OPT_VERBOSE; + break; + case OPT_DEBUG: /* --debug or -d */ + opt_verbose = OPT_DEBUG; + break; + case OPT_VERSION: /* --version or -V */ + version_command(PROGRAM_NAME); + break; + case OPT_HELP: /* --help or -h */ + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); + break; + case '?': + /* getopt_long already printed an error message. */ + exit(1); + default: + abort(); + } + } +} diff --git a/clients/memflush.c b/clients/memflush.c deleted file mode 100644 index 848bc1e7..00000000 --- a/clients/memflush.c +++ /dev/null @@ -1,154 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ -#include "config.h" - -#include -#include -#include -#include -#include -#include "client_options.h" -#include "utilities.h" - -static int opt_binary= 0; -static int opt_verbose= 0; -static time_t opt_expire= 0; -static char *opt_servers= NULL; -static char *opt_username; -static char *opt_passwd; - -#define PROGRAM_NAME "memflush" -#define PROGRAM_DESCRIPTION "Erase all data in a server of memcached servers." - -/* Prototypes */ -void options_parse(int argc, char *argv[]); - -int main(int argc, char *argv[]) -{ - memcached_st *memc; - memcached_return_t rc; - memcached_server_st *servers; - - options_parse(argc, argv); - - if (!opt_servers) - { - char *temp; - - if ((temp= getenv("MEMCACHED_SERVERS"))) - opt_servers= strdup(temp); - else - { - fprintf(stderr, "No Servers provided\n"); - exit(1); - } - } - - memc= memcached_create(NULL); - - servers= memcached_servers_parse(opt_servers); - memcached_server_push(memc, servers); - memcached_server_list_free(servers); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, - (uint64_t) opt_binary); - - if (!initialize_sasl(memc, opt_username, opt_passwd)) - { - memcached_free(memc); - return EXIT_FAILURE; - } - - rc = memcached_flush(memc, opt_expire); - if (rc != MEMCACHED_SUCCESS) - { - fprintf(stderr, "memflush: memcache error %s", - memcached_strerror(memc, rc)); - if (memcached_last_error_errno(memc)) - fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); - fprintf(stderr, "\n"); - } - - memcached_free(memc); - - free(opt_servers); - - shutdown_sasl(); - - return EXIT_SUCCESS; -} - - -void options_parse(int argc, char *argv[]) -{ - memcached_programs_help_st help_options[]= - { - {0}, - }; - - static struct option long_options[]= - { - {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, - {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, - {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, - {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, - {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE}, - {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, - {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, - {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, - {0, 0, 0, 0}, - }; - int option_index= 0; - int option_rv; - - while (1) - { - option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); - if (option_rv == -1) break; - switch (option_rv) - { - case 0: - break; - case OPT_BINARY: - opt_binary = 1; - break; - case OPT_VERBOSE: /* --verbose or -v */ - opt_verbose = OPT_VERBOSE; - break; - case OPT_DEBUG: /* --debug or -d */ - opt_verbose = OPT_DEBUG; - break; - case OPT_VERSION: /* --version or -V */ - version_command(PROGRAM_NAME); - break; - case OPT_HELP: /* --help or -h */ - help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); - break; - case OPT_SERVERS: /* --servers or -s */ - opt_servers= strdup(optarg); - break; - case OPT_EXPIRE: /* --expire */ - opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10); - break; - case OPT_USERNAME: - opt_username= optarg; - break; - case OPT_PASSWD: - opt_passwd= optarg; - break; - case '?': - /* getopt_long already printed an error message. */ - exit(1); - default: - abort(); - } - } -} diff --git a/clients/memflush.cc b/clients/memflush.cc new file mode 100644 index 00000000..848bc1e7 --- /dev/null +++ b/clients/memflush.cc @@ -0,0 +1,154 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include "client_options.h" +#include "utilities.h" + +static int opt_binary= 0; +static int opt_verbose= 0; +static time_t opt_expire= 0; +static char *opt_servers= NULL; +static char *opt_username; +static char *opt_passwd; + +#define PROGRAM_NAME "memflush" +#define PROGRAM_DESCRIPTION "Erase all data in a server of memcached servers." + +/* Prototypes */ +void options_parse(int argc, char *argv[]); + +int main(int argc, char *argv[]) +{ + memcached_st *memc; + memcached_return_t rc; + memcached_server_st *servers; + + options_parse(argc, argv); + + if (!opt_servers) + { + char *temp; + + if ((temp= getenv("MEMCACHED_SERVERS"))) + opt_servers= strdup(temp); + else + { + fprintf(stderr, "No Servers provided\n"); + exit(1); + } + } + + memc= memcached_create(NULL); + + servers= memcached_servers_parse(opt_servers); + memcached_server_push(memc, servers); + memcached_server_list_free(servers); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, + (uint64_t) opt_binary); + + if (!initialize_sasl(memc, opt_username, opt_passwd)) + { + memcached_free(memc); + return EXIT_FAILURE; + } + + rc = memcached_flush(memc, opt_expire); + if (rc != MEMCACHED_SUCCESS) + { + fprintf(stderr, "memflush: memcache error %s", + memcached_strerror(memc, rc)); + if (memcached_last_error_errno(memc)) + fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); + fprintf(stderr, "\n"); + } + + memcached_free(memc); + + free(opt_servers); + + shutdown_sasl(); + + return EXIT_SUCCESS; +} + + +void options_parse(int argc, char *argv[]) +{ + memcached_programs_help_st help_options[]= + { + {0}, + }; + + static struct option long_options[]= + { + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, + {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE}, + {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, + {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, + {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, + {0, 0, 0, 0}, + }; + int option_index= 0; + int option_rv; + + while (1) + { + option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + if (option_rv == -1) break; + switch (option_rv) + { + case 0: + break; + case OPT_BINARY: + opt_binary = 1; + break; + case OPT_VERBOSE: /* --verbose or -v */ + opt_verbose = OPT_VERBOSE; + break; + case OPT_DEBUG: /* --debug or -d */ + opt_verbose = OPT_DEBUG; + break; + case OPT_VERSION: /* --version or -V */ + version_command(PROGRAM_NAME); + break; + case OPT_HELP: /* --help or -h */ + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); + break; + case OPT_SERVERS: /* --servers or -s */ + opt_servers= strdup(optarg); + break; + case OPT_EXPIRE: /* --expire */ + opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10); + break; + case OPT_USERNAME: + opt_username= optarg; + break; + case OPT_PASSWD: + opt_passwd= optarg; + break; + case '?': + /* getopt_long already printed an error message. */ + exit(1); + default: + abort(); + } + } +} diff --git a/clients/memrm.c b/clients/memrm.c deleted file mode 100644 index d4d93c2e..00000000 --- a/clients/memrm.c +++ /dev/null @@ -1,177 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ -#include "config.h" - -#include -#include -#include -#include -#include -#include "client_options.h" -#include "utilities.h" - -static int opt_binary= 0; -static int opt_verbose= 0; -static time_t opt_expire= 0; -static char *opt_servers= NULL; -static char *opt_hash= NULL; -static char *opt_username; -static char *opt_passwd; - -#define PROGRAM_NAME "memrm" -#define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster." - -/* Prototypes */ -static void options_parse(int argc, char *argv[]); - -int main(int argc, char *argv[]) -{ - memcached_st *memc; - memcached_return_t rc; - memcached_server_st *servers; - - int return_code= 0; - - options_parse(argc, argv); - initialize_sockets(); - - if (!opt_servers) - { - char *temp; - - if ((temp= getenv("MEMCACHED_SERVERS"))) - opt_servers= strdup(temp); - else - { - fprintf(stderr, "No Servers provided\n"); - exit(1); - } - } - - memc= memcached_create(NULL); - process_hash_option(memc, opt_hash); - - servers= memcached_servers_parse(opt_servers); - memcached_server_push(memc, servers); - memcached_server_list_free(servers); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, - (uint64_t) opt_binary); - - if (!initialize_sasl(memc, opt_username, opt_passwd)) - { - memcached_free(memc); - return EXIT_FAILURE; - } - - while (optind < argc) - { - if (opt_verbose) - printf("key: %s\nexpires: %llu\n", argv[optind], (unsigned long long)opt_expire); - rc = memcached_delete(memc, argv[optind], strlen(argv[optind]), opt_expire); - - if (rc != MEMCACHED_SUCCESS) - { - fprintf(stderr, "memrm: %s: memcache error %s", - argv[optind], memcached_strerror(memc, rc)); - if (memcached_last_error_errno(memc)) - fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); - fprintf(stderr, "\n"); - - return_code= -1; - } - - optind++; - } - - memcached_free(memc); - - if (opt_servers) - free(opt_servers); - - if (opt_hash) - free(opt_hash); - - shutdown_sasl(); - - return return_code; -} - - -static void options_parse(int argc, char *argv[]) -{ - memcached_programs_help_st help_options[]= - { - {0}, - }; - - static struct option long_options[]= - { - {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, - {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, - {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, - {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, - {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE}, - {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH}, - {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, - {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, - {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, - {0, 0, 0, 0}, - }; - int option_index= 0; - int option_rv; - - while (1) - { - option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); - if (option_rv == -1) break; - switch (option_rv) - { - case 0: - break; - case OPT_BINARY: - opt_binary = 1; - break; - case OPT_VERBOSE: /* --verbose or -v */ - opt_verbose = OPT_VERBOSE; - break; - case OPT_DEBUG: /* --debug or -d */ - opt_verbose = OPT_DEBUG; - break; - case OPT_VERSION: /* --version or -V */ - version_command(PROGRAM_NAME); - break; - case OPT_HELP: /* --help or -h */ - help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); - break; - case OPT_SERVERS: /* --servers or -s */ - opt_servers= strdup(optarg); - break; - case OPT_EXPIRE: /* --expire */ - opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10); - break; - case OPT_HASH: - opt_hash= strdup(optarg); - break; - case OPT_USERNAME: - opt_username= optarg; - break; - case OPT_PASSWD: - opt_passwd= optarg; - break; - case '?': - /* getopt_long already printed an error message. */ - exit(1); - default: - abort(); - } - } -} diff --git a/clients/memrm.cc b/clients/memrm.cc new file mode 100644 index 00000000..d4d93c2e --- /dev/null +++ b/clients/memrm.cc @@ -0,0 +1,177 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include "client_options.h" +#include "utilities.h" + +static int opt_binary= 0; +static int opt_verbose= 0; +static time_t opt_expire= 0; +static char *opt_servers= NULL; +static char *opt_hash= NULL; +static char *opt_username; +static char *opt_passwd; + +#define PROGRAM_NAME "memrm" +#define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster." + +/* Prototypes */ +static void options_parse(int argc, char *argv[]); + +int main(int argc, char *argv[]) +{ + memcached_st *memc; + memcached_return_t rc; + memcached_server_st *servers; + + int return_code= 0; + + options_parse(argc, argv); + initialize_sockets(); + + if (!opt_servers) + { + char *temp; + + if ((temp= getenv("MEMCACHED_SERVERS"))) + opt_servers= strdup(temp); + else + { + fprintf(stderr, "No Servers provided\n"); + exit(1); + } + } + + memc= memcached_create(NULL); + process_hash_option(memc, opt_hash); + + servers= memcached_servers_parse(opt_servers); + memcached_server_push(memc, servers); + memcached_server_list_free(servers); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, + (uint64_t) opt_binary); + + if (!initialize_sasl(memc, opt_username, opt_passwd)) + { + memcached_free(memc); + return EXIT_FAILURE; + } + + while (optind < argc) + { + if (opt_verbose) + printf("key: %s\nexpires: %llu\n", argv[optind], (unsigned long long)opt_expire); + rc = memcached_delete(memc, argv[optind], strlen(argv[optind]), opt_expire); + + if (rc != MEMCACHED_SUCCESS) + { + fprintf(stderr, "memrm: %s: memcache error %s", + argv[optind], memcached_strerror(memc, rc)); + if (memcached_last_error_errno(memc)) + fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); + fprintf(stderr, "\n"); + + return_code= -1; + } + + optind++; + } + + memcached_free(memc); + + if (opt_servers) + free(opt_servers); + + if (opt_hash) + free(opt_hash); + + shutdown_sasl(); + + return return_code; +} + + +static void options_parse(int argc, char *argv[]) +{ + memcached_programs_help_st help_options[]= + { + {0}, + }; + + static struct option long_options[]= + { + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, + {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE}, + {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH}, + {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, + {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, + {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, + {0, 0, 0, 0}, + }; + int option_index= 0; + int option_rv; + + while (1) + { + option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + if (option_rv == -1) break; + switch (option_rv) + { + case 0: + break; + case OPT_BINARY: + opt_binary = 1; + break; + case OPT_VERBOSE: /* --verbose or -v */ + opt_verbose = OPT_VERBOSE; + break; + case OPT_DEBUG: /* --debug or -d */ + opt_verbose = OPT_DEBUG; + break; + case OPT_VERSION: /* --version or -V */ + version_command(PROGRAM_NAME); + break; + case OPT_HELP: /* --help or -h */ + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); + break; + case OPT_SERVERS: /* --servers or -s */ + opt_servers= strdup(optarg); + break; + case OPT_EXPIRE: /* --expire */ + opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10); + break; + case OPT_HASH: + opt_hash= strdup(optarg); + break; + case OPT_USERNAME: + opt_username= optarg; + break; + case OPT_PASSWD: + opt_passwd= optarg; + break; + case '?': + /* getopt_long already printed an error message. */ + exit(1); + default: + abort(); + } + } +} diff --git a/clients/memslap.c b/clients/memslap.c deleted file mode 100644 index 0d77fd6e..00000000 --- a/clients/memslap.c +++ /dev/null @@ -1,495 +0,0 @@ -/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: - * - * Libmemcached library - * - * Copyright (C) 2011 Data Differential, http://datadifferential.com/ - * Copyright (C) 2006-2009 Brian Aker All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * * The names of its contributors may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "client_options.h" -#include "utilities.h" -#include "generator.h" -#include "execute.h" - -#define DEFAULT_INITIAL_LOAD 10000 -#define DEFAULT_EXECUTE_NUMBER 10000 -#define DEFAULT_CONCURRENCY 1 - -#define PROGRAM_NAME "memslap" -#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers." - -/* Global Thread counter */ -volatile unsigned int thread_counter; -pthread_mutex_t counter_mutex; -pthread_cond_t count_threshhold; -volatile unsigned int master_wakeup; -pthread_mutex_t sleeper_mutex; -pthread_cond_t sleep_threshhold; - -void *run_task(void *p); - -/* Types */ -typedef struct conclusions_st conclusions_st; -typedef struct thread_context_st thread_context_st; -typedef enum { - SET_TEST, - GET_TEST, - MGET_TEST -} test_type; - -struct thread_context_st { - unsigned int key_count; - pairs_st *initial_pairs; - unsigned int initial_number; - pairs_st *execute_pairs; - unsigned int execute_number; - char **keys; - size_t *key_lengths; - test_type test; - memcached_st *memc; -}; - -struct conclusions_st { - long int load_time; - long int read_time; - unsigned int rows_loaded; - unsigned int rows_read; -}; - -/* Prototypes */ -void options_parse(int argc, char *argv[]); -void conclusions_print(conclusions_st *conclusion); -void scheduler(memcached_server_st *servers, conclusions_st *conclusion); -pairs_st *load_create_data(memcached_st *memc, unsigned int number_of, - unsigned int *actual_loaded); -void flush_all(memcached_st *memc); - -static int opt_binary= 0; -static int opt_verbose= 0; -static int opt_flush= 0; -static int opt_non_blocking_io= 0; -static int opt_tcp_nodelay= 0; -static unsigned int opt_execute_number= 0; -static unsigned int opt_createial_load= 0; -static unsigned int opt_concurrency= 0; -static int opt_displayflag= 0; -static char *opt_servers= NULL; -static int opt_udp_io= 0; -test_type opt_test= SET_TEST; - -int main(int argc, char *argv[]) -{ - conclusions_st conclusion; - memcached_server_st *servers; - - memset(&conclusion, 0, sizeof(conclusions_st)); - - srandom((unsigned int)time(NULL)); - options_parse(argc, argv); - - if (!opt_servers) - { - char *temp; - - if ((temp= getenv("MEMCACHED_SERVERS"))) - opt_servers= strdup(temp); - else - { - fprintf(stderr, "No Servers provided\n"); - exit(1); - } - } - - servers= memcached_servers_parse(opt_servers); - - pthread_mutex_init(&counter_mutex, NULL); - pthread_cond_init(&count_threshhold, NULL); - pthread_mutex_init(&sleeper_mutex, NULL); - pthread_cond_init(&sleep_threshhold, NULL); - - scheduler(servers, &conclusion); - - free(opt_servers); - - (void)pthread_mutex_destroy(&counter_mutex); - (void)pthread_cond_destroy(&count_threshhold); - (void)pthread_mutex_destroy(&sleeper_mutex); - (void)pthread_cond_destroy(&sleep_threshhold); - conclusions_print(&conclusion); - memcached_server_list_free(servers); - - return 0; -} - -void scheduler(memcached_server_st *servers, conclusions_st *conclusion) -{ - unsigned int actual_loaded= 0; /* Fix warning */ - memcached_st *memc; - - struct timeval start_time, end_time; - pthread_t mainthread; /* Thread descriptor */ - pthread_attr_t attr; /* Thread attributes */ - pairs_st *pairs= NULL; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, - PTHREAD_CREATE_DETACHED); - - memc= memcached_create(NULL); - - /* We need to set udp behavior before adding servers to the client */ - if (opt_udp_io) - { - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, - (uint64_t)opt_udp_io); - for (uint32_t x= 0; x < memcached_server_list_count(servers); x++ ) - { - servers[x].type= MEMCACHED_CONNECTION_UDP; - } - } - memcached_server_push(memc, servers); - - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, - (uint64_t)opt_binary); - - if (opt_flush) - flush_all(memc); - if (opt_createial_load) - pairs= load_create_data(memc, opt_createial_load, &actual_loaded); - - char **keys= calloc(actual_loaded, sizeof(char*)); - size_t *key_lengths= calloc(actual_loaded, sizeof(size_t)); - - if (keys == NULL || key_lengths == NULL) - { - free(keys); - free(key_lengths); - keys= NULL; - key_lengths= NULL; - } - else - { - for (uint32_t x= 0; x < actual_loaded; ++x) - { - keys[x]= pairs[x].key; - key_lengths[x]= pairs[x].key_length; - } - } - - /* We set this after we have loaded */ - { - if (opt_non_blocking_io) - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1); - if (opt_tcp_nodelay) - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1); - } - - pthread_mutex_lock(&counter_mutex); - thread_counter= 0; - - pthread_mutex_lock(&sleeper_mutex); - master_wakeup= 1; - pthread_mutex_unlock(&sleeper_mutex); - - for (uint32_t x= 0; x < opt_concurrency; x++) - { - thread_context_st *context; - context= (thread_context_st *)calloc(1, sizeof(thread_context_st)); - - context->memc= memcached_clone(NULL, memc); - context->test= opt_test; - - context->initial_pairs= pairs; - context->initial_number= actual_loaded; - context->keys= keys; - context->key_lengths= key_lengths; - - if (opt_test == SET_TEST) - { - context->execute_pairs= pairs_generate(opt_execute_number, 400); - context->execute_number= opt_execute_number; - } - - /* now you create the thread */ - if (pthread_create(&mainthread, &attr, run_task, - (void *)context) != 0) - { - fprintf(stderr,"Could not create thread\n"); - exit(1); - } - thread_counter++; - } - - pthread_mutex_unlock(&counter_mutex); - pthread_attr_destroy(&attr); - - pthread_mutex_lock(&sleeper_mutex); - master_wakeup= 0; - pthread_mutex_unlock(&sleeper_mutex); - pthread_cond_broadcast(&sleep_threshhold); - - gettimeofday(&start_time, NULL); - /* - We loop until we know that all children have cleaned up. - */ - pthread_mutex_lock(&counter_mutex); - while (thread_counter) - pthread_cond_wait(&count_threshhold, &counter_mutex); - pthread_mutex_unlock(&counter_mutex); - - gettimeofday(&end_time, NULL); - - conclusion->load_time= timedif(end_time, start_time); - conclusion->read_time= timedif(end_time, start_time); - free(keys); - free(key_lengths); - pairs_free(pairs); - memcached_free(memc); -} - -void options_parse(int argc, char *argv[]) -{ - memcached_programs_help_st help_options[]= - { - {0}, - }; - - static struct option long_options[]= - { - {(OPTIONSTRING)"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY}, - {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, - {(OPTIONSTRING)"execute-number", required_argument, NULL, OPT_SLAP_EXECUTE_NUMBER}, - {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG}, - {(OPTIONSTRING)"flush", no_argument, &opt_flush, OPT_FLUSH}, - {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, - {(OPTIONSTRING)"initial-load", required_argument, NULL, OPT_SLAP_INITIAL_LOAD}, /* Number to load initially */ - {(OPTIONSTRING)"non-blocking", no_argument, &opt_non_blocking_io, OPT_SLAP_NON_BLOCK}, - {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, - {(OPTIONSTRING)"tcp-nodelay", no_argument, &opt_tcp_nodelay, OPT_SLAP_TCP_NODELAY}, - {(OPTIONSTRING)"test", required_argument, NULL, OPT_SLAP_TEST}, - {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, - {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, - {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP}, - {0, 0, 0, 0}, - }; - - int option_index= 0; - int option_rv; - - while (1) - { - option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); - if (option_rv == -1) break; - switch (option_rv) - { - case 0: - break; - case OPT_UDP: - if (opt_test == GET_TEST) - { - fprintf(stderr, "You can not run a get test in UDP mode. UDP mode " - "does not currently support get ops.\n"); - exit(1); - } - opt_udp_io= 1; - break; - case OPT_BINARY: - opt_binary = 1; - break; - case OPT_VERBOSE: /* --verbose or -v */ - opt_verbose = OPT_VERBOSE; - break; - case OPT_DEBUG: /* --debug or -d */ - opt_verbose = OPT_DEBUG; - break; - case OPT_VERSION: /* --version or -V */ - version_command(PROGRAM_NAME); - break; - case OPT_HELP: /* --help or -h */ - help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); - break; - case OPT_SERVERS: /* --servers or -s */ - opt_servers= strdup(optarg); - break; - case OPT_SLAP_TEST: - if (!strcmp(optarg, "get")) - { - if (opt_udp_io == 1) - { - fprintf(stderr, "You can not run a get test in UDP mode. UDP mode " - "does not currently support get ops.\n"); - exit(1); - } - opt_test= GET_TEST ; - } - else if (!strcmp(optarg, "set")) - opt_test= SET_TEST; - else if (!strcmp(optarg, "mget")) - { - opt_test= MGET_TEST; - } - else - { - fprintf(stderr, "Your test, %s, is not a known test\n", optarg); - exit(1); - } - break; - case OPT_SLAP_CONCURRENCY: - opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10); - break; - case OPT_SLAP_EXECUTE_NUMBER: - opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10); - break; - case OPT_SLAP_INITIAL_LOAD: - opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10); - break; - case '?': - /* getopt_long already printed an error message. */ - exit(1); - default: - abort(); - } - } - - if ((opt_test == GET_TEST || opt_test == MGET_TEST) && opt_createial_load == 0) - opt_createial_load= DEFAULT_INITIAL_LOAD; - - if (opt_execute_number == 0) - opt_execute_number= DEFAULT_EXECUTE_NUMBER; - - if (opt_concurrency == 0) - opt_concurrency= DEFAULT_CONCURRENCY; -} - -void conclusions_print(conclusions_st *conclusion) -{ - printf("\tThreads connecting to servers %u\n", opt_concurrency); -#ifdef NOT_FINISHED - printf("\tLoaded %u rows\n", conclusion->rows_loaded); - printf("\tRead %u rows\n", conclusion->rows_read); -#endif - if (opt_test == SET_TEST) - printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000, - conclusion->load_time % 1000); - else - printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000, - conclusion->read_time % 1000); -} - -void *run_task(void *p) -{ - thread_context_st *context= (thread_context_st *)p; - memcached_st *memc; - - memc= context->memc; - - pthread_mutex_lock(&sleeper_mutex); - while (master_wakeup) - { - pthread_cond_wait(&sleep_threshhold, &sleeper_mutex); - } - pthread_mutex_unlock(&sleeper_mutex); - - /* Do Stuff */ - switch (context->test) - { - case SET_TEST: - assert(context->execute_pairs); - execute_set(memc, context->execute_pairs, context->execute_number); - break; - case GET_TEST: - execute_get(memc, context->initial_pairs, context->initial_number); - break; - case MGET_TEST: - execute_mget(memc, (const char*const*)context->keys, context->key_lengths, - context->initial_number); - break; - default: - WATCHPOINT_ASSERT(context->test); - break; - } - - memcached_free(memc); - - if (context->execute_pairs) - pairs_free(context->execute_pairs); - - free(context); - - pthread_mutex_lock(&counter_mutex); - thread_counter--; - pthread_cond_signal(&count_threshhold); - pthread_mutex_unlock(&counter_mutex); - - return NULL; -} - -void flush_all(memcached_st *memc) -{ - memcached_flush(memc, 0); -} - -pairs_st *load_create_data(memcached_st *memc, unsigned int number_of, - unsigned int *actual_loaded) -{ - memcached_st *memc_clone; - pairs_st *pairs; - - memc_clone= memcached_clone(NULL, memc); - /* We always used non-blocking IO for load since it is faster */ - memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NO_BLOCK, 0); - - pairs= pairs_generate(number_of, 400); - *actual_loaded= execute_set(memc_clone, pairs, number_of); - - memcached_free(memc_clone); - - return pairs; -} diff --git a/clients/memslap.cc b/clients/memslap.cc new file mode 100644 index 00000000..d8927e7e --- /dev/null +++ b/clients/memslap.cc @@ -0,0 +1,495 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "client_options.h" +#include "utilities.h" +#include "generator.h" +#include "execute.h" + +#define DEFAULT_INITIAL_LOAD 10000 +#define DEFAULT_EXECUTE_NUMBER 10000 +#define DEFAULT_CONCURRENCY 1 + +#define PROGRAM_NAME "memslap" +#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers." + +/* Global Thread counter */ +volatile unsigned int thread_counter; +pthread_mutex_t counter_mutex; +pthread_cond_t count_threshhold; +volatile unsigned int master_wakeup; +pthread_mutex_t sleeper_mutex; +pthread_cond_t sleep_threshhold; + +void *run_task(void *p); + +/* Types */ +typedef struct conclusions_st conclusions_st; +typedef struct thread_context_st thread_context_st; +typedef enum { + SET_TEST, + GET_TEST, + MGET_TEST +} test_type; + +struct thread_context_st { + unsigned int key_count; + pairs_st *initial_pairs; + unsigned int initial_number; + pairs_st *execute_pairs; + unsigned int execute_number; + char **keys; + size_t *key_lengths; + test_type test; + memcached_st *memc; +}; + +struct conclusions_st { + long int load_time; + long int read_time; + unsigned int rows_loaded; + unsigned int rows_read; +}; + +/* Prototypes */ +void options_parse(int argc, char *argv[]); +void conclusions_print(conclusions_st *conclusion); +void scheduler(memcached_server_st *servers, conclusions_st *conclusion); +pairs_st *load_create_data(memcached_st *memc, unsigned int number_of, + unsigned int *actual_loaded); +void flush_all(memcached_st *memc); + +static int opt_binary= 0; +static int opt_verbose= 0; +static int opt_flush= 0; +static int opt_non_blocking_io= 0; +static int opt_tcp_nodelay= 0; +static unsigned int opt_execute_number= 0; +static unsigned int opt_createial_load= 0; +static unsigned int opt_concurrency= 0; +static int opt_displayflag= 0; +static char *opt_servers= NULL; +static int opt_udp_io= 0; +test_type opt_test= SET_TEST; + +int main(int argc, char *argv[]) +{ + conclusions_st conclusion; + memcached_server_st *servers; + + memset(&conclusion, 0, sizeof(conclusions_st)); + + srandom((unsigned int)time(NULL)); + options_parse(argc, argv); + + if (!opt_servers) + { + char *temp; + + if ((temp= getenv("MEMCACHED_SERVERS"))) + opt_servers= strdup(temp); + else + { + fprintf(stderr, "No Servers provided\n"); + exit(1); + } + } + + servers= memcached_servers_parse(opt_servers); + + pthread_mutex_init(&counter_mutex, NULL); + pthread_cond_init(&count_threshhold, NULL); + pthread_mutex_init(&sleeper_mutex, NULL); + pthread_cond_init(&sleep_threshhold, NULL); + + scheduler(servers, &conclusion); + + free(opt_servers); + + (void)pthread_mutex_destroy(&counter_mutex); + (void)pthread_cond_destroy(&count_threshhold); + (void)pthread_mutex_destroy(&sleeper_mutex); + (void)pthread_cond_destroy(&sleep_threshhold); + conclusions_print(&conclusion); + memcached_server_list_free(servers); + + return 0; +} + +void scheduler(memcached_server_st *servers, conclusions_st *conclusion) +{ + unsigned int actual_loaded= 0; /* Fix warning */ + memcached_st *memc; + + struct timeval start_time, end_time; + pthread_t mainthread; /* Thread descriptor */ + pthread_attr_t attr; /* Thread attributes */ + pairs_st *pairs= NULL; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, + PTHREAD_CREATE_DETACHED); + + memc= memcached_create(NULL); + + /* We need to set udp behavior before adding servers to the client */ + if (opt_udp_io) + { + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, + (uint64_t)opt_udp_io); + for (uint32_t x= 0; x < memcached_server_list_count(servers); x++ ) + { + servers[x].type= MEMCACHED_CONNECTION_UDP; + } + } + memcached_server_push(memc, servers); + + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, + (uint64_t)opt_binary); + + if (opt_flush) + flush_all(memc); + if (opt_createial_load) + pairs= load_create_data(memc, opt_createial_load, &actual_loaded); + + char **keys= static_cast(calloc(actual_loaded, sizeof(char*))); + size_t *key_lengths= static_cast(calloc(actual_loaded, sizeof(size_t))); + + if (keys == NULL || key_lengths == NULL) + { + free(keys); + free(key_lengths); + keys= NULL; + key_lengths= NULL; + } + else + { + for (uint32_t x= 0; x < actual_loaded; ++x) + { + keys[x]= pairs[x].key; + key_lengths[x]= pairs[x].key_length; + } + } + + /* We set this after we have loaded */ + { + if (opt_non_blocking_io) + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1); + if (opt_tcp_nodelay) + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1); + } + + pthread_mutex_lock(&counter_mutex); + thread_counter= 0; + + pthread_mutex_lock(&sleeper_mutex); + master_wakeup= 1; + pthread_mutex_unlock(&sleeper_mutex); + + for (uint32_t x= 0; x < opt_concurrency; x++) + { + thread_context_st *context; + context= (thread_context_st *)calloc(1, sizeof(thread_context_st)); + + context->memc= memcached_clone(NULL, memc); + context->test= opt_test; + + context->initial_pairs= pairs; + context->initial_number= actual_loaded; + context->keys= keys; + context->key_lengths= key_lengths; + + if (opt_test == SET_TEST) + { + context->execute_pairs= pairs_generate(opt_execute_number, 400); + context->execute_number= opt_execute_number; + } + + /* now you create the thread */ + if (pthread_create(&mainthread, &attr, run_task, + (void *)context) != 0) + { + fprintf(stderr,"Could not create thread\n"); + exit(1); + } + thread_counter++; + } + + pthread_mutex_unlock(&counter_mutex); + pthread_attr_destroy(&attr); + + pthread_mutex_lock(&sleeper_mutex); + master_wakeup= 0; + pthread_mutex_unlock(&sleeper_mutex); + pthread_cond_broadcast(&sleep_threshhold); + + gettimeofday(&start_time, NULL); + /* + We loop until we know that all children have cleaned up. + */ + pthread_mutex_lock(&counter_mutex); + while (thread_counter) + pthread_cond_wait(&count_threshhold, &counter_mutex); + pthread_mutex_unlock(&counter_mutex); + + gettimeofday(&end_time, NULL); + + conclusion->load_time= timedif(end_time, start_time); + conclusion->read_time= timedif(end_time, start_time); + free(keys); + free(key_lengths); + pairs_free(pairs); + memcached_free(memc); +} + +void options_parse(int argc, char *argv[]) +{ + memcached_programs_help_st help_options[]= + { + {0}, + }; + + static struct option long_options[]= + { + {(OPTIONSTRING)"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {(OPTIONSTRING)"execute-number", required_argument, NULL, OPT_SLAP_EXECUTE_NUMBER}, + {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG}, + {(OPTIONSTRING)"flush", no_argument, &opt_flush, OPT_FLUSH}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"initial-load", required_argument, NULL, OPT_SLAP_INITIAL_LOAD}, /* Number to load initially */ + {(OPTIONSTRING)"non-blocking", no_argument, &opt_non_blocking_io, OPT_SLAP_NON_BLOCK}, + {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, + {(OPTIONSTRING)"tcp-nodelay", no_argument, &opt_tcp_nodelay, OPT_SLAP_TCP_NODELAY}, + {(OPTIONSTRING)"test", required_argument, NULL, OPT_SLAP_TEST}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, + {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP}, + {0, 0, 0, 0}, + }; + + int option_index= 0; + int option_rv; + + while (1) + { + option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + if (option_rv == -1) break; + switch (option_rv) + { + case 0: + break; + case OPT_UDP: + if (opt_test == GET_TEST) + { + fprintf(stderr, "You can not run a get test in UDP mode. UDP mode " + "does not currently support get ops.\n"); + exit(1); + } + opt_udp_io= 1; + break; + case OPT_BINARY: + opt_binary = 1; + break; + case OPT_VERBOSE: /* --verbose or -v */ + opt_verbose = OPT_VERBOSE; + break; + case OPT_DEBUG: /* --debug or -d */ + opt_verbose = OPT_DEBUG; + break; + case OPT_VERSION: /* --version or -V */ + version_command(PROGRAM_NAME); + break; + case OPT_HELP: /* --help or -h */ + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); + break; + case OPT_SERVERS: /* --servers or -s */ + opt_servers= strdup(optarg); + break; + case OPT_SLAP_TEST: + if (!strcmp(optarg, "get")) + { + if (opt_udp_io == 1) + { + fprintf(stderr, "You can not run a get test in UDP mode. UDP mode " + "does not currently support get ops.\n"); + exit(1); + } + opt_test= GET_TEST ; + } + else if (!strcmp(optarg, "set")) + opt_test= SET_TEST; + else if (!strcmp(optarg, "mget")) + { + opt_test= MGET_TEST; + } + else + { + fprintf(stderr, "Your test, %s, is not a known test\n", optarg); + exit(1); + } + break; + case OPT_SLAP_CONCURRENCY: + opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10); + break; + case OPT_SLAP_EXECUTE_NUMBER: + opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10); + break; + case OPT_SLAP_INITIAL_LOAD: + opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10); + break; + case '?': + /* getopt_long already printed an error message. */ + exit(1); + default: + abort(); + } + } + + if ((opt_test == GET_TEST || opt_test == MGET_TEST) && opt_createial_load == 0) + opt_createial_load= DEFAULT_INITIAL_LOAD; + + if (opt_execute_number == 0) + opt_execute_number= DEFAULT_EXECUTE_NUMBER; + + if (opt_concurrency == 0) + opt_concurrency= DEFAULT_CONCURRENCY; +} + +void conclusions_print(conclusions_st *conclusion) +{ + printf("\tThreads connecting to servers %u\n", opt_concurrency); +#ifdef NOT_FINISHED + printf("\tLoaded %u rows\n", conclusion->rows_loaded); + printf("\tRead %u rows\n", conclusion->rows_read); +#endif + if (opt_test == SET_TEST) + printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000, + conclusion->load_time % 1000); + else + printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000, + conclusion->read_time % 1000); +} + +void *run_task(void *p) +{ + thread_context_st *context= (thread_context_st *)p; + memcached_st *memc; + + memc= context->memc; + + pthread_mutex_lock(&sleeper_mutex); + while (master_wakeup) + { + pthread_cond_wait(&sleep_threshhold, &sleeper_mutex); + } + pthread_mutex_unlock(&sleeper_mutex); + + /* Do Stuff */ + switch (context->test) + { + case SET_TEST: + assert(context->execute_pairs); + execute_set(memc, context->execute_pairs, context->execute_number); + break; + case GET_TEST: + execute_get(memc, context->initial_pairs, context->initial_number); + break; + case MGET_TEST: + execute_mget(memc, (const char*const*)context->keys, context->key_lengths, + context->initial_number); + break; + default: + WATCHPOINT_ASSERT(context->test); + break; + } + + memcached_free(memc); + + if (context->execute_pairs) + pairs_free(context->execute_pairs); + + free(context); + + pthread_mutex_lock(&counter_mutex); + thread_counter--; + pthread_cond_signal(&count_threshhold); + pthread_mutex_unlock(&counter_mutex); + + return NULL; +} + +void flush_all(memcached_st *memc) +{ + memcached_flush(memc, 0); +} + +pairs_st *load_create_data(memcached_st *memc, unsigned int number_of, + unsigned int *actual_loaded) +{ + memcached_st *memc_clone; + pairs_st *pairs; + + memc_clone= memcached_clone(NULL, memc); + /* We always used non-blocking IO for load since it is faster */ + memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NO_BLOCK, 0); + + pairs= pairs_generate(number_of, 400); + *actual_loaded= execute_set(memc_clone, pairs, number_of); + + memcached_free(memc_clone); + + return pairs; +} diff --git a/clients/memstat.c b/clients/memstat.c deleted file mode 100644 index 765e7ab7..00000000 --- a/clients/memstat.c +++ /dev/null @@ -1,351 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - * Authors: - * Brian Aker - * Toru Maesaka - */ -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "client_options.h" -#include "utilities.h" - -#define PROGRAM_NAME "memstat" -#define PROGRAM_DESCRIPTION "Output the state of a memcached cluster." - -/* Prototypes */ -static void options_parse(int argc, char *argv[]); -static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat); -static void print_analysis_report(memcached_st *memc, - memcached_analysis_st *report); - -static int opt_verbose= 0; -static int opt_displayflag= 0; -static int opt_analyze= 0; -static char *opt_servers= NULL; -static char *stat_args= NULL; -static char *analyze_mode= NULL; - -static struct option long_options[]= -{ - {(OPTIONSTRING)"args", required_argument, NULL, OPT_STAT_ARGS}, - {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, - {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, - {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, - {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, - {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG}, - {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE}, - {0, 0, 0, 0}, -}; - - -static memcached_return_t stat_printer(memcached_server_instance_st instance, - const char *key, size_t key_length, - const char *value, size_t value_length, - void *context) -{ - static memcached_server_instance_st last= NULL; - (void)context; - - if (last != instance) - { - printf("Server: %s (%u)\n", memcached_server_name(instance), - (uint32_t)memcached_server_port(instance)); - last= instance; - } - - printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value); - - return MEMCACHED_SUCCESS; -} - -int main(int argc, char *argv[]) -{ - memcached_return_t rc; - memcached_st *memc; - memcached_server_st *servers; - - options_parse(argc, argv); - initialize_sockets(); - - if (! opt_servers) - { - char *temp; - - if ((temp= getenv("MEMCACHED_SERVERS"))) - opt_servers= strdup(temp); - else - { - fprintf(stderr, "No Servers provided\n\n"); - help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, 0); - exit(1); - } - } - - memc= memcached_create(NULL); - - servers= memcached_servers_parse(opt_servers); - rc= memcached_server_push(memc, servers); - memcached_server_list_free(servers); - - if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS) - { - printf("Failure to communicate with servers (%s)\n", - memcached_strerror(memc, rc)); - exit(1); - } - - if (opt_analyze) - { - memcached_stat_st *memc_stat; - - memc_stat= memcached_stat(memc, NULL, &rc); - - if (! memc_stat) - exit(-1); - - run_analyzer(memc, memc_stat); - - memcached_stat_free(memc, memc_stat); - } - else - { - rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL); - } - - free(opt_servers); - - memcached_free(memc); - - return rc == MEMCACHED_SUCCESS ? 0: -1; -} - -static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat) -{ - memcached_return_t rc; - - if (analyze_mode == NULL) - { - memcached_analysis_st *report; - report= memcached_analyze(memc, memc_stat, &rc); - if (rc != MEMCACHED_SUCCESS || report == NULL) - { - printf("Failure to analyze servers (%s)\n", - memcached_strerror(memc, rc)); - exit(1); - } - print_analysis_report(memc, report); - free(report); - } - else if (strcmp(analyze_mode, "latency") == 0) - { - memcached_st **servers; - uint32_t flags, server_count= memcached_server_count(memc); - uint32_t num_of_tests= 32; - const char *test_key= "libmemcached_test_key"; - - servers= malloc(sizeof(memcached_st*) * server_count); - if (!servers) - { - fprintf(stderr, "Failed to allocate memory\n"); - return; - } - - for (uint32_t x= 0; x < server_count; x++) - { - memcached_server_instance_st instance= - memcached_server_instance_by_position(memc, x); - - if ((servers[x]= memcached_create(NULL)) == NULL) - { - fprintf(stderr, "Failed to memcached_create()\n"); - if (x > 0) - memcached_free(servers[0]); - x--; - for (; x > 0; x--) - memcached_free(servers[x]); - - free(servers); - return; - } - memcached_server_add(servers[x], - memcached_server_name(instance), - memcached_server_port(instance)); - } - - printf("Network Latency Test:\n\n"); - struct timeval start_time, end_time; - uint32_t slowest_server= 0; - long elapsed_time, slowest_time= 0; - - for (uint32_t x= 0; x < server_count; x++) - { - memcached_server_instance_st instance= - memcached_server_instance_by_position(memc, x); - gettimeofday(&start_time, NULL); - - for (uint32_t y= 0; y < num_of_tests; y++) - { - size_t vlen; - char *val= memcached_get(servers[x], test_key, strlen(test_key), - &vlen, &flags, &rc); - if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS) - break; - free(val); - } - gettimeofday(&end_time, NULL); - - elapsed_time= (long) timedif(end_time, start_time); - elapsed_time /= (long) num_of_tests; - - if (elapsed_time > slowest_time) - { - slowest_server= x; - slowest_time= elapsed_time; - } - - if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS) - { - printf("\t %s (%d) => failed to reach the server\n", - memcached_server_name(instance), - memcached_server_port(instance)); - } - else - { - printf("\t %s (%d) => %ld.%ld seconds\n", - memcached_server_name(instance), - memcached_server_port(instance), - elapsed_time / 1000, elapsed_time % 1000); - } - } - - if (server_count > 1 && slowest_time > 0) - { - memcached_server_instance_st slowest= - memcached_server_instance_by_position(memc, slowest_server); - - printf("---\n"); - printf("Slowest Server: %s (%d) => %ld.%ld seconds\n", - memcached_server_name(slowest), - memcached_server_port(slowest), - slowest_time / 1000, slowest_time % 1000); - } - printf("\n"); - - for (uint32_t x= 0; x < server_count; x++) - memcached_free(servers[x]); - - free(servers); - free(analyze_mode); - } - else - { - fprintf(stderr, "Invalid Analyzer Option provided\n"); - free(analyze_mode); - } -} - -static void print_analysis_report(memcached_st *memc, - memcached_analysis_st *report) - -{ - uint32_t server_count= memcached_server_count(memc); - memcached_server_instance_st most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server); - memcached_server_instance_st least_free_server= memcached_server_instance_by_position(memc, report->least_free_server); - memcached_server_instance_st oldest_server= memcached_server_instance_by_position(memc, report->oldest_server); - - printf("Memcached Cluster Analysis Report\n\n"); - - printf("\tNumber of Servers Analyzed : %u\n", server_count); - printf("\tAverage Item Size (incl/overhead) : %u bytes\n", - report->average_item_size); - - if (server_count == 1) - { - printf("\nFor a detailed report, you must supply multiple servers.\n"); - return; - } - - printf("\n"); - printf("\tNode with most memory consumption : %s:%u (%llu bytes)\n", - memcached_server_name(most_consumed_server), - (uint32_t)memcached_server_port(most_consumed_server), - (unsigned long long)report->most_used_bytes); - printf("\tNode with least free space : %s:%u (%llu bytes remaining)\n", - memcached_server_name(least_free_server), - (uint32_t)memcached_server_port(least_free_server), - (unsigned long long)report->least_remaining_bytes); - printf("\tNode with longest uptime : %s:%u (%us)\n", - memcached_server_name(oldest_server), - (uint32_t)memcached_server_port(oldest_server), - report->longest_uptime); - printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio); - printf("\n"); -} - -static void options_parse(int argc, char *argv[]) -{ - memcached_programs_help_st help_options[]= - { - {0}, - }; - - int option_index= 0; - int option_rv; - - while (1) - { - option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index); - if (option_rv == -1) break; - switch (option_rv) - { - case 0: - break; - case OPT_VERBOSE: /* --verbose or -v */ - opt_verbose = OPT_VERBOSE; - break; - case OPT_DEBUG: /* --debug or -d */ - opt_verbose = OPT_DEBUG; - break; - case OPT_VERSION: /* --version or -V */ - version_command(PROGRAM_NAME); - break; - case OPT_HELP: /* --help or -h */ - help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); - break; - case OPT_SERVERS: /* --servers or -s */ - opt_servers= strdup(optarg); - break; - case OPT_STAT_ARGS: - stat_args= strdup(optarg); - break; - case OPT_ANALYZE: /* --analyze or -a */ - opt_analyze= OPT_ANALYZE; - analyze_mode= (optarg) ? strdup(optarg) : NULL; - break; - case '?': - /* getopt_long already printed an error message. */ - exit(1); - default: - abort(); - } - } -} diff --git a/clients/memstat.cc b/clients/memstat.cc new file mode 100644 index 00000000..a3b85108 --- /dev/null +++ b/clients/memstat.cc @@ -0,0 +1,349 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + * Authors: + * Brian Aker + * Toru Maesaka + */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "client_options.h" +#include "utilities.h" + +#define PROGRAM_NAME "memstat" +#define PROGRAM_DESCRIPTION "Output the state of a memcached cluster." + +/* Prototypes */ +static void options_parse(int argc, char *argv[]); +static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat); +static void print_analysis_report(memcached_st *memc, + memcached_analysis_st *report); + +static int opt_verbose= 0; +static int opt_displayflag= 0; +static int opt_analyze= 0; +static char *opt_servers= NULL; +static char *stat_args= NULL; +static char *analyze_mode= NULL; + +static struct option long_options[]= +{ + {(OPTIONSTRING)"args", required_argument, NULL, OPT_STAT_ARGS}, + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, + {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG}, + {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE}, + {0, 0, 0, 0}, +}; + + +static memcached_return_t stat_printer(memcached_server_instance_st instance, + const char *key, size_t key_length, + const char *value, size_t value_length, + void *context) +{ + static memcached_server_instance_st last= NULL; + (void)context; + + if (last != instance) + { + printf("Server: %s (%u)\n", memcached_server_name(instance), + (uint32_t)memcached_server_port(instance)); + last= instance; + } + + printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value); + + return MEMCACHED_SUCCESS; +} + +int main(int argc, char *argv[]) +{ + options_parse(argc, argv); + initialize_sockets(); + + if (! opt_servers) + { + char *temp; + + if ((temp= getenv("MEMCACHED_SERVERS"))) + opt_servers= strdup(temp); + else + { + fprintf(stderr, "No Servers provided\n\n"); + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, 0); + exit(1); + } + } + + memcached_st *memc= memcached_create(NULL); + + memcached_server_st *servers= memcached_servers_parse(opt_servers); + free(opt_servers); + + memcached_return_t rc= memcached_server_push(memc, servers); + memcached_server_list_free(servers); + + if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS) + { + printf("Failure to communicate with servers (%s)\n", + memcached_strerror(memc, rc)); + exit(1); + } + + if (opt_analyze) + { + memcached_stat_st *memc_stat; + + memc_stat= memcached_stat(memc, NULL, &rc); + + if (! memc_stat) + exit(-1); + + run_analyzer(memc, memc_stat); + + memcached_stat_free(memc, memc_stat); + } + else + { + rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL); + } + + memcached_free(memc); + + return rc == MEMCACHED_SUCCESS ? EXIT_SUCCESS: EXIT_FAILURE; +} + +static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat) +{ + memcached_return_t rc; + + if (analyze_mode == NULL) + { + memcached_analysis_st *report; + report= memcached_analyze(memc, memc_stat, &rc); + if (rc != MEMCACHED_SUCCESS || report == NULL) + { + printf("Failure to analyze servers (%s)\n", + memcached_strerror(memc, rc)); + exit(1); + } + print_analysis_report(memc, report); + free(report); + } + else if (strcmp(analyze_mode, "latency") == 0) + { + uint32_t flags, server_count= memcached_server_count(memc); + uint32_t num_of_tests= 32; + const char *test_key= "libmemcached_test_key"; + + memcached_st **servers; + servers= static_cast(malloc(sizeof(memcached_st*) * server_count)); + if (not servers) + { + fprintf(stderr, "Failed to allocate memory\n"); + return; + } + + for (uint32_t x= 0; x < server_count; x++) + { + memcached_server_instance_st instance= + memcached_server_instance_by_position(memc, x); + + if ((servers[x]= memcached_create(NULL)) == NULL) + { + fprintf(stderr, "Failed to memcached_create()\n"); + if (x > 0) + memcached_free(servers[0]); + x--; + + for (; x > 0; x--) + memcached_free(servers[x]); + + free(servers); + return; + } + memcached_server_add(servers[x], + memcached_server_name(instance), + memcached_server_port(instance)); + } + + printf("Network Latency Test:\n\n"); + struct timeval start_time, end_time; + uint32_t slowest_server= 0; + long elapsed_time, slowest_time= 0; + + for (uint32_t x= 0; x < server_count; x++) + { + memcached_server_instance_st instance= + memcached_server_instance_by_position(memc, x); + gettimeofday(&start_time, NULL); + + for (uint32_t y= 0; y < num_of_tests; y++) + { + size_t vlen; + char *val= memcached_get(servers[x], test_key, strlen(test_key), + &vlen, &flags, &rc); + if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS) + break; + free(val); + } + gettimeofday(&end_time, NULL); + + elapsed_time= (long) timedif(end_time, start_time); + elapsed_time /= (long) num_of_tests; + + if (elapsed_time > slowest_time) + { + slowest_server= x; + slowest_time= elapsed_time; + } + + if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS) + { + printf("\t %s (%d) => failed to reach the server\n", + memcached_server_name(instance), + memcached_server_port(instance)); + } + else + { + printf("\t %s (%d) => %ld.%ld seconds\n", + memcached_server_name(instance), + memcached_server_port(instance), + elapsed_time / 1000, elapsed_time % 1000); + } + } + + if (server_count > 1 && slowest_time > 0) + { + memcached_server_instance_st slowest= + memcached_server_instance_by_position(memc, slowest_server); + + printf("---\n"); + printf("Slowest Server: %s (%d) => %ld.%ld seconds\n", + memcached_server_name(slowest), + memcached_server_port(slowest), + slowest_time / 1000, slowest_time % 1000); + } + printf("\n"); + + for (uint32_t x= 0; x < server_count; x++) + memcached_free(servers[x]); + + free(servers); + free(analyze_mode); + } + else + { + fprintf(stderr, "Invalid Analyzer Option provided\n"); + free(analyze_mode); + } +} + +static void print_analysis_report(memcached_st *memc, + memcached_analysis_st *report) + +{ + uint32_t server_count= memcached_server_count(memc); + memcached_server_instance_st most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server); + memcached_server_instance_st least_free_server= memcached_server_instance_by_position(memc, report->least_free_server); + memcached_server_instance_st oldest_server= memcached_server_instance_by_position(memc, report->oldest_server); + + printf("Memcached Cluster Analysis Report\n\n"); + + printf("\tNumber of Servers Analyzed : %u\n", server_count); + printf("\tAverage Item Size (incl/overhead) : %u bytes\n", + report->average_item_size); + + if (server_count == 1) + { + printf("\nFor a detailed report, you must supply multiple servers.\n"); + return; + } + + printf("\n"); + printf("\tNode with most memory consumption : %s:%u (%llu bytes)\n", + memcached_server_name(most_consumed_server), + (uint32_t)memcached_server_port(most_consumed_server), + (unsigned long long)report->most_used_bytes); + printf("\tNode with least free space : %s:%u (%llu bytes remaining)\n", + memcached_server_name(least_free_server), + (uint32_t)memcached_server_port(least_free_server), + (unsigned long long)report->least_remaining_bytes); + printf("\tNode with longest uptime : %s:%u (%us)\n", + memcached_server_name(oldest_server), + (uint32_t)memcached_server_port(oldest_server), + report->longest_uptime); + printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio); + printf("\n"); +} + +static void options_parse(int argc, char *argv[]) +{ + memcached_programs_help_st help_options[]= + { + {0}, + }; + + int option_index= 0; + int option_rv; + + while (1) + { + option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index); + if (option_rv == -1) break; + switch (option_rv) + { + case 0: + break; + case OPT_VERBOSE: /* --verbose or -v */ + opt_verbose = OPT_VERBOSE; + break; + case OPT_DEBUG: /* --debug or -d */ + opt_verbose = OPT_DEBUG; + break; + case OPT_VERSION: /* --version or -V */ + version_command(PROGRAM_NAME); + break; + case OPT_HELP: /* --help or -h */ + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); + break; + case OPT_SERVERS: /* --servers or -s */ + opt_servers= strdup(optarg); + break; + case OPT_STAT_ARGS: + stat_args= strdup(optarg); + break; + case OPT_ANALYZE: /* --analyze or -a */ + opt_analyze= OPT_ANALYZE; + analyze_mode= (optarg) ? strdup(optarg) : NULL; + break; + case '?': + /* getopt_long already printed an error message. */ + exit(1); + default: + abort(); + } + } +} diff --git a/clients/ms_conn.h b/clients/ms_conn.h index cf1e8c0f..b915888d 100644 --- a/clients/ms_conn.h +++ b/clients/ms_conn.h @@ -60,7 +60,7 @@ enum conn_states { conn_read, /* reading in a command line */ conn_write, /* writing out a simple response */ - conn_closing, /* closing this connection */ + conn_closing /* closing this connection */ }; /* returned states of memcached command */ @@ -78,7 +78,7 @@ enum mcd_ret MCD_NOTFOUND, /* server not find the object */ MCD_END, /* end of the response of get command */ MCD_DELETED, /* server delete the object successfully */ - MCD_STAT, /* response of stats command */ + MCD_STAT /* response of stats command */ }; /* used to store the current or previous running command state */ @@ -103,7 +103,7 @@ typedef struct udppkt enum protocol { ascii_prot = 3, /* ASCII protocol */ - binary_prot, /* binary protocol */ + binary_prot /* binary protocol */ }; /** diff --git a/clients/ms_memslap.h b/clients/ms_memslap.h index dc0844d8..1c1b29eb 100644 --- a/clients/ms_memslap.h +++ b/clients/ms_memslap.h @@ -55,7 +55,7 @@ typedef enum OPT_BINARY_PROTOCOL= 'B', OPT_OVERWRITE= 'o', OPT_TPS= 'P', - OPT_REP_WRITE_SRV= 'p', + OPT_REP_WRITE_SRV= 'p' } ms_options_t; /* global statistic of response time */ diff --git a/clients/ms_setting.h b/clients/ms_setting.h index d8ccf8bb..964dc400 100644 --- a/clients/ms_setting.h +++ b/clients/ms_setting.h @@ -88,7 +88,7 @@ typedef enum cmd_type { CMD_SET, CMD_GET, - CMD_NULL, + CMD_NULL } ms_cmd_type_t; /* types in the configuration file */ @@ -97,7 +97,7 @@ typedef enum conf_type CONF_KEY, CONF_VALUE, CONF_CMD, - CONF_NULL, + CONF_NULL } ms_conf_type_t; /* information of command distribution */ diff --git a/clients/utilities.c b/clients/utilities.c deleted file mode 100644 index 92987471..00000000 --- a/clients/utilities.c +++ /dev/null @@ -1,233 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ -#include "config.h" - -#include -#include -#include -#include "utilities.h" - - -long int timedif(struct timeval a, struct timeval b) -{ - long us, s; - - us = (int)(a.tv_usec - b.tv_usec); - us /= 1000; - s = (int)(a.tv_sec - b.tv_sec); - s *= 1000; - return s + us; -} - -void version_command(const char *command_name) -{ - printf("%s v%u.%u\n", command_name, 1U, 0U); - exit(0); -} - -static const char *lookup_help(memcached_options option) -{ - switch (option) - { - case OPT_SERVERS: return("List which servers you wish to connect to."); - case OPT_VERSION: return("Display the version of the application and then exit."); - case OPT_HELP: return("Display this message and then exit."); - case OPT_VERBOSE: return("Give more details on the progression of the application."); - case OPT_DEBUG: return("Provide output only useful for debugging."); - case OPT_FLAG: return("Provide flag information for storage operation."); - case OPT_EXPIRE: return("Set the expire option for the object."); - case OPT_SET: return("Use set command with memcached when storing."); - case OPT_REPLACE: return("Use replace command with memcached when storing."); - case OPT_ADD: return("Use add command with memcached when storing."); - case OPT_SLAP_EXECUTE_NUMBER: return("Number of times to execute the given test."); - case OPT_SLAP_INITIAL_LOAD: return("Number of key pairs to load before executing tests."); - case OPT_SLAP_TEST: return("Test to run (currently \"get\" or \"set\")."); - case OPT_SLAP_CONCURRENCY: return("Number of users to simulate with load."); - case OPT_SLAP_NON_BLOCK: return("Set TCP up to use non-blocking IO."); - case OPT_SLAP_TCP_NODELAY: return("Set TCP socket up to use nodelay."); - case OPT_FLUSH: return("Flush servers before running tests."); - case OPT_HASH: return("Select hash type."); - case OPT_BINARY: return("Switch to binary protocol."); - case OPT_ANALYZE: return("Analyze the provided servers."); - case OPT_UDP: return("Use UDP protocol when communicating with server."); - case OPT_USERNAME: return "Username to use for SASL authentication"; - case OPT_PASSWD: return "Password to use for SASL authentication"; - case OPT_FILE: return "Path to file in which to save result"; - case OPT_STAT_ARGS: return "Argument for statistics"; - default: WATCHPOINT_ASSERT(0); - }; - - WATCHPOINT_ASSERT(0); - return "forgot to document this function :)"; -} - -void help_command(const char *command_name, const char *description, - const struct option *long_options, - memcached_programs_help_st *options) -{ - unsigned int x; - (void)options; - - printf("%s v%u.%u\n\n", command_name, 1U, 0U); - printf("\t%s\n\n", description); - printf("Current options. A '=' means the option takes a value.\n\n"); - - for (x= 0; long_options[x].name; x++) - { - const char *help_message; - - printf("\t --%s%c\n", long_options[x].name, - long_options[x].has_arg ? '=' : ' '); - if ((help_message= lookup_help(long_options[x].val))) - printf("\t\t%s\n", help_message); - } - - printf("\n"); - exit(0); -} - -void process_hash_option(memcached_st *memc, char *opt_hash) -{ - uint64_t set; - memcached_return_t rc; - - if (opt_hash == NULL) - return; - - set= MEMCACHED_HASH_DEFAULT; /* Just here to solve warning */ - if (!strcasecmp(opt_hash, "CRC")) - set= MEMCACHED_HASH_CRC; - else if (!strcasecmp(opt_hash, "FNV1_64")) - set= MEMCACHED_HASH_FNV1_64; - else if (!strcasecmp(opt_hash, "FNV1A_64")) - set= MEMCACHED_HASH_FNV1A_64; - else if (!strcasecmp(opt_hash, "FNV1_32")) - set= MEMCACHED_HASH_FNV1_32; - else if (!strcasecmp(opt_hash, "FNV1A_32")) - set= MEMCACHED_HASH_FNV1A_32; - else - { - fprintf(stderr, "hash: type not recognized %s\n", opt_hash); - exit(1); - } - - rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set); - if (rc != MEMCACHED_SUCCESS) - { - fprintf(stderr, "hash: memcache error %s\n", memcached_strerror(memc, rc)); - exit(1); - } -} - -#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT -static char *username; -static char *passwd; - -static int get_username(void *context, int id, const char **result, - unsigned int *len) -{ - (void)context; - if (!result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME)) - return SASL_BADPARAM; - - *result= username; - if (len) - *len= (username == NULL) ? 0 : (unsigned int)strlen(username); - - return SASL_OK; -} - -static int get_password(sasl_conn_t *conn, void *context, int id, - sasl_secret_t **psecret) -{ - (void)context; - static sasl_secret_t* ptr; - - if (!conn || ! psecret || id != SASL_CB_PASS) - return SASL_BADPARAM; - - if (passwd == NULL) - { - *psecret= NULL; - return SASL_OK; - } - - size_t len= strlen(passwd); - ptr= malloc(sizeof(sasl_secret_t) + len +1); - if (! ptr) - return SASL_NOMEM; - - ptr->len= len; - memcpy(ptr->data, passwd, len); - ptr->data[len]= 0; - - *psecret= ptr; - return SASL_OK; -} - -/* callbacks we support */ -static sasl_callback_t sasl_callbacks[] = { - { - SASL_CB_USER, &get_username, NULL - }, { - SASL_CB_AUTHNAME, &get_username, NULL - }, { - SASL_CB_PASS, &get_password, NULL - }, { - SASL_CB_LIST_END, NULL, NULL - } -}; -#endif - -bool initialize_sasl(memcached_st *memc, char *user, char *password) -{ -#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT - if (user != NULL && password != NULL) - { - username= user; - passwd= password; - - if (sasl_client_init(NULL) != SASL_OK) - { - fprintf(stderr, "Failed to initialize sasl library!\n"); - return false; - } - memcached_set_sasl_callbacks(memc, sasl_callbacks); - } -#else - (void)memc; - (void)user; - (void)password; -#endif - - return true; -} - -void shutdown_sasl(void) -{ -#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT - if (username != NULL || passwd != NULL) - sasl_done(); -#endif -} - -void initialize_sockets(void) -{ - /* Define the function for all platforms to avoid #ifdefs in each program */ -#ifdef WIN32 - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0) - { - fprintf(stderr, "Socket Initialization Error. Program aborted\n"); - exit(EXIT_FAILURE); - } -#endif -} diff --git a/clients/utilities.cc b/clients/utilities.cc new file mode 100644 index 00000000..ca109adc --- /dev/null +++ b/clients/utilities.cc @@ -0,0 +1,229 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ +#include "config.h" + +#include +#include +#include +#include + + +long int timedif(struct timeval a, struct timeval b) +{ + long us, s; + + us = (int)(a.tv_usec - b.tv_usec); + us /= 1000; + s = (int)(a.tv_sec - b.tv_sec); + s *= 1000; + return s + us; +} + +void version_command(const char *command_name) +{ + printf("%s v%u.%u\n", command_name, 1U, 0U); + exit(0); +} + +static const char *lookup_help(memcached_options option) +{ + switch (option) + { + case OPT_SERVERS: return("List which servers you wish to connect to."); + case OPT_VERSION: return("Display the version of the application and then exit."); + case OPT_HELP: return("Display this message and then exit."); + case OPT_VERBOSE: return("Give more details on the progression of the application."); + case OPT_DEBUG: return("Provide output only useful for debugging."); + case OPT_FLAG: return("Provide flag information for storage operation."); + case OPT_EXPIRE: return("Set the expire option for the object."); + case OPT_SET: return("Use set command with memcached when storing."); + case OPT_REPLACE: return("Use replace command with memcached when storing."); + case OPT_ADD: return("Use add command with memcached when storing."); + case OPT_SLAP_EXECUTE_NUMBER: return("Number of times to execute the given test."); + case OPT_SLAP_INITIAL_LOAD: return("Number of key pairs to load before executing tests."); + case OPT_SLAP_TEST: return("Test to run (currently \"get\" or \"set\")."); + case OPT_SLAP_CONCURRENCY: return("Number of users to simulate with load."); + case OPT_SLAP_NON_BLOCK: return("Set TCP up to use non-blocking IO."); + case OPT_SLAP_TCP_NODELAY: return("Set TCP socket up to use nodelay."); + case OPT_FLUSH: return("Flush servers before running tests."); + case OPT_HASH: return("Select hash type."); + case OPT_BINARY: return("Switch to binary protocol."); + case OPT_ANALYZE: return("Analyze the provided servers."); + case OPT_UDP: return("Use UDP protocol when communicating with server."); + case OPT_USERNAME: return "Username to use for SASL authentication"; + case OPT_PASSWD: return "Password to use for SASL authentication"; + case OPT_FILE: return "Path to file in which to save result"; + case OPT_STAT_ARGS: return "Argument for statistics"; + default: WATCHPOINT_ASSERT(0); + }; + + WATCHPOINT_ASSERT(0); + return "forgot to document this function :)"; +} + +void help_command(const char *command_name, const char *description, + const struct option *long_options, + memcached_programs_help_st *options) +{ + unsigned int x; + (void)options; + + printf("%s v%u.%u\n\n", command_name, 1U, 0U); + printf("\t%s\n\n", description); + printf("Current options. A '=' means the option takes a value.\n\n"); + + for (x= 0; long_options[x].name; x++) + { + const char *help_message; + + printf("\t --%s%c\n", long_options[x].name, + long_options[x].has_arg ? '=' : ' '); + if ((help_message= lookup_help(memcached_options(long_options[x].val)))) + printf("\t\t%s\n", help_message); + } + + printf("\n"); + exit(0); +} + +void process_hash_option(memcached_st *memc, char *opt_hash) +{ + uint64_t set; + memcached_return_t rc; + + if (opt_hash == NULL) + return; + + set= MEMCACHED_HASH_DEFAULT; /* Just here to solve warning */ + if (!strcasecmp(opt_hash, "CRC")) + set= MEMCACHED_HASH_CRC; + else if (!strcasecmp(opt_hash, "FNV1_64")) + set= MEMCACHED_HASH_FNV1_64; + else if (!strcasecmp(opt_hash, "FNV1A_64")) + set= MEMCACHED_HASH_FNV1A_64; + else if (!strcasecmp(opt_hash, "FNV1_32")) + set= MEMCACHED_HASH_FNV1_32; + else if (!strcasecmp(opt_hash, "FNV1A_32")) + set= MEMCACHED_HASH_FNV1A_32; + else + { + fprintf(stderr, "hash: type not recognized %s\n", opt_hash); + exit(1); + } + + rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set); + if (rc != MEMCACHED_SUCCESS) + { + fprintf(stderr, "hash: memcache error %s\n", memcached_strerror(memc, rc)); + exit(1); + } +} + +#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT +static char *username; +static char *passwd; + +static int get_username(void *context, int id, const char **result, unsigned int *len) +{ + (void)context; + if (!result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME)) + return SASL_BADPARAM; + + *result= username; + if (len) + *len= (username == NULL) ? 0 : (unsigned int)strlen(username); + + return SASL_OK; +} + +static int get_password(sasl_conn_t *conn, void *context, int id, + sasl_secret_t **psecret) +{ + (void)context; + static sasl_secret_t* ptr; + + if (!conn || ! psecret || id != SASL_CB_PASS) + return SASL_BADPARAM; + + if (passwd == NULL) + { + *psecret= NULL; + return SASL_OK; + } + + size_t len= strlen(passwd); + ptr= (sasl_secret_t *)malloc(sizeof(sasl_secret_t) + len +1); + if (not ptr) + return SASL_NOMEM; + + ptr->len= len; + memcpy(ptr->data, passwd, len); + ptr->data[len]= 0; + + *psecret= ptr; + return SASL_OK; +} + +typedef int (*local_sasl_fn)(void); + +/* callbacks we support */ +static sasl_callback_t sasl_callbacks[] = { + { SASL_CB_USER, (local_sasl_fn)get_username, NULL }, + { SASL_CB_AUTHNAME, (local_sasl_fn)get_username, NULL }, + { SASL_CB_PASS, (local_sasl_fn)get_password, NULL }, + { SASL_CB_LIST_END, NULL, NULL } +}; +#endif + +bool initialize_sasl(memcached_st *memc, char *user, char *password) +{ +#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT + if (user != NULL && password != NULL) + { + username= user; + passwd= password; + + if (sasl_client_init(NULL) != SASL_OK) + { + fprintf(stderr, "Failed to initialize sasl library!\n"); + return false; + } + memcached_set_sasl_callbacks(memc, sasl_callbacks); + } +#else + (void)memc; + (void)user; + (void)password; +#endif + + return true; +} + +void shutdown_sasl(void) +{ +#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT + if (username != NULL || passwd != NULL) + sasl_done(); +#endif +} + +void initialize_sockets(void) +{ + /* Define the function for all platforms to avoid #ifdefs in each program */ +#ifdef WIN32 + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0) + { + fprintf(stderr, "Socket Initialization Error. Program aborted\n"); + exit(EXIT_FAILURE); + } +#endif +} diff --git a/clients/utilities.h b/clients/utilities.h index a998773b..685be6a5 100644 --- a/clients/utilities.h +++ b/clients/utilities.h @@ -9,6 +9,8 @@ * */ +#pragma once + #include #include #include "libmemcached/watchpoint.h" @@ -41,6 +43,10 @@ struct memcached_programs_help_st char *not_used_yet; }; +#ifdef __cplusplus +extern "C" { +#endif + char *strdup_cleanup(const char *str); void cleanup(void); long int timedif(struct timeval a, struct timeval b); @@ -52,3 +58,7 @@ void process_hash_option(memcached_st *memc, char *opt_hash); bool initialize_sasl(memcached_st *memc, char *user, char *password); void shutdown_sasl(void); void initialize_sockets(void); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/configure.ac b/configure.ac index ff9329bf..9b8a82c5 100644 --- a/configure.ac +++ b/configure.ac @@ -8,8 +8,8 @@ # the COPYING file in this directory for full text. AC_PREREQ(2.59) -AC_INIT([libmemcached],[0.48],[http://libmemcached.org/]) -AC_CONFIG_SRCDIR([libmemcached/memcached.c]) +AC_INIT([libmemcached],[0.49],[http://libmemcached.org/]) +AC_CONFIG_SRCDIR([libmemcached/memcached.cc]) AC_CONFIG_AUX_DIR(config) PANDORA_CANONICAL_TARGET(no-vc-changelog) @@ -17,9 +17,9 @@ AC_CHECK_PROGS([YACC], ['bison'], [:]) AC_CHECK_PROGS([LEX], ['flex'], [:]) #shared library versioning -MEMCACHED_UTIL_LIBRARY_VERSION=1:0:0 +MEMCACHED_UTIL_LIBRARY_VERSION=2:0:0 MEMCACHED_PROTOCAL_LIBRARY_VERSION=0:0:0 -MEMCACHED_LIBRARY_VERSION=6:0:0 +MEMCACHED_LIBRARY_VERSION=7:0:0 # | | | # +------+ | +---+ # | | | diff --git a/docs/client_errors/MEMCACHED_AUTH_CONTINUE.rst b/docs/client_errors/MEMCACHED_AUTH_CONTINUE.rst new file mode 100644 index 00000000..8a3e6c77 --- /dev/null +++ b/docs/client_errors/MEMCACHED_AUTH_CONTINUE.rst @@ -0,0 +1,5 @@ +======================= +MEMCACHED_AUTH_CONTINUE +======================= + +Authentication has been paused. diff --git a/docs/client_errors/MEMCACHED_AUTH_FAILURE.rst b/docs/client_errors/MEMCACHED_AUTH_FAILURE.rst new file mode 100644 index 00000000..36d5a0c9 --- /dev/null +++ b/docs/client_errors/MEMCACHED_AUTH_FAILURE.rst @@ -0,0 +1,5 @@ +====================== +MEMCACHED_AUTH_FAILURE +====================== + +The credentials provided are not valid for this server. diff --git a/docs/client_errors/MEMCACHED_AUTH_PROBLEM.rst b/docs/client_errors/MEMCACHED_AUTH_PROBLEM.rst new file mode 100644 index 00000000..196d6f98 --- /dev/null +++ b/docs/client_errors/MEMCACHED_AUTH_PROBLEM.rst @@ -0,0 +1,5 @@ +====================== +MEMCACHED_AUTH_PROBLEM +====================== + +An unknown issue has occured during authentication. diff --git a/docs/client_errors/MEMCACHED_BAD_KEY_PROVIDED.rst b/docs/client_errors/MEMCACHED_BAD_KEY_PROVIDED.rst new file mode 100644 index 00000000..73aa4f14 --- /dev/null +++ b/docs/client_errors/MEMCACHED_BAD_KEY_PROVIDED.rst @@ -0,0 +1,5 @@ +========================== +MEMCACHED_BAD_KEY_PROVIDED +========================== + +The key provided is not a valid key. diff --git a/docs/client_errors/MEMCACHED_BUFFERED.rst b/docs/client_errors/MEMCACHED_BUFFERED.rst new file mode 100644 index 00000000..d93526ad --- /dev/null +++ b/docs/client_errors/MEMCACHED_BUFFERED.rst @@ -0,0 +1,5 @@ +================== +MEMCACHED_BUFFERED +================== + +The request has been buffered. diff --git a/docs/client_errors/MEMCACHED_CLIENT_ERROR.rst b/docs/client_errors/MEMCACHED_CLIENT_ERROR.rst new file mode 100644 index 00000000..1db8286f --- /dev/null +++ b/docs/client_errors/MEMCACHED_CLIENT_ERROR.rst @@ -0,0 +1,5 @@ +====================== +MEMCACHED_CLIENT_ERROR +====================== + +An unknown client error has occured internally. diff --git a/docs/client_errors/MEMCACHED_CONNECTION_BIND_FAILURE.rst b/docs/client_errors/MEMCACHED_CONNECTION_BIND_FAILURE.rst new file mode 100644 index 00000000..319701cf --- /dev/null +++ b/docs/client_errors/MEMCACHED_CONNECTION_BIND_FAILURE.rst @@ -0,0 +1,5 @@ +================================= +MEMCACHED_CONNECTION_BIND_FAILURE +================================= + +We were not able to bind() to the socket. diff --git a/docs/client_errors/MEMCACHED_CONNECTION_FAILURE.rst b/docs/client_errors/MEMCACHED_CONNECTION_FAILURE.rst new file mode 100644 index 00000000..f46fa179 --- /dev/null +++ b/docs/client_errors/MEMCACHED_CONNECTION_FAILURE.rst @@ -0,0 +1,5 @@ +============================ +MEMCACHED_CONNECTION_FAILURE +============================ + +A unknown error has occured while trying to connect to a server. diff --git a/docs/client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE.rst b/docs/client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE.rst new file mode 100644 index 00000000..4bf2337e --- /dev/null +++ b/docs/client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE.rst @@ -0,0 +1,5 @@ +========================================== +MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE +========================================== + +An error has occurred while trying to connect to a server. It is likely that either the number of file descriptors need to be increased or you are out of memory. diff --git a/docs/client_errors/MEMCACHED_DATA_DOES_NOT_EXIST.rst b/docs/client_errors/MEMCACHED_DATA_DOES_NOT_EXIST.rst new file mode 100644 index 00000000..13d5646a --- /dev/null +++ b/docs/client_errors/MEMCACHED_DATA_DOES_NOT_EXIST.rst @@ -0,0 +1,5 @@ +============================= +MEMCACHED_DATA_DOES_NOT_EXIST +============================= + +The data requested with the key given was not found. diff --git a/docs/client_errors/MEMCACHED_DATA_EXISTS.rst b/docs/client_errors/MEMCACHED_DATA_EXISTS.rst new file mode 100644 index 00000000..db0de35d --- /dev/null +++ b/docs/client_errors/MEMCACHED_DATA_EXISTS.rst @@ -0,0 +1,5 @@ +===================== +MEMCACHED_DATA_EXISTS +===================== + +The data requested with the key given was not found. diff --git a/docs/client_errors/MEMCACHED_DELETED.rst b/docs/client_errors/MEMCACHED_DELETED.rst new file mode 100644 index 00000000..c1e2acfe --- /dev/null +++ b/docs/client_errors/MEMCACHED_DELETED.rst @@ -0,0 +1,5 @@ +================= +MEMCACHED_DELETED +================= + +The object requested by the key has been deleted. diff --git a/docs/client_errors/MEMCACHED_DEPRECATED.rst b/docs/client_errors/MEMCACHED_DEPRECATED.rst new file mode 100644 index 00000000..733b1c12 --- /dev/null +++ b/docs/client_errors/MEMCACHED_DEPRECATED.rst @@ -0,0 +1,5 @@ +==================== +MEMCACHED_DEPRECATED +==================== + +The method that was requested has been deprecated. diff --git a/docs/client_errors/MEMCACHED_E2BIG.rst b/docs/client_errors/MEMCACHED_E2BIG.rst new file mode 100644 index 00000000..16c7b9c6 --- /dev/null +++ b/docs/client_errors/MEMCACHED_E2BIG.rst @@ -0,0 +1,5 @@ +=============== +MEMCACHED_E2BIG +=============== + +Item is too large for the server to store. diff --git a/docs/client_errors/MEMCACHED_END.rst b/docs/client_errors/MEMCACHED_END.rst new file mode 100644 index 00000000..39ad8542 --- /dev/null +++ b/docs/client_errors/MEMCACHED_END.rst @@ -0,0 +1,5 @@ +============= +MEMCACHED_END +============= + +The server has completed returning all of the objects requested. diff --git a/docs/client_errors/MEMCACHED_ERRNO.rst b/docs/client_errors/MEMCACHED_ERRNO.rst new file mode 100644 index 00000000..343f37d4 --- /dev/null +++ b/docs/client_errors/MEMCACHED_ERRNO.rst @@ -0,0 +1,5 @@ +=============== +MEMCACHED_ERRNO +=============== + +An error has occurred in the driver which has set errno. diff --git a/docs/client_errors/MEMCACHED_FAILURE.rst b/docs/client_errors/MEMCACHED_FAILURE.rst new file mode 100644 index 00000000..66c75083 --- /dev/null +++ b/docs/client_errors/MEMCACHED_FAILURE.rst @@ -0,0 +1,5 @@ +================= +MEMCACHED_FAILURE +================= + +A unknown failure has occurred in the server. diff --git a/docs/client_errors/MEMCACHED_FAIL_UNIX_SOCKET.rst b/docs/client_errors/MEMCACHED_FAIL_UNIX_SOCKET.rst new file mode 100644 index 00000000..d0781711 --- /dev/null +++ b/docs/client_errors/MEMCACHED_FAIL_UNIX_SOCKET.rst @@ -0,0 +1,5 @@ +========================== +MEMCACHED_FAIL_UNIX_SOCKET +========================== + +A connection was not established with the server via a unix domain socket. diff --git a/docs/client_errors/MEMCACHED_FETCH_NOTFINISHED.rst b/docs/client_errors/MEMCACHED_FETCH_NOTFINISHED.rst new file mode 100644 index 00000000..7e90a5a9 --- /dev/null +++ b/docs/client_errors/MEMCACHED_FETCH_NOTFINISHED.rst @@ -0,0 +1,5 @@ +=========================== +MEMCACHED_FETCH_NOTFINISHED +=========================== + +A request has been made, but the server has not finished the fetch of the last request. diff --git a/docs/client_errors/MEMCACHED_HOST_LOOKUP_FAILURE.rst b/docs/client_errors/MEMCACHED_HOST_LOOKUP_FAILURE.rst new file mode 100644 index 00000000..cbfe70ff --- /dev/null +++ b/docs/client_errors/MEMCACHED_HOST_LOOKUP_FAILURE.rst @@ -0,0 +1,5 @@ +============================= +MEMCACHED_HOST_LOOKUP_FAILURE +============================= + +A DNS failure has occurred. diff --git a/docs/client_errors/MEMCACHED_INVALID_ARGUMENTS.rst b/docs/client_errors/MEMCACHED_INVALID_ARGUMENTS.rst new file mode 100644 index 00000000..0684dbf3 --- /dev/null +++ b/docs/client_errors/MEMCACHED_INVALID_ARGUMENTS.rst @@ -0,0 +1,5 @@ +=========================== +MEMCACHED_INVALID_ARGUMENTS +=========================== + +The arguments supplied to the given function were not valid. diff --git a/docs/client_errors/MEMCACHED_INVALID_HOST_PROTOCOL.rst b/docs/client_errors/MEMCACHED_INVALID_HOST_PROTOCOL.rst new file mode 100644 index 00000000..181a959e --- /dev/null +++ b/docs/client_errors/MEMCACHED_INVALID_HOST_PROTOCOL.rst @@ -0,0 +1,5 @@ +=============================== +MEMCACHED_INVALID_HOST_PROTOCOL +=============================== + +The server you are connecting too has an invalid protocol. Most likely you are connecting to an older server that does not speak the binary protocol. diff --git a/docs/client_errors/MEMCACHED_ITEM.rst b/docs/client_errors/MEMCACHED_ITEM.rst new file mode 100644 index 00000000..9f192037 --- /dev/null +++ b/docs/client_errors/MEMCACHED_ITEM.rst @@ -0,0 +1,5 @@ +============== +MEMCACHED_ITEM +============== + +An item has been fetched (this is an internal error only). diff --git a/docs/client_errors/MEMCACHED_KEY_TOO_BIG.rst b/docs/client_errors/MEMCACHED_KEY_TOO_BIG.rst new file mode 100644 index 00000000..cbb2eeb6 --- /dev/null +++ b/docs/client_errors/MEMCACHED_KEY_TOO_BIG.rst @@ -0,0 +1,5 @@ +===================== +MEMCACHED_KEY_TOO_BIG +===================== + +The key that has been provided is too large for the given server. diff --git a/docs/client_errors/MEMCACHED_MAXIMUM_RETURN.rst b/docs/client_errors/MEMCACHED_MAXIMUM_RETURN.rst new file mode 100644 index 00000000..d980e6d6 --- /dev/null +++ b/docs/client_errors/MEMCACHED_MAXIMUM_RETURN.rst @@ -0,0 +1,5 @@ +======================== +MEMCACHED_MAXIMUM_RETURN +======================== + +This in an internal only state. diff --git a/docs/client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE.rst b/docs/client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE.rst new file mode 100644 index 00000000..3a3472b5 --- /dev/null +++ b/docs/client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE.rst @@ -0,0 +1,5 @@ +=================================== +MEMCACHED_MEMORY_ALLOCATION_FAILURE +=================================== + +An error has occurred while trying to allocate memory. diff --git a/docs/client_errors/MEMCACHED_NOTFOUND.rst b/docs/client_errors/MEMCACHED_NOTFOUND.rst new file mode 100644 index 00000000..c1a6ac16 --- /dev/null +++ b/docs/client_errors/MEMCACHED_NOTFOUND.rst @@ -0,0 +1,5 @@ +================== +MEMCACHED_NOTFOUND +================== + +The object requested was not found. diff --git a/docs/client_errors/MEMCACHED_NOTSTORED.rst b/docs/client_errors/MEMCACHED_NOTSTORED.rst new file mode 100644 index 00000000..61ea12b4 --- /dev/null +++ b/docs/client_errors/MEMCACHED_NOTSTORED.rst @@ -0,0 +1,5 @@ +=================== +MEMCACHED_NOTSTORED +=================== + +The request to store an object failed. diff --git a/docs/client_errors/MEMCACHED_NOT_SUPPORTED.rst b/docs/client_errors/MEMCACHED_NOT_SUPPORTED.rst new file mode 100644 index 00000000..f8befa0e --- /dev/null +++ b/docs/client_errors/MEMCACHED_NOT_SUPPORTED.rst @@ -0,0 +1,5 @@ +======================= +MEMCACHED_NOT_SUPPORTED +======================= + +The given method is not supported in the server. diff --git a/docs/client_errors/MEMCACHED_NO_KEY_PROVIDED.rst b/docs/client_errors/MEMCACHED_NO_KEY_PROVIDED.rst new file mode 100644 index 00000000..73cc54d5 --- /dev/null +++ b/docs/client_errors/MEMCACHED_NO_KEY_PROVIDED.rst @@ -0,0 +1,5 @@ +========================= +MEMCACHED_NO_KEY_PROVIDED +========================= + +No key was provided. diff --git a/docs/client_errors/MEMCACHED_NO_SERVERS.rst b/docs/client_errors/MEMCACHED_NO_SERVERS.rst new file mode 100644 index 00000000..5e61425b --- /dev/null +++ b/docs/client_errors/MEMCACHED_NO_SERVERS.rst @@ -0,0 +1,5 @@ +==================== +MEMCACHED_NO_SERVERS +==================== + +No servers have been added to the memcached_st object. diff --git a/docs/client_errors/MEMCACHED_PARSE_ERROR.rst b/docs/client_errors/MEMCACHED_PARSE_ERROR.rst new file mode 100644 index 00000000..a9c298e6 --- /dev/null +++ b/docs/client_errors/MEMCACHED_PARSE_ERROR.rst @@ -0,0 +1,5 @@ +===================== +MEMCACHED_PARSE_ERROR +===================== + +An error has occurred while trying to parse the configuration string. You should use memparse to determine what the error was. diff --git a/docs/client_errors/MEMCACHED_PARSE_USER_ERROR.rst b/docs/client_errors/MEMCACHED_PARSE_USER_ERROR.rst new file mode 100644 index 00000000..035e57ba --- /dev/null +++ b/docs/client_errors/MEMCACHED_PARSE_USER_ERROR.rst @@ -0,0 +1,5 @@ +========================== +MEMCACHED_PARSE_USER_ERROR +========================== + +An error has occurred in parsing the configuration string. diff --git a/docs/client_errors/MEMCACHED_PARTIAL_READ.rst b/docs/client_errors/MEMCACHED_PARTIAL_READ.rst new file mode 100644 index 00000000..7d389981 --- /dev/null +++ b/docs/client_errors/MEMCACHED_PARTIAL_READ.rst @@ -0,0 +1,5 @@ +====================== +MEMCACHED_PARTIAL_READ +====================== + +The read was only partcially successful. diff --git a/docs/client_errors/MEMCACHED_PROTOCOL_ERROR.rst b/docs/client_errors/MEMCACHED_PROTOCOL_ERROR.rst new file mode 100644 index 00000000..add6e902 --- /dev/null +++ b/docs/client_errors/MEMCACHED_PROTOCOL_ERROR.rst @@ -0,0 +1,5 @@ +======================== +MEMCACHED_PROTOCOL_ERROR +======================== + +An unknown error has occurred in the protocol. diff --git a/docs/client_errors/MEMCACHED_READ_FAILURE.rst b/docs/client_errors/MEMCACHED_READ_FAILURE.rst new file mode 100644 index 00000000..0da58b51 --- /dev/null +++ b/docs/client_errors/MEMCACHED_READ_FAILURE.rst @@ -0,0 +1,5 @@ +====================== +MEMCACHED_READ_FAILURE +====================== + +A read failure has occurred. diff --git a/docs/client_errors/MEMCACHED_SERVER_ERROR.rst b/docs/client_errors/MEMCACHED_SERVER_ERROR.rst new file mode 100644 index 00000000..78036443 --- /dev/null +++ b/docs/client_errors/MEMCACHED_SERVER_ERROR.rst @@ -0,0 +1,5 @@ +====================== +MEMCACHED_SERVER_ERROR +====================== + +An unknown error has occurred in the server. diff --git a/docs/client_errors/MEMCACHED_SERVER_MARKED_DEAD.rst b/docs/client_errors/MEMCACHED_SERVER_MARKED_DEAD.rst new file mode 100644 index 00000000..25c21ef9 --- /dev/null +++ b/docs/client_errors/MEMCACHED_SERVER_MARKED_DEAD.rst @@ -0,0 +1,5 @@ +============================ +MEMCACHED_SERVER_MARKED_DEAD +============================ + +The requested server has been marked dead. diff --git a/docs/client_errors/MEMCACHED_SOME_ERRORS.rst b/docs/client_errors/MEMCACHED_SOME_ERRORS.rst new file mode 100644 index 00000000..6666c3d1 --- /dev/null +++ b/docs/client_errors/MEMCACHED_SOME_ERRORS.rst @@ -0,0 +1,5 @@ +===================== +MEMCACHED_SOME_ERRORS +===================== + +A multi request has been made, and some underterminate number of errors have occurred. diff --git a/docs/client_errors/MEMCACHED_STAT.rst b/docs/client_errors/MEMCACHED_STAT.rst new file mode 100644 index 00000000..39f8109c --- /dev/null +++ b/docs/client_errors/MEMCACHED_STAT.rst @@ -0,0 +1,5 @@ +============== +MEMCACHED_STAT +============== + +A "stat" command has been returned in the protocol. diff --git a/docs/client_errors/MEMCACHED_STORED.rst b/docs/client_errors/MEMCACHED_STORED.rst new file mode 100644 index 00000000..daebc625 --- /dev/null +++ b/docs/client_errors/MEMCACHED_STORED.rst @@ -0,0 +1,5 @@ +================ +MEMCACHED_STORED +================ + +The requested object has been successfully stored on the server. diff --git a/docs/client_errors/MEMCACHED_SUCCESS.rst b/docs/client_errors/MEMCACHED_SUCCESS.rst new file mode 100644 index 00000000..f4e398c2 --- /dev/null +++ b/docs/client_errors/MEMCACHED_SUCCESS.rst @@ -0,0 +1,5 @@ +================= +MEMCACHED_SUCCESS +================= + +The request was successfully executed. diff --git a/docs/client_errors/MEMCACHED_TIMEOUT.rst b/docs/client_errors/MEMCACHED_TIMEOUT.rst new file mode 100644 index 00000000..27479a7f --- /dev/null +++ b/docs/client_errors/MEMCACHED_TIMEOUT.rst @@ -0,0 +1,5 @@ +================= +MEMCACHED_TIMEOUT +================= + +Operation has timed out. diff --git a/docs/client_errors/MEMCACHED_UNKNOWN_READ_FAILURE.rst b/docs/client_errors/MEMCACHED_UNKNOWN_READ_FAILURE.rst new file mode 100644 index 00000000..2056c4d6 --- /dev/null +++ b/docs/client_errors/MEMCACHED_UNKNOWN_READ_FAILURE.rst @@ -0,0 +1,5 @@ +============================== +MEMCACHED_UNKNOWN_READ_FAILURE +============================== + +An unknown read failure only occurs when either there is a bug in the server, or in rare cases where an ethernet nic is reporting dubious information. diff --git a/docs/client_errors/MEMCACHED_UNKNOWN_STAT_KEY.rst b/docs/client_errors/MEMCACHED_UNKNOWN_STAT_KEY.rst new file mode 100644 index 00000000..0fe362e0 --- /dev/null +++ b/docs/client_errors/MEMCACHED_UNKNOWN_STAT_KEY.rst @@ -0,0 +1,5 @@ +========================== +MEMCACHED_UNKNOWN_STAT_KEY +========================== + +The server you are communicating with has a stat key which has not be defined in the protocol. diff --git a/docs/client_errors/MEMCACHED_VALUE.rst b/docs/client_errors/MEMCACHED_VALUE.rst new file mode 100644 index 00000000..3eae4a18 --- /dev/null +++ b/docs/client_errors/MEMCACHED_VALUE.rst @@ -0,0 +1,5 @@ +=============== +MEMCACHED_VALUE +=============== + +A value has been returned from the server (this is an internal condition only). diff --git a/docs/client_errors/MEMCACHED_WRITE_FAILURE.rst b/docs/client_errors/MEMCACHED_WRITE_FAILURE.rst new file mode 100644 index 00000000..72388ff9 --- /dev/null +++ b/docs/client_errors/MEMCACHED_WRITE_FAILURE.rst @@ -0,0 +1,5 @@ +======================= +MEMCACHED_WRITE_FAILURE +======================= + +An error has occured while trying to write to a server. diff --git a/docs/error_messages.rst b/docs/error_messages.rst new file mode 100644 index 00000000..34cc3045 --- /dev/null +++ b/docs/error_messages.rst @@ -0,0 +1,55 @@ +===================== +Client Error messages +===================== + +.. toctree:: + :maxdepth: 1 + + client_errors/MEMCACHED_AUTH_CONTINUE + client_errors/MEMCACHED_AUTH_FAILURE + client_errors/MEMCACHED_AUTH_PROBLEM + client_errors/MEMCACHED_BAD_KEY_PROVIDED + client_errors/MEMCACHED_BUFFERED + client_errors/MEMCACHED_CLIENT_ERROR + client_errors/MEMCACHED_CONNECTION_BIND_FAILURE + client_errors/MEMCACHED_CONNECTION_FAILURE + client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE + client_errors/MEMCACHED_DATA_DOES_NOT_EXIST + client_errors/MEMCACHED_DATA_EXISTS + client_errors/MEMCACHED_DELETED + client_errors/MEMCACHED_DEPRECATED + client_errors/MEMCACHED_E2BIG + client_errors/MEMCACHED_END + client_errors/MEMCACHED_ERRNO + client_errors/MEMCACHED_FAILURE + client_errors/MEMCACHED_FAIL_UNIX_SOCKET + client_errors/MEMCACHED_FETCH_NOTFINISHED + client_errors/MEMCACHED_HOST_LOOKUP_FAILURE + client_errors/MEMCACHED_INVALID_ARGUMENTS + client_errors/MEMCACHED_INVALID_HOST_PROTOCOL + client_errors/MEMCACHED_ITEM + client_errors/MEMCACHED_KEY_TOO_BIG + client_errors/MEMCACHED_MAXIMUM_RETURN + client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE + client_errors/MEMCACHED_NOTFOUND + client_errors/MEMCACHED_NOTSTORED + client_errors/MEMCACHED_NOT_SUPPORTED + client_errors/MEMCACHED_NO_KEY_PROVIDED + client_errors/MEMCACHED_NO_SERVERS + client_errors/MEMCACHED_PARSE_ERROR + client_errors/MEMCACHED_PARSE_USER_ERROR + client_errors/MEMCACHED_PARTIAL_READ + client_errors/MEMCACHED_PROTOCOL_ERROR + client_errors/MEMCACHED_READ_FAILURE + client_errors/MEMCACHED_SERVER_ERROR + client_errors/MEMCACHED_SERVER_MARKED_DEAD + client_errors/MEMCACHED_SOME_ERRORS + client_errors/MEMCACHED_STAT + client_errors/MEMCACHED_STORED + client_errors/MEMCACHED_SUCCESS + client_errors/MEMCACHED_TIMEOUT + client_errors/MEMCACHED_UNKNOWN_READ_FAILURE + client_errors/MEMCACHED_UNKNOWN_STAT_KEY + client_errors/MEMCACHED_VALUE + client_errors/MEMCACHED_WRITE_FAILURE + diff --git a/docs/hashkit_create.rst b/docs/hashkit_create.rst index cf11e83e..e0c9c71c 100644 --- a/docs/hashkit_create.rst +++ b/docs/hashkit_create.rst @@ -3,35 +3,24 @@ Creating a hashkit structure ============================ -Create and destroy hashkit objects - - -------- -LIBRARY -------- - - -C Library for hashing algorithms (libmemcached, -lhashkit) - - -------- SYNOPSIS -------- +C Library for hashing algorithms (libmemcached, -lhashkit) -.. code-block:: perl - - #include - - hashkit_st *hashkit_create(hashkit_st *hash); +#include - hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr); +.. c:function:: hashkit_st *hashkit_create(hashkit_st *hash); - void hashkit_free(hashkit_st *hash); - - bool hashkit_is_allocated(const hashkit_st *hash); +.. c:function:: hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr); + +.. c:function:: void hashkit_free(hashkit_st *hash); + +.. c:function:: bool hashkit_is_allocated(const hashkit_st *hash); +Compile and link with -lmemcached ----------- diff --git a/docs/include.am b/docs/include.am index 12ebed36..5cd682b7 100644 --- a/docs/include.am +++ b/docs/include.am @@ -4,6 +4,54 @@ EXTRA_DIST+= \ docs/conf.py \ + docs/error_messages.rst \ + docs/client_errors/MEMCACHED_AUTH_CONTINUE.rst \ + docs/client_errors/MEMCACHED_AUTH_FAILURE.rst \ + docs/client_errors/MEMCACHED_AUTH_PROBLEM.rst \ + docs/client_errors/MEMCACHED_BAD_KEY_PROVIDED.rst \ + docs/client_errors/MEMCACHED_BUFFERED.rst \ + docs/client_errors/MEMCACHED_CLIENT_ERROR.rst \ + docs/client_errors/MEMCACHED_CONNECTION_BIND_FAILURE.rst \ + docs/client_errors/MEMCACHED_CONNECTION_FAILURE.rst \ + docs/client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE.rst \ + docs/client_errors/MEMCACHED_DATA_DOES_NOT_EXIST.rst \ + docs/client_errors/MEMCACHED_DATA_EXISTS.rst \ + docs/client_errors/MEMCACHED_DELETED.rst \ + docs/client_errors/MEMCACHED_DEPRECATED.rst \ + docs/client_errors/MEMCACHED_E2BIG.rst \ + docs/client_errors/MEMCACHED_END.rst \ + docs/client_errors/MEMCACHED_ERRNO.rst \ + docs/client_errors/MEMCACHED_FAILURE.rst \ + docs/client_errors/MEMCACHED_FAIL_UNIX_SOCKET.rst \ + docs/client_errors/MEMCACHED_FETCH_NOTFINISHED.rst \ + docs/client_errors/MEMCACHED_HOST_LOOKUP_FAILURE.rst \ + docs/client_errors/MEMCACHED_INVALID_ARGUMENTS.rst \ + docs/client_errors/MEMCACHED_INVALID_HOST_PROTOCOL.rst \ + docs/client_errors/MEMCACHED_ITEM.rst \ + docs/client_errors/MEMCACHED_KEY_TOO_BIG.rst \ + docs/client_errors/MEMCACHED_MAXIMUM_RETURN.rst \ + docs/client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE.rst \ + docs/client_errors/MEMCACHED_NOTFOUND.rst \ + docs/client_errors/MEMCACHED_NOTSTORED.rst \ + docs/client_errors/MEMCACHED_NOT_SUPPORTED.rst \ + docs/client_errors/MEMCACHED_NO_KEY_PROVIDED.rst \ + docs/client_errors/MEMCACHED_NO_SERVERS.rst \ + docs/client_errors/MEMCACHED_PARSE_ERROR.rst \ + docs/client_errors/MEMCACHED_PARSE_USER_ERROR.rst \ + docs/client_errors/MEMCACHED_PARTIAL_READ.rst \ + docs/client_errors/MEMCACHED_PROTOCOL_ERROR.rst \ + docs/client_errors/MEMCACHED_READ_FAILURE.rst \ + docs/client_errors/MEMCACHED_SERVER_ERROR.rst \ + docs/client_errors/MEMCACHED_SERVER_MARKED_DEAD.rst \ + docs/client_errors/MEMCACHED_SOME_ERRORS.rst \ + docs/client_errors/MEMCACHED_STAT.rst \ + docs/client_errors/MEMCACHED_STORED.rst \ + docs/client_errors/MEMCACHED_SUCCESS.rst \ + docs/client_errors/MEMCACHED_TIMEOUT.rst \ + docs/client_errors/MEMCACHED_UNKNOWN_READ_FAILURE.rst \ + docs/client_errors/MEMCACHED_UNKNOWN_STAT_KEY.rst \ + docs/client_errors/MEMCACHED_VALUE.rst \ + docs/client_errors/MEMCACHED_WRITE_FAILURE.rst \ docs/hashkit_create.rst \ docs/hashkit_functions.rst \ docs/hashkit_value.rst \ diff --git a/docs/index.rst b/docs/index.rst index 79ce45e2..d9d3e033 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -19,6 +19,7 @@ Basics memcached_create libmemcached_examples libmemcached_configuration + error_messages ################# diff --git a/docs/libmemcached.rst b/docs/libmemcached.rst index bb0f0461..23ec93b4 100644 --- a/docs/libmemcached.rst +++ b/docs/libmemcached.rst @@ -10,6 +10,17 @@ SYNOPSIS Compile and link with -lmemcached +libMemcached is an open source C/C++ client library and tools for the memcached server (http://danga.com/memcached). It has been designed to be light on memory usage, thread safe, and provide full access to server side methods. + +libMemcached was designed to provide the greatest number of options to use Memcached. Some of the features provided: + +1. Asynchronous and Synchronous Transport Support. +2. Consistent Hashing and Distribution. +3. Tunable Hashing algorithm to match keys. +4. Access to large object support. +5. Local replication. +6. A complete reference guide and documentation to the API. +7. Tools to Manage your Memcached networks. ----------- DESCRIPTION @@ -21,14 +32,14 @@ system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load." `http://danga.com/memcached/ `_ \ **libmemcached**\ is a small, thread-safe client library for the -memcached protocol. The code has all been written with an eye to allow +memcached protocol. The code has all been written to allow for both web and embedded usage. It handles the work behind routing -particular keys to specific servers that you specify (and values are -matched based on server order as supplied by you). It implements both -a modula and consistent method of object distribution. +individual keys to specific servers specified by the developer (and values are +matched based on server order as supplied by the user). It implements +a modular and consistent method of object distribution. There are multiple implemented routing and hashing methods. See the -memcached_behavior_set() manpage. +memcached_behavior_set() manpage for more information. All operations are performed against a \ ``memcached_st``\ structure. These structures can either be dynamically allocated or statically @@ -117,9 +128,9 @@ THREADS AND PROCESSES --------------------- -When using threads or forked processes it is important to keep an instance +When using threads or forked processes it is important to keep one instance of \ ``memcached_st``\ per process or thread. Without creating your own locking -structures you can not share a single \ ``memcached_st``\ . You can though call +structures you can not share a single \ ``memcached_st``\ . However, you can call memcached_quit(3) on a \ ``memcached_st``\ and then use the resulting cloned structure. diff --git a/docs/man/hashkit_clone.3 b/docs/man/hashkit_clone.3 index fd7b5ee6..d41f71d6 100644 --- a/docs/man/hashkit_clone.3 +++ b/docs/man/hashkit_clone.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_CLONE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_CLONE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_clone \- libhashkit Documentation . diff --git a/docs/man/hashkit_crc32.3 b/docs/man/hashkit_crc32.3 index ede2edcf..2dc8b584 100644 --- a/docs/man/hashkit_crc32.3 +++ b/docs/man/hashkit_crc32.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_CRC32" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_CRC32" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_crc32 \- libhashkit Documentation . diff --git a/docs/man/hashkit_create.3 b/docs/man/hashkit_create.3 index cbd33a66..54d4a3e9 100644 --- a/docs/man/hashkit_create.3 +++ b/docs/man/hashkit_create.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_CREATE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_CREATE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_create \- libhashkit Documentation . diff --git a/docs/man/hashkit_fnv1_32.3 b/docs/man/hashkit_fnv1_32.3 index 2b4934c6..58695663 100644 --- a/docs/man/hashkit_fnv1_32.3 +++ b/docs/man/hashkit_fnv1_32.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_FNV1_32" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_FNV1_32" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_fnv1_32 \- libhashkit Documentation . diff --git a/docs/man/hashkit_fnv1_64.3 b/docs/man/hashkit_fnv1_64.3 index 339cf53c..ac2485ab 100644 --- a/docs/man/hashkit_fnv1_64.3 +++ b/docs/man/hashkit_fnv1_64.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_FNV1_64" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_FNV1_64" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_fnv1_64 \- libhashkit Documentation . diff --git a/docs/man/hashkit_fnv1a_32.3 b/docs/man/hashkit_fnv1a_32.3 index 59ab6456..1bf4291e 100644 --- a/docs/man/hashkit_fnv1a_32.3 +++ b/docs/man/hashkit_fnv1a_32.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_FNV1A_32" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_FNV1A_32" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_fnv1a_32 \- libhashkit Documentation . diff --git a/docs/man/hashkit_fnv1a_64.3 b/docs/man/hashkit_fnv1a_64.3 index 46f2d6ff..f274bbb7 100644 --- a/docs/man/hashkit_fnv1a_64.3 +++ b/docs/man/hashkit_fnv1a_64.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_FNV1A_64" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_FNV1A_64" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_fnv1a_64 \- libhashkit Documentation . diff --git a/docs/man/hashkit_free.3 b/docs/man/hashkit_free.3 index e38a46f1..c31372d6 100644 --- a/docs/man/hashkit_free.3 +++ b/docs/man/hashkit_free.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_FREE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_FREE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_free \- libhashkit Documentation . diff --git a/docs/man/hashkit_functions.3 b/docs/man/hashkit_functions.3 index 34b2a312..b610e1e2 100644 --- a/docs/man/hashkit_functions.3 +++ b/docs/man/hashkit_functions.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_FUNCTIONS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_FUNCTIONS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_functions \- libhashkit Documentation . diff --git a/docs/man/hashkit_hsieh.3 b/docs/man/hashkit_hsieh.3 index 3b2147ff..0d1f7b6d 100644 --- a/docs/man/hashkit_hsieh.3 +++ b/docs/man/hashkit_hsieh.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_HSIEH" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_HSIEH" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_hsieh \- libhashkit Documentation . diff --git a/docs/man/hashkit_is_allocated.3 b/docs/man/hashkit_is_allocated.3 index be101462..a5a5e706 100644 --- a/docs/man/hashkit_is_allocated.3 +++ b/docs/man/hashkit_is_allocated.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_IS_ALLOCATED" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_IS_ALLOCATED" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_is_allocated \- libhashkit Documentation . diff --git a/docs/man/hashkit_jenkins.3 b/docs/man/hashkit_jenkins.3 index 95a5fa09..992f9e8a 100644 --- a/docs/man/hashkit_jenkins.3 +++ b/docs/man/hashkit_jenkins.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_JENKINS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_JENKINS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_jenkins \- libhashkit Documentation . diff --git a/docs/man/hashkit_md5.3 b/docs/man/hashkit_md5.3 index 3085fd87..38489b17 100644 --- a/docs/man/hashkit_md5.3 +++ b/docs/man/hashkit_md5.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_MD5" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_MD5" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_md5 \- libhashkit Documentation . diff --git a/docs/man/hashkit_murmur.3 b/docs/man/hashkit_murmur.3 index 6d100a1a..5063628d 100644 --- a/docs/man/hashkit_murmur.3 +++ b/docs/man/hashkit_murmur.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_MURMUR" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_MURMUR" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_murmur \- libhashkit Documentation . diff --git a/docs/man/hashkit_value.3 b/docs/man/hashkit_value.3 index b6499fda..aeb33a23 100644 --- a/docs/man/hashkit_value.3 +++ b/docs/man/hashkit_value.3 @@ -1,4 +1,4 @@ -.TH "HASHKIT_VALUE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "HASHKIT_VALUE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME hashkit_value \- libhashkit Documentation . diff --git a/docs/man/libhashkit.3 b/docs/man/libhashkit.3 index 679feed5..c1343532 100644 --- a/docs/man/libhashkit.3 +++ b/docs/man/libhashkit.3 @@ -1,4 +1,4 @@ -.TH "LIBHASHKIT" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "LIBHASHKIT" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME libhashkit \- libhashkit Documentation . diff --git a/docs/man/libmemcached.3 b/docs/man/libmemcached.3 index 0891b66e..433cd52a 100644 --- a/docs/man/libmemcached.3 +++ b/docs/man/libmemcached.3 @@ -1,4 +1,4 @@ -.TH "LIBMEMCACHED" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "LIBMEMCACHED" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME libmemcached \- Introducing the C Client Library for memcached . diff --git a/docs/man/libmemcached_check_configuration.3 b/docs/man/libmemcached_check_configuration.3 index 3f166b52..d4b1d1d5 100644 --- a/docs/man/libmemcached_check_configuration.3 +++ b/docs/man/libmemcached_check_configuration.3 @@ -1,4 +1,4 @@ -.TH "LIBMEMCACHED_CHECK_CONFIGURATION" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "LIBMEMCACHED_CHECK_CONFIGURATION" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME libmemcached_check_configuration \- libmemcached Documentation . diff --git a/docs/man/libmemcached_configuration.3 b/docs/man/libmemcached_configuration.3 index 034dec92..3918f735 100644 --- a/docs/man/libmemcached_configuration.3 +++ b/docs/man/libmemcached_configuration.3 @@ -1,4 +1,4 @@ -.TH "LIBMEMCACHED_CONFIGURATION" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "LIBMEMCACHED_CONFIGURATION" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME libmemcached_configuration \- libmemcached Documentation . diff --git a/docs/man/libmemcached_examples.3 b/docs/man/libmemcached_examples.3 index 1909596f..37490002 100644 --- a/docs/man/libmemcached_examples.3 +++ b/docs/man/libmemcached_examples.3 @@ -1,4 +1,4 @@ -.TH "LIBMEMCACHED_EXAMPLES" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "LIBMEMCACHED_EXAMPLES" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME libmemcached_examples \- libmemcached Documentation . diff --git a/docs/man/libmemcachedutil.3 b/docs/man/libmemcachedutil.3 index 4e1e25b1..a09c9320 100644 --- a/docs/man/libmemcachedutil.3 +++ b/docs/man/libmemcachedutil.3 @@ -1,4 +1,4 @@ -.TH "LIBMEMCACHEDUTIL" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "LIBMEMCACHEDUTIL" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME libmemcachedutil \- libmemcached Documentation . diff --git a/docs/man/memaslap.1 b/docs/man/memaslap.1 index a5886722..25859161 100644 --- a/docs/man/memaslap.1 +++ b/docs/man/memaslap.1 @@ -1,4 +1,4 @@ -.TH "MEMASLAP" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMASLAP" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memaslap \- libmemcached Documentation . diff --git a/docs/man/memcached.3 b/docs/man/memcached.3 index 302545f6..5756dbfc 100644 --- a/docs/man/memcached.3 +++ b/docs/man/memcached.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached \- libmemcached Documentation . diff --git a/docs/man/memcached_add.3 b/docs/man/memcached_add.3 index 3a601230..475a8589 100644 --- a/docs/man/memcached_add.3 +++ b/docs/man/memcached_add.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_ADD" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_ADD" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_add \- Storing and Replacing Data . diff --git a/docs/man/memcached_add_by_key.3 b/docs/man/memcached_add_by_key.3 index 092dc0f7..8c7dad81 100644 --- a/docs/man/memcached_add_by_key.3 +++ b/docs/man/memcached_add_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_ADD_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_ADD_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_add_by_key \- Storing and Replacing Data . diff --git a/docs/man/memcached_analyze.3 b/docs/man/memcached_analyze.3 index 310d4b5d..d2840a4b 100644 --- a/docs/man/memcached_analyze.3 +++ b/docs/man/memcached_analyze.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_ANALYZE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_ANALYZE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_analyze \- libmemcached Documentation . diff --git a/docs/man/memcached_append.3 b/docs/man/memcached_append.3 index fa1c7827..0bdc00d2 100644 --- a/docs/man/memcached_append.3 +++ b/docs/man/memcached_append.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_APPEND" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_APPEND" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_append \- Storing and Replacing Data . diff --git a/docs/man/memcached_append_by_key.3 b/docs/man/memcached_append_by_key.3 index fe79cd9e..5fec40be 100644 --- a/docs/man/memcached_append_by_key.3 +++ b/docs/man/memcached_append_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_APPEND_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_APPEND_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_append_by_key \- Storing and Replacing Data . diff --git a/docs/man/memcached_auto.3 b/docs/man/memcached_auto.3 index 8bb2089d..6322d95b 100644 --- a/docs/man/memcached_auto.3 +++ b/docs/man/memcached_auto.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_AUTO" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_AUTO" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_auto \- Incrementing and Decrementing Values . diff --git a/docs/man/memcached_behavior.3 b/docs/man/memcached_behavior.3 index 2d2bed5c..fa566e5b 100644 --- a/docs/man/memcached_behavior.3 +++ b/docs/man/memcached_behavior.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_BEHAVIOR" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_BEHAVIOR" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_behavior \- libmemcached Documentation . diff --git a/docs/man/memcached_behavior_get.3 b/docs/man/memcached_behavior_get.3 index 869db4b7..f0bb38dd 100644 --- a/docs/man/memcached_behavior_get.3 +++ b/docs/man/memcached_behavior_get.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_BEHAVIOR_GET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_BEHAVIOR_GET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_behavior_get \- libmemcached Documentation . diff --git a/docs/man/memcached_behavior_set.3 b/docs/man/memcached_behavior_set.3 index ad41e060..7dcc6fa9 100644 --- a/docs/man/memcached_behavior_set.3 +++ b/docs/man/memcached_behavior_set.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_BEHAVIOR_SET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_BEHAVIOR_SET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_behavior_set \- libmemcached Documentation . diff --git a/docs/man/memcached_callback.3 b/docs/man/memcached_callback.3 index 21c614da..482bb19e 100644 --- a/docs/man/memcached_callback.3 +++ b/docs/man/memcached_callback.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_CALLBACK" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_CALLBACK" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_callback \- libmemcached Documentation . diff --git a/docs/man/memcached_callback_get.3 b/docs/man/memcached_callback_get.3 index 83c95ae7..0215431d 100644 --- a/docs/man/memcached_callback_get.3 +++ b/docs/man/memcached_callback_get.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_CALLBACK_GET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_CALLBACK_GET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_callback_get \- libmemcached Documentation . diff --git a/docs/man/memcached_callback_set.3 b/docs/man/memcached_callback_set.3 index dcce9e6a..c13e24c0 100644 --- a/docs/man/memcached_callback_set.3 +++ b/docs/man/memcached_callback_set.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_CALLBACK_SET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_CALLBACK_SET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_callback_set \- libmemcached Documentation . diff --git a/docs/man/memcached_cas.3 b/docs/man/memcached_cas.3 index d8e5a118..73e8653c 100644 --- a/docs/man/memcached_cas.3 +++ b/docs/man/memcached_cas.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_CAS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_CAS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_cas \- Storing and Replacing Data . diff --git a/docs/man/memcached_cas_by_key.3 b/docs/man/memcached_cas_by_key.3 index dba38cf7..4b4ea9b6 100644 --- a/docs/man/memcached_cas_by_key.3 +++ b/docs/man/memcached_cas_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_CAS_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_CAS_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_cas_by_key \- Storing and Replacing Data . diff --git a/docs/man/memcached_clone.3 b/docs/man/memcached_clone.3 index 12bbd403..65d3f6ec 100644 --- a/docs/man/memcached_clone.3 +++ b/docs/man/memcached_clone.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_CLONE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_CLONE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_clone \- libmemcached Documentation . diff --git a/docs/man/memcached_create.3 b/docs/man/memcached_create.3 index d9a1bb8f..d1c3d2dc 100644 --- a/docs/man/memcached_create.3 +++ b/docs/man/memcached_create.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_CREATE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_CREATE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_create \- libmemcached Documentation . diff --git a/docs/man/memcached_decrement.3 b/docs/man/memcached_decrement.3 index 18679060..a79c6685 100644 --- a/docs/man/memcached_decrement.3 +++ b/docs/man/memcached_decrement.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_DECREMENT" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_DECREMENT" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_decrement \- Incrementing and Decrementing Values . diff --git a/docs/man/memcached_decrement_with_initial.3 b/docs/man/memcached_decrement_with_initial.3 index cd0e035f..99472647 100644 --- a/docs/man/memcached_decrement_with_initial.3 +++ b/docs/man/memcached_decrement_with_initial.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_DECREMENT_WITH_INITIAL" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_DECREMENT_WITH_INITIAL" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_decrement_with_initial \- Incrementing and Decrementing Values . diff --git a/docs/man/memcached_delete.3 b/docs/man/memcached_delete.3 index d6919919..d4215c9b 100644 --- a/docs/man/memcached_delete.3 +++ b/docs/man/memcached_delete.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_DELETE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_DELETE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_delete \- libmemcached Documentation . diff --git a/docs/man/memcached_delete_by_key.3 b/docs/man/memcached_delete_by_key.3 index ae99f61e..6d4ef416 100644 --- a/docs/man/memcached_delete_by_key.3 +++ b/docs/man/memcached_delete_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_DELETE_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_DELETE_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_delete_by_key \- libmemcached Documentation . diff --git a/docs/man/memcached_destroy_sasl_auth_data.3 b/docs/man/memcached_destroy_sasl_auth_data.3 index 928fb74a..ff347c88 100644 --- a/docs/man/memcached_destroy_sasl_auth_data.3 +++ b/docs/man/memcached_destroy_sasl_auth_data.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_DESTROY_SASL_AUTH_DATA" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_DESTROY_SASL_AUTH_DATA" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_destroy_sasl_auth_data \- libmemcached Documentation . diff --git a/docs/man/memcached_dump.3 b/docs/man/memcached_dump.3 index c311fe21..5df723de 100644 --- a/docs/man/memcached_dump.3 +++ b/docs/man/memcached_dump.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_DUMP" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_DUMP" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_dump \- libmemcached Documentation . diff --git a/docs/man/memcached_fetch.3 b/docs/man/memcached_fetch.3 index 68eab8f8..ca505f96 100644 --- a/docs/man/memcached_fetch.3 +++ b/docs/man/memcached_fetch.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_FETCH" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_FETCH" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_fetch \- Retrieving data from the server . diff --git a/docs/man/memcached_fetch_execute.3 b/docs/man/memcached_fetch_execute.3 index c999cb20..5052fff9 100644 --- a/docs/man/memcached_fetch_execute.3 +++ b/docs/man/memcached_fetch_execute.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_FETCH_EXECUTE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_FETCH_EXECUTE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_fetch_execute \- Retrieving data from the server . diff --git a/docs/man/memcached_fetch_result.3 b/docs/man/memcached_fetch_result.3 index 80ed3cb9..aabe6719 100644 --- a/docs/man/memcached_fetch_result.3 +++ b/docs/man/memcached_fetch_result.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_FETCH_RESULT" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_FETCH_RESULT" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_fetch_result \- Retrieving data from the server . diff --git a/docs/man/memcached_flush.3 b/docs/man/memcached_flush.3 index 61449b47..48709ea3 100644 --- a/docs/man/memcached_flush.3 +++ b/docs/man/memcached_flush.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_FLUSH" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_FLUSH" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_flush \- libmemcached Documentation . diff --git a/docs/man/memcached_flush_buffers.3 b/docs/man/memcached_flush_buffers.3 index 45c6bbf5..500d334f 100644 --- a/docs/man/memcached_flush_buffers.3 +++ b/docs/man/memcached_flush_buffers.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_FLUSH_BUFFERS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_FLUSH_BUFFERS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_flush_buffers \- libmemcached Documentation . diff --git a/docs/man/memcached_free.3 b/docs/man/memcached_free.3 index 1ab8e7ae..34b8b115 100644 --- a/docs/man/memcached_free.3 +++ b/docs/man/memcached_free.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_FREE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_FREE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_free \- libmemcached Documentation . diff --git a/docs/man/memcached_generate_hash.3 b/docs/man/memcached_generate_hash.3 index 48008e8f..07c31099 100644 --- a/docs/man/memcached_generate_hash.3 +++ b/docs/man/memcached_generate_hash.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_GENERATE_HASH" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_GENERATE_HASH" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_generate_hash \- Generating hash values directly . diff --git a/docs/man/memcached_generate_hash_value.3 b/docs/man/memcached_generate_hash_value.3 index 831f1760..037a9cee 100644 --- a/docs/man/memcached_generate_hash_value.3 +++ b/docs/man/memcached_generate_hash_value.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_GENERATE_HASH_VALUE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_GENERATE_HASH_VALUE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_generate_hash_value \- Generating hash values directly . diff --git a/docs/man/memcached_get.3 b/docs/man/memcached_get.3 index f8c513b6..f1d8caf9 100644 --- a/docs/man/memcached_get.3 +++ b/docs/man/memcached_get.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_GET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_GET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_get \- Retrieving data from the server . diff --git a/docs/man/memcached_get_by_key.3 b/docs/man/memcached_get_by_key.3 index 91aaa444..e334c296 100644 --- a/docs/man/memcached_get_by_key.3 +++ b/docs/man/memcached_get_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_GET_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_GET_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_get_by_key \- Retrieving data from the server . diff --git a/docs/man/memcached_get_memory_allocators.3 b/docs/man/memcached_get_memory_allocators.3 index 41576bb9..6eb34eb9 100644 --- a/docs/man/memcached_get_memory_allocators.3 +++ b/docs/man/memcached_get_memory_allocators.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_GET_MEMORY_ALLOCATORS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_GET_MEMORY_ALLOCATORS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_get_memory_allocators \- libmemcached Documentation . diff --git a/docs/man/memcached_get_sasl_callbacks.3 b/docs/man/memcached_get_sasl_callbacks.3 index 44023427..653c445f 100644 --- a/docs/man/memcached_get_sasl_callbacks.3 +++ b/docs/man/memcached_get_sasl_callbacks.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_GET_SASL_CALLBACKS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_GET_SASL_CALLBACKS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_get_sasl_callbacks \- libmemcached Documentation . diff --git a/docs/man/memcached_get_user_data.3 b/docs/man/memcached_get_user_data.3 index 6303ca31..990c5772 100644 --- a/docs/man/memcached_get_user_data.3 +++ b/docs/man/memcached_get_user_data.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_GET_USER_DATA" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_GET_USER_DATA" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_get_user_data \- libmemcached Documentation . diff --git a/docs/man/memcached_increment.3 b/docs/man/memcached_increment.3 index 37c066af..fb161b95 100644 --- a/docs/man/memcached_increment.3 +++ b/docs/man/memcached_increment.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_INCREMENT" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_INCREMENT" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_increment \- Incrementing and Decrementing Values . diff --git a/docs/man/memcached_increment_with_initial.3 b/docs/man/memcached_increment_with_initial.3 index 64147f04..5a43ea9c 100644 --- a/docs/man/memcached_increment_with_initial.3 +++ b/docs/man/memcached_increment_with_initial.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_INCREMENT_WITH_INITIAL" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_INCREMENT_WITH_INITIAL" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_increment_with_initial \- Incrementing and Decrementing Values . diff --git a/docs/man/memcached_lib_version.3 b/docs/man/memcached_lib_version.3 index 2c75bac4..e6b419ce 100644 --- a/docs/man/memcached_lib_version.3 +++ b/docs/man/memcached_lib_version.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_LIB_VERSION" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_LIB_VERSION" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_lib_version \- libmemcached Documentation . diff --git a/docs/man/memcached_memory_allocators.3 b/docs/man/memcached_memory_allocators.3 index f4b2f6b9..2a4a57f9 100644 --- a/docs/man/memcached_memory_allocators.3 +++ b/docs/man/memcached_memory_allocators.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_MEMORY_ALLOCATORS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_MEMORY_ALLOCATORS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_memory_allocators \- libmemcached Documentation . diff --git a/docs/man/memcached_mget.3 b/docs/man/memcached_mget.3 index 2f05bd78..0315eed3 100644 --- a/docs/man/memcached_mget.3 +++ b/docs/man/memcached_mget.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_MGET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_MGET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_mget \- Retrieving data from the server . diff --git a/docs/man/memcached_mget_by_key.3 b/docs/man/memcached_mget_by_key.3 index 420a7808..1b2e4a69 100644 --- a/docs/man/memcached_mget_by_key.3 +++ b/docs/man/memcached_mget_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_MGET_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_MGET_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_mget_by_key \- Retrieving data from the server . diff --git a/docs/man/memcached_mget_execute.3 b/docs/man/memcached_mget_execute.3 index fdb5787f..28a43b77 100644 --- a/docs/man/memcached_mget_execute.3 +++ b/docs/man/memcached_mget_execute.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_MGET_EXECUTE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_MGET_EXECUTE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_mget_execute \- Retrieving data from the server . diff --git a/docs/man/memcached_mget_execute_by_key.3 b/docs/man/memcached_mget_execute_by_key.3 index 2b4ad9ac..8e591b91 100644 --- a/docs/man/memcached_mget_execute_by_key.3 +++ b/docs/man/memcached_mget_execute_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_MGET_EXECUTE_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_MGET_EXECUTE_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_mget_execute_by_key \- Retrieving data from the server . diff --git a/docs/man/memcached_pool.3 b/docs/man/memcached_pool.3 index 758a89ff..2ddf8c76 100644 --- a/docs/man/memcached_pool.3 +++ b/docs/man/memcached_pool.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_POOL" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_POOL" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_pool \- libmemcached Documentation . diff --git a/docs/man/memcached_pool_behavior_get.3 b/docs/man/memcached_pool_behavior_get.3 index 164e3407..73550dab 100644 --- a/docs/man/memcached_pool_behavior_get.3 +++ b/docs/man/memcached_pool_behavior_get.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_POOL_BEHAVIOR_GET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_POOL_BEHAVIOR_GET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_pool_behavior_get \- libmemcached Documentation . diff --git a/docs/man/memcached_pool_behavior_set.3 b/docs/man/memcached_pool_behavior_set.3 index b88eaaaa..75511918 100644 --- a/docs/man/memcached_pool_behavior_set.3 +++ b/docs/man/memcached_pool_behavior_set.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_POOL_BEHAVIOR_SET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_POOL_BEHAVIOR_SET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_pool_behavior_set \- libmemcached Documentation . diff --git a/docs/man/memcached_pool_create.3 b/docs/man/memcached_pool_create.3 index d3e54224..740c8e0c 100644 --- a/docs/man/memcached_pool_create.3 +++ b/docs/man/memcached_pool_create.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_POOL_CREATE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_POOL_CREATE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_pool_create \- libmemcached Documentation . diff --git a/docs/man/memcached_pool_destroy.3 b/docs/man/memcached_pool_destroy.3 index 5c97f510..b1c96d70 100644 --- a/docs/man/memcached_pool_destroy.3 +++ b/docs/man/memcached_pool_destroy.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_POOL_DESTROY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_POOL_DESTROY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_pool_destroy \- libmemcached Documentation . diff --git a/docs/man/memcached_pool_pop.3 b/docs/man/memcached_pool_pop.3 index d9cf40cb..10338aa5 100644 --- a/docs/man/memcached_pool_pop.3 +++ b/docs/man/memcached_pool_pop.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_POOL_POP" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_POOL_POP" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_pool_pop \- libmemcached Documentation . diff --git a/docs/man/memcached_pool_push.3 b/docs/man/memcached_pool_push.3 index 615a39a5..ff8cbe45 100644 --- a/docs/man/memcached_pool_push.3 +++ b/docs/man/memcached_pool_push.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_POOL_PUSH" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_POOL_PUSH" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_pool_push \- libmemcached Documentation . diff --git a/docs/man/memcached_pool_st.3 b/docs/man/memcached_pool_st.3 index 642b70ec..e61579a6 100644 --- a/docs/man/memcached_pool_st.3 +++ b/docs/man/memcached_pool_st.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_POOL_ST" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_POOL_ST" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_pool_st \- libmemcached Documentation . diff --git a/docs/man/memcached_prepend.3 b/docs/man/memcached_prepend.3 index 3ff2f080..c18fb4f6 100644 --- a/docs/man/memcached_prepend.3 +++ b/docs/man/memcached_prepend.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_PREPEND" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_PREPEND" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_prepend \- Storing and Replacing Data . diff --git a/docs/man/memcached_prepend_by_key.3 b/docs/man/memcached_prepend_by_key.3 index 321e9fa6..fef8339d 100644 --- a/docs/man/memcached_prepend_by_key.3 +++ b/docs/man/memcached_prepend_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_PREPEND_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_PREPEND_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_prepend_by_key \- Storing and Replacing Data . diff --git a/docs/man/memcached_quit.3 b/docs/man/memcached_quit.3 index 3995eed9..ebca6513 100644 --- a/docs/man/memcached_quit.3 +++ b/docs/man/memcached_quit.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_QUIT" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_QUIT" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_quit \- libmemcached Documentation . diff --git a/docs/man/memcached_replace.3 b/docs/man/memcached_replace.3 index e13fabc6..16ca5449 100644 --- a/docs/man/memcached_replace.3 +++ b/docs/man/memcached_replace.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_REPLACE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_REPLACE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_replace \- Storing and Replacing Data . diff --git a/docs/man/memcached_replace_by_key.3 b/docs/man/memcached_replace_by_key.3 index dace8f26..986923d3 100644 --- a/docs/man/memcached_replace_by_key.3 +++ b/docs/man/memcached_replace_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_REPLACE_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_REPLACE_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_replace_by_key \- Storing and Replacing Data . diff --git a/docs/man/memcached_result_cas.3 b/docs/man/memcached_result_cas.3 index 8fb29d95..89ea077a 100644 --- a/docs/man/memcached_result_cas.3 +++ b/docs/man/memcached_result_cas.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_RESULT_CAS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_RESULT_CAS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_result_cas \- Working with result sets . diff --git a/docs/man/memcached_result_create.3 b/docs/man/memcached_result_create.3 index 427a8a51..952513d6 100644 --- a/docs/man/memcached_result_create.3 +++ b/docs/man/memcached_result_create.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_RESULT_CREATE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_RESULT_CREATE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_result_create \- Working with result sets . diff --git a/docs/man/memcached_result_flags.3 b/docs/man/memcached_result_flags.3 index 38e0b2d7..0bc08747 100644 --- a/docs/man/memcached_result_flags.3 +++ b/docs/man/memcached_result_flags.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_RESULT_FLAGS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_RESULT_FLAGS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_result_flags \- Working with result sets . diff --git a/docs/man/memcached_result_free.3 b/docs/man/memcached_result_free.3 index b3560e17..a7093f33 100644 --- a/docs/man/memcached_result_free.3 +++ b/docs/man/memcached_result_free.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_RESULT_FREE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_RESULT_FREE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_result_free \- Working with result sets . diff --git a/docs/man/memcached_result_key_length.3 b/docs/man/memcached_result_key_length.3 index abbe59c5..86619527 100644 --- a/docs/man/memcached_result_key_length.3 +++ b/docs/man/memcached_result_key_length.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_RESULT_KEY_LENGTH" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_RESULT_KEY_LENGTH" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_result_key_length \- Working with result sets . diff --git a/docs/man/memcached_result_key_value.3 b/docs/man/memcached_result_key_value.3 index 175531a8..4572bb4a 100644 --- a/docs/man/memcached_result_key_value.3 +++ b/docs/man/memcached_result_key_value.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_RESULT_KEY_VALUE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_RESULT_KEY_VALUE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_result_key_value \- Working with result sets . diff --git a/docs/man/memcached_result_length.3 b/docs/man/memcached_result_length.3 index 080d1508..4978d921 100644 --- a/docs/man/memcached_result_length.3 +++ b/docs/man/memcached_result_length.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_RESULT_LENGTH" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_RESULT_LENGTH" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_result_length \- Working with result sets . diff --git a/docs/man/memcached_result_st.3 b/docs/man/memcached_result_st.3 index 5b30c3e7..14c7bdf8 100644 --- a/docs/man/memcached_result_st.3 +++ b/docs/man/memcached_result_st.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_RESULT_ST" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_RESULT_ST" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_result_st \- Working with result sets . diff --git a/docs/man/memcached_result_value.3 b/docs/man/memcached_result_value.3 index 8af1561f..b153a957 100644 --- a/docs/man/memcached_result_value.3 +++ b/docs/man/memcached_result_value.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_RESULT_VALUE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_RESULT_VALUE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_result_value \- Working with result sets . diff --git a/docs/man/memcached_sasl.3 b/docs/man/memcached_sasl.3 index a3c93c52..fc954c8a 100644 --- a/docs/man/memcached_sasl.3 +++ b/docs/man/memcached_sasl.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SASL" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SASL" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_sasl \- libmemcached Documentation . diff --git a/docs/man/memcached_sasl_set_auth_data.3 b/docs/man/memcached_sasl_set_auth_data.3 index cdd1bf7e..caa34279 100644 --- a/docs/man/memcached_sasl_set_auth_data.3 +++ b/docs/man/memcached_sasl_set_auth_data.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SASL_SET_AUTH_DATA" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SASL_SET_AUTH_DATA" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_sasl_set_auth_data \- libmemcached Documentation . diff --git a/docs/man/memcached_server_add.3 b/docs/man/memcached_server_add.3 index c1ce80bf..5f633117 100644 --- a/docs/man/memcached_server_add.3 +++ b/docs/man/memcached_server_add.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_ADD" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_ADD" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_add \- libmemcached Documentation . diff --git a/docs/man/memcached_server_add_unix_socket.3 b/docs/man/memcached_server_add_unix_socket.3 index 9d3cc215..010aa35f 100644 --- a/docs/man/memcached_server_add_unix_socket.3 +++ b/docs/man/memcached_server_add_unix_socket.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_ADD_UNIX_SOCKET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_ADD_UNIX_SOCKET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_add_unix_socket \- libmemcached Documentation . diff --git a/docs/man/memcached_server_count.3 b/docs/man/memcached_server_count.3 index 74d1f0cc..1e330dc4 100644 --- a/docs/man/memcached_server_count.3 +++ b/docs/man/memcached_server_count.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_COUNT" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_COUNT" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_count \- libmemcached Documentation . diff --git a/docs/man/memcached_server_cursor.3 b/docs/man/memcached_server_cursor.3 index 51dae118..f979b713 100644 --- a/docs/man/memcached_server_cursor.3 +++ b/docs/man/memcached_server_cursor.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_CURSOR" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_CURSOR" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_cursor \- libmemcached Documentation . diff --git a/docs/man/memcached_server_list.3 b/docs/man/memcached_server_list.3 index 0b6e854c..bdb0ff08 100644 --- a/docs/man/memcached_server_list.3 +++ b/docs/man/memcached_server_list.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_LIST" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_LIST" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_list \- libmemcached Documentation . diff --git a/docs/man/memcached_server_list_append.3 b/docs/man/memcached_server_list_append.3 index d93f1b15..6340c564 100644 --- a/docs/man/memcached_server_list_append.3 +++ b/docs/man/memcached_server_list_append.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_LIST_APPEND" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_LIST_APPEND" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_list_append \- libmemcached Documentation . diff --git a/docs/man/memcached_server_list_count.3 b/docs/man/memcached_server_list_count.3 index 8c302973..bbb504d1 100644 --- a/docs/man/memcached_server_list_count.3 +++ b/docs/man/memcached_server_list_count.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_LIST_COUNT" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_LIST_COUNT" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_list_count \- libmemcached Documentation . diff --git a/docs/man/memcached_server_list_free.3 b/docs/man/memcached_server_list_free.3 index cffefbc3..217396bd 100644 --- a/docs/man/memcached_server_list_free.3 +++ b/docs/man/memcached_server_list_free.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_LIST_FREE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_LIST_FREE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_list_free \- libmemcached Documentation . diff --git a/docs/man/memcached_server_push.3 b/docs/man/memcached_server_push.3 index b2c4b7e1..fc1c1123 100644 --- a/docs/man/memcached_server_push.3 +++ b/docs/man/memcached_server_push.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_PUSH" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_PUSH" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_push \- libmemcached Documentation . diff --git a/docs/man/memcached_server_st.3 b/docs/man/memcached_server_st.3 index a4041290..1e133342 100644 --- a/docs/man/memcached_server_st.3 +++ b/docs/man/memcached_server_st.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVER_ST" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVER_ST" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_server_st \- libmemcached Documentation . diff --git a/docs/man/memcached_servers.3 b/docs/man/memcached_servers.3 index 702d6fa5..92470304 100644 --- a/docs/man/memcached_servers.3 +++ b/docs/man/memcached_servers.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVERS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVERS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_servers \- libmemcached Documentation . diff --git a/docs/man/memcached_servers_parse.3 b/docs/man/memcached_servers_parse.3 index e692e9c1..cbb4ecda 100644 --- a/docs/man/memcached_servers_parse.3 +++ b/docs/man/memcached_servers_parse.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVERS_PARSE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVERS_PARSE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_servers_parse \- libmemcached Documentation . diff --git a/docs/man/memcached_servers_reset.3 b/docs/man/memcached_servers_reset.3 index 83d02d59..7942d59a 100644 --- a/docs/man/memcached_servers_reset.3 +++ b/docs/man/memcached_servers_reset.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SERVERS_RESET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SERVERS_RESET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_servers_reset \- libmemcached Documentation . diff --git a/docs/man/memcached_set.3 b/docs/man/memcached_set.3 index 326dd461..0bef67c2 100644 --- a/docs/man/memcached_set.3 +++ b/docs/man/memcached_set.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SET" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SET" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_set \- Storing and Replacing Data . diff --git a/docs/man/memcached_set_by_key.3 b/docs/man/memcached_set_by_key.3 index 1c45ac42..e96b4094 100644 --- a/docs/man/memcached_set_by_key.3 +++ b/docs/man/memcached_set_by_key.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SET_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SET_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_set_by_key \- Storing and Replacing Data . diff --git a/docs/man/memcached_set_memory_allocators.3 b/docs/man/memcached_set_memory_allocators.3 index faa98be0..0f74f9ef 100644 --- a/docs/man/memcached_set_memory_allocators.3 +++ b/docs/man/memcached_set_memory_allocators.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SET_MEMORY_ALLOCATORS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SET_MEMORY_ALLOCATORS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_set_memory_allocators \- libmemcached Documentation . diff --git a/docs/man/memcached_set_memory_allocators_context.3 b/docs/man/memcached_set_memory_allocators_context.3 index d2a0f1e1..819314a9 100644 --- a/docs/man/memcached_set_memory_allocators_context.3 +++ b/docs/man/memcached_set_memory_allocators_context.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SET_MEMORY_ALLOCATORS_CONTEXT" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SET_MEMORY_ALLOCATORS_CONTEXT" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_set_memory_allocators_context \- libmemcached Documentation . diff --git a/docs/man/memcached_set_sasl_callbacks.3 b/docs/man/memcached_set_sasl_callbacks.3 index e7321ff8..b9221c60 100644 --- a/docs/man/memcached_set_sasl_callbacks.3 +++ b/docs/man/memcached_set_sasl_callbacks.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SET_SASL_CALLBACKS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SET_SASL_CALLBACKS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_set_sasl_callbacks \- libmemcached Documentation . diff --git a/docs/man/memcached_set_user_data.3 b/docs/man/memcached_set_user_data.3 index 838e24a0..c24fb4a7 100644 --- a/docs/man/memcached_set_user_data.3 +++ b/docs/man/memcached_set_user_data.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_SET_USER_DATA" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_SET_USER_DATA" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_set_user_data \- libmemcached Documentation . diff --git a/docs/man/memcached_stat.3 b/docs/man/memcached_stat.3 index 3c2817d7..e4960a4e 100644 --- a/docs/man/memcached_stat.3 +++ b/docs/man/memcached_stat.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_STAT" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_STAT" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_stat \- libmemcached Documentation . diff --git a/docs/man/memcached_stat_execute.3 b/docs/man/memcached_stat_execute.3 index 4aa87a0e..f7da60bd 100644 --- a/docs/man/memcached_stat_execute.3 +++ b/docs/man/memcached_stat_execute.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_STAT_EXECUTE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_STAT_EXECUTE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_stat_execute \- libmemcached Documentation . diff --git a/docs/man/memcached_stat_get_keys.3 b/docs/man/memcached_stat_get_keys.3 index e03b7dfc..bb4bfb54 100644 --- a/docs/man/memcached_stat_get_keys.3 +++ b/docs/man/memcached_stat_get_keys.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_STAT_GET_KEYS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_STAT_GET_KEYS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_stat_get_keys \- libmemcached Documentation . diff --git a/docs/man/memcached_stat_get_value.3 b/docs/man/memcached_stat_get_value.3 index 0e94a6bb..7ace4aa4 100644 --- a/docs/man/memcached_stat_get_value.3 +++ b/docs/man/memcached_stat_get_value.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_STAT_GET_VALUE" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_STAT_GET_VALUE" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_stat_get_value \- libmemcached Documentation . diff --git a/docs/man/memcached_stat_servername.3 b/docs/man/memcached_stat_servername.3 index 66dd0613..10f01bfd 100644 --- a/docs/man/memcached_stat_servername.3 +++ b/docs/man/memcached_stat_servername.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_STAT_SERVERNAME" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_STAT_SERVERNAME" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_stat_servername \- libmemcached Documentation . diff --git a/docs/man/memcached_stats.3 b/docs/man/memcached_stats.3 index 60a55828..a3c6fb3c 100644 --- a/docs/man/memcached_stats.3 +++ b/docs/man/memcached_stats.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_STATS" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_STATS" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_stats \- libmemcached Documentation . diff --git a/docs/man/memcached_strerror.3 b/docs/man/memcached_strerror.3 index bf5d35e8..0fcd3036 100644 --- a/docs/man/memcached_strerror.3 +++ b/docs/man/memcached_strerror.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_STRERROR" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_STRERROR" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_strerror \- libmemcached Documentation . diff --git a/docs/man/memcached_user_data.3 b/docs/man/memcached_user_data.3 index 01f3e088..dc884349 100644 --- a/docs/man/memcached_user_data.3 +++ b/docs/man/memcached_user_data.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_USER_DATA" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_USER_DATA" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_user_data \- libmemcached Documentation . diff --git a/docs/man/memcached_verbosity.3 b/docs/man/memcached_verbosity.3 index 2eef9f51..3ed1fa3c 100644 --- a/docs/man/memcached_verbosity.3 +++ b/docs/man/memcached_verbosity.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_VERBOSITY" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_VERBOSITY" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_verbosity \- libmemcached Documentation . diff --git a/docs/man/memcached_version.3 b/docs/man/memcached_version.3 index 64d744e4..16829ecf 100644 --- a/docs/man/memcached_version.3 +++ b/docs/man/memcached_version.3 @@ -1,4 +1,4 @@ -.TH "MEMCACHED_VERSION" "3" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCACHED_VERSION" "3" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcached_version \- libmemcached Documentation . diff --git a/docs/man/memcapable.1 b/docs/man/memcapable.1 index a0aa1d67..5a5943cc 100644 --- a/docs/man/memcapable.1 +++ b/docs/man/memcapable.1 @@ -1,4 +1,4 @@ -.TH "MEMCAPABLE" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCAPABLE" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcapable \- libmemcached Documentation . diff --git a/docs/man/memcat.1 b/docs/man/memcat.1 index c3af50af..5a998e8f 100644 --- a/docs/man/memcat.1 +++ b/docs/man/memcat.1 @@ -1,4 +1,4 @@ -.TH "MEMCAT" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCAT" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcat \- libmemcached Documentation . diff --git a/docs/man/memcp.1 b/docs/man/memcp.1 index 7b43c2a6..c97a5bad 100644 --- a/docs/man/memcp.1 +++ b/docs/man/memcp.1 @@ -1,4 +1,4 @@ -.TH "MEMCP" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMCP" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memcp \- libmemcached Documentation . diff --git a/docs/man/memdump.1 b/docs/man/memdump.1 index 857c7689..edf99b39 100644 --- a/docs/man/memdump.1 +++ b/docs/man/memdump.1 @@ -1,4 +1,4 @@ -.TH "MEMDUMP" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMDUMP" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memdump \- libmemcached Documentation . diff --git a/docs/man/memerror.1 b/docs/man/memerror.1 index 7063a764..fc69e551 100644 --- a/docs/man/memerror.1 +++ b/docs/man/memerror.1 @@ -1,4 +1,4 @@ -.TH "MEMERROR" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMERROR" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memerror \- libmemcached Documentation . diff --git a/docs/man/memflush.1 b/docs/man/memflush.1 index b71454cc..ae670fd0 100644 --- a/docs/man/memflush.1 +++ b/docs/man/memflush.1 @@ -1,4 +1,4 @@ -.TH "MEMFLUSH" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMFLUSH" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memflush \- libmemcached Documentation . diff --git a/docs/man/memrm.1 b/docs/man/memrm.1 index 0dc96a7e..0d44a360 100644 --- a/docs/man/memrm.1 +++ b/docs/man/memrm.1 @@ -1,4 +1,4 @@ -.TH "MEMRM" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMRM" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memrm \- libmemcached Documentation . diff --git a/docs/man/memslap.1 b/docs/man/memslap.1 index 33346488..47bc8094 100644 --- a/docs/man/memslap.1 +++ b/docs/man/memslap.1 @@ -1,4 +1,4 @@ -.TH "MEMSLAP" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMSLAP" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memslap \- libmemcached Documentation . diff --git a/docs/man/memstat.1 b/docs/man/memstat.1 index 2e9f9929..848b84e2 100644 --- a/docs/man/memstat.1 +++ b/docs/man/memstat.1 @@ -1,4 +1,4 @@ -.TH "MEMSTAT" "1" "April 13, 2011" "0.47" "libmemcached" +.TH "MEMSTAT" "1" "April 14, 2011" "0.47" "libmemcached" .SH NAME memstat \- libmemcached Documentation . diff --git a/docs/memcached_callback.rst b/docs/memcached_callback.rst index 787bc49a..aac70391 100644 --- a/docs/memcached_callback.rst +++ b/docs/memcached_callback.rst @@ -41,73 +41,71 @@ function set by memcached_callback_set(). memcached_callback_set() changes the function/structure assigned by a callback flag. No connections are reset. -You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for any -of the callbacks +You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for any of the callbacks. .. c:var:: MEMCACHED_CALLBACK_CLEANUP_FUNCTION - When memcached_delete() is called this function will be excuted. At the - point of its execution all connections have been closed. +When memcached_delete() is called this function will be excuted. At the point of its execution all connections are closed. .. c:var:: MEMCACHED_CALLBACK_CLONE_FUNCTION - When memcached_delete() is called this function will be excuted. At the - point of its execution all connections have been closed. +When memcached_delete() is called this function will be excuted. At the +point of its execution all connections are closed. .. c:var:: MEMCACHED_CALLBACK_PREFIX_KEY - You can set a value which will be used to create a domain for your keys. - The value specified here will be prefixed to each of your keys. The value can not - be greater then MEMCACHED_PREFIX_KEY_MAX_SIZE - 1 and will reduce MEMCACHED_MAX_KEY by - the value of your key. The prefix key is only applied to the primary key, - not the master key. MEMCACHED_FAILURE will be returned if no key is set. In the case - of a key which is too long MEMCACHED_BAD_KEY_PROVIDED will be returned. +You can set a value which will be used to create a domain for your keys. +The value specified here will be prefixed to each of your keys. The value can not be greater then MEMCACHED_PREFIX_KEY_MAX_SIZE - 1 and will reduce MEMCACHED_MAX_KEY by the value of your key. + +The prefix key is only applied to the primary key, not the master key. MEMCACHED_FAILURE will be returned if no key is set. In the case of a key which is too long, MEMCACHED_BAD_KEY_PROVIDED will be returned. - If you set a value with the value being NULL then the prefix key is disabled. +If you set a value with the value being NULL then the prefix key is disabled. .. c:var:: MEMCACHED_CALLBACK_USER_DATA - This allows you to store a pointer to a specifc piece of data. This can be - retrieved from inside of memcached_fetch_execute(). Cloning a memcached_st - will copy the pointer to the clone. +This allows you to store a pointer to a specifc piece of data. This can be +retrieved from inside of memcached_fetch_execute(). Cloning a memcached_st +will copy the pointer to the clone. .. c:var:: MEMCACHED_CALLBACK_MALLOC_FUNCTION - DEPRECATED: use memcached_set_memory_allocators instead. +DEPRECATED: use memcached_set_memory_allocators instead. .. c:var:: MEMCACHED_CALLBACK_REALLOC_FUNCTION - DEPRECATED: use memcached_set_memory_allocators instead. +DEPRECATED: use memcached_set_memory_allocators instead. .. c:var:: MEMCACHED_CALLBACK_FREE_FUNCTION - DEPRECATED: use memcached_set_memory_allocators instead. +DEPRECATED: use memcached_set_memory_allocators instead. .. c:var:: MEMCACHED_CALLBACK_GET_FAILURE - This function implements the read through cache behavior. On failure of retrieval this callback will be called. - You are responsible for populating the result object provided. This result object will then be stored in the server and - returned to the calling process. You must clone the memcached_st in order to - make use of it. The value will be stored only if you return - MEMCACHED_SUCCESS or MEMCACHED_BUFFERED. Returning MEMCACHED_BUFFERED will - cause the object to be buffered and not sent immediatly (if this is the default behavior based on your connection setup this will happen automatically). +This function implements the read through cache behavior. On failure of retrieval this callback will be called. + +You are responsible for populating the result object provided. This result object will then be stored in the server and returned to the calling process. + +You must clone the memcached_st in order to +make use of it. The value will be stored only if you return +MEMCACHED_SUCCESS or MEMCACHED_BUFFERED. Returning MEMCACHED_BUFFERED will +cause the object to be buffered and not sent immediatly (if this is the default behavior based on your connection setup this will happen automatically). - The prototype for this is: - memcached_return_t (\*memcached_trigger_key)(memcached_st \*ptr, char \*key, size_t key_length, memcached_result_st \*result); +The prototype for this is: +memcached_return_t (\*memcached_trigger_key)(memcached_st \*ptr, char \*key, size_t key_length, memcached_result_st \*result); diff --git a/docs/memcached_delete.rst b/docs/memcached_delete.rst index 5afccee7..f628f69e 100644 --- a/docs/memcached_delete.rst +++ b/docs/memcached_delete.rst @@ -25,8 +25,8 @@ memcached_delete_by_key() works the same, but it takes a master key to find the given value. Expiration works by placing the item into a delete queue, which means that -it won't possible to retrieve it by the "get" command, but "add" and -"replace" command with this key will also fail (the "set" command will +it won't be possible to retrieve it by the "get" command. The "add" and +"replace" commands with this key will also fail (the "set" command will succeed, however). After the time passes, the item is finally deleted from server memory. Please note the the Danga memcached server removed tests for expiration in diff --git a/docs/memcached_dump.rst b/docs/memcached_dump.rst index 9b6e887e..a7dcb4fe 100644 --- a/docs/memcached_dump.rst +++ b/docs/memcached_dump.rst @@ -42,12 +42,12 @@ DESCRIPTION ----------- -memcached_dump() is used to get a list of keys found memcached(1) servers. +memcached_dump() is used to get a list of keys found in memcached(1) servers. Because memcached(1) does not guarentee to dump all keys you can not assume you have fetched all keys from the server. The function takes an array of callbacks that it will use to execute on keys as they are found. -Currently the binar protocol is not testsed. +Currently the binary protocol is not testsed. ------ diff --git a/docs/memcached_get.rst b/docs/memcached_get.rst index f6813d45..dcb931c7 100644 --- a/docs/memcached_get.rst +++ b/docs/memcached_get.rst @@ -65,7 +65,7 @@ memcached_return_t pointer to hold any error. The object will be returned upon success and NULL will be returned on failure. MEMCACHD_END is returned by the \*error value when all objects that have been found are returned. The final value upon MEMCACHED_END is null. Values returned by -memcached_fetch() musted be free'ed by the caller. memcached_fetch() will +memcached_fetch() must be freed by the caller. memcached_fetch() will be DEPRECATED in the near future, memcached_fetch_result() should be used instead. @@ -89,7 +89,7 @@ memcached_mget_execute() and memcached_mget_execute_by_key() is similar to memcached_mget(), but it may trigger the supplied callbacks with result sets while sending out the queries. If you try to perform a really large multiget with memcached_mget() you may encounter a -deadlock in the OS kernel (we fail to write data to the socket because +deadlock in the OS kernel (it will fail to write data to the socket because the input buffer is full). memcached_mget_execute() solves this problem by processing some of the results before continuing sending out requests. Please note that this function is only available in the @@ -100,9 +100,9 @@ as memcached_get() and memcached_mget(). The difference is that they take a master key that is used for determining which server an object was stored if key partitioning was used for storage. -All of the above functions are not testsed when the \ ``MEMCACHED_BEHAVIOR_USE_UDP``\ +All of the above functions are not tested when the \ ``MEMCACHED_BEHAVIOR_USE_UDP``\ has been set. Executing any of these functions with this behavior on will result in -\ ``MEMCACHED_NOT_SUPPORTED``\ being returned or, for those functions which do not return +\ ``MEMCACHED_NOT_SUPPORTED``\ being returned, or for those functions which do not return a \ ``memcached_return_t``\ , the error function parameter will be set to \ ``MEMCACHED_NOT_SUPPORTED``\ . diff --git a/docs/memcached_memory_allocators.rst b/docs/memcached_memory_allocators.rst index 7f1cd10e..40219079 100644 --- a/docs/memcached_memory_allocators.rst +++ b/docs/memcached_memory_allocators.rst @@ -45,7 +45,7 @@ DESCRIPTION ----------- -libmemcached(3) allows you to specify your own memory allocators optimized +libmemcached(3) allows you to specify your own memory allocators, optimized for your application. This enables libmemcached to be used inside of applications that have their own malloc implementation. memcached_set_memory_allocators() is used to set the memory allocators used diff --git a/docs/memcached_result_st.rst b/docs/memcached_result_st.rst index 9243d6b4..e8aba518 100644 --- a/docs/memcached_result_st.rst +++ b/docs/memcached_result_st.rst @@ -59,9 +59,9 @@ DESCRIPTION libmemcached(3) can optionally return a memcached_result_st which acts as a result object. The result objects have added benefits over the character -pointer returns in that they are forward compatible with new return items +pointer returns, in that they are forward compatible with new return items that future memcached servers may implement (the best current example of -this is the CAS return item). The structures can also be reused which will +this is the CAS return item). The structures can also be reused, which will save on calls to malloc(3). It is suggested that you use result objects over char \* return functions. @@ -72,7 +72,7 @@ memcached_result_create() will either allocate memory for a memcached_result_st or will initialize a structure passed to it. memcached_result_free() will deallocate any memory attached to the -structure. If the structure was also alloacted, it will deallocate it. +structure. If the structure was also allocated, it will deallocate it. memcached_result_key_value() returns the key value associated with the current result object. @@ -91,7 +91,7 @@ current result object. memcached_result_cas() returns the cas associated with the current result object. This value will only be available if the server -testss it. +tests it. memcached_result_set_value() takes a byte array and a size and sets the result to this value. This function is used for trigger responses. diff --git a/docs/memcached_sasl.rst b/docs/memcached_sasl.rst index 30aa72ca..bf0251dd 100644 --- a/docs/memcached_sasl.rst +++ b/docs/memcached_sasl.rst @@ -44,7 +44,7 @@ libsasl to perform SASL authentication. Please note that SASL requires the memcached binary protocol, and you have to specify the callbacks before you connect to the server. -memcached_set_sasl_auth_data() is a helper function for you defining +memcached_set_sasl_auth_data() is a helper function defining the basic functionality for you, but it will store the username and password in memory. If you choose to use this method you have to call memcached_destroy_sasl_auth_data before calling memcached_free to avoid diff --git a/docs/memcached_set.rst b/docs/memcached_set.rst index c2f08b3c..4cdbd994 100644 --- a/docs/memcached_set.rst +++ b/docs/memcached_set.rst @@ -49,8 +49,8 @@ DESCRIPTION memcached_set(), memcached_add(), and memcached_replace() are all used to store information on the server. All methods take a key, and its length to store the object. Keys are currently limited to 250 characters by the -memcached(1) server. You must also supply a value and a length. Optionally you -may tests an expiration time for the object and a 16 byte value (it is +memcached(1) server. You must supply both a value and a length. Optionally you +may test an expiration time for the object and a 16 byte value (it is meant to be used as a bitmap). memcached_set() will write an object to the server. If an object already @@ -87,12 +87,12 @@ If you are looking for performance, memcached_set() with non-blocking IO is the fastest way to store data on the server. All of the above functions are testsed with the \ ``MEMCACHED_BEHAVIOR_USE_UDP``\ -behavior enabled. But when using these operations with this behavior on, there +behavior enabled. However, when using these operations with this behavior on, there are limits to the size of the payload being sent to the server. The reason for -these limits is that the Memcahed Server does not allow multi-datagram requests +these limits is that the Memcached Server does not allow multi-datagram requests and the current server implementation sets a datagram size to 1400 bytes. Due to protocol overhead, the actual limit of the user supplied data is less than -1400 bytes and depends on the protocol in use as well as the operation being +1400 bytes and depends on the protocol in use as, well as the operation being executed. When running with the binary protocol, \ `` MEMCACHED_BEHAVIOR_BINARY_PROTOCOL``\ , the size of the key,value, flags and expiry combined may not exceed 1368 bytes. When running with the ASCII protocol, the exact limit fluctuates depending on diff --git a/docs/memcached_version.rst b/docs/memcached_version.rst index 01403a16..a670c78f 100644 --- a/docs/memcached_version.rst +++ b/docs/memcached_version.rst @@ -39,7 +39,7 @@ DESCRIPTION memcached_lib_version() is used to return a simple version string representing -the libmemcached version (version of the client library, not server) +the libmemcached version (client library version, not server version) memcached_version() is used to set the major, minor, and micro versions of each memcached server being used by the memcached_st connection structure. It returns the diff --git a/docs/memcapable.rst b/docs/memcapable.rst index a8ac4e43..b9d2f5a8 100644 --- a/docs/memcapable.rst +++ b/docs/memcapable.rst @@ -16,29 +16,29 @@ SYNOPSIS .. option:: -h hostname - Specify the hostname to connect to. The default is \ *localhost*\ +Specify the hostname to connect to. The default is \ *localhost*\ .. option:: -p port - Specify the port number to connect to. The default is \ *11211*\ +Specify the port number to connect to. The default is \ *11211*\ .. option:: -c - Generate a coredump when it detects an error from the server. +Generate a coredump when it detects an error from the server. .. option:: -v - Print out the comparison when it detects an error from the server. +Print out the comparison when it detects an error from the server. .. option:: -t n - Set the timeout from an IO operation to/from the server to \ *n*\ seconds. +Set the timeout from an IO operation to/from the server to \ *n*\ seconds. ----------- DESCRIPTION diff --git a/docs/memcp.rst b/docs/memcp.rst index 6e12bedd..7e620cca 100644 --- a/docs/memcp.rst +++ b/docs/memcp.rst @@ -26,11 +26,10 @@ DESCRIPTION It is similar to the standard UNIX cp(1) command. The key names will be the names of the files, -without any directory path part. +without any directory path. You can specify servers via the \ **--servers**\ option or via the -environment variable \ ``MEMCACHED_SERVERS``\ . If you specify neither of -these, the final value in the command line list is the name of a +environment variable \ ``MEMCACHED_SERVERS``\. If you do not specify either these, the final value in the command line list is the name of a server(s). For a full list of operations run the tool with the \ **--help**\ option. diff --git a/docs/memdump.rst b/docs/memdump.rst index 74e1254f..fbdb8c1c 100644 --- a/docs/memdump.rst +++ b/docs/memdump.rst @@ -21,7 +21,7 @@ DESCRIPTION ----------- -\ **memdump**\ currently dumps a list of "keys" from all servers that +\ **memdump**\ dumps a list of "keys" from all servers that it is told to fetch from. Because memcached does not guarentee to provide all keys it is not possible to get a complete "dump". diff --git a/docs/memerror.rst b/docs/memerror.rst index 7e2d967f..7501c071 100644 --- a/docs/memerror.rst +++ b/docs/memerror.rst @@ -3,7 +3,7 @@ memerror - translate an error code to a string ============================================== -Translate a memcached error code to a string +Translates a memcached error code into a string -------- @@ -21,7 +21,7 @@ DESCRIPTION ----------- -\ **memerror**\ translate an error code from libmemcached(3) to a human +\ **memerror**\ translate an error code from libmemcached(3) into a human readable string. For a full list of operations run the tool with the \ **--help**\ option. diff --git a/docs/memflush.rst b/docs/memflush.rst index 6cb04728..e02969bd 100644 --- a/docs/memflush.rst +++ b/docs/memflush.rst @@ -22,7 +22,7 @@ DESCRIPTION \ **memflush**\ resets the contents of memcached(1) servers. -This means all data in these servers will be deleted. +This means that all data in the specified servers will be deleted. You can specify servers via the \ **--servers**\ option or via the environment variable \ ``MEMCACHED_SERVERS``\ . diff --git a/docs/memslap.rst b/docs/memslap.rst index cde4ace7..1996b99f 100644 --- a/docs/memslap.rst +++ b/docs/memslap.rst @@ -20,12 +20,9 @@ DESCRIPTION \ **memslap**\ is a load generation and benchmark tool for memcached(1) -servers. It generates configurable workload such as threads, concurrencies, connections, -run time, overwrite, miss rate, key size, value size, get/set proportion, -expected throughput, and so on. +servers. It generates configurable workload such as threads, concurrencies, connections, run time, overwrite, miss rate, key size, value size, get/set proportion, expected throughput, and so on. -You can specify servers via the \ **--servers**\ option or via the -environment variable \ ``MEMCACHED_SERVERS``\ . +You can specify servers via the \ **--servers**\ option or via the environment variable \ ``MEMCACHED_SERVERS``\ . -------- diff --git a/example/include.am b/example/include.am index ae9bae93..561eebc8 100644 --- a/example/include.am +++ b/example/include.am @@ -10,16 +10,13 @@ example_memcached_light_SOURCES= \ example/interface_v0.c \ example/interface_v1.c \ example/memcached_light.c \ + libmemcached/byteorder.cc \ example/memcached_light.h \ example/storage.h example_memcached_light_LDADD= libmemcached/libmemcachedprotocol.la \ $(LIBINNODB) $(LTLIBEVENT) -if BUILD_BYTEORDER -example_memcached_light_LDADD+= libmemcached/libbyteorder.la -endif - if HAVE_LIBINNODB example_memcached_light_SOURCES+= example/storage_innodb.c else diff --git a/libhashkit/algorithm.c b/libhashkit/algorithm.c deleted file mode 100644 index de00081d..00000000 --- a/libhashkit/algorithm.c +++ /dev/null @@ -1,69 +0,0 @@ -/* HashKit - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - */ - -#include - -uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length) -{ - return hashkit_one_at_a_time(key, key_length, NULL); -} - -uint32_t libhashkit_fnv1_64(const char *key, size_t key_length) -{ - return hashkit_fnv1_64(key, key_length, NULL); -} - -uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length) -{ - return hashkit_fnv1a_64(key, key_length, NULL); -} - -uint32_t libhashkit_fnv1_32(const char *key, size_t key_length) -{ - return hashkit_fnv1_32(key, key_length, NULL); -} - -uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length) -{ - return hashkit_fnv1a_32(key, key_length, NULL); -} - -uint32_t libhashkit_crc32(const char *key, size_t key_length) -{ - return hashkit_crc32(key, key_length, NULL); -} - -#ifdef HAVE_HSIEH_HASH -uint32_t libhashkit_hsieh(const char *key, size_t key_length) -{ - return hashkit_hsieh(key, key_length, NULL); -} -#endif - -#ifdef HAVE_MURMUR_HASH -uint32_t libhashkit_murmur(const char *key, size_t key_length) -{ - return hashkit_murmur(key, key_length, NULL); -} -#endif - -uint32_t libhashkit_jenkins(const char *key, size_t key_length) -{ - return hashkit_jenkins(key, key_length, NULL); -} - -uint32_t libhashkit_md5(const char *key, size_t key_length) -{ - return hashkit_md5(key, key_length, NULL); -} - -void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result) -{ - md5_signature(key, (uint32_t)length, result); -} - diff --git a/libhashkit/algorithm.cc b/libhashkit/algorithm.cc new file mode 100644 index 00000000..de00081d --- /dev/null +++ b/libhashkit/algorithm.cc @@ -0,0 +1,69 @@ +/* HashKit + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#include + +uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length) +{ + return hashkit_one_at_a_time(key, key_length, NULL); +} + +uint32_t libhashkit_fnv1_64(const char *key, size_t key_length) +{ + return hashkit_fnv1_64(key, key_length, NULL); +} + +uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length) +{ + return hashkit_fnv1a_64(key, key_length, NULL); +} + +uint32_t libhashkit_fnv1_32(const char *key, size_t key_length) +{ + return hashkit_fnv1_32(key, key_length, NULL); +} + +uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length) +{ + return hashkit_fnv1a_32(key, key_length, NULL); +} + +uint32_t libhashkit_crc32(const char *key, size_t key_length) +{ + return hashkit_crc32(key, key_length, NULL); +} + +#ifdef HAVE_HSIEH_HASH +uint32_t libhashkit_hsieh(const char *key, size_t key_length) +{ + return hashkit_hsieh(key, key_length, NULL); +} +#endif + +#ifdef HAVE_MURMUR_HASH +uint32_t libhashkit_murmur(const char *key, size_t key_length) +{ + return hashkit_murmur(key, key_length, NULL); +} +#endif + +uint32_t libhashkit_jenkins(const char *key, size_t key_length) +{ + return hashkit_jenkins(key, key_length, NULL); +} + +uint32_t libhashkit_md5(const char *key, size_t key_length) +{ + return hashkit_md5(key, key_length, NULL); +} + +void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result) +{ + md5_signature(key, (uint32_t)length, result); +} + diff --git a/libhashkit/behavior.c b/libhashkit/behavior.c deleted file mode 100644 index ee0efcf3..00000000 --- a/libhashkit/behavior.c +++ /dev/null @@ -1,9 +0,0 @@ -/* HashKit - * Copyright (C) 2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - */ - -#include diff --git a/libhashkit/behavior.cc b/libhashkit/behavior.cc new file mode 100644 index 00000000..ee0efcf3 --- /dev/null +++ b/libhashkit/behavior.cc @@ -0,0 +1,9 @@ +/* HashKit + * Copyright (C) 2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#include diff --git a/libhashkit/common.h b/libhashkit/common.h index 73b198f5..5cf8b9f5 100644 --- a/libhashkit/common.h +++ b/libhashkit/common.h @@ -6,8 +6,7 @@ * the COPYING file in the parent directory for full text. */ -#ifndef HASHKIT_COMMON_H -#define HASHKIT_COMMON_H +#pragma once #include @@ -32,5 +31,3 @@ int update_continuum(hashkit_st *hashkit); #ifdef __cplusplus } #endif - -#endif /* HASHKIT_COMMON_H */ diff --git a/libhashkit/crc32.c b/libhashkit/crc32.c deleted file mode 100644 index f07958ca..00000000 --- a/libhashkit/crc32.c +++ /dev/null @@ -1,86 +0,0 @@ -/* The crc32 functions and data was originally written by Spencer - * Garrett 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 - -static const uint32_t crc32tab[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -}; - -uint32_t hashkit_crc32(const char *key, size_t key_length, void *context) -{ - uint64_t x; - uint32_t crc= UINT32_MAX; - (void)context; - - for (x= 0; x < key_length; x++) - crc= (crc >> 8) ^ crc32tab[(crc ^ (uint64_t)key[x]) & 0xff]; - - return ((~crc) >> 16) & 0x7fff; -} diff --git a/libhashkit/crc32.cc b/libhashkit/crc32.cc new file mode 100644 index 00000000..f07958ca --- /dev/null +++ b/libhashkit/crc32.cc @@ -0,0 +1,86 @@ +/* The crc32 functions and data was originally written by Spencer + * Garrett 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 + +static const uint32_t crc32tab[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +uint32_t hashkit_crc32(const char *key, size_t key_length, void *context) +{ + uint64_t x; + uint32_t crc= UINT32_MAX; + (void)context; + + for (x= 0; x < key_length; x++) + crc= (crc >> 8) ^ crc32tab[(crc ^ (uint64_t)key[x]) & 0xff]; + + return ((~crc) >> 16) & 0x7fff; +} diff --git a/libhashkit/digest.c b/libhashkit/digest.c deleted file mode 100644 index e1559819..00000000 --- a/libhashkit/digest.c +++ /dev/null @@ -1,60 +0,0 @@ -/* HashKit - * Copyright (C) 2010 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - */ - -#include - -uint32_t hashkit_digest(const hashkit_st *self, const char *key, size_t key_length) -{ - return self->base_hash.function(key, key_length, self->base_hash.context); -} - -uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm) -{ - switch (hash_algorithm) - { - case HASHKIT_HASH_DEFAULT: - return libhashkit_one_at_a_time(key, key_length); - case HASHKIT_HASH_MD5: - return libhashkit_md5(key, key_length); - case HASHKIT_HASH_CRC: - return libhashkit_crc32(key, key_length); - case HASHKIT_HASH_FNV1_64: - return libhashkit_fnv1_64(key, key_length); - case HASHKIT_HASH_FNV1A_64: - return libhashkit_fnv1a_64(key, key_length); - case HASHKIT_HASH_FNV1_32: - return libhashkit_fnv1_32(key, key_length); - case HASHKIT_HASH_FNV1A_32: - return libhashkit_fnv1a_32(key, key_length); - case HASHKIT_HASH_HSIEH: -#ifdef HAVE_HSIEH_HASH - return libhashkit_hsieh(key, key_length); -#else - return 1; -#endif - case HASHKIT_HASH_MURMUR: -#ifdef HAVE_MURMUR_HASH - return libhashkit_murmur(key, key_length); -#else - return 1; -#endif - case HASHKIT_HASH_JENKINS: - return libhashkit_jenkins(key, key_length); - case HASHKIT_HASH_CUSTOM: - case HASHKIT_HASH_MAX: - default: -#ifdef HAVE_DEBUG - fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n"); - fflush(stderr); - assert(0); -#endif - break; - } - - return 1; -} diff --git a/libhashkit/digest.cc b/libhashkit/digest.cc new file mode 100644 index 00000000..e1559819 --- /dev/null +++ b/libhashkit/digest.cc @@ -0,0 +1,60 @@ +/* HashKit + * Copyright (C) 2010 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#include + +uint32_t hashkit_digest(const hashkit_st *self, const char *key, size_t key_length) +{ + return self->base_hash.function(key, key_length, self->base_hash.context); +} + +uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm) +{ + switch (hash_algorithm) + { + case HASHKIT_HASH_DEFAULT: + return libhashkit_one_at_a_time(key, key_length); + case HASHKIT_HASH_MD5: + return libhashkit_md5(key, key_length); + case HASHKIT_HASH_CRC: + return libhashkit_crc32(key, key_length); + case HASHKIT_HASH_FNV1_64: + return libhashkit_fnv1_64(key, key_length); + case HASHKIT_HASH_FNV1A_64: + return libhashkit_fnv1a_64(key, key_length); + case HASHKIT_HASH_FNV1_32: + return libhashkit_fnv1_32(key, key_length); + case HASHKIT_HASH_FNV1A_32: + return libhashkit_fnv1a_32(key, key_length); + case HASHKIT_HASH_HSIEH: +#ifdef HAVE_HSIEH_HASH + return libhashkit_hsieh(key, key_length); +#else + return 1; +#endif + case HASHKIT_HASH_MURMUR: +#ifdef HAVE_MURMUR_HASH + return libhashkit_murmur(key, key_length); +#else + return 1; +#endif + case HASHKIT_HASH_JENKINS: + return libhashkit_jenkins(key, key_length); + case HASHKIT_HASH_CUSTOM: + case HASHKIT_HASH_MAX: + default: +#ifdef HAVE_DEBUG + fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n"); + fflush(stderr); + assert(0); +#endif + break; + } + + return 1; +} diff --git a/libhashkit/fnv.c b/libhashkit/fnv.c deleted file mode 100644 index fffb94a4..00000000 --- a/libhashkit/fnv.c +++ /dev/null @@ -1,75 +0,0 @@ -/* HashKit - * Copyright (C) 2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - */ - -#include - -/* FNV hash'es lifted from Dustin Sallings work */ -static uint64_t FNV_64_INIT= UINT64_C(0xcbf29ce484222325); -static uint64_t FNV_64_PRIME= UINT64_C(0x100000001b3); -static uint32_t FNV_32_INIT= 2166136261UL; -static uint32_t FNV_32_PRIME= 16777619; - -uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *context) -{ - /* Thanks to pierre@demartines.com for the pointer */ - uint64_t hash= FNV_64_INIT; - (void)context; - - for (size_t x= 0; x < key_length; x++) - { - hash *= FNV_64_PRIME; - hash ^= (uint64_t)key[x]; - } - - return (uint32_t)hash; -} - -uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *context) -{ - uint32_t hash= (uint32_t) FNV_64_INIT; - (void)context; - - for (size_t x= 0; x < key_length; x++) - { - uint32_t val= (uint32_t)key[x]; - hash ^= val; - hash *= (uint32_t) FNV_64_PRIME; - } - - return hash; -} - -uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context) -{ - uint32_t hash= FNV_32_INIT; - (void)context; - - for (size_t x= 0; x < key_length; x++) - { - uint32_t val= (uint32_t)key[x]; - hash *= FNV_32_PRIME; - hash ^= val; - } - - return hash; -} - -uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context) -{ - uint32_t hash= FNV_32_INIT; - (void)context; - - for (size_t x= 0; x < key_length; x++) - { - uint32_t val= (uint32_t)key[x]; - hash ^= val; - hash *= FNV_32_PRIME; - } - - return hash; -} diff --git a/libhashkit/fnv.cc b/libhashkit/fnv.cc new file mode 100644 index 00000000..fffb94a4 --- /dev/null +++ b/libhashkit/fnv.cc @@ -0,0 +1,75 @@ +/* HashKit + * Copyright (C) 2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#include + +/* FNV hash'es lifted from Dustin Sallings work */ +static uint64_t FNV_64_INIT= UINT64_C(0xcbf29ce484222325); +static uint64_t FNV_64_PRIME= UINT64_C(0x100000001b3); +static uint32_t FNV_32_INIT= 2166136261UL; +static uint32_t FNV_32_PRIME= 16777619; + +uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *context) +{ + /* Thanks to pierre@demartines.com for the pointer */ + uint64_t hash= FNV_64_INIT; + (void)context; + + for (size_t x= 0; x < key_length; x++) + { + hash *= FNV_64_PRIME; + hash ^= (uint64_t)key[x]; + } + + return (uint32_t)hash; +} + +uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *context) +{ + uint32_t hash= (uint32_t) FNV_64_INIT; + (void)context; + + for (size_t x= 0; x < key_length; x++) + { + uint32_t val= (uint32_t)key[x]; + hash ^= val; + hash *= (uint32_t) FNV_64_PRIME; + } + + return hash; +} + +uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context) +{ + uint32_t hash= FNV_32_INIT; + (void)context; + + for (size_t x= 0; x < key_length; x++) + { + uint32_t val= (uint32_t)key[x]; + hash *= FNV_32_PRIME; + hash ^= val; + } + + return hash; +} + +uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context) +{ + uint32_t hash= FNV_32_INIT; + (void)context; + + for (size_t x= 0; x < key_length; x++) + { + uint32_t val= (uint32_t)key[x]; + hash ^= val; + hash *= FNV_32_PRIME; + } + + return hash; +} diff --git a/libhashkit/function.c b/libhashkit/function.c deleted file mode 100644 index 3560abd7..00000000 --- a/libhashkit/function.c +++ /dev/null @@ -1,156 +0,0 @@ -/* HashKit - * Copyright (C) 2010 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - */ - -#include - -static hashkit_return_t _set_function(struct hashkit_function_st *self, hashkit_hash_algorithm_t hash_algorithm) -{ - switch (hash_algorithm) - { - case HASHKIT_HASH_DEFAULT: - self->function= hashkit_one_at_a_time; - break; - case HASHKIT_HASH_MD5: - self->function= hashkit_md5; - break; - case HASHKIT_HASH_CRC: - self->function= hashkit_crc32; - break; - case HASHKIT_HASH_FNV1_64: - self->function= hashkit_fnv1_64; - break; - case HASHKIT_HASH_FNV1A_64: - self->function= hashkit_fnv1a_64; - break; - case HASHKIT_HASH_FNV1_32: - self->function= hashkit_fnv1_32; - break; - case HASHKIT_HASH_FNV1A_32: - self->function= hashkit_fnv1a_32; - break; - case HASHKIT_HASH_HSIEH: -#ifdef HAVE_HSIEH_HASH - self->function= hashkit_hsieh; - break; -#else - return HASHKIT_FAILURE; -#endif - case HASHKIT_HASH_MURMUR: -#ifdef HAVE_MURMUR_HASH - self->function= hashkit_murmur; - break; -#else - return HASHKIT_FAILURE; -#endif - case HASHKIT_HASH_JENKINS: - self->function= hashkit_jenkins; - break; - case HASHKIT_HASH_CUSTOM: - return HASHKIT_INVALID_ARGUMENT; - case HASHKIT_HASH_MAX: - default: - return HASHKIT_INVALID_HASH; - } - - self->context= NULL; - - return HASHKIT_SUCCESS; -} - -hashkit_return_t hashkit_set_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm) -{ - return _set_function(&self->base_hash, hash_algorithm); -} - -hashkit_return_t hashkit_set_distribution_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm) -{ - return _set_function(&self->distribution_hash, hash_algorithm); -} - -static hashkit_return_t _set_custom_function(struct hashkit_function_st *self, hashkit_hash_fn function, void *context) -{ - if (function) - { - self->function= function; - self->context= context; - - return HASHKIT_SUCCESS; - } - - return HASHKIT_FAILURE; -} - -hashkit_return_t hashkit_set_custom_function(hashkit_st *self, hashkit_hash_fn function, void *context) -{ - return _set_custom_function(&self->base_hash, function, context); -} - -hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context) -{ - return _set_custom_function(&self->distribution_hash, function, context); -} - -static hashkit_hash_algorithm_t get_function_type(const hashkit_hash_fn function) -{ - if (function == hashkit_one_at_a_time) - { - return HASHKIT_HASH_DEFAULT; - } - else if (function == hashkit_md5) - { - return HASHKIT_HASH_MD5; - } - else if (function == hashkit_crc32) - { - return HASHKIT_HASH_CRC; - } - else if (function == hashkit_fnv1_64) - { - return HASHKIT_HASH_FNV1_64; - } - else if (function == hashkit_fnv1a_64) - { - return HASHKIT_HASH_FNV1A_64; - } - else if (function == hashkit_fnv1_32) - { - return HASHKIT_HASH_FNV1_32; - } - else if (function == hashkit_fnv1a_32) - { - return HASHKIT_HASH_FNV1A_32; - } -#ifdef HAVE_HSIEH_HASH - else if (function == hashkit_hsieh) - { - return HASHKIT_HASH_HSIEH; - } -#endif -#ifdef HAVE_MURMUR_HASH - else if (function == hashkit_murmur) - { - return HASHKIT_HASH_MURMUR; - } -#endif - else if (function == hashkit_jenkins) - { - return HASHKIT_HASH_JENKINS; - } - - return HASHKIT_HASH_CUSTOM; -} - -hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *self) -{ - return get_function_type(self->base_hash.function); -} - -hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self) -{ - return get_function_type(self->distribution_hash.function); -} diff --git a/libhashkit/function.cc b/libhashkit/function.cc new file mode 100644 index 00000000..7ac91007 --- /dev/null +++ b/libhashkit/function.cc @@ -0,0 +1,156 @@ +/* HashKit + * Copyright (C) 2010 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#include + +static hashkit_return_t _set_function(struct hashkit_st::hashkit_function_st *self, hashkit_hash_algorithm_t hash_algorithm) +{ + switch (hash_algorithm) + { + case HASHKIT_HASH_DEFAULT: + self->function= hashkit_one_at_a_time; + break; + case HASHKIT_HASH_MD5: + self->function= hashkit_md5; + break; + case HASHKIT_HASH_CRC: + self->function= hashkit_crc32; + break; + case HASHKIT_HASH_FNV1_64: + self->function= hashkit_fnv1_64; + break; + case HASHKIT_HASH_FNV1A_64: + self->function= hashkit_fnv1a_64; + break; + case HASHKIT_HASH_FNV1_32: + self->function= hashkit_fnv1_32; + break; + case HASHKIT_HASH_FNV1A_32: + self->function= hashkit_fnv1a_32; + break; + case HASHKIT_HASH_HSIEH: +#ifdef HAVE_HSIEH_HASH + self->function= hashkit_hsieh; + break; +#else + return HASHKIT_FAILURE; +#endif + case HASHKIT_HASH_MURMUR: +#ifdef HAVE_MURMUR_HASH + self->function= hashkit_murmur; + break; +#else + return HASHKIT_FAILURE; +#endif + case HASHKIT_HASH_JENKINS: + self->function= hashkit_jenkins; + break; + case HASHKIT_HASH_CUSTOM: + return HASHKIT_INVALID_ARGUMENT; + case HASHKIT_HASH_MAX: + default: + return HASHKIT_INVALID_HASH; + } + + self->context= NULL; + + return HASHKIT_SUCCESS; +} + +hashkit_return_t hashkit_set_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm) +{ + return _set_function(&self->base_hash, hash_algorithm); +} + +hashkit_return_t hashkit_set_distribution_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm) +{ + return _set_function(&self->distribution_hash, hash_algorithm); +} + +static hashkit_return_t _set_custom_function(struct hashkit_st::hashkit_function_st *self, hashkit_hash_fn function, void *context) +{ + if (function) + { + self->function= function; + self->context= context; + + return HASHKIT_SUCCESS; + } + + return HASHKIT_FAILURE; +} + +hashkit_return_t hashkit_set_custom_function(hashkit_st *self, hashkit_hash_fn function, void *context) +{ + return _set_custom_function(&self->base_hash, function, context); +} + +hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context) +{ + return _set_custom_function(&self->distribution_hash, function, context); +} + +static hashkit_hash_algorithm_t get_function_type(const hashkit_hash_fn function) +{ + if (function == hashkit_one_at_a_time) + { + return HASHKIT_HASH_DEFAULT; + } + else if (function == hashkit_md5) + { + return HASHKIT_HASH_MD5; + } + else if (function == hashkit_crc32) + { + return HASHKIT_HASH_CRC; + } + else if (function == hashkit_fnv1_64) + { + return HASHKIT_HASH_FNV1_64; + } + else if (function == hashkit_fnv1a_64) + { + return HASHKIT_HASH_FNV1A_64; + } + else if (function == hashkit_fnv1_32) + { + return HASHKIT_HASH_FNV1_32; + } + else if (function == hashkit_fnv1a_32) + { + return HASHKIT_HASH_FNV1A_32; + } +#ifdef HAVE_HSIEH_HASH + else if (function == hashkit_hsieh) + { + return HASHKIT_HASH_HSIEH; + } +#endif +#ifdef HAVE_MURMUR_HASH + else if (function == hashkit_murmur) + { + return HASHKIT_HASH_MURMUR; + } +#endif + else if (function == hashkit_jenkins) + { + return HASHKIT_HASH_JENKINS; + } + + return HASHKIT_HASH_CUSTOM; +} + +hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *self) +{ + return get_function_type(self->base_hash.function); +} + +hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self) +{ + return get_function_type(self->distribution_hash.function); +} diff --git a/libhashkit/hashkit.c b/libhashkit/hashkit.c deleted file mode 100644 index 7214c144..00000000 --- a/libhashkit/hashkit.c +++ /dev/null @@ -1,108 +0,0 @@ -/* HashKit - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - */ - -#include - -static const hashkit_st global_default_hash= { - .base_hash= { - .function= hashkit_one_at_a_time, - .context= NULL - }, - .flags= { - .is_base_same_distributed= false, - } -}; - -static inline bool _hashkit_init(hashkit_st *self) -{ - self->base_hash= global_default_hash.base_hash; - self->distribution_hash= global_default_hash.base_hash; - self->flags= global_default_hash.flags; - - return true; -} - -static inline hashkit_st *_hashkit_create(hashkit_st *self) -{ - if (self == NULL) - { - self= (hashkit_st *)malloc(sizeof(hashkit_st)); - if (self == NULL) - { - return NULL; - } - - self->options.is_allocated= true; - } - else - { - self->options.is_allocated= false; - } - - return self; -} - -hashkit_st *hashkit_create(hashkit_st *self) -{ - self= _hashkit_create(self); - if (! self) - return self; - - if (! _hashkit_init(self)) - { - hashkit_free(self); - } - - return self; -} - - -void hashkit_free(hashkit_st *self) -{ - if (hashkit_is_allocated(self)) - { - free(self); - } -} - -hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source) -{ - if (source == NULL) - { - return hashkit_create(destination); - } - - /* new_clone will be a pointer to destination */ - destination= _hashkit_create(destination); - - // Should only happen on allocation failure. - if (destination == NULL) - { - return NULL; - } - - destination->base_hash= source->base_hash; - destination->distribution_hash= source->distribution_hash; - destination->flags= source->flags; - - return destination; -} - -bool hashkit_compare(const hashkit_st *first, const hashkit_st *second) -{ - if (first->base_hash.function == second->base_hash.function && - first->base_hash.context == second->base_hash.context && - first->distribution_hash.function == second->distribution_hash.function && - first->distribution_hash.context == second->distribution_hash.context && - first->flags.is_base_same_distributed == second->flags.is_base_same_distributed) - { - return true; - } - - return false; -} diff --git a/libhashkit/hashkit.cc b/libhashkit/hashkit.cc new file mode 100644 index 00000000..201a6dff --- /dev/null +++ b/libhashkit/hashkit.cc @@ -0,0 +1,99 @@ +/* HashKit + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#include + +static inline bool _hashkit_init(hashkit_st *self) +{ + self->base_hash.function= hashkit_one_at_a_time; + self->base_hash.context= NULL; + self->distribution_hash.function= self->base_hash.function; + self->flags.is_base_same_distributed= false; + + return true; +} + +static inline hashkit_st *_hashkit_create(hashkit_st *self) +{ + if (self == NULL) + { + self= (hashkit_st *)malloc(sizeof(hashkit_st)); + if (self == NULL) + { + return NULL; + } + + self->options.is_allocated= true; + } + else + { + self->options.is_allocated= false; + } + + return self; +} + +hashkit_st *hashkit_create(hashkit_st *self) +{ + self= _hashkit_create(self); + if (! self) + return self; + + if (! _hashkit_init(self)) + { + hashkit_free(self); + } + + return self; +} + + +void hashkit_free(hashkit_st *self) +{ + if (hashkit_is_allocated(self)) + { + free(self); + } +} + +hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source) +{ + if (source == NULL) + { + return hashkit_create(destination); + } + + /* new_clone will be a pointer to destination */ + destination= _hashkit_create(destination); + + // Should only happen on allocation failure. + if (destination == NULL) + { + return NULL; + } + + destination->base_hash= source->base_hash; + destination->distribution_hash= source->distribution_hash; + destination->flags= source->flags; + + return destination; +} + +bool hashkit_compare(const hashkit_st *first, const hashkit_st *second) +{ + if (first->base_hash.function == second->base_hash.function && + first->base_hash.context == second->base_hash.context && + first->distribution_hash.function == second->distribution_hash.function && + first->distribution_hash.context == second->distribution_hash.context && + first->flags.is_base_same_distributed == second->flags.is_base_same_distributed) + { + return true; + } + + return false; +} diff --git a/libhashkit/hashkit.h b/libhashkit/hashkit.h index 2d8ad3a2..9b8761f1 100644 --- a/libhashkit/hashkit.h +++ b/libhashkit/hashkit.h @@ -1,13 +1,42 @@ -/* HashKit - * Copyright (C) 2009-2010 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * HashKit library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2009-2010 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. */ -#ifndef HASHKIT_H -#define HASHKIT_H + +#pragma once #if !defined(__cplusplus) @@ -15,6 +44,7 @@ #endif #include #include + #include #include #include @@ -25,29 +55,6 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif - -HASHKIT_API -hashkit_st *hashkit_create(hashkit_st *hash); - -HASHKIT_API -hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr); - -HASHKIT_API -bool hashkit_compare(const hashkit_st *first, const hashkit_st *second); - -HASHKIT_API -void hashkit_free(hashkit_st *hash); - -#define hashkit_is_allocated(__object) ((__object)->options.is_allocated) -#define hashkit_is_initialized(__object) ((__object)->options.is_initialized) - -#ifdef __cplusplus -} // extern "C" -#endif - struct hashkit_st { struct hashkit_function_st { @@ -65,65 +72,24 @@ struct hashkit_st }; #ifdef __cplusplus +extern "C" { +#endif -#include - -class Hashkit { - -public: - - Hashkit() - { - hashkit_create(&self); - } - - Hashkit(const Hashkit& source) - { - hashkit_clone(&self, &source.self); - } - - Hashkit& operator=(const Hashkit& source) - { - hashkit_free(&self); - hashkit_clone(&self, &source.self); - - return *this; - } - - friend bool operator==(const Hashkit &left, const Hashkit &right) - { - return hashkit_compare(&left.self, &right.self); - } - - uint32_t digest(std::string& str) - { - return hashkit_digest(&self, str.c_str(), str.length()); - } +HASHKIT_API +hashkit_st *hashkit_create(hashkit_st *hash); - uint32_t digest(const char *key, size_t key_length) - { - return hashkit_digest(&self, key, key_length); - } +HASHKIT_API +hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr); - hashkit_return_t set_function(hashkit_hash_algorithm_t hash_algorithm) - { - return hashkit_set_function(&self, hash_algorithm); - } +HASHKIT_API +bool hashkit_compare(const hashkit_st *first, const hashkit_st *second); - hashkit_return_t set_distribution_function(hashkit_hash_algorithm_t hash_algorithm) - { - return hashkit_set_function(&self, hash_algorithm); - } +HASHKIT_API +void hashkit_free(hashkit_st *hash); - ~Hashkit() - { - hashkit_free(&self); - } -private: +#define hashkit_is_allocated(__object) ((__object)->options.is_allocated) +#define hashkit_is_initialized(__object) ((__object)->options.is_initialized) - hashkit_st self; -}; +#ifdef __cplusplus +} // extern "C" #endif - - -#endif /* HASHKIT_H */ diff --git a/libhashkit/hashkit.hpp b/libhashkit/hashkit.hpp new file mode 100644 index 00000000..7ead63d0 --- /dev/null +++ b/libhashkit/hashkit.hpp @@ -0,0 +1,97 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#pragma once + +#include +#include + +class Hashkit { + +public: + + Hashkit() + { + hashkit_create(&self); + } + + Hashkit(const Hashkit& source) + { + hashkit_clone(&self, &source.self); + } + + Hashkit& operator=(const Hashkit& source) + { + hashkit_free(&self); + hashkit_clone(&self, &source.self); + + return *this; + } + + friend bool operator==(const Hashkit &left, const Hashkit &right) + { + return hashkit_compare(&left.self, &right.self); + } + + uint32_t digest(std::string& str) + { + return hashkit_digest(&self, str.c_str(), str.length()); + } + + uint32_t digest(const char *key, size_t key_length) + { + return hashkit_digest(&self, key, key_length); + } + + hashkit_return_t set_function(hashkit_hash_algorithm_t hash_algorithm) + { + return hashkit_set_function(&self, hash_algorithm); + } + + hashkit_return_t set_distribution_function(hashkit_hash_algorithm_t hash_algorithm) + { + return hashkit_set_function(&self, hash_algorithm); + } + + ~Hashkit() + { + hashkit_free(&self); + } +private: + + hashkit_st self; +}; diff --git a/libhashkit/hsieh.c b/libhashkit/hsieh.c deleted file mode 100644 index 35a2e209..00000000 --- a/libhashkit/hsieh.c +++ /dev/null @@ -1,70 +0,0 @@ -/* By Paul Hsieh (C) 2004, 2005. Covered under the Paul Hsieh - * derivative license. - * See: http://www.azillionmonkeys.com/qed/weblicense.html for license - * details. - * http://www.azillionmonkeys.com/qed/hash.html -*/ - -#include - -#undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) -#define get16bits(d) (*((const uint16_t *) (d))) -#endif - -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ - +(uint32_t)(((const uint8_t *)(d))[0]) ) -#endif - -uint32_t hashkit_hsieh(const char *key, size_t key_length, void *context __attribute__((unused))) -{ - uint32_t hash = 0, tmp; - int rem; - - if (key_length <= 0 || key == NULL) - return 0; - - rem = key_length & 3; - key_length >>= 2; - - /* Main loop */ - for (;key_length > 0; key_length--) - { - hash += get16bits (key); - tmp = (get16bits (key+2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - key += 2*sizeof (uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) - { - case 3: hash += get16bits (key); - hash ^= hash << 16; - hash ^= (uint32_t)key[sizeof (uint16_t)] << 18; - hash += hash >> 11; - break; - case 2: hash += get16bits (key); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += (unsigned char)(*key); - hash ^= hash << 10; - hash += hash >> 1; - default: - break; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - diff --git a/libhashkit/hsieh.cc b/libhashkit/hsieh.cc new file mode 100644 index 00000000..35a2e209 --- /dev/null +++ b/libhashkit/hsieh.cc @@ -0,0 +1,70 @@ +/* By Paul Hsieh (C) 2004, 2005. Covered under the Paul Hsieh + * derivative license. + * See: http://www.azillionmonkeys.com/qed/weblicense.html for license + * details. + * http://www.azillionmonkeys.com/qed/hash.html +*/ + +#include + +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif + +uint32_t hashkit_hsieh(const char *key, size_t key_length, void *context __attribute__((unused))) +{ + uint32_t hash = 0, tmp; + int rem; + + if (key_length <= 0 || key == NULL) + return 0; + + rem = key_length & 3; + key_length >>= 2; + + /* Main loop */ + for (;key_length > 0; key_length--) + { + hash += get16bits (key); + tmp = (get16bits (key+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + key += 2*sizeof (uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) + { + case 3: hash += get16bits (key); + hash ^= hash << 16; + hash ^= (uint32_t)key[sizeof (uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: hash += get16bits (key); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += (unsigned char)(*key); + hash ^= hash << 10; + hash += hash >> 1; + default: + break; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + diff --git a/libhashkit/include.am b/libhashkit/include.am index 12575dfb..43300585 100644 --- a/libhashkit/include.am +++ b/libhashkit/include.am @@ -22,6 +22,7 @@ nobase_include_HEADERS+= \ libhashkit/digest.h \ libhashkit/function.h \ libhashkit/hashkit.h \ + libhashkit/hashkit.hpp \ libhashkit/strerror.h \ libhashkit/str_algorithm.h \ libhashkit/types.h \ @@ -31,31 +32,31 @@ noinst_HEADERS+= \ libhashkit/common.h libhashkit_libhashkit_la_SOURCES= \ - libhashkit/algorithm.c \ - libhashkit/behavior.c \ - libhashkit/crc32.c \ - libhashkit/digest.c \ - libhashkit/fnv.c \ - libhashkit/function.c \ - libhashkit/hashkit.c \ - libhashkit/jenkins.c \ - libhashkit/ketama.c \ - libhashkit/md5.c \ - libhashkit/one_at_a_time.c \ - libhashkit/str_algorithm.c \ - libhashkit/strerror.c + libhashkit/algorithm.cc \ + libhashkit/behavior.cc \ + libhashkit/crc32.cc \ + libhashkit/digest.cc \ + libhashkit/fnv.cc \ + libhashkit/function.cc \ + libhashkit/hashkit.cc \ + libhashkit/jenkins.cc \ + libhashkit/ketama.cc \ + libhashkit/md5.cc \ + libhashkit/one_at_a_time.cc \ + libhashkit/str_algorithm.cc \ + libhashkit/strerror.cc if INCLUDE_HSIEH_SRC -libhashkit_libhashkit_la_SOURCES+= libhashkit/hsieh.c +libhashkit_libhashkit_la_SOURCES+= libhashkit/hsieh.cc endif if INCLUDE_MURMUR_SRC -libhashkit_libhashkit_la_SOURCES+= libhashkit/murmur.c +libhashkit_libhashkit_la_SOURCES+= libhashkit/murmur.cc endif -libhashkit_libhashkit_la_CFLAGS= \ - ${AM_CFLAGS} \ - -DBUILDING_HASHKIT +libhashkit_libhashkit_la_CXXFLAGS= \ + ${AM_CXXFLAGS} \ + -DBUILDING_HASHKIT libhashkit_libhashkit_la_LDFLAGS= \ $(LIBM) \ diff --git a/libhashkit/jenkins.c b/libhashkit/jenkins.c deleted file mode 100644 index c2001cb5..00000000 --- a/libhashkit/jenkins.c +++ /dev/null @@ -1,214 +0,0 @@ -/* -* -* By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this -* code any way you wish, private, educational, or commercial. It's free. -* Use for hash table lookup, or anything where one collision in 2^^32 is -* acceptable. Do NOT use for cryptographic purposes. -* http://burtleburtle.net/bob/hash/index.html -* -* Modified by Brian Pontz for libmemcached -* TODO: -* Add big endian support -*/ - -#include - -#define hashsize(n) ((uint32_t)1<<(n)) -#define hashmask(n) (hashsize(n)-1) -#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) - -#define mix(a,b,c) \ -{ \ - a -= c; a ^= rot(c, 4); c += b; \ - b -= a; b ^= rot(a, 6); a += c; \ - c -= b; c ^= rot(b, 8); b += a; \ - a -= c; a ^= rot(c,16); c += b; \ - b -= a; b ^= rot(a,19); a += c; \ - c -= b; c ^= rot(b, 4); b += a; \ -} - -#define final(a,b,c) \ -{ \ - c ^= b; c -= rot(b,14); \ - a ^= c; a -= rot(c,11); \ - b ^= a; b -= rot(a,25); \ - c ^= b; c -= rot(b,16); \ - a ^= c; a -= rot(c,4); \ - b ^= a; b -= rot(a,14); \ - c ^= b; c -= rot(b,24); \ -} - -#define JENKINS_INITVAL 13 - -/* -jenkins_hash() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - length : the length of the key, counting by bytes - initval : can be any 4-byte value -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Two keys differing by one or two bits will have -totally different hash values. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. -*/ - -uint32_t hashkit_jenkins(const char *key, size_t length, void *context) -{ - uint32_t a,b,c; /* internal state */ - union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ - (void)context; - - /* Set up the internal state */ - a = b = c = 0xdeadbeef + ((uint32_t)length) + JENKINS_INITVAL; - - u.ptr = key; -#ifndef WORDS_BIGENDIAN - if ((u.i & 0x3) == 0) - { - const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ - - /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 12; - k += 3; - } - - /*----------------------------- handle the last (probably partial) block */ - /* - * "k[2]&0xffffff" actually reads beyond the end of the string, but - * then masks off the part it's not allowed to read. Because the - * string is aligned, the masked-off tail is in the same word as the - * rest of the string. Every machine with memory protection I've seen - * does it on word boundaries, so is OK with this. But VALGRIND will - * still catch it and complain. The masking trick does make the hash - * noticably faster for short strings (like English words). - */ - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; - case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; - case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=k[1]&0xffffff; a+=k[0]; break; - case 6 : b+=k[1]&0xffff; a+=k[0]; break; - case 5 : b+=k[1]&0xff; a+=k[0]; break; - case 4 : a+=k[0]; break; - case 3 : a+=k[0]&0xffffff; break; - case 2 : a+=k[0]&0xffff; break; - case 1 : a+=k[0]&0xff; break; - case 0 : return c; /* zero length strings require no mixing */ - default: return c; - } - - } - else if ((u.i & 0x1) == 0) - { - const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ - const uint8_t *k8; - - /*--------------- all but last block: aligned reads and different mixing */ - while (length > 12) - { - a += k[0] + (((uint32_t)k[1])<<16); - b += k[2] + (((uint32_t)k[3])<<16); - c += k[4] + (((uint32_t)k[5])<<16); - mix(a,b,c); - length -= 12; - k += 6; - } - - /*----------------------------- handle the last (probably partial) block */ - k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[4]+(((uint32_t)k[5])<<16); - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=k[4]; - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=k[2]; - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=k[0]; - break; - case 1 : a+=k8[0]; - break; - case 0 : return c; /* zero length requires no mixing */ - default: return c; - } - - } - else - { /* need to read the key one byte at a time */ -#endif /* little endian */ - const uint8_t *k = (const uint8_t *)key; - - /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - a += ((uint32_t)k[1])<<8; - a += ((uint32_t)k[2])<<16; - a += ((uint32_t)k[3])<<24; - b += k[4]; - b += ((uint32_t)k[5])<<8; - b += ((uint32_t)k[6])<<16; - b += ((uint32_t)k[7])<<24; - c += k[8]; - c += ((uint32_t)k[9])<<8; - c += ((uint32_t)k[10])<<16; - c += ((uint32_t)k[11])<<24; - mix(a,b,c); - length -= 12; - k += 12; - } - - /*-------------------------------- last block: affect all 32 bits of (c) */ - switch(length) /* all the case statements fall through */ - { - case 12: c+=((uint32_t)k[11])<<24; - case 11: c+=((uint32_t)k[10])<<16; - case 10: c+=((uint32_t)k[9])<<8; - case 9 : c+=k[8]; - case 8 : b+=((uint32_t)k[7])<<24; - case 7 : b+=((uint32_t)k[6])<<16; - case 6 : b+=((uint32_t)k[5])<<8; - case 5 : b+=k[4]; - case 4 : a+=((uint32_t)k[3])<<24; - case 3 : a+=((uint32_t)k[2])<<16; - case 2 : a+=((uint32_t)k[1])<<8; - case 1 : a+=k[0]; - break; - case 0 : return c; - default : return c; - } -#ifndef WORDS_BIGENDIAN - } -#endif - - final(a,b,c); - return c; -} diff --git a/libhashkit/jenkins.cc b/libhashkit/jenkins.cc new file mode 100644 index 00000000..c2001cb5 --- /dev/null +++ b/libhashkit/jenkins.cc @@ -0,0 +1,214 @@ +/* +* +* By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this +* code any way you wish, private, educational, or commercial. It's free. +* Use for hash table lookup, or anything where one collision in 2^^32 is +* acceptable. Do NOT use for cryptographic purposes. +* http://burtleburtle.net/bob/hash/index.html +* +* Modified by Brian Pontz for libmemcached +* TODO: +* Add big endian support +*/ + +#include + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +#define JENKINS_INITVAL 13 + +/* +jenkins_hash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. +*/ + +uint32_t hashkit_jenkins(const char *key, size_t length, void *context) +{ + uint32_t a,b,c; /* internal state */ + union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ + (void)context; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + JENKINS_INITVAL; + + u.ptr = key; +#ifndef WORDS_BIGENDIAN + if ((u.i & 0x3) == 0) + { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + default: return c; + } + + } + else if ((u.i & 0x1) == 0) + { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + default: return c; + } + + } + else + { /* need to read the key one byte at a time */ +#endif /* little endian */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + default : return c; + } +#ifndef WORDS_BIGENDIAN + } +#endif + + final(a,b,c); + return c; +} diff --git a/libhashkit/ketama.c b/libhashkit/ketama.c deleted file mode 100644 index 45052c22..00000000 --- a/libhashkit/ketama.c +++ /dev/null @@ -1,164 +0,0 @@ -/* HashKit - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - */ - -#include -#include - -#if 0 -static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment) -{ - unsigned char results[16]; - - md5_signature((unsigned char*)key, key_length, results); - return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24) - | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16) - | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8) - | (results[0 + alignment * 4] & 0xFF); -} - -static int continuum_points_cmp(const void *t1, const void *t2) -{ - hashkit_continuum_point_st *ct1= (hashkit_continuum_point_st *)t1; - hashkit_continuum_point_st *ct2= (hashkit_continuum_point_st *)t2; - - if (ct1->value == ct2->value) - return 0; - else if (ct1->value > ct2->value) - return 1; - else - return -1; -} - -int update_continuum(hashkit_st *hashkit) -{ - uint32_t count; - uint32_t continuum_index= 0; - uint32_t value; - uint32_t points_index; - uint32_t points_count= 0; - uint32_t points_per_server; - uint32_t points_per_hash; - uint64_t total_weight= 0; - uint32_t live_servers; - uint8_t *context; - - if (hashkit->active_fn != NULL || hashkit->weight_fn != NULL) - { - live_servers= 0; - - for (count= 0, context= hashkit->list; count < hashkit->list_size; - count++, context+= hashkit->context_size) - { - if (hashkit->active_fn != NULL) - { - if (hashkit->active_fn(context)) - live_servers++; - else - continue; - } - - if (hashkit->weight_fn != NULL) - total_weight+= hashkit->weight_fn(context); - } - } - - if (hashkit->active_fn == NULL) - live_servers= (uint32_t)hashkit->list_size; - - if (live_servers == 0) - return 0; - - if (hashkit->weight_fn == NULL) - { - points_per_server= HASHKIT_POINTS_PER_NODE; - points_per_hash= 1; - } - else - { - points_per_server= HASHKIT_POINTS_PER_NODE_WEIGHTED; - points_per_hash= 4; - } - - if (live_servers > hashkit->continuum_count) - { - hashkit_continuum_point_st *new_continuum; - - new_continuum= realloc(hashkit->continuum, - sizeof(hashkit_continuum_point_st) * - (live_servers + HASHKIT_CONTINUUM_ADDITION) * - points_per_server); - - if (new_continuum == NULL) - return ENOMEM; - - hashkit->continuum= new_continuum; - hashkit->continuum_count= live_servers + HASHKIT_CONTINUUM_ADDITION; - } - - for (count= 0, context= hashkit->list; count < hashkit->list_size; - count++, context+= hashkit->context_size) - { - if (hashkit->active_fn != NULL && hashkit->active_fn(context) == false) - continue; - - if (hashkit->weight_fn != NULL) - { - float pct = (float)hashkit->weight_fn(context) / (float)total_weight; - points_per_server= (uint32_t) ((floorf((float) (pct * HASHKIT_POINTS_PER_NODE_WEIGHTED / 4 * (float)live_servers + 0.0000000001))) * 4); - } - - for (points_index= 0; - points_index < points_per_server / points_per_hash; - points_index++) - { - char sort_host[HASHKIT_CONTINUUM_KEY_SIZE]= ""; - size_t sort_host_length; - - if (hashkit->continuum_key_fn == NULL) - { - sort_host_length= (size_t) snprintf(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, "%u", - points_index); - } - else - { - sort_host_length= hashkit->continuum_key_fn(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, - points_index, context); - } - - if (hashkit->weight_fn == NULL) - { - if (hashkit->continuum_hash_fn == NULL) - value= hashkit_default(sort_host, sort_host_length); - else - value= hashkit->continuum_hash_fn(sort_host, sort_host_length); - - hashkit->continuum[continuum_index].index= count; - hashkit->continuum[continuum_index++].value= value; - } - else - { - unsigned int i; - for (i = 0; i < points_per_hash; i++) - { - value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i); - hashkit->continuum[continuum_index].index= count; - hashkit->continuum[continuum_index++].value= value; - } - } - } - - points_count+= points_per_server; - } - - hashkit->continuum_points_count= points_count; - qsort(hashkit->continuum, hashkit->continuum_points_count, sizeof(hashkit_continuum_point_st), - continuum_points_cmp); - - return 0; -} -#endif diff --git a/libhashkit/ketama.cc b/libhashkit/ketama.cc new file mode 100644 index 00000000..45052c22 --- /dev/null +++ b/libhashkit/ketama.cc @@ -0,0 +1,164 @@ +/* HashKit + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#include +#include + +#if 0 +static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment) +{ + unsigned char results[16]; + + md5_signature((unsigned char*)key, key_length, results); + return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24) + | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16) + | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8) + | (results[0 + alignment * 4] & 0xFF); +} + +static int continuum_points_cmp(const void *t1, const void *t2) +{ + hashkit_continuum_point_st *ct1= (hashkit_continuum_point_st *)t1; + hashkit_continuum_point_st *ct2= (hashkit_continuum_point_st *)t2; + + if (ct1->value == ct2->value) + return 0; + else if (ct1->value > ct2->value) + return 1; + else + return -1; +} + +int update_continuum(hashkit_st *hashkit) +{ + uint32_t count; + uint32_t continuum_index= 0; + uint32_t value; + uint32_t points_index; + uint32_t points_count= 0; + uint32_t points_per_server; + uint32_t points_per_hash; + uint64_t total_weight= 0; + uint32_t live_servers; + uint8_t *context; + + if (hashkit->active_fn != NULL || hashkit->weight_fn != NULL) + { + live_servers= 0; + + for (count= 0, context= hashkit->list; count < hashkit->list_size; + count++, context+= hashkit->context_size) + { + if (hashkit->active_fn != NULL) + { + if (hashkit->active_fn(context)) + live_servers++; + else + continue; + } + + if (hashkit->weight_fn != NULL) + total_weight+= hashkit->weight_fn(context); + } + } + + if (hashkit->active_fn == NULL) + live_servers= (uint32_t)hashkit->list_size; + + if (live_servers == 0) + return 0; + + if (hashkit->weight_fn == NULL) + { + points_per_server= HASHKIT_POINTS_PER_NODE; + points_per_hash= 1; + } + else + { + points_per_server= HASHKIT_POINTS_PER_NODE_WEIGHTED; + points_per_hash= 4; + } + + if (live_servers > hashkit->continuum_count) + { + hashkit_continuum_point_st *new_continuum; + + new_continuum= realloc(hashkit->continuum, + sizeof(hashkit_continuum_point_st) * + (live_servers + HASHKIT_CONTINUUM_ADDITION) * + points_per_server); + + if (new_continuum == NULL) + return ENOMEM; + + hashkit->continuum= new_continuum; + hashkit->continuum_count= live_servers + HASHKIT_CONTINUUM_ADDITION; + } + + for (count= 0, context= hashkit->list; count < hashkit->list_size; + count++, context+= hashkit->context_size) + { + if (hashkit->active_fn != NULL && hashkit->active_fn(context) == false) + continue; + + if (hashkit->weight_fn != NULL) + { + float pct = (float)hashkit->weight_fn(context) / (float)total_weight; + points_per_server= (uint32_t) ((floorf((float) (pct * HASHKIT_POINTS_PER_NODE_WEIGHTED / 4 * (float)live_servers + 0.0000000001))) * 4); + } + + for (points_index= 0; + points_index < points_per_server / points_per_hash; + points_index++) + { + char sort_host[HASHKIT_CONTINUUM_KEY_SIZE]= ""; + size_t sort_host_length; + + if (hashkit->continuum_key_fn == NULL) + { + sort_host_length= (size_t) snprintf(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, "%u", + points_index); + } + else + { + sort_host_length= hashkit->continuum_key_fn(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, + points_index, context); + } + + if (hashkit->weight_fn == NULL) + { + if (hashkit->continuum_hash_fn == NULL) + value= hashkit_default(sort_host, sort_host_length); + else + value= hashkit->continuum_hash_fn(sort_host, sort_host_length); + + hashkit->continuum[continuum_index].index= count; + hashkit->continuum[continuum_index++].value= value; + } + else + { + unsigned int i; + for (i = 0; i < points_per_hash; i++) + { + value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i); + hashkit->continuum[continuum_index].index= count; + hashkit->continuum[continuum_index++].value= value; + } + } + } + + points_count+= points_per_server; + } + + hashkit->continuum_points_count= points_count; + qsort(hashkit->continuum, hashkit->continuum_points_count, sizeof(hashkit_continuum_point_st), + continuum_points_cmp); + + return 0; +} +#endif diff --git a/libhashkit/md5.c b/libhashkit/md5.c deleted file mode 100644 index 1af5e6c0..00000000 --- a/libhashkit/md5.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - This Library has been modified from its original form by - Brian Aker (brian@tangent.org) - - See below for original Copyright. -*/ -/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. -*/ - -#include - -#include -#include - -/* POINTER defines a generic pointer type */ -typedef unsigned char *POINTER; - - -/* UINT4 defines a four byte word */ -typedef unsigned int UINT4; - - -/* MD5 context. */ -typedef struct { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -} MD5_CTX; - -static void MD5Init (MD5_CTX *context); /* context */ -static void MD5Update ( MD5_CTX *context, /* context */ - const unsigned char *input, /* input block */ - unsigned int inputLen); /* length of input block */ -static void MD5Final ( unsigned char digest[16], /* message digest */ - MD5_CTX *context); /* context */ - -/* Constants for MD5Transform routine. */ - -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - - -static void MD5Transform (UINT4 state[4], - unsigned char block[64]); -static void Encode (unsigned char *output, - UINT4 *input, - unsigned int len); -static void Decode(UINT4 *output, unsigned char *input, unsigned int len); - -static unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. -Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - - -/* - Just a simple method for getting the signature - result must be == 16 -*/ -void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result) -{ - MD5_CTX my_md5; - - MD5Init(&my_md5); - (void)MD5Update(&my_md5, key, length); - MD5Final(result, &my_md5); -} - -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -static void MD5Init (MD5_CTX *context) /* context */ -{ - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. -*/ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* MD5 block update operation. Continues an MD5 message-digest - operation, processing another message block, and updating the - context. - */ - -static void MD5Update ( - MD5_CTX *context, /* context */ - const unsigned char *input, /* input block */ - unsigned int inputLen) /* length of input block */ -{ - unsigned int i, idx, partLen; - - /* Compute number of bytes mod 64 */ - idx = (unsigned int)((context->count[0] >> 3) & 0x3F); - - - /* Update number of bits */ - if ((context->count[0] += ((UINT4)inputLen << 3)) - < ((UINT4)inputLen << 3)) - context->count[1]++; - context->count[1] += ((UINT4)inputLen >> 29); - - partLen = 64 - idx; - - /* Transform as many times as possible. -*/ - if (inputLen >= partLen) { - memcpy((POINTER)&context->buffer[idx], (POINTER)input, partLen); - MD5Transform(context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform (context->state, (unsigned char *)&input[i]); - - idx = 0; - } - else - i = 0; - - /* Buffer remaining input */ - memcpy((POINTER)&context->buffer[idx], (POINTER)&input[i], - inputLen-i); -} - -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - the message digest and zeroizing the context. - */ - -static void MD5Final ( - unsigned char digest[16], /* message digest */ - MD5_CTX *context) /* context */ -{ - unsigned char bits[8]; - unsigned int idx, padLen; - - /* Save number of bits */ - Encode (bits, context->count, 8); - - /* Pad out to 56 mod 64. -*/ - idx = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (idx < 56) ? (56 - idx) : (120 - idx); - MD5Update (context, PADDING, padLen); - - /* Append length (before padding) */ - MD5Update (context, bits, 8); - - /* Store state in digest */ - Encode (digest, context->state, 16); - - /* Zeroize sensitive information. -*/ - memset((POINTER)context, 0, sizeof (*context)); -} - -/* MD5 basic transformation. Transforms state based on block. - */ -static void MD5Transform ( - UINT4 state[4], - unsigned char block[64]) -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. -*/ - memset((POINTER)x, 0, sizeof (x)); -} - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode ( -unsigned char *output, -UINT4 *input, -unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); - } -} - - -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. - */ -static void Decode ( -UINT4 *output, -unsigned char *input, -unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | - (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); -} - -uint32_t hashkit_md5(const char *key, size_t key_length, void *context) -{ - unsigned char results[16]; - (void)context; - - md5_signature((unsigned char*)key, (unsigned int)key_length, results); - - return ((uint32_t) (results[3] & 0xFF) << 24) - | ((uint32_t) (results[2] & 0xFF) << 16) - | ((uint32_t) (results[1] & 0xFF) << 8) - | (results[0] & 0xFF); -} diff --git a/libhashkit/md5.cc b/libhashkit/md5.cc new file mode 100644 index 00000000..86822f54 --- /dev/null +++ b/libhashkit/md5.cc @@ -0,0 +1,367 @@ +/* + This Library has been modified from its original form by + Brian Aker (brian@tangent.org) + + See below for original Copyright. +*/ +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. +*/ + +#include + +#include +#include + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; +typedef const unsigned char *CONST_POINTER; + + +/* UINT4 defines a four byte word */ +typedef unsigned int UINT4; + + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +static void MD5Init (MD5_CTX *context); /* context */ +static void MD5Update ( MD5_CTX *context, /* context */ + const unsigned char *input, /* input block */ + unsigned int inputLen); /* length of input block */ +static void MD5Final ( unsigned char digest[16], /* message digest */ + MD5_CTX *context); /* context */ + +/* Constants for MD5Transform routine. */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + + +static void MD5Transform (UINT4 state[4], + const unsigned char block[64]); +static void Encode (unsigned char *output, + UINT4 *input, + unsigned int len); +static void Decode(UINT4 *output, const unsigned char *input, unsigned int len); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + + +/* + Just a simple method for getting the signature + result must be == 16 +*/ +void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result) +{ + MD5_CTX my_md5; + + MD5Init(&my_md5); + (void)MD5Update(&my_md5, key, length); + MD5Final(result, &my_md5); +} + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +static void MD5Init (MD5_CTX *context) /* context */ +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. +*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ + +static void MD5Update ( + MD5_CTX *context, /* context */ + const unsigned char *input, /* input block */ + unsigned int inputLen) /* length of input block */ +{ + unsigned int i, idx, partLen; + + /* Compute number of bytes mod 64 */ + idx = (unsigned int)((context->count[0] >> 3) & 0x3F); + + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - idx; + + /* Transform as many times as possible. +*/ + if (inputLen >= partLen) { + memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)input, partLen); + MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, (CONST_POINTER)&input[i]); + + idx = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)&input[i], + inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ + +static void MD5Final ( + unsigned char digest[16], /* message digest */ + MD5_CTX *context) /* context */ +{ + unsigned char bits[8]; + unsigned int idx, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. +*/ + idx = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (idx < 56) ? (56 - idx) : (120 - idx); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. +*/ + memset((POINTER)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform ( + UINT4 state[4], + const unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. +*/ + memset((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode ( +unsigned char *output, +UINT4 *input, +unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode ( + UINT4 *output, + const unsigned char *input, + unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +uint32_t hashkit_md5(const char *key, size_t key_length, void *context) +{ + unsigned char results[16]; + (void)context; + + md5_signature((unsigned char*)key, (unsigned int)key_length, results); + + return ((uint32_t) (results[3] & 0xFF) << 24) + | ((uint32_t) (results[2] & 0xFF) << 16) + | ((uint32_t) (results[1] & 0xFF) << 8) + | (results[0] & 0xFF); +} diff --git a/libhashkit/murmur.c b/libhashkit/murmur.c deleted file mode 100644 index a40b11b7..00000000 --- a/libhashkit/murmur.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - "Murmur" hash provided by Austin, tanjent@gmail.com - http://murmurhash.googlepages.com/ - - Note - This code makes a few assumptions about how your machine behaves - - - 1. We can read a 4-byte value from any address without crashing - 2. sizeof(int) == 4 - - And it has a few limitations - - 1. It will not work incrementally. - 2. It will not produce the same results on little-endian and big-endian - machines. - - Updated to murmur2 hash - BP -*/ - -#include - -uint32_t hashkit_murmur(const char *key, size_t length, void *context) -{ - /* - 'm' and 'r' are mixing constants generated offline. They're not - really 'magic', they just happen to work well. - */ - - const unsigned int m= 0x5bd1e995; - const uint32_t seed= (0xdeadbeef * (uint32_t)length); - const int r= 24; - - - // Initialize the hash to a 'random' value - - uint32_t h= seed ^ (uint32_t)length; - - // Mix 4 bytes at a time into the hash - - const unsigned char * data= (const unsigned char *)key; - (void)context; - - while(length >= 4) - { - unsigned int k = *(unsigned int *)data; - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - data += 4; - length -= 4; - } - - // Handle the last few bytes of the input array - - switch(length) - { - case 3: h ^= ((uint32_t)data[2]) << 16; - case 2: h ^= ((uint32_t)data[1]) << 8; - case 1: h ^= data[0]; - h *= m; - default: break; - }; - - /* - Do a few final mixes of the hash to ensure the last few bytes are - well-incorporated. - */ - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} diff --git a/libhashkit/murmur.cc b/libhashkit/murmur.cc new file mode 100644 index 00000000..a40b11b7 --- /dev/null +++ b/libhashkit/murmur.cc @@ -0,0 +1,77 @@ +/* + "Murmur" hash provided by Austin, tanjent@gmail.com + http://murmurhash.googlepages.com/ + + Note - This code makes a few assumptions about how your machine behaves - + + 1. We can read a 4-byte value from any address without crashing + 2. sizeof(int) == 4 + + And it has a few limitations - + 1. It will not work incrementally. + 2. It will not produce the same results on little-endian and big-endian + machines. + + Updated to murmur2 hash - BP +*/ + +#include + +uint32_t hashkit_murmur(const char *key, size_t length, void *context) +{ + /* + 'm' and 'r' are mixing constants generated offline. They're not + really 'magic', they just happen to work well. + */ + + const unsigned int m= 0x5bd1e995; + const uint32_t seed= (0xdeadbeef * (uint32_t)length); + const int r= 24; + + + // Initialize the hash to a 'random' value + + uint32_t h= seed ^ (uint32_t)length; + + // Mix 4 bytes at a time into the hash + + const unsigned char * data= (const unsigned char *)key; + (void)context; + + while(length >= 4) + { + unsigned int k = *(unsigned int *)data; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + length -= 4; + } + + // Handle the last few bytes of the input array + + switch(length) + { + case 3: h ^= ((uint32_t)data[2]) << 16; + case 2: h ^= ((uint32_t)data[1]) << 8; + case 1: h ^= data[0]; + h *= m; + default: break; + }; + + /* + Do a few final mixes of the hash to ensure the last few bytes are + well-incorporated. + */ + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} diff --git a/libhashkit/one_at_a_time.c b/libhashkit/one_at_a_time.c deleted file mode 100644 index aeb11b12..00000000 --- a/libhashkit/one_at_a_time.c +++ /dev/null @@ -1,34 +0,0 @@ -/* HashKit - * Copyright (C) 2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - */ - -/* - This has is Jenkin's "One at A time Hash". -http://en.wikipedia.org/wiki/Jenkins_hash_function -*/ - -#include - -uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context) -{ - const char *ptr= key; - uint32_t value= 0; - (void)context; - - while (key_length--) - { - uint32_t val= (uint32_t) *ptr++; - value += val; - value += (value << 10); - value ^= (value >> 6); - } - value += (value << 3); - value ^= (value >> 11); - value += (value << 15); - - return value; -} diff --git a/libhashkit/one_at_a_time.cc b/libhashkit/one_at_a_time.cc new file mode 100644 index 00000000..aeb11b12 --- /dev/null +++ b/libhashkit/one_at_a_time.cc @@ -0,0 +1,34 @@ +/* HashKit + * Copyright (C) 2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +/* + This has is Jenkin's "One at A time Hash". +http://en.wikipedia.org/wiki/Jenkins_hash_function +*/ + +#include + +uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context) +{ + const char *ptr= key; + uint32_t value= 0; + (void)context; + + while (key_length--) + { + uint32_t val= (uint32_t) *ptr++; + value += val; + value += (value << 10); + value ^= (value >> 6); + } + value += (value << 3); + value ^= (value >> 11); + value += (value << 15); + + return value; +} diff --git a/libhashkit/str_algorithm.c b/libhashkit/str_algorithm.c deleted file mode 100644 index 0a0613bc..00000000 --- a/libhashkit/str_algorithm.c +++ /dev/null @@ -1,57 +0,0 @@ -/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: - * - * HashKit - * - * Copyright (C) 2011 Data Differential, http://datadifferential.com/ - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * * The names of its contributors may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -const char * libhashkit_string_hash(hashkit_hash_algorithm_t type) -{ - switch(type) - { - case HASHKIT_HASH_DEFAULT: return "DEFAULT"; - case HASHKIT_HASH_MD5: return "MD5"; - case HASHKIT_HASH_CRC: return "CRC"; - case HASHKIT_HASH_FNV1_64: return "FNV1_64"; - case HASHKIT_HASH_FNV1A_64: return "FNV1A_64"; - case HASHKIT_HASH_FNV1_32: return "FNV1_32"; - case HASHKIT_HASH_FNV1A_32: return "FNV1A_32"; - case HASHKIT_HASH_HSIEH: return "HSIEH"; - case HASHKIT_HASH_MURMUR: return "MURMUR"; - case HASHKIT_HASH_JENKINS: return "JENKINS"; - case HASHKIT_HASH_CUSTOM: return "CUSTOM"; - default: - case HASHKIT_HASH_MAX: return "INVALID"; - } -} diff --git a/libhashkit/str_algorithm.cc b/libhashkit/str_algorithm.cc new file mode 100644 index 00000000..0a0613bc --- /dev/null +++ b/libhashkit/str_algorithm.cc @@ -0,0 +1,57 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * HashKit + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +const char * libhashkit_string_hash(hashkit_hash_algorithm_t type) +{ + switch(type) + { + case HASHKIT_HASH_DEFAULT: return "DEFAULT"; + case HASHKIT_HASH_MD5: return "MD5"; + case HASHKIT_HASH_CRC: return "CRC"; + case HASHKIT_HASH_FNV1_64: return "FNV1_64"; + case HASHKIT_HASH_FNV1A_64: return "FNV1A_64"; + case HASHKIT_HASH_FNV1_32: return "FNV1_32"; + case HASHKIT_HASH_FNV1A_32: return "FNV1A_32"; + case HASHKIT_HASH_HSIEH: return "HSIEH"; + case HASHKIT_HASH_MURMUR: return "MURMUR"; + case HASHKIT_HASH_JENKINS: return "JENKINS"; + case HASHKIT_HASH_CUSTOM: return "CUSTOM"; + default: + case HASHKIT_HASH_MAX: return "INVALID"; + } +} diff --git a/libhashkit/strerror.c b/libhashkit/strerror.c deleted file mode 100644 index 8d7246c6..00000000 --- a/libhashkit/strerror.c +++ /dev/null @@ -1,25 +0,0 @@ -/* HashKit - * Copyright (C) 2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - */ - -#include - -const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc) -{ - (void)ptr; - switch (rc) - { - case HASHKIT_SUCCESS: return "SUCCESS"; - case HASHKIT_FAILURE: return "FAILURE"; - case HASHKIT_MEMORY_ALLOCATION_FAILURE: return "MEMORY ALLOCATION FAILURE"; - case HASHKIT_INVALID_ARGUMENT: return "INVALID ARGUMENT"; - case HASHKIT_INVALID_HASH: return "INVALID hashkit_hash_algorithm_t"; - case HASHKIT_MAXIMUM_RETURN: - default: - return "INVALID hashkit_return_t"; - } -} diff --git a/libhashkit/strerror.cc b/libhashkit/strerror.cc new file mode 100644 index 00000000..8d7246c6 --- /dev/null +++ b/libhashkit/strerror.cc @@ -0,0 +1,25 @@ +/* HashKit + * Copyright (C) 2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#include + +const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc) +{ + (void)ptr; + switch (rc) + { + case HASHKIT_SUCCESS: return "SUCCESS"; + case HASHKIT_FAILURE: return "FAILURE"; + case HASHKIT_MEMORY_ALLOCATION_FAILURE: return "MEMORY ALLOCATION FAILURE"; + case HASHKIT_INVALID_ARGUMENT: return "INVALID ARGUMENT"; + case HASHKIT_INVALID_HASH: return "INVALID hashkit_hash_algorithm_t"; + case HASHKIT_MAXIMUM_RETURN: + default: + return "INVALID hashkit_return_t"; + } +} diff --git a/libhashkit/visibility.h b/libhashkit/visibility.h index 7691d4b5..b8f194c5 100644 --- a/libhashkit/visibility.h +++ b/libhashkit/visibility.h @@ -13,8 +13,7 @@ * @brief Visibility control macros */ -#ifndef HASHKIT_VISIBILITY_H -#define HASHKIT_VISIBILITY_H +#pragma once /** * @@ -47,5 +46,3 @@ # define HASHKIT_LOCAL # endif /* defined(_MSC_VER) */ #endif /* defined(BUILDING_HASHKIT) */ - -#endif /* HASHKIT_VISIBILITY_H */ diff --git a/libmemcached/allocators.c b/libmemcached/allocators.c deleted file mode 100644 index fe7b296c..00000000 --- a/libmemcached/allocators.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "common.h" - -void _libmemcached_free(const memcached_st *ptr, void *mem, void *context) -{ - (void) ptr; - (void) context; - free(mem); -} - -void *_libmemcached_malloc(const memcached_st *ptr, size_t size, void *context) -{ - (void) ptr; - (void) context; - return malloc(size); -} - -void *_libmemcached_realloc(const memcached_st *ptr, void *mem, size_t size, void *context) -{ - (void) ptr; - (void) context; - return realloc(mem, size); -} - -void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context) -{ - if (ptr->allocators.malloc != _libmemcached_malloc) - { - void *ret = _libmemcached_malloc(ptr, nelem * size, context); - if (ret != NULL) - memset(ret, 0, nelem * size); - - return ret; - } - - return calloc(nelem, size); -} - -static const struct _allocators_st global_default_allocator= { - .calloc= _libmemcached_calloc, - .context= NULL, - .free= _libmemcached_free, - .malloc= _libmemcached_malloc, - .realloc= _libmemcached_realloc -}; - -struct _allocators_st memcached_allocators_return_default(void) -{ - return global_default_allocator; -} - -memcached_return_t memcached_set_memory_allocators(memcached_st *ptr, - memcached_malloc_fn mem_malloc, - memcached_free_fn mem_free, - memcached_realloc_fn mem_realloc, - memcached_calloc_fn mem_calloc, - void *context) -{ - /* All should be set, or none should be set */ - if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL) - { - ptr->allocators= memcached_allocators_return_default(); - } - else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL) - { - return MEMCACHED_FAILURE; - } - else - { - ptr->allocators.malloc= mem_malloc; - ptr->allocators.free= mem_free; - ptr->allocators.realloc= mem_realloc; - ptr->allocators.calloc= mem_calloc; - ptr->allocators.context= context; - } - - return MEMCACHED_SUCCESS; -} - -void *memcached_get_memory_allocators_context(const memcached_st *ptr) -{ - return ptr->allocators.context; -} - -void memcached_get_memory_allocators(const memcached_st *ptr, - memcached_malloc_fn *mem_malloc, - memcached_free_fn *mem_free, - memcached_realloc_fn *mem_realloc, - memcached_calloc_fn *mem_calloc) -{ - *mem_malloc= ptr->allocators.malloc; - *mem_free= ptr->allocators.free; - *mem_realloc= ptr->allocators.realloc; - *mem_calloc= ptr->allocators.calloc; -} diff --git a/libmemcached/allocators.cc b/libmemcached/allocators.cc new file mode 100644 index 00000000..e716bee3 --- /dev/null +++ b/libmemcached/allocators.cc @@ -0,0 +1,87 @@ +#include "common.h" + +void _libmemcached_free(const memcached_st *ptr, void *mem, void *context) +{ + (void) ptr; + (void) context; + free(mem); +} + +void *_libmemcached_malloc(const memcached_st *ptr, size_t size, void *context) +{ + (void) ptr; + (void) context; + return malloc(size); +} + +void *_libmemcached_realloc(const memcached_st *ptr, void *mem, size_t size, void *context) +{ + (void) ptr; + (void) context; + return realloc(mem, size); +} + +void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context) +{ + if (ptr->allocators.malloc != _libmemcached_malloc) + { + void *ret = _libmemcached_malloc(ptr, nelem * size, context); + if (ret != NULL) + memset(ret, 0, nelem * size); + + return ret; + } + + return calloc(nelem, size); +} + +struct memcached_allocator_t memcached_allocators_return_default(void) +{ + static struct memcached_allocator_t global_default_allocator= { _libmemcached_calloc, _libmemcached_free, _libmemcached_malloc, _libmemcached_realloc, 0 }; + return global_default_allocator; +} + +memcached_return_t memcached_set_memory_allocators(memcached_st *ptr, + memcached_malloc_fn mem_malloc, + memcached_free_fn mem_free, + memcached_realloc_fn mem_realloc, + memcached_calloc_fn mem_calloc, + void *context) +{ + /* All should be set, or none should be set */ + if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL) + { + ptr->allocators= memcached_allocators_return_default(); + } + else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL) + { + return MEMCACHED_FAILURE; + } + else + { + ptr->allocators.malloc= mem_malloc; + ptr->allocators.free= mem_free; + ptr->allocators.realloc= mem_realloc; + ptr->allocators.calloc= mem_calloc; + ptr->allocators.context= context; + } + + return MEMCACHED_SUCCESS; +} + +void *memcached_get_memory_allocators_context(const memcached_st *ptr) +{ + return ptr->allocators.context; +} + +void memcached_get_memory_allocators(const memcached_st *ptr, + memcached_malloc_fn *mem_malloc, + memcached_free_fn *mem_free, + memcached_realloc_fn *mem_realloc, + memcached_calloc_fn *mem_calloc) +{ + *mem_malloc= ptr->allocators.malloc; + *mem_free= ptr->allocators.free; + *mem_realloc= ptr->allocators.realloc; + *mem_calloc= ptr->allocators.calloc; +} diff --git a/libmemcached/allocators.h b/libmemcached/allocators.h index b525e901..6e4455f0 100644 --- a/libmemcached/allocators.h +++ b/libmemcached/allocators.h @@ -1,16 +1,49 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. * - * Summary: work with user defined memory allocators + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_ALLOCATORS_H__ -#define __LIBMEMCACHED_ALLOCATORS_H__ +#pragma once + +struct memcached_allocator_t { + memcached_calloc_fn calloc; + memcached_free_fn free; + memcached_malloc_fn malloc; + memcached_realloc_fn realloc; + void *context; +}; #ifdef __cplusplus extern "C" { @@ -47,10 +80,8 @@ LIBMEMCACHED_LOCAL void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context); LIBMEMCACHED_LOCAL -struct _allocators_st memcached_allocators_return_default(void); +struct memcached_allocator_t memcached_allocators_return_default(void); #ifdef __cplusplus } #endif - -#endif /* __LIBMEMCACHED_ALLOCATORS_H__ */ diff --git a/libmemcached/analyze.c b/libmemcached/analyze.c deleted file mode 100644 index 7dcbf8cb..00000000 --- a/libmemcached/analyze.c +++ /dev/null @@ -1,107 +0,0 @@ -#include "common.h" - -static void calc_largest_consumption(memcached_analysis_st *result, - const uint32_t server_num, - const uint64_t nbytes) -{ - if (result->most_used_bytes < nbytes) - { - result->most_used_bytes= nbytes; - result->most_consumed_server= server_num; - } -} - -static void calc_oldest_node(memcached_analysis_st *result, - const uint32_t server_num, - const uint32_t uptime) -{ - if (result->longest_uptime < uptime) - { - result->longest_uptime= uptime; - result->oldest_server= server_num; - } -} - -static void calc_least_free_node(memcached_analysis_st *result, - const uint32_t server_num, - const uint64_t max_allowed_bytes, - const uint64_t used_bytes) -{ - uint64_t remaining_bytes= max_allowed_bytes - used_bytes; - - if (result->least_remaining_bytes == 0 || - remaining_bytes < result->least_remaining_bytes) - { - result->least_remaining_bytes= remaining_bytes; - result->least_free_server= server_num; - } -} - -static void calc_average_item_size(memcached_analysis_st *result, - const uint64_t total_items, - const uint64_t total_bytes) -{ - if (total_items > 0 && total_bytes > 0) - result->average_item_size= (uint32_t) (total_bytes / total_items); -} - -static void calc_hit_ratio(memcached_analysis_st *result, - const uint64_t total_get_hits, - const uint64_t total_get_cmds) -{ - if (total_get_hits == 0 || total_get_cmds == 0) - { - result->pool_hit_ratio= 0; - return; - } - - double temp= (double) (total_get_hits/total_get_cmds); - result->pool_hit_ratio= temp * 100; -} - -memcached_analysis_st *memcached_analyze(memcached_st *memc, - memcached_stat_st *memc_stat, - memcached_return_t *error) -{ - uint64_t total_items= 0, total_bytes= 0; - uint64_t total_get_cmds= 0, total_get_hits= 0; - uint32_t server_count, x; - memcached_analysis_st *result; - - *error= MEMCACHED_SUCCESS; - server_count= memcached_server_count(memc); - result= (memcached_analysis_st*)calloc(memcached_server_count(memc), - sizeof(memcached_analysis_st)); - - if (!result) - { - *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE; - return NULL; - } - - result->root= memc; - - for (x= 0; x < server_count; x++) - { - calc_largest_consumption(result, x, memc_stat[x].bytes); - calc_oldest_node(result, x, memc_stat[x].uptime); - calc_least_free_node(result, x, - memc_stat[x].limit_maxbytes, - memc_stat[x].bytes); - - total_get_hits+= memc_stat[x].get_hits; - total_get_cmds+= memc_stat[x].cmd_get; - total_items+= memc_stat[x].curr_items; - total_bytes+= memc_stat[x].bytes; - } - - calc_average_item_size(result, total_items, total_bytes); - calc_hit_ratio(result, total_get_hits, total_get_cmds); - - return result; -} - -void memcached_analyze_free(memcached_analysis_st *ptr) -{ - free(ptr); -} diff --git a/libmemcached/analyze.cc b/libmemcached/analyze.cc new file mode 100644 index 00000000..7dcbf8cb --- /dev/null +++ b/libmemcached/analyze.cc @@ -0,0 +1,107 @@ +#include "common.h" + +static void calc_largest_consumption(memcached_analysis_st *result, + const uint32_t server_num, + const uint64_t nbytes) +{ + if (result->most_used_bytes < nbytes) + { + result->most_used_bytes= nbytes; + result->most_consumed_server= server_num; + } +} + +static void calc_oldest_node(memcached_analysis_st *result, + const uint32_t server_num, + const uint32_t uptime) +{ + if (result->longest_uptime < uptime) + { + result->longest_uptime= uptime; + result->oldest_server= server_num; + } +} + +static void calc_least_free_node(memcached_analysis_st *result, + const uint32_t server_num, + const uint64_t max_allowed_bytes, + const uint64_t used_bytes) +{ + uint64_t remaining_bytes= max_allowed_bytes - used_bytes; + + if (result->least_remaining_bytes == 0 || + remaining_bytes < result->least_remaining_bytes) + { + result->least_remaining_bytes= remaining_bytes; + result->least_free_server= server_num; + } +} + +static void calc_average_item_size(memcached_analysis_st *result, + const uint64_t total_items, + const uint64_t total_bytes) +{ + if (total_items > 0 && total_bytes > 0) + result->average_item_size= (uint32_t) (total_bytes / total_items); +} + +static void calc_hit_ratio(memcached_analysis_st *result, + const uint64_t total_get_hits, + const uint64_t total_get_cmds) +{ + if (total_get_hits == 0 || total_get_cmds == 0) + { + result->pool_hit_ratio= 0; + return; + } + + double temp= (double) (total_get_hits/total_get_cmds); + result->pool_hit_ratio= temp * 100; +} + +memcached_analysis_st *memcached_analyze(memcached_st *memc, + memcached_stat_st *memc_stat, + memcached_return_t *error) +{ + uint64_t total_items= 0, total_bytes= 0; + uint64_t total_get_cmds= 0, total_get_hits= 0; + uint32_t server_count, x; + memcached_analysis_st *result; + + *error= MEMCACHED_SUCCESS; + server_count= memcached_server_count(memc); + result= (memcached_analysis_st*)calloc(memcached_server_count(memc), + sizeof(memcached_analysis_st)); + + if (!result) + { + *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE; + return NULL; + } + + result->root= memc; + + for (x= 0; x < server_count; x++) + { + calc_largest_consumption(result, x, memc_stat[x].bytes); + calc_oldest_node(result, x, memc_stat[x].uptime); + calc_least_free_node(result, x, + memc_stat[x].limit_maxbytes, + memc_stat[x].bytes); + + total_get_hits+= memc_stat[x].get_hits; + total_get_cmds+= memc_stat[x].cmd_get; + total_items+= memc_stat[x].curr_items; + total_bytes+= memc_stat[x].bytes; + } + + calc_average_item_size(result, total_items, total_bytes); + calc_hit_ratio(result, total_get_hits, total_get_cmds); + + return result; +} + +void memcached_analyze_free(memcached_analysis_st *ptr) +{ + free(ptr); +} diff --git a/libmemcached/auto.c b/libmemcached/auto.c deleted file mode 100644 index 325ddb6b..00000000 --- a/libmemcached/auto.c +++ /dev/null @@ -1,326 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: Methods for adding or decrementing values from an object in memcached - * - */ - -#include "libmemcached/common.h" - -static memcached_return_t text_incr_decr(memcached_st *ptr, - const char *verb, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - uint64_t offset, - uint64_t *value) -{ - memcached_return_t rc; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - uint32_t server_key; - memcached_server_write_instance_st instance; - bool no_reply= ptr->flags.no_reply; - - if (memcached_server_count(ptr) == 0) - return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL); - - if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)) - return MEMCACHED_BAD_KEY_PROVIDED; - - server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); - instance= memcached_server_instance_fetch(ptr, server_key); - - int send_length; - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "%s %.*s%.*s %" PRIu64 "%s\r\n", verb, - memcached_print_array(ptr->prefix_key), - (int)key_length, key, - offset, no_reply ? " noreply" : ""); - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) - return MEMCACHED_WRITE_FAILURE; - - rc= memcached_do(instance, buffer, (size_t)send_length, true); - if (no_reply || rc != MEMCACHED_SUCCESS) - return rc; - - rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - - /* - So why recheck responce? Because the protocol is brain dead :) - The number returned might end up equaling one of the string - values. Less chance of a mistake with strncmp() so we will - use it. We still called memcached_response() though since it - worked its magic for non-blocking IO. - */ - if (! strncmp(buffer, "ERROR\r\n", 7)) - { - *value= 0; - rc= MEMCACHED_PROTOCOL_ERROR; - } - else if (! strncmp(buffer, "CLIENT_ERROR\r\n", 14)) - { - *value= 0; - rc= MEMCACHED_PROTOCOL_ERROR; - } - else if (!strncmp(buffer, "NOT_FOUND\r\n", 11)) - { - *value= 0; - rc= MEMCACHED_NOTFOUND; - } - else - { - *value= strtoull(buffer, (char **)NULL, 10); - rc= MEMCACHED_SUCCESS; - } - - return rc; -} - -static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - uint64_t offset, uint64_t initial, - uint32_t expiration, - uint64_t *value) -{ - uint32_t server_key; - memcached_server_write_instance_st instance; - bool no_reply= ptr->flags.no_reply; - - if (memcached_server_count(ptr) == 0) - return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL); - - server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); - instance= memcached_server_instance_fetch(ptr, server_key); - - if (no_reply) - { - if(cmd == PROTOCOL_BINARY_CMD_DECREMENT) - cmd= PROTOCOL_BINARY_CMD_DECREMENTQ; - if(cmd == PROTOCOL_BINARY_CMD_INCREMENT) - cmd= PROTOCOL_BINARY_CMD_INCREMENTQ; - } - protocol_binary_request_incr request= {.bytes= {0}}; - - request.message.header.request.magic= PROTOCOL_BINARY_REQ; - request.message.header.request.opcode= cmd; - request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key))); - request.message.header.request.extlen= 20; - request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key) +request.message.header.request.extlen)); - request.message.body.delta= htonll(offset); - request.message.body.initial= htonll(initial); - request.message.body.expiration= htonl((uint32_t) expiration); - - struct libmemcached_io_vector_st vector[]= - { - { .length= sizeof(request.bytes), .buffer= request.bytes }, - { .length= memcached_array_size(ptr->prefix_key), .buffer= ptr->prefix_key }, - { .length= key_length, .buffer= key } - }; - - memcached_return_t rc; - if ((rc= memcached_vdo(instance, vector, 3, true)) != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc; - } - - if (no_reply) - return MEMCACHED_SUCCESS; - return memcached_response(instance, (char*)value, sizeof(*value), NULL); -} - -memcached_return_t memcached_increment(memcached_st *ptr, - const char *key, size_t key_length, - uint32_t offset, - uint64_t *value) -{ - uint64_t local_value; - if (! value) - value= &local_value; - - return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value); -} - -memcached_return_t memcached_decrement(memcached_st *ptr, - const char *key, size_t key_length, - uint32_t offset, - uint64_t *value) -{ - uint64_t local_value; - if (! value) - value= &local_value; - - return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value); -} - -memcached_return_t memcached_increment_by_key(memcached_st *ptr, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - uint64_t offset, - uint64_t *value) -{ - memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol); - unlikely (rc != MEMCACHED_SUCCESS) - return rc; - - uint64_t local_value; - if (! value) - value= &local_value; - - LIBMEMCACHED_MEMCACHED_INCREMENT_START(); - if (ptr->flags.binary_protocol) - { - rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT, - group_key, group_key_length, key, key_length, - (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD, - value); - } - else - { - rc= text_incr_decr(ptr, "incr", group_key, group_key_length, key, key_length, offset, value); - } - - LIBMEMCACHED_MEMCACHED_INCREMENT_END(); - - return rc; -} - -memcached_return_t memcached_decrement_by_key(memcached_st *ptr, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - uint64_t offset, - uint64_t *value) -{ - memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol); - unlikely (rc != MEMCACHED_SUCCESS) - return rc; - - uint64_t local_value; - if (! value) - value= &local_value; - - LIBMEMCACHED_MEMCACHED_DECREMENT_START(); - if (ptr->flags.binary_protocol) - { - rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT, - group_key, group_key_length, key, key_length, - (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD, - value); - } - else - { - rc= text_incr_decr(ptr, "decr", group_key, group_key_length, key, key_length, offset, value); - } - - LIBMEMCACHED_MEMCACHED_DECREMENT_END(); - - return rc; -} - -memcached_return_t memcached_increment_with_initial(memcached_st *ptr, - const char *key, - size_t key_length, - uint64_t offset, - uint64_t initial, - time_t expiration, - uint64_t *value) -{ - uint64_t local_value; - if (! value) - value= &local_value; - - return memcached_increment_with_initial_by_key(ptr, key, key_length, - key, key_length, - offset, initial, expiration, value); -} - -memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr, - const char *group_key, - size_t group_key_length, - const char *key, - size_t key_length, - uint64_t offset, - uint64_t initial, - time_t expiration, - uint64_t *value) -{ - memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol); - unlikely (rc != MEMCACHED_SUCCESS) - return rc; - - uint64_t local_value; - if (! value) - value= &local_value; - - LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START(); - if (ptr->flags.binary_protocol) - rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT, - group_key, group_key_length, key, key_length, - offset, initial, (uint32_t)expiration, - value); - else - rc= MEMCACHED_PROTOCOL_ERROR; - - LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END(); - - return rc; -} - -memcached_return_t memcached_decrement_with_initial(memcached_st *ptr, - const char *key, - size_t key_length, - uint64_t offset, - uint64_t initial, - time_t expiration, - uint64_t *value) -{ - uint64_t local_value; - if (! value) - value= &local_value; - - return memcached_decrement_with_initial_by_key(ptr, key, key_length, - key, key_length, - offset, initial, expiration, value); -} - -memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr, - const char *group_key, - size_t group_key_length, - const char *key, - size_t key_length, - uint64_t offset, - uint64_t initial, - time_t expiration, - uint64_t *value) -{ - memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol); - unlikely (rc != MEMCACHED_SUCCESS) - return rc; - - uint64_t local_value; - if (! value) - value= &local_value; - - LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START(); - if (ptr->flags.binary_protocol) - { - rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT, - group_key, group_key_length, key, key_length, - offset, initial, (uint32_t)expiration, - value); - } - else - { - rc= MEMCACHED_PROTOCOL_ERROR; - } - - LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END(); - - return rc; -} - diff --git a/libmemcached/auto.cc b/libmemcached/auto.cc new file mode 100644 index 00000000..42c3b5f0 --- /dev/null +++ b/libmemcached/auto.cc @@ -0,0 +1,380 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +static memcached_return_t text_incr_decr(memcached_st *ptr, + const char *verb, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + uint64_t offset, + uint64_t *value) +{ + memcached_return_t rc; + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + uint32_t server_key; + memcached_server_write_instance_st instance; + bool no_reply= ptr->flags.no_reply; + + if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)) + return MEMCACHED_BAD_KEY_PROVIDED; + + server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + instance= memcached_server_instance_fetch(ptr, server_key); + + int send_length; + send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "%s %.*s%.*s %" PRIu64 "%s\r\n", verb, + memcached_print_array(ptr->prefix_key), + (int)key_length, key, + offset, no_reply ? " noreply" : ""); + if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + return MEMCACHED_WRITE_FAILURE; + + rc= memcached_do(instance, buffer, (size_t)send_length, true); + if (no_reply || rc != MEMCACHED_SUCCESS) + return rc; + + rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + + /* + So why recheck responce? Because the protocol is brain dead :) + The number returned might end up equaling one of the string + values. Less chance of a mistake with strncmp() so we will + use it. We still called memcached_response() though since it + worked its magic for non-blocking IO. + */ + if (! strncmp(buffer, "ERROR\r\n", 7)) + { + *value= 0; + rc= MEMCACHED_PROTOCOL_ERROR; + } + else if (! strncmp(buffer, "CLIENT_ERROR\r\n", 14)) + { + *value= 0; + rc= MEMCACHED_PROTOCOL_ERROR; + } + else if (!strncmp(buffer, "NOT_FOUND\r\n", 11)) + { + *value= 0; + rc= MEMCACHED_NOTFOUND; + } + else + { + *value= strtoull(buffer, (char **)NULL, 10); + rc= MEMCACHED_SUCCESS; + } + + return rc; +} + +static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + uint64_t offset, uint64_t initial, + uint32_t expiration, + uint64_t *value) +{ + uint32_t server_key; + memcached_server_write_instance_st instance; + bool no_reply= ptr->flags.no_reply; + + if (memcached_server_count(ptr) == 0) + return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL); + + server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + instance= memcached_server_instance_fetch(ptr, server_key); + + if (no_reply) + { + if(cmd == PROTOCOL_BINARY_CMD_DECREMENT) + cmd= PROTOCOL_BINARY_CMD_DECREMENTQ; + if(cmd == PROTOCOL_BINARY_CMD_INCREMENT) + cmd= PROTOCOL_BINARY_CMD_INCREMENTQ; + } + protocol_binary_request_incr request= {}; // = {.bytes= {0}}; + + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= cmd; + request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key))); + request.message.header.request.extlen= 20; + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key) +request.message.header.request.extlen)); + request.message.body.delta= htonll(offset); + request.message.body.initial= htonll(initial); + request.message.body.expiration= htonl((uint32_t) expiration); + + struct libmemcached_io_vector_st vector[]= + { + { sizeof(request.bytes), request.bytes }, + { memcached_array_size(ptr->prefix_key), ptr->prefix_key }, + { key_length, key } + }; + + memcached_return_t rc; + if ((rc= memcached_vdo(instance, vector, 3, true)) != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc; + } + + if (no_reply) + return MEMCACHED_SUCCESS; + + return memcached_response(instance, (char*)value, sizeof(*value), NULL); +} + +memcached_return_t memcached_increment(memcached_st *ptr, + const char *key, size_t key_length, + uint32_t offset, + uint64_t *value) +{ + uint64_t local_value; + if (! value) + value= &local_value; + + return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value); +} + +memcached_return_t memcached_decrement(memcached_st *ptr, + const char *key, size_t key_length, + uint32_t offset, + uint64_t *value) +{ + uint64_t local_value; + if (! value) + value= &local_value; + + return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value); +} + +memcached_return_t memcached_increment_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + uint64_t offset, + uint64_t *value) +{ + memcached_return_t rc; + uint64_t local_value; + if (not value) + value= &local_value; + + if (memcached_failed(rc= initialize_query(ptr))) + { + return rc; + } + + if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + { + return rc; + } + + LIBMEMCACHED_MEMCACHED_INCREMENT_START(); + if (ptr->flags.binary_protocol) + { + rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT, + group_key, group_key_length, key, key_length, + (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD, + value); + } + else + { + rc= text_incr_decr(ptr, "incr", group_key, group_key_length, key, key_length, offset, value); + } + + LIBMEMCACHED_MEMCACHED_INCREMENT_END(); + + return rc; +} + +memcached_return_t memcached_decrement_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + uint64_t offset, + uint64_t *value) +{ + uint64_t local_value; + if (not value) + value= &local_value; + + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr))) + { + return rc; + } + + if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + { + return rc; + } + + + LIBMEMCACHED_MEMCACHED_DECREMENT_START(); + if (ptr->flags.binary_protocol) + { + rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT, + group_key, group_key_length, key, key_length, + (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD, + value); + } + else + { + rc= text_incr_decr(ptr, "decr", group_key, group_key_length, key, key_length, offset, value); + } + + LIBMEMCACHED_MEMCACHED_DECREMENT_END(); + + return rc; +} + +memcached_return_t memcached_increment_with_initial(memcached_st *ptr, + const char *key, + size_t key_length, + uint64_t offset, + uint64_t initial, + time_t expiration, + uint64_t *value) +{ + uint64_t local_value; + if (! value) + value= &local_value; + + return memcached_increment_with_initial_by_key(ptr, key, key_length, + key, key_length, + offset, initial, expiration, value); +} + +memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr, + const char *group_key, + size_t group_key_length, + const char *key, + size_t key_length, + uint64_t offset, + uint64_t initial, + time_t expiration, + uint64_t *value) +{ + uint64_t local_value; + if (not value) + value= &local_value; + + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr))) + { + return rc; + } + + if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + { + return rc; + } + + LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START(); + if (ptr->flags.binary_protocol) + rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT, + group_key, group_key_length, key, key_length, + offset, initial, (uint32_t)expiration, + value); + else + rc= MEMCACHED_PROTOCOL_ERROR; + + LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END(); + + return rc; +} + +memcached_return_t memcached_decrement_with_initial(memcached_st *ptr, + const char *key, + size_t key_length, + uint64_t offset, + uint64_t initial, + time_t expiration, + uint64_t *value) +{ + uint64_t local_value; + if (! value) + value= &local_value; + + return memcached_decrement_with_initial_by_key(ptr, key, key_length, + key, key_length, + offset, initial, expiration, value); +} + +memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr, + const char *group_key, + size_t group_key_length, + const char *key, + size_t key_length, + uint64_t offset, + uint64_t initial, + time_t expiration, + uint64_t *value) +{ + uint64_t local_value; + if (not value) + value= &local_value; + + memcached_return_t rc; + if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + { + return rc; + } + + if (memcached_failed(rc= initialize_query(ptr))) + { + return rc; + } + + + LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START(); + if (ptr->flags.binary_protocol) + { + rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT, + group_key, group_key_length, key, key_length, + offset, initial, (uint32_t)expiration, + value); + } + else + { + rc= MEMCACHED_PROTOCOL_ERROR; + } + + LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END(); + + return rc; +} + diff --git a/libmemcached/auto.h b/libmemcached/auto.h index 14ee90b5..f37d50fc 100644 --- a/libmemcached/auto.h +++ b/libmemcached/auto.h @@ -1,16 +1,41 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. * - * Summary: Change the behavior of the memcached connection. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_AUTO_H__ -#define __LIBMEMCACHED_AUTO_H__ +#pragma once #ifdef __cplusplus extern "C" { @@ -84,5 +109,3 @@ LIBMEMCACHED_API #ifdef __cplusplus } #endif - -#endif /* __LIBMEMCACHED_AUTO_H__ */ diff --git a/libmemcached/behavior.c b/libmemcached/behavior.c deleted file mode 100644 index 91e33a0b..00000000 --- a/libmemcached/behavior.c +++ /dev/null @@ -1,509 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: Change the behavior of the memcached connection. - * - */ - -#include -#include - -#include -#include - -static bool set_flag(uint64_t data) -{ - // Wordy :) - return data ? true : false; -} - -/* - This function is used to modify the behavior of running client. - - We quit all connections so we can reset the sockets. -*/ - -memcached_return_t memcached_behavior_set(memcached_st *ptr, - const memcached_behavior_t flag, - uint64_t data) -{ - switch (flag) - { - case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: - ptr->number_of_replicas= (uint32_t)data; - break; - case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: - ptr->io_msg_watermark= (uint32_t) data; - break; - case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: - ptr->io_bytes_watermark= (uint32_t)data; - break; - case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: - ptr->io_key_prefetch = (uint32_t)data; - break; - case MEMCACHED_BEHAVIOR_SND_TIMEOUT: - ptr->snd_timeout= (int32_t)data; - break; - case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: - ptr->rcv_timeout= (int32_t)data; - break; - - case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: - ptr->flags.auto_eject_hosts= set_flag(data); - case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: - ptr->server_failure_limit= (uint32_t)data; - break; - - case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: - send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol - if (data) - { - ptr->flags.verify_key= false; - } - ptr->flags.binary_protocol= set_flag(data); - break; - case MEMCACHED_BEHAVIOR_SUPPORT_CAS: - ptr->flags.support_cas= set_flag(data); - break; - case MEMCACHED_BEHAVIOR_NO_BLOCK: - ptr->flags.no_block= set_flag(data); - send_quit(ptr); - break; - case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: - ptr->flags.buffer_requests= set_flag(data); - send_quit(ptr); - break; - case MEMCACHED_BEHAVIOR_USE_UDP: - if (memcached_server_count(ptr)) - { - return MEMCACHED_FAILURE; - } - ptr->flags.use_udp= set_flag(data); - if (data) - { - ptr->flags.no_reply= set_flag(data); - } - break; - case MEMCACHED_BEHAVIOR_TCP_NODELAY: - ptr->flags.tcp_nodelay= set_flag(data); - send_quit(ptr); - break; - case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: - ptr->flags.tcp_keepalive= set_flag(data); - send_quit(ptr); - break; - case MEMCACHED_BEHAVIOR_DISTRIBUTION: - return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data); - case MEMCACHED_BEHAVIOR_KETAMA: - { - if (data) // Turn on - return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA); - - return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA); - } - case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: - { - (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5); - (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5); - ptr->ketama.weighted= set_flag(data); - /** - @note We try to keep the same distribution going. This should be deprecated and rewritten. - */ - return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA); - } - case MEMCACHED_BEHAVIOR_HASH: - return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data)); - case MEMCACHED_BEHAVIOR_KETAMA_HASH: - return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data)); - - case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: - return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, - memcached_string_with_size("MEMCACHED_BEHAVIOR_CACHE_LOOKUPS has been deprecated.")); - - case MEMCACHED_BEHAVIOR_VERIFY_KEY: - if (ptr->flags.binary_protocol) - return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, - memcached_string_with_size("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled.")); - ptr->flags.verify_key= set_flag(data); - break; - case MEMCACHED_BEHAVIOR_SORT_HOSTS: - { - ptr->flags.use_sort_hosts= set_flag(data); - run_distribution(ptr); - - break; - } - case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: - ptr->poll_timeout= (int32_t)data; - break; - case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: - ptr->connect_timeout= (int32_t)data; - break; - case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: - ptr->retry_timeout= (int32_t)data; - break; - case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: - ptr->send_size= (int32_t)data; - send_quit(ptr); - break; - case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: - ptr->recv_size= (int32_t)data; - send_quit(ptr); - break; - case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: - ptr->tcp_keepidle= (uint32_t)data; - send_quit(ptr); - break; - case MEMCACHED_BEHAVIOR_USER_DATA: - return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, - memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated.")); - case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: - ptr->flags.hash_with_prefix_key= set_flag(data); - break; - case MEMCACHED_BEHAVIOR_NOREPLY: - ptr->flags.no_reply= set_flag(data); - break; - case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: - ptr->flags.auto_eject_hosts= set_flag(data); - break; - case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: - srandom((uint32_t) time(NULL)); - ptr->flags.randomize_replica_read= set_flag(data); - break; - case MEMCACHED_BEHAVIOR_CORK: - { - return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, - memcached_string_with_size("MEMCACHED_BEHAVIOR_CORK is now incorporated into the driver by default.")); - } - break; - case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: - return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, - memcached_string_with_size("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()")); - case MEMCACHED_BEHAVIOR_MAX: - default: - /* Shouldn't get here */ - WATCHPOINT_ASSERT(0); - return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, - memcached_string_with_size("Invalid behavior passed to memcached_behavior_set()")); - } - - return MEMCACHED_SUCCESS; -} - -bool _is_auto_eject_host(const memcached_st *ptr) -{ - return ptr->flags.auto_eject_hosts; -} - -uint64_t memcached_behavior_get(memcached_st *ptr, - const memcached_behavior_t flag) -{ - switch (flag) - { - case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: - return ptr->number_of_replicas; - case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: - return ptr->io_msg_watermark; - case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: - return ptr->io_bytes_watermark; - case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: - return ptr->io_key_prefetch; - case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: - return ptr->flags.binary_protocol; - case MEMCACHED_BEHAVIOR_SUPPORT_CAS: - return ptr->flags.support_cas; - - case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: - return true; - - case MEMCACHED_BEHAVIOR_NO_BLOCK: - return ptr->flags.no_block; - case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: - return ptr->flags.buffer_requests; - case MEMCACHED_BEHAVIOR_USE_UDP: - return ptr->flags.use_udp; - case MEMCACHED_BEHAVIOR_TCP_NODELAY: - return ptr->flags.tcp_nodelay; - case MEMCACHED_BEHAVIOR_VERIFY_KEY: - return ptr->flags.verify_key; - case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: - return ptr->ketama.weighted; - case MEMCACHED_BEHAVIOR_DISTRIBUTION: - return ptr->distribution; - case MEMCACHED_BEHAVIOR_KETAMA: - return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0; - case MEMCACHED_BEHAVIOR_HASH: - return hashkit_get_function(&ptr->hashkit); - case MEMCACHED_BEHAVIOR_KETAMA_HASH: - return hashkit_get_function(&ptr->distribution_hashkit); - case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: - case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: - return ptr->server_failure_limit; - case MEMCACHED_BEHAVIOR_SORT_HOSTS: - return ptr->flags.use_sort_hosts; - case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: - return (uint64_t)ptr->poll_timeout; - case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: - return (uint64_t)ptr->connect_timeout; - case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: - return (uint64_t)ptr->retry_timeout; - case MEMCACHED_BEHAVIOR_SND_TIMEOUT: - return (uint64_t)ptr->snd_timeout; - case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: - return (uint64_t)ptr->rcv_timeout; - case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: - return (uint64_t)ptr->tcp_keepidle; - case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: - { - int sock_size= 0; - socklen_t sock_length= sizeof(int); - memcached_server_write_instance_st instance; - - if (ptr->send_size != -1) // If value is -1 then we are using the default - return (uint64_t) ptr->send_size; - - instance= memcached_server_instance_fetch(ptr, 0); - - if (instance) // If we have an instance we test, otherwise we just set and pray - { - /* REFACTOR */ - /* We just try the first host, and if it is down we return zero */ - if ((memcached_connect(instance)) != MEMCACHED_SUCCESS) - { - return 0; - } - - if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS) - { - return 0; - } - - if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, &sock_size, &sock_length) < 0) - { - memcached_set_errno(ptr, errno, NULL); - return 0; /* Zero means error */ - } - } - - return (uint64_t) sock_size; - } - case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: - { - int sock_size= 0; - socklen_t sock_length= sizeof(int); - memcached_server_write_instance_st instance; - - if (ptr->recv_size != -1) // If value is -1 then we are using the default - return (uint64_t) ptr->recv_size; - - instance= memcached_server_instance_fetch(ptr, 0); - - /** - @note REFACTOR - */ - if (instance) - { - /* We just try the first host, and if it is down we return zero */ - if ((memcached_connect(instance)) != MEMCACHED_SUCCESS) - { - return 0; - } - - if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS) - { - return 0; - } - - if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, &sock_size, &sock_length) < 0) - { - memcached_set_errno(ptr, errno, NULL); - return 0; /* Zero means error */ - } - - } - - return (uint64_t) sock_size; - } - case MEMCACHED_BEHAVIOR_USER_DATA: - memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, - memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated.")); - return 0; - case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: - return ptr->flags.hash_with_prefix_key; - case MEMCACHED_BEHAVIOR_NOREPLY: - return ptr->flags.no_reply; - case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: - return ptr->flags.auto_eject_hosts; - case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: - return ptr->flags.randomize_replica_read; - case MEMCACHED_BEHAVIOR_CORK: -#ifdef HAVE_MSG_MORE - return true; -#else - return false; -#endif - case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: - return ptr->flags.tcp_keepalive; - case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: - return ptr->configure.filename ? true : false; - case MEMCACHED_BEHAVIOR_MAX: - default: - WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */ - return 0; - } - - /* NOTREACHED */ -} - - -memcached_return_t memcached_behavior_set_distribution(memcached_st *ptr, memcached_server_distribution_t type) -{ - if (type < MEMCACHED_DISTRIBUTION_CONSISTENT_MAX) - { - if (MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED) - { - ptr->ketama.weighted= true; - } - else - { - ptr->ketama.weighted= false; - } - ptr->distribution= type; - run_distribution(ptr); - return MEMCACHED_SUCCESS; - } - - return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, - memcached_string_with_size("Invalid memcached_server_distribution_t")); -} - - -memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *ptr) -{ - return ptr->distribution; -} - -memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type) -{ - if (hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS) - return MEMCACHED_SUCCESS; - - return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, - memcached_string_with_size("Invalid memcached_hash_t()")); -} - -memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr) -{ - return (memcached_hash_t)hashkit_get_function(&ptr->hashkit); -} - -memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type) -{ - if (hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS) - return MEMCACHED_SUCCESS; - - return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, - memcached_string_with_size("Invalid memcached_hash_t()")); -} - -memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr) -{ - return (memcached_hash_t)hashkit_get_function(&ptr->distribution_hashkit); -} - -const char *libmemcached_string_behavior(const memcached_behavior_t flag) -{ - switch (flag) - { - case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK"; - case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY"; - case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH"; - case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA"; - case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE"; - case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE"; - case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS"; - case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS"; - case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT"; - case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION"; - case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS"; - case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA"; - case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS"; - case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY"; - case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT"; - case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT"; - case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED"; - case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH"; - case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL"; - case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT"; - case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT"; - case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT"; - case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK"; - case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK"; - case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH"; - case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY"; - case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY"; - case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP"; - case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS"; - case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: return "MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS"; - case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS"; - case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ"; - case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK"; - case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE"; - case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE"; - case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE"; - default: - case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t"; - } -} - -const char *libmemcached_string_distribution(const memcached_server_distribution_t flag) -{ - switch (flag) - { - case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA"; - case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT"; - case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA"; - case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM"; - case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY"; - case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: return "MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED"; - case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: return "MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET"; - default: - case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t"; - } -} - -memcached_return_t memcached_bucket_set(memcached_st *self, - const uint32_t *host_map, - const uint32_t *forward_map, - const uint32_t buckets, - const uint32_t replicas) -{ - memcached_return_t rc; - - if (! self) - return MEMCACHED_INVALID_ARGUMENTS; - - if (! host_map) - return MEMCACHED_INVALID_ARGUMENTS; - - memcached_server_distribution_t old; - old= memcached_behavior_get_distribution(self); - - rc =memcached_behavior_set_distribution(self, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET); - if (rc != MEMCACHED_SUCCESS) - { - return rc; - } - - rc= memcached_virtual_bucket_create(self, host_map, forward_map, buckets, replicas); - if (rc != MEMCACHED_SUCCESS) - { - memcached_behavior_set_distribution(self, old); - } - - return rc; -} diff --git a/libmemcached/behavior.cc b/libmemcached/behavior.cc new file mode 100644 index 00000000..91e33a0b --- /dev/null +++ b/libmemcached/behavior.cc @@ -0,0 +1,509 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: Change the behavior of the memcached connection. + * + */ + +#include +#include + +#include +#include + +static bool set_flag(uint64_t data) +{ + // Wordy :) + return data ? true : false; +} + +/* + This function is used to modify the behavior of running client. + + We quit all connections so we can reset the sockets. +*/ + +memcached_return_t memcached_behavior_set(memcached_st *ptr, + const memcached_behavior_t flag, + uint64_t data) +{ + switch (flag) + { + case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: + ptr->number_of_replicas= (uint32_t)data; + break; + case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: + ptr->io_msg_watermark= (uint32_t) data; + break; + case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: + ptr->io_bytes_watermark= (uint32_t)data; + break; + case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: + ptr->io_key_prefetch = (uint32_t)data; + break; + case MEMCACHED_BEHAVIOR_SND_TIMEOUT: + ptr->snd_timeout= (int32_t)data; + break; + case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: + ptr->rcv_timeout= (int32_t)data; + break; + + case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: + ptr->flags.auto_eject_hosts= set_flag(data); + case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: + ptr->server_failure_limit= (uint32_t)data; + break; + + case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: + send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol + if (data) + { + ptr->flags.verify_key= false; + } + ptr->flags.binary_protocol= set_flag(data); + break; + case MEMCACHED_BEHAVIOR_SUPPORT_CAS: + ptr->flags.support_cas= set_flag(data); + break; + case MEMCACHED_BEHAVIOR_NO_BLOCK: + ptr->flags.no_block= set_flag(data); + send_quit(ptr); + break; + case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: + ptr->flags.buffer_requests= set_flag(data); + send_quit(ptr); + break; + case MEMCACHED_BEHAVIOR_USE_UDP: + if (memcached_server_count(ptr)) + { + return MEMCACHED_FAILURE; + } + ptr->flags.use_udp= set_flag(data); + if (data) + { + ptr->flags.no_reply= set_flag(data); + } + break; + case MEMCACHED_BEHAVIOR_TCP_NODELAY: + ptr->flags.tcp_nodelay= set_flag(data); + send_quit(ptr); + break; + case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: + ptr->flags.tcp_keepalive= set_flag(data); + send_quit(ptr); + break; + case MEMCACHED_BEHAVIOR_DISTRIBUTION: + return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data); + case MEMCACHED_BEHAVIOR_KETAMA: + { + if (data) // Turn on + return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA); + + return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA); + } + case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: + { + (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5); + (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5); + ptr->ketama.weighted= set_flag(data); + /** + @note We try to keep the same distribution going. This should be deprecated and rewritten. + */ + return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA); + } + case MEMCACHED_BEHAVIOR_HASH: + return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data)); + case MEMCACHED_BEHAVIOR_KETAMA_HASH: + return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data)); + + case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: + return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, + memcached_string_with_size("MEMCACHED_BEHAVIOR_CACHE_LOOKUPS has been deprecated.")); + + case MEMCACHED_BEHAVIOR_VERIFY_KEY: + if (ptr->flags.binary_protocol) + return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, + memcached_string_with_size("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled.")); + ptr->flags.verify_key= set_flag(data); + break; + case MEMCACHED_BEHAVIOR_SORT_HOSTS: + { + ptr->flags.use_sort_hosts= set_flag(data); + run_distribution(ptr); + + break; + } + case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: + ptr->poll_timeout= (int32_t)data; + break; + case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: + ptr->connect_timeout= (int32_t)data; + break; + case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: + ptr->retry_timeout= (int32_t)data; + break; + case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: + ptr->send_size= (int32_t)data; + send_quit(ptr); + break; + case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: + ptr->recv_size= (int32_t)data; + send_quit(ptr); + break; + case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: + ptr->tcp_keepidle= (uint32_t)data; + send_quit(ptr); + break; + case MEMCACHED_BEHAVIOR_USER_DATA: + return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, + memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated.")); + case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: + ptr->flags.hash_with_prefix_key= set_flag(data); + break; + case MEMCACHED_BEHAVIOR_NOREPLY: + ptr->flags.no_reply= set_flag(data); + break; + case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: + ptr->flags.auto_eject_hosts= set_flag(data); + break; + case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: + srandom((uint32_t) time(NULL)); + ptr->flags.randomize_replica_read= set_flag(data); + break; + case MEMCACHED_BEHAVIOR_CORK: + { + return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, + memcached_string_with_size("MEMCACHED_BEHAVIOR_CORK is now incorporated into the driver by default.")); + } + break; + case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: + return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, + memcached_string_with_size("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()")); + case MEMCACHED_BEHAVIOR_MAX: + default: + /* Shouldn't get here */ + WATCHPOINT_ASSERT(0); + return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, + memcached_string_with_size("Invalid behavior passed to memcached_behavior_set()")); + } + + return MEMCACHED_SUCCESS; +} + +bool _is_auto_eject_host(const memcached_st *ptr) +{ + return ptr->flags.auto_eject_hosts; +} + +uint64_t memcached_behavior_get(memcached_st *ptr, + const memcached_behavior_t flag) +{ + switch (flag) + { + case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: + return ptr->number_of_replicas; + case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: + return ptr->io_msg_watermark; + case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: + return ptr->io_bytes_watermark; + case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: + return ptr->io_key_prefetch; + case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: + return ptr->flags.binary_protocol; + case MEMCACHED_BEHAVIOR_SUPPORT_CAS: + return ptr->flags.support_cas; + + case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: + return true; + + case MEMCACHED_BEHAVIOR_NO_BLOCK: + return ptr->flags.no_block; + case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: + return ptr->flags.buffer_requests; + case MEMCACHED_BEHAVIOR_USE_UDP: + return ptr->flags.use_udp; + case MEMCACHED_BEHAVIOR_TCP_NODELAY: + return ptr->flags.tcp_nodelay; + case MEMCACHED_BEHAVIOR_VERIFY_KEY: + return ptr->flags.verify_key; + case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: + return ptr->ketama.weighted; + case MEMCACHED_BEHAVIOR_DISTRIBUTION: + return ptr->distribution; + case MEMCACHED_BEHAVIOR_KETAMA: + return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0; + case MEMCACHED_BEHAVIOR_HASH: + return hashkit_get_function(&ptr->hashkit); + case MEMCACHED_BEHAVIOR_KETAMA_HASH: + return hashkit_get_function(&ptr->distribution_hashkit); + case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: + case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: + return ptr->server_failure_limit; + case MEMCACHED_BEHAVIOR_SORT_HOSTS: + return ptr->flags.use_sort_hosts; + case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: + return (uint64_t)ptr->poll_timeout; + case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: + return (uint64_t)ptr->connect_timeout; + case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: + return (uint64_t)ptr->retry_timeout; + case MEMCACHED_BEHAVIOR_SND_TIMEOUT: + return (uint64_t)ptr->snd_timeout; + case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: + return (uint64_t)ptr->rcv_timeout; + case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: + return (uint64_t)ptr->tcp_keepidle; + case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: + { + int sock_size= 0; + socklen_t sock_length= sizeof(int); + memcached_server_write_instance_st instance; + + if (ptr->send_size != -1) // If value is -1 then we are using the default + return (uint64_t) ptr->send_size; + + instance= memcached_server_instance_fetch(ptr, 0); + + if (instance) // If we have an instance we test, otherwise we just set and pray + { + /* REFACTOR */ + /* We just try the first host, and if it is down we return zero */ + if ((memcached_connect(instance)) != MEMCACHED_SUCCESS) + { + return 0; + } + + if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS) + { + return 0; + } + + if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, &sock_size, &sock_length) < 0) + { + memcached_set_errno(ptr, errno, NULL); + return 0; /* Zero means error */ + } + } + + return (uint64_t) sock_size; + } + case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: + { + int sock_size= 0; + socklen_t sock_length= sizeof(int); + memcached_server_write_instance_st instance; + + if (ptr->recv_size != -1) // If value is -1 then we are using the default + return (uint64_t) ptr->recv_size; + + instance= memcached_server_instance_fetch(ptr, 0); + + /** + @note REFACTOR + */ + if (instance) + { + /* We just try the first host, and if it is down we return zero */ + if ((memcached_connect(instance)) != MEMCACHED_SUCCESS) + { + return 0; + } + + if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS) + { + return 0; + } + + if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, &sock_size, &sock_length) < 0) + { + memcached_set_errno(ptr, errno, NULL); + return 0; /* Zero means error */ + } + + } + + return (uint64_t) sock_size; + } + case MEMCACHED_BEHAVIOR_USER_DATA: + memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, + memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated.")); + return 0; + case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: + return ptr->flags.hash_with_prefix_key; + case MEMCACHED_BEHAVIOR_NOREPLY: + return ptr->flags.no_reply; + case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: + return ptr->flags.auto_eject_hosts; + case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: + return ptr->flags.randomize_replica_read; + case MEMCACHED_BEHAVIOR_CORK: +#ifdef HAVE_MSG_MORE + return true; +#else + return false; +#endif + case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: + return ptr->flags.tcp_keepalive; + case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: + return ptr->configure.filename ? true : false; + case MEMCACHED_BEHAVIOR_MAX: + default: + WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */ + return 0; + } + + /* NOTREACHED */ +} + + +memcached_return_t memcached_behavior_set_distribution(memcached_st *ptr, memcached_server_distribution_t type) +{ + if (type < MEMCACHED_DISTRIBUTION_CONSISTENT_MAX) + { + if (MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED) + { + ptr->ketama.weighted= true; + } + else + { + ptr->ketama.weighted= false; + } + ptr->distribution= type; + run_distribution(ptr); + return MEMCACHED_SUCCESS; + } + + return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, + memcached_string_with_size("Invalid memcached_server_distribution_t")); +} + + +memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *ptr) +{ + return ptr->distribution; +} + +memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type) +{ + if (hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS) + return MEMCACHED_SUCCESS; + + return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, + memcached_string_with_size("Invalid memcached_hash_t()")); +} + +memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr) +{ + return (memcached_hash_t)hashkit_get_function(&ptr->hashkit); +} + +memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type) +{ + if (hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS) + return MEMCACHED_SUCCESS; + + return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, + memcached_string_with_size("Invalid memcached_hash_t()")); +} + +memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr) +{ + return (memcached_hash_t)hashkit_get_function(&ptr->distribution_hashkit); +} + +const char *libmemcached_string_behavior(const memcached_behavior_t flag) +{ + switch (flag) + { + case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK"; + case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY"; + case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH"; + case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA"; + case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE"; + case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE"; + case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS"; + case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS"; + case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT"; + case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION"; + case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS"; + case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA"; + case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS"; + case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY"; + case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT"; + case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT"; + case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED"; + case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH"; + case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL"; + case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT"; + case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT"; + case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT"; + case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK"; + case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK"; + case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH"; + case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY"; + case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY"; + case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP"; + case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS"; + case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: return "MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS"; + case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS"; + case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ"; + case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK"; + case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE"; + case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE"; + case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE"; + default: + case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t"; + } +} + +const char *libmemcached_string_distribution(const memcached_server_distribution_t flag) +{ + switch (flag) + { + case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA"; + case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT"; + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA"; + case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM"; + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY"; + case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: return "MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED"; + case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: return "MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET"; + default: + case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t"; + } +} + +memcached_return_t memcached_bucket_set(memcached_st *self, + const uint32_t *host_map, + const uint32_t *forward_map, + const uint32_t buckets, + const uint32_t replicas) +{ + memcached_return_t rc; + + if (! self) + return MEMCACHED_INVALID_ARGUMENTS; + + if (! host_map) + return MEMCACHED_INVALID_ARGUMENTS; + + memcached_server_distribution_t old; + old= memcached_behavior_get_distribution(self); + + rc =memcached_behavior_set_distribution(self, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET); + if (rc != MEMCACHED_SUCCESS) + { + return rc; + } + + rc= memcached_virtual_bucket_create(self, host_map, forward_map, buckets, replicas); + if (rc != MEMCACHED_SUCCESS) + { + memcached_behavior_set_distribution(self, old); + } + + return rc; +} diff --git a/libmemcached/byteorder.c b/libmemcached/byteorder.c deleted file mode 100644 index 97d14f2b..00000000 --- a/libmemcached/byteorder.c +++ /dev/null @@ -1,43 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - -#include "byteorder.h" - -/* Byte swap a 64-bit number. */ -#ifndef swap64 -static inline uint64_t swap64(uint64_t in) -{ -#ifndef WORDS_BIGENDIAN - /* Little endian, flip the bytes around until someone makes a faster/better - * way to do this. */ - uint64_t rv= 0; - for (uint8_t x= 0; x < 8; x++) - { - rv= (rv << 8) | (in & 0xff); - in >>= 8; - } - return rv; -#else - /* big-endian machines don't need byte swapping */ - return in; -#endif // WORDS_BIGENDIAN -} -#endif - -uint64_t memcached_ntohll(uint64_t value) -{ - return swap64(value); -} - -uint64_t memcached_htonll(uint64_t value) -{ - return swap64(value); -} diff --git a/libmemcached/byteorder.cc b/libmemcached/byteorder.cc new file mode 100644 index 00000000..ab35a9ef --- /dev/null +++ b/libmemcached/byteorder.cc @@ -0,0 +1,69 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +/* Byte swap a 64-bit number. */ +#ifndef swap64 +static inline uint64_t swap64(uint64_t in) +{ +#ifndef WORDS_BIGENDIAN + /* Little endian, flip the bytes around until someone makes a faster/better + * way to do this. */ + uint64_t rv= 0; + for (uint8_t x= 0; x < 8; x++) + { + rv= (rv << 8) | (in & 0xff); + in >>= 8; + } + return rv; +#else + /* big-endian machines don't need byte swapping */ + return in; +#endif // WORDS_BIGENDIAN +} +#endif + +uint64_t memcached_ntohll(uint64_t value) +{ + return swap64(value); +} + +uint64_t memcached_htonll(uint64_t value) +{ + return swap64(value); +} diff --git a/libmemcached/byteorder.h b/libmemcached/byteorder.h index 90a71ee4..f78790a8 100644 --- a/libmemcached/byteorder.h +++ b/libmemcached/byteorder.h @@ -1,39 +1,62 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. * - * Summary: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_BYTEORDER_H__ -#define __LIBMEMCACHED_BYTEORDER_H__ - -#include "config.h" +#pragma once #if HAVE_SYS_TYPES_H #include #endif - -/* Define this here, which will turn on the visibilty controls while we're - * building libmemcached. - */ -#define BUILDING_LIBMEMCACHED 1 - -#include "libmemcached/memcached.h" - #ifndef HAVE_HTONLL #define ntohll(a) memcached_ntohll(a) #define htonll(a) memcached_htonll(a) +#ifdef __cplusplus +extern "C" { +#endif + LIBMEMCACHED_LOCAL uint64_t memcached_ntohll(uint64_t); LIBMEMCACHED_LOCAL uint64_t memcached_htonll(uint64_t); +#ifdef __cplusplus +} +#endif + #endif #ifdef linux @@ -47,5 +70,3 @@ uint64_t memcached_htonll(uint64_t); #undef htons #undef htonl #endif - -#endif /*__LIBMEMCACHED_BYTEORDER_H__ */ diff --git a/libmemcached/callback.c b/libmemcached/callback.c deleted file mode 100644 index dcb3ddeb..00000000 --- a/libmemcached/callback.c +++ /dev/null @@ -1,158 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: Change any of the possible callbacks. - * - */ - -#include "libmemcached/common.h" -#include - -/* - These functions provide data and function callback support -*/ - -memcached_return_t memcached_callback_set(memcached_st *ptr, - const memcached_callback_t flag, - void *data) -{ - switch (flag) - { - case MEMCACHED_CALLBACK_PREFIX_KEY: - { - return memcached_set_prefix_key(ptr, (char*)data, data ? strlen((char*)data) : 0); - } - case MEMCACHED_CALLBACK_USER_DATA: - { - ptr->user_data= data; - break; - } - case MEMCACHED_CALLBACK_CLEANUP_FUNCTION: - { - memcached_cleanup_fn func= *(memcached_cleanup_fn *)&data; - ptr->on_cleanup= func; - break; - } - case MEMCACHED_CALLBACK_CLONE_FUNCTION: - { - memcached_clone_fn func= *(memcached_clone_fn *)&data; - ptr->on_clone= func; - break; - } -#ifdef MEMCACHED_ENABLE_DEPRECATED - case MEMCACHED_CALLBACK_MALLOC_FUNCTION: - { - memcached_malloc_function func= *(memcached_malloc_fn *)&data; - ptr->call_malloc= func; - break; - } - case MEMCACHED_CALLBACK_REALLOC_FUNCTION: - { - memcached_realloc_function func= *(memcached_realloc_fn *)&data; - ptr->call_realloc= func; - break; - } - case MEMCACHED_CALLBACK_FREE_FUNCTION: - { - memcached_free_function func= *(memcached_free_fn *)&data; - ptr->call_free= func; - break; - } -#endif - case MEMCACHED_CALLBACK_GET_FAILURE: - { - memcached_trigger_key_fn func= *(memcached_trigger_key_fn *)&data; - ptr->get_key_failure= func; - break; - } - case MEMCACHED_CALLBACK_DELETE_TRIGGER: - { - memcached_trigger_delete_key_fn func= *(memcached_trigger_delete_key_fn *)&data; - ptr->delete_trigger= func; - break; - } - case MEMCACHED_CALLBACK_MAX: - default: - return MEMCACHED_FAILURE; - } - - return MEMCACHED_SUCCESS; -} - -void *memcached_callback_get(memcached_st *ptr, - const memcached_callback_t flag, - memcached_return_t *error) -{ - memcached_return_t local_error; - - if (!error) - error = &local_error; - - switch (flag) - { - case MEMCACHED_CALLBACK_PREFIX_KEY: - { - if (ptr->prefix_key) - { - *error= MEMCACHED_SUCCESS; - return (void *)memcached_array_string(ptr->prefix_key); - } - else - { - *error= MEMCACHED_FAILURE; - return NULL; - } - } - case MEMCACHED_CALLBACK_USER_DATA: - { - *error= ptr->user_data ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; - return (void *)ptr->user_data; - } - case MEMCACHED_CALLBACK_CLEANUP_FUNCTION: - { - *error= ptr->on_cleanup ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; - return *(void **)&ptr->on_cleanup; - } - case MEMCACHED_CALLBACK_CLONE_FUNCTION: - { - *error= ptr->on_clone ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; - return *(void **)&ptr->on_clone; - } -#ifdef MEMCACHED_ENABLE_DEPRECATED - case MEMCACHED_CALLBACK_MALLOC_FUNCTION: - { - *error= ptr->call_malloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; - return *(void **)&ptr->call_malloc; - } - case MEMCACHED_CALLBACK_REALLOC_FUNCTION: - { - *error= ptr->call_realloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; - return *(void **)&ptr->call_realloc; - } - case MEMCACHED_CALLBACK_FREE_FUNCTION: - { - *error= ptr->call_free ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; - return *(void **)&ptr->call_free; - } -#endif - case MEMCACHED_CALLBACK_GET_FAILURE: - { - *error= ptr->get_key_failure ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; - return *(void **)&ptr->get_key_failure; - } - case MEMCACHED_CALLBACK_DELETE_TRIGGER: - { - *error= ptr->delete_trigger ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; - return *(void **)&ptr->delete_trigger; - } - case MEMCACHED_CALLBACK_MAX: - default: - WATCHPOINT_ASSERT(0); - *error= MEMCACHED_FAILURE; - return NULL; - } -} diff --git a/libmemcached/callback.cc b/libmemcached/callback.cc new file mode 100644 index 00000000..9818af4f --- /dev/null +++ b/libmemcached/callback.cc @@ -0,0 +1,160 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: Change any of the possible callbacks. + * + */ + +#include +#include + +#pragma GCC diagnostic ignored "-Wstrict-aliasing" + +/* + These functions provide data and function callback support +*/ + +memcached_return_t memcached_callback_set(memcached_st *ptr, + const memcached_callback_t flag, + void *data) +{ + switch (flag) + { + case MEMCACHED_CALLBACK_PREFIX_KEY: + { + return memcached_set_prefix_key(ptr, (char*)data, data ? strlen((char*)data) : 0); + } + case MEMCACHED_CALLBACK_USER_DATA: + { + ptr->user_data= data; + break; + } + case MEMCACHED_CALLBACK_CLEANUP_FUNCTION: + { + memcached_cleanup_fn func= *(memcached_cleanup_fn *)&data; + ptr->on_cleanup= func; + break; + } + case MEMCACHED_CALLBACK_CLONE_FUNCTION: + { + memcached_clone_fn func= *(memcached_clone_fn *)&data; + ptr->on_clone= func; + break; + } +#ifdef MEMCACHED_ENABLE_DEPRECATED + case MEMCACHED_CALLBACK_MALLOC_FUNCTION: + { + memcached_malloc_function func= *(memcached_malloc_fn *)&data; + ptr->call_malloc= func; + break; + } + case MEMCACHED_CALLBACK_REALLOC_FUNCTION: + { + memcached_realloc_function func= *(memcached_realloc_fn *)&data; + ptr->call_realloc= func; + break; + } + case MEMCACHED_CALLBACK_FREE_FUNCTION: + { + memcached_free_function func= *(memcached_free_fn *)&data; + ptr->call_free= func; + break; + } +#endif + case MEMCACHED_CALLBACK_GET_FAILURE: + { + memcached_trigger_key_fn func= *(memcached_trigger_key_fn *)&data; + ptr->get_key_failure= func; + break; + } + case MEMCACHED_CALLBACK_DELETE_TRIGGER: + { + memcached_trigger_delete_key_fn func= *(memcached_trigger_delete_key_fn *)&data; + ptr->delete_trigger= func; + break; + } + case MEMCACHED_CALLBACK_MAX: + default: + return MEMCACHED_FAILURE; + } + + return MEMCACHED_SUCCESS; +} + +void *memcached_callback_get(memcached_st *ptr, + const memcached_callback_t flag, + memcached_return_t *error) +{ + memcached_return_t local_error; + + if (!error) + error = &local_error; + + switch (flag) + { + case MEMCACHED_CALLBACK_PREFIX_KEY: + { + if (ptr->prefix_key) + { + *error= MEMCACHED_SUCCESS; + return (void *)memcached_array_string(ptr->prefix_key); + } + else + { + *error= MEMCACHED_FAILURE; + return NULL; + } + } + case MEMCACHED_CALLBACK_USER_DATA: + { + *error= ptr->user_data ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; + return (void *)ptr->user_data; + } + case MEMCACHED_CALLBACK_CLEANUP_FUNCTION: + { + *error= ptr->on_cleanup ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; + return *(void **)&ptr->on_cleanup; + } + case MEMCACHED_CALLBACK_CLONE_FUNCTION: + { + *error= ptr->on_clone ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; + return *(void **)&ptr->on_clone; + } +#ifdef MEMCACHED_ENABLE_DEPRECATED + case MEMCACHED_CALLBACK_MALLOC_FUNCTION: + { + *error= ptr->call_malloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; + return *(void **)&ptr->call_malloc; + } + case MEMCACHED_CALLBACK_REALLOC_FUNCTION: + { + *error= ptr->call_realloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; + return *(void **)&ptr->call_realloc; + } + case MEMCACHED_CALLBACK_FREE_FUNCTION: + { + *error= ptr->call_free ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; + return *(void **)&ptr->call_free; + } +#endif + case MEMCACHED_CALLBACK_GET_FAILURE: + { + *error= ptr->get_key_failure ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; + return *(void **)&ptr->get_key_failure; + } + case MEMCACHED_CALLBACK_DELETE_TRIGGER: + { + *error= ptr->delete_trigger ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; + return *(void **)&ptr->delete_trigger; + } + case MEMCACHED_CALLBACK_MAX: + default: + WATCHPOINT_ASSERT(0); + *error= MEMCACHED_FAILURE; + return NULL; + } +} diff --git a/libmemcached/callback.h b/libmemcached/callback.h index 4c3a95f4..b4da8080 100644 --- a/libmemcached/callback.h +++ b/libmemcached/callback.h @@ -9,6 +9,7 @@ * */ +#pragma once #ifndef __LIBMEMCACHED_CALLBACK_H__ #define __LIBMEMCACHED_CALLBACK_H__ diff --git a/libmemcached/common.h b/libmemcached/common.h index d0a4ab4c..ec58fd8e 100644 --- a/libmemcached/common.h +++ b/libmemcached/common.h @@ -65,16 +65,14 @@ # endif #endif -/* Define this here, which will turn on the visibilty controls while we're - * building libmemcached. - */ -#define BUILDING_LIBMEMCACHED 1 - #include #include #include -#include + +#ifdef __cplusplus +extern "C" { +#endif typedef struct memcached_server_st * memcached_server_write_instance_st; @@ -87,6 +85,9 @@ LIBMEMCACHED_LOCAL memcached_return_t memcached_server_execute(memcached_st *ptr, memcached_server_execute_fn callback, void *context); +#ifdef __cplusplus +} // extern "C" +#endif /* These are private not to be installed headers */ diff --git a/libmemcached/connect.c b/libmemcached/connect.c deleted file mode 100644 index a7b17f0c..00000000 --- a/libmemcached/connect.c +++ /dev/null @@ -1,578 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2010 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: Server IO, Not public! - * - */ - -#include -#include -#include -#include - -static memcached_return_t connect_poll(memcached_server_st *ptr) -{ - struct pollfd fds[1]; - fds[0].fd = ptr->fd; - fds[0].events = POLLOUT; - - int error; - size_t loop_max= 5; - - while (--loop_max) // Should only loop on cases of ERESTART or EINTR - { - error= poll(fds, 1, ptr->root->connect_timeout); - - switch (error) - { - case 1: - { - int err; - socklen_t len= sizeof (err); - (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len); - - // We check the value to see what happened wth the socket. - if (err == 0) - { - return MEMCACHED_SUCCESS; - } - else - { - ptr->cached_errno= errno; - - return MEMCACHED_ERRNO; - } - } - case 0: - return MEMCACHED_TIMEOUT; - default: // A real error occurred and we need to completely bail - WATCHPOINT_ERRNO(get_socket_errno()); - switch (get_socket_errno()) - { -#ifdef TARGET_OS_LINUX - case ERESTART: -#endif - case EINTR: - continue; - default: - if (fds[0].revents & POLLERR) - { - int err; - socklen_t len= sizeof (err); - (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len); - ptr->cached_errno= (err == 0) ? get_socket_errno() : err; - } - else - { - ptr->cached_errno= get_socket_errno(); - } - - (void)closesocket(ptr->fd); - ptr->fd= INVALID_SOCKET; - - return MEMCACHED_ERRNO; - } - } - } - - // This should only be possible from ERESTART or EINTR; - ptr->cached_errno= get_socket_errno(); - - return MEMCACHED_ERRNO; -} - -static memcached_return_t set_hostinfo(memcached_server_st *server) -{ - struct addrinfo hints; - char str_port[NI_MAXSERV]; - - assert(! server->address_info); // We cover the case where a programming mistake has been made. - if (server->address_info) - { - freeaddrinfo(server->address_info); - server->address_info= NULL; - server->address_info_next= NULL; - } - - int length= snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port); - if (length >= NI_MAXSERV || length < 0) - return MEMCACHED_FAILURE; - - memset(&hints, 0, sizeof(hints)); - -#if 0 - hints.ai_family= AF_INET; -#endif - if (server->type == MEMCACHED_CONNECTION_UDP) - { - hints.ai_protocol= IPPROTO_UDP; - hints.ai_socktype= SOCK_DGRAM; - } - else - { - hints.ai_socktype= SOCK_STREAM; - hints.ai_protocol= IPPROTO_TCP; - } - - uint32_t counter= 5; - while (--counter) - { - int e= getaddrinfo(server->hostname, str_port, &hints, &server->address_info); - - if (e == 0) - { - break; - } - else if (e == EAI_AGAIN) - { -#ifndef WIN32 - struct timespec dream, rem; - - dream.tv_nsec= 1000; - dream.tv_sec= 0; - - nanosleep(&dream, &rem); -#endif - continue; - } - else - { - WATCHPOINT_STRING(server->hostname); - WATCHPOINT_STRING(gai_strerror(e)); - return MEMCACHED_HOST_LOOKUP_FAILURE; - } - } - - server->address_info_next= server->address_info; - - return MEMCACHED_SUCCESS; -} - -static inline memcached_return_t set_socket_nonblocking(memcached_server_st *ptr) -{ -#ifdef WIN32 - u_long arg = 1; - if (ioctlsocket(ptr->fd, FIONBIO, &arg) == SOCKET_ERROR) - { - ptr->cached_errno= get_socket_errno(); - return MEMCACHED_CONNECTION_FAILURE; - } -#else - int flags; - - do - { - flags= fcntl(ptr->fd, F_GETFL, 0); - } - while (flags == -1 && (errno == EINTR || errno == EAGAIN)); - - unlikely (flags == -1) - { - ptr->cached_errno= errno; - return MEMCACHED_CONNECTION_FAILURE; - } - else if ((flags & O_NONBLOCK) == 0) - { - int rval; - - do - { - rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK); - } - while (rval == -1 && (errno == EINTR || errno == EAGAIN)); - - unlikely (rval == -1) - { - ptr->cached_errno= errno; - return MEMCACHED_CONNECTION_FAILURE; - } - } -#endif - return MEMCACHED_SUCCESS; -} - -static memcached_return_t set_socket_options(memcached_server_st *ptr) -{ - WATCHPOINT_ASSERT(ptr->fd != -1); - - if (ptr->type == MEMCACHED_CONNECTION_UDP) - return MEMCACHED_SUCCESS; - -#ifdef HAVE_SNDTIMEO - if (ptr->root->snd_timeout) - { - int error; - struct timeval waittime; - - waittime.tv_sec= 0; - waittime.tv_usec= ptr->root->snd_timeout; - - error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO, - &waittime, (socklen_t)sizeof(struct timeval)); - WATCHPOINT_ASSERT(error == 0); - if (error) - return MEMCACHED_FAILURE; - } -#endif - -#ifdef HAVE_RCVTIMEO - if (ptr->root->rcv_timeout) - { - int error; - struct timeval waittime; - - waittime.tv_sec= 0; - waittime.tv_usec= ptr->root->rcv_timeout; - - error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO, - &waittime, (socklen_t)sizeof(struct timeval)); - WATCHPOINT_ASSERT(error == 0); - if (error) - return MEMCACHED_FAILURE; - } -#endif - - -#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - { - int set = 1; - int error= setsockopt(ptr->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); - - // This is not considered a fatal error - if (error == -1) - { - WATCHPOINT_ERRNO(get_socket_errno()); - perror("setsockopt(SO_NOSIGPIPE)"); - } - } -#endif - - if (ptr->root->flags.no_block) - { - int error; - struct linger linger; - - linger.l_onoff= 1; - linger.l_linger= 0; /* By default on close() just drop the socket */ - error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER, - &linger, (socklen_t)sizeof(struct linger)); - WATCHPOINT_ASSERT(error == 0); - if (error) - return MEMCACHED_FAILURE; - } - - if (ptr->root->flags.tcp_nodelay) - { - int flag= 1; - int error; - - error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY, - &flag, (socklen_t)sizeof(int)); - WATCHPOINT_ASSERT(error == 0); - if (error) - return MEMCACHED_FAILURE; - } - - if (ptr->root->flags.tcp_keepalive) - { - int flag= 1; - int error; - - error= setsockopt(ptr->fd, SOL_SOCKET, SO_KEEPALIVE, - &flag, (socklen_t)sizeof(int)); - WATCHPOINT_ASSERT(error == 0); - if (error) - return MEMCACHED_FAILURE; - } - -#ifdef TCP_KEEPIDLE - if (ptr->root->tcp_keepidle > 0) - { - int error; - - error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_KEEPIDLE, - &ptr->root->tcp_keepidle, (socklen_t)sizeof(int)); - WATCHPOINT_ASSERT(error == 0); - if (error) - return MEMCACHED_FAILURE; - } -#endif - - if (ptr->root->send_size > 0) - { - int error; - - error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF, - &ptr->root->send_size, (socklen_t)sizeof(int)); - WATCHPOINT_ASSERT(error == 0); - if (error) - return MEMCACHED_FAILURE; - } - - if (ptr->root->recv_size > 0) - { - int error; - - error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF, - &ptr->root->recv_size, (socklen_t)sizeof(int)); - WATCHPOINT_ASSERT(error == 0); - if (error) - return MEMCACHED_FAILURE; - } - - - /* libmemcached will always use nonblocking IO to avoid write deadlocks */ - return set_socket_nonblocking(ptr); -} - -static memcached_return_t unix_socket_connect(memcached_server_st *ptr) -{ -#ifndef WIN32 - struct sockaddr_un servAddr; - - WATCHPOINT_ASSERT(ptr->fd == -1); - - if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - { - ptr->cached_errno= errno; - return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE; - } - - memset(&servAddr, 0, sizeof (struct sockaddr_un)); - servAddr.sun_family= AF_UNIX; - strncpy(servAddr.sun_path, ptr->hostname, sizeof(servAddr.sun_path)); /* Copy filename */ - -test_connect: - if (connect(ptr->fd, - (struct sockaddr *)&servAddr, - sizeof(servAddr)) < 0) - { - switch (errno) - { - case EINPROGRESS: - case EALREADY: - case EINTR: - goto test_connect; - case EISCONN: /* We were spinning waiting on connect */ - break; - default: - WATCHPOINT_ERRNO(errno); - ptr->cached_errno= errno; - return MEMCACHED_ERRNO; - } - } - - WATCHPOINT_ASSERT(ptr->fd != -1); - - return MEMCACHED_SUCCESS; -#else - (void)ptr; - return MEMCACHED_NOT_SUPPORTED; -#endif -} - -static memcached_return_t network_connect(memcached_server_st *ptr) -{ - bool timeout_error_occured= false; - - WATCHPOINT_ASSERT(ptr->fd == INVALID_SOCKET); - WATCHPOINT_ASSERT(ptr->cursor_active == 0); - - if (! ptr->address_info) - { - memcached_return_t rc= set_hostinfo(ptr); - if (rc != MEMCACHED_SUCCESS) - return rc; - } - - /* Create the socket */ - while (ptr->address_info_next && ptr->fd == INVALID_SOCKET) - { - /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */ - if (ptr->type == MEMCACHED_CONNECTION_UDP && ptr->address_info_next->ai_family != AF_INET) - { - ptr->address_info_next= ptr->address_info_next->ai_next; - continue; - } - - if ((ptr->fd= socket(ptr->address_info_next->ai_family, - ptr->address_info_next->ai_socktype, - ptr->address_info_next->ai_protocol)) < 0) - { - ptr->cached_errno= get_socket_errno(); - WATCHPOINT_ERRNO(get_socket_errno()); - return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE; - } - - (void)set_socket_options(ptr); - - /* connect to server */ - if ((connect(ptr->fd, ptr->address_info_next->ai_addr, ptr->address_info_next->ai_addrlen) != SOCKET_ERROR)) - { - break; // Success - } - - /* An error occurred */ - ptr->cached_errno= get_socket_errno(); - switch (ptr->cached_errno) - { - case EWOULDBLOCK: - case EINPROGRESS: // nonblocking mode - first return - case EALREADY: // nonblocking mode - subsequent returns - { - memcached_return_t rc; - rc= connect_poll(ptr); - - if (rc == MEMCACHED_TIMEOUT) - timeout_error_occured= true; - - if (rc == MEMCACHED_SUCCESS) - break; - } - - case EISCONN: // we are connected :-) - break; - - case EINTR: // Special case, we retry ai_addr - (void)closesocket(ptr->fd); - ptr->fd= INVALID_SOCKET; - continue; - - default: - (void)closesocket(ptr->fd); - ptr->fd= INVALID_SOCKET; - ptr->address_info_next= ptr->address_info_next->ai_next; - break; - } - } - - if (ptr->fd == INVALID_SOCKET) - { - WATCHPOINT_STRING("Never got a good file descriptor"); - - /* Failed to connect. schedule next retry */ - if (ptr->root->retry_timeout) - { - struct timeval next_time; - - if (gettimeofday(&next_time, NULL) == 0) - ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout; - } - - if (timeout_error_occured) - return MEMCACHED_TIMEOUT; - - return MEMCACHED_ERRNO; /* The last error should be from connect() */ - } - - return MEMCACHED_SUCCESS; /* The last error should be from connect() */ -} - -void set_last_disconnected_host(memcached_server_write_instance_st ptr) -{ - // const_cast - memcached_st *root= (memcached_st *)ptr->root; - -#if 0 - WATCHPOINT_STRING(ptr->hostname); - WATCHPOINT_NUMBER(ptr->port); - WATCHPOINT_ERRNO(ptr->cached_errno); -#endif - if (root->last_disconnected_server) - memcached_server_free(root->last_disconnected_server); - root->last_disconnected_server= memcached_server_clone(NULL, ptr); -} - -memcached_return_t memcached_connect(memcached_server_write_instance_st ptr) -{ - memcached_return_t rc= MEMCACHED_NO_SERVERS; - - if (ptr->fd != INVALID_SOCKET) - return MEMCACHED_SUCCESS; - - LIBMEMCACHED_MEMCACHED_CONNECT_START(); - - /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */ - WATCHPOINT_ASSERT(ptr->root); - if (ptr->root->retry_timeout && ptr->next_retry) - { - struct timeval curr_time; - - gettimeofday(&curr_time, NULL); - - // We should optimize this to remove the allocation if the server was - // the last server to die - if (ptr->next_retry > curr_time.tv_sec) - { - set_last_disconnected_host(ptr); - - return MEMCACHED_SERVER_MARKED_DEAD; - } - } - - // If we are over the counter failure, we just fail. Reject host only - // works if you have a set number of failures. - if (ptr->root->server_failure_limit && ptr->server_failure_counter >= ptr->root->server_failure_limit) - { - set_last_disconnected_host(ptr); - - // @todo fix this by fixing behavior to no longer make use of - // memcached_st - if (_is_auto_eject_host(ptr->root)) - { - run_distribution((memcached_st *)ptr->root); - } - - return MEMCACHED_SERVER_MARKED_DEAD; - } - - /* We need to clean up the multi startup piece */ - switch (ptr->type) - { - case MEMCACHED_CONNECTION_UNKNOWN: - WATCHPOINT_ASSERT(0); - rc= MEMCACHED_NOT_SUPPORTED; - break; - case MEMCACHED_CONNECTION_UDP: - case MEMCACHED_CONNECTION_TCP: - rc= network_connect(ptr); -#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT - if (ptr->fd != INVALID_SOCKET && ptr->root->sasl.callbacks) - { - rc= memcached_sasl_authenticate_connection(ptr); - if (rc != MEMCACHED_SUCCESS) - { - (void)closesocket(ptr->fd); - ptr->fd= INVALID_SOCKET; - } - } -#endif - break; - case MEMCACHED_CONNECTION_UNIX_SOCKET: - rc= unix_socket_connect(ptr); - break; - case MEMCACHED_CONNECTION_MAX: - default: - WATCHPOINT_ASSERT(0); - } - - if (rc == MEMCACHED_SUCCESS) - { - ptr->server_failure_counter= 0; - ptr->next_retry= 0; - } - else - { - ptr->server_failure_counter++; - - set_last_disconnected_host(ptr); - } - - LIBMEMCACHED_MEMCACHED_CONNECT_END(); - - return rc; -} diff --git a/libmemcached/connect.cc b/libmemcached/connect.cc new file mode 100644 index 00000000..1914bc0f --- /dev/null +++ b/libmemcached/connect.cc @@ -0,0 +1,605 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2010 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include +#include +#include + +static memcached_return_t connect_poll(memcached_server_st *ptr) +{ + struct pollfd fds[1]; + fds[0].fd = ptr->fd; + fds[0].events = POLLOUT; + + int error; + size_t loop_max= 5; + + while (--loop_max) // Should only loop on cases of ERESTART or EINTR + { + error= poll(fds, 1, ptr->root->connect_timeout); + + switch (error) + { + case 1: + { + int err; + socklen_t len= sizeof (err); + (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len); + + // We check the value to see what happened wth the socket. + if (err == 0) + { + return MEMCACHED_SUCCESS; + } + else + { + ptr->cached_errno= errno; + + return MEMCACHED_ERRNO; + } + } + case 0: + return MEMCACHED_TIMEOUT; + default: // A real error occurred and we need to completely bail + WATCHPOINT_ERRNO(get_socket_errno()); + switch (get_socket_errno()) + { +#ifdef TARGET_OS_LINUX + case ERESTART: +#endif + case EINTR: + continue; + default: + if (fds[0].revents & POLLERR) + { + int err; + socklen_t len= sizeof (err); + (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len); + ptr->cached_errno= (err == 0) ? get_socket_errno() : err; + } + else + { + ptr->cached_errno= get_socket_errno(); + } + + (void)closesocket(ptr->fd); + ptr->fd= INVALID_SOCKET; + + return MEMCACHED_ERRNO; + } + } + } + + // This should only be possible from ERESTART or EINTR; + ptr->cached_errno= get_socket_errno(); + + return MEMCACHED_ERRNO; +} + +static memcached_return_t set_hostinfo(memcached_server_st *server) +{ + char str_port[NI_MAXSERV]; + + assert(! server->address_info); // We cover the case where a programming mistake has been made. + if (server->address_info) + { + freeaddrinfo(server->address_info); + server->address_info= NULL; + server->address_info_next= NULL; + } + + int length= snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port); + if (length >= NI_MAXSERV || length < 0) + return MEMCACHED_FAILURE; + + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + +#if 0 + hints.ai_family= AF_INET; +#endif + if (server->type == MEMCACHED_CONNECTION_UDP) + { + hints.ai_protocol= IPPROTO_UDP; + hints.ai_socktype= SOCK_DGRAM; + } + else + { + hints.ai_socktype= SOCK_STREAM; + hints.ai_protocol= IPPROTO_TCP; + } + + uint32_t counter= 5; + while (--counter) + { + int e= getaddrinfo(server->hostname, str_port, &hints, &server->address_info); + + if (e == 0) + { + break; + } + else if (e == EAI_AGAIN) + { +#ifndef WIN32 + struct timespec dream, rem; + + dream.tv_nsec= 1000; + dream.tv_sec= 0; + + nanosleep(&dream, &rem); +#endif + continue; + } + else + { + WATCHPOINT_STRING(server->hostname); + WATCHPOINT_STRING(gai_strerror(e)); + return MEMCACHED_HOST_LOOKUP_FAILURE; + } + } + + server->address_info_next= server->address_info; + + return MEMCACHED_SUCCESS; +} + +static inline memcached_return_t set_socket_nonblocking(memcached_server_st *ptr) +{ +#ifdef WIN32 + u_long arg = 1; + if (ioctlsocket(ptr->fd, FIONBIO, &arg) == SOCKET_ERROR) + { + ptr->cached_errno= get_socket_errno(); + return MEMCACHED_CONNECTION_FAILURE; + } +#else + int flags; + + do + { + flags= fcntl(ptr->fd, F_GETFL, 0); + } + while (flags == -1 && (errno == EINTR || errno == EAGAIN)); + + unlikely (flags == -1) + { + ptr->cached_errno= errno; + return MEMCACHED_CONNECTION_FAILURE; + } + else if ((flags & O_NONBLOCK) == 0) + { + int rval; + + do + { + rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK); + } + while (rval == -1 && (errno == EINTR || errno == EAGAIN)); + + unlikely (rval == -1) + { + ptr->cached_errno= errno; + return MEMCACHED_CONNECTION_FAILURE; + } + } +#endif + return MEMCACHED_SUCCESS; +} + +static memcached_return_t set_socket_options(memcached_server_st *ptr) +{ + WATCHPOINT_ASSERT(ptr->fd != -1); + + if (ptr->type == MEMCACHED_CONNECTION_UDP) + return MEMCACHED_SUCCESS; + +#ifdef HAVE_SNDTIMEO + if (ptr->root->snd_timeout) + { + int error; + struct timeval waittime; + + waittime.tv_sec= 0; + waittime.tv_usec= ptr->root->snd_timeout; + + error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO, + &waittime, (socklen_t)sizeof(struct timeval)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } +#endif + +#ifdef HAVE_RCVTIMEO + if (ptr->root->rcv_timeout) + { + int error; + struct timeval waittime; + + waittime.tv_sec= 0; + waittime.tv_usec= ptr->root->rcv_timeout; + + error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO, + &waittime, (socklen_t)sizeof(struct timeval)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } +#endif + + +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + { + int set = 1; + int error= setsockopt(ptr->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); + + // This is not considered a fatal error + if (error == -1) + { + WATCHPOINT_ERRNO(get_socket_errno()); + perror("setsockopt(SO_NOSIGPIPE)"); + } + } +#endif + + if (ptr->root->flags.no_block) + { + int error; + struct linger linger; + + linger.l_onoff= 1; + linger.l_linger= 0; /* By default on close() just drop the socket */ + error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER, + &linger, (socklen_t)sizeof(struct linger)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } + + if (ptr->root->flags.tcp_nodelay) + { + int flag= 1; + int error; + + error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY, + &flag, (socklen_t)sizeof(int)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } + + if (ptr->root->flags.tcp_keepalive) + { + int flag= 1; + int error; + + error= setsockopt(ptr->fd, SOL_SOCKET, SO_KEEPALIVE, + &flag, (socklen_t)sizeof(int)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } + +#ifdef TCP_KEEPIDLE + if (ptr->root->tcp_keepidle > 0) + { + int error; + + error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_KEEPIDLE, + &ptr->root->tcp_keepidle, (socklen_t)sizeof(int)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } +#endif + + if (ptr->root->send_size > 0) + { + int error; + + error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF, + &ptr->root->send_size, (socklen_t)sizeof(int)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } + + if (ptr->root->recv_size > 0) + { + int error; + + error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF, + &ptr->root->recv_size, (socklen_t)sizeof(int)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } + + + /* libmemcached will always use nonblocking IO to avoid write deadlocks */ + return set_socket_nonblocking(ptr); +} + +static memcached_return_t unix_socket_connect(memcached_server_st *ptr) +{ +#ifndef WIN32 + WATCHPOINT_ASSERT(ptr->fd == -1); + + if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + ptr->cached_errno= errno; + return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE; + } + + struct sockaddr_un servAddr; + + memset(&servAddr, 0, sizeof (struct sockaddr_un)); + servAddr.sun_family= AF_UNIX; + strncpy(servAddr.sun_path, ptr->hostname, sizeof(servAddr.sun_path)); /* Copy filename */ + +test_connect: + if (connect(ptr->fd, + (struct sockaddr *)&servAddr, + sizeof(servAddr)) < 0) + { + switch (errno) + { + case EINPROGRESS: + case EALREADY: + case EINTR: + goto test_connect; + case EISCONN: /* We were spinning waiting on connect */ + break; + default: + WATCHPOINT_ERRNO(errno); + ptr->cached_errno= errno; + return MEMCACHED_ERRNO; + } + } + + WATCHPOINT_ASSERT(ptr->fd != -1); + + return MEMCACHED_SUCCESS; +#else + (void)ptr; + return MEMCACHED_NOT_SUPPORTED; +#endif +} + +static memcached_return_t network_connect(memcached_server_st *ptr) +{ + bool timeout_error_occured= false; + + WATCHPOINT_ASSERT(ptr->fd == INVALID_SOCKET); + WATCHPOINT_ASSERT(ptr->cursor_active == 0); + + if (! ptr->address_info) + { + memcached_return_t rc= set_hostinfo(ptr); + if (rc != MEMCACHED_SUCCESS) + return rc; + } + + /* Create the socket */ + while (ptr->address_info_next && ptr->fd == INVALID_SOCKET) + { + /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */ + if (ptr->type == MEMCACHED_CONNECTION_UDP && ptr->address_info_next->ai_family != AF_INET) + { + ptr->address_info_next= ptr->address_info_next->ai_next; + continue; + } + + if ((ptr->fd= socket(ptr->address_info_next->ai_family, + ptr->address_info_next->ai_socktype, + ptr->address_info_next->ai_protocol)) < 0) + { + ptr->cached_errno= get_socket_errno(); + WATCHPOINT_ERRNO(get_socket_errno()); + return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE; + } + + (void)set_socket_options(ptr); + + /* connect to server */ + if ((connect(ptr->fd, ptr->address_info_next->ai_addr, ptr->address_info_next->ai_addrlen) != SOCKET_ERROR)) + { + break; // Success + } + + /* An error occurred */ + ptr->cached_errno= get_socket_errno(); + switch (ptr->cached_errno) + { + case EWOULDBLOCK: + case EINPROGRESS: // nonblocking mode - first return + case EALREADY: // nonblocking mode - subsequent returns + { + memcached_return_t rc; + rc= connect_poll(ptr); + + if (rc == MEMCACHED_TIMEOUT) + timeout_error_occured= true; + + if (rc == MEMCACHED_SUCCESS) + break; + } + + case EISCONN: // we are connected :-) + break; + + case EINTR: // Special case, we retry ai_addr + (void)closesocket(ptr->fd); + ptr->fd= INVALID_SOCKET; + continue; + + default: + (void)closesocket(ptr->fd); + ptr->fd= INVALID_SOCKET; + ptr->address_info_next= ptr->address_info_next->ai_next; + break; + } + } + + if (ptr->fd == INVALID_SOCKET) + { + WATCHPOINT_STRING("Never got a good file descriptor"); + + /* Failed to connect. schedule next retry */ + if (ptr->root->retry_timeout) + { + struct timeval next_time; + + if (gettimeofday(&next_time, NULL) == 0) + ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout; + } + + if (timeout_error_occured) + return MEMCACHED_TIMEOUT; + + return MEMCACHED_ERRNO; /* The last error should be from connect() */ + } + + return MEMCACHED_SUCCESS; /* The last error should be from connect() */ +} + +void set_last_disconnected_host(memcached_server_write_instance_st ptr) +{ + // const_cast + memcached_st *root= (memcached_st *)ptr->root; + +#if 0 + WATCHPOINT_STRING(ptr->hostname); + WATCHPOINT_NUMBER(ptr->port); + WATCHPOINT_ERRNO(ptr->cached_errno); +#endif + if (root->last_disconnected_server) + memcached_server_free(root->last_disconnected_server); + root->last_disconnected_server= memcached_server_clone(NULL, ptr); +} + +memcached_return_t memcached_connect(memcached_server_write_instance_st ptr) +{ + memcached_return_t rc= MEMCACHED_NO_SERVERS; + + if (ptr->fd != INVALID_SOCKET) + return MEMCACHED_SUCCESS; + + LIBMEMCACHED_MEMCACHED_CONNECT_START(); + + /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */ + WATCHPOINT_ASSERT(ptr->root); + if (ptr->root->retry_timeout && ptr->next_retry) + { + struct timeval curr_time; + + gettimeofday(&curr_time, NULL); + + // We should optimize this to remove the allocation if the server was + // the last server to die + if (ptr->next_retry > curr_time.tv_sec) + { + set_last_disconnected_host(ptr); + + return MEMCACHED_SERVER_MARKED_DEAD; + } + } + + // If we are over the counter failure, we just fail. Reject host only + // works if you have a set number of failures. + if (ptr->root->server_failure_limit && ptr->server_failure_counter >= ptr->root->server_failure_limit) + { + set_last_disconnected_host(ptr); + + // @todo fix this by fixing behavior to no longer make use of + // memcached_st + if (_is_auto_eject_host(ptr->root)) + { + run_distribution((memcached_st *)ptr->root); + } + + return MEMCACHED_SERVER_MARKED_DEAD; + } + + /* We need to clean up the multi startup piece */ + switch (ptr->type) + { + case MEMCACHED_CONNECTION_UNKNOWN: + WATCHPOINT_ASSERT(0); + rc= MEMCACHED_NOT_SUPPORTED; + break; + case MEMCACHED_CONNECTION_UDP: + case MEMCACHED_CONNECTION_TCP: + rc= network_connect(ptr); +#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT + if (ptr->fd != INVALID_SOCKET && ptr->root->sasl.callbacks) + { + rc= memcached_sasl_authenticate_connection(ptr); + if (rc != MEMCACHED_SUCCESS) + { + (void)closesocket(ptr->fd); + ptr->fd= INVALID_SOCKET; + } + } +#endif + break; + case MEMCACHED_CONNECTION_UNIX_SOCKET: + rc= unix_socket_connect(ptr); + break; + case MEMCACHED_CONNECTION_MAX: + default: + WATCHPOINT_ASSERT(0); + } + + if (rc == MEMCACHED_SUCCESS) + { + ptr->server_failure_counter= 0; + ptr->next_retry= 0; + } + else + { + ptr->server_failure_counter++; + + set_last_disconnected_host(ptr); + } + + LIBMEMCACHED_MEMCACHED_CONNECT_END(); + + return rc; +} diff --git a/libmemcached/constants.h b/libmemcached/constants.h index b4a87257..3fe44739 100644 --- a/libmemcached/constants.h +++ b/libmemcached/constants.h @@ -30,61 +30,6 @@ #define MEMCACHED_VERSION_STRING_LENGTH 24 -enum memcached_return_t { - MEMCACHED_SUCCESS, - MEMCACHED_FAILURE, - MEMCACHED_HOST_LOOKUP_FAILURE, - MEMCACHED_CONNECTION_FAILURE, - MEMCACHED_CONNECTION_BIND_FAILURE, - MEMCACHED_WRITE_FAILURE, - MEMCACHED_READ_FAILURE, - MEMCACHED_UNKNOWN_READ_FAILURE, - MEMCACHED_PROTOCOL_ERROR, - MEMCACHED_CLIENT_ERROR, - MEMCACHED_SERVER_ERROR, - MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE, - MEMCACHED_DATA_EXISTS, - MEMCACHED_DATA_DOES_NOT_EXIST, - MEMCACHED_NOTSTORED, - MEMCACHED_STORED, - MEMCACHED_NOTFOUND, - MEMCACHED_MEMORY_ALLOCATION_FAILURE, - MEMCACHED_PARTIAL_READ, - MEMCACHED_SOME_ERRORS, - MEMCACHED_NO_SERVERS, - MEMCACHED_END, - MEMCACHED_DELETED, - MEMCACHED_VALUE, - MEMCACHED_STAT, - MEMCACHED_ITEM, - MEMCACHED_ERRNO, - MEMCACHED_FAIL_UNIX_SOCKET, - MEMCACHED_NOT_SUPPORTED, - MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */ - MEMCACHED_FETCH_NOTFINISHED, - MEMCACHED_TIMEOUT, - MEMCACHED_BUFFERED, - MEMCACHED_BAD_KEY_PROVIDED, - MEMCACHED_INVALID_HOST_PROTOCOL, - MEMCACHED_SERVER_MARKED_DEAD, - MEMCACHED_UNKNOWN_STAT_KEY, - MEMCACHED_E2BIG, - MEMCACHED_INVALID_ARGUMENTS, - MEMCACHED_KEY_TOO_BIG, - MEMCACHED_AUTH_PROBLEM, - MEMCACHED_AUTH_FAILURE, - MEMCACHED_AUTH_CONTINUE, - MEMCACHED_PARSE_ERROR, - MEMCACHED_PARSE_USER_ERROR, - MEMCACHED_DEPRECATED, - MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */ -}; - -#ifndef __cplusplus -typedef enum memcached_return_t memcached_return_t; -#endif - - enum memcached_server_distribution_t { MEMCACHED_DISTRIBUTION_MODULA, MEMCACHED_DISTRIBUTION_CONSISTENT, diff --git a/libmemcached/delete.c b/libmemcached/delete.c deleted file mode 100644 index 78f08f26..00000000 --- a/libmemcached/delete.c +++ /dev/null @@ -1,260 +0,0 @@ -/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: - * - * Libmemcached library - * - * Copyright (C) 2011 Data Differential, http://datadifferential.com/ - * Copyright (C) 2006-2009 Brian Aker All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * * The names of its contributors may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length, - time_t expiration) -{ - return memcached_delete_by_key(ptr, key, key_length, - key, key_length, expiration); -} - -static inline memcached_return_t binary_delete(memcached_st *ptr, - uint32_t server_key, - const char *key, - size_t key_length, - bool flush); - -memcached_return_t memcached_delete_by_key(memcached_st *ptr, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - time_t expiration) -{ - bool to_write; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - uint32_t server_key; - memcached_server_write_instance_st instance; - - LIBMEMCACHED_MEMCACHED_DELETE_START(); - - memcached_return_t rc; - if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS) - { - return rc; - } - - rc= memcached_validate_key_length(key_length, - ptr->flags.binary_protocol); - unlikely (rc != MEMCACHED_SUCCESS) - return rc; - - unlikely (memcached_server_count(ptr) == 0) - return MEMCACHED_NO_SERVERS; - - server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); - instance= memcached_server_instance_fetch(ptr, server_key); - - to_write= (ptr->flags.buffer_requests) ? false : true; - - bool no_reply= (ptr->flags.no_reply); - - if (ptr->flags.binary_protocol) - { - likely (! expiration) - { - rc= binary_delete(ptr, server_key, key, key_length, to_write); - } - else - { - rc= MEMCACHED_INVALID_ARGUMENTS; - } - } - else - { - int send_length; - - unlikely (expiration) - { - if ((instance->major_version == 1 && - instance->minor_version > 2) || - instance->major_version > 1) - { - rc= MEMCACHED_INVALID_ARGUMENTS; - goto error; - } - else - { - /* ensure that we are connected, otherwise we might bump the - * command counter before connection */ - if ((rc= memcached_connect(instance)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return rc; - } - - if (instance->minor_version == 0) - { - if (no_reply || ! to_write) - { - /* We might get out of sync with the server if we - * send this command to a server newer than 1.2.x.. - * disable no_reply and buffered mode. - */ - to_write= true; - if (no_reply) - memcached_server_response_increment(instance); - no_reply= false; - } - } - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "delete %.*s%.*s %u%s\r\n", - memcached_print_array(ptr->prefix_key), - (int) key_length, key, - (uint32_t)expiration, - no_reply ? " noreply" :"" ); - } - } - else - { - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "delete %.*s%.*s%s\r\n", - memcached_print_array(ptr->prefix_key), - (int)key_length, key, no_reply ? " noreply" :""); - } - - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) - { - rc= MEMCACHED_WRITE_FAILURE; - goto error; - } - - if (ptr->flags.use_udp && ! to_write) - { - if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) - return MEMCACHED_WRITE_FAILURE; - if (send_length + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) - memcached_io_write(instance, NULL, 0, true); - } - - rc= memcached_do(instance, buffer, (size_t)send_length, to_write); - } - - if (rc != MEMCACHED_SUCCESS) - goto error; - - if (! to_write) - { - rc= MEMCACHED_BUFFERED; - } - else if (!no_reply) - { - rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - if (rc == MEMCACHED_DELETED) - rc= MEMCACHED_SUCCESS; - } - - if (rc == MEMCACHED_SUCCESS && ptr->delete_trigger) - ptr->delete_trigger(ptr, key, key_length); - -error: - LIBMEMCACHED_MEMCACHED_DELETE_END(); - return rc; -} - -static inline memcached_return_t binary_delete(memcached_st *ptr, - uint32_t server_key, - const char *key, - size_t key_length, - bool flush) -{ - memcached_server_write_instance_st instance; - protocol_binary_request_delete request= {.bytes= {0}}; - - instance= memcached_server_instance_fetch(ptr, server_key); - - request.message.header.request.magic= PROTOCOL_BINARY_REQ; - if (ptr->flags.no_reply) - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ; - else - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE; - request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key))); - request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key))); - - if (ptr->flags.use_udp && ! flush) - { - size_t cmd_size= sizeof(request.bytes) + key_length; - if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) - return MEMCACHED_WRITE_FAILURE; - if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) - memcached_io_write(instance, NULL, 0, true); - } - - struct libmemcached_io_vector_st vector[]= - { - { .length= sizeof(request.bytes), .buffer= request.bytes}, - { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) }, - { .length= key_length, .buffer= key }, - }; - - memcached_return_t rc= MEMCACHED_SUCCESS; - - if ((rc= memcached_vdo(instance, vector, 3, flush)) != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - rc= (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc; - } - - unlikely (ptr->number_of_replicas > 0) - { - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ; - - for (uint32_t x= 0; x < ptr->number_of_replicas; ++x) - { - memcached_server_write_instance_st replica; - - ++server_key; - if (server_key == memcached_server_count(ptr)) - server_key= 0; - - replica= memcached_server_instance_fetch(ptr, server_key); - - if (memcached_vdo(replica, vector, 3, flush) != MEMCACHED_SUCCESS) - { - memcached_io_reset(replica); - } - else - { - memcached_server_response_decrement(replica); - } - } - } - - return rc; -} diff --git a/libmemcached/delete.cc b/libmemcached/delete.cc new file mode 100644 index 00000000..1005cb90 --- /dev/null +++ b/libmemcached/delete.cc @@ -0,0 +1,264 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length, + time_t expiration) +{ + return memcached_delete_by_key(ptr, key, key_length, + key, key_length, expiration); +} + +static inline memcached_return_t binary_delete(memcached_st *ptr, + uint32_t server_key, + const char *key, + size_t key_length, + bool flush); + +memcached_return_t memcached_delete_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + time_t expiration) +{ + bool to_write; + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + uint32_t server_key; + memcached_server_write_instance_st instance; + + LIBMEMCACHED_MEMCACHED_DELETE_START(); + + memcached_return_t rc; + if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS) + { + return rc; + } + + rc= memcached_validate_key_length(key_length, + ptr->flags.binary_protocol); + unlikely (rc != MEMCACHED_SUCCESS) + return rc; + + unlikely (memcached_server_count(ptr) == 0) + return MEMCACHED_NO_SERVERS; + + server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + instance= memcached_server_instance_fetch(ptr, server_key); + + to_write= (ptr->flags.buffer_requests) ? false : true; + + bool no_reply= (ptr->flags.no_reply); + + if (ptr->flags.binary_protocol) + { + likely (! expiration) + { + rc= binary_delete(ptr, server_key, key, key_length, to_write); + } + else + { + rc= MEMCACHED_INVALID_ARGUMENTS; + } + } + else + { + int send_length; + + unlikely (expiration) + { + if ((instance->major_version == 1 && + instance->minor_version > 2) || + instance->major_version > 1) + { + rc= MEMCACHED_INVALID_ARGUMENTS; + goto error; + } + else + { + /* ensure that we are connected, otherwise we might bump the + * command counter before connection */ + if ((rc= memcached_connect(instance)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return rc; + } + + if (instance->minor_version == 0) + { + if (no_reply || ! to_write) + { + /* We might get out of sync with the server if we + * send this command to a server newer than 1.2.x.. + * disable no_reply and buffered mode. + */ + to_write= true; + if (no_reply) + memcached_server_response_increment(instance); + no_reply= false; + } + } + send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "delete %.*s%.*s %u%s\r\n", + memcached_print_array(ptr->prefix_key), + (int) key_length, key, + (uint32_t)expiration, + no_reply ? " noreply" :"" ); + } + } + else + { + send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "delete %.*s%.*s%s\r\n", + memcached_print_array(ptr->prefix_key), + (int)key_length, key, no_reply ? " noreply" :""); + } + + if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + { + rc= MEMCACHED_WRITE_FAILURE; + goto error; + } + + if (ptr->flags.use_udp && ! to_write) + { + if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) + return MEMCACHED_WRITE_FAILURE; + if (send_length + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) + memcached_io_write(instance, NULL, 0, true); + } + + rc= memcached_do(instance, buffer, (size_t)send_length, to_write); + } + + if (rc != MEMCACHED_SUCCESS) + goto error; + + if (! to_write) + { + rc= MEMCACHED_BUFFERED; + } + else if (!no_reply) + { + rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + if (rc == MEMCACHED_DELETED) + rc= MEMCACHED_SUCCESS; + } + + if (rc == MEMCACHED_SUCCESS && ptr->delete_trigger) + ptr->delete_trigger(ptr, key, key_length); + +error: + LIBMEMCACHED_MEMCACHED_DELETE_END(); + return rc; +} + +static inline memcached_return_t binary_delete(memcached_st *ptr, + uint32_t server_key, + const char *key, + size_t key_length, + bool flush) +{ + memcached_server_write_instance_st instance; + protocol_binary_request_delete request= {}; + + instance= memcached_server_instance_fetch(ptr, server_key); + + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + if (ptr->flags.no_reply) + { + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ; + } + else + { + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE; + } + request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key))); + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key))); + + if (ptr->flags.use_udp && ! flush) + { + size_t cmd_size= sizeof(request.bytes) + key_length; + if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) + return MEMCACHED_WRITE_FAILURE; + if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) + memcached_io_write(instance, NULL, 0, true); + } + + struct libmemcached_io_vector_st vector[]= + { + { sizeof(request.bytes), request.bytes}, + { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) }, + { key_length, key }, + }; + + memcached_return_t rc= MEMCACHED_SUCCESS; + + if ((rc= memcached_vdo(instance, vector, 3, flush)) != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + rc= (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc; + } + + unlikely (ptr->number_of_replicas > 0) + { + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ; + + for (uint32_t x= 0; x < ptr->number_of_replicas; ++x) + { + memcached_server_write_instance_st replica; + + ++server_key; + if (server_key == memcached_server_count(ptr)) + server_key= 0; + + replica= memcached_server_instance_fetch(ptr, server_key); + + if (memcached_vdo(replica, vector, 3, flush) != MEMCACHED_SUCCESS) + { + memcached_io_reset(replica); + } + else + { + memcached_server_response_decrement(replica); + } + } + } + + return rc; +} diff --git a/libmemcached/delete.h b/libmemcached/delete.h index 8d0d7eda..617d5857 100644 --- a/libmemcached/delete.h +++ b/libmemcached/delete.h @@ -1,16 +1,42 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. * - * Summary: Delete a key from the server. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_DELETE_H__ -#define __LIBMEMCACHED_DELETE_H__ + +#pragma once #ifdef __cplusplus extern "C" { @@ -29,5 +55,3 @@ memcached_return_t memcached_delete_by_key(memcached_st *ptr, #ifdef __cplusplus } #endif - -#endif /* __LIBMEMCACHED_DELETE_H__ */ diff --git a/libmemcached/do.c b/libmemcached/do.c deleted file mode 100644 index 14824a64..00000000 --- a/libmemcached/do.c +++ /dev/null @@ -1,99 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2010 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - -#include "common.h" - -memcached_return_t memcached_do(memcached_server_write_instance_st ptr, const void *command, - size_t command_length, bool with_flush) -{ - memcached_return_t rc; - ssize_t sent_length; - - WATCHPOINT_ASSERT(command_length); - WATCHPOINT_ASSERT(command); - - if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return rc; - } - - /* - ** Since non buffering ops in UDP mode dont check to make sure they will fit - ** before they start writing, if there is any data in buffer, clear it out, - ** otherwise we might get a partial write. - **/ - if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH) - { - memcached_io_write(ptr, NULL, 0, true); - } - - sent_length= memcached_io_write(ptr, command, command_length, with_flush); - - if (sent_length == -1 || (size_t)sent_length != command_length) - { - rc= MEMCACHED_WRITE_FAILURE; - } - else if ((ptr->root->flags.no_reply) == 0) - { - memcached_server_response_increment(ptr); - } - - return rc; -} - -memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr, - const struct libmemcached_io_vector_st *vector, size_t count, - bool with_flush) -{ - memcached_return_t rc; - ssize_t sent_length; - - WATCHPOINT_ASSERT(count); - WATCHPOINT_ASSERT(vector); - - if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return rc; - } - - /* - ** Since non buffering ops in UDP mode dont check to make sure they will fit - ** before they start writing, if there is any data in buffer, clear it out, - ** otherwise we might get a partial write. - **/ - if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH) - { - memcached_io_write(ptr, NULL, 0, true); - } - - sent_length= memcached_io_writev(ptr, vector, count, with_flush); - - size_t command_length= 0; - for (uint32_t x= 0; x < count; ++x, vector++) - { - command_length+= vector->length; - } - - if (sent_length == -1 || (size_t)sent_length != command_length) - { - rc= MEMCACHED_WRITE_FAILURE; - WATCHPOINT_ERROR(rc); - WATCHPOINT_ERRNO(errno); - } - else if ((ptr->root->flags.no_reply) == 0) - { - memcached_server_response_increment(ptr); - } - - return rc; -} diff --git a/libmemcached/do.cc b/libmemcached/do.cc new file mode 100644 index 00000000..14824a64 --- /dev/null +++ b/libmemcached/do.cc @@ -0,0 +1,99 @@ +/* LibMemcached + * Copyright (C) 2006-2010 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ + +#include "common.h" + +memcached_return_t memcached_do(memcached_server_write_instance_st ptr, const void *command, + size_t command_length, bool with_flush) +{ + memcached_return_t rc; + ssize_t sent_length; + + WATCHPOINT_ASSERT(command_length); + WATCHPOINT_ASSERT(command); + + if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return rc; + } + + /* + ** Since non buffering ops in UDP mode dont check to make sure they will fit + ** before they start writing, if there is any data in buffer, clear it out, + ** otherwise we might get a partial write. + **/ + if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH) + { + memcached_io_write(ptr, NULL, 0, true); + } + + sent_length= memcached_io_write(ptr, command, command_length, with_flush); + + if (sent_length == -1 || (size_t)sent_length != command_length) + { + rc= MEMCACHED_WRITE_FAILURE; + } + else if ((ptr->root->flags.no_reply) == 0) + { + memcached_server_response_increment(ptr); + } + + return rc; +} + +memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr, + const struct libmemcached_io_vector_st *vector, size_t count, + bool with_flush) +{ + memcached_return_t rc; + ssize_t sent_length; + + WATCHPOINT_ASSERT(count); + WATCHPOINT_ASSERT(vector); + + if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return rc; + } + + /* + ** Since non buffering ops in UDP mode dont check to make sure they will fit + ** before they start writing, if there is any data in buffer, clear it out, + ** otherwise we might get a partial write. + **/ + if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH) + { + memcached_io_write(ptr, NULL, 0, true); + } + + sent_length= memcached_io_writev(ptr, vector, count, with_flush); + + size_t command_length= 0; + for (uint32_t x= 0; x < count; ++x, vector++) + { + command_length+= vector->length; + } + + if (sent_length == -1 || (size_t)sent_length != command_length) + { + rc= MEMCACHED_WRITE_FAILURE; + WATCHPOINT_ERROR(rc); + WATCHPOINT_ERRNO(errno); + } + else if ((ptr->root->flags.no_reply) == 0) + { + memcached_server_response_increment(ptr); + } + + return rc; +} diff --git a/libmemcached/dump.c b/libmemcached/dump.c deleted file mode 100644 index 18c15974..00000000 --- a/libmemcached/dump.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - We use this to dump all keys. - - At this point we only support a callback method. This could be optimized by first - calling items and finding active slabs. For the moment though we just loop through - all slabs on servers and "grab" the keys. -*/ - -#include "common.h" -static memcached_return_t ascii_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks) -{ - memcached_return_t rc= MEMCACHED_SUCCESS; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - uint32_t server_key; - uint32_t x; - - unlikely (memcached_server_count(ptr) == 0) - return MEMCACHED_NO_SERVERS; - - for (server_key= 0; server_key < memcached_server_count(ptr); server_key++) - { - memcached_server_write_instance_st instance; - instance= memcached_server_instance_fetch(ptr, server_key); - - /* 256 I BELIEVE is the upper limit of slabs */ - for (x= 0; x < 256; x++) - { - int send_length; - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "stats cachedump %u 0 0\r\n", x); - - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) - { - return MEMCACHED_FAILURE; - } - - rc= memcached_do(instance, buffer, (size_t)send_length, true); - - unlikely (rc != MEMCACHED_SUCCESS) - goto error; - - while (1) - { - uint32_t callback_counter; - rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - - if (rc == MEMCACHED_ITEM) - { - char *string_ptr, *end_ptr; - char *key; - - string_ptr= buffer; - string_ptr+= 5; /* Move past ITEM */ - for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++); - key= string_ptr; - key[(size_t)(end_ptr-string_ptr)]= 0; - for (callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++) - { - rc= (*callback[callback_counter])(ptr, key, (size_t)(end_ptr-string_ptr), context); - if (rc != MEMCACHED_SUCCESS) - break; - } - } - else if (rc == MEMCACHED_END) - break; - else if (rc == MEMCACHED_SERVER_ERROR || rc == MEMCACHED_CLIENT_ERROR) - { - /* If we try to request stats cachedump for a slab class that is too big - * the server will return an incorrect error message: - * "MEMCACHED_SERVER_ERROR failed to allocate memory" - * This isn't really a fatal error, so let's just skip it. I want to - * fix the return value from the memcached server to a CLIENT_ERROR, - * so let's add support for that as well right now. - */ - rc= MEMCACHED_END; - break; - } - else - goto error; - } - } - } - -error: - if (rc == MEMCACHED_END) - return MEMCACHED_SUCCESS; - else - return rc; -} - -memcached_return_t memcached_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks) -{ - memcached_return_t rc; - if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS) - { - return rc; - } - - /* - No support for Binary protocol yet - @todo Fix this so that we just flush, switch to ascii, and then go back to binary. - */ - if (ptr->flags.binary_protocol) - return MEMCACHED_FAILURE; - - return ascii_dump(ptr, callback, context, number_of_callbacks); -} diff --git a/libmemcached/dump.cc b/libmemcached/dump.cc new file mode 100644 index 00000000..18c15974 --- /dev/null +++ b/libmemcached/dump.cc @@ -0,0 +1,107 @@ +/* + We use this to dump all keys. + + At this point we only support a callback method. This could be optimized by first + calling items and finding active slabs. For the moment though we just loop through + all slabs on servers and "grab" the keys. +*/ + +#include "common.h" +static memcached_return_t ascii_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks) +{ + memcached_return_t rc= MEMCACHED_SUCCESS; + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + uint32_t server_key; + uint32_t x; + + unlikely (memcached_server_count(ptr) == 0) + return MEMCACHED_NO_SERVERS; + + for (server_key= 0; server_key < memcached_server_count(ptr); server_key++) + { + memcached_server_write_instance_st instance; + instance= memcached_server_instance_fetch(ptr, server_key); + + /* 256 I BELIEVE is the upper limit of slabs */ + for (x= 0; x < 256; x++) + { + int send_length; + send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "stats cachedump %u 0 0\r\n", x); + + if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + { + return MEMCACHED_FAILURE; + } + + rc= memcached_do(instance, buffer, (size_t)send_length, true); + + unlikely (rc != MEMCACHED_SUCCESS) + goto error; + + while (1) + { + uint32_t callback_counter; + rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + + if (rc == MEMCACHED_ITEM) + { + char *string_ptr, *end_ptr; + char *key; + + string_ptr= buffer; + string_ptr+= 5; /* Move past ITEM */ + for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++); + key= string_ptr; + key[(size_t)(end_ptr-string_ptr)]= 0; + for (callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++) + { + rc= (*callback[callback_counter])(ptr, key, (size_t)(end_ptr-string_ptr), context); + if (rc != MEMCACHED_SUCCESS) + break; + } + } + else if (rc == MEMCACHED_END) + break; + else if (rc == MEMCACHED_SERVER_ERROR || rc == MEMCACHED_CLIENT_ERROR) + { + /* If we try to request stats cachedump for a slab class that is too big + * the server will return an incorrect error message: + * "MEMCACHED_SERVER_ERROR failed to allocate memory" + * This isn't really a fatal error, so let's just skip it. I want to + * fix the return value from the memcached server to a CLIENT_ERROR, + * so let's add support for that as well right now. + */ + rc= MEMCACHED_END; + break; + } + else + goto error; + } + } + } + +error: + if (rc == MEMCACHED_END) + return MEMCACHED_SUCCESS; + else + return rc; +} + +memcached_return_t memcached_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks) +{ + memcached_return_t rc; + if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS) + { + return rc; + } + + /* + No support for Binary protocol yet + @todo Fix this so that we just flush, switch to ascii, and then go back to binary. + */ + if (ptr->flags.binary_protocol) + return MEMCACHED_FAILURE; + + return ascii_dump(ptr, callback, context, number_of_callbacks); +} diff --git a/libmemcached/error.cc b/libmemcached/error.cc index ef207a95..02169a28 100644 --- a/libmemcached/error.cc +++ b/libmemcached/error.cc @@ -139,7 +139,7 @@ void memcached_error_print(const memcached_st *self) static void _error_free(memcached_error_t *error) { - if (! error) + if (not error) return; _error_free(error->next); @@ -156,10 +156,11 @@ static void _error_free(memcached_error_t *error) void memcached_error_free(memcached_st *self) { - if (! self) + if (not self) return; _error_free(self->error_messages); + self->error_messages= NULL; } const char *memcached_last_error_message(memcached_st *memc) diff --git a/libmemcached/flush.c b/libmemcached/flush.c deleted file mode 100644 index 8da6b5b5..00000000 --- a/libmemcached/flush.c +++ /dev/null @@ -1,113 +0,0 @@ -#include "common.h" - -static memcached_return_t memcached_flush_binary(memcached_st *ptr, - time_t expiration); -static memcached_return_t memcached_flush_textual(memcached_st *ptr, - time_t expiration); - -memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration) -{ - memcached_return_t rc; - if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS) - { - return rc; - } - - LIBMEMCACHED_MEMCACHED_FLUSH_START(); - if (ptr->flags.binary_protocol) - rc= memcached_flush_binary(ptr, expiration); - else - rc= memcached_flush_textual(ptr, expiration); - LIBMEMCACHED_MEMCACHED_FLUSH_END(); - return rc; -} - -static memcached_return_t memcached_flush_textual(memcached_st *ptr, - time_t expiration) -{ - unlikely (memcached_server_count(ptr) == 0) - return MEMCACHED_NO_SERVERS; - - for (unsigned int x= 0; x < memcached_server_count(ptr); x++) - { - memcached_return_t rc; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - - bool no_reply= ptr->flags.no_reply; - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - int send_length; - if (expiration) - { - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "flush_all %llu%s\r\n", - (unsigned long long)expiration, no_reply ? " noreply" : ""); - } - else - { - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "flush_all%s\r\n", no_reply ? " noreply" : ""); - } - - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) - { - return MEMCACHED_FAILURE; - } - - rc= memcached_do(instance, buffer, (size_t)send_length, true); - - if (rc == MEMCACHED_SUCCESS && !no_reply) - (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - } - - return MEMCACHED_SUCCESS; -} - -static memcached_return_t memcached_flush_binary(memcached_st *ptr, - time_t expiration) -{ - protocol_binary_request_flush request= {.bytes= {0}}; - - unlikely (memcached_server_count(ptr) == 0) - return MEMCACHED_NO_SERVERS; - - request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ; - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH; - request.message.header.request.extlen= 4; - request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - request.message.header.request.bodylen= htonl(request.message.header.request.extlen); - request.message.body.expiration= htonl((uint32_t) expiration); - - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - if (ptr->flags.no_reply) - { - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ; - } - else - { - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH; - } - - if (memcached_do(instance, request.bytes, sizeof(request.bytes), true) != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - return MEMCACHED_WRITE_FAILURE; - } - } - - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - if (memcached_server_response_count(instance) > 0) - (void)memcached_response(instance, NULL, 0, NULL); - } - - return MEMCACHED_SUCCESS; -} diff --git a/libmemcached/flush.cc b/libmemcached/flush.cc new file mode 100644 index 00000000..6a1364c2 --- /dev/null +++ b/libmemcached/flush.cc @@ -0,0 +1,149 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +static memcached_return_t memcached_flush_binary(memcached_st *ptr, + time_t expiration); +static memcached_return_t memcached_flush_textual(memcached_st *ptr, + time_t expiration); + +memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration) +{ + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr))) + { + return rc; + } + + LIBMEMCACHED_MEMCACHED_FLUSH_START(); + if (ptr->flags.binary_protocol) + rc= memcached_flush_binary(ptr, expiration); + else + rc= memcached_flush_textual(ptr, expiration); + LIBMEMCACHED_MEMCACHED_FLUSH_END(); + return rc; +} + +static memcached_return_t memcached_flush_textual(memcached_st *ptr, + time_t expiration) +{ + unlikely (memcached_server_count(ptr) == 0) + return MEMCACHED_NO_SERVERS; + + for (unsigned int x= 0; x < memcached_server_count(ptr); x++) + { + memcached_return_t rc; + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + + bool no_reply= ptr->flags.no_reply; + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + int send_length; + if (expiration) + { + send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "flush_all %llu%s\r\n", + (unsigned long long)expiration, no_reply ? " noreply" : ""); + } + else + { + send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "flush_all%s\r\n", no_reply ? " noreply" : ""); + } + + if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + { + return MEMCACHED_FAILURE; + } + + rc= memcached_do(instance, buffer, (size_t)send_length, true); + + if (rc == MEMCACHED_SUCCESS && !no_reply) + (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + } + + return MEMCACHED_SUCCESS; +} + +static memcached_return_t memcached_flush_binary(memcached_st *ptr, + time_t expiration) +{ + protocol_binary_request_flush request= {}; + + unlikely (memcached_server_count(ptr) == 0) + return MEMCACHED_NO_SERVERS; + + request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH; + request.message.header.request.extlen= 4; + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + request.message.header.request.bodylen= htonl(request.message.header.request.extlen); + request.message.body.expiration= htonl((uint32_t) expiration); + + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + if (ptr->flags.no_reply) + { + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ; + } + else + { + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH; + } + + if (memcached_do(instance, request.bytes, sizeof(request.bytes), true) != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + return MEMCACHED_WRITE_FAILURE; + } + } + + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + if (memcached_server_response_count(instance) > 0) + (void)memcached_response(instance, NULL, 0, NULL); + } + + return MEMCACHED_SUCCESS; +} diff --git a/libmemcached/flush.h b/libmemcached/flush.h index 36c07598..820a98e7 100644 --- a/libmemcached/flush.h +++ b/libmemcached/flush.h @@ -1,16 +1,41 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. * - * Summary: Flush connections. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_FLUSH_H__ -#define __LIBMEMCACHED_FLUSH_H__ +#pragma once #ifdef __cplusplus extern "C" { @@ -22,5 +47,3 @@ memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration); #ifdef __cplusplus } #endif - -#endif /* __LIBMEMCACHED_FLUSH_H__ */ diff --git a/libmemcached/flush_buffers.c b/libmemcached/flush_buffers.c deleted file mode 100644 index 649db983..00000000 --- a/libmemcached/flush_buffers.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "common.h" - -memcached_return_t memcached_flush_buffers(memcached_st *memc) -{ - memcached_return_t ret= MEMCACHED_SUCCESS; - - for (uint32_t x= 0; x < memcached_server_count(memc); ++x) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(memc, x); - - if (instance->write_buffer_offset != 0) - { - if (instance->fd == -1 && - (ret= memcached_connect(instance)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(ret); - return ret; - } - - if (memcached_io_write(instance, NULL, 0, true) == -1) - { - ret= MEMCACHED_SOME_ERRORS; - } - } - } - - return ret; -} diff --git a/libmemcached/flush_buffers.cc b/libmemcached/flush_buffers.cc new file mode 100644 index 00000000..bb3c4dec --- /dev/null +++ b/libmemcached/flush_buffers.cc @@ -0,0 +1,66 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +memcached_return_t memcached_flush_buffers(memcached_st *memc) +{ + memcached_return_t ret= MEMCACHED_SUCCESS; + + for (uint32_t x= 0; x < memcached_server_count(memc); ++x) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(memc, x); + + if (instance->write_buffer_offset != 0) + { + if (instance->fd == -1 && + (ret= memcached_connect(instance)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(ret); + return ret; + } + + if (memcached_io_write(instance, NULL, 0, true) == -1) + { + ret= MEMCACHED_SOME_ERRORS; + } + } + } + + return ret; +} diff --git a/libmemcached/flush_buffers.h b/libmemcached/flush_buffers.h index 88d8a81c..31b58687 100644 --- a/libmemcached/flush_buffers.h +++ b/libmemcached/flush_buffers.h @@ -1,16 +1,41 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. * - * Summary: Work with fetching results + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_FLUSH_BUFFERS_H__ -#define __LIBMEMCACHED_FLUSH_BUFFERS_H__ +#pragma once #ifdef __cplusplus extern "C" { @@ -22,5 +47,3 @@ memcached_return_t memcached_flush_buffers(memcached_st *mem); #ifdef __cplusplus } #endif - -#endif /* __LIBMEMCACHED_FLUSH_BUFFERS_H__ */ diff --git a/libmemcached/get.c b/libmemcached/get.c deleted file mode 100644 index 46b6319c..00000000 --- a/libmemcached/get.c +++ /dev/null @@ -1,648 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: Get functions for libmemcached - * - */ - -#include "common.h" - -/* - What happens if no servers exist? -*/ -char *memcached_get(memcached_st *ptr, const char *key, - size_t key_length, - size_t *value_length, - uint32_t *flags, - memcached_return_t *error) -{ - return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length, - flags, error); -} - -static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr, - const char *group_key, - size_t group_key_length, - const char * const *keys, - const size_t *key_length, - size_t number_of_keys, - bool mget_mode); - -char *memcached_get_by_key(memcached_st *ptr, - const char *group_key, - size_t group_key_length, - const char *key, size_t key_length, - size_t *value_length, - uint32_t *flags, - memcached_return_t *error) -{ - char *value; - size_t dummy_length; - uint32_t dummy_flags; - memcached_return_t dummy_error; - - unlikely (ptr->flags.use_udp) - { - *error= MEMCACHED_NOT_SUPPORTED; - return NULL; - } - - /* Request the key */ - *error= memcached_mget_by_key_real(ptr, group_key, group_key_length, - (const char * const *)&key, - &key_length, 1, false); - - value= memcached_fetch(ptr, NULL, NULL, - value_length, flags, error); - /* This is for historical reasons */ - if (*error == MEMCACHED_END) - *error= MEMCACHED_NOTFOUND; - - if (value == NULL) - { - if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND) - { - memcached_return_t rc; - - memcached_result_reset(&ptr->result); - rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result); - - /* On all failure drop to returning NULL */ - if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) - { - if (rc == MEMCACHED_BUFFERED) - { - uint64_t latch; /* We use latch to track the state of the original socket */ - latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS); - if (latch == 0) - memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1); - - rc= memcached_set(ptr, key, key_length, - (memcached_result_value(&ptr->result)), - (memcached_result_length(&ptr->result)), - 0, - (memcached_result_flags(&ptr->result))); - - if (rc == MEMCACHED_BUFFERED && latch == 0) - memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0); - } - else - { - rc= memcached_set(ptr, key, key_length, - (memcached_result_value(&ptr->result)), - (memcached_result_length(&ptr->result)), - 0, - (memcached_result_flags(&ptr->result))); - } - - if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) - { - *error= rc; - *value_length= memcached_result_length(&ptr->result); - *flags= memcached_result_flags(&ptr->result); - return memcached_string_c_copy(&ptr->result.value); - } - } - } - - return NULL; - } - - (void)memcached_fetch(ptr, NULL, NULL, - &dummy_length, &dummy_flags, - &dummy_error); - WATCHPOINT_ASSERT(dummy_length == 0); - - return value; -} - -memcached_return_t memcached_mget(memcached_st *ptr, - const char * const *keys, - const size_t *key_length, - size_t number_of_keys) -{ - return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys); -} - -static memcached_return_t binary_mget_by_key(memcached_st *ptr, - uint32_t master_server_key, - bool is_group_key_set, - const char * const *keys, - const size_t *key_length, - size_t number_of_keys, - bool mget_mode); - -static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr, - const char *group_key, - size_t group_key_length, - const char * const *keys, - const size_t *key_length, - size_t number_of_keys, - bool mget_mode) -{ - bool failures_occured_in_sending= false; - const char *get_command= "get "; - uint8_t get_command_length= 4; - unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */ - bool is_group_key_set= false; - - memcached_return_t rc; - if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS) - { - return rc; - } - - unlikely (ptr->flags.use_udp) - return MEMCACHED_NOT_SUPPORTED; - - LIBMEMCACHED_MEMCACHED_MGET_START(); - - if (number_of_keys == 0) - return MEMCACHED_NOTFOUND; - - if (ptr->flags.verify_key && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED)) - return MEMCACHED_BAD_KEY_PROVIDED; - - if (group_key && group_key_length) - { - if (ptr->flags.verify_key && (memcached_key_test((const char * const *)&group_key, &group_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)) - return MEMCACHED_BAD_KEY_PROVIDED; - master_server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); - is_group_key_set= true; - } - - /* - Here is where we pay for the non-block API. We need to remove any data sitting - in the queue before we start our get. - - It might be optimum to bounce the connection if count > some number. - */ - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - if (memcached_server_response_count(instance)) - { - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - - if (ptr->flags.no_block) - (void)memcached_io_write(instance, NULL, 0, true); - - while(memcached_server_response_count(instance)) - (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result); - } - } - - if (ptr->flags.binary_protocol) - { - return binary_mget_by_key(ptr, master_server_key, is_group_key_set, keys, - key_length, number_of_keys, mget_mode); - } - - if (ptr->flags.support_cas) - { - get_command= "gets "; - get_command_length= 5; - } - - /* - If a server fails we warn about errors and start all over with sending keys - to the server. - */ - WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS); - size_t hosts_connected= 0; - for (uint32_t x= 0; x < number_of_keys; x++) - { - memcached_server_write_instance_st instance; - uint32_t server_key; - - if (is_group_key_set) - { - server_key= master_server_key; - } - else - { - server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]); - } - - instance= memcached_server_instance_fetch(ptr, server_key); - - struct libmemcached_io_vector_st vector[]= - { - { .length= get_command_length, .buffer= get_command }, - { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) }, - { .length= key_length[x], .buffer= keys[x] }, - { .length= 1, .buffer= " " } - }; - - - if (memcached_server_response_count(instance) == 0) - { - rc= memcached_connect(instance); - - if (rc != MEMCACHED_SUCCESS) - { - continue; - } - hosts_connected++; - - if ((memcached_io_writev(instance, vector, 4, false)) == -1) - { - failures_occured_in_sending= true; - continue; - } - WATCHPOINT_ASSERT(instance->cursor_active == 0); - memcached_server_response_increment(instance); - WATCHPOINT_ASSERT(instance->cursor_active == 1); - } - else - { - if ((memcached_io_writev(instance, (vector + 1), 3, false)) == -1) - { - memcached_server_response_reset(instance); - failures_occured_in_sending= true; - continue; - } - } - } - - if (hosts_connected == 0) - { - LIBMEMCACHED_MEMCACHED_MGET_END(); - - if (rc != MEMCACHED_SUCCESS) - return rc; - - return MEMCACHED_NO_SERVERS; - } - - - /* - Should we muddle on if some servers are dead? - */ - bool success_happened= false; - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - if (memcached_server_response_count(instance)) - { - /* We need to do something about non-connnected hosts in the future */ - if ((memcached_io_write(instance, "\r\n", 2, true)) == -1) - { - failures_occured_in_sending= true; - } - else - { - success_happened= true; - } - } - } - - LIBMEMCACHED_MEMCACHED_MGET_END(); - - if (failures_occured_in_sending && success_happened) - return MEMCACHED_SOME_ERRORS; - - if (success_happened) - return MEMCACHED_SUCCESS; - - return MEMCACHED_FAILURE; -} - -memcached_return_t memcached_mget_by_key(memcached_st *ptr, - const char *group_key, - size_t group_key_length, - const char * const *keys, - const size_t *key_length, - size_t number_of_keys) -{ - return memcached_mget_by_key_real(ptr, group_key, group_key_length, keys, - key_length, number_of_keys, true); -} - -memcached_return_t memcached_mget_execute(memcached_st *ptr, - const char * const *keys, - const size_t *key_length, - size_t number_of_keys, - memcached_execute_fn *callback, - void *context, - unsigned int number_of_callbacks) -{ - return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length, - number_of_keys, callback, - context, number_of_callbacks); -} - -memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr, - const char *group_key, - size_t group_key_length, - const char * const *keys, - const size_t *key_length, - size_t number_of_keys, - memcached_execute_fn *callback, - void *context, - unsigned int number_of_callbacks) -{ - if ((ptr->flags.binary_protocol) == 0) - return MEMCACHED_NOT_SUPPORTED; - - memcached_return_t rc; - memcached_callback_st *original_callbacks= ptr->callbacks; - memcached_callback_st cb= { - .callback= callback, - .context= context, - .number_of_callback= number_of_callbacks - }; - - ptr->callbacks= &cb; - rc= memcached_mget_by_key(ptr, group_key, group_key_length, keys, - key_length, number_of_keys); - ptr->callbacks= original_callbacks; - return rc; -} - -static memcached_return_t simple_binary_mget(memcached_st *ptr, - uint32_t master_server_key, - bool is_group_key_set, - const char * const *keys, - const size_t *key_length, - size_t number_of_keys, bool mget_mode) -{ - memcached_return_t rc= MEMCACHED_NOTFOUND; - - bool flush= (number_of_keys == 1); - - /* - If a server fails we warn about errors and start all over with sending keys - to the server. - */ - for (uint32_t x= 0; x < number_of_keys; ++x) - { - uint32_t server_key; - memcached_server_write_instance_st instance; - - if (is_group_key_set) - { - server_key= master_server_key; - } - else - { - server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]); - } - - instance= memcached_server_instance_fetch(ptr, server_key); - - if (memcached_server_response_count(instance) == 0) - { - rc= memcached_connect(instance); - if (rc != MEMCACHED_SUCCESS) - continue; - } - - protocol_binary_request_getk request= {.bytes= {0}}; - request.message.header.request.magic= PROTOCOL_BINARY_REQ; - if (mget_mode) - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ; - else - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK; - - memcached_return_t vk; - vk= memcached_validate_key_length(key_length[x], - ptr->flags.binary_protocol); - unlikely (vk != MEMCACHED_SUCCESS) - { - if (x > 0) - { - memcached_io_reset(instance); - } - - return vk; - } - - request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key))); - request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->prefix_key))); - - struct libmemcached_io_vector_st vector[]= - { - { .length= sizeof(request.bytes), .buffer= request.bytes }, - { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) }, - { .length= key_length[x], .buffer= keys[x] } - }; - - if (memcached_io_writev(instance, vector, 3, flush) == -1) - { - memcached_server_response_reset(instance); - rc= MEMCACHED_SOME_ERRORS; - continue; - } - - /* We just want one pending response per server */ - memcached_server_response_reset(instance); - memcached_server_response_increment(instance); - if ((x > 0 && x == ptr->io_key_prefetch) && memcached_flush_buffers(ptr) != MEMCACHED_SUCCESS) - { - rc= MEMCACHED_SOME_ERRORS; - } - } - - if (mget_mode) - { - /* - * Send a noop command to flush the buffers - */ - protocol_binary_request_noop request= {.bytes= {0}}; - request.message.header.request.magic= PROTOCOL_BINARY_REQ; - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_NOOP; - request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - - for (uint32_t x= 0; x < memcached_server_count(ptr); ++x) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - if (memcached_server_response_count(instance)) - { - if (memcached_io_write(instance, NULL, 0, true) == -1) - { - memcached_server_response_reset(instance); - memcached_io_reset(instance); - rc= MEMCACHED_SOME_ERRORS; - } - - if (memcached_io_write(instance, request.bytes, - sizeof(request.bytes), true) == -1) - { - memcached_server_response_reset(instance); - memcached_io_reset(instance); - rc= MEMCACHED_SOME_ERRORS; - } - } - } - } - - - return rc; -} - -static memcached_return_t replication_binary_mget(memcached_st *ptr, - uint32_t* hash, - bool* dead_servers, - const char *const *keys, - const size_t *key_length, - size_t number_of_keys) -{ - memcached_return_t rc= MEMCACHED_NOTFOUND; - uint32_t start= 0; - uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ); - - if (randomize_read) - start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1); - - /* Loop for each replica */ - for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica) - { - bool success= true; - - for (uint32_t x= 0; x < number_of_keys; ++x) - { - memcached_server_write_instance_st instance; - - if (hash[x] == memcached_server_count(ptr)) - continue; /* Already successfully sent */ - - uint32_t server= hash[x] + replica; - - /* In case of randomized reads */ - if (randomize_read && ((server + start) <= (hash[x] + ptr->number_of_replicas))) - server += start; - - while (server >= memcached_server_count(ptr)) - server -= memcached_server_count(ptr); - - if (dead_servers[server]) - continue; - - instance= memcached_server_instance_fetch(ptr, server); - - if (memcached_server_response_count(instance) == 0) - { - rc= memcached_connect(instance); - if (rc != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - dead_servers[server]= true; - success= false; - continue; - } - } - - protocol_binary_request_getk request= { - .message.header.request= { - .magic= PROTOCOL_BINARY_REQ, - .opcode= PROTOCOL_BINARY_CMD_GETK, - .keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key))), - .datatype= PROTOCOL_BINARY_RAW_BYTES, - .bodylen= htonl((uint32_t)(key_length[x] + memcached_array_size(ptr->prefix_key))) - } - }; - - /* - * We need to disable buffering to actually know that the request was - * successfully sent to the server (so that we should expect a result - * back). It would be nice to do this in buffered mode, but then it - * would be complex to handle all error situations if we got to send - * some of the messages, and then we failed on writing out some others - * and we used the callback interface from memcached_mget_execute so - * that we might have processed some of the responses etc. For now, - * just make sure we work _correctly_ - */ - struct libmemcached_io_vector_st vector[]= - { - { .length= sizeof(request.bytes), .buffer= request.bytes }, - { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) }, - { .length= key_length[x], .buffer= keys[x] } - }; - - if (memcached_io_writev(instance, vector, 3, true) == -1) - { - memcached_io_reset(instance); - dead_servers[server]= true; - success= false; - continue; - } - - memcached_server_response_increment(instance); - hash[x]= memcached_server_count(ptr); - } - - if (success) - break; - } - - return rc; -} - -static memcached_return_t binary_mget_by_key(memcached_st *ptr, - uint32_t master_server_key, - bool is_group_key_set, - const char * const *keys, - const size_t *key_length, - size_t number_of_keys, - bool mget_mode) -{ - memcached_return_t rc; - - if (ptr->number_of_replicas == 0) - { - rc= simple_binary_mget(ptr, master_server_key, is_group_key_set, - keys, key_length, number_of_keys, mget_mode); - } - else - { - uint32_t* hash; - bool* dead_servers; - - hash= libmemcached_malloc(ptr, sizeof(uint32_t) * number_of_keys); - dead_servers= libmemcached_calloc(ptr, memcached_server_count(ptr), sizeof(bool)); - - if (hash == NULL || dead_servers == NULL) - { - libmemcached_free(ptr, hash); - libmemcached_free(ptr, dead_servers); - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - } - - if (is_group_key_set) - { - for (size_t x= 0; x < number_of_keys; x++) - { - hash[x]= master_server_key; - } - } - else - { - for (size_t x= 0; x < number_of_keys; x++) - { - hash[x]= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]); - } - } - - rc= replication_binary_mget(ptr, hash, dead_servers, keys, - key_length, number_of_keys); - - libmemcached_free(ptr, hash); - libmemcached_free(ptr, dead_servers); - - return MEMCACHED_SUCCESS; - } - - return rc; -} diff --git a/libmemcached/get.cc b/libmemcached/get.cc new file mode 100644 index 00000000..29d01bc8 --- /dev/null +++ b/libmemcached/get.cc @@ -0,0 +1,648 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: Get functions for libmemcached + * + */ + +#include "common.h" + +/* + What happens if no servers exist? +*/ +char *memcached_get(memcached_st *ptr, const char *key, + size_t key_length, + size_t *value_length, + uint32_t *flags, + memcached_return_t *error) +{ + return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length, + flags, error); +} + +static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr, + const char *group_key, + size_t group_key_length, + const char * const *keys, + const size_t *key_length, + size_t number_of_keys, + bool mget_mode); + +char *memcached_get_by_key(memcached_st *ptr, + const char *group_key, + size_t group_key_length, + const char *key, size_t key_length, + size_t *value_length, + uint32_t *flags, + memcached_return_t *error) +{ + char *value; + size_t dummy_length; + uint32_t dummy_flags; + memcached_return_t dummy_error; + + unlikely (ptr->flags.use_udp) + { + *error= MEMCACHED_NOT_SUPPORTED; + return NULL; + } + + /* Request the key */ + *error= memcached_mget_by_key_real(ptr, group_key, group_key_length, + (const char * const *)&key, + &key_length, 1, false); + + value= memcached_fetch(ptr, NULL, NULL, + value_length, flags, error); + /* This is for historical reasons */ + if (*error == MEMCACHED_END) + *error= MEMCACHED_NOTFOUND; + + if (value == NULL) + { + if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND) + { + memcached_return_t rc; + + memcached_result_reset(&ptr->result); + rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result); + + /* On all failure drop to returning NULL */ + if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) + { + if (rc == MEMCACHED_BUFFERED) + { + uint64_t latch; /* We use latch to track the state of the original socket */ + latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS); + if (latch == 0) + memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1); + + rc= memcached_set(ptr, key, key_length, + (memcached_result_value(&ptr->result)), + (memcached_result_length(&ptr->result)), + 0, + (memcached_result_flags(&ptr->result))); + + if (rc == MEMCACHED_BUFFERED && latch == 0) + memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0); + } + else + { + rc= memcached_set(ptr, key, key_length, + (memcached_result_value(&ptr->result)), + (memcached_result_length(&ptr->result)), + 0, + (memcached_result_flags(&ptr->result))); + } + + if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) + { + *error= rc; + *value_length= memcached_result_length(&ptr->result); + *flags= memcached_result_flags(&ptr->result); + return memcached_string_c_copy(&ptr->result.value); + } + } + } + + return NULL; + } + + (void)memcached_fetch(ptr, NULL, NULL, + &dummy_length, &dummy_flags, + &dummy_error); + WATCHPOINT_ASSERT(dummy_length == 0); + + return value; +} + +memcached_return_t memcached_mget(memcached_st *ptr, + const char * const *keys, + const size_t *key_length, + size_t number_of_keys) +{ + return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys); +} + +static memcached_return_t binary_mget_by_key(memcached_st *ptr, + uint32_t master_server_key, + bool is_group_key_set, + const char * const *keys, + const size_t *key_length, + size_t number_of_keys, + bool mget_mode); + +static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr, + const char *group_key, + size_t group_key_length, + const char * const *keys, + const size_t *key_length, + size_t number_of_keys, + bool mget_mode) +{ + bool failures_occured_in_sending= false; + const char *get_command= "get "; + uint8_t get_command_length= 4; + unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */ + bool is_group_key_set= false; + + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr))) + { + return rc; + } + + unlikely (ptr->flags.use_udp) + return MEMCACHED_NOT_SUPPORTED; + + LIBMEMCACHED_MEMCACHED_MGET_START(); + + if (number_of_keys == 0) + return MEMCACHED_NOTFOUND; + + if (ptr->flags.verify_key && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED)) + { + return MEMCACHED_BAD_KEY_PROVIDED; + } + + if (group_key && group_key_length) + { + if (ptr->flags.verify_key and (memcached_key_test((const char * const *)&group_key, &group_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)) + return MEMCACHED_BAD_KEY_PROVIDED; + + master_server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + is_group_key_set= true; + } + + /* + Here is where we pay for the non-block API. We need to remove any data sitting + in the queue before we start our get. + + It might be optimum to bounce the connection if count > some number. + */ + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + if (memcached_server_response_count(instance)) + { + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + + if (ptr->flags.no_block) + (void)memcached_io_write(instance, NULL, 0, true); + + while(memcached_server_response_count(instance)) + (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result); + } + } + + if (ptr->flags.binary_protocol) + { + return binary_mget_by_key(ptr, master_server_key, is_group_key_set, keys, + key_length, number_of_keys, mget_mode); + } + + if (ptr->flags.support_cas) + { + get_command= "gets "; + get_command_length= 5; + } + + /* + If a server fails we warn about errors and start all over with sending keys + to the server. + */ + WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS); + size_t hosts_connected= 0; + for (uint32_t x= 0; x < number_of_keys; x++) + { + memcached_server_write_instance_st instance; + uint32_t server_key; + + if (is_group_key_set) + { + server_key= master_server_key; + } + else + { + server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]); + } + + instance= memcached_server_instance_fetch(ptr, server_key); + + struct libmemcached_io_vector_st vector[]= + { + { get_command_length, get_command }, + { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) }, + { key_length[x], keys[x] }, + { 1, " " } + }; + + + if (memcached_server_response_count(instance) == 0) + { + rc= memcached_connect(instance); + + if (rc != MEMCACHED_SUCCESS) + { + continue; + } + hosts_connected++; + + if ((memcached_io_writev(instance, vector, 4, false)) == -1) + { + failures_occured_in_sending= true; + continue; + } + WATCHPOINT_ASSERT(instance->cursor_active == 0); + memcached_server_response_increment(instance); + WATCHPOINT_ASSERT(instance->cursor_active == 1); + } + else + { + if ((memcached_io_writev(instance, (vector + 1), 3, false)) == -1) + { + memcached_server_response_reset(instance); + failures_occured_in_sending= true; + continue; + } + } + } + + if (hosts_connected == 0) + { + LIBMEMCACHED_MEMCACHED_MGET_END(); + + if (rc != MEMCACHED_SUCCESS) + return rc; + + return MEMCACHED_NO_SERVERS; + } + + + /* + Should we muddle on if some servers are dead? + */ + bool success_happened= false; + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + if (memcached_server_response_count(instance)) + { + /* We need to do something about non-connnected hosts in the future */ + if ((memcached_io_write(instance, "\r\n", 2, true)) == -1) + { + failures_occured_in_sending= true; + } + else + { + success_happened= true; + } + } + } + + LIBMEMCACHED_MEMCACHED_MGET_END(); + + if (failures_occured_in_sending && success_happened) + return MEMCACHED_SOME_ERRORS; + + if (success_happened) + return MEMCACHED_SUCCESS; + + return MEMCACHED_FAILURE; +} + +memcached_return_t memcached_mget_by_key(memcached_st *ptr, + const char *group_key, + size_t group_key_length, + const char * const *keys, + const size_t *key_length, + size_t number_of_keys) +{ + return memcached_mget_by_key_real(ptr, group_key, group_key_length, keys, + key_length, number_of_keys, true); +} + +memcached_return_t memcached_mget_execute(memcached_st *ptr, + const char * const *keys, + const size_t *key_length, + size_t number_of_keys, + memcached_execute_fn *callback, + void *context, + unsigned int number_of_callbacks) +{ + return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length, + number_of_keys, callback, + context, number_of_callbacks); +} + +memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr, + const char *group_key, + size_t group_key_length, + const char * const *keys, + const size_t *key_length, + size_t number_of_keys, + memcached_execute_fn *callback, + void *context, + unsigned int number_of_callbacks) +{ + if ((ptr->flags.binary_protocol) == 0) + return MEMCACHED_NOT_SUPPORTED; + + memcached_return_t rc; + memcached_callback_st *original_callbacks= ptr->callbacks; + memcached_callback_st cb= { + callback, + context, + number_of_callbacks + }; + + ptr->callbacks= &cb; + rc= memcached_mget_by_key(ptr, group_key, group_key_length, keys, + key_length, number_of_keys); + ptr->callbacks= original_callbacks; + return rc; +} + +static memcached_return_t simple_binary_mget(memcached_st *ptr, + uint32_t master_server_key, + bool is_group_key_set, + const char * const *keys, + const size_t *key_length, + size_t number_of_keys, bool mget_mode) +{ + memcached_return_t rc= MEMCACHED_NOTFOUND; + + bool flush= (number_of_keys == 1); + + /* + If a server fails we warn about errors and start all over with sending keys + to the server. + */ + for (uint32_t x= 0; x < number_of_keys; ++x) + { + uint32_t server_key; + memcached_server_write_instance_st instance; + + if (is_group_key_set) + { + server_key= master_server_key; + } + else + { + server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]); + } + + instance= memcached_server_instance_fetch(ptr, server_key); + + if (memcached_server_response_count(instance) == 0) + { + rc= memcached_connect(instance); + if (rc != MEMCACHED_SUCCESS) + continue; + } + + protocol_binary_request_getk request= { }; //= {.bytes= {0}}; + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + if (mget_mode) + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ; + else + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK; + + memcached_return_t vk; + vk= memcached_validate_key_length(key_length[x], + ptr->flags.binary_protocol); + unlikely (vk != MEMCACHED_SUCCESS) + { + if (x > 0) + { + memcached_io_reset(instance); + } + + return vk; + } + + request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key))); + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->prefix_key))); + + struct libmemcached_io_vector_st vector[]= + { + { sizeof(request.bytes), request.bytes }, + { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) }, + { key_length[x], keys[x] } + }; + + if (memcached_io_writev(instance, vector, 3, flush) == -1) + { + memcached_server_response_reset(instance); + rc= MEMCACHED_SOME_ERRORS; + continue; + } + + /* We just want one pending response per server */ + memcached_server_response_reset(instance); + memcached_server_response_increment(instance); + if ((x > 0 && x == ptr->io_key_prefetch) && memcached_flush_buffers(ptr) != MEMCACHED_SUCCESS) + { + rc= MEMCACHED_SOME_ERRORS; + } + } + + if (mget_mode) + { + /* + Send a noop command to flush the buffers + */ + protocol_binary_request_noop request= {}; //= {.bytes= {0}}; + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_NOOP; + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + + for (uint32_t x= 0; x < memcached_server_count(ptr); ++x) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + if (memcached_server_response_count(instance)) + { + if (memcached_io_write(instance, NULL, 0, true) == -1) + { + memcached_server_response_reset(instance); + memcached_io_reset(instance); + rc= MEMCACHED_SOME_ERRORS; + } + + if (memcached_io_write(instance, request.bytes, + sizeof(request.bytes), true) == -1) + { + memcached_server_response_reset(instance); + memcached_io_reset(instance); + rc= MEMCACHED_SOME_ERRORS; + } + } + } + } + + + return rc; +} + +static memcached_return_t replication_binary_mget(memcached_st *ptr, + uint32_t* hash, + bool* dead_servers, + const char *const *keys, + const size_t *key_length, + size_t number_of_keys) +{ + memcached_return_t rc= MEMCACHED_NOTFOUND; + uint32_t start= 0; + uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ); + + if (randomize_read) + start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1); + + /* Loop for each replica */ + for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica) + { + bool success= true; + + for (uint32_t x= 0; x < number_of_keys; ++x) + { + memcached_server_write_instance_st instance; + + if (hash[x] == memcached_server_count(ptr)) + continue; /* Already successfully sent */ + + uint32_t server= hash[x] + replica; + + /* In case of randomized reads */ + if (randomize_read && ((server + start) <= (hash[x] + ptr->number_of_replicas))) + server += start; + + while (server >= memcached_server_count(ptr)) + server -= memcached_server_count(ptr); + + if (dead_servers[server]) + continue; + + instance= memcached_server_instance_fetch(ptr, server); + + if (memcached_server_response_count(instance) == 0) + { + rc= memcached_connect(instance); + if (rc != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + dead_servers[server]= true; + success= false; + continue; + } + } + + protocol_binary_request_getk request= {}; + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK; + request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key))); + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + request.message.header.request.bodylen= htonl((uint32_t)(key_length[x] + memcached_array_size(ptr->prefix_key))); + + /* + * We need to disable buffering to actually know that the request was + * successfully sent to the server (so that we should expect a result + * back). It would be nice to do this in buffered mode, but then it + * would be complex to handle all error situations if we got to send + * some of the messages, and then we failed on writing out some others + * and we used the callback interface from memcached_mget_execute so + * that we might have processed some of the responses etc. For now, + * just make sure we work _correctly_ + */ + struct libmemcached_io_vector_st vector[]= + { + { sizeof(request.bytes), request.bytes }, + { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) }, + { key_length[x], keys[x] } + }; + + if (memcached_io_writev(instance, vector, 3, true) == -1) + { + memcached_io_reset(instance); + dead_servers[server]= true; + success= false; + continue; + } + + memcached_server_response_increment(instance); + hash[x]= memcached_server_count(ptr); + } + + if (success) + break; + } + + return rc; +} + +static memcached_return_t binary_mget_by_key(memcached_st *ptr, + uint32_t master_server_key, + bool is_group_key_set, + const char * const *keys, + const size_t *key_length, + size_t number_of_keys, + bool mget_mode) +{ + memcached_return_t rc; + + if (ptr->number_of_replicas == 0) + { + rc= simple_binary_mget(ptr, master_server_key, is_group_key_set, + keys, key_length, number_of_keys, mget_mode); + } + else + { + uint32_t* hash; + bool* dead_servers; + + hash= static_cast(libmemcached_malloc(ptr, sizeof(uint32_t) * number_of_keys)); + dead_servers= static_cast(libmemcached_calloc(ptr, memcached_server_count(ptr), sizeof(bool))); + + if (hash == NULL || dead_servers == NULL) + { + libmemcached_free(ptr, hash); + libmemcached_free(ptr, dead_servers); + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + } + + if (is_group_key_set) + { + for (size_t x= 0; x < number_of_keys; x++) + { + hash[x]= master_server_key; + } + } + else + { + for (size_t x= 0; x < number_of_keys; x++) + { + hash[x]= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]); + } + } + + rc= replication_binary_mget(ptr, hash, dead_servers, keys, + key_length, number_of_keys); + + libmemcached_free(ptr, hash); + libmemcached_free(ptr, dead_servers); + + return MEMCACHED_SUCCESS; + } + + return rc; +} diff --git a/libmemcached/hash.c b/libmemcached/hash.c deleted file mode 100644 index e5f87a75..00000000 --- a/libmemcached/hash.c +++ /dev/null @@ -1,176 +0,0 @@ -/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: - * - * Libmemcached library - * - * Copyright (C) 2011 Data Differential, http://datadifferential.com/ - * Copyright (C) 2006-2009 Brian Aker All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * * The names of its contributors may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include -#include - - -uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm) -{ - return libhashkit_digest(key, key_length, (hashkit_hash_algorithm_t)hash_algorithm); -} - -static inline uint32_t generate_hash(const memcached_st *ptr, const char *key, size_t key_length) -{ - return hashkit_digest(&ptr->hashkit, key, key_length); -} - -static uint32_t dispatch_host(const memcached_st *ptr, uint32_t hash) -{ - switch (ptr->distribution) - { - case MEMCACHED_DISTRIBUTION_CONSISTENT: - case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: - case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: - case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: - { - uint32_t num= ptr->ketama.continuum_points_counter; - WATCHPOINT_ASSERT(ptr->continuum); - - hash= hash; - memcached_continuum_item_st *begin, *end, *left, *right, *middle; - begin= left= ptr->ketama.continuum; - end= right= ptr->ketama.continuum + num; - - while (left < right) - { - middle= left + (right - left) / 2; - if (middle->value < hash) - left= middle + 1; - else - right= middle; - } - if (right == end) - right= begin; - return right->index; - } - case MEMCACHED_DISTRIBUTION_MODULA: - return hash % memcached_server_count(ptr); - case MEMCACHED_DISTRIBUTION_RANDOM: - return (uint32_t) random() % memcached_server_count(ptr); - case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: - { - return memcached_virtual_bucket_get(ptr, hash); - } - default: - case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: - WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */ - return hash % memcached_server_count(ptr); - } - /* NOTREACHED */ -} - -/* - One version is public and will not modify the distribution hash, the other will. -*/ -static inline uint32_t _generate_hash_wrapper(const memcached_st *ptr, const char *key, size_t key_length) -{ - WATCHPOINT_ASSERT(memcached_server_count(ptr)); - - if (memcached_server_count(ptr) == 1) - return 0; - - if (ptr->flags.hash_with_prefix_key) - { - size_t temp_length= memcached_array_size(ptr->prefix_key) + key_length; - char temp[temp_length]; - - if (temp_length > MEMCACHED_MAX_KEY -1) - return 0; - - strncpy(temp, memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key)); - strncpy(temp + memcached_array_size(ptr->prefix_key), key, key_length); - - return generate_hash(ptr, temp, temp_length); - } - else - { - return generate_hash(ptr, key, key_length); - } -} - -static inline void _regen_for_auto_eject(memcached_st *ptr) -{ - if (_is_auto_eject_host(ptr) && ptr->ketama.next_distribution_rebuild) - { - struct timeval now; - - if (gettimeofday(&now, NULL) == 0 && - now.tv_sec > ptr->ketama.next_distribution_rebuild) - { - run_distribution(ptr); - } - } -} - -void memcached_autoeject(memcached_st *ptr) -{ - _regen_for_auto_eject(ptr); -} - -uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length) -{ - uint32_t hash= _generate_hash_wrapper(ptr, key, key_length); - - _regen_for_auto_eject(ptr); - - return dispatch_host(ptr, hash); -} - -uint32_t memcached_generate_hash(const memcached_st *ptr, const char *key, size_t key_length) -{ - return dispatch_host(ptr, _generate_hash_wrapper(ptr, key, key_length)); -} - -const hashkit_st *memcached_get_hashkit(const memcached_st *ptr) -{ - return &ptr->hashkit; -} - -memcached_return_t memcached_set_hashkit(memcached_st *self, hashkit_st *hashk) -{ - hashkit_free(&self->hashkit); - hashkit_clone(&self->hashkit, hashk); - - return MEMCACHED_SUCCESS; -} - -const char * libmemcached_string_hash(memcached_hash_t type) -{ - return libhashkit_string_hash((hashkit_hash_algorithm_t)type); -} diff --git a/libmemcached/hash.cc b/libmemcached/hash.cc new file mode 100644 index 00000000..0e6295b8 --- /dev/null +++ b/libmemcached/hash.cc @@ -0,0 +1,176 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include + + +uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm) +{ + return libhashkit_digest(key, key_length, (hashkit_hash_algorithm_t)hash_algorithm); +} + +static inline uint32_t generate_hash(const memcached_st *ptr, const char *key, size_t key_length) +{ + return hashkit_digest(&ptr->hashkit, key, key_length); +} + +static uint32_t dispatch_host(const memcached_st *ptr, uint32_t hash) +{ + switch (ptr->distribution) + { + case MEMCACHED_DISTRIBUTION_CONSISTENT: + case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: + { + uint32_t num= ptr->ketama.continuum_points_counter; + WATCHPOINT_ASSERT(ptr->continuum); + + hash= hash; + memcached_continuum_item_st *begin, *end, *left, *right, *middle; + begin= left= ptr->ketama.continuum; + end= right= ptr->ketama.continuum + num; + + while (left < right) + { + middle= left + (right - left) / 2; + if (middle->value < hash) + left= middle + 1; + else + right= middle; + } + if (right == end) + right= begin; + return right->index; + } + case MEMCACHED_DISTRIBUTION_MODULA: + return hash % memcached_server_count(ptr); + case MEMCACHED_DISTRIBUTION_RANDOM: + return (uint32_t) random() % memcached_server_count(ptr); + case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: + { + return memcached_virtual_bucket_get(ptr, hash); + } + default: + case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: + WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */ + return hash % memcached_server_count(ptr); + } + /* NOTREACHED */ +} + +/* + One version is public and will not modify the distribution hash, the other will. +*/ +static inline uint32_t _generate_hash_wrapper(const memcached_st *ptr, const char *key, size_t key_length) +{ + WATCHPOINT_ASSERT(memcached_server_count(ptr)); + + if (memcached_server_count(ptr) == 1) + return 0; + + if (ptr->flags.hash_with_prefix_key) + { + size_t temp_length= memcached_array_size(ptr->prefix_key) + key_length; + char temp[MEMCACHED_MAX_KEY]; + + if (temp_length > MEMCACHED_MAX_KEY -1) + return 0; + + strncpy(temp, memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key)); + strncpy(temp + memcached_array_size(ptr->prefix_key), key, key_length); + + return generate_hash(ptr, temp, temp_length); + } + else + { + return generate_hash(ptr, key, key_length); + } +} + +static inline void _regen_for_auto_eject(memcached_st *ptr) +{ + if (_is_auto_eject_host(ptr) && ptr->ketama.next_distribution_rebuild) + { + struct timeval now; + + if (gettimeofday(&now, NULL) == 0 && + now.tv_sec > ptr->ketama.next_distribution_rebuild) + { + run_distribution(ptr); + } + } +} + +void memcached_autoeject(memcached_st *ptr) +{ + _regen_for_auto_eject(ptr); +} + +uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length) +{ + uint32_t hash= _generate_hash_wrapper(ptr, key, key_length); + + _regen_for_auto_eject(ptr); + + return dispatch_host(ptr, hash); +} + +uint32_t memcached_generate_hash(const memcached_st *ptr, const char *key, size_t key_length) +{ + return dispatch_host(ptr, _generate_hash_wrapper(ptr, key, key_length)); +} + +const hashkit_st *memcached_get_hashkit(const memcached_st *ptr) +{ + return &ptr->hashkit; +} + +memcached_return_t memcached_set_hashkit(memcached_st *self, hashkit_st *hashk) +{ + hashkit_free(&self->hashkit); + hashkit_clone(&self->hashkit, hashk); + + return MEMCACHED_SUCCESS; +} + +const char * libmemcached_string_hash(memcached_hash_t type) +{ + return libhashkit_string_hash((hashkit_hash_algorithm_t)type); +} diff --git a/libmemcached/hosts.c b/libmemcached/hosts.c deleted file mode 100644 index 93f830a7..00000000 --- a/libmemcached/hosts.c +++ /dev/null @@ -1,468 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2010 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - -#include "common.h" -#include - -/* Protoypes (static) */ -static memcached_return_t server_add(memcached_st *ptr, const char *hostname, - in_port_t port, - uint32_t weight, - memcached_connection_t type); - -static memcached_return_t update_continuum(memcached_st *ptr); - -static int compare_servers(const void *p1, const void *p2) -{ - int return_value; - memcached_server_instance_st a= (memcached_server_instance_st)p1; - memcached_server_instance_st b= (memcached_server_instance_st)p2; - - return_value= strcmp(a->hostname, b->hostname); - - if (return_value == 0) - { - return_value= (int) (a->port - b->port); - } - - return return_value; -} - -static void sort_hosts(memcached_st *ptr) -{ - if (memcached_server_count(ptr)) - { - memcached_server_write_instance_st instance; - - qsort(memcached_server_list(ptr), memcached_server_count(ptr), sizeof(memcached_server_st), compare_servers); - instance= memcached_server_instance_fetch(ptr, 0); - instance->number_of_hosts= memcached_server_count(ptr); - } -} - - -memcached_return_t run_distribution(memcached_st *ptr) -{ - if (ptr->flags.use_sort_hosts) - sort_hosts(ptr); - - switch (ptr->distribution) - { - case MEMCACHED_DISTRIBUTION_CONSISTENT: - case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: - case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: - case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: - return update_continuum(ptr); - case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: - case MEMCACHED_DISTRIBUTION_MODULA: - break; - case MEMCACHED_DISTRIBUTION_RANDOM: - srandom((uint32_t) time(NULL)); - break; - case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: - default: - WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */ - } - - return MEMCACHED_SUCCESS; -} - -static uint32_t ketama_server_hash(const char *key, size_t key_length, uint32_t alignment) -{ - unsigned char results[16]; - - libhashkit_md5_signature((unsigned char*)key, key_length, results); - - return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24) - | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16) - | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8) - | (results[0 + alignment * 4] & 0xFF); -} - -static int continuum_item_cmp(const void *t1, const void *t2) -{ - memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1; - memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2; - - /* Why 153? Hmmm... */ - WATCHPOINT_ASSERT(ct1->value != 153); - if (ct1->value == ct2->value) - return 0; - else if (ct1->value > ct2->value) - return 1; - else - return -1; -} - -static memcached_return_t update_continuum(memcached_st *ptr) -{ - uint32_t continuum_index= 0; - memcached_server_st *list; - uint32_t pointer_counter= 0; - uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER; - uint32_t pointer_per_hash= 1; - uint32_t live_servers= 0; - struct timeval now; - - if (gettimeofday(&now, NULL) != 0) - { - memcached_set_errno(ptr, errno, NULL); - return MEMCACHED_ERRNO; - } - - list= memcached_server_list(ptr); - - /* count live servers (those without a retry delay set) */ - bool is_auto_ejecting= _is_auto_eject_host(ptr); - if (is_auto_ejecting) - { - live_servers= 0; - ptr->ketama.next_distribution_rebuild= 0; - for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index) - { - if (list[host_index].next_retry <= now.tv_sec) - live_servers++; - else - { - if (ptr->ketama.next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->ketama.next_distribution_rebuild) - ptr->ketama.next_distribution_rebuild= list[host_index].next_retry; - } - } - } - else - { - live_servers= memcached_server_count(ptr); - } - - uint64_t is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED); - uint32_t points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER); - - if (live_servers == 0) - return MEMCACHED_SUCCESS; - - if (live_servers > ptr->ketama.continuum_count) - { - memcached_continuum_item_st *new_ptr; - - new_ptr= libmemcached_realloc(ptr, ptr->ketama.continuum, - sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server); - - if (new_ptr == 0) - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - - ptr->ketama.continuum= new_ptr; - ptr->ketama.continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION; - } - - uint64_t total_weight= 0; - if (is_ketama_weighted) - { - for (uint32_t host_index = 0; host_index < memcached_server_count(ptr); ++host_index) - { - if (! is_auto_ejecting || list[host_index].next_retry <= now.tv_sec) - { - total_weight += list[host_index].weight; - } - } - } - - for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index) - { - if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec) - continue; - - if (is_ketama_weighted) - { - float pct = (float)list[host_index].weight / (float)total_weight; - pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4); - pointer_per_hash= 4; -#ifdef DEBUG - printf("ketama_weighted:%s|%d|%llu|%u\n", - list[host_index].hostname, - list[host_index].port, - (unsigned long long)list[host_index].weight, - pointer_per_server); -#endif - } - - - if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY) - { - for (uint32_t pointer_index= 0; - pointer_index < pointer_per_server / pointer_per_hash; - pointer_index++) - { - char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= ""; - int sort_host_length; - - // Spymemcached ketema key format is: hostname/ip:port-index - // If hostname is not available then: /ip:port-index - sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, - "/%s:%u-%u", - list[host_index].hostname, - (uint32_t)list[host_index].port, - pointer_index); - - if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0) - { - return MEMCACHED_FAILURE; - } -#ifdef DEBUG - printf("update_continuum: key is %s\n", sort_host); -#endif - - WATCHPOINT_ASSERT(sort_host_length); - - if (is_ketama_weighted) - { - for (uint32_t x= 0; x < pointer_per_hash; x++) - { - uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x); - ptr->ketama.continuum[continuum_index].index= host_index; - ptr->ketama.continuum[continuum_index++].value= value; - } - } - else - { - uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length); - ptr->ketama.continuum[continuum_index].index= host_index; - ptr->ketama.continuum[continuum_index++].value= value; - } - } - } - else - { - for (uint32_t pointer_index= 1; - pointer_index <= pointer_per_server / pointer_per_hash; - pointer_index++) - { - char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= ""; - int sort_host_length; - - if (list[host_index].port == MEMCACHED_DEFAULT_PORT) - { - sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, - "%s-%u", - list[host_index].hostname, - pointer_index - 1); - } - else - { - sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, - "%s:%u-%u", - list[host_index].hostname, - (uint32_t)list[host_index].port, - pointer_index - 1); - } - - if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0) - { - return MEMCACHED_FAILURE; - } - - WATCHPOINT_ASSERT(sort_host_length); - - if (is_ketama_weighted) - { - for (uint32_t x = 0; x < pointer_per_hash; x++) - { - uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x); - ptr->ketama.continuum[continuum_index].index= host_index; - ptr->ketama.continuum[continuum_index++].value= value; - } - } - else - { - uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length); - ptr->ketama.continuum[continuum_index].index= host_index; - ptr->ketama.continuum[continuum_index++].value= value; - } - } - } - - pointer_counter+= pointer_per_server; - } - - WATCHPOINT_ASSERT(ptr); - WATCHPOINT_ASSERT(ptr->continuum); - WATCHPOINT_ASSERT(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE); - ptr->ketama.continuum_points_counter= pointer_counter; - qsort(ptr->ketama.continuum, ptr->ketama.continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp); - -#ifdef DEBUG - for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++) - { - WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value); - } -#endif - - return MEMCACHED_SUCCESS; -} - - -memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list) -{ - uint32_t count; - memcached_server_st *new_host_list; - - if (! list) - return MEMCACHED_SUCCESS; - - count= memcached_server_list_count(list); - new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr), - sizeof(memcached_server_st) * (count + memcached_server_count(ptr))); - - if (! new_host_list) - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - - memcached_server_list_set(ptr, new_host_list); - - for (uint32_t x= 0; x < count; x++) - { - memcached_server_write_instance_st instance; - - if ((ptr->flags.use_udp && list[x].type != MEMCACHED_CONNECTION_UDP) - || ((list[x].type == MEMCACHED_CONNECTION_UDP) - && ! (ptr->flags.use_udp)) ) - { - return MEMCACHED_INVALID_HOST_PROTOCOL; - } - - WATCHPOINT_ASSERT(list[x].hostname[0] != 0); - - instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr)); - WATCHPOINT_ASSERT(instance); - - /* TODO check return type */ - instance= memcached_server_create_with(ptr, instance, list[x].hostname, - list[x].port, list[x].weight, list[x].type); - if (! instance) - { - return memcached_set_error(ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, NULL); - } - ptr->number_of_hosts++; - } - - // Provides backwards compatibility with server list. - { - memcached_server_write_instance_st instance; - instance= memcached_server_instance_fetch(ptr, 0); - instance->number_of_hosts= memcached_server_count(ptr); - } - - return run_distribution(ptr); -} - -memcached_return_t memcached_server_add_unix_socket(memcached_st *ptr, - const char *filename) -{ - return memcached_server_add_unix_socket_with_weight(ptr, filename, 0); -} - -memcached_return_t memcached_server_add_unix_socket_with_weight(memcached_st *ptr, - const char *filename, - uint32_t weight) -{ - if (! filename) - return MEMCACHED_FAILURE; - - return server_add(ptr, filename, 0, weight, MEMCACHED_CONNECTION_UNIX_SOCKET); -} - -memcached_return_t memcached_server_add_udp(memcached_st *ptr, - const char *hostname, - in_port_t port) -{ - return memcached_server_add_udp_with_weight(ptr, hostname, port, 0); -} - -memcached_return_t memcached_server_add_udp_with_weight(memcached_st *ptr, - const char *hostname, - in_port_t port, - uint32_t weight) -{ - if (! port) - port= MEMCACHED_DEFAULT_PORT; - - if (! hostname) - hostname= "localhost"; - - return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_UDP); -} - -memcached_return_t memcached_server_add(memcached_st *ptr, - const char *hostname, - in_port_t port) -{ - return memcached_server_add_with_weight(ptr, hostname, port, 0); -} - -memcached_return_t memcached_server_add_with_weight(memcached_st *ptr, - const char *hostname, - in_port_t port, - uint32_t weight) -{ - if (! port) - port= MEMCACHED_DEFAULT_PORT; - - if (! hostname) - hostname= "localhost"; - - return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_TCP); -} - -static memcached_return_t server_add(memcached_st *ptr, const char *hostname, - in_port_t port, - uint32_t weight, - memcached_connection_t type) -{ - memcached_server_st *new_host_list; - memcached_server_write_instance_st instance; - - if ( (ptr->flags.use_udp && type != MEMCACHED_CONNECTION_UDP) - || ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) ) - return MEMCACHED_INVALID_HOST_PROTOCOL; - - new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr), - sizeof(memcached_server_st) * (ptr->number_of_hosts + 1)); - - if (new_host_list == NULL) - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - - memcached_server_list_set(ptr, new_host_list); - - /* TODO: Check return type */ - instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr)); - (void)memcached_server_create_with(ptr, instance, hostname, port, weight, type); - ptr->number_of_hosts++; - - instance= memcached_server_instance_fetch(ptr, 0); - memcached_servers_set_count(instance, memcached_server_count(ptr)); - - return run_distribution(ptr); -} - -memcached_return_t memcached_server_add_parsed(memcached_st *ptr, - const char *hostname, - size_t hostname_length, - in_port_t port, - uint32_t weight) -{ - char buffer[NI_MAXHOST]; - - memcpy(buffer, hostname, hostname_length); - buffer[hostname_length]= 0; - - return server_add(ptr, buffer, - port, - weight, - MEMCACHED_CONNECTION_TCP); -} diff --git a/libmemcached/hosts.cc b/libmemcached/hosts.cc new file mode 100644 index 00000000..d38b12e9 --- /dev/null +++ b/libmemcached/hosts.cc @@ -0,0 +1,467 @@ +/* LibMemcached + * Copyright (C) 2006-2010 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ + +#include "common.h" +#include + +/* Protoypes (static) */ +static memcached_return_t server_add(memcached_st *ptr, const char *hostname, + in_port_t port, + uint32_t weight, + memcached_connection_t type); + +static memcached_return_t update_continuum(memcached_st *ptr); + +static int compare_servers(const void *p1, const void *p2) +{ + int return_value; + memcached_server_instance_st a= (memcached_server_instance_st)p1; + memcached_server_instance_st b= (memcached_server_instance_st)p2; + + return_value= strcmp(a->hostname, b->hostname); + + if (return_value == 0) + { + return_value= (int) (a->port - b->port); + } + + return return_value; +} + +static void sort_hosts(memcached_st *ptr) +{ + if (memcached_server_count(ptr)) + { + memcached_server_write_instance_st instance; + + qsort(memcached_server_list(ptr), memcached_server_count(ptr), sizeof(memcached_server_st), compare_servers); + instance= memcached_server_instance_fetch(ptr, 0); + instance->number_of_hosts= memcached_server_count(ptr); + } +} + + +memcached_return_t run_distribution(memcached_st *ptr) +{ + if (ptr->flags.use_sort_hosts) + sort_hosts(ptr); + + switch (ptr->distribution) + { + case MEMCACHED_DISTRIBUTION_CONSISTENT: + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: + case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: + case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: + return update_continuum(ptr); + case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: + case MEMCACHED_DISTRIBUTION_MODULA: + break; + case MEMCACHED_DISTRIBUTION_RANDOM: + srandom((uint32_t) time(NULL)); + break; + case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: + default: + WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */ + } + + return MEMCACHED_SUCCESS; +} + +static uint32_t ketama_server_hash(const char *key, size_t key_length, uint32_t alignment) +{ + unsigned char results[16]; + + libhashkit_md5_signature((unsigned char*)key, key_length, results); + + return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24) + | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16) + | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8) + | (results[0 + alignment * 4] & 0xFF); +} + +static int continuum_item_cmp(const void *t1, const void *t2) +{ + memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1; + memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2; + + /* Why 153? Hmmm... */ + WATCHPOINT_ASSERT(ct1->value != 153); + if (ct1->value == ct2->value) + return 0; + else if (ct1->value > ct2->value) + return 1; + else + return -1; +} + +static memcached_return_t update_continuum(memcached_st *ptr) +{ + uint32_t continuum_index= 0; + memcached_server_st *list; + uint32_t pointer_counter= 0; + uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER; + uint32_t pointer_per_hash= 1; + uint32_t live_servers= 0; + struct timeval now; + + if (gettimeofday(&now, NULL) != 0) + { + memcached_set_errno(ptr, errno, NULL); + return MEMCACHED_ERRNO; + } + + list= memcached_server_list(ptr); + + /* count live servers (those without a retry delay set) */ + bool is_auto_ejecting= _is_auto_eject_host(ptr); + if (is_auto_ejecting) + { + live_servers= 0; + ptr->ketama.next_distribution_rebuild= 0; + for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index) + { + if (list[host_index].next_retry <= now.tv_sec) + live_servers++; + else + { + if (ptr->ketama.next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->ketama.next_distribution_rebuild) + ptr->ketama.next_distribution_rebuild= list[host_index].next_retry; + } + } + } + else + { + live_servers= memcached_server_count(ptr); + } + + uint64_t is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED); + uint32_t points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER); + + if (live_servers == 0) + return MEMCACHED_SUCCESS; + + if (live_servers > ptr->ketama.continuum_count) + { + memcached_continuum_item_st *new_ptr; + + new_ptr= static_cast(libmemcached_realloc(ptr, ptr->ketama.continuum, + sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server)); + + if (new_ptr == 0) + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + + ptr->ketama.continuum= new_ptr; + ptr->ketama.continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION; + } + + uint64_t total_weight= 0; + if (is_ketama_weighted) + { + for (uint32_t host_index = 0; host_index < memcached_server_count(ptr); ++host_index) + { + if (! is_auto_ejecting || list[host_index].next_retry <= now.tv_sec) + { + total_weight += list[host_index].weight; + } + } + } + + for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index) + { + if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec) + continue; + + if (is_ketama_weighted) + { + float pct = (float)list[host_index].weight / (float)total_weight; + pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4); + pointer_per_hash= 4; +#ifdef DEBUG + printf("ketama_weighted:%s|%d|%llu|%u\n", + list[host_index].hostname, + list[host_index].port, + (unsigned long long)list[host_index].weight, + pointer_per_server); +#endif + } + + + if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY) + { + for (uint32_t pointer_index= 0; + pointer_index < pointer_per_server / pointer_per_hash; + pointer_index++) + { + char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= ""; + int sort_host_length; + + // Spymemcached ketema key format is: hostname/ip:port-index + // If hostname is not available then: /ip:port-index + sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, + "/%s:%u-%u", + list[host_index].hostname, + (uint32_t)list[host_index].port, + pointer_index); + + if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0) + { + return MEMCACHED_FAILURE; + } +#ifdef DEBUG + printf("update_continuum: key is %s\n", sort_host); +#endif + + WATCHPOINT_ASSERT(sort_host_length); + + if (is_ketama_weighted) + { + for (uint32_t x= 0; x < pointer_per_hash; x++) + { + uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x); + ptr->ketama.continuum[continuum_index].index= host_index; + ptr->ketama.continuum[continuum_index++].value= value; + } + } + else + { + uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length); + ptr->ketama.continuum[continuum_index].index= host_index; + ptr->ketama.continuum[continuum_index++].value= value; + } + } + } + else + { + for (uint32_t pointer_index= 1; + pointer_index <= pointer_per_server / pointer_per_hash; + pointer_index++) + { + char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= ""; + int sort_host_length; + + if (list[host_index].port == MEMCACHED_DEFAULT_PORT) + { + sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, + "%s-%u", + list[host_index].hostname, + pointer_index - 1); + } + else + { + sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH, + "%s:%u-%u", + list[host_index].hostname, + (uint32_t)list[host_index].port, + pointer_index - 1); + } + + if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0) + { + return MEMCACHED_FAILURE; + } + + WATCHPOINT_ASSERT(sort_host_length); + + if (is_ketama_weighted) + { + for (uint32_t x = 0; x < pointer_per_hash; x++) + { + uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x); + ptr->ketama.continuum[continuum_index].index= host_index; + ptr->ketama.continuum[continuum_index++].value= value; + } + } + else + { + uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length); + ptr->ketama.continuum[continuum_index].index= host_index; + ptr->ketama.continuum[continuum_index++].value= value; + } + } + } + + pointer_counter+= pointer_per_server; + } + + WATCHPOINT_ASSERT(ptr); + WATCHPOINT_ASSERT(ptr->continuum); + WATCHPOINT_ASSERT(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE); + ptr->ketama.continuum_points_counter= pointer_counter; + qsort(ptr->ketama.continuum, ptr->ketama.continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp); + +#ifdef DEBUG + for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++) + { + WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value); + } +#endif + + return MEMCACHED_SUCCESS; +} + + +memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list) +{ + if (not list) + return MEMCACHED_SUCCESS; + + uint32_t count= memcached_server_list_count(list); + + memcached_server_st *new_host_list; + new_host_list= static_cast(libmemcached_realloc(ptr, memcached_server_list(ptr), + sizeof(memcached_server_st) * (count + memcached_server_count(ptr)))); + + if (not new_host_list) + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + + memcached_server_list_set(ptr, new_host_list); + + for (uint32_t x= 0; x < count; x++) + { + memcached_server_write_instance_st instance; + + if ((ptr->flags.use_udp && list[x].type != MEMCACHED_CONNECTION_UDP) + || ((list[x].type == MEMCACHED_CONNECTION_UDP) + && ! (ptr->flags.use_udp)) ) + { + return MEMCACHED_INVALID_HOST_PROTOCOL; + } + + WATCHPOINT_ASSERT(list[x].hostname[0] != 0); + + instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr)); + WATCHPOINT_ASSERT(instance); + + /* TODO check return type */ + instance= memcached_server_create_with(ptr, instance, list[x].hostname, + list[x].port, list[x].weight, list[x].type); + if (! instance) + { + return memcached_set_error(ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, NULL); + } + ptr->number_of_hosts++; + } + + // Provides backwards compatibility with server list. + { + memcached_server_write_instance_st instance; + instance= memcached_server_instance_fetch(ptr, 0); + instance->number_of_hosts= memcached_server_count(ptr); + } + + return run_distribution(ptr); +} + +memcached_return_t memcached_server_add_unix_socket(memcached_st *ptr, + const char *filename) +{ + return memcached_server_add_unix_socket_with_weight(ptr, filename, 0); +} + +memcached_return_t memcached_server_add_unix_socket_with_weight(memcached_st *ptr, + const char *filename, + uint32_t weight) +{ + if (! filename) + return MEMCACHED_FAILURE; + + return server_add(ptr, filename, 0, weight, MEMCACHED_CONNECTION_UNIX_SOCKET); +} + +memcached_return_t memcached_server_add_udp(memcached_st *ptr, + const char *hostname, + in_port_t port) +{ + return memcached_server_add_udp_with_weight(ptr, hostname, port, 0); +} + +memcached_return_t memcached_server_add_udp_with_weight(memcached_st *ptr, + const char *hostname, + in_port_t port, + uint32_t weight) +{ + if (! port) + port= MEMCACHED_DEFAULT_PORT; + + if (! hostname) + hostname= "localhost"; + + return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_UDP); +} + +memcached_return_t memcached_server_add(memcached_st *ptr, + const char *hostname, + in_port_t port) +{ + return memcached_server_add_with_weight(ptr, hostname, port, 0); +} + +memcached_return_t memcached_server_add_with_weight(memcached_st *ptr, + const char *hostname, + in_port_t port, + uint32_t weight) +{ + if (! port) + port= MEMCACHED_DEFAULT_PORT; + + if (! hostname) + hostname= "localhost"; + + return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_TCP); +} + +static memcached_return_t server_add(memcached_st *ptr, const char *hostname, + in_port_t port, + uint32_t weight, + memcached_connection_t type) +{ + memcached_server_st *new_host_list; + memcached_server_write_instance_st instance; + + if ( (ptr->flags.use_udp && type != MEMCACHED_CONNECTION_UDP) + || ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) ) + return MEMCACHED_INVALID_HOST_PROTOCOL; + + new_host_list= static_cast(libmemcached_realloc(ptr, memcached_server_list(ptr), + sizeof(memcached_server_st) * (ptr->number_of_hosts + 1))); + + if (new_host_list == NULL) + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + + memcached_server_list_set(ptr, new_host_list); + + /* TODO: Check return type */ + instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr)); + (void)memcached_server_create_with(ptr, instance, hostname, port, weight, type); + ptr->number_of_hosts++; + + instance= memcached_server_instance_fetch(ptr, 0); + memcached_servers_set_count(instance, memcached_server_count(ptr)); + + return run_distribution(ptr); +} + +memcached_return_t memcached_server_add_parsed(memcached_st *ptr, + const char *hostname, + size_t hostname_length, + in_port_t port, + uint32_t weight) +{ + char buffer[NI_MAXHOST]; + + memcpy(buffer, hostname, hostname_length); + buffer[hostname_length]= 0; + + return server_add(ptr, buffer, + port, + weight, + MEMCACHED_CONNECTION_TCP); +} diff --git a/libmemcached/include.am b/libmemcached/include.am index 5a4b8b09..28c5513a 100644 --- a/libmemcached/include.am +++ b/libmemcached/include.am @@ -55,6 +55,7 @@ nobase_include_HEADERS+= \ libmemcached/protocol/callback.h \ libmemcached/protocol_handler.h \ libmemcached/quit.h \ + libmemcached/return.h \ libmemcached/platform.h \ libmemcached/result.h \ libmemcached/sasl.h \ @@ -70,104 +71,73 @@ nobase_include_HEADERS+= \ libmemcached/visibility.h \ libmemcached/watchpoint.h -lib_LTLIBRARIES+= libmemcached/libmemcachedprotocol.la -libmemcached_libmemcachedprotocol_la_SOURCES = \ - libmemcached/protocol/ascii_handler.c \ - libmemcached/protocol/binary_handler.c \ - libmemcached/protocol/cache.c \ - libmemcached/protocol/pedantic.c \ - libmemcached/protocol/protocol_handler.c - -libmemcached_libmemcachedprotocol_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION} ${PTHREAD_CFLAGS} -libmemcached_libmemcachedprotocol_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_PROTOCAL_LIBRARY_VERSION} - -noinst_LTLIBRARIES+= \ - libmemcached/libmemcachedcallbacks.la - -libmemcached_libmemcachedcallbacks_la_CFLAGS = ${AM_CFLAGS} ${NO_STRICT_ALIASING} -libmemcached_libmemcachedcallbacks_la_SOURCES = libmemcached/callback.c - # This noinst lib contains things we want to be ABI private but still want to # either use in client programs or be able to test in test cases # These symbols will not be exposed in the shipped .so noinst_LTLIBRARIES+= libmemcached/libmemcachedinternal.la libmemcached_libmemcachedinternal_la_SOURCES= \ libmemcached/error.cc \ - libmemcached/string.c + libmemcached/string.cc lib_LTLIBRARIES+= libmemcached/libmemcached.la -libmemcached_libmemcached_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION} +libmemcached_libmemcached_la_CFLAGS= \ + ${AM_CFLAGS} \ + ${NO_CONVERSION} \ + -DBUILDING_LIBMEMCACHED + +libmemcached_libmemcached_la_CXXFLAGS= \ + ${AM_CXXFLAGS} \ + ${NO_CONVERSION} \ + -DBUILDING_LIBMEMCACHED + libmemcached_libmemcached_la_SOURCES+= \ - libmemcached/allocators.c \ - libmemcached/analyze.c \ + ${libhashkit_libhashkit_la_SOURCES} \ + libmemcached/allocators.cc \ + libmemcached/analyze.cc \ libmemcached/array.c \ - libmemcached/auto.c \ - libmemcached/behavior.c \ - libmemcached/connect.c \ - libmemcached/delete.c \ - libmemcached/do.c \ - libmemcached/dump.c \ + libmemcached/auto.cc \ + libmemcached/behavior.cc \ + libmemcached/byteorder.cc \ + libmemcached/callback.cc \ + libmemcached/connect.cc \ + libmemcached/delete.cc \ + libmemcached/do.cc \ + libmemcached/dump.cc \ + libmemcached/error.cc \ libmemcached/fetch.c \ - libmemcached/flush.c \ - libmemcached/flush_buffers.c \ - libmemcached/get.c \ - libmemcached/hash.c \ - libmemcached/hosts.c \ + libmemcached/flush.cc \ + libmemcached/flush_buffers.cc \ + libmemcached/get.cc \ + libmemcached/hash.cc \ + libmemcached/hosts.cc \ libmemcached/initialize_query.cc \ - libmemcached/io.c \ - libmemcached/key.c \ - libmemcached/memcached.c \ + libmemcached/io.cc \ + libmemcached/key.cc \ + libmemcached/memcached.cc \ libmemcached/options.cc \ - libmemcached/parse.c \ + libmemcached/parse.cc \ libmemcached/prefix_key.cc \ - libmemcached/purge.c \ - libmemcached/quit.c \ - libmemcached/response.c \ - libmemcached/result.c \ - libmemcached/server.c \ - libmemcached/server_list.c \ - libmemcached/stats.c \ - libmemcached/storage.c \ - libmemcached/strerror.c \ - libmemcached/verbosity.c \ - libmemcached/version.c \ + libmemcached/purge.cc \ + libmemcached/quit.cc \ + libmemcached/response.cc \ + libmemcached/result.cc \ + libmemcached/server.cc \ + libmemcached/server_list.cc \ + libmemcached/stats.cc \ + libmemcached/storage.cc \ + libmemcached/strerror.cc \ + libmemcached/string.cc \ + libmemcached/verbosity.cc \ + libmemcached/version.cc \ libmemcached/virtual_bucket.c libmemcached/options.cc: libmemcached/options/parser.h -libmemcached_libmemcached_la_DEPENDENCIES= libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la libhashkit/libhashkitinc.la -libmemcached_libmemcached_la_LIBADD= $(LIBM) libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la libhashkit/libhashkitinc.la +libmemcached_libmemcached_la_DEPENDENCIES= +libmemcached_libmemcached_la_LIBADD= $(LIBM) libmemcached_libmemcached_la_LDFLAGS= ${AM_LDFLAGS} -version-info ${MEMCACHED_LIBRARY_VERSION} -if BUILD_LIBMEMCACHEDUTIL -nobase_include_HEADERS+= \ - libmemcached/memcached_util.h \ - libmemcached/util.h \ - libmemcached/util/ping.h \ - libmemcached/util/pool.h \ - libmemcached/util/version.h -lib_LTLIBRARIES+= libmemcached/libmemcachedutil.la -endif - -libmemcached_libmemcachedutil_la_SOURCES= \ - libmemcached/util/ping.c \ - libmemcached/util/pool.c \ - libmemcached/util/version.c -libmemcached_libmemcachedutil_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION} ${PTHREAD_CFLAGS} -libmemcached_libmemcachedutil_la_LIBADD= libmemcached/libmemcached.la -libmemcached_libmemcachedutil_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_UTIL_LIBRARY_VERSION} -libmemcached_libmemcachedutil_la_DEPENDENCIES= libmemcached/libmemcached.la - -if BUILD_BYTEORDER -noinst_LTLIBRARIES += libmemcached/libbyteorder.la -libmemcached_libbyteorder_la_SOURCES= libmemcached/byteorder.c -libmemcached_libmemcached_la_LIBADD += libmemcached/libbyteorder.la -libmemcached_libmemcached_la_DEPENDENCIES+= libmemcached/libbyteorder.la -libmemcached_libmemcachedprotocol_la_LIBADD=libmemcached/libbyteorder.la -libmemcached_libmemcachedprotocol_la_DEPENDENCIES=libmemcached/libbyteorder.la -endif - if HAVE_SASL libmemcached_libmemcached_la_LDFLAGS+= $(LTLIBSASL) $(LTLIBSASL2) libmemcached_libmemcached_la_SOURCES += libmemcached/sasl.c diff --git a/libmemcached/initialize_query.cc b/libmemcached/initialize_query.cc index abc8dfdc..31a15fbc 100644 --- a/libmemcached/initialize_query.cc +++ b/libmemcached/initialize_query.cc @@ -35,13 +35,14 @@ */ #include -#include memcached_return_t initialize_query(memcached_st *self) { - if (! self) + if (not self) return MEMCACHED_INVALID_ARGUMENTS; + self->query_id++; + if (self->state.is_time_for_rebuild) { memcached_reset(self); @@ -52,15 +53,12 @@ memcached_return_t initialize_query(memcached_st *self) return memcached_set_error(self, MEMCACHED_NO_SERVERS, NULL); } - - self->query_id++; - return MEMCACHED_SUCCESS; } memcached_return_t initialize_const_query(const memcached_st *self) { - if (! self) + if (not self) return MEMCACHED_INVALID_ARGUMENTS; if (memcached_server_count(self) == 0) diff --git a/libmemcached/internal.h b/libmemcached/internal.h index 743bf870..67ae67d5 100644 --- a/libmemcached/internal.h +++ b/libmemcached/internal.h @@ -1,18 +1,41 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. * - * Summary: Internal functions used by the library. Not for public use! + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_INTERNAL_H__ -#define __LIBMEMCACHED_INTERNAL_H__ - -#if defined(BUILDING_LIBMEMCACHED) +#pragma once #ifdef __cplusplus extern "C" { @@ -21,6 +44,3 @@ extern "C" { #ifdef __cplusplus } #endif - -#endif /* BUILDING_LIBMEMCACHED */ -#endif /* __LIBMEMCACHED_INTERNAL_H__ */ diff --git a/libmemcached/io.c b/libmemcached/io.c deleted file mode 100644 index 5acbbd52..00000000 --- a/libmemcached/io.c +++ /dev/null @@ -1,806 +0,0 @@ -/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: - * - * LibMemcached - * - * Copyright (C) 2011 Data Differential, http://datadifferential.com/ - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * * The names of its contributors may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include "libmemcached/common.h" - -typedef enum { - MEM_READ, - MEM_WRITE -} memc_read_or_write; - -static ssize_t io_flush(memcached_server_write_instance_st ptr, - const bool with_flush, - memcached_return_t *error); -static void increment_udp_message_id(memcached_server_write_instance_st ptr); - -static memcached_return_t io_wait(memcached_server_write_instance_st ptr, - memc_read_or_write read_or_write) -{ - struct pollfd fds= { - .fd= ptr->fd, - .events = POLLIN - }; - int error; - - if (read_or_write == MEM_WRITE) /* write */ - { - fds.events= POLLOUT; - WATCHPOINT_SET(ptr->io_wait_count.write++); - } - else - { - WATCHPOINT_SET(ptr->io_wait_count.read++); - } - - /* - ** We are going to block on write, but at least on Solaris we might block - ** on write if we haven't read anything from our input buffer.. - ** Try to purge the input buffer if we don't do any flow control in the - ** application layer (just sending a lot of data etc) - ** The test is moved down in the purge function to avoid duplication of - ** the test. - */ - if (read_or_write == MEM_WRITE) - { - memcached_return_t rc= memcached_purge(ptr); - if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED) - return MEMCACHED_FAILURE; - } - - size_t loop_max= 5; - while (--loop_max) // While loop is for ERESTART or EINTR - { - error= poll(&fds, 1, ptr->root->poll_timeout); - - switch (error) - { - case 1: // Success! - WATCHPOINT_IF_LABELED_NUMBER(read_or_write && loop_max < 4, "read() times we had to loop, decremented down from 5", loop_max); - WATCHPOINT_IF_LABELED_NUMBER(!read_or_write && loop_max < 4, "write() times we had to loop, decremented down from 5", loop_max); - - return MEMCACHED_SUCCESS; - case 0: // Timeout occured, we let the while() loop do its thing. - return MEMCACHED_TIMEOUT; - default: - WATCHPOINT_ERRNO(get_socket_errno()); - switch (get_socket_errno()) - { -#ifdef TARGET_OS_LINUX - case ERESTART: -#endif - case EINTR: - break; - default: - if (fds.revents & POLLERR) - { - int err; - socklen_t len= sizeof (err); - (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len); - ptr->cached_errno= (err == 0) ? get_socket_errno() : err; - } - else - { - ptr->cached_errno= get_socket_errno(); - } - memcached_quit_server(ptr, true); - - return MEMCACHED_FAILURE; - } - } - } - - /* Imposssible for anything other then -1 */ - WATCHPOINT_ASSERT(error == -1); - ptr->cached_errno= get_socket_errno(); - memcached_quit_server(ptr, true); - - return MEMCACHED_FAILURE; -} - -memcached_return_t memcached_io_wait_for_write(memcached_server_write_instance_st ptr) -{ - return io_wait(ptr, MEM_WRITE); -} - -/** - * Try to fill the input buffer for a server with as much - * data as possible. - * - * @param ptr the server to pack - */ -static bool repack_input_buffer(memcached_server_write_instance_st ptr) -{ - if (ptr->read_ptr != ptr->read_buffer) - { - /* Move all of the data to the beginning of the buffer so - ** that we can fit more data into the buffer... - */ - memmove(ptr->read_buffer, ptr->read_ptr, ptr->read_buffer_length); - ptr->read_ptr= ptr->read_buffer; - ptr->read_data_length= ptr->read_buffer_length; - } - - /* There is room in the buffer, try to fill it! */ - if (ptr->read_buffer_length != MEMCACHED_MAX_BUFFER) - { - /* Just try a single read to grab what's available */ - ssize_t nr= recv(ptr->fd, - ptr->read_ptr + ptr->read_data_length, - MEMCACHED_MAX_BUFFER - ptr->read_data_length, - 0); - - if (nr > 0) - { - ptr->read_data_length+= (size_t)nr; - ptr->read_buffer_length+= (size_t)nr; - return true; - } - } - return false; -} - -/** - * If the we have callbacks connected to this server structure - * we may start process the input queue and fire the callbacks - * for the incomming messages. This function is _only_ called - * when the input buffer is full, so that we _know_ that we have - * at least _one_ message to process. - * - * @param ptr the server to star processing iput messages for - * @return true if we processed anything, false otherwise - */ -static bool process_input_buffer(memcached_server_write_instance_st ptr) -{ - /* - ** We might be able to process some of the response messages if we - ** have a callback set up - */ - if (ptr->root->callbacks != NULL && ptr->root->flags.use_udp == false) - { - /* - * We might have responses... try to read them out and fire - * callbacks - */ - memcached_callback_st cb= *ptr->root->callbacks; - - memcached_set_processing_input((memcached_st *)ptr->root, true); - - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - memcached_return_t error; - memcached_st *root= (memcached_st *)ptr->root; - error= memcached_response(ptr, buffer, sizeof(buffer), - &root->result); - - memcached_set_processing_input(root, false); - - if (error == MEMCACHED_SUCCESS) - { - for (unsigned int x= 0; x < cb.number_of_callback; x++) - { - error= (*cb.callback[x])(ptr->root, &root->result, cb.context); - if (error != MEMCACHED_SUCCESS) - break; - } - - /* @todo what should I do with the error message??? */ - } - /* @todo what should I do with other error messages?? */ - return true; - } - - return false; -} - -#if 0 // Dead code, this should be removed. -void memcached_io_preread(memcached_st *ptr) -{ - unsigned int x; - - return; - - for (x= 0; x < memcached_server_count(ptr); x++) - { - if (memcached_server_response_count(ptr, x) && - ptr->hosts[x].read_data_length < MEMCACHED_MAX_BUFFER ) - { - size_t data_read; - - data_read= recv(ptr->hosts[x].fd, - ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length, - MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length, 0); - if (data_read == SOCKET_ERROR) - continue; - - ptr->hosts[x].read_buffer_length+= data_read; - ptr->hosts[x].read_data_length+= data_read; - } - } -} -#endif - -memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, - void *buffer, size_t length, ssize_t *nread) -{ - char *buffer_ptr; - - buffer_ptr= buffer; - - while (length) - { - if (!ptr->read_buffer_length) - { - ssize_t data_read; - - while (1) - { - data_read= recv(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER, 0); - if (data_read > 0) - { - break; - } - else if (data_read == SOCKET_ERROR) - { - ptr->cached_errno= get_socket_errno(); - memcached_return_t rc= MEMCACHED_ERRNO; - switch (get_socket_errno()) - { - case EWOULDBLOCK: -#ifdef USE_EAGAIN - case EAGAIN: -#endif - case EINTR: -#ifdef TARGET_OS_LINUX - case ERESTART: -#endif - if ((rc= io_wait(ptr, MEM_READ)) == MEMCACHED_SUCCESS) - continue; - /* fall through */ - - default: - { - memcached_quit_server(ptr, true); - *nread= -1; - return rc; - } - } - } - else - { - /* - EOF. Any data received so far is incomplete - so discard it. This always reads by byte in case of TCP - and protocol enforcement happens at memcached_response() - looking for '\n'. We do not care for UDB which requests 8 bytes - at once. Generally, this means that connection went away. Since - for blocking I/O we do not return 0 and for non-blocking case - it will return EGAIN if data is not immediatly available. - */ - WATCHPOINT_STRING("We had a zero length recv()"); - memcached_quit_server(ptr, true); - *nread= -1; - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - } - - ptr->io_bytes_sent = 0; - ptr->read_data_length= (size_t) data_read; - ptr->read_buffer_length= (size_t) data_read; - ptr->read_ptr= ptr->read_buffer; - } - - if (length > 1) - { - size_t difference; - - difference= (length > ptr->read_buffer_length) ? ptr->read_buffer_length : length; - - memcpy(buffer_ptr, ptr->read_ptr, difference); - length -= difference; - ptr->read_ptr+= difference; - ptr->read_buffer_length-= difference; - buffer_ptr+= difference; - } - else - { - *buffer_ptr= *ptr->read_ptr; - ptr->read_ptr++; - ptr->read_buffer_length--; - buffer_ptr++; - break; - } - } - - ptr->server_failure_counter= 0; - *nread = (ssize_t)(buffer_ptr - (char*)buffer); - return MEMCACHED_SUCCESS; -} - -static ssize_t _io_write(memcached_server_write_instance_st ptr, - const void *buffer, size_t length, bool with_flush) -{ - size_t original_length; - const char* buffer_ptr; - - WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - - original_length= length; - buffer_ptr= buffer; - - while (length) - { - char *write_ptr; - size_t should_write; - size_t buffer_end; - - if (ptr->type == MEMCACHED_CONNECTION_UDP) - { - //UDP does not support partial writes - buffer_end= MAX_UDP_DATAGRAM_LENGTH; - should_write= length; - if (ptr->write_buffer_offset + should_write > buffer_end) - { - return -1; - } - } - else - { - buffer_end= MEMCACHED_MAX_BUFFER; - should_write= buffer_end - ptr->write_buffer_offset; - should_write= (should_write < length) ? should_write : length; - } - - write_ptr= ptr->write_buffer + ptr->write_buffer_offset; - memcpy(write_ptr, buffer_ptr, should_write); - ptr->write_buffer_offset+= should_write; - buffer_ptr+= should_write; - length-= should_write; - - if (ptr->write_buffer_offset == buffer_end && ptr->type != MEMCACHED_CONNECTION_UDP) - { - memcached_return_t rc; - ssize_t sent_length; - - WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - sent_length= io_flush(ptr, with_flush, &rc); - if (sent_length == -1) - { - return -1; - } - - /* If io_flush calls memcached_purge, sent_length may be 0 */ - unlikely (sent_length != 0) - { - WATCHPOINT_ASSERT(sent_length == (ssize_t)buffer_end); - } - } - } - - if (with_flush) - { - memcached_return_t rc; - WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - if (io_flush(ptr, with_flush, &rc) == -1) - { - return -1; - } - } - - return (ssize_t) original_length; -} - -ssize_t memcached_io_write(memcached_server_write_instance_st ptr, - const void *buffer, size_t length, bool with_flush) -{ - return _io_write(ptr, buffer, length, with_flush); -} - -ssize_t memcached_io_writev(memcached_server_write_instance_st ptr, - const struct libmemcached_io_vector_st *vector, - size_t number_of, bool with_flush) -{ - ssize_t total= 0; - - for (size_t x= 0; x < number_of; x++, vector++) - { - ssize_t returnable; - - if ((returnable= _io_write(ptr, vector->buffer, vector->length, false)) == -1) - { - return -1; - } - total+= returnable; - } - - if (with_flush) - { - if (memcached_io_write(ptr, NULL, 0, true) == -1) - { - return -1; - } - } - - return total; -} - - -memcached_return_t memcached_io_close(memcached_server_write_instance_st ptr) -{ - if (ptr->fd == INVALID_SOCKET) - { - return MEMCACHED_SUCCESS; - } - - /* in case of death shutdown to avoid blocking at close() */ - if (shutdown(ptr->fd, SHUT_RDWR) == SOCKET_ERROR && get_socket_errno() != ENOTCONN) - { - WATCHPOINT_NUMBER(ptr->fd); - WATCHPOINT_ERRNO(get_socket_errno()); - WATCHPOINT_ASSERT(get_socket_errno()); - } - - if (closesocket(ptr->fd) == SOCKET_ERROR) - { - WATCHPOINT_ERRNO(get_socket_errno()); - } - - return MEMCACHED_SUCCESS; -} - -memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st *memc) -{ -#define MAX_SERVERS_TO_POLL 100 - struct pollfd fds[MAX_SERVERS_TO_POLL]; - unsigned int host_index= 0; - - for (uint32_t x= 0; - x< memcached_server_count(memc) && host_index < MAX_SERVERS_TO_POLL; - ++x) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(memc, x); - - if (instance->read_buffer_length > 0) /* I have data in the buffer */ - return instance; - - if (memcached_server_response_count(instance) > 0) - { - fds[host_index].events = POLLIN; - fds[host_index].revents = 0; - fds[host_index].fd = instance->fd; - ++host_index; - } - } - - if (host_index < 2) - { - /* We have 0 or 1 server with pending events.. */ - for (uint32_t x= 0; x< memcached_server_count(memc); ++x) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(memc, x); - - if (memcached_server_response_count(instance) > 0) - { - return instance; - } - } - - return NULL; - } - - int err= poll(fds, host_index, memc->poll_timeout); - switch (err) { - case -1: - memcached_set_errno(memc, get_socket_errno(), NULL); - /* FALLTHROUGH */ - case 0: - break; - default: - for (size_t x= 0; x < host_index; ++x) - { - if (fds[x].revents & POLLIN) - { - for (uint32_t y= 0; y < memcached_server_count(memc); ++y) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(memc, y); - - if (instance->fd == fds[x].fd) - return instance; - } - } - } - } - - return NULL; -} - -static ssize_t io_flush(memcached_server_write_instance_st ptr, - const bool with_flush, - memcached_return_t *error) -{ - /* - ** We might want to purge the input buffer if we haven't consumed - ** any output yet... The test for the limits is the purge is inline - ** in the purge function to avoid duplicating the logic.. - */ - { - memcached_return_t rc; - WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - rc= memcached_purge(ptr); - - if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED) - { - return -1; - } - } - ssize_t sent_length; - size_t return_length; - char *local_write_ptr= ptr->write_buffer; - size_t write_length= ptr->write_buffer_offset; - - *error= MEMCACHED_SUCCESS; - - WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - - // UDP Sanity check, make sure that we are not sending somthing too big - if (ptr->type == MEMCACHED_CONNECTION_UDP && write_length > MAX_UDP_DATAGRAM_LENGTH) - { - return -1; - } - - if (ptr->write_buffer_offset == 0 || (ptr->type == MEMCACHED_CONNECTION_UDP - && ptr->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH)) - return 0; - - /* Looking for memory overflows */ -#if defined(DEBUG) - if (write_length == MEMCACHED_MAX_BUFFER) - WATCHPOINT_ASSERT(ptr->write_buffer == local_write_ptr); - WATCHPOINT_ASSERT((ptr->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length)); -#endif - - return_length= 0; - while (write_length) - { - WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - WATCHPOINT_ASSERT(write_length > 0); - sent_length= 0; - if (ptr->type == MEMCACHED_CONNECTION_UDP) - increment_udp_message_id(ptr); - - WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - if (with_flush) - { - sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT); - } - else - { - sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT|MSG_MORE); - } - - if (sent_length == SOCKET_ERROR) - { - ptr->cached_errno= get_socket_errno(); -#if 0 // @todo I should look at why we hit this bit of code hard frequently - WATCHPOINT_ERRNO(get_socket_errno()); - WATCHPOINT_NUMBER(get_socket_errno()); -#endif - switch (get_socket_errno()) - { - case ENOBUFS: - continue; - case EWOULDBLOCK: -#ifdef USE_EAGAIN - case EAGAIN: -#endif - { - /* - * We may be blocked on write because the input buffer - * is full. Let's check if we have room in our input - * buffer for more data and retry the write before - * waiting.. - */ - if (repack_input_buffer(ptr) || - process_input_buffer(ptr)) - continue; - - memcached_return_t rc; - rc= io_wait(ptr, MEM_WRITE); - - if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_TIMEOUT) - continue; - - memcached_quit_server(ptr, true); - return -1; - } - case ENOTCONN: - case EPIPE: - default: - memcached_quit_server(ptr, true); - *error= MEMCACHED_ERRNO; - WATCHPOINT_ASSERT(ptr->fd == -1); - return -1; - } - } - - if (ptr->type == MEMCACHED_CONNECTION_UDP && - (size_t)sent_length != write_length) - { - memcached_quit_server(ptr, true); - return -1; - } - - ptr->io_bytes_sent += (uint32_t) sent_length; - - local_write_ptr+= sent_length; - write_length-= (uint32_t) sent_length; - return_length+= (uint32_t) sent_length; - } - - WATCHPOINT_ASSERT(write_length == 0); - // Need to study this assert() WATCHPOINT_ASSERT(return_length == - // ptr->write_buffer_offset); - - // if we are a udp server, the begining of the buffer is reserverd for - // the upd frame header - if (ptr->type == MEMCACHED_CONNECTION_UDP) - ptr->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH; - else - ptr->write_buffer_offset= 0; - - return (ssize_t) return_length; -} - -/* - Eventually we will just kill off the server with the problem. -*/ -void memcached_io_reset(memcached_server_write_instance_st ptr) -{ - memcached_quit_server(ptr, true); -} - -/** - * Read a given number of bytes from the server and place it into a specific - * buffer. Reset the IO channel on this server if an error occurs. - */ -memcached_return_t memcached_safe_read(memcached_server_write_instance_st ptr, - void *dta, - size_t size) -{ - size_t offset= 0; - char *data= dta; - - while (offset < size) - { - ssize_t nread; - memcached_return_t rc= memcached_io_read(ptr, data + offset, size - offset, - &nread); - if (rc != MEMCACHED_SUCCESS) - return rc; - - offset+= (size_t) nread; - } - - return MEMCACHED_SUCCESS; -} - -memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr, - char *buffer_ptr, - size_t size) -{ - bool line_complete= false; - size_t total_nr= 0; - - while (!line_complete) - { - if (ptr->read_buffer_length == 0) - { - /* - * We don't have any data in the buffer, so let's fill the read - * buffer. Call the standard read function to avoid duplicating - * the logic. - */ - ssize_t nread; - memcached_return_t rc= memcached_io_read(ptr, buffer_ptr, 1, &nread); - if (rc != MEMCACHED_SUCCESS) - return rc; - - if (*buffer_ptr == '\n') - line_complete= true; - - ++buffer_ptr; - ++total_nr; - } - - /* Now let's look in the buffer and copy as we go! */ - while (ptr->read_buffer_length && total_nr < size && !line_complete) - { - *buffer_ptr = *ptr->read_ptr; - if (*buffer_ptr == '\n') - line_complete = true; - --ptr->read_buffer_length; - ++ptr->read_ptr; - ++total_nr; - ++buffer_ptr; - } - - if (total_nr == size) - return MEMCACHED_PROTOCOL_ERROR; - } - - return MEMCACHED_SUCCESS; -} - -/* - * The udp request id consists of two seperate sections - * 1) The thread id - * 2) The message number - * The thread id should only be set when the memcached_st struct is created - * and should not be changed. - * - * The message num is incremented for each new message we send, this function - * extracts the message number from message_id, increments it and then - * writes the new value back into the header - */ -static void increment_udp_message_id(memcached_server_write_instance_st ptr) -{ - struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer; - uint16_t cur_req= get_udp_datagram_request_id(header); - int msg_num= get_msg_num_from_request_id(cur_req); - int thread_id= get_thread_id_from_request_id(cur_req); - - if (((++msg_num) & UDP_REQUEST_ID_THREAD_MASK) != 0) - msg_num= 0; - - header->request_id= htons((uint16_t) (thread_id | msg_num)); -} - -memcached_return_t memcached_io_init_udp_header(memcached_server_write_instance_st ptr, uint16_t thread_id) -{ - if (thread_id > UDP_REQUEST_ID_MAX_THREAD_ID) - return MEMCACHED_FAILURE; - - struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer; - header->request_id= htons((uint16_t) (generate_udp_request_thread_id(thread_id))); - header->num_datagrams= htons(1); - header->sequence_number= htons(0); - - return MEMCACHED_SUCCESS; -} diff --git a/libmemcached/io.cc b/libmemcached/io.cc new file mode 100644 index 00000000..74aa4a23 --- /dev/null +++ b/libmemcached/io.cc @@ -0,0 +1,806 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * LibMemcached + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include "libmemcached/common.h" + +typedef enum { + MEM_READ, + MEM_WRITE +} memc_read_or_write; + +static ssize_t io_flush(memcached_server_write_instance_st ptr, + const bool with_flush, + memcached_return_t *error); +static void increment_udp_message_id(memcached_server_write_instance_st ptr); + +static memcached_return_t io_wait(memcached_server_write_instance_st ptr, + memc_read_or_write read_or_write) +{ + struct pollfd fds; + fds.fd= ptr->fd; + fds.events= POLLIN; + + int error; + + if (read_or_write == MEM_WRITE) /* write */ + { + fds.events= POLLOUT; + WATCHPOINT_SET(ptr->io_wait_count.write++); + } + else + { + WATCHPOINT_SET(ptr->io_wait_count.read++); + } + + /* + ** We are going to block on write, but at least on Solaris we might block + ** on write if we haven't read anything from our input buffer.. + ** Try to purge the input buffer if we don't do any flow control in the + ** application layer (just sending a lot of data etc) + ** The test is moved down in the purge function to avoid duplication of + ** the test. + */ + if (read_or_write == MEM_WRITE) + { + memcached_return_t rc= memcached_purge(ptr); + if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED) + return MEMCACHED_FAILURE; + } + + size_t loop_max= 5; + while (--loop_max) // While loop is for ERESTART or EINTR + { + error= poll(&fds, 1, ptr->root->poll_timeout); + + switch (error) + { + case 1: // Success! + WATCHPOINT_IF_LABELED_NUMBER(read_or_write && loop_max < 4, "read() times we had to loop, decremented down from 5", loop_max); + WATCHPOINT_IF_LABELED_NUMBER(!read_or_write && loop_max < 4, "write() times we had to loop, decremented down from 5", loop_max); + + return MEMCACHED_SUCCESS; + case 0: // Timeout occured, we let the while() loop do its thing. + return MEMCACHED_TIMEOUT; + default: + WATCHPOINT_ERRNO(get_socket_errno()); + switch (get_socket_errno()) + { +#ifdef TARGET_OS_LINUX + case ERESTART: +#endif + case EINTR: + break; + default: + if (fds.revents & POLLERR) + { + int err; + socklen_t len= sizeof (err); + (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len); + ptr->cached_errno= (err == 0) ? get_socket_errno() : err; + } + else + { + ptr->cached_errno= get_socket_errno(); + } + memcached_quit_server(ptr, true); + + return MEMCACHED_FAILURE; + } + } + } + + /* Imposssible for anything other then -1 */ + WATCHPOINT_ASSERT(error == -1); + ptr->cached_errno= get_socket_errno(); + memcached_quit_server(ptr, true); + + return MEMCACHED_FAILURE; +} + +memcached_return_t memcached_io_wait_for_write(memcached_server_write_instance_st ptr) +{ + return io_wait(ptr, MEM_WRITE); +} + +/** + * Try to fill the input buffer for a server with as much + * data as possible. + * + * @param ptr the server to pack + */ +static bool repack_input_buffer(memcached_server_write_instance_st ptr) +{ + if (ptr->read_ptr != ptr->read_buffer) + { + /* Move all of the data to the beginning of the buffer so + ** that we can fit more data into the buffer... + */ + memmove(ptr->read_buffer, ptr->read_ptr, ptr->read_buffer_length); + ptr->read_ptr= ptr->read_buffer; + ptr->read_data_length= ptr->read_buffer_length; + } + + /* There is room in the buffer, try to fill it! */ + if (ptr->read_buffer_length != MEMCACHED_MAX_BUFFER) + { + /* Just try a single read to grab what's available */ + ssize_t nr= recv(ptr->fd, + ptr->read_ptr + ptr->read_data_length, + MEMCACHED_MAX_BUFFER - ptr->read_data_length, + 0); + + if (nr > 0) + { + ptr->read_data_length+= (size_t)nr; + ptr->read_buffer_length+= (size_t)nr; + return true; + } + } + return false; +} + +/** + * If the we have callbacks connected to this server structure + * we may start process the input queue and fire the callbacks + * for the incomming messages. This function is _only_ called + * when the input buffer is full, so that we _know_ that we have + * at least _one_ message to process. + * + * @param ptr the server to star processing iput messages for + * @return true if we processed anything, false otherwise + */ +static bool process_input_buffer(memcached_server_write_instance_st ptr) +{ + /* + ** We might be able to process some of the response messages if we + ** have a callback set up + */ + if (ptr->root->callbacks != NULL && ptr->root->flags.use_udp == false) + { + /* + * We might have responses... try to read them out and fire + * callbacks + */ + memcached_callback_st cb= *ptr->root->callbacks; + + memcached_set_processing_input((memcached_st *)ptr->root, true); + + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + memcached_return_t error; + memcached_st *root= (memcached_st *)ptr->root; + error= memcached_response(ptr, buffer, sizeof(buffer), + &root->result); + + memcached_set_processing_input(root, false); + + if (error == MEMCACHED_SUCCESS) + { + for (unsigned int x= 0; x < cb.number_of_callback; x++) + { + error= (*cb.callback[x])(ptr->root, &root->result, cb.context); + if (error != MEMCACHED_SUCCESS) + break; + } + + /* @todo what should I do with the error message??? */ + } + /* @todo what should I do with other error messages?? */ + return true; + } + + return false; +} + +#if 0 // Dead code, this should be removed. +void memcached_io_preread(memcached_st *ptr) +{ + unsigned int x; + + return; + + for (x= 0; x < memcached_server_count(ptr); x++) + { + if (memcached_server_response_count(ptr, x) && + ptr->hosts[x].read_data_length < MEMCACHED_MAX_BUFFER ) + { + size_t data_read; + + data_read= recv(ptr->hosts[x].fd, + ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length, + MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length, 0); + if (data_read == SOCKET_ERROR) + continue; + + ptr->hosts[x].read_buffer_length+= data_read; + ptr->hosts[x].read_data_length+= data_read; + } + } +} +#endif + +memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, + void *buffer, size_t length, ssize_t *nread) +{ + char *buffer_ptr; + + buffer_ptr= static_cast(buffer); + + while (length) + { + if (not ptr->read_buffer_length) + { + ssize_t data_read; + + while (1) + { + data_read= recv(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER, 0); + if (data_read > 0) + { + break; + } + else if (data_read == SOCKET_ERROR) + { + ptr->cached_errno= get_socket_errno(); + memcached_return_t rc= MEMCACHED_ERRNO; + switch (get_socket_errno()) + { + case EWOULDBLOCK: +#ifdef USE_EAGAIN + case EAGAIN: +#endif + case EINTR: +#ifdef TARGET_OS_LINUX + case ERESTART: +#endif + if ((rc= io_wait(ptr, MEM_READ)) == MEMCACHED_SUCCESS) + continue; + /* fall through */ + + default: + { + memcached_quit_server(ptr, true); + *nread= -1; + return rc; + } + } + } + else + { + /* + EOF. Any data received so far is incomplete + so discard it. This always reads by byte in case of TCP + and protocol enforcement happens at memcached_response() + looking for '\n'. We do not care for UDB which requests 8 bytes + at once. Generally, this means that connection went away. Since + for blocking I/O we do not return 0 and for non-blocking case + it will return EGAIN if data is not immediatly available. + */ + WATCHPOINT_STRING("We had a zero length recv()"); + memcached_quit_server(ptr, true); + *nread= -1; + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + } + + ptr->io_bytes_sent = 0; + ptr->read_data_length= (size_t) data_read; + ptr->read_buffer_length= (size_t) data_read; + ptr->read_ptr= ptr->read_buffer; + } + + if (length > 1) + { + size_t difference; + + difference= (length > ptr->read_buffer_length) ? ptr->read_buffer_length : length; + + memcpy(buffer_ptr, ptr->read_ptr, difference); + length -= difference; + ptr->read_ptr+= difference; + ptr->read_buffer_length-= difference; + buffer_ptr+= difference; + } + else + { + *buffer_ptr= *ptr->read_ptr; + ptr->read_ptr++; + ptr->read_buffer_length--; + buffer_ptr++; + break; + } + } + + ptr->server_failure_counter= 0; + *nread = (ssize_t)(buffer_ptr - (char*)buffer); + return MEMCACHED_SUCCESS; +} + +static ssize_t _io_write(memcached_server_write_instance_st ptr, + const void *buffer, size_t length, bool with_flush) +{ + size_t original_length; + const char* buffer_ptr; + + WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); + + original_length= length; + buffer_ptr= static_cast(buffer); + + while (length) + { + char *write_ptr; + size_t should_write; + size_t buffer_end; + + if (ptr->type == MEMCACHED_CONNECTION_UDP) + { + //UDP does not support partial writes + buffer_end= MAX_UDP_DATAGRAM_LENGTH; + should_write= length; + if (ptr->write_buffer_offset + should_write > buffer_end) + { + return -1; + } + } + else + { + buffer_end= MEMCACHED_MAX_BUFFER; + should_write= buffer_end - ptr->write_buffer_offset; + should_write= (should_write < length) ? should_write : length; + } + + write_ptr= ptr->write_buffer + ptr->write_buffer_offset; + memcpy(write_ptr, buffer_ptr, should_write); + ptr->write_buffer_offset+= should_write; + buffer_ptr+= should_write; + length-= should_write; + + if (ptr->write_buffer_offset == buffer_end && ptr->type != MEMCACHED_CONNECTION_UDP) + { + memcached_return_t rc; + ssize_t sent_length; + + WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); + sent_length= io_flush(ptr, with_flush, &rc); + if (sent_length == -1) + { + return -1; + } + + /* If io_flush calls memcached_purge, sent_length may be 0 */ + unlikely (sent_length != 0) + { + WATCHPOINT_ASSERT(sent_length == (ssize_t)buffer_end); + } + } + } + + if (with_flush) + { + memcached_return_t rc; + WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); + if (io_flush(ptr, with_flush, &rc) == -1) + { + return -1; + } + } + + return (ssize_t) original_length; +} + +ssize_t memcached_io_write(memcached_server_write_instance_st ptr, + const void *buffer, size_t length, bool with_flush) +{ + return _io_write(ptr, buffer, length, with_flush); +} + +ssize_t memcached_io_writev(memcached_server_write_instance_st ptr, + const struct libmemcached_io_vector_st *vector, + size_t number_of, bool with_flush) +{ + ssize_t total= 0; + + for (size_t x= 0; x < number_of; x++, vector++) + { + ssize_t returnable; + + if ((returnable= _io_write(ptr, vector->buffer, vector->length, false)) == -1) + { + return -1; + } + total+= returnable; + } + + if (with_flush) + { + if (memcached_io_write(ptr, NULL, 0, true) == -1) + { + return -1; + } + } + + return total; +} + + +memcached_return_t memcached_io_close(memcached_server_write_instance_st ptr) +{ + if (ptr->fd == INVALID_SOCKET) + { + return MEMCACHED_SUCCESS; + } + + /* in case of death shutdown to avoid blocking at close() */ + if (shutdown(ptr->fd, SHUT_RDWR) == SOCKET_ERROR && get_socket_errno() != ENOTCONN) + { + WATCHPOINT_NUMBER(ptr->fd); + WATCHPOINT_ERRNO(get_socket_errno()); + WATCHPOINT_ASSERT(get_socket_errno()); + } + + if (closesocket(ptr->fd) == SOCKET_ERROR) + { + WATCHPOINT_ERRNO(get_socket_errno()); + } + + return MEMCACHED_SUCCESS; +} + +memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st *memc) +{ +#define MAX_SERVERS_TO_POLL 100 + struct pollfd fds[MAX_SERVERS_TO_POLL]; + unsigned int host_index= 0; + + for (uint32_t x= 0; + x< memcached_server_count(memc) && host_index < MAX_SERVERS_TO_POLL; + ++x) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(memc, x); + + if (instance->read_buffer_length > 0) /* I have data in the buffer */ + return instance; + + if (memcached_server_response_count(instance) > 0) + { + fds[host_index].events = POLLIN; + fds[host_index].revents = 0; + fds[host_index].fd = instance->fd; + ++host_index; + } + } + + if (host_index < 2) + { + /* We have 0 or 1 server with pending events.. */ + for (uint32_t x= 0; x< memcached_server_count(memc); ++x) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(memc, x); + + if (memcached_server_response_count(instance) > 0) + { + return instance; + } + } + + return NULL; + } + + int err= poll(fds, host_index, memc->poll_timeout); + switch (err) { + case -1: + memcached_set_errno(memc, get_socket_errno(), NULL); + /* FALLTHROUGH */ + case 0: + break; + default: + for (size_t x= 0; x < host_index; ++x) + { + if (fds[x].revents & POLLIN) + { + for (uint32_t y= 0; y < memcached_server_count(memc); ++y) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(memc, y); + + if (instance->fd == fds[x].fd) + return instance; + } + } + } + } + + return NULL; +} + +static ssize_t io_flush(memcached_server_write_instance_st ptr, + const bool with_flush, + memcached_return_t *error) +{ + /* + ** We might want to purge the input buffer if we haven't consumed + ** any output yet... The test for the limits is the purge is inline + ** in the purge function to avoid duplicating the logic.. + */ + { + memcached_return_t rc; + WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); + rc= memcached_purge(ptr); + + if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED) + { + return -1; + } + } + ssize_t sent_length; + size_t return_length; + char *local_write_ptr= ptr->write_buffer; + size_t write_length= ptr->write_buffer_offset; + + *error= MEMCACHED_SUCCESS; + + WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); + + // UDP Sanity check, make sure that we are not sending somthing too big + if (ptr->type == MEMCACHED_CONNECTION_UDP && write_length > MAX_UDP_DATAGRAM_LENGTH) + { + return -1; + } + + if (ptr->write_buffer_offset == 0 || (ptr->type == MEMCACHED_CONNECTION_UDP + && ptr->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH)) + return 0; + + /* Looking for memory overflows */ +#if defined(DEBUG) + if (write_length == MEMCACHED_MAX_BUFFER) + WATCHPOINT_ASSERT(ptr->write_buffer == local_write_ptr); + WATCHPOINT_ASSERT((ptr->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length)); +#endif + + return_length= 0; + while (write_length) + { + WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); + WATCHPOINT_ASSERT(write_length > 0); + sent_length= 0; + if (ptr->type == MEMCACHED_CONNECTION_UDP) + increment_udp_message_id(ptr); + + WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); + if (with_flush) + { + sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT); + } + else + { + sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT|MSG_MORE); + } + + if (sent_length == SOCKET_ERROR) + { + ptr->cached_errno= get_socket_errno(); +#if 0 // @todo I should look at why we hit this bit of code hard frequently + WATCHPOINT_ERRNO(get_socket_errno()); + WATCHPOINT_NUMBER(get_socket_errno()); +#endif + switch (get_socket_errno()) + { + case ENOBUFS: + continue; + case EWOULDBLOCK: +#ifdef USE_EAGAIN + case EAGAIN: +#endif + { + /* + * We may be blocked on write because the input buffer + * is full. Let's check if we have room in our input + * buffer for more data and retry the write before + * waiting.. + */ + if (repack_input_buffer(ptr) || + process_input_buffer(ptr)) + continue; + + memcached_return_t rc; + rc= io_wait(ptr, MEM_WRITE); + + if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_TIMEOUT) + continue; + + memcached_quit_server(ptr, true); + return -1; + } + case ENOTCONN: + case EPIPE: + default: + memcached_quit_server(ptr, true); + *error= MEMCACHED_ERRNO; + WATCHPOINT_ASSERT(ptr->fd == -1); + return -1; + } + } + + if (ptr->type == MEMCACHED_CONNECTION_UDP && + (size_t)sent_length != write_length) + { + memcached_quit_server(ptr, true); + return -1; + } + + ptr->io_bytes_sent += (uint32_t) sent_length; + + local_write_ptr+= sent_length; + write_length-= (uint32_t) sent_length; + return_length+= (uint32_t) sent_length; + } + + WATCHPOINT_ASSERT(write_length == 0); + // Need to study this assert() WATCHPOINT_ASSERT(return_length == + // ptr->write_buffer_offset); + + // if we are a udp server, the begining of the buffer is reserverd for + // the upd frame header + if (ptr->type == MEMCACHED_CONNECTION_UDP) + ptr->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH; + else + ptr->write_buffer_offset= 0; + + return (ssize_t) return_length; +} + +/* + Eventually we will just kill off the server with the problem. +*/ +void memcached_io_reset(memcached_server_write_instance_st ptr) +{ + memcached_quit_server(ptr, true); +} + +/** + * Read a given number of bytes from the server and place it into a specific + * buffer. Reset the IO channel on this server if an error occurs. + */ +memcached_return_t memcached_safe_read(memcached_server_write_instance_st ptr, + void *dta, + size_t size) +{ + size_t offset= 0; + char *data= static_cast(dta); + + while (offset < size) + { + ssize_t nread; + memcached_return_t rc= memcached_io_read(ptr, data + offset, size - offset, + &nread); + if (rc != MEMCACHED_SUCCESS) + return rc; + + offset+= (size_t) nread; + } + + return MEMCACHED_SUCCESS; +} + +memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr, + char *buffer_ptr, + size_t size) +{ + bool line_complete= false; + size_t total_nr= 0; + + while (!line_complete) + { + if (ptr->read_buffer_length == 0) + { + /* + * We don't have any data in the buffer, so let's fill the read + * buffer. Call the standard read function to avoid duplicating + * the logic. + */ + ssize_t nread; + memcached_return_t rc= memcached_io_read(ptr, buffer_ptr, 1, &nread); + if (rc != MEMCACHED_SUCCESS) + return rc; + + if (*buffer_ptr == '\n') + line_complete= true; + + ++buffer_ptr; + ++total_nr; + } + + /* Now let's look in the buffer and copy as we go! */ + while (ptr->read_buffer_length && total_nr < size && !line_complete) + { + *buffer_ptr = *ptr->read_ptr; + if (*buffer_ptr == '\n') + line_complete = true; + --ptr->read_buffer_length; + ++ptr->read_ptr; + ++total_nr; + ++buffer_ptr; + } + + if (total_nr == size) + return MEMCACHED_PROTOCOL_ERROR; + } + + return MEMCACHED_SUCCESS; +} + +/* + * The udp request id consists of two seperate sections + * 1) The thread id + * 2) The message number + * The thread id should only be set when the memcached_st struct is created + * and should not be changed. + * + * The message num is incremented for each new message we send, this function + * extracts the message number from message_id, increments it and then + * writes the new value back into the header + */ +static void increment_udp_message_id(memcached_server_write_instance_st ptr) +{ + struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer; + uint16_t cur_req= get_udp_datagram_request_id(header); + int msg_num= get_msg_num_from_request_id(cur_req); + int thread_id= get_thread_id_from_request_id(cur_req); + + if (((++msg_num) & UDP_REQUEST_ID_THREAD_MASK) != 0) + msg_num= 0; + + header->request_id= htons((uint16_t) (thread_id | msg_num)); +} + +memcached_return_t memcached_io_init_udp_header(memcached_server_write_instance_st ptr, uint16_t thread_id) +{ + if (thread_id > UDP_REQUEST_ID_MAX_THREAD_ID) + return MEMCACHED_FAILURE; + + struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer; + header->request_id= htons((uint16_t) (generate_udp_request_thread_id(thread_id))); + header->num_datagrams= htons(1); + header->sequence_number= htons(0); + + return MEMCACHED_SUCCESS; +} diff --git a/libmemcached/io.h b/libmemcached/io.h index 85d56b16..a5d34474 100644 --- a/libmemcached/io.h +++ b/libmemcached/io.h @@ -36,12 +36,9 @@ * */ -#ifndef __LIBMEMCACHED_IO_H__ -#define __LIBMEMCACHED_IO_H__ +#pragma once -#if defined(BUILDING_LIBMEMCACHED) - -#include "libmemcached/memcached.h" +#include #define MAX_UDP_DATAGRAM_LENGTH 1400 #define UDP_DATAGRAM_HEADER_LENGTH 8 @@ -117,7 +114,3 @@ memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st #ifdef __cplusplus } #endif - -#endif /* BUILDING_LIBMEMCACHED */ - -#endif /* __LIBMEMCACHED_IO_H__ */ diff --git a/libmemcached/key.c b/libmemcached/key.c deleted file mode 100644 index 76a7d8ed..00000000 --- a/libmemcached/key.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "common.h" - -memcached_return_t memcached_key_test(const char * const *keys, - const size_t *key_length, - size_t number_of_keys) -{ - uint32_t x; - memcached_return_t rc; - - for (x= 0; x < number_of_keys; x++) - { - size_t y; - - rc= memcached_validate_key_length(*(key_length + x), false); - if (rc != MEMCACHED_SUCCESS) - return rc; - - for (y= 0; y < *(key_length + x); y++) - { - if ((isgraph(keys[x][y])) == 0) - return MEMCACHED_BAD_KEY_PROVIDED; - } - } - - return MEMCACHED_SUCCESS; -} - diff --git a/libmemcached/key.cc b/libmemcached/key.cc new file mode 100644 index 00000000..c2c2b14b --- /dev/null +++ b/libmemcached/key.cc @@ -0,0 +1,23 @@ +#include "common.h" + +memcached_return_t memcached_key_test(const char * const *keys, + const size_t *key_length, + size_t number_of_keys) +{ + for (uint32_t x= 0; x < number_of_keys; x++) + { + memcached_return_t rc; + rc= memcached_validate_key_length(*(key_length + x), false); + if (rc != MEMCACHED_SUCCESS) + return rc; + + for (size_t y= 0; y < *(key_length + x); y++) + { + if ((isgraph(keys[x][y])) == 0) + return MEMCACHED_BAD_KEY_PROVIDED; + } + } + + return MEMCACHED_SUCCESS; +} + diff --git a/libmemcached/memcached.c b/libmemcached/memcached.c deleted file mode 100644 index 3c583502..00000000 --- a/libmemcached/memcached.c +++ /dev/null @@ -1,437 +0,0 @@ -/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: - * - * Libmemcached library - * - * Copyright (C) 2011 Data Differential, http://datadifferential.com/ - * Copyright (C) 2006-2009 Brian Aker All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * * The names of its contributors may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -static const memcached_st global_copy= { - .state= { - .is_purging= false, - .is_processing_input= false, - .is_time_for_rebuild= false, - }, - .flags= { - .auto_eject_hosts= false, - .binary_protocol= false, - .buffer_requests= false, - .hash_with_prefix_key= false, - .no_block= false, - .no_reply= false, - .randomize_replica_read= false, - .support_cas= false, - .tcp_nodelay= false, - .use_sort_hosts= false, - .use_udp= false, - .verify_key= false, - .tcp_keepalive= false, - }, -}; - -static inline bool _memcached_init(memcached_st *self) -{ - self->state= global_copy.state; - self->flags= global_copy.flags; - self->virtual_bucket= NULL; - - self->distribution= MEMCACHED_DISTRIBUTION_MODULA; - - hashkit_st *hash_ptr; - hash_ptr= hashkit_create(&self->hashkit); - if (! hash_ptr) - return false; - - self->ketama.continuum= NULL; - self->ketama.continuum_count= 0; - self->ketama.continuum_points_counter= 0; - self->ketama.next_distribution_rebuild= 0; - self->ketama.weighted= false; - - self->number_of_hosts= 0; - self->servers= NULL; - self->last_disconnected_server= NULL; - - self->snd_timeout= 0; - self->rcv_timeout= 0; - self->server_failure_limit= 0; - self->query_id= 0; - - /* TODO, Document why we picked these defaults */ - self->io_msg_watermark= 500; - self->io_bytes_watermark= 65 * 1024; - - self->tcp_keepidle= 0; - - self->io_key_prefetch= 0; - self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT; - self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT; - self->retry_timeout= 0; - - self->send_size= -1; - self->recv_size= -1; - - self->user_data= NULL; - self->number_of_replicas= 0; - hash_ptr= hashkit_create(&self->distribution_hashkit); - if (! hash_ptr) - return false; - - self->allocators= memcached_allocators_return_default(); - - self->on_clone= NULL; - self->on_cleanup= NULL; - self->get_key_failure= NULL; - self->delete_trigger= NULL; - self->callbacks= NULL; - self->sasl.callbacks= NULL; - self->sasl.is_allocated= false; - - self->error_messages= NULL; - self->prefix_key= NULL; - self->configure.initial_pool_size= 1; - self->configure.max_pool_size= 1; - self->configure.filename= NULL; - - return true; -} - -static void _free(memcached_st *ptr, bool release_st) -{ - /* If we have anything open, lets close it now */ - send_quit(ptr); - memcached_server_list_free(memcached_server_list(ptr)); - memcached_result_free(&ptr->result); - - memcached_virtual_bucket_free(ptr); - - if (ptr->last_disconnected_server) - memcached_server_free(ptr->last_disconnected_server); - - if (ptr->on_cleanup) - ptr->on_cleanup(ptr); - - if (ptr->ketama.continuum) - libmemcached_free(ptr, ptr->ketama.continuum); - - memcached_array_free(ptr->prefix_key); - ptr->prefix_key= NULL; - - memcached_error_free(ptr); - - if (ptr->sasl.callbacks) - { -#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT - memcached_destroy_sasl_auth_data(ptr); -#endif - } - - if (release_st) - { - memcached_array_free(ptr->configure.filename); - ptr->configure.filename= NULL; - } - - if (memcached_is_allocated(ptr) && release_st) - { - libmemcached_free(ptr, ptr); - } -} - -memcached_st *memcached_create(memcached_st *ptr) -{ - if (ptr == NULL) - { - ptr= (memcached_st *)malloc(sizeof(memcached_st)); - - if (! ptr) - { - return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */ - } - - ptr->options.is_allocated= true; - } - else - { - ptr->options.is_allocated= false; - } - -#if 0 - memcached_set_purging(ptr, false); - memcached_set_processing_input(ptr, false); -#endif - - if (! _memcached_init(ptr)) - { - memcached_free(ptr); - return NULL; - } - - if (! memcached_result_create(ptr, &ptr->result)) - { - memcached_free(ptr); - return NULL; - } - - WATCHPOINT_ASSERT_INITIALIZED(&ptr->result); - - return ptr; -} - -memcached_st *memcached(const char *string, size_t length) -{ - if (! length || ! string) - { - errno= EINVAL; - return NULL; - } - - memcached_st *self= memcached_create(NULL); - if (! self) - { - errno= ENOMEM; - return NULL; - } - - memcached_return_t rc; - rc= memcached_parse_configuration(self, string, length); - - if (rc == MEMCACHED_SUCCESS && memcached_parse_filename(self)) - { - rc= memcached_parse_configure_file(self, memcached_parse_filename(self), memcached_parse_filename_length(self)); - } - - if (rc != MEMCACHED_SUCCESS) - { - memcached_free(self); - errno= EINVAL; - return NULL; - } - - errno= 0; - - return self; -} - -memcached_return_t memcached_reset(memcached_st *ptr) -{ - WATCHPOINT_ASSERT(ptr); - if (! ptr) - return MEMCACHED_INVALID_ARGUMENTS; - - bool stored_is_allocated= memcached_is_allocated(ptr); - uint64_t query_id= ptr->query_id; - _free(ptr, false); - memcached_create(ptr); - memcached_set_allocated(ptr, stored_is_allocated); - ptr->query_id= query_id; - - if (ptr->configure.filename) - { - return memcached_parse_configure_file(ptr, memcached_param_array(ptr->configure.filename)); - } - - return MEMCACHED_SUCCESS; -} - -void memcached_servers_reset(memcached_st *ptr) -{ - if (! ptr) - return; - - memcached_server_list_free(memcached_server_list(ptr)); - - memcached_server_list_set(ptr, NULL); - ptr->number_of_hosts= 0; - if (ptr->last_disconnected_server) - { - memcached_server_free(ptr->last_disconnected_server); - } - ptr->last_disconnected_server= NULL; - ptr->server_failure_limit= 0; -} - -void memcached_reset_last_disconnected_server(memcached_st *ptr) -{ - if (! ptr) - return; - - if (ptr->last_disconnected_server) - { - memcached_server_free(ptr->last_disconnected_server); - ptr->last_disconnected_server= NULL; - } -} - -void memcached_free(memcached_st *ptr) -{ - if (! ptr) - return; - - _free(ptr, true); -} - -/* - clone is the destination, while source is the structure to clone. - If source is NULL the call is the same as if a memcached_create() was - called. -*/ -memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source) -{ - memcached_return_t rc= MEMCACHED_SUCCESS; - memcached_st *new_clone; - - if (source == NULL) - return memcached_create(clone); - - if (clone && memcached_is_allocated(clone)) - { - return NULL; - } - - new_clone= memcached_create(clone); - - if (new_clone == NULL) - return NULL; - - new_clone->flags= source->flags; - new_clone->send_size= source->send_size; - new_clone->recv_size= source->recv_size; - new_clone->poll_timeout= source->poll_timeout; - new_clone->connect_timeout= source->connect_timeout; - new_clone->retry_timeout= source->retry_timeout; - new_clone->distribution= source->distribution; - - hashkit_st *hash_ptr; - - hash_ptr= hashkit_clone(&new_clone->hashkit, &source->hashkit); - if (! hash_ptr) - { - memcached_free(new_clone); - return NULL; - } - - hash_ptr= hashkit_clone(&new_clone->distribution_hashkit, &source->distribution_hashkit); - if (! hash_ptr) - { - memcached_free(new_clone); - return NULL; - } - - new_clone->user_data= source->user_data; - - new_clone->snd_timeout= source->snd_timeout; - new_clone->rcv_timeout= source->rcv_timeout; - - new_clone->on_clone= source->on_clone; - new_clone->on_cleanup= source->on_cleanup; - - new_clone->allocators= source->allocators; - - new_clone->get_key_failure= source->get_key_failure; - new_clone->delete_trigger= source->delete_trigger; - new_clone->server_failure_limit= source->server_failure_limit; - new_clone->io_msg_watermark= source->io_msg_watermark; - new_clone->io_bytes_watermark= source->io_bytes_watermark; - new_clone->io_key_prefetch= source->io_key_prefetch; - new_clone->number_of_replicas= source->number_of_replicas; - new_clone->tcp_keepidle= source->tcp_keepidle; - - if (memcached_server_count(source)) - rc= memcached_push(new_clone, source); - - if (rc != MEMCACHED_SUCCESS) - { - memcached_free(new_clone); - - return NULL; - } - - - new_clone->prefix_key= memcached_array_clone(new_clone, source->prefix_key); - -#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT - if (source->sasl.callbacks) - { - if (memcached_clone_sasl(new_clone, source) != MEMCACHED_SUCCESS) - { - memcached_free(new_clone); - return NULL; - } - } -#endif - - rc= run_distribution(new_clone); - - if (rc != MEMCACHED_SUCCESS) - { - memcached_free(new_clone); - - return NULL; - } - - if (source->on_clone) - source->on_clone(new_clone, source); - - return new_clone; -} - -void *memcached_get_user_data(const memcached_st *ptr) -{ - return ptr->user_data; -} - -void *memcached_set_user_data(memcached_st *ptr, void *data) -{ - void *ret= ptr->user_data; - ptr->user_data= data; - - return ret; -} - -memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source) -{ - return memcached_server_push(destination, source->servers); -} - -memcached_server_write_instance_st memcached_server_instance_fetch(memcached_st *ptr, uint32_t server_key) -{ - return &ptr->servers[server_key]; -} - -memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key) -{ - return &ptr->servers[server_key]; -} diff --git a/libmemcached/memcached.cc b/libmemcached/memcached.cc new file mode 100644 index 00000000..1197dd5d --- /dev/null +++ b/libmemcached/memcached.cc @@ -0,0 +1,464 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#if 0 +static const memcached_st global_copy= { + .state= { + .is_purging= false, // .is_purging + .is_processing_input= false, // is_processing_input + .is_time_for_rebuild= false, + }, + .flags= { + .auto_eject_hosts= false, + .binary_protocol= false, + .buffer_requests= false, + .hash_with_prefix_key= false, + .no_block= false, + .no_reply= false, + .randomize_replica_read= false, + .support_cas= false, + .tcp_nodelay= false, + .use_sort_hosts= false, + .use_udp= false, + .verify_key= false, + .tcp_keepalive= false, + }, +}; +#endif + +static inline bool _memcached_init(memcached_st *self) +{ + self->state.is_purging= false; + self->state.is_processing_input= false; + self->state.is_time_for_rebuild= false; + + self->flags.auto_eject_hosts= false; + self->flags.binary_protocol= false; + self->flags.buffer_requests= false; + self->flags.hash_with_prefix_key= false; + self->flags.no_block= false; + self->flags.no_reply= false; + self->flags.randomize_replica_read= false; + self->flags.support_cas= false; + self->flags.tcp_nodelay= false; + self->flags.use_sort_hosts= false; + self->flags.use_udp= false; + self->flags.verify_key= false; + self->flags.tcp_keepalive= false; + + self->virtual_bucket= NULL; + + self->distribution= MEMCACHED_DISTRIBUTION_MODULA; + + hashkit_st *hash_ptr; + hash_ptr= hashkit_create(&self->hashkit); + if (! hash_ptr) + return false; + + self->ketama.continuum= NULL; + self->ketama.continuum_count= 0; + self->ketama.continuum_points_counter= 0; + self->ketama.next_distribution_rebuild= 0; + self->ketama.weighted= false; + + self->number_of_hosts= 0; + self->servers= NULL; + self->last_disconnected_server= NULL; + + self->snd_timeout= 0; + self->rcv_timeout= 0; + self->server_failure_limit= 0; + self->query_id= 1; // 0 is considered invalid + + /* TODO, Document why we picked these defaults */ + self->io_msg_watermark= 500; + self->io_bytes_watermark= 65 * 1024; + + self->tcp_keepidle= 0; + + self->io_key_prefetch= 0; + self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT; + self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT; + self->retry_timeout= 0; + + self->send_size= -1; + self->recv_size= -1; + + self->user_data= NULL; + self->number_of_replicas= 0; + hash_ptr= hashkit_create(&self->distribution_hashkit); + if (! hash_ptr) + return false; + + self->allocators= memcached_allocators_return_default(); + + self->on_clone= NULL; + self->on_cleanup= NULL; + self->get_key_failure= NULL; + self->delete_trigger= NULL; + self->callbacks= NULL; + self->sasl.callbacks= NULL; + self->sasl.is_allocated= false; + + self->error_messages= NULL; + self->prefix_key= NULL; + self->configure.initial_pool_size= 1; + self->configure.max_pool_size= 1; + self->configure.version= -1; + self->configure.filename= NULL; + + return true; +} + +static void _free(memcached_st *ptr, bool release_st) +{ + /* If we have anything open, lets close it now */ + send_quit(ptr); + memcached_server_list_free(memcached_server_list(ptr)); + memcached_result_free(&ptr->result); + + memcached_virtual_bucket_free(ptr); + + if (ptr->last_disconnected_server) + memcached_server_free(ptr->last_disconnected_server); + + if (ptr->on_cleanup) + ptr->on_cleanup(ptr); + + if (ptr->ketama.continuum) + libmemcached_free(ptr, ptr->ketama.continuum); + + memcached_array_free(ptr->prefix_key); + ptr->prefix_key= NULL; + + memcached_error_free(ptr); + + if (ptr->sasl.callbacks) + { +#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT + memcached_destroy_sasl_auth_data(ptr); +#endif + } + + if (release_st) + { + memcached_array_free(ptr->configure.filename); + ptr->configure.filename= NULL; + } + + if (memcached_is_allocated(ptr) && release_st) + { + libmemcached_free(ptr, ptr); + } +} + +memcached_st *memcached_create(memcached_st *ptr) +{ + if (ptr == NULL) + { + ptr= (memcached_st *)malloc(sizeof(memcached_st)); + + if (! ptr) + { + return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */ + } + + ptr->options.is_allocated= true; + } + else + { + ptr->options.is_allocated= false; + } + +#if 0 + memcached_set_purging(ptr, false); + memcached_set_processing_input(ptr, false); +#endif + + if (! _memcached_init(ptr)) + { + memcached_free(ptr); + return NULL; + } + + if (! memcached_result_create(ptr, &ptr->result)) + { + memcached_free(ptr); + return NULL; + } + + WATCHPOINT_ASSERT_INITIALIZED(&ptr->result); + + return ptr; +} + +memcached_st *memcached(const char *string, size_t length) +{ + if (! length || ! string) + { + errno= EINVAL; + return NULL; + } + + memcached_st *self= memcached_create(NULL); + if (! self) + { + errno= ENOMEM; + return NULL; + } + + memcached_return_t rc; + rc= memcached_parse_configuration(self, string, length); + + if (rc == MEMCACHED_SUCCESS && memcached_parse_filename(self)) + { + rc= memcached_parse_configure_file(self, memcached_parse_filename(self), memcached_parse_filename_length(self)); + } + + if (rc != MEMCACHED_SUCCESS) + { + memcached_free(self); + errno= EINVAL; + return NULL; + } + + errno= 0; + + return self; +} + +memcached_return_t memcached_reset(memcached_st *ptr) +{ + WATCHPOINT_ASSERT(ptr); + if (not ptr) + return MEMCACHED_INVALID_ARGUMENTS; + + bool stored_is_allocated= memcached_is_allocated(ptr); + uint64_t query_id= ptr->query_id; + _free(ptr, false); + memcached_create(ptr); + memcached_set_allocated(ptr, stored_is_allocated); + ptr->query_id= query_id; + + if (ptr->configure.filename) + { + return memcached_parse_configure_file(ptr, memcached_param_array(ptr->configure.filename)); + } + + return MEMCACHED_SUCCESS; +} + +void memcached_servers_reset(memcached_st *ptr) +{ + if (! ptr) + return; + + memcached_server_list_free(memcached_server_list(ptr)); + + memcached_server_list_set(ptr, NULL); + ptr->number_of_hosts= 0; + if (ptr->last_disconnected_server) + { + memcached_server_free(ptr->last_disconnected_server); + } + ptr->last_disconnected_server= NULL; + ptr->server_failure_limit= 0; +} + +void memcached_reset_last_disconnected_server(memcached_st *ptr) +{ + if (! ptr) + return; + + if (ptr->last_disconnected_server) + { + memcached_server_free(ptr->last_disconnected_server); + ptr->last_disconnected_server= NULL; + } +} + +void memcached_free(memcached_st *ptr) +{ + if (! ptr) + return; + + _free(ptr, true); +} + +/* + clone is the destination, while source is the structure to clone. + If source is NULL the call is the same as if a memcached_create() was + called. +*/ +memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source) +{ + memcached_return_t rc= MEMCACHED_SUCCESS; + memcached_st *new_clone; + + if (source == NULL) + return memcached_create(clone); + + if (clone && memcached_is_allocated(clone)) + { + return NULL; + } + + new_clone= memcached_create(clone); + + if (new_clone == NULL) + return NULL; + + new_clone->flags= source->flags; + new_clone->send_size= source->send_size; + new_clone->recv_size= source->recv_size; + new_clone->poll_timeout= source->poll_timeout; + new_clone->connect_timeout= source->connect_timeout; + new_clone->retry_timeout= source->retry_timeout; + new_clone->distribution= source->distribution; + + hashkit_st *hash_ptr; + + hash_ptr= hashkit_clone(&new_clone->hashkit, &source->hashkit); + if (! hash_ptr) + { + memcached_free(new_clone); + return NULL; + } + + hash_ptr= hashkit_clone(&new_clone->distribution_hashkit, &source->distribution_hashkit); + if (! hash_ptr) + { + memcached_free(new_clone); + return NULL; + } + + new_clone->user_data= source->user_data; + + new_clone->snd_timeout= source->snd_timeout; + new_clone->rcv_timeout= source->rcv_timeout; + + new_clone->on_clone= source->on_clone; + new_clone->on_cleanup= source->on_cleanup; + + new_clone->allocators= source->allocators; + + new_clone->get_key_failure= source->get_key_failure; + new_clone->delete_trigger= source->delete_trigger; + new_clone->server_failure_limit= source->server_failure_limit; + new_clone->io_msg_watermark= source->io_msg_watermark; + new_clone->io_bytes_watermark= source->io_bytes_watermark; + new_clone->io_key_prefetch= source->io_key_prefetch; + new_clone->number_of_replicas= source->number_of_replicas; + new_clone->tcp_keepidle= source->tcp_keepidle; + + if (memcached_server_count(source)) + rc= memcached_push(new_clone, source); + + if (rc != MEMCACHED_SUCCESS) + { + memcached_free(new_clone); + + return NULL; + } + + + new_clone->prefix_key= memcached_array_clone(new_clone, source->prefix_key); + +#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT + if (source->sasl.callbacks) + { + if (memcached_clone_sasl(new_clone, source) != MEMCACHED_SUCCESS) + { + memcached_free(new_clone); + return NULL; + } + } +#endif + + rc= run_distribution(new_clone); + + if (rc != MEMCACHED_SUCCESS) + { + memcached_free(new_clone); + + return NULL; + } + + if (source->on_clone) + source->on_clone(new_clone, source); + + return new_clone; +} + +void *memcached_get_user_data(const memcached_st *ptr) +{ + return ptr->user_data; +} + +void *memcached_set_user_data(memcached_st *ptr, void *data) +{ + void *ret= ptr->user_data; + ptr->user_data= data; + + return ret; +} + +memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source) +{ + return memcached_server_push(destination, source->servers); +} + +memcached_server_write_instance_st memcached_server_instance_fetch(memcached_st *ptr, uint32_t server_key) +{ + return &ptr->servers[server_key]; +} + +memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key) +{ + return &ptr->servers[server_key]; +} + +uint64_t memcached_query_id(const memcached_st *self) +{ + if (not self) + return 0; + + return self->query_id; +} diff --git a/libmemcached/memcached.h b/libmemcached/memcached.h index 2f1caf2b..f32fe0e7 100644 --- a/libmemcached/memcached.h +++ b/libmemcached/memcached.h @@ -35,8 +35,7 @@ * */ -#ifndef __LIBMEMCACHED_MEMCACHED_H__ -#define __LIBMEMCACHED_MEMCACHED_H__ +#pragma once #include #include @@ -51,12 +50,14 @@ #include #include #include +#include #include #include #include #include #include #include + // Everything above this line must be in the order specified. #include #include @@ -142,13 +143,7 @@ struct memcached_st { struct memcached_virtual_bucket_t *virtual_bucket; - struct _allocators_st { - memcached_calloc_fn calloc; - memcached_free_fn free; - memcached_malloc_fn malloc; - memcached_realloc_fn realloc; - void *context; - } allocators; + struct memcached_allocator_t allocators; memcached_clone_fn on_clone; memcached_cleanup_fn on_cleanup; @@ -161,6 +156,7 @@ struct memcached_st { struct { uint32_t initial_pool_size; uint32_t max_pool_size; + int32_t version; // This is used by pool and others to determine if the memcached_st is out of date. struct memcached_array_st *filename; } configure; struct { @@ -209,9 +205,9 @@ memcached_server_instance_st memcached_server_instance_by_position(const memcach LIBMEMCACHED_API uint32_t memcached_server_count(const memcached_st *); +LIBMEMCACHED_API +uint64_t memcached_query_id(const memcached_st *); + #ifdef __cplusplus } // extern "C" #endif - -#endif /* __LIBMEMCACHED_MEMCACHED_H__ */ - diff --git a/libmemcached/memcached.hpp b/libmemcached/memcached.hpp index 55f96c7e..b0985715 100644 --- a/libmemcached/memcached.hpp +++ b/libmemcached/memcached.hpp @@ -13,8 +13,6 @@ */ #pragma once -#ifndef LIBMEMCACHEDPP_H -#define LIBMEMCACHEDPP_H #include #include @@ -37,8 +35,7 @@ class Memcache { public: - Memcache() - : + Memcache() : servers_list(), memc(), result() @@ -261,17 +258,12 @@ public: * this vector * @return true on success; false otherwise */ - bool get(const std::string &key, - std::vector &ret_val) throw (Error) + bool get(const std::string &key, std::vector &ret_val) { uint32_t flags= 0; memcached_return_t rc; size_t value_length= 0; - if (key.empty()) - { - throw(Error("the key supplied is empty!", false)); - } char *value= memcached_get(&memc, key.c_str(), key.length(), &value_length, &flags, &rc); if (value != NULL && ret_val.empty()) @@ -298,16 +290,12 @@ public: */ bool getByKey(const std::string &master_key, const std::string &key, - std::vector &ret_val) throw(Error) + std::vector &ret_val) { uint32_t flags= 0; memcached_return_t rc; size_t value_length= 0; - if (master_key.empty() || key.empty()) - { - throw(Error("the master key or key supplied is empty!", false)); - } char *value= memcached_get_by_key(&memc, master_key.c_str(), master_key.length(), key.c_str(), key.length(), @@ -379,12 +367,8 @@ public: bool set(const std::string &key, const std::vector &value, time_t expiration, - uint32_t flags) throw(Error) + uint32_t flags) { - if (key.empty() || value.empty()) - { - throw(Error("the key or value supplied is empty!", false)); - } memcached_return_t rc= memcached_set(&memc, key.c_str(), key.length(), &value[0], value.size(), @@ -407,14 +391,8 @@ public: const std::string &key, const std::vector &value, time_t expiration, - uint32_t flags) throw(Error) + uint32_t flags) { - if (master_key.empty() || - key.empty() || - value.empty()) - { - throw(Error("the key or value supplied is empty!", false)); - } memcached_return_t rc= memcached_set_by_key(&memc, master_key.c_str(), master_key.length(), key.c_str(), key.length(), @@ -437,12 +415,8 @@ public: bool setAll(std::vector &keys, std::vector< std::vector *> &values, time_t expiration, - uint32_t flags) throw(Error) + uint32_t flags) { - if (keys.size() != values.size()) - { - throw(Error("The number of keys and values do not match!", false)); - } bool retval= true; std::vector::iterator key_it= keys.begin(); std::vector< std::vector *>::iterator val_it= values.begin(); @@ -470,23 +444,18 @@ public: */ bool setAll(std::map > &key_value_map, time_t expiration, - uint32_t flags) throw(Error) + uint32_t flags) { - if (key_value_map.empty()) - { - throw(Error("The key/values are not properly set!", false)); - } bool retval= true; - std::map >::iterator it= - key_value_map.begin(); + std::map >::iterator it= key_value_map.begin(); + while (it != key_value_map.end()) { retval= set(it->first, it->second, expiration, flags); if (retval == false) { - std::string err_buff("There was an error setting the key "); - err_buff.append(it->first); - throw(Error(err_buff, false)); + // We should tell the user what the key that failed was + return false; } ++it; } @@ -503,12 +472,8 @@ public: * @param[out] value store the result of the increment here * @return true on success; false otherwise */ - bool increment(const std::string &key, uint32_t offset, uint64_t *value) throw(Error) + bool increment(const std::string &key, uint32_t offset, uint64_t *value) { - if (key.empty()) - { - throw(Error("the key supplied is empty!", false)); - } memcached_return_t rc= memcached_increment(&memc, key.c_str(), key.length(), offset, value); return (rc == MEMCACHED_SUCCESS); @@ -525,12 +490,7 @@ public: * @return true on success; false otherwise */ bool decrement(const std::string &key, uint32_t offset, uint64_t *value) - throw(Error) { - if (key.empty()) - { - throw(Error("the key supplied is empty!", false)); - } memcached_return_t rc= memcached_decrement(&memc, key.c_str(), key.length(), offset, value); @@ -547,12 +507,7 @@ public: * @return true on success; false otherwise */ bool add(const std::string &key, const std::vector &value) - throw(Error) { - if (key.empty() || value.empty()) - { - throw(Error("the key or value supplied is empty!", false)); - } memcached_return_t rc= memcached_add(&memc, key.c_str(), key.length(), &value[0], value.size(), 0, 0); return (rc == MEMCACHED_SUCCESS); @@ -570,14 +525,8 @@ public: */ bool addByKey(const std::string &master_key, const std::string &key, - const std::vector &value) throw(Error) + const std::vector &value) { - if (master_key.empty() || - key.empty() || - value.empty()) - { - throw(Error("the master key or key supplied is empty!", false)); - } memcached_return_t rc= memcached_add_by_key(&memc, master_key.c_str(), master_key.length(), @@ -597,13 +546,8 @@ public: * @param[in[ value value to replace object with * @return true on success; false otherwise */ - bool replace(const std::string &key, const std::vector &value) throw(Error) + bool replace(const std::string &key, const std::vector &value) { - if (key.empty() || - value.empty()) - { - throw(Error("the key or value supplied is empty!", false)); - } memcached_return_t rc= memcached_replace(&memc, key.c_str(), key.length(), &value[0], value.size(), 0, 0); @@ -624,12 +568,6 @@ public: const std::string &key, const std::vector &value) { - if (master_key.empty() || - key.empty() || - value.empty()) - { - throw(Error("the master key or key supplied is empty!", false)); - } memcached_return_t rc= memcached_replace_by_key(&memc, master_key.c_str(), master_key.length(), @@ -649,12 +587,7 @@ public: * @return true on success; false otherwise */ bool prepend(const std::string &key, const std::vector &value) - throw(Error) { - if (key.empty() || value.empty()) - { - throw(Error("the key or value supplied is empty!", false)); - } memcached_return_t rc= memcached_prepend(&memc, key.c_str(), key.length(), &value[0], value.size(), 0, 0); return (rc == MEMCACHED_SUCCESS); @@ -673,14 +606,7 @@ public: bool prependByKey(const std::string &master_key, const std::string &key, const std::vector &value) - throw(Error) { - if (master_key.empty() || - key.empty() || - value.empty()) - { - throw(Error("the master key or key supplied is empty!", false)); - } memcached_return_t rc= memcached_prepend_by_key(&memc, master_key.c_str(), master_key.length(), @@ -701,18 +627,13 @@ public: * @return true on success; false otherwise */ bool append(const std::string &key, const std::vector &value) - throw(Error) { - if (key.empty() || value.empty()) - { - throw(Error("the key or value supplied is empty!", false)); - } memcached_return_t rc= memcached_append(&memc, - key.c_str(), - key.length(), - &value[0], - value.size(), - 0, 0); + key.c_str(), + key.length(), + &value[0], + value.size(), + 0, 0); return (rc == MEMCACHED_SUCCESS); } @@ -729,22 +650,15 @@ public: bool appendByKey(const std::string &master_key, const std::string &key, const std::vector &value) - throw(Error) { - if (master_key.empty() || - key.empty() || - value.empty()) - { - throw(Error("the master key or key supplied is empty!", false)); - } memcached_return_t rc= memcached_append_by_key(&memc, - master_key.c_str(), - master_key.length(), - key.c_str(), - key.length(), - &value[0], - value.size(), - 0, 0); + master_key.c_str(), + master_key.length(), + key.c_str(), + key.length(), + &value[0], + value.size(), + 0, 0); return (rc == MEMCACHED_SUCCESS); } @@ -758,12 +672,8 @@ public: */ bool cas(const std::string &key, const std::vector &value, - uint64_t cas_arg) throw(Error) + uint64_t cas_arg) { - if (key.empty() || value.empty()) - { - throw(Error("the key or value supplied is empty!", false)); - } memcached_return_t rc= memcached_cas(&memc, key.c_str(), key.length(), &value[0], value.size(), 0, 0, cas_arg); @@ -783,14 +693,8 @@ public: bool casByKey(const std::string &master_key, const std::string &key, const std::vector &value, - uint64_t cas_arg) throw(Error) + uint64_t cas_arg) { - if (master_key.empty() || - key.empty() || - value.empty()) - { - throw(Error("the master key, key or value supplied is empty!", false)); - } memcached_return_t rc= memcached_cas_by_key(&memc, master_key.c_str(), master_key.length(), @@ -808,12 +712,8 @@ public: * @param[in] key key of object to delete * @return true on success; false otherwise */ - bool remove(const std::string &key) throw(Error) + bool remove(const std::string &key) { - if (key.empty()) - { - throw(Error("the key supplied is empty!", false)); - } memcached_return_t rc= memcached_delete(&memc, key.c_str(), key.length(), 0); return (rc == MEMCACHED_SUCCESS); } @@ -825,13 +725,8 @@ public: * @param[in] expiration time to delete the object after * @return true on success; false otherwise */ - bool remove(const std::string &key, - time_t expiration) throw(Error) + bool remove(const std::string &key, time_t expiration) { - if (key.empty()) - { - throw(Error("the key supplied is empty!", false)); - } memcached_return_t rc= memcached_delete(&memc, key.c_str(), key.length(), @@ -847,12 +742,8 @@ public: * @return true on success; false otherwise */ bool removeByKey(const std::string &master_key, - const std::string &key) throw(Error) + const std::string &key) { - if (master_key.empty() || key.empty()) - { - throw(Error("the master key or key supplied is empty!", false)); - } memcached_return_t rc= memcached_delete_by_key(&memc, master_key.c_str(), master_key.length(), @@ -872,12 +763,8 @@ public: */ bool removeByKey(const std::string &master_key, const std::string &key, - time_t expiration) throw(Error) + time_t expiration) { - if (master_key.empty() || key.empty()) - { - throw(Error("the master key or key supplied is empty!", false)); - } memcached_return_t rc= memcached_delete_by_key(&memc, master_key.c_str(), master_key.length(), @@ -900,27 +787,6 @@ public: return (rc == MEMCACHED_SUCCESS); } - /** - * Callback function for result sets. It passes the result - * sets to the list of functions provided. - * - * @param[in] callback list of callback functions - * @param[in] context pointer to memory reference that is - * supplied to the calling function - * @param[in] num_of_callbacks number of callback functions - * @return true on success; false otherwise - */ - bool fetchExecute(memcached_execute_fn *callback, - void *context, - uint32_t num_of_callbacks) - { - memcached_return_t rc= memcached_fetch_execute(&memc, - callback, - context, - num_of_callbacks); - return (rc == MEMCACHED_SUCCESS); - } - /** * Get the library version string. * @return std::string containing a copy of the library version string. @@ -996,5 +862,3 @@ private: }; } - -#endif /* LIBMEMCACHEDPP_H */ diff --git a/libmemcached/memcached/protocol_binary.h b/libmemcached/memcached/protocol_binary.h index 4509bbcb..7a253ae7 100644 --- a/libmemcached/memcached/protocol_binary.h +++ b/libmemcached/memcached/protocol_binary.h @@ -218,12 +218,13 @@ extern "C" /** * Definition of a request-packet containing no extras */ - typedef union { + union protocol_binary_request_no_extras { struct { protocol_binary_request_header header; } message; uint8_t bytes[sizeof(protocol_binary_request_header)]; - } protocol_binary_request_no_extras; + }; + typedef union protocol_binary_request_no_extras protocol_binary_request_no_extras; /** * Definition of a response-packet containing no extras diff --git a/libmemcached/options/context.h b/libmemcached/options/context.h index bbca66c8..226284d9 100644 --- a/libmemcached/options/context.h +++ b/libmemcached/options/context.h @@ -90,7 +90,7 @@ public: const char *set_hostname(const char *str, size_t size) { - size_t copy_length= std::min((size_t)NI_MAXHOST, size); + size_t copy_length= (size_t)NI_MAXHOST > size ? size : (size_t)NI_MAXHOST; memcpy(_hostname, str, copy_length); _hostname[copy_length]= 0; diff --git a/libmemcached/options/parser.cc b/libmemcached/options/parser.cc index 91dfcd29..c0c5cc25 100644 --- a/libmemcached/options/parser.cc +++ b/libmemcached/options/parser.cc @@ -82,14 +82,13 @@ #include +#include #include #include #include -#include -#include +#include #pragma GCC diagnostic ignored "-Wold-style-cast" -#include int conf_lex(YYSTYPE* lvalp, void* scanner); @@ -104,7 +103,7 @@ inline void config_error(Context *context, yyscan_t *scanner, const char *error) /* Line 189 of yacc.c */ -#line 108 "libmemcached/options/parser.cc" +#line 107 "libmemcached/options/parser.cc" /* Enabling traces. */ #ifndef YYDEBUG @@ -215,7 +214,7 @@ inline void config_error(Context *context, yyscan_t *scanner, const char *error) /* Line 264 of yacc.c */ -#line 219 "libmemcached/options/parser.cc" +#line 218 "libmemcached/options/parser.cc" #ifdef short # undef short @@ -524,13 +523,13 @@ static const yytype_int8 yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 157, 157, 158, 162, 164, 166, 168, 173, 178, - 182, 186, 197, 205, 213, 217, 221, 225, 229, 236, - 243, 254, 261, 268, 275, 281, 285, 289, 293, 297, - 301, 305, 309, 313, 317, 321, 325, 332, 336, 340, - 344, 348, 352, 356, 360, 364, 368, 372, 376, 383, - 384, 389, 390, 395, 399, 403, 407, 411, 415, 419, - 423, 427, 434, 438, 446, 450, 454 + 0, 156, 156, 157, 161, 163, 165, 167, 172, 177, + 181, 185, 196, 204, 212, 216, 220, 224, 228, 235, + 242, 253, 260, 267, 274, 280, 284, 288, 292, 296, + 300, 304, 308, 312, 316, 320, 324, 331, 335, 339, + 343, 347, 351, 355, 359, 363, 367, 371, 375, 382, + 383, 388, 389, 394, 398, 402, 406, 410, 414, 418, + 422, 426, 433, 437, 445, 449, 453 }; #endif @@ -1522,28 +1521,28 @@ yyreduce: case 4: /* Line 1464 of yacc.c */ -#line 163 "libmemcached/options/parser.yy" +#line 162 "libmemcached/options/parser.yy" { ;} break; case 5: /* Line 1464 of yacc.c */ -#line 165 "libmemcached/options/parser.yy" +#line 164 "libmemcached/options/parser.yy" { ;} break; case 6: /* Line 1464 of yacc.c */ -#line 167 "libmemcached/options/parser.yy" +#line 166 "libmemcached/options/parser.yy" { ;} break; case 7: /* Line 1464 of yacc.c */ -#line 169 "libmemcached/options/parser.yy" +#line 168 "libmemcached/options/parser.yy" { context->set_end(); YYACCEPT; @@ -1553,7 +1552,7 @@ yyreduce: case 8: /* Line 1464 of yacc.c */ -#line 174 "libmemcached/options/parser.yy" +#line 173 "libmemcached/options/parser.yy" { context->rc= MEMCACHED_PARSE_USER_ERROR; parser_abort(context, NULL); @@ -1563,7 +1562,7 @@ yyreduce: case 9: /* Line 1464 of yacc.c */ -#line 179 "libmemcached/options/parser.yy" +#line 178 "libmemcached/options/parser.yy" { memcached_reset(context->memc); ;} @@ -1572,7 +1571,7 @@ yyreduce: case 10: /* Line 1464 of yacc.c */ -#line 183 "libmemcached/options/parser.yy" +#line 182 "libmemcached/options/parser.yy" { yydebug= 1; ;} @@ -1581,7 +1580,7 @@ yyreduce: case 11: /* Line 1464 of yacc.c */ -#line 187 "libmemcached/options/parser.yy" +#line 186 "libmemcached/options/parser.yy" { if ((context->rc= memcached_parse_configure_file(context->memc, (yyvsp[(3) - (3)].string).c_str, (yyvsp[(3) - (3)].string).length)) != MEMCACHED_SUCCESS) { @@ -1593,7 +1592,7 @@ yyreduce: case 12: /* Line 1464 of yacc.c */ -#line 198 "libmemcached/options/parser.yy" +#line 197 "libmemcached/options/parser.yy" { if ((context->rc= memcached_server_add_with_weight(context->memc, (yyvsp[(2) - (4)].server).c_str, (yyvsp[(2) - (4)].server).port, (yyvsp[(2) - (4)].server).weight)) != MEMCACHED_SUCCESS) { @@ -1606,7 +1605,7 @@ yyreduce: case 13: /* Line 1464 of yacc.c */ -#line 206 "libmemcached/options/parser.yy" +#line 205 "libmemcached/options/parser.yy" { if ((context->rc= memcached_server_add_with_weight(context->memc, (yyvsp[(2) - (4)].server).c_str, (yyvsp[(2) - (4)].server).port, (yyvsp[(2) - (4)].server).weight)) != MEMCACHED_SUCCESS) { @@ -1619,7 +1618,7 @@ yyreduce: case 14: /* Line 1464 of yacc.c */ -#line 214 "libmemcached/options/parser.yy" +#line 213 "libmemcached/options/parser.yy" { memcached_set_configuration_file(context->memc, (yyvsp[(2) - (2)].string).c_str, (yyvsp[(2) - (2)].string).length); ;} @@ -1628,7 +1627,7 @@ yyreduce: case 15: /* Line 1464 of yacc.c */ -#line 218 "libmemcached/options/parser.yy" +#line 217 "libmemcached/options/parser.yy" { context->memc->configure.initial_pool_size= (yyvsp[(2) - (2)].number); ;} @@ -1637,7 +1636,7 @@ yyreduce: case 16: /* Line 1464 of yacc.c */ -#line 222 "libmemcached/options/parser.yy" +#line 221 "libmemcached/options/parser.yy" { context->memc->configure.max_pool_size= (yyvsp[(2) - (2)].number); ;} @@ -1646,7 +1645,7 @@ yyreduce: case 18: /* Line 1464 of yacc.c */ -#line 230 "libmemcached/options/parser.yy" +#line 229 "libmemcached/options/parser.yy" { if ((context->rc= memcached_set_prefix_key(context->memc, (yyvsp[(2) - (2)].string).c_str, (yyvsp[(2) - (2)].string).length)) != MEMCACHED_SUCCESS) { @@ -1658,7 +1657,7 @@ yyreduce: case 19: /* Line 1464 of yacc.c */ -#line 237 "libmemcached/options/parser.yy" +#line 236 "libmemcached/options/parser.yy" { if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, (yyvsp[(2) - (2)].distribution))) != MEMCACHED_SUCCESS) { @@ -1670,7 +1669,7 @@ yyreduce: case 20: /* Line 1464 of yacc.c */ -#line 244 "libmemcached/options/parser.yy" +#line 243 "libmemcached/options/parser.yy" { if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, (yyvsp[(2) - (4)].distribution))) != MEMCACHED_SUCCESS) { @@ -1686,7 +1685,7 @@ yyreduce: case 21: /* Line 1464 of yacc.c */ -#line 255 "libmemcached/options/parser.yy" +#line 254 "libmemcached/options/parser.yy" { if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_HASH, (yyvsp[(2) - (2)].hash))) != MEMCACHED_SUCCESS) { @@ -1698,7 +1697,7 @@ yyreduce: case 22: /* Line 1464 of yacc.c */ -#line 262 "libmemcached/options/parser.yy" +#line 261 "libmemcached/options/parser.yy" { if ((context->rc= memcached_behavior_set(context->memc, (yyvsp[(1) - (2)].behavior), (yyvsp[(2) - (2)].number))) != MEMCACHED_SUCCESS) { @@ -1710,7 +1709,7 @@ yyreduce: case 23: /* Line 1464 of yacc.c */ -#line 269 "libmemcached/options/parser.yy" +#line 268 "libmemcached/options/parser.yy" { if ((context->rc= memcached_behavior_set(context->memc, (yyvsp[(1) - (1)].behavior), true)) != MEMCACHED_SUCCESS) { @@ -1722,7 +1721,7 @@ yyreduce: case 24: /* Line 1464 of yacc.c */ -#line 276 "libmemcached/options/parser.yy" +#line 275 "libmemcached/options/parser.yy" { ;} break; @@ -1730,7 +1729,7 @@ yyreduce: case 25: /* Line 1464 of yacc.c */ -#line 282 "libmemcached/options/parser.yy" +#line 281 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS; ;} @@ -1739,7 +1738,7 @@ yyreduce: case 26: /* Line 1464 of yacc.c */ -#line 286 "libmemcached/options/parser.yy" +#line 285 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT; ;} @@ -1748,7 +1747,7 @@ yyreduce: case 27: /* Line 1464 of yacc.c */ -#line 290 "libmemcached/options/parser.yy" +#line 289 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK; ;} @@ -1757,7 +1756,7 @@ yyreduce: case 28: /* Line 1464 of yacc.c */ -#line 294 "libmemcached/options/parser.yy" +#line 293 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK; ;} @@ -1766,7 +1765,7 @@ yyreduce: case 29: /* Line 1464 of yacc.c */ -#line 298 "libmemcached/options/parser.yy" +#line 297 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH; ;} @@ -1775,7 +1774,7 @@ yyreduce: case 30: /* Line 1464 of yacc.c */ -#line 302 "libmemcached/options/parser.yy" +#line 301 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS; ;} @@ -1784,7 +1783,7 @@ yyreduce: case 31: /* Line 1464 of yacc.c */ -#line 306 "libmemcached/options/parser.yy" +#line 305 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_POLL_TIMEOUT; ;} @@ -1793,7 +1792,7 @@ yyreduce: case 32: /* Line 1464 of yacc.c */ -#line 310 "libmemcached/options/parser.yy" +#line 309 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_RCV_TIMEOUT; ;} @@ -1802,7 +1801,7 @@ yyreduce: case 33: /* Line 1464 of yacc.c */ -#line 314 "libmemcached/options/parser.yy" +#line 313 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_RETRY_TIMEOUT; ;} @@ -1811,7 +1810,7 @@ yyreduce: case 34: /* Line 1464 of yacc.c */ -#line 318 "libmemcached/options/parser.yy" +#line 317 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_SND_TIMEOUT; ;} @@ -1820,7 +1819,7 @@ yyreduce: case 35: /* Line 1464 of yacc.c */ -#line 322 "libmemcached/options/parser.yy" +#line 321 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE; ;} @@ -1829,7 +1828,7 @@ yyreduce: case 36: /* Line 1464 of yacc.c */ -#line 326 "libmemcached/options/parser.yy" +#line 325 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE; ;} @@ -1838,7 +1837,7 @@ yyreduce: case 37: /* Line 1464 of yacc.c */ -#line 333 "libmemcached/options/parser.yy" +#line 332 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_BINARY_PROTOCOL; ;} @@ -1847,7 +1846,7 @@ yyreduce: case 38: /* Line 1464 of yacc.c */ -#line 337 "libmemcached/options/parser.yy" +#line 336 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_BUFFER_REQUESTS; ;} @@ -1856,7 +1855,7 @@ yyreduce: case 39: /* Line 1464 of yacc.c */ -#line 341 "libmemcached/options/parser.yy" +#line 340 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY; ;} @@ -1865,7 +1864,7 @@ yyreduce: case 40: /* Line 1464 of yacc.c */ -#line 345 "libmemcached/options/parser.yy" +#line 344 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_NOREPLY; ;} @@ -1874,7 +1873,7 @@ yyreduce: case 41: /* Line 1464 of yacc.c */ -#line 349 "libmemcached/options/parser.yy" +#line 348 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ; ;} @@ -1883,7 +1882,7 @@ yyreduce: case 42: /* Line 1464 of yacc.c */ -#line 353 "libmemcached/options/parser.yy" +#line 352 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_SORT_HOSTS; ;} @@ -1892,7 +1891,7 @@ yyreduce: case 43: /* Line 1464 of yacc.c */ -#line 357 "libmemcached/options/parser.yy" +#line 356 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_SUPPORT_CAS; ;} @@ -1901,7 +1900,7 @@ yyreduce: case 44: /* Line 1464 of yacc.c */ -#line 361 "libmemcached/options/parser.yy" +#line 360 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_TCP_NODELAY; ;} @@ -1910,7 +1909,7 @@ yyreduce: case 45: /* Line 1464 of yacc.c */ -#line 365 "libmemcached/options/parser.yy" +#line 364 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_TCP_KEEPALIVE; ;} @@ -1919,7 +1918,7 @@ yyreduce: case 46: /* Line 1464 of yacc.c */ -#line 369 "libmemcached/options/parser.yy" +#line 368 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_TCP_KEEPIDLE; ;} @@ -1928,7 +1927,7 @@ yyreduce: case 47: /* Line 1464 of yacc.c */ -#line 373 "libmemcached/options/parser.yy" +#line 372 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_USE_UDP; ;} @@ -1937,7 +1936,7 @@ yyreduce: case 48: /* Line 1464 of yacc.c */ -#line 377 "libmemcached/options/parser.yy" +#line 376 "libmemcached/options/parser.yy" { (yyval.behavior)= MEMCACHED_BEHAVIOR_VERIFY_KEY; ;} @@ -1946,35 +1945,35 @@ yyreduce: case 49: /* Line 1464 of yacc.c */ -#line 383 "libmemcached/options/parser.yy" +#line 382 "libmemcached/options/parser.yy" { ;} break; case 50: /* Line 1464 of yacc.c */ -#line 385 "libmemcached/options/parser.yy" +#line 384 "libmemcached/options/parser.yy" { ;} break; case 51: /* Line 1464 of yacc.c */ -#line 389 "libmemcached/options/parser.yy" +#line 388 "libmemcached/options/parser.yy" { ;} break; case 52: /* Line 1464 of yacc.c */ -#line 391 "libmemcached/options/parser.yy" +#line 390 "libmemcached/options/parser.yy" { ;} break; case 53: /* Line 1464 of yacc.c */ -#line 396 "libmemcached/options/parser.yy" +#line 395 "libmemcached/options/parser.yy" { (yyval.hash)= MEMCACHED_HASH_MD5; ;} @@ -1983,7 +1982,7 @@ yyreduce: case 54: /* Line 1464 of yacc.c */ -#line 400 "libmemcached/options/parser.yy" +#line 399 "libmemcached/options/parser.yy" { (yyval.hash)= MEMCACHED_HASH_CRC; ;} @@ -1992,7 +1991,7 @@ yyreduce: case 55: /* Line 1464 of yacc.c */ -#line 404 "libmemcached/options/parser.yy" +#line 403 "libmemcached/options/parser.yy" { (yyval.hash)= MEMCACHED_HASH_FNV1_64; ;} @@ -2001,7 +2000,7 @@ yyreduce: case 56: /* Line 1464 of yacc.c */ -#line 408 "libmemcached/options/parser.yy" +#line 407 "libmemcached/options/parser.yy" { (yyval.hash)= MEMCACHED_HASH_FNV1A_64; ;} @@ -2010,7 +2009,7 @@ yyreduce: case 57: /* Line 1464 of yacc.c */ -#line 412 "libmemcached/options/parser.yy" +#line 411 "libmemcached/options/parser.yy" { (yyval.hash)= MEMCACHED_HASH_FNV1_32; ;} @@ -2019,7 +2018,7 @@ yyreduce: case 58: /* Line 1464 of yacc.c */ -#line 416 "libmemcached/options/parser.yy" +#line 415 "libmemcached/options/parser.yy" { (yyval.hash)= MEMCACHED_HASH_FNV1A_32; ;} @@ -2028,7 +2027,7 @@ yyreduce: case 59: /* Line 1464 of yacc.c */ -#line 420 "libmemcached/options/parser.yy" +#line 419 "libmemcached/options/parser.yy" { (yyval.hash)= MEMCACHED_HASH_HSIEH; ;} @@ -2037,7 +2036,7 @@ yyreduce: case 60: /* Line 1464 of yacc.c */ -#line 424 "libmemcached/options/parser.yy" +#line 423 "libmemcached/options/parser.yy" { (yyval.hash)= MEMCACHED_HASH_MURMUR; ;} @@ -2046,7 +2045,7 @@ yyreduce: case 61: /* Line 1464 of yacc.c */ -#line 428 "libmemcached/options/parser.yy" +#line 427 "libmemcached/options/parser.yy" { (yyval.hash)= MEMCACHED_HASH_JENKINS; ;} @@ -2055,7 +2054,7 @@ yyreduce: case 62: /* Line 1464 of yacc.c */ -#line 435 "libmemcached/options/parser.yy" +#line 434 "libmemcached/options/parser.yy" { (yyval.string)= (yyvsp[(1) - (1)].string); ;} @@ -2064,7 +2063,7 @@ yyreduce: case 63: /* Line 1464 of yacc.c */ -#line 439 "libmemcached/options/parser.yy" +#line 438 "libmemcached/options/parser.yy" { (yyval.string).c_str= (yyvsp[(1) - (1)].string).c_str +1; // +1 to move use passed the initial quote (yyval.string).length= (yyvsp[(1) - (1)].string).length -1; // -1 removes the end quote @@ -2074,7 +2073,7 @@ yyreduce: case 64: /* Line 1464 of yacc.c */ -#line 447 "libmemcached/options/parser.yy" +#line 446 "libmemcached/options/parser.yy" { (yyval.distribution)= MEMCACHED_DISTRIBUTION_CONSISTENT; ;} @@ -2083,7 +2082,7 @@ yyreduce: case 65: /* Line 1464 of yacc.c */ -#line 451 "libmemcached/options/parser.yy" +#line 450 "libmemcached/options/parser.yy" { (yyval.distribution)= MEMCACHED_DISTRIBUTION_MODULA; ;} @@ -2092,7 +2091,7 @@ yyreduce: case 66: /* Line 1464 of yacc.c */ -#line 455 "libmemcached/options/parser.yy" +#line 454 "libmemcached/options/parser.yy" { (yyval.distribution)= MEMCACHED_DISTRIBUTION_RANDOM; ;} @@ -2101,7 +2100,7 @@ yyreduce: /* Line 1464 of yacc.c */ -#line 2105 "libmemcached/options/parser.cc" +#line 2104 "libmemcached/options/parser.cc" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -2313,7 +2312,7 @@ yyreturn: /* Line 1684 of yacc.c */ -#line 460 "libmemcached/options/parser.yy" +#line 459 "libmemcached/options/parser.yy" void Context::start() diff --git a/libmemcached/options/scanner.cc b/libmemcached/options/scanner.cc index b6143087..7af88fd0 100644 --- a/libmemcached/options/scanner.cc +++ b/libmemcached/options/scanner.cc @@ -1,21 +1,22 @@ #line 2 "libmemcached/options/scanner.cc" #line 22 "libmemcached/options/scanner.l" -#pragma GCC diagnostic ignored "-Wold-style-cast" -#pragma GCC diagnostic ignored "-Wsign-compare" -#pragma GCC diagnostic ignored "-Wunused-parameter" - +#include #include #include #include #include +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wunused-parameter" + #define YY_EXTRA_TYPE Context* -#line 19 "libmemcached/options/scanner.cc" +#line 20 "libmemcached/options/scanner.cc" #define YY_INT_ALIGNED short int @@ -1075,13 +1076,13 @@ static yyconst flex_int16_t yy_chk[1722] = static yyconst flex_int16_t yy_rule_linenum[64] = { 0, - 77, 79, 81, 83, 85, 88, 92, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 123, 124, 126, 128, 129, - 130, 131, 132, 133, 135, 136, 139, 144, 145, 146, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 158, - 167, 185, 191 + 78, 80, 82, 84, 86, 89, 93, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 124, 125, 127, 129, 130, + 131, 132, 133, 134, 136, 137, 140, 145, 146, 147, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 159, + 168, 186, 192 } ; /* The intent behind this definition is that it'll catch @@ -1112,7 +1113,7 @@ static yyconst flex_int16_t yy_rule_linenum[64] = * along with this program. If not, see . */ -#line 38 "libmemcached/options/scanner.l" +#line 39 "libmemcached/options/scanner.l" #include #include @@ -1136,7 +1137,7 @@ static yyconst flex_int16_t yy_rule_linenum[64] = #define YY_INPUT(buffer, result, max_size) get_lex_chars(buffer, result, max_size, PARAM) -#line 1140 "libmemcached/options/scanner.cc" +#line 1141 "libmemcached/options/scanner.cc" #define INITIAL 0 @@ -1439,11 +1440,11 @@ YY_DECL struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* %% [7.0] user's declarations go here */ -#line 74 "libmemcached/options/scanner.l" +#line 75 "libmemcached/options/scanner.l" -#line 1447 "libmemcached/options/scanner.cc" +#line 1448 "libmemcached/options/scanner.cc" yylval = yylval_param; @@ -1562,28 +1563,28 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -#line 77 "libmemcached/options/scanner.l" +#line 78 "libmemcached/options/scanner.l" { return yytext[0];} YY_BREAK case 2: YY_RULE_SETUP -#line 79 "libmemcached/options/scanner.l" +#line 80 "libmemcached/options/scanner.l" { yylval->number = atoi(yytext); return (NUMBER); } YY_BREAK case 3: YY_RULE_SETUP -#line 81 "libmemcached/options/scanner.l" +#line 82 "libmemcached/options/scanner.l" { yylval->server.port = atoi(yytext +1); return PORT; } YY_BREAK case 4: YY_RULE_SETUP -#line 83 "libmemcached/options/scanner.l" +#line 84 "libmemcached/options/scanner.l" { yylval->server.weight = atoi(yytext +2); return WEIGHT_START; } YY_BREAK case 5: /* rule 5 can match eol */ YY_RULE_SETUP -#line 85 "libmemcached/options/scanner.l" +#line 86 "libmemcached/options/scanner.l" ; /* skip whitespace */ YY_BREAK case 6: @@ -1591,214 +1592,214 @@ case 6: yyg->yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 88 "libmemcached/options/scanner.l" +#line 89 "libmemcached/options/scanner.l" { return COMMENT; } YY_BREAK case 7: YY_RULE_SETUP -#line 92 "libmemcached/options/scanner.l" +#line 93 "libmemcached/options/scanner.l" { yyextra->begin= yytext; yyextra->set_server(); return SERVER; } YY_BREAK case 8: YY_RULE_SETUP -#line 94 "libmemcached/options/scanner.l" +#line 95 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return BINARY_PROTOCOL; } YY_BREAK case 9: YY_RULE_SETUP -#line 95 "libmemcached/options/scanner.l" +#line 96 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return BUFFER_REQUESTS; } YY_BREAK case 10: YY_RULE_SETUP -#line 96 "libmemcached/options/scanner.l" +#line 97 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return CONFIGURE_FILE; } YY_BREAK case 11: YY_RULE_SETUP -#line 97 "libmemcached/options/scanner.l" +#line 98 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return CONNECT_TIMEOUT; } YY_BREAK case 12: YY_RULE_SETUP -#line 98 "libmemcached/options/scanner.l" +#line 99 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return DISTRIBUTION; } YY_BREAK case 13: YY_RULE_SETUP -#line 99 "libmemcached/options/scanner.l" +#line 100 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return HASH_WITH_NAMESPACE; } YY_BREAK case 14: YY_RULE_SETUP -#line 100 "libmemcached/options/scanner.l" +#line 101 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return HASH; } YY_BREAK case 15: YY_RULE_SETUP -#line 101 "libmemcached/options/scanner.l" +#line 102 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return IO_BYTES_WATERMARK; } YY_BREAK case 16: YY_RULE_SETUP -#line 102 "libmemcached/options/scanner.l" +#line 103 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return IO_KEY_PREFETCH; } YY_BREAK case 17: YY_RULE_SETUP -#line 103 "libmemcached/options/scanner.l" +#line 104 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return IO_MSG_WATERMARK; } YY_BREAK case 18: YY_RULE_SETUP -#line 104 "libmemcached/options/scanner.l" +#line 105 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return NOREPLY; } YY_BREAK case 19: YY_RULE_SETUP -#line 105 "libmemcached/options/scanner.l" +#line 106 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return NUMBER_OF_REPLICAS; } YY_BREAK case 20: YY_RULE_SETUP -#line 106 "libmemcached/options/scanner.l" +#line 107 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return POLL_TIMEOUT; } YY_BREAK case 21: YY_RULE_SETUP -#line 107 "libmemcached/options/scanner.l" +#line 108 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return RANDOMIZE_REPLICA_READ; } YY_BREAK case 22: YY_RULE_SETUP -#line 108 "libmemcached/options/scanner.l" +#line 109 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return RCV_TIMEOUT; } YY_BREAK case 23: YY_RULE_SETUP -#line 109 "libmemcached/options/scanner.l" +#line 110 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return REMOVE_FAILED_SERVERS; } YY_BREAK case 24: YY_RULE_SETUP -#line 110 "libmemcached/options/scanner.l" +#line 111 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return RETRY_TIMEOUT; } YY_BREAK case 25: YY_RULE_SETUP -#line 111 "libmemcached/options/scanner.l" +#line 112 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return SND_TIMEOUT; } YY_BREAK case 26: YY_RULE_SETUP -#line 112 "libmemcached/options/scanner.l" +#line 113 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return SOCKET_RECV_SIZE; } YY_BREAK case 27: YY_RULE_SETUP -#line 113 "libmemcached/options/scanner.l" +#line 114 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return SOCKET_SEND_SIZE; } YY_BREAK case 28: YY_RULE_SETUP -#line 114 "libmemcached/options/scanner.l" +#line 115 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return SORT_HOSTS; } YY_BREAK case 29: YY_RULE_SETUP -#line 115 "libmemcached/options/scanner.l" +#line 116 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return SUPPORT_CAS; } YY_BREAK case 30: YY_RULE_SETUP -#line 116 "libmemcached/options/scanner.l" +#line 117 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return _TCP_KEEPALIVE; } YY_BREAK case 31: YY_RULE_SETUP -#line 117 "libmemcached/options/scanner.l" +#line 118 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return _TCP_KEEPIDLE; } YY_BREAK case 32: YY_RULE_SETUP -#line 118 "libmemcached/options/scanner.l" +#line 119 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return _TCP_NODELAY; } YY_BREAK case 33: YY_RULE_SETUP -#line 119 "libmemcached/options/scanner.l" +#line 120 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return USE_UDP; } YY_BREAK case 34: YY_RULE_SETUP -#line 120 "libmemcached/options/scanner.l" +#line 121 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return USER_DATA; } YY_BREAK case 35: YY_RULE_SETUP -#line 121 "libmemcached/options/scanner.l" +#line 122 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return VERIFY_KEY; } YY_BREAK case 36: YY_RULE_SETUP -#line 123 "libmemcached/options/scanner.l" +#line 124 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return POOL_MIN; } YY_BREAK case 37: YY_RULE_SETUP -#line 124 "libmemcached/options/scanner.l" +#line 125 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return POOL_MAX; } YY_BREAK case 38: YY_RULE_SETUP -#line 126 "libmemcached/options/scanner.l" +#line 127 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return NAMESPACE; } YY_BREAK case 39: YY_RULE_SETUP -#line 128 "libmemcached/options/scanner.l" +#line 129 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return INCLUDE; } YY_BREAK case 40: YY_RULE_SETUP -#line 129 "libmemcached/options/scanner.l" +#line 130 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return RESET; } YY_BREAK case 41: YY_RULE_SETUP -#line 130 "libmemcached/options/scanner.l" +#line 131 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return PARSER_DEBUG; } YY_BREAK case 42: YY_RULE_SETUP -#line 131 "libmemcached/options/scanner.l" +#line 132 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return SERVERS; } YY_BREAK case 43: YY_RULE_SETUP -#line 132 "libmemcached/options/scanner.l" +#line 133 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return END; } YY_BREAK case 44: YY_RULE_SETUP -#line 133 "libmemcached/options/scanner.l" +#line 134 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return ERROR; } YY_BREAK case 45: YY_RULE_SETUP -#line 135 "libmemcached/options/scanner.l" +#line 136 "libmemcached/options/scanner.l" { return TRUE; } YY_BREAK case 46: YY_RULE_SETUP -#line 136 "libmemcached/options/scanner.l" +#line 137 "libmemcached/options/scanner.l" { return FALSE; } YY_BREAK case 47: YY_RULE_SETUP -#line 139 "libmemcached/options/scanner.l" +#line 140 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return UNKNOWN_OPTION; @@ -1806,67 +1807,67 @@ YY_RULE_SETUP YY_BREAK case 48: YY_RULE_SETUP -#line 144 "libmemcached/options/scanner.l" +#line 145 "libmemcached/options/scanner.l" { return CONSISTENT; } YY_BREAK case 49: YY_RULE_SETUP -#line 145 "libmemcached/options/scanner.l" +#line 146 "libmemcached/options/scanner.l" { return MODULA; } YY_BREAK case 50: YY_RULE_SETUP -#line 146 "libmemcached/options/scanner.l" +#line 147 "libmemcached/options/scanner.l" { return RANDOM; } YY_BREAK case 51: YY_RULE_SETUP -#line 148 "libmemcached/options/scanner.l" +#line 149 "libmemcached/options/scanner.l" { return MD5; } YY_BREAK case 52: YY_RULE_SETUP -#line 149 "libmemcached/options/scanner.l" +#line 150 "libmemcached/options/scanner.l" { return CRC; } YY_BREAK case 53: YY_RULE_SETUP -#line 150 "libmemcached/options/scanner.l" +#line 151 "libmemcached/options/scanner.l" { return FNV1_64; } YY_BREAK case 54: YY_RULE_SETUP -#line 151 "libmemcached/options/scanner.l" +#line 152 "libmemcached/options/scanner.l" { return FNV1A_64; } YY_BREAK case 55: YY_RULE_SETUP -#line 152 "libmemcached/options/scanner.l" +#line 153 "libmemcached/options/scanner.l" { return FNV1_32; } YY_BREAK case 56: YY_RULE_SETUP -#line 153 "libmemcached/options/scanner.l" +#line 154 "libmemcached/options/scanner.l" { return FNV1A_32; } YY_BREAK case 57: YY_RULE_SETUP -#line 154 "libmemcached/options/scanner.l" +#line 155 "libmemcached/options/scanner.l" { return HSIEH; } YY_BREAK case 58: YY_RULE_SETUP -#line 155 "libmemcached/options/scanner.l" +#line 156 "libmemcached/options/scanner.l" { return MURMUR; } YY_BREAK case 59: YY_RULE_SETUP -#line 156 "libmemcached/options/scanner.l" +#line 157 "libmemcached/options/scanner.l" { return JENKINS; } YY_BREAK case 60: YY_RULE_SETUP -#line 158 "libmemcached/options/scanner.l" +#line 159 "libmemcached/options/scanner.l" { yylval->server.port= MEMCACHED_DEFAULT_PORT; yylval->server.weight= 1; @@ -1878,7 +1879,7 @@ YY_RULE_SETUP YY_BREAK case 61: YY_RULE_SETUP -#line 167 "libmemcached/options/scanner.l" +#line 168 "libmemcached/options/scanner.l" { if (yyextra->is_server()) { @@ -1899,7 +1900,7 @@ YY_RULE_SETUP YY_BREAK case 62: YY_RULE_SETUP -#line 185 "libmemcached/options/scanner.l" +#line 186 "libmemcached/options/scanner.l" { yylval->string.c_str = yytext; yylval->string.length = yyleng; @@ -1908,7 +1909,7 @@ YY_RULE_SETUP YY_BREAK case 63: YY_RULE_SETUP -#line 191 "libmemcached/options/scanner.l" +#line 192 "libmemcached/options/scanner.l" { yyextra->begin= yytext; return UNKNOWN; @@ -1916,10 +1917,10 @@ YY_RULE_SETUP YY_BREAK case 64: YY_RULE_SETUP -#line 196 "libmemcached/options/scanner.l" +#line 197 "libmemcached/options/scanner.l" ECHO; YY_BREAK -#line 1923 "libmemcached/options/scanner.cc" +#line 1924 "libmemcached/options/scanner.cc" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -3185,7 +3186,7 @@ void config_free (void * ptr , yyscan_t yyscanner) /* %ok-for-header */ -#line 196 "libmemcached/options/scanner.l" +#line 197 "libmemcached/options/scanner.l" diff --git a/libmemcached/options/scanner.h b/libmemcached/options/scanner.h index b5bddde3..1742031a 100644 --- a/libmemcached/options/scanner.h +++ b/libmemcached/options/scanner.h @@ -5,21 +5,22 @@ #line 6 "libmemcached/options/scanner.h" #line 22 "libmemcached/options/scanner.l" -#pragma GCC diagnostic ignored "-Wold-style-cast" -#pragma GCC diagnostic ignored "-Wsign-compare" -#pragma GCC diagnostic ignored "-Wunused-parameter" - +#include #include #include #include #include +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wunused-parameter" + #define YY_EXTRA_TYPE Context* -#line 23 "libmemcached/options/scanner.h" +#line 24 "libmemcached/options/scanner.h" #define YY_INT_ALIGNED short int @@ -471,9 +472,9 @@ extern int config_lex \ #undef YY_DECL #endif -#line 196 "libmemcached/options/scanner.l" +#line 197 "libmemcached/options/scanner.l" -#line 478 "libmemcached/options/scanner.h" +#line 479 "libmemcached/options/scanner.h" #undef config_IN_HEADER #endif /* config_HEADER_H */ diff --git a/libmemcached/parse.c b/libmemcached/parse.c deleted file mode 100644 index 85860ef3..00000000 --- a/libmemcached/parse.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - I debated about putting this in the client library since it does an - action I don't really believe belongs in the library. - - Frankly its too damn useful not to be here though. -*/ - -#include "common.h" - -memcached_server_list_st memcached_servers_parse(const char *server_strings) -{ - char *string; - const char *begin_ptr; - const char *end_ptr; - memcached_server_st *servers= NULL; - memcached_return_t rc; - - WATCHPOINT_ASSERT(server_strings); - - end_ptr= server_strings + strlen(server_strings); - - for (begin_ptr= server_strings, string= index(server_strings, ','); - begin_ptr != end_ptr; - string= index(begin_ptr, ',')) - { - char buffer[HUGE_STRING_LEN]; - char *ptr, *ptr2; - uint32_t weight= 0; - - if (string) - { - memcpy(buffer, begin_ptr, (size_t) (string - begin_ptr)); - buffer[(unsigned int)(string - begin_ptr)]= 0; - begin_ptr= string+1; - } - else - { - size_t length= strlen(begin_ptr); - memcpy(buffer, begin_ptr, length); - buffer[length]= 0; - begin_ptr= end_ptr; - } - - ptr= index(buffer, ':'); - - in_port_t port= 0; - if (ptr) - { - ptr[0]= 0; - - ptr++; - - port= (in_port_t) strtoul(ptr, (char **)NULL, 10); - - ptr2= index(ptr, ' '); - if (! ptr2) - ptr2= index(ptr, ':'); - - if (ptr2) - { - ptr2++; - weight = (uint32_t) strtoul(ptr2, (char **)NULL, 10); - } - } - - servers= memcached_server_list_append_with_weight(servers, buffer, port, weight, &rc); - - if (isspace(*begin_ptr)) - begin_ptr++; - } - - return servers; -} diff --git a/libmemcached/parse.cc b/libmemcached/parse.cc new file mode 100644 index 00000000..3284a4f6 --- /dev/null +++ b/libmemcached/parse.cc @@ -0,0 +1,110 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + I debated about putting this in the client library since it does an + action I don't really believe belongs in the library. + + Frankly its too damn useful not to be here though. +*/ + +#include + +memcached_server_list_st memcached_servers_parse(const char *server_strings) +{ + char *string; + const char *begin_ptr; + const char *end_ptr; + memcached_server_st *servers= NULL; + memcached_return_t rc; + + WATCHPOINT_ASSERT(server_strings); + + end_ptr= server_strings + strlen(server_strings); + + for (begin_ptr= server_strings, string= (char *)index(server_strings, ','); + begin_ptr != end_ptr; + string= (char *)index(begin_ptr, ',')) + { + char buffer[HUGE_STRING_LEN]; + char *ptr, *ptr2; + uint32_t weight= 0; + + if (string) + { + memcpy(buffer, begin_ptr, (size_t) (string - begin_ptr)); + buffer[(unsigned int)(string - begin_ptr)]= 0; + begin_ptr= string+1; + } + else + { + size_t length= strlen(begin_ptr); + memcpy(buffer, begin_ptr, length); + buffer[length]= 0; + begin_ptr= end_ptr; + } + + ptr= index(buffer, ':'); + + in_port_t port= 0; + if (ptr) + { + ptr[0]= 0; + + ptr++; + + port= (in_port_t) strtoul(ptr, (char **)NULL, 10); + + ptr2= index(ptr, ' '); + if (! ptr2) + ptr2= index(ptr, ':'); + + if (ptr2) + { + ptr2++; + weight = (uint32_t) strtoul(ptr2, (char **)NULL, 10); + } + } + + servers= memcached_server_list_append_with_weight(servers, buffer, port, weight, &rc); + + if (isspace(*begin_ptr)) + begin_ptr++; + } + + return servers; +} diff --git a/libmemcached/protocol/ascii_handler.c b/libmemcached/protocol/ascii_handler.c index 465b7396..5e7307ae 100644 --- a/libmemcached/protocol/ascii_handler.c +++ b/libmemcached/protocol/ascii_handler.c @@ -1,10 +1,48 @@ -/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ -#include "libmemcached/protocol/common.h" +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#include +#include #include -#include -#include #include +#include +#include /** * Try to parse a key from the string. diff --git a/libmemcached/protocol/ascii_handler.h b/libmemcached/protocol/ascii_handler.h index 02a1a82d..02f8831e 100644 --- a/libmemcached/protocol/ascii_handler.h +++ b/libmemcached/protocol/ascii_handler.h @@ -1,8 +1,40 @@ -/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ -#ifndef LIBMEMCACHED_PROTOCOL_ASCII_HANDLER_H -#define LIBMEMCACHED_PROTOCOL_ASCII_HANDLER_H +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#pragma once LIBMEMCACHED_LOCAL memcached_protocol_event_t memcached_ascii_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr); - -#endif diff --git a/libmemcached/protocol/binary_handler.c b/libmemcached/protocol/binary_handler.c index a9e4ce95..93fb3162 100644 --- a/libmemcached/protocol/binary_handler.c +++ b/libmemcached/protocol/binary_handler.c @@ -1,5 +1,41 @@ -/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ -#include "libmemcached/protocol/common.h" +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include #include #include diff --git a/libmemcached/protocol/binary_handler.h b/libmemcached/protocol/binary_handler.h index a21165b2..d5a74e78 100644 --- a/libmemcached/protocol/binary_handler.h +++ b/libmemcached/protocol/binary_handler.h @@ -1,6 +1,40 @@ -/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ -#ifndef LIBMEMCACHED_PROTOCOL_BINARY_HANDLER_H -#define LIBMEMCACHED_PROTOCOL_BINARY_HANDLER_H +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#pragma once LIBMEMCACHED_LOCAL bool memcached_binary_protocol_pedantic_check_request(const protocol_binary_request_header *request); @@ -11,5 +45,3 @@ bool memcached_binary_protocol_pedantic_check_response(const protocol_binary_req LIBMEMCACHED_LOCAL memcached_protocol_event_t memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr); - -#endif diff --git a/libmemcached/protocol/common.h b/libmemcached/protocol/common.h index 185aef0b..808a6086 100644 --- a/libmemcached/protocol/common.h +++ b/libmemcached/protocol/common.h @@ -1,6 +1,40 @@ -/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ -#ifndef LIBMEMCACHED_PROTOCOL_COMMON_H -#define LIBMEMCACHED_PROTOCOL_COMMON_H +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#pragma once #include "config.h" #if !defined(__cplusplus) @@ -8,12 +42,7 @@ #endif #include -/* Define this here, which will turn on the visibilty controls while we're - * building libmemcached. - */ -#define BUILDING_LIBMEMCACHED 1 - -#include +#include #include #include @@ -132,5 +161,3 @@ struct memcached_protocol_client_st { #include "ascii_handler.h" #include "binary_handler.h" - -#endif diff --git a/libmemcached/protocol/include.am b/libmemcached/protocol/include.am new file mode 100644 index 00000000..9c4c1bc2 --- /dev/null +++ b/libmemcached/protocol/include.am @@ -0,0 +1,26 @@ +# vim:ft=automake +# included from Top Level Makefile.am +# All paths should be given relative to the root + + +lib_LTLIBRARIES+= libmemcached/libmemcachedprotocol.la +libmemcached_libmemcachedprotocol_la_SOURCES= \ + libmemcached/byteorder.cc \ + libmemcached/protocol/ascii_handler.c \ + libmemcached/protocol/binary_handler.c \ + libmemcached/protocol/cache.c \ + libmemcached/protocol/pedantic.c \ + libmemcached/protocol/protocol_handler.c + +libmemcached_libmemcachedprotocol_la_CFLAGS= \ + ${AM_CFLAGS} \ + ${NO_CONVERSION} \ + ${PTHREAD_CFLAGS} \ + -DBUILDING_LIBMEMCACHED + +libmemcached_libmemcachedprotocol_la_CXXFLAGS= \ + ${AM_CXXFLAGS} \ + ${PTHREAD_CFLAGS} \ + -DBUILDING_LIBMEMCACHED + +libmemcached_libmemcachedprotocol_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_PROTOCAL_LIBRARY_VERSION} diff --git a/libmemcached/purge.c b/libmemcached/purge.c deleted file mode 100644 index 07cd135f..00000000 --- a/libmemcached/purge.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "common.h" - -memcached_return_t memcached_purge(memcached_server_write_instance_st ptr) -{ - uint32_t x; - memcached_return_t ret= MEMCACHED_SUCCESS; - memcached_st *root= (memcached_st *)ptr->root; - - if (memcached_is_purging(ptr->root) || /* already purging */ - (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark && - ptr->io_bytes_sent < ptr->root->io_bytes_watermark) || - (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark && - memcached_server_response_count(ptr) < 2)) - { - return MEMCACHED_SUCCESS; - } - - /* memcached_io_write and memcached_response may call memcached_purge - so we need to be able stop any recursion.. */ - memcached_set_purging(root, true); - - WATCHPOINT_ASSERT(ptr->fd != -1); - /* Force a flush of the buffer to ensure that we don't have the n-1 pending - requests buffered up.. */ - if (memcached_io_write(ptr, NULL, 0, true) == -1) - { - memcached_set_purging(root, true); - - return MEMCACHED_WRITE_FAILURE; - } - WATCHPOINT_ASSERT(ptr->fd != -1); - - uint32_t no_msg= memcached_server_response_count(ptr) - 1; - if (no_msg > 0) - { - memcached_result_st result; - memcached_result_st *result_ptr; - char buffer[SMALL_STRING_LEN]; - - /* - * We need to increase the timeout, because we might be waiting for - * data to be sent from the server (the commands was in the output buffer - * and just flushed - */ - const int32_t timeo= ptr->root->poll_timeout; - root->poll_timeout= 2000; - - result_ptr= memcached_result_create(root, &result); - WATCHPOINT_ASSERT(result_ptr); - - for (x= 0; x < no_msg; x++) - { - memcached_result_reset(result_ptr); - memcached_return_t rc= memcached_read_one_response(ptr, buffer, - sizeof (buffer), - result_ptr); - /* - * Purge doesn't care for what kind of command results that is received. - * The only kind of errors I care about if is I'm out of sync with the - * protocol or have problems reading data from the network.. - */ - if (rc== MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_UNKNOWN_READ_FAILURE) - { - WATCHPOINT_ERROR(rc); - ret = rc; - memcached_io_reset(ptr); - } - - if (ptr->root->callbacks != NULL) - { - memcached_callback_st cb = *ptr->root->callbacks; - if (rc == MEMCACHED_SUCCESS) - { - for (uint32_t y= 0; y < cb.number_of_callback; y++) - { - rc = (*cb.callback[y])(ptr->root, result_ptr, cb.context); - if (rc != MEMCACHED_SUCCESS) - break; - } - } - } - } - - memcached_result_free(result_ptr); - root->poll_timeout= timeo; - } - memcached_set_purging(root, false); - - return ret; -} diff --git a/libmemcached/purge.cc b/libmemcached/purge.cc new file mode 100644 index 00000000..07cd135f --- /dev/null +++ b/libmemcached/purge.cc @@ -0,0 +1,90 @@ +#include "common.h" + +memcached_return_t memcached_purge(memcached_server_write_instance_st ptr) +{ + uint32_t x; + memcached_return_t ret= MEMCACHED_SUCCESS; + memcached_st *root= (memcached_st *)ptr->root; + + if (memcached_is_purging(ptr->root) || /* already purging */ + (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark && + ptr->io_bytes_sent < ptr->root->io_bytes_watermark) || + (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark && + memcached_server_response_count(ptr) < 2)) + { + return MEMCACHED_SUCCESS; + } + + /* memcached_io_write and memcached_response may call memcached_purge + so we need to be able stop any recursion.. */ + memcached_set_purging(root, true); + + WATCHPOINT_ASSERT(ptr->fd != -1); + /* Force a flush of the buffer to ensure that we don't have the n-1 pending + requests buffered up.. */ + if (memcached_io_write(ptr, NULL, 0, true) == -1) + { + memcached_set_purging(root, true); + + return MEMCACHED_WRITE_FAILURE; + } + WATCHPOINT_ASSERT(ptr->fd != -1); + + uint32_t no_msg= memcached_server_response_count(ptr) - 1; + if (no_msg > 0) + { + memcached_result_st result; + memcached_result_st *result_ptr; + char buffer[SMALL_STRING_LEN]; + + /* + * We need to increase the timeout, because we might be waiting for + * data to be sent from the server (the commands was in the output buffer + * and just flushed + */ + const int32_t timeo= ptr->root->poll_timeout; + root->poll_timeout= 2000; + + result_ptr= memcached_result_create(root, &result); + WATCHPOINT_ASSERT(result_ptr); + + for (x= 0; x < no_msg; x++) + { + memcached_result_reset(result_ptr); + memcached_return_t rc= memcached_read_one_response(ptr, buffer, + sizeof (buffer), + result_ptr); + /* + * Purge doesn't care for what kind of command results that is received. + * The only kind of errors I care about if is I'm out of sync with the + * protocol or have problems reading data from the network.. + */ + if (rc== MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_UNKNOWN_READ_FAILURE) + { + WATCHPOINT_ERROR(rc); + ret = rc; + memcached_io_reset(ptr); + } + + if (ptr->root->callbacks != NULL) + { + memcached_callback_st cb = *ptr->root->callbacks; + if (rc == MEMCACHED_SUCCESS) + { + for (uint32_t y= 0; y < cb.number_of_callback; y++) + { + rc = (*cb.callback[y])(ptr->root, result_ptr, cb.context); + if (rc != MEMCACHED_SUCCESS) + break; + } + } + } + } + + memcached_result_free(result_ptr); + root->poll_timeout= timeo; + } + memcached_set_purging(root, false); + + return ret; +} diff --git a/libmemcached/quit.c b/libmemcached/quit.c deleted file mode 100644 index 6d72906c..00000000 --- a/libmemcached/quit.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "common.h" - -/* - This closes all connections (forces flush of input as well). - - Maybe add a host specific, or key specific version? - - The reason we send "quit" is that in case we have buffered IO, this - will force data to be completed. -*/ - -void memcached_quit_server(memcached_server_st *ptr, bool io_death) -{ - if (ptr->fd != INVALID_SOCKET) - { - if (io_death == false && ptr->type != MEMCACHED_CONNECTION_UDP && ptr->options.is_shutting_down == false) - { - memcached_return_t rc; - char buffer[MEMCACHED_MAX_BUFFER]; - - ptr->options.is_shutting_down= true; - - if (ptr->root->flags.binary_protocol) - { - protocol_binary_request_quit request = {.bytes= {0}}; - request.message.header.request.magic = PROTOCOL_BINARY_REQ; - request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT; - request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; - rc= memcached_do(ptr, request.bytes, sizeof(request.bytes), true); - } - else - { - rc= memcached_do(ptr, "quit\r\n", sizeof("quit\r\n") -1, true); - } - - WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED); - (void)rc; // Shut up ICC - - /* read until socket is closed, or there is an error - * closing the socket before all data is read - * results in server throwing away all data which is - * not read - * - * In .40 we began to only do this if we had been doing buffered - * requests of had replication enabled. - */ - if (ptr->root->flags.buffer_requests || ptr->root->number_of_replicas) - { - ssize_t nread; - while (memcached_io_read(ptr, buffer, sizeof(buffer)/sizeof(*buffer), - &nread) == MEMCACHED_SUCCESS); - } - - - /* - * memcached_io_read may call memcached_quit_server with io_death if - * it encounters problems, but we don't care about those occurences. - * The intention of that loop is to drain the data sent from the - * server to ensure that the server processed all of the data we - * sent to the server. - */ - ptr->server_failure_counter= 0; - } - memcached_io_close(ptr); - } - - ptr->fd= INVALID_SOCKET; - ptr->io_bytes_sent= 0; - ptr->write_buffer_offset= (size_t) ((ptr->type == MEMCACHED_CONNECTION_UDP) ? UDP_DATAGRAM_HEADER_LENGTH : 0); - ptr->read_buffer_length= 0; - ptr->read_ptr= ptr->read_buffer; - ptr->options.is_shutting_down= false; - memcached_server_response_reset(ptr); - - // We reset the version so that if we end up talking to a different server - // we don't have stale server version information. - ptr->major_version= ptr->minor_version= ptr->micro_version= UINT8_MAX; - - if (io_death) - { - ptr->server_failure_counter++; - set_last_disconnected_host(ptr); - } -} - -void send_quit(memcached_st *ptr) -{ - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - memcached_quit_server(instance, false); - } -} - -void memcached_quit(memcached_st *ptr) -{ - if (initialize_query(ptr) != MEMCACHED_SUCCESS) - { - return; - } - - send_quit(ptr); -} diff --git a/libmemcached/quit.cc b/libmemcached/quit.cc new file mode 100644 index 00000000..2efe909b --- /dev/null +++ b/libmemcached/quit.cc @@ -0,0 +1,142 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +/* + This closes all connections (forces flush of input as well). + + Maybe add a host specific, or key specific version? + + The reason we send "quit" is that in case we have buffered IO, this + will force data to be completed. +*/ + +void memcached_quit_server(memcached_server_st *ptr, bool io_death) +{ + if (ptr->fd != INVALID_SOCKET) + { + if (io_death == false && ptr->type != MEMCACHED_CONNECTION_UDP && ptr->options.is_shutting_down == false) + { + memcached_return_t rc; + char buffer[MEMCACHED_MAX_BUFFER]; + + ptr->options.is_shutting_down= true; + + if (ptr->root->flags.binary_protocol) + { + protocol_binary_request_quit request= {}; // = {.bytes= {0}}; + request.message.header.request.magic = PROTOCOL_BINARY_REQ; + request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT; + request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; + rc= memcached_do(ptr, request.bytes, sizeof(request.bytes), true); + } + else + { + rc= memcached_do(ptr, "quit\r\n", sizeof("quit\r\n") -1, true); + } + + WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED); + (void)rc; // Shut up ICC + + /* read until socket is closed, or there is an error + * closing the socket before all data is read + * results in server throwing away all data which is + * not read + * + * In .40 we began to only do this if we had been doing buffered + * requests of had replication enabled. + */ + if (ptr->root->flags.buffer_requests || ptr->root->number_of_replicas) + { + ssize_t nread; + while (memcached_io_read(ptr, buffer, sizeof(buffer)/sizeof(*buffer), + &nread) == MEMCACHED_SUCCESS); + } + + + /* + * memcached_io_read may call memcached_quit_server with io_death if + * it encounters problems, but we don't care about those occurences. + * The intention of that loop is to drain the data sent from the + * server to ensure that the server processed all of the data we + * sent to the server. + */ + ptr->server_failure_counter= 0; + } + memcached_io_close(ptr); + } + + ptr->fd= INVALID_SOCKET; + ptr->io_bytes_sent= 0; + ptr->write_buffer_offset= (size_t) ((ptr->type == MEMCACHED_CONNECTION_UDP) ? UDP_DATAGRAM_HEADER_LENGTH : 0); + ptr->read_buffer_length= 0; + ptr->read_ptr= ptr->read_buffer; + ptr->options.is_shutting_down= false; + memcached_server_response_reset(ptr); + + // We reset the version so that if we end up talking to a different server + // we don't have stale server version information. + ptr->major_version= ptr->minor_version= ptr->micro_version= UINT8_MAX; + + if (io_death) + { + ptr->server_failure_counter++; + set_last_disconnected_host(ptr); + } +} + +void send_quit(memcached_st *ptr) +{ + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + memcached_quit_server(instance, false); + } +} + +void memcached_quit(memcached_st *ptr) +{ + if (initialize_query(ptr) != MEMCACHED_SUCCESS) + { + return; + } + + send_quit(ptr); +} diff --git a/libmemcached/quit.h b/libmemcached/quit.h index e640020a..0338eaf0 100644 --- a/libmemcached/quit.h +++ b/libmemcached/quit.h @@ -1,16 +1,41 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. * - * Summary: returns a human readable string for the error message + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_QUIT_H__ -#define __LIBMEMCACHED_QUIT_H__ +#pragma once #ifdef __cplusplus extern "C" { @@ -28,5 +53,3 @@ void send_quit(memcached_st *ptr); #ifdef __cplusplus } #endif - -#endif /* __LIBMEMCACHED_QUIT_H__ */ diff --git a/libmemcached/response.c b/libmemcached/response.c deleted file mode 100644 index 49825fb1..00000000 --- a/libmemcached/response.c +++ /dev/null @@ -1,584 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: memcached_response() is used to determine the return result from an issued command. - * -*/ - -#include "common.h" - -static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result); -static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result); - -memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result) -{ - memcached_server_response_decrement(ptr); - - if (result == NULL) - { - memcached_st *root= (memcached_st *)ptr->root; - result = &root->result; - } - - memcached_return_t rc; - if (ptr->root->flags.binary_protocol) - rc= binary_read_one_response(ptr, buffer, buffer_length, result); - else - rc= textual_read_one_response(ptr, buffer, buffer_length, result); - - unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE || - rc == MEMCACHED_PROTOCOL_ERROR || - rc == MEMCACHED_CLIENT_ERROR || - rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) - memcached_io_reset(ptr); - - return rc; -} - -memcached_return_t memcached_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result) -{ - /* We may have old commands in the buffer not set, first purge */ - if ((ptr->root->flags.no_block) && (memcached_is_processing_input(ptr->root) == false)) - { - (void)memcached_io_write(ptr, NULL, 0, true); - } - - /* - * The previous implementation purged all pending requests and just - * returned the last one. Purge all pending messages to ensure backwards - * compatibility. - */ - if (ptr->root->flags.binary_protocol == false) - { - while (memcached_server_response_count(ptr) > 1) - { - memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result); - - unlikely (rc != MEMCACHED_END && - rc != MEMCACHED_STORED && - rc != MEMCACHED_SUCCESS && - rc != MEMCACHED_STAT && - rc != MEMCACHED_DELETED && - rc != MEMCACHED_NOTFOUND && - rc != MEMCACHED_NOTSTORED && - rc != MEMCACHED_DATA_EXISTS) - return rc; - } - } - - return memcached_read_one_response(ptr, buffer, buffer_length, result); -} - -static memcached_return_t textual_value_fetch(memcached_server_write_instance_st ptr, - char *buffer, - memcached_result_st *result) -{ - memcached_return_t rc= MEMCACHED_SUCCESS; - char *string_ptr; - char *end_ptr; - char *next_ptr; - size_t value_length; - size_t to_read; - char *value_ptr; - ssize_t read_length= 0; - memcached_return_t rrc; - - if (ptr->root->flags.use_udp) - return MEMCACHED_NOT_SUPPORTED; - - WATCHPOINT_ASSERT(ptr->root); - end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE; - - memcached_result_reset(result); - - string_ptr= buffer; - string_ptr+= 6; /* "VALUE " */ - - - /* We load the key */ - { - char *key; - size_t prefix_length; - - key= result->item_key; - result->key_length= 0; - - for (prefix_length= memcached_array_size(ptr->root->prefix_key); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++) - { - if (prefix_length == 0) - { - *key= *string_ptr; - key++; - result->key_length++; - } - else - prefix_length--; - } - result->item_key[result->key_length]= 0; - } - - if (end_ptr == string_ptr) - goto read_error; - - /* Flags fetch move past space */ - string_ptr++; - if (end_ptr == string_ptr) - goto read_error; - for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++); - result->item_flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10); - - if (end_ptr == string_ptr) - goto read_error; - - /* Length fetch move past space*/ - string_ptr++; - if (end_ptr == string_ptr) - goto read_error; - - for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++); - value_length= (size_t)strtoull(next_ptr, &string_ptr, 10); - - if (end_ptr == string_ptr) - goto read_error; - - /* Skip spaces */ - if (*string_ptr == '\r') - { - /* Skip past the \r\n */ - string_ptr+= 2; - } - else - { - string_ptr++; - for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++); - result->item_cas= strtoull(next_ptr, &string_ptr, 10); - } - - if (end_ptr < string_ptr) - goto read_error; - - /* We add two bytes so that we can walk the \r\n */ - rc= memcached_string_check(&result->value, value_length+2); - if (rc != MEMCACHED_SUCCESS) - { - value_length= 0; - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - } - - value_ptr= memcached_string_value_mutable(&result->value); - /* - We read the \r\n into the string since not doing so is more - cycles then the waster of memory to do so. - - We are null terminating through, which will most likely make - some people lazy about using the return length. - */ - to_read= (value_length) + 2; - rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length); - if (rrc != MEMCACHED_SUCCESS) - return rrc; - - if (read_length != (ssize_t)(value_length + 2)) - { - goto read_error; - } - - /* This next bit blows the API, but this is internal....*/ - { - char *char_ptr; - char_ptr= memcached_string_value_mutable(&result->value);; - char_ptr[value_length]= 0; - char_ptr[value_length + 1]= 0; - memcached_string_set_length(&result->value, value_length); - } - - return MEMCACHED_SUCCESS; - -read_error: - memcached_io_reset(ptr); - - return MEMCACHED_PARTIAL_READ; -} - -static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result) -{ - memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length); - if (rc != MEMCACHED_SUCCESS) - return rc; - - switch(buffer[0]) - { - case 'V': /* VALUE || VERSION */ - if (buffer[1] == 'A') /* VALUE */ - { - /* We add back in one because we will need to search for END */ - memcached_server_response_increment(ptr); - return textual_value_fetch(ptr, buffer, result); - } - else if (buffer[1] == 'E') /* VERSION */ - { - return MEMCACHED_SUCCESS; - } - else - { - WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - case 'O': /* OK */ - return MEMCACHED_SUCCESS; - case 'S': /* STORED STATS SERVER_ERROR */ - { - if (buffer[2] == 'A') /* STORED STATS */ - { - memcached_server_response_increment(ptr); - return MEMCACHED_STAT; - } - else if (buffer[1] == 'E') /* SERVER_ERROR */ - { - char *rel_ptr; - char *startptr= buffer + 13, *endptr= startptr; - - while (*endptr != '\r' && *endptr != '\n') endptr++; - - /* - Yes, we could make this "efficent" but to do that we would need - to maintain more state for the size of the buffer. Why waste - memory in the struct, which is important, for something that - rarely should happen? - */ - rel_ptr= (char *)libmemcached_realloc(ptr->root, - ptr->cached_server_error, - (size_t) (endptr - startptr + 1)); - - if (rel_ptr == NULL) - { - /* If we happened to have some memory, we just null it since we don't know the size */ - if (ptr->cached_server_error) - ptr->cached_server_error[0]= 0; - return MEMCACHED_SERVER_ERROR; - } - ptr->cached_server_error= rel_ptr; - - memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr)); - ptr->cached_server_error[endptr - startptr]= 0; - return MEMCACHED_SERVER_ERROR; - } - else if (buffer[1] == 'T') - return MEMCACHED_STORED; - else - { - WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - } - case 'D': /* DELETED */ - return MEMCACHED_DELETED; - case 'N': /* NOT_FOUND */ - { - if (buffer[4] == 'F') - return MEMCACHED_NOTFOUND; - else if (buffer[4] == 'S') - return MEMCACHED_NOTSTORED; - else - { - WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - } - case 'E': /* PROTOCOL ERROR or END */ - { - if (buffer[1] == 'N') - return MEMCACHED_END; - else if (buffer[1] == 'R') - return MEMCACHED_PROTOCOL_ERROR; - else if (buffer[1] == 'X') - return MEMCACHED_DATA_EXISTS; - else - { - WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - - } - case 'I': /* CLIENT ERROR */ - /* We add back in one because we will need to search for END */ - memcached_server_response_increment(ptr); - return MEMCACHED_ITEM; - case 'C': /* CLIENT ERROR */ - return MEMCACHED_CLIENT_ERROR; - default: - { - unsigned long long auto_return_value; - - if (sscanf(buffer, "%llu", &auto_return_value) == 1) - return MEMCACHED_SUCCESS; - - WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - } - - /* NOTREACHED */ -} - -static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result) -{ - memcached_return_t rc; - protocol_binary_response_header header; - - if ((rc= memcached_safe_read(ptr, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return rc; - } - - if (header.response.magic != PROTOCOL_BINARY_RES) - { - return MEMCACHED_PROTOCOL_ERROR; - } - - /* - ** Convert the header to host local endian! - */ - header.response.keylen= ntohs(header.response.keylen); - header.response.status= ntohs(header.response.status); - header.response.bodylen= ntohl(header.response.bodylen); - header.response.cas= ntohll(header.response.cas); - uint32_t bodylen= header.response.bodylen; - - if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS || - header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) - { - switch (header.response.opcode) - { - case PROTOCOL_BINARY_CMD_GETKQ: - /* - * We didn't increment the response counter for the GETKQ packet - * (only the final NOOP), so we need to increment the counter again. - */ - memcached_server_response_increment(ptr); - /* FALLTHROUGH */ - case PROTOCOL_BINARY_CMD_GETK: - { - uint16_t keylen= header.response.keylen; - memcached_result_reset(result); - result->item_cas= header.response.cas; - - if ((rc= memcached_safe_read(ptr, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - - result->item_flags= ntohl(result->item_flags); - bodylen -= header.response.extlen; - - result->key_length= keylen; - if ((rc= memcached_safe_read(ptr, result->item_key, keylen)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - - bodylen -= keylen; - if (memcached_string_check(&result->value, - bodylen) != MEMCACHED_SUCCESS) - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - - char *vptr= memcached_string_value_mutable(&result->value); - if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - - memcached_string_set_length(&result->value, bodylen); - } - break; - case PROTOCOL_BINARY_CMD_INCREMENT: - case PROTOCOL_BINARY_CMD_DECREMENT: - { - if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t)) - return MEMCACHED_PROTOCOL_ERROR; - - WATCHPOINT_ASSERT(bodylen == buffer_length); - uint64_t val; - if ((rc= memcached_safe_read(ptr, &val, sizeof(val))) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - - val= ntohll(val); - memcpy(buffer, &val, sizeof(val)); - } - break; - case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: - case PROTOCOL_BINARY_CMD_VERSION: - { - memset(buffer, 0, buffer_length); - if (bodylen >= buffer_length) - { - /* not enough space in buffer.. should not happen... */ - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - else if ((rc= memcached_safe_read(ptr, buffer, bodylen)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - } - break; - case PROTOCOL_BINARY_CMD_FLUSH: - case PROTOCOL_BINARY_CMD_QUIT: - case PROTOCOL_BINARY_CMD_SET: - case PROTOCOL_BINARY_CMD_ADD: - case PROTOCOL_BINARY_CMD_REPLACE: - case PROTOCOL_BINARY_CMD_APPEND: - case PROTOCOL_BINARY_CMD_PREPEND: - case PROTOCOL_BINARY_CMD_DELETE: - { - WATCHPOINT_ASSERT(bodylen == 0); - return MEMCACHED_SUCCESS; - } - case PROTOCOL_BINARY_CMD_NOOP: - { - WATCHPOINT_ASSERT(bodylen == 0); - return MEMCACHED_END; - } - case PROTOCOL_BINARY_CMD_STAT: - { - if (bodylen == 0) - { - return MEMCACHED_END; - } - else if (bodylen + 1 > buffer_length) - { - /* not enough space in buffer.. should not happen... */ - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - else - { - size_t keylen= header.response.keylen; - memset(buffer, 0, buffer_length); - if ((rc= memcached_safe_read(ptr, buffer, keylen)) != MEMCACHED_SUCCESS || - (rc= memcached_safe_read(ptr, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - } - } - break; - - case PROTOCOL_BINARY_CMD_SASL_AUTH: - case PROTOCOL_BINARY_CMD_SASL_STEP: - { - memcached_result_reset(result); - result->item_cas= header.response.cas; - - if (memcached_string_check(&result->value, - bodylen) != MEMCACHED_SUCCESS) - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - - char *vptr= memcached_string_value_mutable(&result->value); - if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - - memcached_string_set_length(&result->value, bodylen); - } - break; - default: - { - /* Command not implemented yet! */ - WATCHPOINT_ASSERT(0); - return MEMCACHED_PROTOCOL_ERROR; - } - } - } - else if (header.response.bodylen) - { - /* What should I do with the error message??? just discard it for now */ - char hole[SMALL_STRING_LEN]; - while (bodylen > 0) - { - size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen; - if ((rc= memcached_safe_read(ptr, hole, nr)) != MEMCACHED_SUCCESS) - { - WATCHPOINT_ERROR(rc); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - bodylen-= (uint32_t) nr; - } - - /* This might be an error from one of the quiet commands.. if - * so, just throw it away and get the next one. What about creating - * a callback to the user with the error information? - */ - switch (header.response.opcode) - { - case PROTOCOL_BINARY_CMD_SETQ: - case PROTOCOL_BINARY_CMD_ADDQ: - case PROTOCOL_BINARY_CMD_REPLACEQ: - case PROTOCOL_BINARY_CMD_APPENDQ: - case PROTOCOL_BINARY_CMD_PREPENDQ: - return binary_read_one_response(ptr, buffer, buffer_length, result); - default: - break; - } - } - - rc= MEMCACHED_SUCCESS; - unlikely(header.response.status != 0) - switch (header.response.status) - { - case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT: - rc= MEMCACHED_NOTFOUND; - break; - case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS: - rc= MEMCACHED_DATA_EXISTS; - break; - case PROTOCOL_BINARY_RESPONSE_NOT_STORED: - rc= MEMCACHED_NOTSTORED; - break; - case PROTOCOL_BINARY_RESPONSE_E2BIG: - rc= MEMCACHED_E2BIG; - break; - case PROTOCOL_BINARY_RESPONSE_ENOMEM: - rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE; - break; - case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE: - rc= MEMCACHED_AUTH_CONTINUE; - break; - case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR: - rc= MEMCACHED_AUTH_FAILURE; - break; - case PROTOCOL_BINARY_RESPONSE_EINVAL: - case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND: - default: - /* @todo fix the error mappings */ - rc= MEMCACHED_PROTOCOL_ERROR; - break; - } - - return rc; -} diff --git a/libmemcached/response.cc b/libmemcached/response.cc new file mode 100644 index 00000000..572aef58 --- /dev/null +++ b/libmemcached/response.cc @@ -0,0 +1,610 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result); +static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result); + +memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result) +{ + memcached_server_response_decrement(ptr); + + if (result == NULL) + { + memcached_st *root= (memcached_st *)ptr->root; + result = &root->result; + } + + memcached_return_t rc; + if (ptr->root->flags.binary_protocol) + rc= binary_read_one_response(ptr, buffer, buffer_length, result); + else + rc= textual_read_one_response(ptr, buffer, buffer_length, result); + + unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE || + rc == MEMCACHED_PROTOCOL_ERROR || + rc == MEMCACHED_CLIENT_ERROR || + rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) + memcached_io_reset(ptr); + + return rc; +} + +memcached_return_t memcached_response(memcached_server_write_instance_st ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result) +{ + /* We may have old commands in the buffer not set, first purge */ + if ((ptr->root->flags.no_block) && (memcached_is_processing_input(ptr->root) == false)) + { + (void)memcached_io_write(ptr, NULL, 0, true); + } + + /* + * The previous implementation purged all pending requests and just + * returned the last one. Purge all pending messages to ensure backwards + * compatibility. + */ + if (ptr->root->flags.binary_protocol == false) + { + while (memcached_server_response_count(ptr) > 1) + { + memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result); + + unlikely (rc != MEMCACHED_END && + rc != MEMCACHED_STORED && + rc != MEMCACHED_SUCCESS && + rc != MEMCACHED_STAT && + rc != MEMCACHED_DELETED && + rc != MEMCACHED_NOTFOUND && + rc != MEMCACHED_NOTSTORED && + rc != MEMCACHED_DATA_EXISTS) + return rc; + } + } + + return memcached_read_one_response(ptr, buffer, buffer_length, result); +} + +static memcached_return_t textual_value_fetch(memcached_server_write_instance_st ptr, + char *buffer, + memcached_result_st *result) +{ + memcached_return_t rc= MEMCACHED_SUCCESS; + char *string_ptr; + char *end_ptr; + char *next_ptr; + size_t value_length; + size_t to_read; + char *value_ptr; + ssize_t read_length= 0; + memcached_return_t rrc; + + if (ptr->root->flags.use_udp) + return MEMCACHED_NOT_SUPPORTED; + + WATCHPOINT_ASSERT(ptr->root); + end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE; + + memcached_result_reset(result); + + string_ptr= buffer; + string_ptr+= 6; /* "VALUE " */ + + + /* We load the key */ + { + char *key; + size_t prefix_length; + + key= result->item_key; + result->key_length= 0; + + for (prefix_length= memcached_array_size(ptr->root->prefix_key); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++) + { + if (prefix_length == 0) + { + *key= *string_ptr; + key++; + result->key_length++; + } + else + prefix_length--; + } + result->item_key[result->key_length]= 0; + } + + if (end_ptr == string_ptr) + goto read_error; + + /* Flags fetch move past space */ + string_ptr++; + if (end_ptr == string_ptr) + goto read_error; + for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++); + result->item_flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10); + + if (end_ptr == string_ptr) + goto read_error; + + /* Length fetch move past space*/ + string_ptr++; + if (end_ptr == string_ptr) + goto read_error; + + for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++); + value_length= (size_t)strtoull(next_ptr, &string_ptr, 10); + + if (end_ptr == string_ptr) + goto read_error; + + /* Skip spaces */ + if (*string_ptr == '\r') + { + /* Skip past the \r\n */ + string_ptr+= 2; + } + else + { + string_ptr++; + for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++); + result->item_cas= strtoull(next_ptr, &string_ptr, 10); + } + + if (end_ptr < string_ptr) + goto read_error; + + /* We add two bytes so that we can walk the \r\n */ + rc= memcached_string_check(&result->value, value_length+2); + if (rc != MEMCACHED_SUCCESS) + { + value_length= 0; + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + } + + value_ptr= memcached_string_value_mutable(&result->value); + /* + We read the \r\n into the string since not doing so is more + cycles then the waster of memory to do so. + + We are null terminating through, which will most likely make + some people lazy about using the return length. + */ + to_read= (value_length) + 2; + rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length); + if (rrc != MEMCACHED_SUCCESS) + return rrc; + + if (read_length != (ssize_t)(value_length + 2)) + { + goto read_error; + } + + /* This next bit blows the API, but this is internal....*/ + { + char *char_ptr; + char_ptr= memcached_string_value_mutable(&result->value);; + char_ptr[value_length]= 0; + char_ptr[value_length + 1]= 0; + memcached_string_set_length(&result->value, value_length); + } + + return MEMCACHED_SUCCESS; + +read_error: + memcached_io_reset(ptr); + + return MEMCACHED_PARTIAL_READ; +} + +static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result) +{ + memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length); + if (rc != MEMCACHED_SUCCESS) + return rc; + + switch(buffer[0]) + { + case 'V': /* VALUE || VERSION */ + if (buffer[1] == 'A') /* VALUE */ + { + /* We add back in one because we will need to search for END */ + memcached_server_response_increment(ptr); + return textual_value_fetch(ptr, buffer, result); + } + else if (buffer[1] == 'E') /* VERSION */ + { + return MEMCACHED_SUCCESS; + } + else + { + WATCHPOINT_STRING(buffer); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + case 'O': /* OK */ + return MEMCACHED_SUCCESS; + case 'S': /* STORED STATS SERVER_ERROR */ + { + if (buffer[2] == 'A') /* STORED STATS */ + { + memcached_server_response_increment(ptr); + return MEMCACHED_STAT; + } + else if (buffer[1] == 'E') /* SERVER_ERROR */ + { + char *rel_ptr; + char *startptr= buffer + 13, *endptr= startptr; + + while (*endptr != '\r' && *endptr != '\n') endptr++; + + /* + Yes, we could make this "efficent" but to do that we would need + to maintain more state for the size of the buffer. Why waste + memory in the struct, which is important, for something that + rarely should happen? + */ + rel_ptr= (char *)libmemcached_realloc(ptr->root, + ptr->cached_server_error, + (size_t) (endptr - startptr + 1)); + + if (rel_ptr == NULL) + { + /* If we happened to have some memory, we just null it since we don't know the size */ + if (ptr->cached_server_error) + ptr->cached_server_error[0]= 0; + return MEMCACHED_SERVER_ERROR; + } + ptr->cached_server_error= rel_ptr; + + memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr)); + ptr->cached_server_error[endptr - startptr]= 0; + return MEMCACHED_SERVER_ERROR; + } + else if (buffer[1] == 'T') + return MEMCACHED_STORED; + else + { + WATCHPOINT_STRING(buffer); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + } + case 'D': /* DELETED */ + return MEMCACHED_DELETED; + case 'N': /* NOT_FOUND */ + { + if (buffer[4] == 'F') + return MEMCACHED_NOTFOUND; + else if (buffer[4] == 'S') + return MEMCACHED_NOTSTORED; + else + { + WATCHPOINT_STRING(buffer); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + } + case 'E': /* PROTOCOL ERROR or END */ + { + if (buffer[1] == 'N') + return MEMCACHED_END; + else if (buffer[1] == 'R') + return MEMCACHED_PROTOCOL_ERROR; + else if (buffer[1] == 'X') + return MEMCACHED_DATA_EXISTS; + else + { + WATCHPOINT_STRING(buffer); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + + } + case 'I': /* CLIENT ERROR */ + /* We add back in one because we will need to search for END */ + memcached_server_response_increment(ptr); + return MEMCACHED_ITEM; + case 'C': /* CLIENT ERROR */ + return MEMCACHED_CLIENT_ERROR; + default: + { + unsigned long long auto_return_value; + + if (sscanf(buffer, "%llu", &auto_return_value) == 1) + return MEMCACHED_SUCCESS; + + WATCHPOINT_STRING(buffer); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + } + + /* NOTREACHED */ +} + +static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result) +{ + memcached_return_t rc; + protocol_binary_response_header header; + + if ((rc= memcached_safe_read(ptr, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return rc; + } + + if (header.response.magic != PROTOCOL_BINARY_RES) + { + return MEMCACHED_PROTOCOL_ERROR; + } + + /* + ** Convert the header to host local endian! + */ + header.response.keylen= ntohs(header.response.keylen); + header.response.status= ntohs(header.response.status); + header.response.bodylen= ntohl(header.response.bodylen); + header.response.cas= ntohll(header.response.cas); + uint32_t bodylen= header.response.bodylen; + + if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS || + header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) + { + switch (header.response.opcode) + { + case PROTOCOL_BINARY_CMD_GETKQ: + /* + * We didn't increment the response counter for the GETKQ packet + * (only the final NOOP), so we need to increment the counter again. + */ + memcached_server_response_increment(ptr); + /* FALLTHROUGH */ + case PROTOCOL_BINARY_CMD_GETK: + { + uint16_t keylen= header.response.keylen; + memcached_result_reset(result); + result->item_cas= header.response.cas; + + if ((rc= memcached_safe_read(ptr, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + + result->item_flags= ntohl(result->item_flags); + bodylen -= header.response.extlen; + + result->key_length= keylen; + if ((rc= memcached_safe_read(ptr, result->item_key, keylen)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + + bodylen -= keylen; + if (memcached_string_check(&result->value, + bodylen) != MEMCACHED_SUCCESS) + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + + char *vptr= memcached_string_value_mutable(&result->value); + if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + + memcached_string_set_length(&result->value, bodylen); + } + break; + case PROTOCOL_BINARY_CMD_INCREMENT: + case PROTOCOL_BINARY_CMD_DECREMENT: + { + if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t)) + return MEMCACHED_PROTOCOL_ERROR; + + WATCHPOINT_ASSERT(bodylen == buffer_length); + uint64_t val; + if ((rc= memcached_safe_read(ptr, &val, sizeof(val))) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + + val= ntohll(val); + memcpy(buffer, &val, sizeof(val)); + } + break; + case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: + case PROTOCOL_BINARY_CMD_VERSION: + { + memset(buffer, 0, buffer_length); + if (bodylen >= buffer_length) + { + /* not enough space in buffer.. should not happen... */ + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + else if ((rc= memcached_safe_read(ptr, buffer, bodylen)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + } + break; + case PROTOCOL_BINARY_CMD_FLUSH: + case PROTOCOL_BINARY_CMD_QUIT: + case PROTOCOL_BINARY_CMD_SET: + case PROTOCOL_BINARY_CMD_ADD: + case PROTOCOL_BINARY_CMD_REPLACE: + case PROTOCOL_BINARY_CMD_APPEND: + case PROTOCOL_BINARY_CMD_PREPEND: + case PROTOCOL_BINARY_CMD_DELETE: + { + WATCHPOINT_ASSERT(bodylen == 0); + return MEMCACHED_SUCCESS; + } + case PROTOCOL_BINARY_CMD_NOOP: + { + WATCHPOINT_ASSERT(bodylen == 0); + return MEMCACHED_END; + } + case PROTOCOL_BINARY_CMD_STAT: + { + if (bodylen == 0) + { + return MEMCACHED_END; + } + else if (bodylen + 1 > buffer_length) + { + /* not enough space in buffer.. should not happen... */ + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + else + { + size_t keylen= header.response.keylen; + memset(buffer, 0, buffer_length); + if ((rc= memcached_safe_read(ptr, buffer, keylen)) != MEMCACHED_SUCCESS || + (rc= memcached_safe_read(ptr, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + } + } + break; + + case PROTOCOL_BINARY_CMD_SASL_AUTH: + case PROTOCOL_BINARY_CMD_SASL_STEP: + { + memcached_result_reset(result); + result->item_cas= header.response.cas; + + if (memcached_string_check(&result->value, + bodylen) != MEMCACHED_SUCCESS) + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + + char *vptr= memcached_string_value_mutable(&result->value); + if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + + memcached_string_set_length(&result->value, bodylen); + } + break; + default: + { + /* Command not implemented yet! */ + WATCHPOINT_ASSERT(0); + return MEMCACHED_PROTOCOL_ERROR; + } + } + } + else if (header.response.bodylen) + { + /* What should I do with the error message??? just discard it for now */ + char hole[SMALL_STRING_LEN]; + while (bodylen > 0) + { + size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen; + if ((rc= memcached_safe_read(ptr, hole, nr)) != MEMCACHED_SUCCESS) + { + WATCHPOINT_ERROR(rc); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + bodylen-= (uint32_t) nr; + } + + /* This might be an error from one of the quiet commands.. if + * so, just throw it away and get the next one. What about creating + * a callback to the user with the error information? + */ + switch (header.response.opcode) + { + case PROTOCOL_BINARY_CMD_SETQ: + case PROTOCOL_BINARY_CMD_ADDQ: + case PROTOCOL_BINARY_CMD_REPLACEQ: + case PROTOCOL_BINARY_CMD_APPENDQ: + case PROTOCOL_BINARY_CMD_PREPENDQ: + return binary_read_one_response(ptr, buffer, buffer_length, result); + default: + break; + } + } + + rc= MEMCACHED_SUCCESS; + unlikely(header.response.status != 0) + switch (header.response.status) + { + case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT: + rc= MEMCACHED_NOTFOUND; + break; + case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS: + rc= MEMCACHED_DATA_EXISTS; + break; + case PROTOCOL_BINARY_RESPONSE_NOT_STORED: + rc= MEMCACHED_NOTSTORED; + break; + case PROTOCOL_BINARY_RESPONSE_E2BIG: + rc= MEMCACHED_E2BIG; + break; + case PROTOCOL_BINARY_RESPONSE_ENOMEM: + rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE; + break; + case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE: + rc= MEMCACHED_AUTH_CONTINUE; + break; + case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR: + rc= MEMCACHED_AUTH_FAILURE; + break; + case PROTOCOL_BINARY_RESPONSE_EINVAL: + case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND: + default: + /* @todo fix the error mappings */ + rc= MEMCACHED_PROTOCOL_ERROR; + break; + } + + return rc; +} diff --git a/libmemcached/response.h b/libmemcached/response.h index da6f2b42..51f09998 100644 --- a/libmemcached/response.h +++ b/libmemcached/response.h @@ -1,16 +1,41 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. * - * Summary: Change the behavior of the memcached connection. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_RESPONSE_H__ -#define __LIBMEMCACHED_RESPONSE_H__ +#pragma once #ifdef __cplusplus extern "C" { @@ -30,5 +55,3 @@ memcached_return_t memcached_response(memcached_server_write_instance_st ptr, #ifdef __cplusplus } #endif - -#endif /* __LIBMEMCACHED_RESPONSE_H__ */ diff --git a/libmemcached/result.c b/libmemcached/result.c deleted file mode 100644 index 6e58eebd..00000000 --- a/libmemcached/result.c +++ /dev/null @@ -1,144 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: Functions to manipulate the result structure. - * - */ - -/* - memcached_result_st are used to internally represent the return values from - memcached. We use a structure so that long term as identifiers are added - to memcached we will be able to absorb new attributes without having - to addjust the entire API. -*/ -#include "common.h" - -static inline void _result_init(memcached_result_st *self, - memcached_st *memc) -{ - self->item_flags= 0; - self->item_expiration= 0; - self->key_length= 0; - self->item_cas= 0; - self->root= memc; - self->item_key[0]= 0; -} - -memcached_result_st *memcached_result_create(const memcached_st *memc, - memcached_result_st *ptr) -{ - WATCHPOINT_ASSERT(memc); - - /* Saving malloc calls :) */ - if (ptr) - { - ptr->options.is_allocated= false; - } - else - { - ptr= libmemcached_malloc(memc, sizeof(memcached_result_st)); - - if (ptr == NULL) - return NULL; - - ptr->options.is_allocated= true; - } - - ptr->options.is_initialized= true; - - _result_init(ptr, (memcached_st *)memc); - - WATCHPOINT_SET(ptr->value.options.is_initialized= false); - memcached_string_create(memc, &ptr->value, 0); - WATCHPOINT_ASSERT_INITIALIZED(&ptr->value); - WATCHPOINT_ASSERT(ptr->value.string == NULL); - - return ptr; -} - -void memcached_result_reset(memcached_result_st *ptr) -{ - ptr->key_length= 0; - memcached_string_reset(&ptr->value); - ptr->item_flags= 0; - ptr->item_cas= 0; - ptr->item_expiration= 0; -} - -void memcached_result_free(memcached_result_st *ptr) -{ - if (ptr == NULL) - return; - - memcached_string_free(&ptr->value); - - if (memcached_is_allocated(ptr)) - { - WATCHPOINT_ASSERT(ptr->root); // Without a root, that means that result was not properly initialized. - libmemcached_free(ptr->root, ptr); - } - else - { - ptr->options.is_initialized= false; - } -} - -memcached_return_t memcached_result_set_value(memcached_result_st *ptr, - const char *value, - size_t length) -{ - memcached_return_t rc= memcached_string_append(&ptr->value, value, length); - - if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) - { - memcached_set_errno(ptr->root, errno, NULL); - } - - return rc; -} - -const char *memcached_result_key_value(const memcached_result_st *self) -{ - return self->key_length ? self->item_key : NULL; -} - -size_t memcached_result_key_length(const memcached_result_st *self) -{ - return self->key_length; -} - -const char *memcached_result_value(const memcached_result_st *self) -{ - const memcached_string_st *sptr= &self->value; - return memcached_string_value(sptr); -} - -size_t memcached_result_length(const memcached_result_st *self) -{ - const memcached_string_st *sptr= &self->value; - return memcached_string_length(sptr); -} - -uint32_t memcached_result_flags(const memcached_result_st *self) -{ - return self->item_flags; -} - -uint64_t memcached_result_cas(const memcached_result_st *self) -{ - return self->item_cas; -} - -void memcached_result_set_flags(memcached_result_st *self, uint32_t flags) -{ - self->item_flags= flags; -} - -void memcached_result_set_expiration(memcached_result_st *self, time_t expiration) -{ - self->item_expiration= expiration; -} diff --git a/libmemcached/result.cc b/libmemcached/result.cc new file mode 100644 index 00000000..1d0b763d --- /dev/null +++ b/libmemcached/result.cc @@ -0,0 +1,171 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + memcached_result_st are used to internally represent the return values from + memcached. We use a structure so that long term as identifiers are added + to memcached we will be able to absorb new attributes without having + to addjust the entire API. +*/ +#include + +static inline void _result_init(memcached_result_st *self, + memcached_st *memc) +{ + self->item_flags= 0; + self->item_expiration= 0; + self->key_length= 0; + self->item_cas= 0; + self->root= memc; + self->item_key[0]= 0; +} + +memcached_result_st *memcached_result_create(const memcached_st *memc, + memcached_result_st *ptr) +{ + WATCHPOINT_ASSERT(memc); + + /* Saving malloc calls :) */ + if (ptr) + { + ptr->options.is_allocated= false; + } + else + { + ptr= static_cast(libmemcached_malloc(memc, sizeof(memcached_result_st))); + + if (ptr == NULL) + return NULL; + + ptr->options.is_allocated= true; + } + + ptr->options.is_initialized= true; + + _result_init(ptr, (memcached_st *)memc); + + WATCHPOINT_SET(ptr->value.options.is_initialized= false); + memcached_string_create(memc, &ptr->value, 0); + WATCHPOINT_ASSERT_INITIALIZED(&ptr->value); + WATCHPOINT_ASSERT(ptr->value.string == NULL); + + return ptr; +} + +void memcached_result_reset(memcached_result_st *ptr) +{ + ptr->key_length= 0; + memcached_string_reset(&ptr->value); + ptr->item_flags= 0; + ptr->item_cas= 0; + ptr->item_expiration= 0; +} + +void memcached_result_free(memcached_result_st *ptr) +{ + if (ptr == NULL) + return; + + memcached_string_free(&ptr->value); + + if (memcached_is_allocated(ptr)) + { + WATCHPOINT_ASSERT(ptr->root); // Without a root, that means that result was not properly initialized. + libmemcached_free(ptr->root, ptr); + } + else + { + ptr->options.is_initialized= false; + } +} + +memcached_return_t memcached_result_set_value(memcached_result_st *ptr, + const char *value, + size_t length) +{ + memcached_return_t rc= memcached_string_append(&ptr->value, value, length); + + if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) + { + memcached_set_errno(ptr->root, errno, NULL); + } + + return rc; +} + +const char *memcached_result_key_value(const memcached_result_st *self) +{ + return self->key_length ? self->item_key : NULL; +} + +size_t memcached_result_key_length(const memcached_result_st *self) +{ + return self->key_length; +} + +const char *memcached_result_value(const memcached_result_st *self) +{ + const memcached_string_st *sptr= &self->value; + return memcached_string_value(sptr); +} + +size_t memcached_result_length(const memcached_result_st *self) +{ + const memcached_string_st *sptr= &self->value; + return memcached_string_length(sptr); +} + +uint32_t memcached_result_flags(const memcached_result_st *self) +{ + return self->item_flags; +} + +uint64_t memcached_result_cas(const memcached_result_st *self) +{ + return self->item_cas; +} + +void memcached_result_set_flags(memcached_result_st *self, uint32_t flags) +{ + self->item_flags= flags; +} + +void memcached_result_set_expiration(memcached_result_st *self, time_t expiration) +{ + self->item_expiration= expiration; +} diff --git a/libmemcached/return.h b/libmemcached/return.h new file mode 100644 index 00000000..048c0670 --- /dev/null +++ b/libmemcached/return.h @@ -0,0 +1,94 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#pragma once + +enum memcached_return_t { + MEMCACHED_SUCCESS, + MEMCACHED_FAILURE, + MEMCACHED_HOST_LOOKUP_FAILURE, + MEMCACHED_CONNECTION_FAILURE, + MEMCACHED_CONNECTION_BIND_FAILURE, + MEMCACHED_WRITE_FAILURE, + MEMCACHED_READ_FAILURE, + MEMCACHED_UNKNOWN_READ_FAILURE, + MEMCACHED_PROTOCOL_ERROR, + MEMCACHED_CLIENT_ERROR, + MEMCACHED_SERVER_ERROR, + MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE, + MEMCACHED_DATA_EXISTS, + MEMCACHED_DATA_DOES_NOT_EXIST, + MEMCACHED_NOTSTORED, + MEMCACHED_STORED, + MEMCACHED_NOTFOUND, + MEMCACHED_MEMORY_ALLOCATION_FAILURE, + MEMCACHED_PARTIAL_READ, + MEMCACHED_SOME_ERRORS, + MEMCACHED_NO_SERVERS, + MEMCACHED_END, + MEMCACHED_DELETED, + MEMCACHED_VALUE, + MEMCACHED_STAT, + MEMCACHED_ITEM, + MEMCACHED_ERRNO, + MEMCACHED_FAIL_UNIX_SOCKET, + MEMCACHED_NOT_SUPPORTED, + MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */ + MEMCACHED_FETCH_NOTFINISHED, + MEMCACHED_TIMEOUT, + MEMCACHED_BUFFERED, + MEMCACHED_BAD_KEY_PROVIDED, + MEMCACHED_INVALID_HOST_PROTOCOL, + MEMCACHED_SERVER_MARKED_DEAD, + MEMCACHED_UNKNOWN_STAT_KEY, + MEMCACHED_E2BIG, + MEMCACHED_INVALID_ARGUMENTS, + MEMCACHED_KEY_TOO_BIG, + MEMCACHED_AUTH_PROBLEM, + MEMCACHED_AUTH_FAILURE, + MEMCACHED_AUTH_CONTINUE, + MEMCACHED_PARSE_ERROR, + MEMCACHED_PARSE_USER_ERROR, + MEMCACHED_DEPRECATED, + MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */ +}; + +#ifndef __cplusplus +typedef enum memcached_return_t memcached_return_t; +#endif + +#define memcached_failed(A) (A) != MEMCACHED_SUCCESS ? true : false + diff --git a/libmemcached/server.c b/libmemcached/server.c deleted file mode 100644 index 4fe676b0..00000000 --- a/libmemcached/server.c +++ /dev/null @@ -1,348 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: String structure used for libmemcached. - * - */ - -/* - This is a partial implementation for fetching/creating memcached_server_st objects. -*/ -#include - -static inline void _server_init(memcached_server_st *self, const memcached_st *root, - const char *hostname, in_port_t port, - uint32_t weight, memcached_connection_t type) -{ - self->options.is_shutting_down= false; - self->options.is_dead= false; - self->number_of_hosts= 0; - self->cursor_active= 0; - self->port= port; - self->cached_errno= 0; - self->fd= -1; - self->io_bytes_sent= 0; - self->server_failure_counter= 0; - self->weight= weight ? weight : 1; // 1 is the default weight value - WATCHPOINT_SET(self->io_wait_count.read= 0); - WATCHPOINT_SET(self->io_wait_count.write= 0); - self->major_version= UINT8_MAX; - self->micro_version= UINT8_MAX; - self->minor_version= UINT8_MAX; - self->type= type; - self->read_ptr= self->read_buffer; - self->cached_server_error= NULL; - self->read_buffer_length= 0; - self->read_data_length= 0; - self->write_buffer_offset= 0; - self->address_info= NULL; - self->address_info_next= NULL; - - if (root) - { - self->next_retry= root->retry_timeout; - } - else - { - self->next_retry= 0; - } - - if (self->weight > 1 && root) - { - ((memcached_st *)root)->ketama.weighted= true; - } - - self->root= root; - self->limit_maxbytes= 0; - if (hostname == NULL) - { - self->hostname[0]= 0; - } - else - { - strncpy(self->hostname, hostname, NI_MAXHOST - 1); - } -} - -static memcached_server_st *_server_create(memcached_server_st *self, const memcached_st *memc) -{ - if (self == NULL) - { - self= (memcached_server_st *)libmemcached_malloc(memc, sizeof(memcached_server_st)); - - if (! self) - return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */ - - self->options.is_allocated= true; - } - else - { - self->options.is_allocated= false; - } - - self->options.is_initialized= true; - - return self; -} - -memcached_server_st *memcached_server_create_with(const memcached_st *memc, - memcached_server_write_instance_st self, - const char *hostname, in_port_t port, - uint32_t weight, memcached_connection_t type) -{ - self= _server_create(self, memc); - - if (self == NULL) - return NULL; - - _server_init(self, memc, hostname, port, weight, type); - - - if (type == MEMCACHED_CONNECTION_UDP) - { - self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH; - memcached_io_init_udp_header(self, 0); - } - - return self; -} - -void memcached_server_free(memcached_server_st *self) -{ - memcached_quit_server(self, false); - - if (self->cached_server_error) - free(self->cached_server_error); - - if (self->address_info) - freeaddrinfo(self->address_info); - - if (memcached_is_allocated(self)) - { - if (self->root) - { - libmemcached_free(self->root, self); - } - else - { - free(self); - } - } - else - { - self->options.is_initialized= false; - } -} - -/* - If we do not have a valid object to clone from, we toss an error. -*/ -memcached_server_st *memcached_server_clone(memcached_server_st *destination, - const memcached_server_st *source) -{ - /* We just do a normal create if source is missing */ - if (source == NULL) - return NULL; - - destination= memcached_server_create_with(source->root, destination, - source->hostname, source->port, source->weight, - source->type); - if (destination != NULL) - { - destination->cached_errno= source->cached_errno; - - if (source->cached_server_error) - destination->cached_server_error= strdup(source->cached_server_error); - } - - return destination; - -} - -memcached_return_t memcached_server_cursor(const memcached_st *ptr, - const memcached_server_fn *callback, - void *context, - uint32_t number_of_callbacks) -{ - memcached_return_t rc; - if ((rc= initialize_const_query(ptr)) != MEMCACHED_SUCCESS) - { - return rc; - } - - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_server_instance_st instance= - memcached_server_instance_by_position(ptr, x); - - for (uint32_t y= 0; y < number_of_callbacks; y++) - { - unsigned int iferror; - - iferror= (*callback[y])(ptr, instance, context); - - if (iferror) - continue; - } - } - - return MEMCACHED_SUCCESS; -} - -memcached_return_t memcached_server_execute(memcached_st *ptr, - memcached_server_execute_fn callback, - void *context) -{ - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - unsigned int iferror; - - iferror= (*callback)(ptr, instance, context); - - if (iferror) - continue; - } - - return MEMCACHED_SUCCESS; -} - -memcached_server_instance_st memcached_server_by_key(const memcached_st *ptr, - const char *key, - size_t key_length, - memcached_return_t *error) -{ - uint32_t server_key; - memcached_server_instance_st instance; - - memcached_return_t rc; - if ((rc= initialize_const_query(ptr)) != MEMCACHED_SUCCESS) - { - if (error) - *error= rc; - - return NULL; - } - - if ((rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)) != MEMCACHED_SUCCESS) - { - if (error) - *error= rc; - - return NULL; - } - - if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)) - { - *error= MEMCACHED_BAD_KEY_PROVIDED; - return NULL; - } - - server_key= memcached_generate_hash(ptr, key, key_length); - instance= memcached_server_instance_by_position(ptr, server_key); - - return instance; - -} - -void memcached_server_error_reset(memcached_server_st *self) -{ - WATCHPOINT_ASSERT(self); - if (! self) - return; - - self->cached_server_error[0]= 0; -} - -memcached_server_instance_st memcached_server_get_last_disconnect(const memcached_st *self) -{ - WATCHPOINT_ASSERT(self); - if (! self) - return 0; - - return self->last_disconnected_server; -} - -void memcached_server_list_free(memcached_server_list_st self) -{ - if (self == NULL) - return; - - for (uint32_t x= 0; x < memcached_server_list_count(self); x++) - { - if (self[x].address_info) - { - freeaddrinfo(self[x].address_info); - self[x].address_info= NULL; - } - } - - const memcached_st *root= self->root; - if (root) - { - libmemcached_free(root, self); - } - else - { - free(self); - } -} - -uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count) -{ - WATCHPOINT_ASSERT(servers); - if (! servers) - return 0; - - return servers->number_of_hosts= count; -} - -uint32_t memcached_server_count(const memcached_st *self) -{ - WATCHPOINT_ASSERT(self); - if (! self) - return 0; - - return self->number_of_hosts; -} - -const char *memcached_server_name(memcached_server_instance_st self) -{ - WATCHPOINT_ASSERT(self); - if (! self) - return NULL; - - return self->hostname; -} - -in_port_t memcached_server_port(memcached_server_instance_st self) -{ - WATCHPOINT_ASSERT(self); - if (! self) - return 0; - - return self->port; -} - -uint32_t memcached_server_response_count(memcached_server_instance_st self) -{ - WATCHPOINT_ASSERT(self); - if (! self) - return 0; - - return self->cursor_active; -} - -const char *memcached_server_error(memcached_server_instance_st ptr) -{ - return ptr - ? ptr->cached_server_error - : NULL; -} - diff --git a/libmemcached/server.cc b/libmemcached/server.cc new file mode 100644 index 00000000..1eb50ee4 --- /dev/null +++ b/libmemcached/server.cc @@ -0,0 +1,342 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: String structure used for libmemcached. + * + */ + +/* + This is a partial implementation for fetching/creating memcached_server_st objects. +*/ +#include + +static inline void _server_init(memcached_server_st *self, const memcached_st *root, + const char *hostname, in_port_t port, + uint32_t weight, memcached_connection_t type) +{ + self->options.is_shutting_down= false; + self->options.is_dead= false; + self->number_of_hosts= 0; + self->cursor_active= 0; + self->port= port; + self->cached_errno= 0; + self->fd= -1; + self->io_bytes_sent= 0; + self->server_failure_counter= 0; + self->weight= weight ? weight : 1; // 1 is the default weight value + WATCHPOINT_SET(self->io_wait_count.read= 0); + WATCHPOINT_SET(self->io_wait_count.write= 0); + self->major_version= UINT8_MAX; + self->micro_version= UINT8_MAX; + self->minor_version= UINT8_MAX; + self->type= type; + self->read_ptr= self->read_buffer; + self->cached_server_error= NULL; + self->read_buffer_length= 0; + self->read_data_length= 0; + self->write_buffer_offset= 0; + self->address_info= NULL; + self->address_info_next= NULL; + + if (root) + { + self->next_retry= root->retry_timeout; + } + else + { + self->next_retry= 0; + } + + if (self->weight > 1 && root) + { + ((memcached_st *)root)->ketama.weighted= true; + } + + self->root= root; + self->limit_maxbytes= 0; + if (hostname == NULL) + { + self->hostname[0]= 0; + } + else + { + strncpy(self->hostname, hostname, NI_MAXHOST - 1); + } +} + +static memcached_server_st *_server_create(memcached_server_st *self, const memcached_st *memc) +{ + if (self == NULL) + { + self= (memcached_server_st *)libmemcached_malloc(memc, sizeof(memcached_server_st)); + + if (! self) + return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */ + + self->options.is_allocated= true; + } + else + { + self->options.is_allocated= false; + } + + self->options.is_initialized= true; + + return self; +} + +memcached_server_st *memcached_server_create_with(const memcached_st *memc, + memcached_server_write_instance_st self, + const char *hostname, in_port_t port, + uint32_t weight, memcached_connection_t type) +{ + self= _server_create(self, memc); + + if (self == NULL) + return NULL; + + _server_init(self, memc, hostname, port, weight, type); + + + if (type == MEMCACHED_CONNECTION_UDP) + { + self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH; + memcached_io_init_udp_header(self, 0); + } + + return self; +} + +void memcached_server_free(memcached_server_st *self) +{ + memcached_quit_server(self, false); + + if (self->cached_server_error) + free(self->cached_server_error); + + if (self->address_info) + freeaddrinfo(self->address_info); + + if (memcached_is_allocated(self)) + { + if (self->root) + { + libmemcached_free(self->root, self); + } + else + { + free(self); + } + } + else + { + self->options.is_initialized= false; + } +} + +/* + If we do not have a valid object to clone from, we toss an error. +*/ +memcached_server_st *memcached_server_clone(memcached_server_st *destination, + const memcached_server_st *source) +{ + /* We just do a normal create if source is missing */ + if (source == NULL) + return NULL; + + destination= memcached_server_create_with(source->root, destination, + source->hostname, source->port, source->weight, + source->type); + if (destination != NULL) + { + destination->cached_errno= source->cached_errno; + + if (source->cached_server_error) + destination->cached_server_error= strdup(source->cached_server_error); + } + + return destination; + +} + +memcached_return_t memcached_server_cursor(const memcached_st *ptr, + const memcached_server_fn *callback, + void *context, + uint32_t number_of_callbacks) +{ + memcached_return_t rc; + if ((rc= initialize_const_query(ptr)) != MEMCACHED_SUCCESS) + { + return rc; + } + + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_server_instance_st instance= + memcached_server_instance_by_position(ptr, x); + + for (uint32_t y= 0; y < number_of_callbacks; y++) + { + unsigned int iferror; + + iferror= (*callback[y])(ptr, instance, context); + + if (iferror) + continue; + } + } + + return MEMCACHED_SUCCESS; +} + +memcached_return_t memcached_server_execute(memcached_st *ptr, + memcached_server_execute_fn callback, + void *context) +{ + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + unsigned int iferror; + + iferror= (*callback)(ptr, instance, context); + + if (iferror) + continue; + } + + return MEMCACHED_SUCCESS; +} + +memcached_server_instance_st memcached_server_by_key(const memcached_st *ptr, + const char *key, + size_t key_length, + memcached_return_t *error) +{ + memcached_return_t rc; + if (memcached_failed(rc= initialize_const_query(ptr))) + { + if (error) + *error= rc; + + return NULL; + } + + if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + { + if (error) + *error= rc; + + return NULL; + } + + if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)) + { + if (error) + *error= MEMCACHED_BAD_KEY_PROVIDED; + return NULL; + } + + uint32_t server_key= memcached_generate_hash(ptr, key, key_length); + return memcached_server_instance_by_position(ptr, server_key); + +} + +void memcached_server_error_reset(memcached_server_st *self) +{ + WATCHPOINT_ASSERT(self); + if (not self) + return; + + self->cached_server_error[0]= 0; +} + +memcached_server_instance_st memcached_server_get_last_disconnect(const memcached_st *self) +{ + WATCHPOINT_ASSERT(self); + if (not self) + return 0; + + return self->last_disconnected_server; +} + +void memcached_server_list_free(memcached_server_list_st self) +{ + if (not self) + return; + + for (uint32_t x= 0; x < memcached_server_list_count(self); x++) + { + if (self[x].address_info) + { + freeaddrinfo(self[x].address_info); + self[x].address_info= NULL; + } + } + + const memcached_st *root= self->root; + if (root) + { + libmemcached_free(root, self); + } + else + { + free(self); + } +} + +uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count) +{ + WATCHPOINT_ASSERT(servers); + if (not servers) + return 0; + + return servers->number_of_hosts= count; +} + +uint32_t memcached_server_count(const memcached_st *self) +{ + WATCHPOINT_ASSERT(self); + if (not self) + return 0; + + return self->number_of_hosts; +} + +const char *memcached_server_name(memcached_server_instance_st self) +{ + WATCHPOINT_ASSERT(self); + if (not self) + return NULL; + + return self->hostname; +} + +in_port_t memcached_server_port(memcached_server_instance_st self) +{ + WATCHPOINT_ASSERT(self); + if (not self) + return 0; + + return self->port; +} + +uint32_t memcached_server_response_count(memcached_server_instance_st self) +{ + WATCHPOINT_ASSERT(self); + if (not self) + return 0; + + return self->cursor_active; +} + +const char *memcached_server_error(memcached_server_instance_st ptr) +{ + return ptr ? ptr->cached_server_error : NULL; +} + diff --git a/libmemcached/server_list.c b/libmemcached/server_list.c deleted file mode 100644 index ca37f7f9..00000000 --- a/libmemcached/server_list.c +++ /dev/null @@ -1,83 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2010 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: - * - */ - - -#include "common.h" - -memcached_server_list_st -memcached_server_list_append_with_weight(memcached_server_list_st ptr, - const char *hostname, in_port_t port, - uint32_t weight, - memcached_return_t *error) -{ - uint32_t count; - memcached_server_list_st new_host_list; - - if (hostname == NULL || error == NULL) - return NULL; - - if (hostname[0] == '/') - port = 0; - else if (! port) - port= MEMCACHED_DEFAULT_PORT; - - /* Increment count for hosts */ - count= 1; - if (ptr != NULL) - { - count+= memcached_server_list_count(ptr); - } - - new_host_list= (memcached_server_write_instance_st)realloc(ptr, sizeof(memcached_server_st) * count); - if (!new_host_list) - { - ptr->cached_errno= errno; - *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE; - return NULL; - } - - /* @todo Check return type */ - memcached_server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET); - - // Handset allocated since - new_host_list->options.is_allocated= true; - - /* Backwards compatibility hack */ - memcached_servers_set_count(new_host_list, count); - - *error= MEMCACHED_SUCCESS; - return new_host_list; -} - -memcached_server_list_st -memcached_server_list_append(memcached_server_list_st ptr, - const char *hostname, in_port_t port, - memcached_return_t *error) -{ - return memcached_server_list_append_with_weight(ptr, hostname, port, 0, error); -} - -uint32_t memcached_server_list_count(const memcached_server_list_st self) -{ - return (self == NULL) - ? 0 - : self->number_of_hosts; -} - -memcached_server_st *memcached_server_list(const memcached_st *self) -{ - return self->servers; -} - -void memcached_server_list_set(memcached_st *self, memcached_server_st *list) -{ - self->servers= list; -} diff --git a/libmemcached/server_list.cc b/libmemcached/server_list.cc new file mode 100644 index 00000000..ca37f7f9 --- /dev/null +++ b/libmemcached/server_list.cc @@ -0,0 +1,83 @@ +/* LibMemcached + * Copyright (C) 2006-2010 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ + + +#include "common.h" + +memcached_server_list_st +memcached_server_list_append_with_weight(memcached_server_list_st ptr, + const char *hostname, in_port_t port, + uint32_t weight, + memcached_return_t *error) +{ + uint32_t count; + memcached_server_list_st new_host_list; + + if (hostname == NULL || error == NULL) + return NULL; + + if (hostname[0] == '/') + port = 0; + else if (! port) + port= MEMCACHED_DEFAULT_PORT; + + /* Increment count for hosts */ + count= 1; + if (ptr != NULL) + { + count+= memcached_server_list_count(ptr); + } + + new_host_list= (memcached_server_write_instance_st)realloc(ptr, sizeof(memcached_server_st) * count); + if (!new_host_list) + { + ptr->cached_errno= errno; + *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE; + return NULL; + } + + /* @todo Check return type */ + memcached_server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET); + + // Handset allocated since + new_host_list->options.is_allocated= true; + + /* Backwards compatibility hack */ + memcached_servers_set_count(new_host_list, count); + + *error= MEMCACHED_SUCCESS; + return new_host_list; +} + +memcached_server_list_st +memcached_server_list_append(memcached_server_list_st ptr, + const char *hostname, in_port_t port, + memcached_return_t *error) +{ + return memcached_server_list_append_with_weight(ptr, hostname, port, 0, error); +} + +uint32_t memcached_server_list_count(const memcached_server_list_st self) +{ + return (self == NULL) + ? 0 + : self->number_of_hosts; +} + +memcached_server_st *memcached_server_list(const memcached_st *self) +{ + return self->servers; +} + +void memcached_server_list_set(memcached_st *self, memcached_server_st *list) +{ + self->servers= list; +} diff --git a/libmemcached/stats.c b/libmemcached/stats.c deleted file mode 100644 index 45b530e4..00000000 --- a/libmemcached/stats.c +++ /dev/null @@ -1,582 +0,0 @@ -/* -*/ - -#include "common.h" - -static const char *memcached_stat_keys[] = { - "pid", - "uptime", - "time", - "version", - "pointer_size", - "rusage_user", - "rusage_system", - "curr_items", - "total_items", - "bytes", - "curr_connections", - "total_connections", - "connection_structures", - "cmd_get", - "cmd_set", - "get_hits", - "get_misses", - "evictions", - "bytes_read", - "bytes_written", - "limit_maxbytes", - "threads", - NULL -}; - -struct local_context -{ - memcached_stat_fn func; - void *context; - const char *args; -}; - - -static memcached_return_t set_data(memcached_stat_st *memc_stat, char *key, char *value) -{ - - if (strlen(key) < 1) - { - WATCHPOINT_STRING(key); - return MEMCACHED_UNKNOWN_STAT_KEY; - } - else if (!strcmp("pid", key)) - { - memc_stat->pid= (uint32_t) strtol(value, (char **)NULL, 10); - } - else if (!strcmp("uptime", key)) - { - memc_stat->uptime= (uint32_t) strtol(value, (char **)NULL, 10); - } - else if (!strcmp("time", key)) - { - memc_stat->time= (uint32_t) strtol(value, (char **)NULL, 10); - } - else if (!strcmp("version", key)) - { - memcpy(memc_stat->version, value, strlen(value)); - memc_stat->version[strlen(value)]= 0; - } - else if (!strcmp("pointer_size", key)) - { - memc_stat->pointer_size= (uint32_t) strtol(value, (char **)NULL, 10); - } - else if (!strcmp("rusage_user", key)) - { - char *walk_ptr; - for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++); - *walk_ptr= 0; - walk_ptr++; - memc_stat->rusage_user_seconds= (uint32_t) strtol(value, (char **)NULL, 10); - memc_stat->rusage_user_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10); - } - else if (!strcmp("rusage_system", key)) - { - char *walk_ptr; - for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++); - *walk_ptr= 0; - walk_ptr++; - memc_stat->rusage_system_seconds= (uint32_t) strtol(value, (char **)NULL, 10); - memc_stat->rusage_system_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10); - } - else if (!strcmp("curr_items", key)) - { - memc_stat->curr_items= (uint32_t) strtol(value, (char **)NULL, 10); - } - else if (!strcmp("total_items", key)) - { - memc_stat->total_items= (uint32_t) strtol(value, (char **)NULL, 10); - } - else if (!strcmp("bytes_read", key)) - { - memc_stat->bytes_read= (uint32_t) strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("bytes_written", key)) - { - memc_stat->bytes_written= (uint32_t) strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("bytes", key)) - { - memc_stat->bytes= (uint32_t) strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("curr_connections", key)) - { - memc_stat->curr_connections= (uint32_t) strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("total_connections", key)) - { - memc_stat->total_connections= (uint32_t) strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("connection_structures", key)) - { - memc_stat->connection_structures= (uint32_t) strtol(value, (char **)NULL, 10); - } - else if (!strcmp("cmd_get", key)) - { - memc_stat->cmd_get= (uint64_t) strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("cmd_set", key)) - { - memc_stat->cmd_set= (uint64_t) strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("get_hits", key)) - { - memc_stat->get_hits= (uint64_t) strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("get_misses", key)) - { - memc_stat->get_misses= (uint64_t)strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("evictions", key)) - { - memc_stat->evictions= (uint64_t)strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("limit_maxbytes", key)) - { - memc_stat->limit_maxbytes= (uint64_t) strtoll(value, (char **)NULL, 10); - } - else if (!strcmp("threads", key)) - { - memc_stat->threads= (uint32_t) strtol(value, (char **)NULL, 10); - } - else if (!(strcmp("delete_misses", key) == 0 ||/* New stats in the 1.3 beta */ - strcmp("delete_hits", key) == 0 ||/* Just swallow them for now.. */ - strcmp("incr_misses", key) == 0 || - strcmp("incr_hits", key) == 0 || - strcmp("decr_misses", key) == 0 || - strcmp("decr_hits", key) == 0 || - strcmp("cas_misses", key) == 0 || - strcmp("cas_hits", key) == 0 || - strcmp("cas_badval", key) == 0 || - strcmp("cmd_flush", key) == 0 || - strcmp("accepting_conns", key) == 0 || - strcmp("listen_disabled_num", key) == 0 || - strcmp("conn_yields", key) == 0 || - strcmp("auth_cmds", key) == 0 || - strcmp("auth_errors", key) == 0 || - strcmp("reclaimed", key) == 0)) - { - WATCHPOINT_STRING(key); - /* return MEMCACHED_UNKNOWN_STAT_KEY; */ - return MEMCACHED_SUCCESS; - } - - return MEMCACHED_SUCCESS; -} - -char *memcached_stat_get_value(const memcached_st *ptr, memcached_stat_st *memc_stat, - const char *key, memcached_return_t *error) -{ - char buffer[SMALL_STRING_LEN]; - int length; - char *ret; - - *error= MEMCACHED_SUCCESS; - - if (!memcmp("pid", key, sizeof("pid") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pid); - else if (!memcmp("uptime", key, sizeof("uptime") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->uptime); - else if (!memcmp("time", key, sizeof("time") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time); - else if (!memcmp("version", key, sizeof("version") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version); - else if (!memcmp("pointer_size", key, sizeof("pointer_size") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pointer_size); - else if (!memcmp("rusage_user", key, sizeof("rusage_user") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds); - else if (!memcmp("rusage_system", key, sizeof("rusage_system") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds); - else if (!memcmp("curr_items", key, sizeof("curr_items") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_items); - else if (!memcmp("total_items", key, sizeof("total_items") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_items); - else if (!memcmp("curr_connections", key, sizeof("curr_connections") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_connections); - else if (!memcmp("total_connections", key, sizeof("total_connections") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_connections); - else if (!memcmp("connection_structures", key, sizeof("connection_structures") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->connection_structures); - else if (!memcmp("cmd_get", key, sizeof("cmd_get") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get); - else if (!memcmp("cmd_set", key, sizeof("cmd_set") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set); - else if (!memcmp("get_hits", key, sizeof("get_hits") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits); - else if (!memcmp("get_misses", key, sizeof("get_misses") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses); - else if (!memcmp("evictions", key, sizeof("evictions") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions); - else if (!memcmp("bytes_read", key, sizeof("bytes_read") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read); - else if (!memcmp("bytes_written", key, sizeof("bytes_written") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written); - else if (!memcmp("bytes", key, sizeof("bytes") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes); - else if (!memcmp("limit_maxbytes", key, sizeof("limit_maxbytes") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes); - else if (! memcmp("threads", key, sizeof("threads") -1)) - length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->threads); - else - { - *error= MEMCACHED_NOTFOUND; - return NULL; - } - - if (length >= SMALL_STRING_LEN || length < 0) - { - *error= MEMCACHED_FAILURE; - return NULL; - } - - ret= libmemcached_malloc(ptr, (size_t) (length + 1)); - memcpy(ret, buffer, (size_t) length); - ret[length]= '\0'; - - return ret; -} - -static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, - const char *args, - memcached_server_write_instance_st instance, - struct local_context *check) -{ - memcached_return_t rc; - - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - protocol_binary_request_stats request= {.bytes= {0}}; - request.message.header.request.magic= PROTOCOL_BINARY_REQ; - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT; - request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - - if (args != NULL) - { - size_t len= strlen(args); - - rc= memcached_validate_key_length(len, true); - unlikely (rc != MEMCACHED_SUCCESS) - return rc; - - request.message.header.request.keylen= htons((uint16_t)len); - request.message.header.request.bodylen= htonl((uint32_t) len); - - struct libmemcached_io_vector_st vector[]= - { - { .length= sizeof(request.bytes), .buffer= request.bytes }, - { .length= len, .buffer= args } - }; - - if (memcached_vdo(instance, vector, 2, true) != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - return MEMCACHED_WRITE_FAILURE; - } - } - else - { - if (memcached_do(instance, request.bytes, - sizeof(request.bytes), true) != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - return MEMCACHED_WRITE_FAILURE; - } - } - - memcached_server_response_decrement(instance); - do - { - rc= memcached_response(instance, buffer, sizeof(buffer), NULL); - - if (rc == MEMCACHED_END) - break; - - unlikely (rc != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - return rc; - } - - if (memc_stat) - { - unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY) - { - WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); - WATCHPOINT_ASSERT(0); - } - } - - if (check && check->func) - { - size_t key_length= strlen(buffer); - - check->func(instance, - buffer, key_length, - buffer+key_length+1, strlen(buffer+key_length+1), - check->context); - } - } while (1); - - /* shit... memcached_response will decrement the counter, so I need to - ** reset it.. todo: look at this and try to find a better solution. - */ - instance->cursor_active= 0; - - return MEMCACHED_SUCCESS; -} - -static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat, - const char *args, - memcached_server_write_instance_st instance, - struct local_context *check) -{ - memcached_return_t rc; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - int send_length; - - if (args) - send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "stats %s\r\n", args); - else - send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "stats\r\n"); - - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) - return MEMCACHED_WRITE_FAILURE; - - rc= memcached_do(instance, buffer, (size_t)send_length, true); - if (rc != MEMCACHED_SUCCESS) - goto error; - - while (1) - { - rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - - if (rc == MEMCACHED_STAT) - { - char *string_ptr, *end_ptr; - char *key, *value; - - string_ptr= buffer; - string_ptr+= 5; /* Move past STAT */ - for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++); - key= string_ptr; - key[(size_t)(end_ptr-string_ptr)]= 0; - - string_ptr= end_ptr + 1; - for (end_ptr= string_ptr; !(isspace(*end_ptr)); end_ptr++); - value= string_ptr; - value[(size_t)(end_ptr-string_ptr)]= 0; - string_ptr= end_ptr + 2; - if (memc_stat) - { - unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY) - { - WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); - WATCHPOINT_ASSERT(0); - } - } - - if (check && check->func) - { - check->func(instance, - key, strlen(key), - value, strlen(value), - check->context); - } - } - else - break; - } - -error: - if (rc == MEMCACHED_END) - return MEMCACHED_SUCCESS; - else - return rc; -} - -memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_return_t *error) -{ - memcached_return_t rc; - memcached_stat_st *stats; - - if ((rc= initialize_query(self)) != MEMCACHED_SUCCESS) - { - if (error) - *error= rc; - - return NULL; - } - - WATCHPOINT_ASSERT(error); - - unlikely (self->flags.use_udp) - { - if (error) - *error= MEMCACHED_NOT_SUPPORTED; - - return NULL; - } - - stats= libmemcached_calloc(self, memcached_server_count(self), sizeof(memcached_stat_st)); - - if (! stats) - { - if (error) - *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE; - - return NULL; - } - - WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS); - rc= MEMCACHED_SUCCESS; - for (uint32_t x= 0; x < memcached_server_count(self); x++) - { - memcached_return_t temp_return; - memcached_server_write_instance_st instance; - memcached_stat_st *stat_instance; - - stat_instance= stats + x; - - stat_instance->root= self; - - instance= memcached_server_instance_fetch(self, x); - - if (self->flags.binary_protocol) - { - temp_return= binary_stats_fetch(stat_instance, args, instance, NULL); - } - else - { - temp_return= ascii_stats_fetch(stat_instance, args, instance, NULL); - } - - if (temp_return != MEMCACHED_SUCCESS) - rc= MEMCACHED_SOME_ERRORS; - } - - if (error) - *error= rc; - - return stats; -} - -memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args, - const char *hostname, in_port_t port) -{ - memcached_st memc; - memcached_st *memc_ptr; - memcached_server_write_instance_st instance; - - memset(memc_stat, 0, sizeof(memcached_stat_st)); - - memc_ptr= memcached_create(&memc); - if (! memc_ptr) - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - - memcached_server_add(&memc, hostname, port); - - memcached_return_t rc; - if ((rc= initialize_query(memc_ptr)) != MEMCACHED_SUCCESS) - { - return rc; - } - - instance= memcached_server_instance_fetch(memc_ptr, 0); - - if (memc.flags.binary_protocol) - { - rc= binary_stats_fetch(memc_stat, args, instance, NULL); - } - else - { - rc= ascii_stats_fetch(memc_stat, args, instance, NULL); - } - - memcached_free(&memc); - - return rc; -} - -/* - We make a copy of the keys since at some point in the not so distant future - we will add support for "found" keys. -*/ -char ** memcached_stat_get_keys(const memcached_st *ptr, - memcached_stat_st *memc_stat, - memcached_return_t *error) -{ - char **list; - size_t length= sizeof(memcached_stat_keys); - - (void)memc_stat; - - list= libmemcached_malloc(ptr, length); - - if (! list) - { - *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE; - return NULL; - } - - memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys)); - - *error= MEMCACHED_SUCCESS; - - return list; -} - -void memcached_stat_free(const memcached_st *ptr, memcached_stat_st *memc_stat) -{ - if (memc_stat == NULL) - { - WATCHPOINT_ASSERT(0); /* Be polite, but when debugging catch this as an error */ - return; - } - - if (memc_stat->root) - { - libmemcached_free(memc_stat->root, memc_stat); - } - else if (ptr) - { - libmemcached_free(ptr, memc_stat); - } - else - { - free(memc_stat); - } -} - -static memcached_return_t call_stat_fn(memcached_st *ptr, - memcached_server_write_instance_st instance, - void *context) -{ - memcached_return_t rc; - struct local_context *check= (struct local_context *)context; - - if (ptr->flags.binary_protocol) - { - rc= binary_stats_fetch(NULL, check->args, instance, check); - } - else - { - rc= ascii_stats_fetch(NULL, check->args, instance, check); - } - - return rc; -} - -memcached_return_t memcached_stat_execute(memcached_st *memc, const char *args, memcached_stat_fn func, void *context) -{ - memcached_version(memc); - - struct local_context check= { .func= func, .context= context, .args= args }; - - return memcached_server_execute(memc, call_stat_fn, (void *)&check); -} diff --git a/libmemcached/stats.cc b/libmemcached/stats.cc new file mode 100644 index 00000000..08934ba6 --- /dev/null +++ b/libmemcached/stats.cc @@ -0,0 +1,590 @@ +/* +*/ + +#include "common.h" + +static const char *memcached_stat_keys[] = { + "pid", + "uptime", + "time", + "version", + "pointer_size", + "rusage_user", + "rusage_system", + "curr_items", + "total_items", + "bytes", + "curr_connections", + "total_connections", + "connection_structures", + "cmd_get", + "cmd_set", + "get_hits", + "get_misses", + "evictions", + "bytes_read", + "bytes_written", + "limit_maxbytes", + "threads", + NULL +}; + +struct local_context +{ + memcached_stat_fn func; + void *context; + const char *args; + + local_context(memcached_stat_fn func_arg, + void *context_arg, + const char *args_arg) : + func(func_arg), + context(context_arg), + args(args_arg) + { } +}; + + +static memcached_return_t set_data(memcached_stat_st *memc_stat, char *key, char *value) +{ + + if (strlen(key) < 1) + { + WATCHPOINT_STRING(key); + return MEMCACHED_UNKNOWN_STAT_KEY; + } + else if (!strcmp("pid", key)) + { + memc_stat->pid= (uint32_t) strtol(value, (char **)NULL, 10); + } + else if (!strcmp("uptime", key)) + { + memc_stat->uptime= (uint32_t) strtol(value, (char **)NULL, 10); + } + else if (!strcmp("time", key)) + { + memc_stat->time= (uint32_t) strtol(value, (char **)NULL, 10); + } + else if (!strcmp("version", key)) + { + memcpy(memc_stat->version, value, strlen(value)); + memc_stat->version[strlen(value)]= 0; + } + else if (!strcmp("pointer_size", key)) + { + memc_stat->pointer_size= (uint32_t) strtol(value, (char **)NULL, 10); + } + else if (!strcmp("rusage_user", key)) + { + char *walk_ptr; + for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++); + *walk_ptr= 0; + walk_ptr++; + memc_stat->rusage_user_seconds= (uint32_t) strtol(value, (char **)NULL, 10); + memc_stat->rusage_user_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10); + } + else if (!strcmp("rusage_system", key)) + { + char *walk_ptr; + for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++); + *walk_ptr= 0; + walk_ptr++; + memc_stat->rusage_system_seconds= (uint32_t) strtol(value, (char **)NULL, 10); + memc_stat->rusage_system_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10); + } + else if (!strcmp("curr_items", key)) + { + memc_stat->curr_items= (uint32_t) strtol(value, (char **)NULL, 10); + } + else if (!strcmp("total_items", key)) + { + memc_stat->total_items= (uint32_t) strtol(value, (char **)NULL, 10); + } + else if (!strcmp("bytes_read", key)) + { + memc_stat->bytes_read= (uint32_t) strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("bytes_written", key)) + { + memc_stat->bytes_written= (uint32_t) strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("bytes", key)) + { + memc_stat->bytes= (uint32_t) strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("curr_connections", key)) + { + memc_stat->curr_connections= (uint32_t) strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("total_connections", key)) + { + memc_stat->total_connections= (uint32_t) strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("connection_structures", key)) + { + memc_stat->connection_structures= (uint32_t) strtol(value, (char **)NULL, 10); + } + else if (!strcmp("cmd_get", key)) + { + memc_stat->cmd_get= (uint64_t) strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("cmd_set", key)) + { + memc_stat->cmd_set= (uint64_t) strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("get_hits", key)) + { + memc_stat->get_hits= (uint64_t) strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("get_misses", key)) + { + memc_stat->get_misses= (uint64_t)strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("evictions", key)) + { + memc_stat->evictions= (uint64_t)strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("limit_maxbytes", key)) + { + memc_stat->limit_maxbytes= (uint64_t) strtoll(value, (char **)NULL, 10); + } + else if (!strcmp("threads", key)) + { + memc_stat->threads= (uint32_t) strtol(value, (char **)NULL, 10); + } + else if (!(strcmp("delete_misses", key) == 0 ||/* New stats in the 1.3 beta */ + strcmp("delete_hits", key) == 0 ||/* Just swallow them for now.. */ + strcmp("incr_misses", key) == 0 || + strcmp("incr_hits", key) == 0 || + strcmp("decr_misses", key) == 0 || + strcmp("decr_hits", key) == 0 || + strcmp("cas_misses", key) == 0 || + strcmp("cas_hits", key) == 0 || + strcmp("cas_badval", key) == 0 || + strcmp("cmd_flush", key) == 0 || + strcmp("accepting_conns", key) == 0 || + strcmp("listen_disabled_num", key) == 0 || + strcmp("conn_yields", key) == 0 || + strcmp("auth_cmds", key) == 0 || + strcmp("auth_errors", key) == 0 || + strcmp("reclaimed", key) == 0)) + { + WATCHPOINT_STRING(key); + /* return MEMCACHED_UNKNOWN_STAT_KEY; */ + return MEMCACHED_SUCCESS; + } + + return MEMCACHED_SUCCESS; +} + +char *memcached_stat_get_value(const memcached_st *ptr, memcached_stat_st *memc_stat, + const char *key, memcached_return_t *error) +{ + char buffer[SMALL_STRING_LEN]; + int length; + char *ret; + + *error= MEMCACHED_SUCCESS; + + if (!memcmp("pid", key, sizeof("pid") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pid); + else if (!memcmp("uptime", key, sizeof("uptime") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->uptime); + else if (!memcmp("time", key, sizeof("time") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time); + else if (!memcmp("version", key, sizeof("version") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version); + else if (!memcmp("pointer_size", key, sizeof("pointer_size") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pointer_size); + else if (!memcmp("rusage_user", key, sizeof("rusage_user") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds); + else if (!memcmp("rusage_system", key, sizeof("rusage_system") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds); + else if (!memcmp("curr_items", key, sizeof("curr_items") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_items); + else if (!memcmp("total_items", key, sizeof("total_items") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_items); + else if (!memcmp("curr_connections", key, sizeof("curr_connections") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_connections); + else if (!memcmp("total_connections", key, sizeof("total_connections") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_connections); + else if (!memcmp("connection_structures", key, sizeof("connection_structures") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->connection_structures); + else if (!memcmp("cmd_get", key, sizeof("cmd_get") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get); + else if (!memcmp("cmd_set", key, sizeof("cmd_set") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set); + else if (!memcmp("get_hits", key, sizeof("get_hits") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits); + else if (!memcmp("get_misses", key, sizeof("get_misses") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses); + else if (!memcmp("evictions", key, sizeof("evictions") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions); + else if (!memcmp("bytes_read", key, sizeof("bytes_read") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read); + else if (!memcmp("bytes_written", key, sizeof("bytes_written") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written); + else if (!memcmp("bytes", key, sizeof("bytes") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes); + else if (!memcmp("limit_maxbytes", key, sizeof("limit_maxbytes") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes); + else if (! memcmp("threads", key, sizeof("threads") -1)) + length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->threads); + else + { + *error= MEMCACHED_NOTFOUND; + return NULL; + } + + if (length >= SMALL_STRING_LEN || length < 0) + { + *error= MEMCACHED_FAILURE; + return NULL; + } + + ret= static_cast(libmemcached_malloc(ptr, (size_t) (length + 1))); + memcpy(ret, buffer, (size_t) length); + ret[length]= '\0'; + + return ret; +} + +static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, + const char *args, + memcached_server_write_instance_st instance, + struct local_context *check) +{ + memcached_return_t rc; + + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + protocol_binary_request_stats request= {}; // = {.bytes= {0}}; + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT; + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + + if (args != NULL) + { + size_t len= strlen(args); + + rc= memcached_validate_key_length(len, true); + unlikely (rc != MEMCACHED_SUCCESS) + return rc; + + request.message.header.request.keylen= htons((uint16_t)len); + request.message.header.request.bodylen= htonl((uint32_t) len); + + struct libmemcached_io_vector_st vector[]= + { + { sizeof(request.bytes), request.bytes }, + { len, args } + }; + + if (memcached_vdo(instance, vector, 2, true) != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + return MEMCACHED_WRITE_FAILURE; + } + } + else + { + if (memcached_do(instance, request.bytes, + sizeof(request.bytes), true) != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + return MEMCACHED_WRITE_FAILURE; + } + } + + memcached_server_response_decrement(instance); + do + { + rc= memcached_response(instance, buffer, sizeof(buffer), NULL); + + if (rc == MEMCACHED_END) + break; + + unlikely (rc != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + return rc; + } + + if (memc_stat) + { + unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY) + { + WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); + WATCHPOINT_ASSERT(0); + } + } + + if (check && check->func) + { + size_t key_length= strlen(buffer); + + check->func(instance, + buffer, key_length, + buffer+key_length+1, strlen(buffer+key_length+1), + check->context); + } + } while (1); + + /* shit... memcached_response will decrement the counter, so I need to + ** reset it.. todo: look at this and try to find a better solution. + */ + instance->cursor_active= 0; + + return MEMCACHED_SUCCESS; +} + +static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat, + const char *args, + memcached_server_write_instance_st instance, + struct local_context *check) +{ + memcached_return_t rc; + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + int send_length; + + if (args) + send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "stats %s\r\n", args); + else + send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "stats\r\n"); + + if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + return MEMCACHED_WRITE_FAILURE; + + rc= memcached_do(instance, buffer, (size_t)send_length, true); + if (rc != MEMCACHED_SUCCESS) + goto error; + + while (1) + { + rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + + if (rc == MEMCACHED_STAT) + { + char *string_ptr, *end_ptr; + char *key, *value; + + string_ptr= buffer; + string_ptr+= 5; /* Move past STAT */ + for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++); + key= string_ptr; + key[(size_t)(end_ptr-string_ptr)]= 0; + + string_ptr= end_ptr + 1; + for (end_ptr= string_ptr; !(isspace(*end_ptr)); end_ptr++); + value= string_ptr; + value[(size_t)(end_ptr-string_ptr)]= 0; + string_ptr= end_ptr + 2; + if (memc_stat) + { + unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY) + { + WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); + WATCHPOINT_ASSERT(0); + } + } + + if (check && check->func) + { + check->func(instance, + key, strlen(key), + value, strlen(value), + check->context); + } + } + else + break; + } + +error: + if (rc == MEMCACHED_END) + return MEMCACHED_SUCCESS; + else + return rc; +} + +memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_return_t *error) +{ + memcached_return_t rc; + memcached_stat_st *stats; + + if ((rc= initialize_query(self)) != MEMCACHED_SUCCESS) + { + if (error) + *error= rc; + + return NULL; + } + + WATCHPOINT_ASSERT(error); + + unlikely (self->flags.use_udp) + { + if (error) + *error= MEMCACHED_NOT_SUPPORTED; + + return NULL; + } + + stats= static_cast(libmemcached_calloc(self, memcached_server_count(self), sizeof(memcached_stat_st))); + + if (! stats) + { + if (error) + *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE; + + return NULL; + } + + WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS); + rc= MEMCACHED_SUCCESS; + for (uint32_t x= 0; x < memcached_server_count(self); x++) + { + memcached_return_t temp_return; + memcached_server_write_instance_st instance; + memcached_stat_st *stat_instance; + + stat_instance= stats + x; + + stat_instance->root= self; + + instance= memcached_server_instance_fetch(self, x); + + if (self->flags.binary_protocol) + { + temp_return= binary_stats_fetch(stat_instance, args, instance, NULL); + } + else + { + temp_return= ascii_stats_fetch(stat_instance, args, instance, NULL); + } + + if (temp_return != MEMCACHED_SUCCESS) + rc= MEMCACHED_SOME_ERRORS; + } + + if (error) + *error= rc; + + return stats; +} + +memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args, + const char *hostname, in_port_t port) +{ + memcached_st memc; + memcached_st *memc_ptr; + memcached_server_write_instance_st instance; + + memset(memc_stat, 0, sizeof(memcached_stat_st)); + + memc_ptr= memcached_create(&memc); + if (! memc_ptr) + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + + memcached_server_add(&memc, hostname, port); + + memcached_return_t rc; + if ((rc= initialize_query(memc_ptr)) != MEMCACHED_SUCCESS) + { + return rc; + } + + instance= memcached_server_instance_fetch(memc_ptr, 0); + + if (memc.flags.binary_protocol) + { + rc= binary_stats_fetch(memc_stat, args, instance, NULL); + } + else + { + rc= ascii_stats_fetch(memc_stat, args, instance, NULL); + } + + memcached_free(&memc); + + return rc; +} + +/* + We make a copy of the keys since at some point in the not so distant future + we will add support for "found" keys. +*/ +char ** memcached_stat_get_keys(const memcached_st *ptr, + memcached_stat_st *memc_stat, + memcached_return_t *error) +{ + char **list; + size_t length= sizeof(memcached_stat_keys); + + (void)memc_stat; + + list= static_cast(libmemcached_malloc(ptr, length)); + + if (not list) + { + *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE; + return NULL; + } + + memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys)); + + *error= MEMCACHED_SUCCESS; + + return list; +} + +void memcached_stat_free(const memcached_st *ptr, memcached_stat_st *memc_stat) +{ + if (memc_stat == NULL) + { + WATCHPOINT_ASSERT(0); /* Be polite, but when debugging catch this as an error */ + return; + } + + if (memc_stat->root) + { + libmemcached_free(memc_stat->root, memc_stat); + } + else if (ptr) + { + libmemcached_free(ptr, memc_stat); + } + else + { + free(memc_stat); + } +} + +static memcached_return_t call_stat_fn(memcached_st *ptr, + memcached_server_write_instance_st instance, + void *context) +{ + memcached_return_t rc; + struct local_context *check= (struct local_context *)context; + + if (ptr->flags.binary_protocol) + { + rc= binary_stats_fetch(NULL, check->args, instance, check); + } + else + { + rc= ascii_stats_fetch(NULL, check->args, instance, check); + } + + return rc; +} + +memcached_return_t memcached_stat_execute(memcached_st *memc, const char *args, memcached_stat_fn func, void *context) +{ + memcached_version(memc); + + struct local_context check(func, context, args); + + return memcached_server_execute(memc, call_stat_fn, (void *)&check); +} diff --git a/libmemcached/storage.c b/libmemcached/storage.c deleted file mode 100644 index 135def30..00000000 --- a/libmemcached/storage.c +++ /dev/null @@ -1,570 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: Storage related functions, aka set, replace,.. - * - */ - -#include "common.h" - -typedef enum { - SET_OP, - REPLACE_OP, - ADD_OP, - PREPEND_OP, - APPEND_OP, - CAS_OP, -} memcached_storage_action_t; - -/* Inline this */ -static inline const char *storage_op_string(memcached_storage_action_t verb) -{ - switch (verb) - { - case SET_OP: - return "set "; - case REPLACE_OP: - return "replace "; - case ADD_OP: - return "add "; - case PREPEND_OP: - return "prepend "; - case APPEND_OP: - return "append "; - case CAS_OP: - return "cas "; - default: - return "tosserror"; /* This is impossible, fixes issue for compiler warning in VisualStudio */ - } - - /* NOTREACHED */ -} - -static memcached_return_t memcached_send_binary(memcached_st *ptr, - memcached_server_write_instance_st server, - uint32_t server_key, - const char *key, - size_t key_length, - const char *value, - size_t value_length, - time_t expiration, - uint32_t flags, - uint64_t cas, - memcached_storage_action_t verb); - -static inline memcached_return_t memcached_send(memcached_st *ptr, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags, - uint64_t cas, - memcached_storage_action_t verb) -{ - bool to_write; - size_t write_length; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - uint32_t server_key; - memcached_server_write_instance_st instance; - - WATCHPOINT_ASSERT(!(value == NULL && value_length > 0)); - - memcached_return_t rc; - if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS) - { - return rc; - } - - rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol); - unlikely (rc != MEMCACHED_SUCCESS) - return rc; - - if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)) - return MEMCACHED_BAD_KEY_PROVIDED; - - server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); - instance= memcached_server_instance_fetch(ptr, server_key); - - WATCHPOINT_SET(instance->io_wait_count.read= 0); - WATCHPOINT_SET(instance->io_wait_count.write= 0); - - if (ptr->flags.binary_protocol) - { - rc= memcached_send_binary(ptr, instance, server_key, - key, key_length, - value, value_length, expiration, - flags, cas, verb); - WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read); - WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write); - } - else - { - - if (cas) - { - int check_length; - check_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "%s %.*s%.*s %u %llu %lu %llu%s\r\n", - storage_op_string(verb), - memcached_print_array(ptr->prefix_key), - (int)key_length, key, flags, - (unsigned long long)expiration, (unsigned long)value_length, - (unsigned long long)cas, - (ptr->flags.no_reply) ? " noreply" : ""); - if (check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || check_length < 0) - { - rc= MEMCACHED_WRITE_FAILURE; - memcached_io_reset(instance); - - return rc; - } - write_length= check_length; - } - else - { - char *buffer_ptr= buffer; - const char *command= storage_op_string(verb); - - /* Copy in the command, no space needed, we handle that in the command function*/ - memcpy(buffer_ptr, command, strlen(command)); - - /* Copy in the key prefix, switch to the buffer_ptr */ - buffer_ptr= memcpy((buffer_ptr + strlen(command)), memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key)); - - /* Copy in the key, adjust point if a key prefix was used. */ - buffer_ptr= memcpy(buffer_ptr + memcached_array_size(ptr->prefix_key), - key, key_length); - buffer_ptr+= key_length; - buffer_ptr[0]= ' '; - buffer_ptr++; - - write_length= (size_t)(buffer_ptr - buffer); - int check_length; - check_length= snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer), - "%u %llu %lu%s\r\n", - flags, - (unsigned long long)expiration, (unsigned long)value_length, - ptr->flags.no_reply ? " noreply" : ""); - if ((size_t)check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer) || check_length < 0) - { - rc= MEMCACHED_WRITE_FAILURE; - memcached_io_reset(instance); - - return rc; - } - - write_length+= (size_t)check_length; - WATCHPOINT_ASSERT(write_length < MEMCACHED_DEFAULT_COMMAND_SIZE); - } - - if (ptr->flags.use_udp && ptr->flags.buffer_requests) - { - size_t cmd_size= write_length + value_length + 2; - if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) - return MEMCACHED_WRITE_FAILURE; - if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) - memcached_io_write(instance, NULL, 0, true); - } - - if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE) - { - rc= MEMCACHED_WRITE_FAILURE; - } - else - { - struct libmemcached_io_vector_st vector[]= - { - { .length= write_length, .buffer= buffer }, - { .length= value_length, .buffer= value }, - { .length= 2, .buffer= "\r\n" } - }; - - if (ptr->flags.buffer_requests && verb == SET_OP) - { - to_write= false; - } - else - { - to_write= true; - } - - /* Send command header */ - rc= memcached_vdo(instance, vector, 3, to_write); - if (rc == MEMCACHED_SUCCESS) - { - - if (ptr->flags.no_reply) - { - rc= (to_write == false) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS; - } - else if (to_write == false) - { - rc= MEMCACHED_BUFFERED; - } - else - { - rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - - if (rc == MEMCACHED_STORED) - rc= MEMCACHED_SUCCESS; - } - } - } - - if (rc == MEMCACHED_WRITE_FAILURE) - memcached_io_reset(instance); - } - - WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read); - WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write); - - return rc; -} - - -memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - LIBMEMCACHED_MEMCACHED_SET_START(); - rc= memcached_send(ptr, key, key_length, - key, key_length, value, value_length, - expiration, flags, 0, SET_OP); - LIBMEMCACHED_MEMCACHED_SET_END(); - return rc; -} - -memcached_return_t memcached_add(memcached_st *ptr, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - LIBMEMCACHED_MEMCACHED_ADD_START(); - rc= memcached_send(ptr, key, key_length, - key, key_length, value, value_length, - expiration, flags, 0, ADD_OP); - LIBMEMCACHED_MEMCACHED_ADD_END(); - return rc; -} - -memcached_return_t memcached_replace(memcached_st *ptr, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - LIBMEMCACHED_MEMCACHED_REPLACE_START(); - rc= memcached_send(ptr, key, key_length, - key, key_length, value, value_length, - expiration, flags, 0, REPLACE_OP); - LIBMEMCACHED_MEMCACHED_REPLACE_END(); - return rc; -} - -memcached_return_t memcached_prepend(memcached_st *ptr, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - rc= memcached_send(ptr, key, key_length, - key, key_length, value, value_length, - expiration, flags, 0, PREPEND_OP); - return rc; -} - -memcached_return_t memcached_append(memcached_st *ptr, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - rc= memcached_send(ptr, key, key_length, - key, key_length, value, value_length, - expiration, flags, 0, APPEND_OP); - return rc; -} - -memcached_return_t memcached_cas(memcached_st *ptr, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags, - uint64_t cas) -{ - memcached_return_t rc; - rc= memcached_send(ptr, key, key_length, - key, key_length, value, value_length, - expiration, flags, cas, CAS_OP); - return rc; -} - -memcached_return_t memcached_set_by_key(memcached_st *ptr, - const char *group_key, - size_t group_key_length, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - LIBMEMCACHED_MEMCACHED_SET_START(); - rc= memcached_send(ptr, group_key, group_key_length, - key, key_length, value, value_length, - expiration, flags, 0, SET_OP); - LIBMEMCACHED_MEMCACHED_SET_END(); - return rc; -} - -memcached_return_t memcached_add_by_key(memcached_st *ptr, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - LIBMEMCACHED_MEMCACHED_ADD_START(); - rc= memcached_send(ptr, group_key, group_key_length, - key, key_length, value, value_length, - expiration, flags, 0, ADD_OP); - LIBMEMCACHED_MEMCACHED_ADD_END(); - return rc; -} - -memcached_return_t memcached_replace_by_key(memcached_st *ptr, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - LIBMEMCACHED_MEMCACHED_REPLACE_START(); - rc= memcached_send(ptr, group_key, group_key_length, - key, key_length, value, value_length, - expiration, flags, 0, REPLACE_OP); - LIBMEMCACHED_MEMCACHED_REPLACE_END(); - return rc; -} - -memcached_return_t memcached_prepend_by_key(memcached_st *ptr, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - rc= memcached_send(ptr, group_key, group_key_length, - key, key_length, value, value_length, - expiration, flags, 0, PREPEND_OP); - return rc; -} - -memcached_return_t memcached_append_by_key(memcached_st *ptr, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags) -{ - memcached_return_t rc; - rc= memcached_send(ptr, group_key, group_key_length, - key, key_length, value, value_length, - expiration, flags, 0, APPEND_OP); - return rc; -} - -memcached_return_t memcached_cas_by_key(memcached_st *ptr, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - const char *value, size_t value_length, - time_t expiration, - uint32_t flags, - uint64_t cas) -{ - memcached_return_t rc; - rc= memcached_send(ptr, group_key, group_key_length, - key, key_length, value, value_length, - expiration, flags, cas, CAS_OP); - return rc; -} - -static inline uint8_t get_com_code(memcached_storage_action_t verb, bool noreply) -{ - /* 0 isn't a value we want, but GCC 4.2 seems to think ret can otherwise - * be used uninitialized in this function. FAIL */ - uint8_t ret= 0; - - if (noreply) - switch (verb) - { - case SET_OP: - ret=PROTOCOL_BINARY_CMD_SETQ; - break; - case ADD_OP: - ret=PROTOCOL_BINARY_CMD_ADDQ; - break; - case CAS_OP: /* FALLTHROUGH */ - case REPLACE_OP: - ret=PROTOCOL_BINARY_CMD_REPLACEQ; - break; - case APPEND_OP: - ret=PROTOCOL_BINARY_CMD_APPENDQ; - break; - case PREPEND_OP: - ret=PROTOCOL_BINARY_CMD_PREPENDQ; - break; - default: - WATCHPOINT_ASSERT(verb); - break; - } - else - switch (verb) - { - case SET_OP: - ret=PROTOCOL_BINARY_CMD_SET; - break; - case ADD_OP: - ret=PROTOCOL_BINARY_CMD_ADD; - break; - case CAS_OP: /* FALLTHROUGH */ - case REPLACE_OP: - ret=PROTOCOL_BINARY_CMD_REPLACE; - break; - case APPEND_OP: - ret=PROTOCOL_BINARY_CMD_APPEND; - break; - case PREPEND_OP: - ret=PROTOCOL_BINARY_CMD_PREPEND; - break; - default: - WATCHPOINT_ASSERT(verb); - break; - } - - return ret; -} - - - -static memcached_return_t memcached_send_binary(memcached_st *ptr, - memcached_server_write_instance_st server, - uint32_t server_key, - const char *key, - size_t key_length, - const char *value, - size_t value_length, - time_t expiration, - uint32_t flags, - uint64_t cas, - memcached_storage_action_t verb) -{ - bool flush; - protocol_binary_request_set request= {.bytes= {0}}; - size_t send_length= sizeof(request.bytes); - - bool noreply= server->root->flags.no_reply; - - request.message.header.request.magic= PROTOCOL_BINARY_REQ; - request.message.header.request.opcode= get_com_code(verb, noreply); - request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key))); - request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - if (verb == APPEND_OP || verb == PREPEND_OP) - send_length -= 8; /* append & prepend does not contain extras! */ - else - { - request.message.header.request.extlen= 8; - request.message.body.flags= htonl(flags); - request.message.body.expiration= htonl((uint32_t)expiration); - } - - request.message.header.request.bodylen= htonl((uint32_t) (key_length + memcached_array_size(ptr->prefix_key) + value_length + - request.message.header.request.extlen)); - - if (cas) - request.message.header.request.cas= htonll(cas); - - flush= (bool) ((server->root->flags.buffer_requests && verb == SET_OP) ? 0 : 1); - - if (server->root->flags.use_udp && ! flush) - { - size_t cmd_size= send_length + key_length + value_length; - - if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) - { - return MEMCACHED_WRITE_FAILURE; - } - if (cmd_size + server->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) - { - memcached_io_write(server, NULL, 0, true); - } - } - - struct libmemcached_io_vector_st vector[]= - { - { .length= send_length, .buffer= request.bytes }, - { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) }, - { .length= key_length, .buffer= key }, - { .length= value_length, .buffer= value } - }; - - /* write the header */ - memcached_return_t rc; - if ((rc= memcached_vdo(server, vector, 4, flush)) != MEMCACHED_SUCCESS) - { - memcached_io_reset(server); - return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc; - } - - if (verb == SET_OP && ptr->number_of_replicas > 0) - { - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ; - WATCHPOINT_STRING("replicating"); - - for (uint32_t x= 0; x < ptr->number_of_replicas; x++) - { - memcached_server_write_instance_st instance; - - ++server_key; - if (server_key == memcached_server_count(ptr)) - server_key= 0; - - instance= memcached_server_instance_fetch(ptr, server_key); - - if (memcached_vdo(instance, vector, 4, false) != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - } - else - { - memcached_server_response_decrement(instance); - } - } - } - - if (flush == false) - { - return MEMCACHED_BUFFERED; - } - - if (noreply) - { - return MEMCACHED_SUCCESS; - } - - return memcached_response(server, NULL, 0, NULL); -} - diff --git a/libmemcached/storage.cc b/libmemcached/storage.cc new file mode 100644 index 00000000..006393c4 --- /dev/null +++ b/libmemcached/storage.cc @@ -0,0 +1,569 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: Storage related functions, aka set, replace,.. + * + */ + +#include + +enum memcached_storage_action_t { + SET_OP, + REPLACE_OP, + ADD_OP, + PREPEND_OP, + APPEND_OP, + CAS_OP +}; + +/* Inline this */ +static inline const char *storage_op_string(memcached_storage_action_t verb) +{ + switch (verb) + { + case SET_OP: + return "set "; + case REPLACE_OP: + return "replace "; + case ADD_OP: + return "add "; + case PREPEND_OP: + return "prepend "; + case APPEND_OP: + return "append "; + case CAS_OP: + return "cas "; + default: + return "tosserror"; /* This is impossible, fixes issue for compiler warning in VisualStudio */ + } + + /* NOTREACHED */ +} + +static memcached_return_t memcached_send_binary(memcached_st *ptr, + memcached_server_write_instance_st server, + uint32_t server_key, + const char *key, + size_t key_length, + const char *value, + size_t value_length, + time_t expiration, + uint32_t flags, + uint64_t cas, + memcached_storage_action_t verb); + +static inline memcached_return_t memcached_send(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags, + uint64_t cas, + memcached_storage_action_t verb) +{ + bool to_write; + size_t write_length; + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + uint32_t server_key; + memcached_server_write_instance_st instance; + + WATCHPOINT_ASSERT(!(value == NULL && value_length > 0)); + + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr))) + { + return rc; + } + + if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + return rc; + + if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)) + return MEMCACHED_BAD_KEY_PROVIDED; + + server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + instance= memcached_server_instance_fetch(ptr, server_key); + + WATCHPOINT_SET(instance->io_wait_count.read= 0); + WATCHPOINT_SET(instance->io_wait_count.write= 0); + + if (ptr->flags.binary_protocol) + { + rc= memcached_send_binary(ptr, instance, server_key, + key, key_length, + value, value_length, expiration, + flags, cas, verb); + WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read); + WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write); + } + else + { + + if (cas) + { + int check_length; + check_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "%s %.*s%.*s %u %llu %lu %llu%s\r\n", + storage_op_string(verb), + memcached_print_array(ptr->prefix_key), + (int)key_length, key, flags, + (unsigned long long)expiration, (unsigned long)value_length, + (unsigned long long)cas, + (ptr->flags.no_reply) ? " noreply" : ""); + if (check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || check_length < 0) + { + rc= MEMCACHED_WRITE_FAILURE; + memcached_io_reset(instance); + + return rc; + } + write_length= check_length; + } + else + { + char *buffer_ptr= buffer; + const char *command= storage_op_string(verb); + + /* Copy in the command, no space needed, we handle that in the command function*/ + memcpy(buffer_ptr, command, strlen(command)); + + /* Copy in the key prefix, switch to the buffer_ptr */ + buffer_ptr= (char *)memcpy((char *)(buffer_ptr + strlen(command)), (char *)memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key)); + + /* Copy in the key, adjust point if a key prefix was used. */ + buffer_ptr= (char *)memcpy(buffer_ptr + memcached_array_size(ptr->prefix_key), + key, key_length); + buffer_ptr+= key_length; + buffer_ptr[0]= ' '; + buffer_ptr++; + + write_length= (size_t)(buffer_ptr - buffer); + int check_length; + check_length= snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer), + "%u %llu %lu%s\r\n", + flags, + (unsigned long long)expiration, (unsigned long)value_length, + ptr->flags.no_reply ? " noreply" : ""); + if ((size_t)check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer) || check_length < 0) + { + rc= MEMCACHED_WRITE_FAILURE; + memcached_io_reset(instance); + + return rc; + } + + write_length+= (size_t)check_length; + WATCHPOINT_ASSERT(write_length < MEMCACHED_DEFAULT_COMMAND_SIZE); + } + + if (ptr->flags.use_udp && ptr->flags.buffer_requests) + { + size_t cmd_size= write_length + value_length + 2; + if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) + return MEMCACHED_WRITE_FAILURE; + if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) + memcached_io_write(instance, NULL, 0, true); + } + + if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE) + { + rc= MEMCACHED_WRITE_FAILURE; + } + else + { + struct libmemcached_io_vector_st vector[]= + { + { write_length, buffer }, + { value_length, value }, + { 2, "\r\n" } + }; + + if (ptr->flags.buffer_requests && verb == SET_OP) + { + to_write= false; + } + else + { + to_write= true; + } + + /* Send command header */ + rc= memcached_vdo(instance, vector, 3, to_write); + if (rc == MEMCACHED_SUCCESS) + { + + if (ptr->flags.no_reply) + { + rc= (to_write == false) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS; + } + else if (to_write == false) + { + rc= MEMCACHED_BUFFERED; + } + else + { + rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + + if (rc == MEMCACHED_STORED) + rc= MEMCACHED_SUCCESS; + } + } + } + + if (rc == MEMCACHED_WRITE_FAILURE) + memcached_io_reset(instance); + } + + WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read); + WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write); + + return rc; +} + + +memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + LIBMEMCACHED_MEMCACHED_SET_START(); + rc= memcached_send(ptr, key, key_length, + key, key_length, value, value_length, + expiration, flags, 0, SET_OP); + LIBMEMCACHED_MEMCACHED_SET_END(); + return rc; +} + +memcached_return_t memcached_add(memcached_st *ptr, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + LIBMEMCACHED_MEMCACHED_ADD_START(); + rc= memcached_send(ptr, key, key_length, + key, key_length, value, value_length, + expiration, flags, 0, ADD_OP); + LIBMEMCACHED_MEMCACHED_ADD_END(); + return rc; +} + +memcached_return_t memcached_replace(memcached_st *ptr, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + LIBMEMCACHED_MEMCACHED_REPLACE_START(); + rc= memcached_send(ptr, key, key_length, + key, key_length, value, value_length, + expiration, flags, 0, REPLACE_OP); + LIBMEMCACHED_MEMCACHED_REPLACE_END(); + return rc; +} + +memcached_return_t memcached_prepend(memcached_st *ptr, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + rc= memcached_send(ptr, key, key_length, + key, key_length, value, value_length, + expiration, flags, 0, PREPEND_OP); + return rc; +} + +memcached_return_t memcached_append(memcached_st *ptr, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + rc= memcached_send(ptr, key, key_length, + key, key_length, value, value_length, + expiration, flags, 0, APPEND_OP); + return rc; +} + +memcached_return_t memcached_cas(memcached_st *ptr, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags, + uint64_t cas) +{ + memcached_return_t rc; + rc= memcached_send(ptr, key, key_length, + key, key_length, value, value_length, + expiration, flags, cas, CAS_OP); + return rc; +} + +memcached_return_t memcached_set_by_key(memcached_st *ptr, + const char *group_key, + size_t group_key_length, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + LIBMEMCACHED_MEMCACHED_SET_START(); + rc= memcached_send(ptr, group_key, group_key_length, + key, key_length, value, value_length, + expiration, flags, 0, SET_OP); + LIBMEMCACHED_MEMCACHED_SET_END(); + return rc; +} + +memcached_return_t memcached_add_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + LIBMEMCACHED_MEMCACHED_ADD_START(); + rc= memcached_send(ptr, group_key, group_key_length, + key, key_length, value, value_length, + expiration, flags, 0, ADD_OP); + LIBMEMCACHED_MEMCACHED_ADD_END(); + return rc; +} + +memcached_return_t memcached_replace_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + LIBMEMCACHED_MEMCACHED_REPLACE_START(); + rc= memcached_send(ptr, group_key, group_key_length, + key, key_length, value, value_length, + expiration, flags, 0, REPLACE_OP); + LIBMEMCACHED_MEMCACHED_REPLACE_END(); + return rc; +} + +memcached_return_t memcached_prepend_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + rc= memcached_send(ptr, group_key, group_key_length, + key, key_length, value, value_length, + expiration, flags, 0, PREPEND_OP); + return rc; +} + +memcached_return_t memcached_append_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags) +{ + memcached_return_t rc; + rc= memcached_send(ptr, group_key, group_key_length, + key, key_length, value, value_length, + expiration, flags, 0, APPEND_OP); + return rc; +} + +memcached_return_t memcached_cas_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + const char *value, size_t value_length, + time_t expiration, + uint32_t flags, + uint64_t cas) +{ + memcached_return_t rc; + rc= memcached_send(ptr, group_key, group_key_length, + key, key_length, value, value_length, + expiration, flags, cas, CAS_OP); + return rc; +} + +static inline uint8_t get_com_code(memcached_storage_action_t verb, bool noreply) +{ + /* 0 isn't a value we want, but GCC 4.2 seems to think ret can otherwise + * be used uninitialized in this function. FAIL */ + uint8_t ret= 0; + + if (noreply) + switch (verb) + { + case SET_OP: + ret=PROTOCOL_BINARY_CMD_SETQ; + break; + case ADD_OP: + ret=PROTOCOL_BINARY_CMD_ADDQ; + break; + case CAS_OP: /* FALLTHROUGH */ + case REPLACE_OP: + ret=PROTOCOL_BINARY_CMD_REPLACEQ; + break; + case APPEND_OP: + ret=PROTOCOL_BINARY_CMD_APPENDQ; + break; + case PREPEND_OP: + ret=PROTOCOL_BINARY_CMD_PREPENDQ; + break; + default: + WATCHPOINT_ASSERT(verb); + break; + } + else + switch (verb) + { + case SET_OP: + ret=PROTOCOL_BINARY_CMD_SET; + break; + case ADD_OP: + ret=PROTOCOL_BINARY_CMD_ADD; + break; + case CAS_OP: /* FALLTHROUGH */ + case REPLACE_OP: + ret=PROTOCOL_BINARY_CMD_REPLACE; + break; + case APPEND_OP: + ret=PROTOCOL_BINARY_CMD_APPEND; + break; + case PREPEND_OP: + ret=PROTOCOL_BINARY_CMD_PREPEND; + break; + default: + WATCHPOINT_ASSERT(verb); + break; + } + + return ret; +} + + + +static memcached_return_t memcached_send_binary(memcached_st *ptr, + memcached_server_write_instance_st server, + uint32_t server_key, + const char *key, + size_t key_length, + const char *value, + size_t value_length, + time_t expiration, + uint32_t flags, + uint64_t cas, + memcached_storage_action_t verb) +{ + bool flush; + protocol_binary_request_set request= {}; + size_t send_length= sizeof(request.bytes); + + bool noreply= server->root->flags.no_reply; + + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= get_com_code(verb, noreply); + request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key))); + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + if (verb == APPEND_OP || verb == PREPEND_OP) + send_length -= 8; /* append & prepend does not contain extras! */ + else + { + request.message.header.request.extlen= 8; + request.message.body.flags= htonl(flags); + request.message.body.expiration= htonl((uint32_t)expiration); + } + + request.message.header.request.bodylen= htonl((uint32_t) (key_length + memcached_array_size(ptr->prefix_key) + value_length + + request.message.header.request.extlen)); + + if (cas) + request.message.header.request.cas= htonll(cas); + + flush= (bool) ((server->root->flags.buffer_requests && verb == SET_OP) ? 0 : 1); + + if (server->root->flags.use_udp && ! flush) + { + size_t cmd_size= send_length + key_length + value_length; + + if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) + { + return MEMCACHED_WRITE_FAILURE; + } + if (cmd_size + server->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) + { + memcached_io_write(server, NULL, 0, true); + } + } + + struct libmemcached_io_vector_st vector[]= + { + { send_length, request.bytes }, + { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) }, + { key_length, key }, + { value_length, value } + }; + + /* write the header */ + memcached_return_t rc; + if ((rc= memcached_vdo(server, vector, 4, flush)) != MEMCACHED_SUCCESS) + { + memcached_io_reset(server); + return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc; + } + + if (verb == SET_OP && ptr->number_of_replicas > 0) + { + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ; + WATCHPOINT_STRING("replicating"); + + for (uint32_t x= 0; x < ptr->number_of_replicas; x++) + { + memcached_server_write_instance_st instance; + + ++server_key; + if (server_key == memcached_server_count(ptr)) + server_key= 0; + + instance= memcached_server_instance_fetch(ptr, server_key); + + if (memcached_vdo(instance, vector, 4, false) != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + } + else + { + memcached_server_response_decrement(instance); + } + } + } + + if (flush == false) + { + return MEMCACHED_BUFFERED; + } + + if (noreply) + { + return MEMCACHED_SUCCESS; + } + + return memcached_response(server, NULL, 0, NULL); +} + diff --git a/libmemcached/strerror.c b/libmemcached/strerror.c deleted file mode 100644 index b3ac2b75..00000000 --- a/libmemcached/strerror.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "common.h" - -const char *memcached_strerror(memcached_st *ptr, memcached_return_t rc) -{ - (void)ptr; - switch (rc) - { - case MEMCACHED_SUCCESS: - return "SUCCESS"; - case MEMCACHED_FAILURE: - return "FAILURE"; - case MEMCACHED_HOST_LOOKUP_FAILURE: - return "HOSTNAME LOOKUP FAILURE"; - case MEMCACHED_CONNECTION_FAILURE: - return "CONNECTION FAILURE"; - case MEMCACHED_CONNECTION_BIND_FAILURE: - return "CONNECTION BIND FAILURE"; - case MEMCACHED_READ_FAILURE: - return "READ FAILURE"; - case MEMCACHED_UNKNOWN_READ_FAILURE: - return "UNKNOWN READ FAILURE"; - case MEMCACHED_PROTOCOL_ERROR: - return "PROTOCOL ERROR"; - case MEMCACHED_CLIENT_ERROR: - return "CLIENT ERROR"; - case MEMCACHED_SERVER_ERROR: - return "SERVER ERROR"; - case MEMCACHED_WRITE_FAILURE: - return "WRITE FAILURE"; - case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: - return "CONNECTION SOCKET CREATE FAILURE"; - case MEMCACHED_DATA_EXISTS: - return "CONNECTION DATA EXISTS"; - case MEMCACHED_DATA_DOES_NOT_EXIST: - return "CONNECTION DATA DOES NOT EXIST"; - case MEMCACHED_NOTSTORED: - return "NOT STORED"; - case MEMCACHED_STORED: - return "STORED"; - case MEMCACHED_NOTFOUND: - return "NOT FOUND"; - case MEMCACHED_MEMORY_ALLOCATION_FAILURE: - return "MEMORY ALLOCATION FAILURE"; - case MEMCACHED_PARTIAL_READ: - return "PARTIAL READ"; - case MEMCACHED_SOME_ERRORS: - return "SOME ERRORS WERE REPORTED"; - case MEMCACHED_NO_SERVERS: - return "NO SERVERS DEFINED"; - case MEMCACHED_END: - return "SERVER END"; - case MEMCACHED_DELETED: - return "SERVER DELETE"; - case MEMCACHED_VALUE: - return "SERVER VALUE"; - case MEMCACHED_STAT: - return "STAT VALUE"; - case MEMCACHED_ITEM: - return "ITEM VALUE"; - case MEMCACHED_ERRNO: - return "SYSTEM ERROR"; - case MEMCACHED_FAIL_UNIX_SOCKET: - return "COULD NOT OPEN UNIX SOCKET"; - case MEMCACHED_NOT_SUPPORTED: - return "ACTION NOT SUPPORTED"; - case MEMCACHED_FETCH_NOTFINISHED: - return "FETCH WAS NOT COMPLETED"; - case MEMCACHED_NO_KEY_PROVIDED: - return "A KEY LENGTH OF ZERO WAS PROVIDED"; - case MEMCACHED_BUFFERED: - return "ACTION QUEUED"; - case MEMCACHED_TIMEOUT: - return "A TIMEOUT OCCURRED"; - case MEMCACHED_BAD_KEY_PROVIDED: - return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE"; - case MEMCACHED_INVALID_HOST_PROTOCOL: - return "THE HOST TRANSPORT PROTOCOL DOES NOT MATCH THAT OF THE CLIENT"; - case MEMCACHED_SERVER_MARKED_DEAD: - return "SERVER IS MARKED DEAD"; - case MEMCACHED_UNKNOWN_STAT_KEY: - return "ENCOUNTERED AN UNKNOWN STAT KEY"; - case MEMCACHED_E2BIG: - return "ITEM TOO BIG"; - case MEMCACHED_INVALID_ARGUMENTS: - return "INVALID ARGUMENTS"; - case MEMCACHED_KEY_TOO_BIG: - return "KEY RETURNED FROM SERVER WAS TOO LARGE"; - case MEMCACHED_AUTH_PROBLEM: - return "FAILED TO SEND AUTHENTICATION TO SERVER"; - case MEMCACHED_AUTH_FAILURE: - return "AUTHENTICATION FAILURE"; - case MEMCACHED_AUTH_CONTINUE: - return "CONTINUE AUTHENTICATION"; - case MEMCACHED_PARSE_ERROR: - return "ERROR OCCURED WHILE PARSING"; - case MEMCACHED_PARSE_USER_ERROR: - return "USER INITIATED ERROR OCCURED WHILE PARSING"; - case MEMCACHED_DEPRECATED: - return "DEPRECATED"; - case MEMCACHED_MAXIMUM_RETURN: - return "Gibberish returned!"; - default: - return "Gibberish returned!"; - } -} diff --git a/libmemcached/strerror.cc b/libmemcached/strerror.cc new file mode 100644 index 00000000..b3ac2b75 --- /dev/null +++ b/libmemcached/strerror.cc @@ -0,0 +1,105 @@ +#include "common.h" + +const char *memcached_strerror(memcached_st *ptr, memcached_return_t rc) +{ + (void)ptr; + switch (rc) + { + case MEMCACHED_SUCCESS: + return "SUCCESS"; + case MEMCACHED_FAILURE: + return "FAILURE"; + case MEMCACHED_HOST_LOOKUP_FAILURE: + return "HOSTNAME LOOKUP FAILURE"; + case MEMCACHED_CONNECTION_FAILURE: + return "CONNECTION FAILURE"; + case MEMCACHED_CONNECTION_BIND_FAILURE: + return "CONNECTION BIND FAILURE"; + case MEMCACHED_READ_FAILURE: + return "READ FAILURE"; + case MEMCACHED_UNKNOWN_READ_FAILURE: + return "UNKNOWN READ FAILURE"; + case MEMCACHED_PROTOCOL_ERROR: + return "PROTOCOL ERROR"; + case MEMCACHED_CLIENT_ERROR: + return "CLIENT ERROR"; + case MEMCACHED_SERVER_ERROR: + return "SERVER ERROR"; + case MEMCACHED_WRITE_FAILURE: + return "WRITE FAILURE"; + case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: + return "CONNECTION SOCKET CREATE FAILURE"; + case MEMCACHED_DATA_EXISTS: + return "CONNECTION DATA EXISTS"; + case MEMCACHED_DATA_DOES_NOT_EXIST: + return "CONNECTION DATA DOES NOT EXIST"; + case MEMCACHED_NOTSTORED: + return "NOT STORED"; + case MEMCACHED_STORED: + return "STORED"; + case MEMCACHED_NOTFOUND: + return "NOT FOUND"; + case MEMCACHED_MEMORY_ALLOCATION_FAILURE: + return "MEMORY ALLOCATION FAILURE"; + case MEMCACHED_PARTIAL_READ: + return "PARTIAL READ"; + case MEMCACHED_SOME_ERRORS: + return "SOME ERRORS WERE REPORTED"; + case MEMCACHED_NO_SERVERS: + return "NO SERVERS DEFINED"; + case MEMCACHED_END: + return "SERVER END"; + case MEMCACHED_DELETED: + return "SERVER DELETE"; + case MEMCACHED_VALUE: + return "SERVER VALUE"; + case MEMCACHED_STAT: + return "STAT VALUE"; + case MEMCACHED_ITEM: + return "ITEM VALUE"; + case MEMCACHED_ERRNO: + return "SYSTEM ERROR"; + case MEMCACHED_FAIL_UNIX_SOCKET: + return "COULD NOT OPEN UNIX SOCKET"; + case MEMCACHED_NOT_SUPPORTED: + return "ACTION NOT SUPPORTED"; + case MEMCACHED_FETCH_NOTFINISHED: + return "FETCH WAS NOT COMPLETED"; + case MEMCACHED_NO_KEY_PROVIDED: + return "A KEY LENGTH OF ZERO WAS PROVIDED"; + case MEMCACHED_BUFFERED: + return "ACTION QUEUED"; + case MEMCACHED_TIMEOUT: + return "A TIMEOUT OCCURRED"; + case MEMCACHED_BAD_KEY_PROVIDED: + return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE"; + case MEMCACHED_INVALID_HOST_PROTOCOL: + return "THE HOST TRANSPORT PROTOCOL DOES NOT MATCH THAT OF THE CLIENT"; + case MEMCACHED_SERVER_MARKED_DEAD: + return "SERVER IS MARKED DEAD"; + case MEMCACHED_UNKNOWN_STAT_KEY: + return "ENCOUNTERED AN UNKNOWN STAT KEY"; + case MEMCACHED_E2BIG: + return "ITEM TOO BIG"; + case MEMCACHED_INVALID_ARGUMENTS: + return "INVALID ARGUMENTS"; + case MEMCACHED_KEY_TOO_BIG: + return "KEY RETURNED FROM SERVER WAS TOO LARGE"; + case MEMCACHED_AUTH_PROBLEM: + return "FAILED TO SEND AUTHENTICATION TO SERVER"; + case MEMCACHED_AUTH_FAILURE: + return "AUTHENTICATION FAILURE"; + case MEMCACHED_AUTH_CONTINUE: + return "CONTINUE AUTHENTICATION"; + case MEMCACHED_PARSE_ERROR: + return "ERROR OCCURED WHILE PARSING"; + case MEMCACHED_PARSE_USER_ERROR: + return "USER INITIATED ERROR OCCURED WHILE PARSING"; + case MEMCACHED_DEPRECATED: + return "DEPRECATED"; + case MEMCACHED_MAXIMUM_RETURN: + return "Gibberish returned!"; + default: + return "Gibberish returned!"; + } +} diff --git a/libmemcached/string.c b/libmemcached/string.c deleted file mode 100644 index b5badc5e..00000000 --- a/libmemcached/string.c +++ /dev/null @@ -1,214 +0,0 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: String structure used for libmemcached. - * - */ - -#include "common.h" - -inline static memcached_return_t _string_check(memcached_string_st *string, size_t need) -{ - if (need && need > (size_t)(string->current_size - (size_t)(string->end - string->string))) - { - size_t current_offset= (size_t) (string->end - string->string); - char *new_value; - size_t adjust; - size_t new_size; - - /* This is the block multiplier. To keep it larger and surive division errors we must round it up */ - adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / MEMCACHED_BLOCK_SIZE; - adjust++; - - new_size= sizeof(char) * (size_t)((adjust * MEMCACHED_BLOCK_SIZE) + string->current_size); - /* Test for overflow */ - if (new_size < need) - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - - new_value= libmemcached_realloc(string->root, string->string, new_size); - - if (new_value == NULL) - { - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - } - - string->string= new_value; - string->end= string->string + current_offset; - - string->current_size+= (MEMCACHED_BLOCK_SIZE * adjust); - } - - return MEMCACHED_SUCCESS; -} - -static inline void _init_string(memcached_string_st *self) -{ - self->current_size= 0; - self->end= self->string= NULL; -} - -memcached_string_st *memcached_string_create(const memcached_st *memc, memcached_string_st *self, size_t initial_size) -{ - memcached_return_t rc; - - WATCHPOINT_ASSERT(memc); - - /* Saving malloc calls :) */ - if (self) - { - WATCHPOINT_ASSERT(self->options.is_initialized == false); - - self->options.is_allocated= false; - } - else - { - self= libmemcached_malloc(memc, sizeof(memcached_string_st)); - - if (self == NULL) - { - return NULL; - } - - self->options.is_allocated= true; - } - self->root= (memcached_st *)memc; - - _init_string(self); - - rc= _string_check(self, initial_size); - if (rc != MEMCACHED_SUCCESS) - { - if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) - { - memcached_set_errno(self->root, errno, NULL); - } - libmemcached_free(memc, self); - - return NULL; - } - - self->options.is_initialized= true; - - WATCHPOINT_ASSERT(self->string == self->end); - - return self; -} - -memcached_return_t memcached_string_append_character(memcached_string_st *string, - char character) -{ - memcached_return_t rc; - - rc= _string_check(string, 1); - - if (rc != MEMCACHED_SUCCESS) - { - return rc; - } - - *string->end= character; - string->end++; - - return MEMCACHED_SUCCESS; -} - -memcached_return_t memcached_string_append(memcached_string_st *string, - const char *value, size_t length) -{ - memcached_return_t rc; - - rc= _string_check(string, length); - - if (rc != MEMCACHED_SUCCESS) - { - return rc; - } - - WATCHPOINT_ASSERT(length <= string->current_size); - WATCHPOINT_ASSERT(string->string); - WATCHPOINT_ASSERT(string->end >= string->string); - - memcpy(string->end, value, length); - string->end+= length; - - return MEMCACHED_SUCCESS; -} - -char *memcached_string_c_copy(memcached_string_st *string) -{ - char *c_ptr; - - if (memcached_string_length(string) == 0) - return NULL; - - c_ptr= libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char)); - - if (c_ptr == NULL) - return NULL; - - memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string)); - c_ptr[memcached_string_length(string)]= 0; - - return c_ptr; -} - -memcached_return_t memcached_string_reset(memcached_string_st *string) -{ - string->end= string->string; - - return MEMCACHED_SUCCESS; -} - -void memcached_string_free(memcached_string_st *ptr) -{ - if (ptr == NULL) - return; - - if (ptr->string) - { - libmemcached_free(ptr->root, ptr->string); - } - - if (memcached_is_allocated(ptr)) - { - libmemcached_free(ptr->root, ptr); - } - else - { - ptr->options.is_initialized= false; - } -} - -memcached_return_t memcached_string_check(memcached_string_st *string, size_t need) -{ - return _string_check(string, need); -} - -size_t memcached_string_length(const memcached_string_st *self) -{ - return (size_t)(self->end - self->string); -} - -size_t memcached_string_size(const memcached_string_st *self) -{ - return self->current_size; -} - -const char *memcached_string_value(const memcached_string_st *self) -{ - return self->string; -} - -char *memcached_string_value_mutable(const memcached_string_st *self) -{ - return self->string; -} - -void memcached_string_set_length(memcached_string_st *self, size_t length) -{ - self->end= self->string + length; -} diff --git a/libmemcached/string.cc b/libmemcached/string.cc new file mode 100644 index 00000000..4f012795 --- /dev/null +++ b/libmemcached/string.cc @@ -0,0 +1,241 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include + +inline static memcached_return_t _string_check(memcached_string_st *string, size_t need) +{ + if (need && need > (size_t)(string->current_size - (size_t)(string->end - string->string))) + { + size_t current_offset= (size_t) (string->end - string->string); + char *new_value; + size_t adjust; + size_t new_size; + + /* This is the block multiplier. To keep it larger and surive division errors we must round it up */ + adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / MEMCACHED_BLOCK_SIZE; + adjust++; + + new_size= sizeof(char) * (size_t)((adjust * MEMCACHED_BLOCK_SIZE) + string->current_size); + /* Test for overflow */ + if (new_size < need) + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + + new_value= static_cast(libmemcached_realloc(string->root, string->string, new_size)); + + if (new_value == NULL) + { + return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + } + + string->string= new_value; + string->end= string->string + current_offset; + + string->current_size+= (MEMCACHED_BLOCK_SIZE * adjust); + } + + return MEMCACHED_SUCCESS; +} + +static inline void _init_string(memcached_string_st *self) +{ + self->current_size= 0; + self->end= self->string= NULL; +} + +memcached_string_st *memcached_string_create(const memcached_st *memc, memcached_string_st *self, size_t initial_size) +{ + memcached_return_t rc; + + WATCHPOINT_ASSERT(memc); + + /* Saving malloc calls :) */ + if (self) + { + WATCHPOINT_ASSERT(self->options.is_initialized == false); + + self->options.is_allocated= false; + } + else + { + self= static_cast(libmemcached_malloc(memc, sizeof(memcached_string_st))); + + if (self == NULL) + { + return NULL; + } + + self->options.is_allocated= true; + } + self->root= const_cast(memc); + + _init_string(self); + + rc= _string_check(self, initial_size); + if (rc != MEMCACHED_SUCCESS) + { + if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) + { + memcached_set_errno(self->root, errno, NULL); + } + libmemcached_free(memc, self); + + return NULL; + } + + self->options.is_initialized= true; + + WATCHPOINT_ASSERT(self->string == self->end); + + return self; +} + +memcached_return_t memcached_string_append_character(memcached_string_st *string, + char character) +{ + memcached_return_t rc; + + rc= _string_check(string, 1); + + if (rc != MEMCACHED_SUCCESS) + { + return rc; + } + + *string->end= character; + string->end++; + + return MEMCACHED_SUCCESS; +} + +memcached_return_t memcached_string_append(memcached_string_st *string, + const char *value, size_t length) +{ + memcached_return_t rc; + + rc= _string_check(string, length); + + if (rc != MEMCACHED_SUCCESS) + { + return rc; + } + + WATCHPOINT_ASSERT(length <= string->current_size); + WATCHPOINT_ASSERT(string->string); + WATCHPOINT_ASSERT(string->end >= string->string); + + memcpy(string->end, value, length); + string->end+= length; + + return MEMCACHED_SUCCESS; +} + +char *memcached_string_c_copy(memcached_string_st *string) +{ + char *c_ptr; + + if (memcached_string_length(string) == 0) + return NULL; + + c_ptr= static_cast(libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char))); + + if (c_ptr == NULL) + return NULL; + + memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string)); + c_ptr[memcached_string_length(string)]= 0; + + return c_ptr; +} + +memcached_return_t memcached_string_reset(memcached_string_st *string) +{ + string->end= string->string; + + return MEMCACHED_SUCCESS; +} + +void memcached_string_free(memcached_string_st *ptr) +{ + if (ptr == NULL) + return; + + if (ptr->string) + { + libmemcached_free(ptr->root, ptr->string); + } + + if (memcached_is_allocated(ptr)) + { + libmemcached_free(ptr->root, ptr); + } + else + { + ptr->options.is_initialized= false; + } +} + +memcached_return_t memcached_string_check(memcached_string_st *string, size_t need) +{ + return _string_check(string, need); +} + +size_t memcached_string_length(const memcached_string_st *self) +{ + return (size_t)(self->end - self->string); +} + +size_t memcached_string_size(const memcached_string_st *self) +{ + return self->current_size; +} + +const char *memcached_string_value(const memcached_string_st *self) +{ + return self->string; +} + +char *memcached_string_value_mutable(const memcached_string_st *self) +{ + return self->string; +} + +void memcached_string_set_length(memcached_string_st *self, size_t length) +{ + self->end= self->string + length; +} diff --git a/libmemcached/string.h b/libmemcached/string.h index ca3dad14..8c57c8b0 100644 --- a/libmemcached/string.h +++ b/libmemcached/string.h @@ -1,17 +1,41 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. * - * Summary: String structure used for libmemcached. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #pragma once -#ifndef __LIBMEMCACHED_STRING_H__ -#define __LIBMEMCACHED_STRING_H__ /** Strings are always under our control so we make some assumptions @@ -97,5 +121,3 @@ void memcached_string_set_length(memcached_string_st *self, size_t length); #define memcached_string_make_from_cstr(X) (X), ((X) ? strlen(X) : 0) #endif - -#endif /* __LIBMEMCACHED_STRING_H__ */ diff --git a/libmemcached/types.h b/libmemcached/types.h index 2ebb8c00..b3d8f479 100644 --- a/libmemcached/types.h +++ b/libmemcached/types.h @@ -9,6 +9,7 @@ * */ +#pragma once #ifndef __LIBMEMCACHED_TYPES_H__ #define __LIBMEMCACHED_TYPES_H__ diff --git a/libmemcached/util/include.am b/libmemcached/util/include.am new file mode 100644 index 00000000..2c452f52 --- /dev/null +++ b/libmemcached/util/include.am @@ -0,0 +1,32 @@ +# vim:ft=automake +# included from Top Level Makefile.am +# All paths should be given relative to the root + +if BUILD_LIBMEMCACHEDUTIL +nobase_include_HEADERS+= \ + libmemcached/memcached_util.h \ + libmemcached/util.h \ + libmemcached/util/ping.h \ + libmemcached/util/pool.h \ + libmemcached/util/version.h +lib_LTLIBRARIES+= libmemcached/libmemcachedutil.la +endif + +libmemcached_libmemcachedutil_la_SOURCES= \ + libmemcached/util/ping.cc \ + libmemcached/util/pool.cc \ + libmemcached/util/version.cc +libmemcached_libmemcachedutil_la_CFLAGS= \ + ${AM_CFLAGS} \ + ${NO_CONVERSION} \ + ${PTHREAD_CFLAGS} \ + -DBUILDING_LIBMEMCACHED +libmemcached_libmemcachedutil_la_CXXFLAGS= \ + ${AM_CXXFLAGS} \ + ${NO_CONVERSION} \ + ${PTHREAD_CFLAGS} \ + -DBUILDING_LIBMEMCACHED +libmemcached_libmemcachedutil_la_LIBADD= libmemcached/libmemcached.la +libmemcached_libmemcachedutil_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_UTIL_LIBRARY_VERSION} +libmemcached_libmemcachedutil_la_DEPENDENCIES= libmemcached/libmemcached.la + diff --git a/libmemcached/util/ping.c b/libmemcached/util/ping.c deleted file mode 100644 index 3d5471a3..00000000 --- a/libmemcached/util/ping.c +++ /dev/null @@ -1,38 +0,0 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: connects to a host, and makes sure it is alive. - * - */ - -#include "libmemcached/common.h" -#include "libmemcached/memcached_util.h" - - -bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret) -{ - memcached_return_t rc; - memcached_st memc, *memc_ptr; - - memc_ptr= memcached_create(&memc); - - rc= memcached_server_add(memc_ptr, hostname, port); - - if (rc == MEMCACHED_SUCCESS) - { - rc= memcached_version(memc_ptr); - } - - memcached_free(memc_ptr); - - if (ret) - { - *ret= rc; - } - - return rc == MEMCACHED_SUCCESS; -} diff --git a/libmemcached/util/ping.cc b/libmemcached/util/ping.cc new file mode 100644 index 00000000..3d5471a3 --- /dev/null +++ b/libmemcached/util/ping.cc @@ -0,0 +1,38 @@ +/* LibMemcached + * Copyright (C) 2010 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: connects to a host, and makes sure it is alive. + * + */ + +#include "libmemcached/common.h" +#include "libmemcached/memcached_util.h" + + +bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret) +{ + memcached_return_t rc; + memcached_st memc, *memc_ptr; + + memc_ptr= memcached_create(&memc); + + rc= memcached_server_add(memc_ptr, hostname, port); + + if (rc == MEMCACHED_SUCCESS) + { + rc= memcached_version(memc_ptr); + } + + memcached_free(memc_ptr); + + if (ret) + { + *ret= rc; + } + + return rc == MEMCACHED_SUCCESS; +} diff --git a/libmemcached/util/pool.c b/libmemcached/util/pool.c deleted file mode 100644 index 948f765b..00000000 --- a/libmemcached/util/pool.c +++ /dev/null @@ -1,332 +0,0 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: connects to a host, and makes sure it is alive. - * - */ - -/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ -#include "libmemcached/common.h" -#include "libmemcached/memcached_util.h" - -#include -#include - -struct memcached_pool_st -{ - pthread_mutex_t mutex; - pthread_cond_t cond; - memcached_st *master; - memcached_st **mmc; - int firstfree; - uint32_t size; - uint32_t current_size; - bool _owns_master; - char *version; -}; - -static memcached_return_t mutex_enter(pthread_mutex_t *mutex) -{ - int ret; - do - ret= pthread_mutex_lock(mutex); - while (ret == -1 && errno == EINTR); - - return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS; -} - -static memcached_return_t mutex_exit(pthread_mutex_t *mutex) -{ - int ret; - do - ret= pthread_mutex_unlock(mutex); - while (ret == -1 && errno == EINTR); - - return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS; -} - -/** - * Grow the connection pool by creating a connection structure and clone the - * original memcached handle. - */ -static int grow_pool(memcached_pool_st* pool) -{ - memcached_st *obj= calloc(1, sizeof(*obj)); - - if (obj == NULL) - return -1; - - if (memcached_clone(obj, pool->master) == NULL) - { - free(obj); - return -1; - } - - pool->mmc[++pool->firstfree] = obj; - pool->current_size++; - - return EXIT_SUCCESS; -} - -static inline memcached_pool_st *_pool_create(memcached_st* mmc, uint32_t initial, uint32_t max) -{ - memcached_pool_st* ret= NULL; - - if (! initial || ! max || initial > max) - { - errno= EINVAL; - return NULL; - } - - memcached_pool_st object= { .mutex = PTHREAD_MUTEX_INITIALIZER, - .cond= PTHREAD_COND_INITIALIZER, - .master= mmc, - .mmc= calloc(max, sizeof(memcached_st*)), - .firstfree= -1, - .size= max, - .current_size= 0, - ._owns_master= false}; - - if (object.mmc != NULL) - { - ret= (memcached_pool_st*)calloc(1, sizeof(memcached_pool_st)); - if (ret == NULL) - { - free(object.mmc); - errno= ENOMEM; // Set this for the failed calloc - return NULL; - } - - *ret= object; - - /* - Try to create the initial size of the pool. An allocation failure at - this time is not fatal.. - */ - for (unsigned int ii= 0; ii < initial; ++ii) - { - if (grow_pool(ret) == -1) - break; - } - } - - return ret; -} - -memcached_pool_st *memcached_pool_create(memcached_st* mmc, uint32_t initial, uint32_t max) -{ - return _pool_create(mmc, initial, max); -} - -memcached_pool_st * memcached_pool(const char *option_string, size_t option_string_length) -{ - memcached_pool_st *self; - memcached_st *memc= memcached(option_string, option_string_length); - - if (! memc) - return NULL; - - self= memcached_pool_create(memc, memc->configure.initial_pool_size, memc->configure.max_pool_size); - if (! self) - { - memcached_free(memc); - errno= ENOMEM; - return NULL; - } - errno= 0; - - self->_owns_master= true; - - return self; -} - -memcached_st* memcached_pool_destroy(memcached_pool_st* pool) -{ - if (! pool) - return NULL; - - memcached_st *ret= pool->master; - - for (int xx= 0; xx <= pool->firstfree; ++xx) - { - memcached_free(pool->mmc[xx]); - free(pool->mmc[xx]); - pool->mmc[xx] = NULL; - } - - pthread_mutex_destroy(&pool->mutex); - pthread_cond_destroy(&pool->cond); - free(pool->mmc); - if (pool->_owns_master) - { - memcached_free(pool->master); - ret= NULL; - } - free(pool); - - return ret; -} - -memcached_st* memcached_pool_pop(memcached_pool_st* pool, - bool block, - memcached_return_t *rc) -{ - if (! pool || ! rc) - { - errno= EINVAL; - return NULL; - } - - memcached_st *ret= NULL; - if ((*rc= mutex_enter(&pool->mutex)) != MEMCACHED_SUCCESS) - { - return NULL; - } - - do - { - if (pool->firstfree > -1) - { - ret= pool->mmc[pool->firstfree--]; - } - else if (pool->current_size == pool->size) - { - if (!block) - { - *rc= mutex_exit(&pool->mutex); - return NULL; - } - - if (pthread_cond_wait(&pool->cond, &pool->mutex) == -1) - { - int err= errno; - mutex_exit(&pool->mutex); - errno= err; - *rc= MEMCACHED_ERRNO; - return NULL; - } - } - else if (grow_pool(pool) == -1) - { - *rc= mutex_exit(&pool->mutex); - return NULL; - } - } - while (ret == NULL); - - *rc= mutex_exit(&pool->mutex); - - return ret; -} - -memcached_return_t memcached_pool_push(memcached_pool_st* pool, - memcached_st *mmc) -{ - if (! pool) - return MEMCACHED_INVALID_ARGUMENTS; - - memcached_return_t rc= mutex_enter(&pool->mutex); - - if (rc != MEMCACHED_SUCCESS) - return rc; - - char* version= memcached_get_user_data(mmc); - /* Someone updated the behavior on the object.. */ - if (version != pool->version) - { - memcached_free(mmc); - memset(mmc, 0, sizeof(*mmc)); - if (memcached_clone(mmc, pool->master) == NULL) - { - rc= MEMCACHED_SOME_ERRORS; - } - } - - pool->mmc[++pool->firstfree]= mmc; - - if (pool->firstfree == 0 && pool->current_size == pool->size) - { - /* we might have people waiting for a connection.. wake them up :-) */ - pthread_cond_broadcast(&pool->cond); - } - - memcached_return_t rval= mutex_exit(&pool->mutex); - if (rc == MEMCACHED_SOME_ERRORS) - return rc; - - return rval; -} - - -memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool, - memcached_behavior_t flag, - uint64_t data) -{ - if (! pool) - return MEMCACHED_INVALID_ARGUMENTS; - - memcached_return_t rc= mutex_enter(&pool->mutex); - if (rc != MEMCACHED_SUCCESS) - return rc; - - /* update the master */ - rc= memcached_behavior_set(pool->master, flag, data); - if (rc != MEMCACHED_SUCCESS) - { - mutex_exit(&pool->mutex); - return rc; - } - - ++pool->version; - memcached_set_user_data(pool->master, pool->version); - /* update the clones */ - for (int xx= 0; xx <= pool->firstfree; ++xx) - { - rc= memcached_behavior_set(pool->mmc[xx], flag, data); - if (rc == MEMCACHED_SUCCESS) - { - memcached_set_user_data(pool->mmc[xx], pool->version); - } - else - { - memcached_free(pool->mmc[xx]); - memset(pool->mmc[xx], 0, sizeof(*pool->mmc[xx])); - - if (memcached_clone(pool->mmc[xx], pool->master) == NULL) - { - /* I'm not sure what to do in this case.. this would happen - if we fail to push the server list inside the client.. - I should add a testcase for this, but I believe the following - would work, except that you would add a hole in the pool list.. - in theory you could end up with an empty pool.... - */ - free(pool->mmc[xx]); - pool->mmc[xx]= NULL; - } - } - } - - return mutex_exit(&pool->mutex); -} - -memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool, - memcached_behavior_t flag, - uint64_t *value) -{ - if (! pool) - return MEMCACHED_INVALID_ARGUMENTS; - - memcached_return_t rc= mutex_enter(&pool->mutex); - if (rc != MEMCACHED_SUCCESS) - { - return rc; - } - - *value= memcached_behavior_get(pool->master, flag); - - return mutex_exit(&pool->mutex); -} diff --git a/libmemcached/util/pool.cc b/libmemcached/util/pool.cc new file mode 100644 index 00000000..17cff077 --- /dev/null +++ b/libmemcached/util/pool.cc @@ -0,0 +1,392 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include + +#include +#include +#include +#include + +static bool grow_pool(memcached_pool_st* pool); + +struct memcached_pool_st +{ + pthread_mutex_t mutex; + pthread_cond_t cond; + memcached_st *master; + memcached_st **server_pool; + int firstfree; + const uint32_t size; + uint32_t current_size; + bool _owns_master; + + memcached_pool_st(memcached_st *master_arg, size_t max_arg) : + master(master_arg), + server_pool(NULL), + firstfree(-1), + size(max_arg), + current_size(0), + _owns_master(false) + { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cond, NULL); + } + + bool init(uint32_t initial) + { + server_pool= new (std::nothrow) memcached_st *[size]; + if (not server_pool) + return false; + + /* + Try to create the initial size of the pool. An allocation failure at + this time is not fatal.. + */ + for (unsigned int x= 0; x < initial; ++x) + { + if (not grow_pool(this)) + break; + } + + return true; + } + + ~memcached_pool_st() + { + for (int x= 0; x <= firstfree; ++x) + { + memcached_free(server_pool[x]); + server_pool[x] = NULL; + } + + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&cond); + delete [] server_pool; + if (_owns_master) + { + memcached_free(master); + } + } + + void increment_version() + { + ++master->configure.version; + } + + bool compare_version(const memcached_st *arg) const + { + return (arg->configure.version == version()); + } + + int32_t version() const + { + return master->configure.version; + } +}; + +static memcached_return_t mutex_enter(pthread_mutex_t *mutex) +{ + int ret; + do + { + ret= pthread_mutex_lock(mutex); + } while (ret == -1 && errno == EINTR); + + return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS; +} + +static memcached_return_t mutex_exit(pthread_mutex_t *mutex) +{ + int ret; + do + { + ret= pthread_mutex_unlock(mutex); + } while (ret == -1 && errno == EINTR); + + return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS; +} + +/** + * Grow the connection pool by creating a connection structure and clone the + * original memcached handle. + */ +static bool grow_pool(memcached_pool_st* pool) +{ + memcached_st *obj; + if (not (obj= memcached_clone(NULL, pool->master))) + { + return false; + } + + pool->server_pool[++pool->firstfree]= obj; + pool->current_size++; + obj->configure.version= pool->version(); + + return true; +} + +static inline memcached_pool_st *_pool_create(memcached_st* master, uint32_t initial, uint32_t max) +{ + if (! initial || ! max || initial > max) + { + errno= EINVAL; + return NULL; + } + + memcached_pool_st *object= new (std::nothrow) memcached_pool_st(master, max); + if (not object) + { + errno= ENOMEM; // Set this for the failed calloc + return NULL; + } + + /* + Try to create the initial size of the pool. An allocation failure at + this time is not fatal.. + */ + if (not object->init(initial)) + { + delete object; + return NULL; + } + + return object; +} + +memcached_pool_st *memcached_pool_create(memcached_st* master, uint32_t initial, uint32_t max) +{ + return _pool_create(master, initial, max); +} + +memcached_pool_st * memcached_pool(const char *option_string, size_t option_string_length) +{ + memcached_st *memc= memcached(option_string, option_string_length); + + if (not memc) + return NULL; + + memcached_pool_st *self; + self= memcached_pool_create(memc, memc->configure.initial_pool_size, memc->configure.max_pool_size); + if (not self) + { + memcached_free(memc); + errno= ENOMEM; + return NULL; + } + errno= 0; + + self->_owns_master= true; + + return self; +} + +memcached_st* memcached_pool_destroy(memcached_pool_st* pool) +{ + if (not pool) + return NULL; + + // Legacy that we return the original structure + memcached_st *ret= NULL; + if (pool->_owns_master) + { } + else + { + ret= pool->master; + } + + delete pool; + + return ret; +} + +memcached_st* memcached_pool_pop(memcached_pool_st* pool, + bool block, + memcached_return_t *rc) +{ + assert(pool); + assert(rc); + if (not pool || not rc) + { + errno= EINVAL; + return NULL; + } + + if ((*rc= mutex_enter(&pool->mutex)) != MEMCACHED_SUCCESS) + { + return NULL; + } + + memcached_st *ret= NULL; + do + { + if (pool->firstfree > -1) + { + ret= pool->server_pool[pool->firstfree--]; + } + else if (pool->current_size == pool->size) + { + if (not block) + { + *rc= mutex_exit(&pool->mutex); // this should be a different error + return NULL; + } + + if (pthread_cond_wait(&pool->cond, &pool->mutex) == -1) + { + int err= errno; + mutex_exit(&pool->mutex); + errno= err; + *rc= MEMCACHED_ERRNO; + return NULL; + } + } + else if (not grow_pool(pool)) + { + (void)mutex_exit(&pool->mutex); + *rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE; + return NULL; + } + } + while (ret == NULL); + + *rc= mutex_exit(&pool->mutex); + + return ret; +} + +memcached_return_t memcached_pool_push(memcached_pool_st* pool, memcached_st *released) +{ + if (not pool) + return MEMCACHED_INVALID_ARGUMENTS; + + memcached_return_t rc= mutex_enter(&pool->mutex); + + if (rc != MEMCACHED_SUCCESS) + return rc; + + /* Someone updated the behavior on the object.. */ + if (not pool->compare_version(released)) + { + memcached_free(released); + if (not (released= memcached_clone(NULL, pool->master))) + { + rc= MEMCACHED_SOME_ERRORS; + } + } + + pool->server_pool[++pool->firstfree]= released; + + if (pool->firstfree == 0 && pool->current_size == pool->size) + { + /* we might have people waiting for a connection.. wake them up :-) */ + pthread_cond_broadcast(&pool->cond); + } + + memcached_return_t rval= mutex_exit(&pool->mutex); + if (rc == MEMCACHED_SOME_ERRORS) + return rc; + + return rval; +} + + +memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool, + memcached_behavior_t flag, + uint64_t data) +{ + if (not pool) + return MEMCACHED_INVALID_ARGUMENTS; + + memcached_return_t rc= mutex_enter(&pool->mutex); + if (rc != MEMCACHED_SUCCESS) + return rc; + + /* update the master */ + rc= memcached_behavior_set(pool->master, flag, data); + if (rc != MEMCACHED_SUCCESS) + { + mutex_exit(&pool->mutex); + return rc; + } + + pool->increment_version(); + /* update the clones */ + for (int xx= 0; xx <= pool->firstfree; ++xx) + { + rc= memcached_behavior_set(pool->server_pool[xx], flag, data); + if (rc == MEMCACHED_SUCCESS) + { + pool->server_pool[xx]->configure.version= pool->version(); + } + else + { + memcached_free(pool->server_pool[xx]); + if (not (pool->server_pool[xx]= memcached_clone(NULL, pool->master))) + { + /* I'm not sure what to do in this case.. this would happen + if we fail to push the server list inside the client.. + I should add a testcase for this, but I believe the following + would work, except that you would add a hole in the pool list.. + in theory you could end up with an empty pool.... + */ + } + } + } + + return mutex_exit(&pool->mutex); +} + +memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool, + memcached_behavior_t flag, + uint64_t *value) +{ + if (! pool) + return MEMCACHED_INVALID_ARGUMENTS; + + memcached_return_t rc= mutex_enter(&pool->mutex); + if (rc != MEMCACHED_SUCCESS) + { + return rc; + } + + *value= memcached_behavior_get(pool->master, flag); + + return mutex_exit(&pool->mutex); +} diff --git a/libmemcached/util/version.c b/libmemcached/util/version.c deleted file mode 100644 index a0b69255..00000000 --- a/libmemcached/util/version.c +++ /dev/null @@ -1,63 +0,0 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. - * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. - * - * Summary: connect to all hosts, and make sure they meet a minimum version - * - */ - -/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ -#include "libmemcached/common.h" -#include "libmemcached/memcached_util.h" - -struct local_context -{ - uint8_t major_version; - uint8_t minor_version; - uint8_t micro_version; - - bool truth; -}; - -static memcached_return_t check_server_version(const memcached_st *ptr, - const memcached_server_st *instance, - void *context) -{ - /* Do Nothing */ - struct local_context *check= (struct local_context *)context; - (void)ptr; - - if (instance->major_version != UINT8_MAX && - instance->major_version >= check->major_version && - instance->minor_version >= check->minor_version && - instance->micro_version >= check->micro_version ) - { - return MEMCACHED_SUCCESS; - } - - check->truth= false; - - return MEMCACHED_FAILURE; -} - -bool libmemcached_util_version_check(memcached_st *memc, - uint8_t major_version, - uint8_t minor_version, - uint8_t micro_version) -{ - memcached_server_fn callbacks[1]; - memcached_return_t rc= memcached_version(memc); - - if (rc != MEMCACHED_SUCCESS) - return false; - - struct local_context check= { .major_version= major_version, .minor_version= minor_version, .micro_version= micro_version, .truth= true }; - - callbacks[0]= check_server_version; - memcached_server_cursor(memc, callbacks, (void *)&check, 1); - - return check.truth; -} diff --git a/libmemcached/util/version.cc b/libmemcached/util/version.cc new file mode 100644 index 00000000..a8208298 --- /dev/null +++ b/libmemcached/util/version.cc @@ -0,0 +1,87 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include + +struct local_context +{ + uint8_t major_version; + uint8_t minor_version; + uint8_t micro_version; + + bool truth; +}; + +static memcached_return_t check_server_version(const memcached_st *ptr, + const memcached_server_st *instance, + void *context) +{ + /* Do Nothing */ + struct local_context *check= (struct local_context *)context; + (void)ptr; + + if (instance->major_version != UINT8_MAX && + instance->major_version >= check->major_version && + instance->minor_version >= check->minor_version && + instance->micro_version >= check->micro_version ) + { + return MEMCACHED_SUCCESS; + } + + check->truth= false; + + return MEMCACHED_FAILURE; +} + +bool libmemcached_util_version_check(memcached_st *memc, + uint8_t major_version, + uint8_t minor_version, + uint8_t micro_version) +{ + if (memcached_version(memc) != MEMCACHED_SUCCESS) + return false; + + struct local_context check= { major_version, minor_version, micro_version, true }; + + memcached_server_fn callbacks[1]; + callbacks[0]= check_server_version; + memcached_server_cursor(memc, callbacks, (void *)&check, 1); + + return check.truth; +} diff --git a/libmemcached/verbosity.c b/libmemcached/verbosity.c deleted file mode 100644 index d71fced7..00000000 --- a/libmemcached/verbosity.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "common.h" - -struct context_st -{ - size_t length; - const char *buffer; -}; - -static memcached_return_t _set_verbosity(const memcached_st *ptr, - const memcached_server_st *server, - void *context) -{ - memcached_return_t rc; - memcached_st local_memc; - memcached_st *memc_ptr; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - - struct context_st *execute= (struct context_st *)context; - (void)ptr; - - memc_ptr= memcached_create(&local_memc); - - rc= memcached_server_add(memc_ptr, memcached_server_name(server), memcached_server_port(server)); - - if (rc == MEMCACHED_SUCCESS) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(memc_ptr, 0); - - rc= memcached_do(instance, execute->buffer, execute->length, true); - - if (rc == MEMCACHED_SUCCESS) - { - rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - } - } - - memcached_free(memc_ptr); - - return rc; -} - -memcached_return_t memcached_verbosity(memcached_st *ptr, uint32_t verbosity) -{ - int send_length; - memcached_server_fn callbacks[1]; - - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "verbosity %u\r\n", verbosity); - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) - return MEMCACHED_WRITE_FAILURE; - - struct context_st context = { .length= (size_t)send_length, .buffer= buffer }; - - callbacks[0]= _set_verbosity; - - return memcached_server_cursor(ptr, callbacks, &context, 1); -} diff --git a/libmemcached/verbosity.cc b/libmemcached/verbosity.cc new file mode 100644 index 00000000..ec00b8de --- /dev/null +++ b/libmemcached/verbosity.cc @@ -0,0 +1,97 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +struct context_st +{ + size_t length; + const char *buffer; +}; + +static memcached_return_t _set_verbosity(const memcached_st *ptr, + const memcached_server_st *server, + void *context) +{ + memcached_return_t rc; + memcached_st local_memc; + memcached_st *memc_ptr; + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + + struct context_st *execute= (struct context_st *)context; + (void)ptr; + + memc_ptr= memcached_create(&local_memc); + + rc= memcached_server_add(memc_ptr, memcached_server_name(server), memcached_server_port(server)); + + if (rc == MEMCACHED_SUCCESS) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(memc_ptr, 0); + + rc= memcached_do(instance, execute->buffer, execute->length, true); + + if (rc == MEMCACHED_SUCCESS) + { + rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + } + } + + memcached_free(memc_ptr); + + return rc; +} + +memcached_return_t memcached_verbosity(memcached_st *ptr, uint32_t verbosity) +{ + int send_length; + memcached_server_fn callbacks[1]; + + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + + send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, + "verbosity %u\r\n", verbosity); + if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + return MEMCACHED_WRITE_FAILURE; + + struct context_st context = { (size_t)send_length, buffer }; + + callbacks[0]= _set_verbosity; + + return memcached_server_cursor(ptr, callbacks, &context, 1); +} diff --git a/libmemcached/verbosity.h b/libmemcached/verbosity.h index b28458e4..29946486 100644 --- a/libmemcached/verbosity.h +++ b/libmemcached/verbosity.h @@ -1,16 +1,41 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. * - * Summary: Change the verbository level of the memcached server + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_VERBOSITY_H__ -#define __LIBMEMCACHED_VERBOSITY_H__ +#pragma once #ifdef __cplusplus extern "C" { @@ -23,5 +48,3 @@ memcached_return_t memcached_verbosity(memcached_st *ptr, uint32_t verbosity); #ifdef __cplusplus } #endif - -#endif /* __LIBMEMCACHED_VERBOSITY_H__ */ diff --git a/libmemcached/version.c b/libmemcached/version.c deleted file mode 100644 index 82de87d3..00000000 --- a/libmemcached/version.c +++ /dev/null @@ -1,178 +0,0 @@ -#include "common.h" - -const char * memcached_lib_version(void) -{ - return LIBMEMCACHED_VERSION_STRING; -} - -static inline memcached_return_t memcached_version_binary(memcached_st *ptr); -static inline memcached_return_t memcached_version_textual(memcached_st *ptr); - -memcached_return_t memcached_version(memcached_st *ptr) -{ - if (ptr->flags.use_udp) - return MEMCACHED_NOT_SUPPORTED; - - memcached_return_t rc; - - if (ptr->flags.binary_protocol) - rc= memcached_version_binary(ptr); - else - rc= memcached_version_textual(ptr); - - return rc; -} - -static inline memcached_return_t memcached_version_textual(memcached_st *ptr) -{ - size_t send_length; - memcached_return_t rc; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - char *response_ptr; - const char *command= "version\r\n"; - - send_length= sizeof("version\r\n") -1; - - rc= MEMCACHED_SUCCESS; - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_return_t rrc; - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - // Optimization, we only fetch version once. - if (instance->major_version != UINT8_MAX) - continue; - - rrc= memcached_do(instance, command, send_length, true); - if (rrc != MEMCACHED_SUCCESS) - { - instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; - rc= MEMCACHED_SOME_ERRORS; - continue; - } - - rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - if (rrc != MEMCACHED_SUCCESS) - { - instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; - rc= MEMCACHED_SOME_ERRORS; - continue; - } - - /* Find the space, and then move one past it to copy version */ - response_ptr= index(buffer, ' '); - response_ptr++; - - instance->major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10); - if (errno == ERANGE) - { - instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; - rc= MEMCACHED_SOME_ERRORS; - continue; - } - - response_ptr= index(response_ptr, '.'); - response_ptr++; - - instance->minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10); - if (errno == ERANGE) - { - instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; - rc= MEMCACHED_SOME_ERRORS; - continue; - } - - response_ptr= index(response_ptr, '.'); - response_ptr++; - instance->micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10); - if (errno == ERANGE) - { - instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; - rc= MEMCACHED_SOME_ERRORS; - continue; - } - } - - return rc; -} - -static inline memcached_return_t memcached_version_binary(memcached_st *ptr) -{ - memcached_return_t rc; - protocol_binary_request_version request= { .bytes= {0}}; - request.message.header.request.magic= PROTOCOL_BINARY_REQ; - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION; - request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - - rc= MEMCACHED_SUCCESS; - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_return_t rrc; - - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - if (instance->major_version != UINT8_MAX) - continue; - - rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true); - if (rrc != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - rc= MEMCACHED_SOME_ERRORS; - continue; - } - } - - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) - { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); - - if (instance->major_version != UINT8_MAX) - continue; - - if (memcached_server_response_count(instance) > 0) - { - memcached_return_t rrc; - char buffer[32]; - char *p; - - rrc= memcached_response(instance, buffer, sizeof(buffer), NULL); - if (rrc != MEMCACHED_SUCCESS) - { - memcached_io_reset(instance); - rc= MEMCACHED_SOME_ERRORS; - continue; - } - - instance->major_version= (uint8_t)strtol(buffer, &p, 10); - if (errno == ERANGE) - { - instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; - rc= MEMCACHED_SOME_ERRORS; - continue; - } - - instance->minor_version= (uint8_t)strtol(p + 1, &p, 10); - if (errno == ERANGE) - { - instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; - rc= MEMCACHED_SOME_ERRORS; - continue; - } - - instance->micro_version= (uint8_t)strtol(p + 1, NULL, 10); - if (errno == ERANGE) - { - instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; - rc= MEMCACHED_SOME_ERRORS; - continue; - } - - } - } - - return rc; -} diff --git a/libmemcached/version.cc b/libmemcached/version.cc new file mode 100644 index 00000000..abb72005 --- /dev/null +++ b/libmemcached/version.cc @@ -0,0 +1,214 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include + +const char * memcached_lib_version(void) +{ + return LIBMEMCACHED_VERSION_STRING; +} + +static inline memcached_return_t memcached_version_binary(memcached_st *ptr); +static inline memcached_return_t memcached_version_textual(memcached_st *ptr); + +memcached_return_t memcached_version(memcached_st *ptr) +{ + if (ptr->flags.use_udp) + return MEMCACHED_NOT_SUPPORTED; + + memcached_return_t rc; + + if (ptr->flags.binary_protocol) + rc= memcached_version_binary(ptr); + else + rc= memcached_version_textual(ptr); + + return rc; +} + +static inline memcached_return_t memcached_version_textual(memcached_st *ptr) +{ + size_t send_length; + memcached_return_t rc; + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + char *response_ptr; + const char *command= "version\r\n"; + + send_length= sizeof("version\r\n") -1; + + rc= MEMCACHED_SUCCESS; + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_return_t rrc; + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + // Optimization, we only fetch version once. + if (instance->major_version != UINT8_MAX) + continue; + + rrc= memcached_do(instance, command, send_length, true); + if (rrc != MEMCACHED_SUCCESS) + { + instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; + rc= MEMCACHED_SOME_ERRORS; + continue; + } + + rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + if (rrc != MEMCACHED_SUCCESS) + { + instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; + rc= MEMCACHED_SOME_ERRORS; + continue; + } + + /* Find the space, and then move one past it to copy version */ + response_ptr= index(buffer, ' '); + response_ptr++; + + instance->major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10); + if (errno == ERANGE) + { + instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; + rc= MEMCACHED_SOME_ERRORS; + continue; + } + + response_ptr= index(response_ptr, '.'); + response_ptr++; + + instance->minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10); + if (errno == ERANGE) + { + instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; + rc= MEMCACHED_SOME_ERRORS; + continue; + } + + response_ptr= index(response_ptr, '.'); + response_ptr++; + instance->micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10); + if (errno == ERANGE) + { + instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; + rc= MEMCACHED_SOME_ERRORS; + continue; + } + } + + return rc; +} + +static inline memcached_return_t memcached_version_binary(memcached_st *ptr) +{ + memcached_return_t rc; + protocol_binary_request_version request= {}; + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION; + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + + rc= MEMCACHED_SUCCESS; + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_return_t rrc; + + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + if (instance->major_version != UINT8_MAX) + continue; + + rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true); + if (rrc != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + rc= MEMCACHED_SOME_ERRORS; + continue; + } + } + + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + { + memcached_server_write_instance_st instance= + memcached_server_instance_fetch(ptr, x); + + if (instance->major_version != UINT8_MAX) + continue; + + if (memcached_server_response_count(instance) > 0) + { + memcached_return_t rrc; + char buffer[32]; + char *p; + + rrc= memcached_response(instance, buffer, sizeof(buffer), NULL); + if (rrc != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + rc= MEMCACHED_SOME_ERRORS; + continue; + } + + instance->major_version= (uint8_t)strtol(buffer, &p, 10); + if (errno == ERANGE) + { + instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; + rc= MEMCACHED_SOME_ERRORS; + continue; + } + + instance->minor_version= (uint8_t)strtol(p + 1, &p, 10); + if (errno == ERANGE) + { + instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; + rc= MEMCACHED_SOME_ERRORS; + continue; + } + + instance->micro_version= (uint8_t)strtol(p + 1, NULL, 10); + if (errno == ERANGE) + { + instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; + rc= MEMCACHED_SOME_ERRORS; + continue; + } + + } + } + + return rc; +} diff --git a/libmemcached/version.h b/libmemcached/version.h index 7e6f607a..c443accb 100644 --- a/libmemcached/version.h +++ b/libmemcached/version.h @@ -1,16 +1,41 @@ -/* LibMemcached - * Copyright (C) 2010 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 Brian Aker All rights reserved. * - * Summary: Find version information + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __LIBMEMCACHED_VERSION_H__ -#define __LIBMEMCACHED_VERSION_H__ +#pragma once #ifdef __cplusplus extern "C" { @@ -25,5 +50,3 @@ const char * memcached_lib_version(void); #ifdef __cplusplus } #endif - -#endif /* __LIBMEMCACHED_VERSION_H__ */ diff --git a/libmemcached/visibility.h b/libmemcached/visibility.h index 7d9af058..646806ac 100644 --- a/libmemcached/visibility.h +++ b/libmemcached/visibility.h @@ -16,8 +16,7 @@ * @brief Visibility control macros */ -#ifndef __LIBMEMCACHED_VISIBILITY_H__ -#define __LIBMEMCACHED_VISIBILITY_H__ +#pragma once /** * @@ -50,5 +49,3 @@ # define LIBMEMCACHED_LOCAL # endif /* defined(_MSC_VER) */ #endif /* defined(BUILDING_LIBMEMCACHED) */ - -#endif /* __LIBMEMCACHED_VISIBILITY_H__ */ diff --git a/libtest/test.c b/libtest/test.c index 9a79e4c5..afb2b965 100644 --- a/libtest/test.c +++ b/libtest/test.c @@ -24,8 +24,6 @@ #include #include -#include - #include #include @@ -370,9 +368,5 @@ cleanup: world_stats_print(&stats); -#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT - sasl_done(); -#endif - return stats.failed == 0 ? 0 : 1; } diff --git a/libtest/test.h b/libtest/test.h index 58d24373..656be169 100644 --- a/libtest/test.h +++ b/libtest/test.h @@ -217,6 +217,17 @@ do \ } \ } while (0) +#define test_compare(A,B) \ +do \ +{ \ + if ((A) != (B)) \ + { \ + fprintf(stderr, "\n%s:%d: Expected %lu == %lu\n", __FILE__, __LINE__, (unsigned long)(A), (unsigned long)(B)); \ + create_core(); \ + return TEST_FAILURE; \ + } \ +} while (0) + #define test_false(A) \ do \ { \ @@ -248,6 +259,16 @@ do \ } \ } while (0) +#define test_memcmp(A,B,C) \ +do \ +{ \ + if (memcmp((A), (B), (C))) \ + { \ + fprintf(stderr, "\n%s:%d: %.*s -> %.*s\n", __FILE__, __LINE__, (int)(C), (char *)(A), (int)(C), (char *)(B)); \ + create_core(); \ + return TEST_FAILURE; \ + } \ +} while (0) #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) diff --git a/support/libmemcached.spec.in b/support/libmemcached.spec.in index 2e93ffb9..10f9eff3 100644 --- a/support/libmemcached.spec.in +++ b/support/libmemcached.spec.in @@ -83,13 +83,13 @@ you will need to install %{name}-devel. %exclude %{_libdir}/libmemcachedutil.la %exclude %{_libdir}/libmemcachedprotocol.la %{_libdir}/libhashkit.so.1.0.0 -%{_libdir}/libmemcached.so.6.0.0 -%{_libdir}/libmemcachedutil.so.1.0.0 +%{_libdir}/libmemcached.so.7.0.0 +%{_libdir}/libmemcachedutil.so.2.0.0 %{_libdir}/libmemcachedprotocol.so.0.0.0 %{_libdir}/libhashkit.so.1 -%{_libdir}/libmemcached.so.6 +%{_libdir}/libmemcached.so.7 %{_libdir}/libmemcachedprotocol.so.0 -%{_libdir}/libmemcachedutil.so.1 +%{_libdir}/libmemcachedutil.so.2 %{_mandir}/man1/memcapable.1.gz %{_mandir}/man1/memcat.1.gz %{_mandir}/man1/memcp.1.gz @@ -188,6 +188,7 @@ you will need to install %{name}-devel. %{_mandir}/man3/libmemcached_configuration.3.gz %{_mandir}/man3/libmemcached_examples.3.gz %{_mandir}/man3/libmemcachedutil.3.gz +%{_mandir}/man3/memcached.3.gz %{_mandir}/man3/memcached_add.3.gz %{_mandir}/man3/memcached_add_by_key.3.gz %{_mandir}/man3/memcached_analyze.3.gz @@ -201,7 +202,6 @@ you will need to install %{name}-devel. %{_mandir}/man3/memcached_cas_by_key.3.gz %{_mandir}/man3/memcached_clone.3.gz %{_mandir}/man3/memcached_create.3.gz -%{_mandir}/man3/memcached_create_with_options.3.gz %{_mandir}/man3/memcached_decrement.3.gz %{_mandir}/man3/memcached_decrement_with_initial.3.gz %{_mandir}/man3/memcached_delete.3.gz diff --git a/tests/atomsmasher.c b/tests/atomsmasher.c index afdf0830..8563e4ec 100644 --- a/tests/atomsmasher.c +++ b/tests/atomsmasher.c @@ -26,8 +26,8 @@ #include #include #include -#include "../clients/generator.h" -#include "../clients/execute.h" +#include +#include #include #include diff --git a/tests/hash_plus.cc b/tests/hash_plus.cc index 140d28fc..20cf79db 100644 --- a/tests/hash_plus.cc +++ b/tests/hash_plus.cc @@ -1,13 +1,16 @@ /* C++ to libhashkit */ + +#include + #include #include #include #include -#include +#include #include "hash_results.h" diff --git a/tests/include.am b/tests/include.am index 2a3e5cb8..44954b11 100644 --- a/tests/include.am +++ b/tests/include.am @@ -67,18 +67,23 @@ tests_testapp_SOURCES= \ tests_testapp_DEPENDENCIES= \ $(BUILT_SOURCES) \ + $(TESTS_LDADDS) \ clients/libgenexec.la \ - libmemcached/libmemcachedinternal.la \ - $(TESTS_LDADDS) + libhashkit/libhashkit.la \ + libmemcached/libmemcachedinternal.la -tests_testapp_LDADD= clients/libgenexec.la \ - libmemcached/libmemcachedinternal.la \ - $(TESTS_LDADDS) $(LIBSASL) +tests_testapp_LDADD= \ + $(LIBSASL) \ + $(TESTS_LDADDS) \ + clients/libgenexec.la \ + libhashkit/libhashkit.la \ + libmemcached/libmemcachedinternal.la tests_testplus_SOURCES= tests/plus.cpp tests_testplus_CXXFLAGS = $(AM_CXXFLAGS) $(NO_EFF_CXX) tests_testplus_DEPENDENCIES= $(TESTS_LDADDS) tests_testplus_LDADD= $(tests_testplus_DEPENDENCIES) $(LIBSASL) +check_PROGRAMS+= tests/testplus tests_atomsmasher_SOURCES= tests/atomsmasher.c tests_atomsmasher_DEPENDENCIES= \ @@ -101,12 +106,12 @@ tests_startservers_LDADD= $(tests_startservers_DEPENDENCIES) $(LIBSASL) tests_testhashkit_SOURCES = tests/hashkit_functions.c tests_testhashkit_DEPENDENCIES = libtest/libtest.la libhashkit/libhashkit.la -tests_testhashkit_LDADD = $(tests_testhashkit_DEPENDENCIES) $(LIBSASL) +tests_testhashkit_LDADD = $(tests_testhashkit_DEPENDENCIES) -tests_hash_plus_SOURCES = tests/hash_plus.cc -tests_hash_plus_CXXFLAGS = $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_hash_plus_DEPENDENCIES = $(tests_testhashkit_DEPENDENCIES) -tests_hash_plus_LDADD = $(tests_testhashkit_DEPENDENCIES) $(LIBSASL) +tests_hash_plus_SOURCES= tests/hash_plus.cc +tests_hash_plus_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) +tests_hash_plus_DEPENDENCIES= $(tests_testhashkit_DEPENDENCIES) +tests_hash_plus_LDADD= $(tests_testhashkit_DEPENDENCIES) check_PROGRAMS+= tests/hash_plus test: check diff --git a/tests/libmemcached_world.h b/tests/libmemcached_world.h index 5a5e15b5..4793569c 100644 --- a/tests/libmemcached_world.h +++ b/tests/libmemcached_world.h @@ -133,6 +133,10 @@ test_return_t world_destroy(libmemcached_test_container_st *container) server_shutdown(construct); +#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT + sasl_done(); +#endif + return TEST_SUCCESS; } diff --git a/tests/mem_functions.c b/tests/mem_functions.c index a5e28e69..0400ce5a 100644 --- a/tests/mem_functions.c +++ b/tests/mem_functions.c @@ -767,8 +767,10 @@ static test_return_t flush_test(memcached_st *memc) { memcached_return_t rc; + uint64_t query_id= memcached_query_id(memc); rc= memcached_flush(memc, 0); - test_true(rc == MEMCACHED_SUCCESS); + test_compare(rc, MEMCACHED_SUCCESS); + test_compare(query_id +1, memcached_query_id(memc)); return TEST_SUCCESS; } @@ -806,18 +808,23 @@ static test_return_t bad_key_test(memcached_st *memc) size_t max_keylen= 0xffff; // Just skip if we are in binary mode. + uint64_t query_id= memcached_query_id(memc); if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) return TEST_SKIPPED; + test_compare(query_id, memcached_query_id(memc)); // We should not increase the query_id for memcached_behavior_get() memc_clone= memcached_clone(NULL, memc); test_true(memc_clone); + query_id= memcached_query_id(memc_clone); rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set); test_true(rc == MEMCACHED_SUCCESS); + test_compare(query_id, memcached_query_id(memc_clone)); // We should not increase the query_id for memcached_behavior_set() /* All keys are valid in the binary protocol (except for length) */ if (memcached_behavior_get(memc_clone, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 0) { + query_id= memcached_query_id(memc_clone); string= memcached_get(memc_clone, key, strlen(key), &string_length, &flags, &rc); test_true(rc == MEMCACHED_BAD_KEY_PROVIDED); @@ -825,7 +832,9 @@ static test_return_t bad_key_test(memcached_st *memc) test_true(!string); set= 0; + query_id= memcached_query_id(memc_clone); rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set); + test_compare(query_id, memcached_query_id(memc_clone)); // We should not increase the query_id for memcached_behavior_set() test_true(rc == MEMCACHED_SUCCESS); string= memcached_get(memc_clone, key, strlen(key), &string_length, &flags, &rc); @@ -837,14 +846,20 @@ static test_return_t bad_key_test(memcached_st *memc) const char *keys[] = { "GoodKey", "Bad Key", "NotMine" }; size_t key_lengths[] = { 7, 7, 7 }; set= 1; + query_id= memcached_query_id(memc_clone); rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set); test_true(rc == MEMCACHED_SUCCESS); + test_compare(query_id, memcached_query_id(memc_clone)); + query_id= memcached_query_id(memc_clone); rc= memcached_mget(memc_clone, keys, key_lengths, 3); test_true(rc == MEMCACHED_BAD_KEY_PROVIDED); + test_compare(query_id +1, memcached_query_id(memc_clone)); + query_id= memcached_query_id(memc_clone); rc= memcached_mget_by_key(memc_clone, "foo daddy", 9, keys, key_lengths, 1); test_true(rc == MEMCACHED_BAD_KEY_PROVIDED); + test_compare(query_id +1, memcached_query_id(memc_clone)); max_keylen= 250; @@ -970,8 +985,10 @@ static test_return_t get_test(memcached_st *memc) size_t string_length; uint32_t flags; + uint64_t query_id= memcached_query_id(memc); rc= memcached_delete(memc, key, strlen(key), (time_t)0); test_true(rc == MEMCACHED_BUFFERED || rc == MEMCACHED_NOTFOUND); + test_compare(query_id +1, memcached_query_id(memc)); string= memcached_get(memc, key, strlen(key), &string_length, &flags, &rc); @@ -992,18 +1009,22 @@ static test_return_t get_test2(memcached_st *memc) size_t string_length; uint32_t flags; + uint64_t query_id= memcached_query_id(memc); rc= memcached_set(memc, key, strlen(key), value, strlen(value), (time_t)0, (uint32_t)0); test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + test_compare(query_id +1, memcached_query_id(memc)); + query_id= memcached_query_id(memc); string= memcached_get(memc, key, strlen(key), &string_length, &flags, &rc); + test_compare(query_id +1, memcached_query_id(memc)); test_true(string); test_true(rc == MEMCACHED_SUCCESS); test_true(string_length == strlen(value)); - test_true(!memcmp(string, value, string_length)); + test_memcmp(string, value, string_length); free(string); @@ -1034,25 +1055,26 @@ static test_return_t set_test3(memcached_st *memc) memcached_return_t rc; char *value; size_t value_length= 8191; - unsigned int x; value = (char*)malloc(value_length); test_true(value); - for (x= 0; x < value_length; x++) + for (uint32_t x= 0; x < value_length; x++) value[x] = (char) (x % 127); /* The dump test relies on there being at least 32 items in memcached */ - for (x= 0; x < 32; x++) + for (uint32_t x= 0; x < 32; x++) { char key[16]; snprintf(key, sizeof(key), "foo%u", x); + uint64_t query_id= memcached_query_id(memc); rc= memcached_set(memc, key, strlen(key), value, value_length, (time_t)0, (uint32_t)0); test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + test_compare(query_id +1, memcached_query_id(memc)); } free(value); @@ -1720,8 +1742,10 @@ static test_return_t mget_execute(memcached_st *memc) key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%lu", (unsigned long)x); keys[x]= strdup(k); test_true(keys[x] != NULL); + uint64_t query_id= memcached_query_id(memc); rc= memcached_add(memc, keys[x], key_length[x], blob, sizeof(blob), 0, 0); test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + test_compare(query_id +1, memcached_query_id(memc)); } /* Try to get all of them with a large multiget */ @@ -1733,8 +1757,10 @@ static test_return_t mget_execute(memcached_st *memc) if (rc == MEMCACHED_SUCCESS) { test_true(binary); + uint64_t query_id= memcached_query_id(memc); rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1); test_true(rc == MEMCACHED_END); + test_compare(query_id, memcached_query_id(memc)); /* Verify that we got all of the items */ test_true(counter == max_keys); @@ -2257,7 +2283,7 @@ static test_return_t user_supplied_bug4(memcached_st *memc) /* We need to empty the server before continueing test */ rc= memcached_flush(memc, 0); - test_true(rc == MEMCACHED_NO_SERVERS); + test_compare(rc, MEMCACHED_NO_SERVERS); rc= memcached_mget(memc, keys, key_length, 3); test_true(rc == MEMCACHED_NO_SERVERS); @@ -2267,7 +2293,7 @@ static test_return_t user_supplied_bug4(memcached_st *memc) { test_true(return_value); } - test_true(!return_value); + test_false(return_value); test_true(return_value_length == 0); test_true(rc == MEMCACHED_NO_SERVERS); @@ -2289,7 +2315,7 @@ static test_return_t user_supplied_bug4(memcached_st *memc) test_true(return_value); test_true(rc == MEMCACHED_SUCCESS); test_true(return_key_length == return_value_length); - test_true(!memcmp(return_value, return_key, return_value_length)); + test_memcmp(return_value, return_key, return_value_length); free(return_value); x++; } @@ -4310,6 +4336,7 @@ static void* connection_release(void *arg) } *resource= arg; usleep(250); + // Release all of the memc we are holding assert(memcached_pool_push(resource->pool, resource->mmc) == MEMCACHED_SUCCESS); return arg; } @@ -4322,6 +4349,7 @@ static test_return_t connection_pool_test(memcached_st *memc) memcached_st *mmc[POOL_SIZE]; memcached_return_t rc; + // Fill up our array that we will store the memc that are in the pool for (size_t x= 0; x < POOL_SIZE; ++x) { mmc[x]= memcached_pool_pop(pool, false, &rc); @@ -4329,6 +4357,7 @@ static test_return_t connection_pool_test(memcached_st *memc) test_true(rc == MEMCACHED_SUCCESS); } + // All memc should be gone test_true(memcached_pool_pop(pool, false, &rc) == NULL); test_true(rc == MEMCACHED_SUCCESS); @@ -4337,11 +4366,12 @@ static test_return_t connection_pool_test(memcached_st *memc) memcached_pool_st* pool; memcached_st* mmc; } item= { .pool = pool, .mmc = mmc[9] }; + pthread_create(&tid, NULL, connection_release, &item); mmc[9]= memcached_pool_pop(pool, true, &rc); test_true(rc == MEMCACHED_SUCCESS); pthread_join(tid, NULL); - test_true(mmc[9] == item.mmc); + test_true(mmc[9]); const char *key= "key"; size_t keylen= strlen(key); @@ -6291,7 +6321,7 @@ collection_st collection[] ={ {0, 0, 0, 0} }; -#include "libmemcached_world.h" +#include "tests/libmemcached_world.h" void get_world(world_st *world) { diff --git a/tests/plus.cpp b/tests/plus.cpp index c0c6bb95..c4b67115 100644 --- a/tests/plus.cpp +++ b/tests/plus.cpp @@ -1,17 +1,16 @@ /* C++ interface test */ -#include "libmemcached/memcached.hpp" +#include -#include -#include -#include -#include +#include +#include +#include #include #include #include #include -#include +#include #include @@ -44,7 +43,7 @@ static void populate_vector(vector &vec, const string &str) static void copy_vec_to_string(vector &vec, string &str) { str.clear(); - if (! vec.empty()) + if (not vec.empty()) { str.assign(vec.begin(), vec.end()); } @@ -59,31 +58,18 @@ test_return_t basic_test(memcached_st *memc) populate_vector(value, value_set); - foo.set("mine", value, 0, 0); - foo.get("mine", test_value); + test_true(foo.set("mine", value, 0, 0)); + test_true(foo.get("mine", test_value)); - assert((memcmp(&test_value[0], &value[0], test_value.size()) == 0)); + test_memcmp(&test_value[0], &value[0], test_value.size()); + test_false(foo.set("", value, 0, 0)); - /* - * Simple test of the exceptions here...this should throw an exception - * saying that the key is empty. - */ - try - { - foo.set("", value, 0, 0); - } - catch (Error &err) - { - return TEST_SUCCESS; - } - - return TEST_FAILURE; + return TEST_SUCCESS; } -test_return_t increment_test(memcached_st *memc) +test_return_t increment_test(memcached_st *original) { - Memcache mcach(memc); - bool rc; + Memcache mcach(original); const string key("blah"); const string inc_value("1"); std::vector inc_val; @@ -94,40 +80,31 @@ test_return_t increment_test(memcached_st *memc) populate_vector(inc_val, inc_value); - rc= mcach.set(key, inc_val, 0, 0); - if (rc == false) - { - return TEST_FAILURE; - } - mcach.get(key, ret_value); - if (ret_value.empty()) - { - return TEST_FAILURE; - } + test_true(mcach.set(key, inc_val, 0, 0)); + + test_true(mcach.get(key, ret_value)); + test_false(ret_value.empty()); copy_vec_to_string(ret_value, ret_string); int_inc_value= uint64_t(atol(inc_value.c_str())); int_ret_value= uint64_t(atol(ret_string.c_str())); - assert(int_ret_value == int_inc_value); + test_compare(int_inc_value, int_ret_value); - rc= mcach.increment(key, 1, &int_ret_value); - assert(rc == true); - assert(int_ret_value == 2); + test_true(mcach.increment(key, 1, &int_ret_value)); + test_compare(2, int_ret_value); - rc= mcach.increment(key, 1, &int_ret_value); - assert(rc == true); - assert(int_ret_value == 3); + test_true(mcach.increment(key, 1, &int_ret_value)); + test_compare(3, int_ret_value); - rc= mcach.increment(key, 5, &int_ret_value); - assert(rc == true); - assert(int_ret_value == 8); + test_true(mcach.increment(key, 5, &int_ret_value)); + test_compare(8, int_ret_value); return TEST_SUCCESS; } -test_return_t basic_master_key_test(memcached_st *memc) +test_return_t basic_master_key_test(memcached_st *original) { - Memcache foo(memc); + Memcache foo(original); const string value_set("Data for server A"); vector value; vector test_value; @@ -140,12 +117,12 @@ test_return_t basic_master_key_test(memcached_st *memc) foo.setByKey(master_key_a, key, value, 0, 0); foo.getByKey(master_key_a, key, test_value); - assert((memcmp(&value[0], &test_value[0], value.size()) == 0)); + test_true((memcmp(&value[0], &test_value[0], value.size()) == 0)); test_value.clear(); foo.getByKey(master_key_b, key, test_value); - assert((memcmp(&value[0], &test_value[0], value.size()) == 0)); + test_true((memcmp(&value[0], &test_value[0], value.size()) == 0)); return TEST_SUCCESS; } @@ -162,53 +139,9 @@ memcached_return_t callback_counter(const memcached_st *, return MEMCACHED_SUCCESS; } -test_return_t mget_result_function(memcached_st *memc) -{ - Memcache mc(memc); - bool rc; - string key1("fudge"); - string key2("son"); - string key3("food"); - vector keys; - vector< vector *> values; - vector val1; - vector val2; - vector val3; - populate_vector(val1, key1); - populate_vector(val2, key2); - populate_vector(val3, key3); - keys.reserve(3); - keys.push_back(key1); - keys.push_back(key2); - keys.push_back(key3); - values.reserve(3); - values.push_back(&val1); - values.push_back(&val2); - values.push_back(&val3); - unsigned int counter; - memcached_execute_fn callbacks[1]; - - /* We need to empty the server before we continue the test */ - rc= mc.flush(0); - rc= mc.setAll(keys, values, 50, 9); - assert(rc == true); - - rc= mc.mget(keys); - assert(rc == true); - - callbacks[0]= &callback_counter; - counter= 0; - rc= mc.fetchExecute(callbacks, static_cast(&counter), 1); - - assert(counter == 3); - - return TEST_SUCCESS; -} - -test_return_t mget_test(memcached_st *memc) +test_return_t mget_test(memcached_st *original) { - Memcache mc(memc); - bool rc; + Memcache memc(original); memcached_return_t mc_rc; vector keys; vector< vector *> values; @@ -231,43 +164,37 @@ test_return_t mget_test(memcached_st *memc) vector return_value; /* We need to empty the server before we continue the test */ - rc= mc.flush(0); - assert(rc == true); + test_true(memc.flush(0)); - rc= mc.mget(keys); - assert(rc == true); + test_true(memc.mget(keys)); - while ((mc_rc= mc.fetch(return_key, return_value)) != MEMCACHED_END) + while ((mc_rc= memc.fetch(return_key, return_value)) != MEMCACHED_END) { - assert(return_value.size() != 0); + test_true(return_value.size()); return_value.clear(); } - assert(mc_rc == MEMCACHED_END); + test_compare(mc_rc, MEMCACHED_END); - rc= mc.setAll(keys, values, 50, 9); - assert(rc == true); + test_true(memc.setAll(keys, values, 50, 9)); - rc= mc.mget(keys); - assert(rc == true); + test_true(memc.mget(keys)); - while ((mc_rc= mc.fetch(return_key, return_value)) != MEMCACHED_END) + while ((mc_rc= memc.fetch(return_key, return_value)) != MEMCACHED_END) { - assert(return_key.length() == return_value.size()); - assert(!memcmp(&return_value[0], return_key.c_str(), return_value.size())); + test_compare(return_key.length(), return_value.size()); + test_memcmp(&return_value[0], return_key.c_str(), return_value.size()); } return TEST_SUCCESS; } -test_return_t basic_behavior(memcached_st *memc) +test_return_t basic_behavior(memcached_st *original) { - Memcache mc(memc); - bool rc; - uint64_t value = 1; - rc = mc.setBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY, value); - assert(rc); - uint64_t behavior = mc.getBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY); - assert(behavior == value); + Memcache memc(original); + uint64_t value= 1; + test_true(memc.setBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY, value)); + uint64_t behavior= memc.getBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY); + test_compare(behavior, value); return TEST_SUCCESS; } @@ -281,8 +208,6 @@ test_st tests[] ={ reinterpret_cast(increment_test) }, { "mget", 1, reinterpret_cast(mget_test) }, - { "mget_result_function", 1, - reinterpret_cast(mget_result_function) }, { "basic_behavior", 0, reinterpret_cast(basic_behavior) }, {0, 0, 0} diff --git a/tests/string.cc b/tests/string.cc index 35d6eb41..aa8a7d6f 100644 --- a/tests/string.cc +++ b/tests/string.cc @@ -35,9 +35,11 @@ * */ -#include "libmemcached/common.h" -#include "libmemcached/error.h" -#include "tests/string.h" +#define BUILDING_LIBMEMCACHED + +#include +#include +#include test_return_t string_static_null(memcached_st *memc) {