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
find . -name '*.gcno' | xargs rm -f
find . -name '*.gcda' | xargs rm -f
-CLEANFILES+= config/top.h
-
-
+DISTCLEANFILES+= config/top.h
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-/*
- 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;
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+/*
+ 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;
+}
*
*/
-#ifndef CLIENTS_EXECUTE_H
-#define CLIENTS_EXECUTE_H
+#pragma once
#include <stdio.h>
#include "libmemcached/memcached.h"
-#include "generator.h"
+#include "clients/generator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of);
unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of);
unsigned int execute_mget(memcached_st *memc, const char * const *keys, size_t *key_length,
unsigned int number_of);
-#endif
+#ifdef __cplusplus
+} // extern "C"
+#endif
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "generator.h"
-
-/* Use this for string generation */
-static const char ALPHANUMERICS[]=
- "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
-
-#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
-
-static size_t get_alpha_num(void)
-{
- return (size_t)random() % ALPHANUMERICS_SIZE;
-}
-
-static void get_random_string(char *buffer, size_t size)
-{
- char *buffer_ptr= buffer;
-
- while (--size)
- *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
- *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
-}
-
-void pairs_free(pairs_st *pairs)
-{
- uint32_t x;
-
- if (! pairs)
- return;
-
- /* We free until we hit the null pair we stores during creation */
- for (x= 0; pairs[x].key; x++)
- {
- free(pairs[x].key);
- if (pairs[x].value)
- free(pairs[x].value);
- }
-
- free(pairs);
-}
-
-pairs_st *pairs_generate(uint64_t number_of, size_t value_length)
-{
- unsigned int x;
- pairs_st *pairs;
-
- pairs= (pairs_st*)calloc((size_t)number_of + 1, sizeof(pairs_st));
-
- if (!pairs)
- goto error;
-
- for (x= 0; x < number_of; x++)
- {
- pairs[x].key= (char *)calloc(100, sizeof(char));
- if (!pairs[x].key)
- goto error;
- get_random_string(pairs[x].key, 100);
- pairs[x].key_length= 100;
-
- if (value_length)
- {
- pairs[x].value= (char *)calloc(value_length, sizeof(char));
- if (!pairs[x].value)
- goto error;
- get_random_string(pairs[x].value, value_length);
- pairs[x].value_length= value_length;
- }
- else
- {
- pairs[x].value= NULL;
- pairs[x].value_length= 0;
- }
- }
-
- return pairs;
-error:
- fprintf(stderr, "Memory Allocation failure in pairs_generate.\n");
- exit(0);
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "generator.h"
+
+/* Use this for string generation */
+static const char ALPHANUMERICS[]=
+ "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
+
+#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
+
+static size_t get_alpha_num(void)
+{
+ return (size_t)random() % ALPHANUMERICS_SIZE;
+}
+
+static void get_random_string(char *buffer, size_t size)
+{
+ char *buffer_ptr= buffer;
+
+ while (--size)
+ *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
+ *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
+}
+
+void pairs_free(pairs_st *pairs)
+{
+ uint32_t x;
+
+ if (! pairs)
+ return;
+
+ /* We free until we hit the null pair we stores during creation */
+ for (x= 0; pairs[x].key; x++)
+ {
+ free(pairs[x].key);
+ if (pairs[x].value)
+ free(pairs[x].value);
+ }
+
+ free(pairs);
+}
+
+pairs_st *pairs_generate(uint64_t number_of, size_t value_length)
+{
+ unsigned int x;
+ pairs_st *pairs;
+
+ pairs= (pairs_st*)calloc((size_t)number_of + 1, sizeof(pairs_st));
+
+ if (!pairs)
+ goto error;
+
+ for (x= 0; x < number_of; x++)
+ {
+ pairs[x].key= (char *)calloc(100, sizeof(char));
+ if (!pairs[x].key)
+ goto error;
+ get_random_string(pairs[x].key, 100);
+ pairs[x].key_length= 100;
+
+ if (value_length)
+ {
+ pairs[x].value= (char *)calloc(value_length, sizeof(char));
+ if (!pairs[x].value)
+ goto error;
+ get_random_string(pairs[x].value, value_length);
+ pairs[x].value_length= value_length;
+ }
+ else
+ {
+ pairs[x].value= NULL;
+ pairs[x].value_length= 0;
+ }
+ }
+
+ return pairs;
+error:
+ fprintf(stderr, "Memory Allocation failure in pairs_generate.\n");
+ exit(0);
+}
Code to generate data to be pushed into memcached
*/
-#ifndef __GENERATOR_H__
-#define __GENERATOR_H__
+#pragma once
typedef struct pairs_st 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
# 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)
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
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#undef NDEBUG
-#include "config.h"
-#include <pthread.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <assert.h>
-#include <string.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include <libmemcached/memcached.h>
-#include <libmemcached/memcached/protocol_binary.h>
-#include <libmemcached/byteorder.h>
-#include "utilities.h"
-
-#ifdef linux
-/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
- * optimize the conversion functions, but the prototypes generate warnings
- * from gcc. The conversion methods isn't the bottleneck for my app, so
- * just remove the warnings by undef'ing the optimization ..
- */
-#undef ntohs
-#undef ntohl
-#endif
-
-/* Should we generate coredumps when we enounter an error (-c) */
-static bool do_core= false;
-/* connection to the server */
-static memcached_socket_t sock;
-/* Should the output from test failures be verbose or quiet? */
-static bool verbose= false;
-
-/* The number of seconds to wait for an IO-operation */
-static int timeout= 2;
-
-/*
- * Instead of having to cast between the different datatypes we create
- * a union of all of the different types of pacages we want to send.
- * A lot of the different commands use the same packet layout, so I'll
- * just define the different types I need. The typedefs only contain
- * the header of the message, so we need some space for keys and body
- * To avoid to have to do multiple writes, lets add a chunk of memory
- * to use. 1k should be more than enough for header, key and body.
- */
-typedef union
-{
- protocol_binary_request_no_extras plain;
- protocol_binary_request_flush flush;
- protocol_binary_request_incr incr;
- protocol_binary_request_set set;
- char bytes[1024];
-} command;
-
-typedef union
-{
- protocol_binary_response_no_extras plain;
- protocol_binary_response_incr incr;
- protocol_binary_response_decr decr;
- char bytes[1024];
-} response;
-
-enum test_return
-{
- TEST_SKIP, TEST_PASS, TEST_PASS_RECONNECT, TEST_FAIL
-};
-
-/**
- * Try to get an addrinfo struct for a given port on a given host
- */
-static struct addrinfo *lookuphost(const char *hostname, const char *port)
-{
- struct addrinfo *ai= 0;
- struct addrinfo hints= {.ai_family=AF_UNSPEC,
- .ai_protocol=IPPROTO_TCP,
- .ai_socktype=SOCK_STREAM};
- int error= getaddrinfo(hostname, port, &hints, &ai);
-
- if (error != 0)
- {
- if (error != EAI_SYSTEM)
- fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
- else
- perror("getaddrinfo()");
- }
-
- return ai;
-}
-
-/**
- * Set the socket in nonblocking mode
- * @return -1 if failure, the socket otherwise
- */
-static memcached_socket_t set_noblock(void)
-{
-#ifdef WIN32
- u_long arg = 1;
- if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
- {
- perror("Failed to set nonblocking io");
- closesocket(sock);
- return INVALID_SOCKET;
- }
-#else
- int flags= fcntl(sock, F_GETFL, 0);
- if (flags == -1)
- {
- perror("Failed to get socket flags");
- closesocket(sock);
- return INVALID_SOCKET;
- }
-
- if ((flags & O_NONBLOCK) != O_NONBLOCK)
- {
- if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
- {
- perror("Failed to set socket to nonblocking mode");
- closesocket(sock);
- return INVALID_SOCKET;
- }
- }
-#endif
- return sock;
-}
-
-/**
- * Try to open a connection to the server
- * @param hostname the name of the server to connect to
- * @param port the port number (or service) to connect to
- * @return positive integer if success, -1 otherwise
- */
-static memcached_socket_t connect_server(const char *hostname, const char *port)
-{
- struct addrinfo *ai= lookuphost(hostname, port);
- sock= INVALID_SOCKET;
- if (ai != NULL)
- {
- if ((sock= socket(ai->ai_family, ai->ai_socktype,
- ai->ai_protocol)) != INVALID_SOCKET)
- {
- if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR)
- {
- fprintf(stderr, "Failed to connect socket: %s\n",
- strerror(get_socket_errno()));
- closesocket(sock);
- sock= INVALID_SOCKET;
- }
- else
- {
- sock= set_noblock();
- }
- }
- else
- fprintf(stderr, "Failed to create socket: %s\n",
- strerror(get_socket_errno()));
-
- freeaddrinfo(ai);
- }
-
- return sock;
-}
-
-static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len)
-{
- ssize_t ret;
-
- if (direction == POLLOUT)
- ret= send(fd, buf, len, 0);
- else
- ret= recv(fd, buf, len, 0);
-
- if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK) {
- struct pollfd fds= {
- .events= direction,
- .fd= fd
- };
-
- int err= poll(&fds, 1, timeout * 1000);
-
- if (err == 1)
- {
- if (direction == POLLOUT)
- ret= send(fd, buf, len, 0);
- else
- ret= recv(fd, buf, len, 0);
- }
- else if (err == 0)
- {
- errno= ETIMEDOUT;
- }
- else
- {
- perror("Failed to poll");
- return -1;
- }
- }
-
- return ret;
-}
-
-/**
- * Ensure that an expression is true. If it isn't print out a message similar
- * to assert() and create a coredump if the user wants that. If not an error
- * message is returned.
- *
- */
-static enum test_return ensure(bool val, const char *expression, const char *file, int line)
-{
- if (!val)
- {
- if (verbose)
- fprintf(stderr, "\n%s:%d: %s", file, line, expression);
-
- if (do_core)
- abort();
-
- return TEST_FAIL;
- }
-
- return TEST_PASS;
-}
-
-#define verify(expression) do { if (ensure(expression, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
-#define execute(expression) do { if (ensure(expression == TEST_PASS, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
-
-/**
- * Send a chunk of memory over the socket (retry if the call is iterrupted
- */
-static enum test_return retry_write(const void* buf, size_t len)
-{
- size_t offset= 0;
- const char* ptr= buf;
-
- do
- {
- size_t num_bytes= len - offset;
- ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes);
- if (nw == -1)
- verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
- else
- offset+= (size_t)nw;
- } while (offset < len);
-
- return TEST_PASS;
-}
-
-/**
- * Resend a packet to the server (All fields in the command header should
- * be in network byte order)
- */
-static enum test_return resend_packet(command *cmd)
-{
- size_t length= sizeof (protocol_binary_request_no_extras) +
- ntohl(cmd->plain.message.header.request.bodylen);
-
- execute(retry_write(cmd, length));
- return TEST_PASS;
-}
-
-/**
- * Send a command to the server. The command header needs to be updated
- * to network byte order
- */
-static enum test_return send_packet(command *cmd)
-{
- /* Fix the byteorder of the header */
- cmd->plain.message.header.request.keylen=
- ntohs(cmd->plain.message.header.request.keylen);
- cmd->plain.message.header.request.bodylen=
- ntohl(cmd->plain.message.header.request.bodylen);
- cmd->plain.message.header.request.cas=
- ntohll(cmd->plain.message.header.request.cas);
-
- execute(resend_packet(cmd));
- return TEST_PASS;
-}
-
-/**
- * Read a fixed length chunk of data from the server
- */
-static enum test_return retry_read(void *buf, size_t len)
-{
- size_t offset= 0;
- do
- {
- ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset);
- switch (nr) {
- case -1 :
- fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno));
- verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
- break;
- case 0:
- return TEST_FAIL;
- default:
- offset+= (size_t)nr;
- }
- } while (offset < len);
-
- return TEST_PASS;
-}
-
-/**
- * Receive a response from the server and conver the fields in the header
- * to local byte order
- */
-static enum test_return recv_packet(response *rsp)
-{
- execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras)));
-
- /* Fix the byte order in the packet header */
- rsp->plain.message.header.response.keylen=
- ntohs(rsp->plain.message.header.response.keylen);
- rsp->plain.message.header.response.status=
- ntohs(rsp->plain.message.header.response.status);
- rsp->plain.message.header.response.bodylen=
- ntohl(rsp->plain.message.header.response.bodylen);
- rsp->plain.message.header.response.cas=
- ntohll(rsp->plain.message.header.response.cas);
-
- size_t bodysz= rsp->plain.message.header.response.bodylen;
- if (bodysz > 0)
- execute(retry_read(rsp->bytes + sizeof (protocol_binary_response_no_extras), bodysz));
-
- return TEST_PASS;
-}
-
-/**
- * Create a storage command (add, set, replace etc)
- *
- * @param cmd destination buffer
- * @param cc the storage command to create
- * @param key the key to store
- * @param keylen the length of the key
- * @param dta the data to store with the key
- * @param dtalen the length of the data to store with the key
- * @param flags the flags to store along with the key
- * @param exptime the expiry time for the key
- */
-static void storage_command(command *cmd,
- uint8_t cc,
- const void* key,
- size_t keylen,
- const void* dta,
- size_t dtalen,
- uint32_t flags,
- uint32_t exptime)
-{
- /* all of the storage commands use the same command layout */
- protocol_binary_request_set *request= &cmd->set;
-
- memset(request, 0, sizeof (*request));
- request->message.header.request.magic= PROTOCOL_BINARY_REQ;
- request->message.header.request.opcode= cc;
- request->message.header.request.keylen= (uint16_t)keylen;
- request->message.header.request.extlen= 8;
- request->message.header.request.bodylen= (uint32_t)(keylen + 8 + dtalen);
- request->message.header.request.opaque= 0xdeadbeef;
- request->message.body.flags= flags;
- request->message.body.expiration= exptime;
-
- off_t key_offset= sizeof (protocol_binary_request_no_extras) + 8;
- memcpy(cmd->bytes + key_offset, key, keylen);
- if (dta != NULL)
- memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
-}
-
-/**
- * Create a basic command to send to the server
- * @param cmd destination buffer
- * @param cc the command to create
- * @param key the key to store
- * @param keylen the length of the key
- * @param dta the data to store with the key
- * @param dtalen the length of the data to store with the key
- */
-static void raw_command(command *cmd,
- uint8_t cc,
- const void* key,
- size_t keylen,
- const void* dta,
- size_t dtalen)
-{
- /* all of the storage commands use the same command layout */
- memset(cmd, 0, sizeof (*cmd));
- cmd->plain.message.header.request.magic= PROTOCOL_BINARY_REQ;
- cmd->plain.message.header.request.opcode= cc;
- cmd->plain.message.header.request.keylen= (uint16_t)keylen;
- cmd->plain.message.header.request.bodylen= (uint32_t)(keylen + dtalen);
- cmd->plain.message.header.request.opaque= 0xdeadbeef;
-
- off_t key_offset= sizeof (protocol_binary_request_no_extras);
-
- if (key != NULL)
- memcpy(cmd->bytes + key_offset, key, keylen);
-
- if (dta != NULL)
- memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
-}
-
-/**
- * Create the flush command
- * @param cmd destination buffer
- * @param cc the command to create (FLUSH/FLUSHQ)
- * @param exptime when to flush
- * @param use_extra to force using of the extra field?
- */
-static void flush_command(command *cmd,
- uint8_t cc, uint32_t exptime, bool use_extra)
-{
- memset(cmd, 0, sizeof (cmd->flush));
- cmd->flush.message.header.request.magic= PROTOCOL_BINARY_REQ;
- cmd->flush.message.header.request.opcode= cc;
- cmd->flush.message.header.request.opaque= 0xdeadbeef;
-
- if (exptime != 0 || use_extra)
- {
- cmd->flush.message.header.request.extlen= 4;
- cmd->flush.message.body.expiration= htonl(exptime);
- cmd->flush.message.header.request.bodylen= 4;
- }
-}
-
-/**
- * Create a incr/decr command
- * @param cc the cmd to create (FLUSH/FLUSHQ)
- * @param key the key to operate on
- * @param keylen the number of bytes in the key
- * @param delta the number to add/subtract
- * @param initial the initial value if the key doesn't exist
- * @param exptime when the key should expire if it isn't set
- */
-static void arithmetic_command(command *cmd,
- uint8_t cc,
- const void* key,
- size_t keylen,
- uint64_t delta,
- uint64_t initial,
- uint32_t exptime)
-{
- memset(cmd, 0, sizeof (cmd->incr));
- cmd->incr.message.header.request.magic= PROTOCOL_BINARY_REQ;
- cmd->incr.message.header.request.opcode= cc;
- cmd->incr.message.header.request.keylen= (uint16_t)keylen;
- cmd->incr.message.header.request.extlen= 20;
- cmd->incr.message.header.request.bodylen= (uint32_t)(keylen + 20);
- cmd->incr.message.header.request.opaque= 0xdeadbeef;
- cmd->incr.message.body.delta= htonll(delta);
- cmd->incr.message.body.initial= htonll(initial);
- cmd->incr.message.body.expiration= htonl(exptime);
-
- off_t key_offset= sizeof (protocol_binary_request_no_extras) + 20;
- memcpy(cmd->bytes + key_offset, key, keylen);
-}
-
-/**
- * Validate the response header from the server
- * @param rsp the response to check
- * @param cc the expected command
- * @param status the expected status
- */
-static enum test_return do_validate_response_header(response *rsp,
- uint8_t cc, uint16_t status)
-{
- verify(rsp->plain.message.header.response.magic == PROTOCOL_BINARY_RES);
- verify(rsp->plain.message.header.response.opcode == cc);
- verify(rsp->plain.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
- verify(rsp->plain.message.header.response.status == status);
- verify(rsp->plain.message.header.response.opaque == 0xdeadbeef);
-
- if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS)
- {
- switch (cc) {
- case PROTOCOL_BINARY_CMD_ADDQ:
- case PROTOCOL_BINARY_CMD_APPENDQ:
- case PROTOCOL_BINARY_CMD_DECREMENTQ:
- case PROTOCOL_BINARY_CMD_DELETEQ:
- case PROTOCOL_BINARY_CMD_FLUSHQ:
- case PROTOCOL_BINARY_CMD_INCREMENTQ:
- case PROTOCOL_BINARY_CMD_PREPENDQ:
- case PROTOCOL_BINARY_CMD_QUITQ:
- case PROTOCOL_BINARY_CMD_REPLACEQ:
- case PROTOCOL_BINARY_CMD_SETQ:
- verify("Quiet command shouldn't return on success" == NULL);
- default:
- break;
- }
-
- switch (cc) {
- case PROTOCOL_BINARY_CMD_ADD:
- case PROTOCOL_BINARY_CMD_REPLACE:
- case PROTOCOL_BINARY_CMD_SET:
- case PROTOCOL_BINARY_CMD_APPEND:
- case PROTOCOL_BINARY_CMD_PREPEND:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- verify(rsp->plain.message.header.response.bodylen == 0);
- verify(rsp->plain.message.header.response.cas != 0);
- break;
- case PROTOCOL_BINARY_CMD_FLUSH:
- case PROTOCOL_BINARY_CMD_NOOP:
- case PROTOCOL_BINARY_CMD_QUIT:
- case PROTOCOL_BINARY_CMD_DELETE:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- verify(rsp->plain.message.header.response.bodylen == 0);
- verify(rsp->plain.message.header.response.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_DECREMENT:
- case PROTOCOL_BINARY_CMD_INCREMENT:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- verify(rsp->plain.message.header.response.bodylen == 8);
- verify(rsp->plain.message.header.response.cas != 0);
- break;
-
- case PROTOCOL_BINARY_CMD_STAT:
- verify(rsp->plain.message.header.response.extlen == 0);
- /* key and value exists in all packets except in the terminating */
- verify(rsp->plain.message.header.response.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_VERSION:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- verify(rsp->plain.message.header.response.bodylen != 0);
- verify(rsp->plain.message.header.response.cas == 0);
- break;
-
- case PROTOCOL_BINARY_CMD_GET:
- case PROTOCOL_BINARY_CMD_GETQ:
- verify(rsp->plain.message.header.response.keylen == 0);
- verify(rsp->plain.message.header.response.extlen == 4);
- verify(rsp->plain.message.header.response.cas != 0);
- break;
-
- case PROTOCOL_BINARY_CMD_GETK:
- case PROTOCOL_BINARY_CMD_GETKQ:
- verify(rsp->plain.message.header.response.keylen != 0);
- verify(rsp->plain.message.header.response.extlen == 4);
- verify(rsp->plain.message.header.response.cas != 0);
- break;
-
- default:
- /* Undefined command code */
- break;
- }
- }
- else
- {
- verify(rsp->plain.message.header.response.cas == 0);
- verify(rsp->plain.message.header.response.extlen == 0);
- if (cc != PROTOCOL_BINARY_CMD_GETK)
- {
- verify(rsp->plain.message.header.response.keylen == 0);
- }
- }
-
- return TEST_PASS;
-}
-
-/* We call verify(validate_response_header), but that macro
- * expects a boolean expression, and the function returns
- * an enum.... Let's just create a macro to avoid cluttering
- * the code with all of the == TEST_PASS ;-)
- */
-#define validate_response_header(a,b,c) \
- do_validate_response_header(a,b,c) == TEST_PASS
-
-
-static enum test_return send_binary_noop(void)
-{
- command cmd;
- raw_command(&cmd, PROTOCOL_BINARY_CMD_NOOP, NULL, 0, NULL, 0);
- execute(send_packet(&cmd));
- return TEST_PASS;
-}
-
-static enum test_return receive_binary_noop(void)
-{
- response rsp;
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_NOOP,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- return TEST_PASS;
-}
-
-static enum test_return test_binary_noop(void)
-{
- execute(send_binary_noop());
- execute(receive_binary_noop());
- return TEST_PASS;
-}
-
-static enum test_return test_binary_quit_impl(uint8_t cc)
-{
- command cmd;
- response rsp;
- raw_command(&cmd, cc, NULL, 0, NULL, 0);
-
- execute(send_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_QUIT)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_QUIT,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
-
- /* Socket should be closed now, read should return EXIT_SUCCESS */
- verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0);
-
- return TEST_PASS_RECONNECT;
-}
-
-static enum test_return test_binary_quit(void)
-{
- return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
-}
-
-static enum test_return test_binary_quitq(void)
-{
- return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
-}
-
-static enum test_return test_binary_set_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
-
- uint64_t value= 0xdeadbeefdeadcafe;
- storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
-
- /* set should always work */
- for (int ii= 0; ii < 10; ii++)
- {
- if (ii == 0)
- execute(send_packet(&cmd));
- else
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_SET)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- execute(test_binary_noop());
- }
-
- /*
- * We need to get the current CAS id, and at this time we haven't
- * verified that we have a working get
- */
- if (cc == PROTOCOL_BINARY_CMD_SETQ)
- {
- cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET;
- execute(resend_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
- }
-
- /* try to set with the correct CAS value */
- cmd.plain.message.header.request.cas=
- htonll(rsp.plain.message.header.response.cas);
- execute(resend_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_SET)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- execute(test_binary_noop());
-
- /* try to set with an incorrect CAS value */
- cmd.plain.message.header.request.cas=
- htonll(rsp.plain.message.header.response.cas - 1);
- execute(resend_packet(&cmd));
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
- execute(receive_binary_noop());
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_set(void)
-{
- return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
-}
-
-static enum test_return test_binary_setq(void)
-{
- return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
-}
-
-static enum test_return test_binary_add_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
- uint64_t value= 0xdeadbeefdeadcafe;
- storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
-
- /* first add should work, rest of them should fail (even with cas
- as wildcard */
- for (int ii=0; ii < 10; ii++)
- {
- if (ii == 0)
- execute(send_packet(&cmd));
- else
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_ADD || ii > 0)
- {
- uint16_t expected_result;
- if (ii == 0)
- expected_result= PROTOCOL_BINARY_RESPONSE_SUCCESS;
- else
- expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
-
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- execute(receive_binary_noop());
- verify(validate_response_header(&rsp, cc, expected_result));
- }
- else
- execute(test_binary_noop());
- }
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_add(void)
-{
- return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
-}
-
-static enum test_return test_binary_addq(void)
-{
- return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
-}
-
-static enum test_return binary_set_item(const char *key, const char *value)
-{
- command cmd;
- response rsp;
- storage_command(&cmd, PROTOCOL_BINARY_CMD_SET, key, strlen(key),
- value, strlen(value), 0, 0);
- execute(send_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- return TEST_PASS;
-}
-
-static enum test_return test_binary_replace_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
- uint64_t value= 0xdeadbeefdeadcafe;
- storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
-
- /* first replace should fail, successive should succeed (when the
- item is added! */
- for (int ii= 0; ii < 10; ii++)
- {
- if (ii == 0)
- execute(send_packet(&cmd));
- else
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0)
- {
- uint16_t expected_result;
- if (ii == 0)
- expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
- else
- expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS;
-
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- execute(receive_binary_noop());
- verify(validate_response_header(&rsp, cc, expected_result));
-
- if (ii == 0)
- execute(binary_set_item(key, key));
- }
- else
- execute(test_binary_noop());
- }
-
- /* verify that replace with CAS value works! */
- cmd.plain.message.header.request.cas=
- htonll(rsp.plain.message.header.response.cas);
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_REPLACE)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- execute(test_binary_noop());
-
- /* try to set with an incorrect CAS value */
- cmd.plain.message.header.request.cas=
- htonll(rsp.plain.message.header.response.cas - 1);
- execute(resend_packet(&cmd));
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- execute(receive_binary_noop());
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_replace(void)
-{
- return test_binary_replace_impl("test_binary_replace", PROTOCOL_BINARY_CMD_REPLACE);
-}
-
-static enum test_return test_binary_replaceq(void)
-{
- return test_binary_replace_impl("test_binary_replaceq", PROTOCOL_BINARY_CMD_REPLACEQ);
-}
-
-static enum test_return test_binary_delete_impl(const char *key, uint8_t cc)
-{
- command cmd;
- response rsp;
- raw_command(&cmd, cc, key, strlen(key), NULL, 0);
-
- /* The delete shouldn't work the first time, because the item isn't there */
- execute(send_packet(&cmd));
- execute(send_binary_noop());
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
- execute(receive_binary_noop());
- execute(binary_set_item(key, key));
-
- /* The item should be present now, resend*/
- execute(resend_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_DELETE)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
-
- execute(test_binary_noop());
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_delete(void)
-{
- return test_binary_delete_impl("test_binary_delete", PROTOCOL_BINARY_CMD_DELETE);
-}
-
-static enum test_return test_binary_deleteq(void)
-{
- return test_binary_delete_impl("test_binary_deleteq", PROTOCOL_BINARY_CMD_DELETEQ);
-}
-
-static enum test_return test_binary_get_impl(const char *key, uint8_t cc)
-{
- command cmd;
- response rsp;
-
- raw_command(&cmd, cc, key, strlen(key), NULL, 0);
- execute(send_packet(&cmd));
- execute(send_binary_noop());
-
- if (cc == PROTOCOL_BINARY_CMD_GET || cc == PROTOCOL_BINARY_CMD_GETK)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
- }
-
- execute(receive_binary_noop());
-
- execute(binary_set_item(key, key));
- execute(resend_packet(&cmd));
- execute(send_binary_noop());
-
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- execute(receive_binary_noop());
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_get(void)
-{
- return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
-}
-
-static enum test_return test_binary_getk(void)
-{
- return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
-}
-
-static enum test_return test_binary_getq(void)
-{
- return test_binary_get_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
-}
-
-static enum test_return test_binary_getkq(void)
-{
- return test_binary_get_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
-}
-
-static enum test_return test_binary_incr_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
- arithmetic_command(&cmd, cc, key, strlen(key), 1, 0, 0);
-
- uint64_t ii;
- for (ii= 0; ii < 10; ++ii)
- {
- if (ii == 0)
- execute(send_packet(&cmd));
- else
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_INCREMENT)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- verify(ntohll(rsp.incr.message.body.value) == ii);
- }
- else
- execute(test_binary_noop());
- }
-
- /* @todo add incorrect CAS */
- return TEST_PASS;
-}
-
-static enum test_return test_binary_incr(void)
-{
- return test_binary_incr_impl("test_binary_incr", PROTOCOL_BINARY_CMD_INCREMENT);
-}
-
-static enum test_return test_binary_incrq(void)
-{
- return test_binary_incr_impl("test_binary_incrq", PROTOCOL_BINARY_CMD_INCREMENTQ);
-}
-
-static enum test_return test_binary_decr_impl(const char* key, uint8_t cc)
-{
- command cmd;
- response rsp;
- arithmetic_command(&cmd, cc, key, strlen(key), 1, 9, 0);
-
- int ii;
- for (ii= 9; ii > -1; --ii)
- {
- if (ii == 9)
- execute(send_packet(&cmd));
- else
- execute(resend_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- verify(ntohll(rsp.decr.message.body.value) == (uint64_t)ii);
- }
- else
- execute(test_binary_noop());
- }
-
- /* decr 0 should not wrap */
- execute(resend_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- verify(ntohll(rsp.decr.message.body.value) == 0);
- }
- else
- {
- /* @todo get the value and verify! */
-
- }
-
- /* @todo add incorrect cas */
- execute(test_binary_noop());
- return TEST_PASS;
-}
-
-static enum test_return test_binary_decr(void)
-{
- return test_binary_decr_impl("test_binary_decr",
- PROTOCOL_BINARY_CMD_DECREMENT);
-}
-
-static enum test_return test_binary_decrq(void)
-{
- return test_binary_decr_impl("test_binary_decrq",
- PROTOCOL_BINARY_CMD_DECREMENTQ);
-}
-
-static enum test_return test_binary_version(void)
-{
- command cmd;
- response rsp;
- raw_command(&cmd, PROTOCOL_BINARY_CMD_VERSION, NULL, 0, NULL, 0);
-
- execute(send_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_VERSION,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_flush_impl(const char *key, uint8_t cc)
-{
- command cmd;
- response rsp;
-
- for (int ii= 0; ii < 2; ++ii)
- {
- execute(binary_set_item(key, key));
- flush_command(&cmd, cc, 0, ii == 0);
- execute(send_packet(&cmd));
-
- if (cc == PROTOCOL_BINARY_CMD_FLUSH)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- execute(test_binary_noop());
-
- raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
- execute(send_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
- PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
- }
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_flush(void)
-{
- return test_binary_flush_impl("test_binary_flush", PROTOCOL_BINARY_CMD_FLUSH);
-}
-
-static enum test_return test_binary_flushq(void)
-{
- return test_binary_flush_impl("test_binary_flushq", PROTOCOL_BINARY_CMD_FLUSHQ);
-}
-
-static enum test_return test_binary_concat_impl(const char *key, uint8_t cc)
-{
- command cmd;
- response rsp;
- const char *value;
-
- if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
- value="hello";
- else
- value=" world";
-
- execute(binary_set_item(key, value));
-
- if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
- value=" world";
- else
- value="hello";
-
- raw_command(&cmd, cc, key, strlen(key), value, strlen(value));
- execute(send_packet(&cmd));
- if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_PREPEND)
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
- }
- else
- execute(test_binary_noop());
-
- raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
- execute(send_packet(&cmd));
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- verify(rsp.plain.message.header.response.bodylen - 4 == 11);
- verify(memcmp(rsp.bytes + 28, "hello world", 11) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return test_binary_append(void)
-{
- return test_binary_concat_impl("test_binary_append", PROTOCOL_BINARY_CMD_APPEND);
-}
-
-static enum test_return test_binary_prepend(void)
-{
- return test_binary_concat_impl("test_binary_prepend", PROTOCOL_BINARY_CMD_PREPEND);
-}
-
-static enum test_return test_binary_appendq(void)
-{
- return test_binary_concat_impl("test_binary_appendq", PROTOCOL_BINARY_CMD_APPENDQ);
-}
-
-static enum test_return test_binary_prependq(void)
-{
- return test_binary_concat_impl("test_binary_prependq", PROTOCOL_BINARY_CMD_PREPENDQ);
-}
-
-static enum test_return test_binary_stat(void)
-{
- command cmd;
- response rsp;
-
- raw_command(&cmd, PROTOCOL_BINARY_CMD_STAT, NULL, 0, NULL, 0);
- execute(send_packet(&cmd));
-
- do
- {
- execute(recv_packet(&rsp));
- verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_STAT,
- PROTOCOL_BINARY_RESPONSE_SUCCESS));
- } while (rsp.plain.message.header.response.keylen != 0);
-
- return TEST_PASS;
-}
-
-static enum test_return send_string(const char *cmd)
-{
- execute(retry_write(cmd, strlen(cmd)));
- return TEST_PASS;
-}
-
-static enum test_return receive_line(char *buffer, size_t size)
-{
- size_t offset= 0;
- while (offset < size)
- {
- execute(retry_read(buffer + offset, 1));
- if (buffer[offset] == '\n')
- {
- if (offset + 1 < size)
- {
- buffer[offset + 1]= '\0';
- return TEST_PASS;
- }
- else
- return TEST_FAIL;
- }
- ++offset;
- }
-
- return TEST_FAIL;
-}
-
-static enum test_return receive_response(const char *msg) {
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- if (strcmp(msg, buffer) != 0) {
- fprintf(stderr, "[%s]\n", buffer);
- }
- verify(strcmp(msg, buffer) == 0);
- return TEST_PASS;
-}
-
-static enum test_return receive_error_response(void)
-{
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "ERROR", 5) == 0 ||
- strncmp(buffer, "CLIENT_ERROR", 12) == 0 ||
- strncmp(buffer, "SERVER_ERROR", 12) == 0);
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_quit(void)
-{
- /* Verify that quit handles unknown options */
- execute(send_string("quit foo bar\r\n"));
- execute(receive_error_response());
-
- /* quit doesn't support noreply */
- execute(send_string("quit noreply\r\n"));
- execute(receive_error_response());
-
- /* Verify that quit works */
- execute(send_string("quit\r\n"));
-
- /* Socket should be closed now, read should return EXIT_SUCCESS */
- char buffer[80];
- verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0);
- return TEST_PASS_RECONNECT;
-
-}
-
-static enum test_return test_ascii_version(void)
-{
- /* Verify that version command handles unknown options */
- execute(send_string("version foo bar\r\n"));
- execute(receive_error_response());
-
- /* version doesn't support noreply */
- execute(send_string("version noreply\r\n"));
- execute(receive_error_response());
-
- /* Verify that verify works */
- execute(send_string("version\r\n"));
- char buffer[256];
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "VERSION ", 8) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_verbosity(void)
-{
- /* This command does not adhere to the spec! */
- execute(send_string("verbosity foo bar my\r\n"));
- execute(receive_error_response());
-
- execute(send_string("verbosity noreply\r\n"));
- execute(receive_error_response());
-
- execute(send_string("verbosity 0 noreply\r\n"));
- execute(test_ascii_version());
-
- execute(send_string("verbosity\r\n"));
- execute(receive_error_response());
-
- execute(send_string("verbosity 1\r\n"));
- execute(receive_response("OK\r\n"));
-
- execute(send_string("verbosity 0\r\n"));
- execute(receive_response("OK\r\n"));
-
- return TEST_PASS;
-}
-
-
-
-static enum test_return test_ascii_set_impl(const char* key, bool noreply)
-{
- /* @todo add tests for bogus format! */
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (!noreply)
- execute(receive_response("STORED\r\n"));
-
- return test_ascii_version();
-}
-
-static enum test_return test_ascii_set(void)
-{
- return test_ascii_set_impl("test_ascii_set", false);
-}
-
-static enum test_return test_ascii_set_noreply(void)
-{
- return test_ascii_set_impl("test_ascii_set_noreply", true);
-}
-
-static enum test_return test_ascii_add_impl(const char* key, bool noreply)
-{
- /* @todo add tests for bogus format! */
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (!noreply)
- execute(receive_response("STORED\r\n"));
-
- execute(send_string(buffer));
-
- if (!noreply)
- execute(receive_response("NOT_STORED\r\n"));
-
- return test_ascii_version();
-}
-
-static enum test_return test_ascii_add(void)
-{
- return test_ascii_add_impl("test_ascii_add", false);
-}
-
-static enum test_return test_ascii_add_noreply(void)
-{
- return test_ascii_add_impl("test_ascii_add_noreply", true);
-}
-
-static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata)
-{
- char buffer[1024];
-
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "VALUE ", 6) == 0);
- char *end= strchr(buffer + 6, ' ');
- verify(end != NULL);
- *end= '\0';
- *key= strdup(buffer + 6);
- verify(*key != NULL);
- char *ptr= end + 1;
-
- unsigned long val= strtoul(ptr, &end, 10); /* flags */
- verify(ptr != end);
- verify(val == 0);
- verify(end != NULL);
- *ndata = (ssize_t)strtoul(end, &end, 10); /* size */
- verify(ptr != end);
- verify(end != NULL);
- while (*end != '\n' && isspace(*end))
- ++end;
- verify(*end == '\n');
-
- *value= malloc((size_t)*ndata);
- verify(*value != NULL);
-
- execute(retry_read(*value, (size_t)*ndata));
-
- execute(retry_read(buffer, 2));
- verify(memcmp(buffer, "\r\n", 2) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_get_value(const char *key, const char *value)
-{
-
- char buffer[1024];
- size_t datasize= strlen(value);
-
- verify(datasize < sizeof(buffer));
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "VALUE ", 6) == 0);
- verify(strncmp(buffer + 6, key, strlen(key)) == 0);
- char *ptr= buffer + 6 + strlen(key) + 1;
- char *end;
-
- unsigned long val= strtoul(ptr, &end, 10); /* flags */
- verify(ptr != end);
- verify(val == 0);
- verify(end != NULL);
- val= strtoul(end, &end, 10); /* size */
- verify(ptr != end);
- verify(val == datasize);
- verify(end != NULL);
- while (*end != '\n' && isspace(*end))
- ++end;
- verify(*end == '\n');
-
- execute(retry_read(buffer, datasize));
- verify(memcmp(buffer, value, datasize) == 0);
-
- execute(retry_read(buffer, 2));
- verify(memcmp(buffer, "\r\n", 2) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_get_item(const char *key, const char *value,
- bool exist)
-{
- char buffer[1024];
- size_t datasize= 0;
- if (value != NULL)
- datasize= strlen(value);
-
- verify(datasize < sizeof(buffer));
- snprintf(buffer, sizeof(buffer), "get %s\r\n", key);
- execute(send_string(buffer));
-
- if (exist)
- execute(ascii_get_value(key, value));
-
- execute(retry_read(buffer, 5));
- verify(memcmp(buffer, "END\r\n", 5) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_gets_value(const char *key, const char *value,
- unsigned long *cas)
-{
-
- char buffer[1024];
- size_t datasize= strlen(value);
-
- verify(datasize < sizeof(buffer));
- execute(receive_line(buffer, sizeof(buffer)));
- verify(strncmp(buffer, "VALUE ", 6) == 0);
- verify(strncmp(buffer + 6, key, strlen(key)) == 0);
- char *ptr= buffer + 6 + strlen(key) + 1;
- char *end;
-
- unsigned long val= strtoul(ptr, &end, 10); /* flags */
- verify(ptr != end);
- verify(val == 0);
- verify(end != NULL);
- val= strtoul(end, &end, 10); /* size */
- verify(ptr != end);
- verify(val == datasize);
- verify(end != NULL);
- *cas= strtoul(end, &end, 10); /* cas */
- verify(ptr != end);
- verify(val == datasize);
- verify(end != NULL);
-
- while (*end != '\n' && isspace(*end))
- ++end;
- verify(*end == '\n');
-
- execute(retry_read(buffer, datasize));
- verify(memcmp(buffer, value, datasize) == 0);
-
- execute(retry_read(buffer, 2));
- verify(memcmp(buffer, "\r\n", 2) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_gets_item(const char *key, const char *value,
- bool exist, unsigned long *cas)
-{
- char buffer[1024];
- size_t datasize= 0;
- if (value != NULL)
- datasize= strlen(value);
-
- verify(datasize < sizeof(buffer));
- snprintf(buffer, sizeof(buffer), "gets %s\r\n", key);
- execute(send_string(buffer));
-
- if (exist)
- execute(ascii_gets_value(key, value, cas));
-
- execute(retry_read(buffer, 5));
- verify(memcmp(buffer, "END\r\n", 5) == 0);
-
- return TEST_PASS;
-}
-
-static enum test_return ascii_set_item(const char *key, const char *value)
-{
- char buffer[300];
- size_t len= strlen(value);
- snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len);
- execute(send_string(buffer));
- execute(retry_write(value, len));
- execute(send_string("\r\n"));
- execute(receive_response("STORED\r\n"));
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_replace_impl(const char* key, bool noreply)
-{
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("NOT_STORED\r\n"));
-
- execute(ascii_set_item(key, "value"));
- execute(ascii_get_item(key, "value", true));
-
-
- execute(send_string(buffer));
-
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("STORED\r\n"));
-
- return test_ascii_version();
-}
-
-static enum test_return test_ascii_replace(void)
-{
- return test_ascii_replace_impl("test_ascii_replace", false);
-}
-
-static enum test_return test_ascii_replace_noreply(void)
-{
- return test_ascii_replace_impl("test_ascii_replace_noreply", true);
-}
-
-static enum test_return test_ascii_cas_impl(const char* key, bool noreply)
-{
- char buffer[1024];
- unsigned long cas;
-
- execute(ascii_set_item(key, "value"));
- execute(ascii_gets_item(key, "value", true, &cas));
-
- snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("STORED\r\n"));
-
- /* reexecute the same command should fail due to illegal cas */
- execute(send_string(buffer));
-
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("EXISTS\r\n"));
-
- return test_ascii_version();
-}
-
-static enum test_return test_ascii_cas(void)
-{
- return test_ascii_cas_impl("test_ascii_cas", false);
-}
-
-static enum test_return test_ascii_cas_noreply(void)
-{
- return test_ascii_cas_impl("test_ascii_cas_noreply", true);
-}
-
-static enum test_return test_ascii_delete_impl(const char *key, bool noreply)
-{
- execute(ascii_set_item(key, "value"));
-
- execute(send_string("delete\r\n"));
- execute(receive_error_response());
- /* BUG: the server accepts delete a b */
- execute(send_string("delete a b c d e\r\n"));
- execute(receive_error_response());
-
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : "");
- execute(send_string(buffer));
-
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("DELETED\r\n"));
-
- execute(ascii_get_item(key, "value", false));
- execute(send_string(buffer));
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("NOT_FOUND\r\n"));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_delete(void)
-{
- return test_ascii_delete_impl("test_ascii_delete", false);
-}
-
-static enum test_return test_ascii_delete_noreply(void)
-{
- return test_ascii_delete_impl("test_ascii_delete_noreply", true);
-}
-
-static enum test_return test_ascii_get(void)
-{
- execute(ascii_set_item("test_ascii_get", "value"));
-
- execute(send_string("get\r\n"));
- execute(receive_error_response());
- execute(ascii_get_item("test_ascii_get", "value", true));
- execute(ascii_get_item("test_ascii_get_notfound", "value", false));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_gets(void)
-{
- execute(ascii_set_item("test_ascii_gets", "value"));
-
- execute(send_string("gets\r\n"));
- execute(receive_error_response());
- unsigned long cas;
- execute(ascii_gets_item("test_ascii_gets", "value", true, &cas));
- execute(ascii_gets_item("test_ascii_gets_notfound", "value", false, &cas));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_mget(void)
-{
- const uint32_t nkeys= 5;
- const char * const keys[]= {
- "test_ascii_mget1",
- "test_ascii_mget2",
- /* test_ascii_mget_3 does not exist :) */
- "test_ascii_mget4",
- "test_ascii_mget5",
- "test_ascii_mget6"
- };
-
- for (uint32_t x= 0; x < nkeys; ++x)
- execute(ascii_set_item(keys[x], "value"));
-
- /* Ask for a key that doesn't exist as well */
- execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 "
- "test_ascii_mget4 test_ascii_mget5 "
- "test_ascii_mget6\r\n"));
-
- char *returned[nkeys];
-
- for (uint32_t x= 0; x < nkeys; ++x)
- {
- ssize_t nbytes = 0;
- char *v= NULL;
- execute(ascii_get_unknown_value(&returned[x], &v, &nbytes));
- verify(nbytes == 5);
- verify(memcmp(v, "value", 5) == 0);
- free(v);
- }
-
- char buffer[5];
- execute(retry_read(buffer, 5));
- verify(memcmp(buffer, "END\r\n", 5) == 0);
-
- /* verify that we got all the keys we expected */
- for (uint32_t x= 0; x < nkeys; ++x)
- {
- bool found= false;
- for (uint32_t y= 0; y < nkeys; ++y)
- {
- if (strcmp(keys[x], returned[y]) == 0)
- {
- found = true;
- break;
- }
- }
- verify(found);
- }
-
- for (uint32_t x= 0; x < nkeys; ++x)
- free(returned[x]);
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_incr_impl(const char* key, bool noreply)
-{
- char cmd[300];
- snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : "");
-
- execute(ascii_set_item(key, "0"));
- for (int x= 1; x < 11; ++x)
- {
- execute(send_string(cmd));
-
- if (noreply)
- execute(test_ascii_version());
- else
- {
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- int val= atoi(buffer);
- verify(val == x);
- }
- }
-
- execute(ascii_get_item(key, "10", true));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_incr(void)
-{
- return test_ascii_incr_impl("test_ascii_incr", false);
-}
-
-static enum test_return test_ascii_incr_noreply(void)
-{
- return test_ascii_incr_impl("test_ascii_incr_noreply", true);
-}
-
-static enum test_return test_ascii_decr_impl(const char* key, bool noreply)
-{
- char cmd[300];
- snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : "");
-
- execute(ascii_set_item(key, "9"));
- for (int x= 8; x > -1; --x)
- {
- execute(send_string(cmd));
-
- if (noreply)
- execute(test_ascii_version());
- else
- {
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- int val= atoi(buffer);
- verify(val == x);
- }
- }
-
- execute(ascii_get_item(key, "0", true));
-
- /* verify that it doesn't wrap */
- execute(send_string(cmd));
- if (noreply)
- execute(test_ascii_version());
- else
- {
- char buffer[80];
- execute(receive_line(buffer, sizeof(buffer)));
- }
- execute(ascii_get_item(key, "0", true));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_decr(void)
-{
- return test_ascii_decr_impl("test_ascii_decr", false);
-}
-
-static enum test_return test_ascii_decr_noreply(void)
-{
- return test_ascii_decr_impl("test_ascii_decr_noreply", true);
-}
-
-
-static enum test_return test_ascii_flush_impl(const char *key, bool noreply)
-{
-#if 0
- /* Verify that the flush_all command handles unknown options */
- /* Bug in the current memcached server! */
- execute(send_string("flush_all foo bar\r\n"));
- execute(receive_error_response());
-#endif
-
- execute(ascii_set_item(key, key));
- execute(ascii_get_item(key, key, true));
-
- if (noreply)
- {
- execute(send_string("flush_all noreply\r\n"));
- execute(test_ascii_version());
- }
- else
- {
- execute(send_string("flush_all\r\n"));
- execute(receive_response("OK\r\n"));
- }
-
- execute(ascii_get_item(key, key, false));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_flush(void)
-{
- return test_ascii_flush_impl("test_ascii_flush", false);
-}
-
-static enum test_return test_ascii_flush_noreply(void)
-{
- return test_ascii_flush_impl("test_ascii_flush_noreply", true);
-}
-
-static enum test_return test_ascii_concat_impl(const char *key,
- bool append,
- bool noreply)
-{
- const char *value;
-
- if (append)
- value="hello";
- else
- value=" world";
-
- execute(ascii_set_item(key, value));
-
- if (append)
- value=" world";
- else
- value="hello";
-
- char cmd[400];
- snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n",
- append ? "append" : "prepend",
- key, (unsigned int)strlen(value), noreply ? " noreply" : "",
- value);
- execute(send_string(cmd));
-
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("STORED\r\n"));
-
- execute(ascii_get_item(key, "hello world", true));
-
- snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n",
- append ? "append" : "prepend",
- key, (unsigned int)strlen(value), noreply ? " noreply" : "",
- value);
- execute(send_string(cmd));
-
- if (noreply)
- execute(test_ascii_version());
- else
- execute(receive_response("NOT_STORED\r\n"));
-
- return TEST_PASS;
-}
-
-static enum test_return test_ascii_append(void)
-{
- return test_ascii_concat_impl("test_ascii_append", true, false);
-}
-
-static enum test_return test_ascii_prepend(void)
-{
- return test_ascii_concat_impl("test_ascii_prepend", false, false);
-}
-
-static enum test_return test_ascii_append_noreply(void)
-{
- return test_ascii_concat_impl("test_ascii_append_noreply", true, true);
-}
-
-static enum test_return test_ascii_prepend_noreply(void)
-{
- return test_ascii_concat_impl("test_ascii_prepend_noreply", false, true);
-}
-
-static enum test_return test_ascii_stat(void)
-{
- execute(send_string("stats noreply\r\n"));
- execute(receive_error_response());
- execute(send_string("stats\r\n"));
- char buffer[1024];
- do {
- execute(receive_line(buffer, sizeof(buffer)));
- } while (strcmp(buffer, "END\r\n") != 0);
-
- return TEST_PASS_RECONNECT;
-}
-
-typedef enum test_return(*TEST_FUNC)(void);
-
-struct testcase
-{
- const char *description;
- TEST_FUNC function;
-};
-
-struct testcase testcases[]= {
- { "ascii quit", test_ascii_quit },
- { "ascii version", test_ascii_version },
- { "ascii verbosity", test_ascii_verbosity },
- { "ascii set", test_ascii_set },
- { "ascii set noreply", test_ascii_set_noreply },
- { "ascii get", test_ascii_get },
- { "ascii gets", test_ascii_gets },
- { "ascii mget", test_ascii_mget },
- { "ascii flush", test_ascii_flush },
- { "ascii flush noreply", test_ascii_flush_noreply },
- { "ascii add", test_ascii_add },
- { "ascii add noreply", test_ascii_add_noreply },
- { "ascii replace", test_ascii_replace },
- { "ascii replace noreply", test_ascii_replace_noreply },
- { "ascii cas", test_ascii_cas },
- { "ascii cas noreply", test_ascii_cas_noreply },
- { "ascii delete", test_ascii_delete },
- { "ascii delete noreply", test_ascii_delete_noreply },
- { "ascii incr", test_ascii_incr },
- { "ascii incr noreply", test_ascii_incr_noreply },
- { "ascii decr", test_ascii_decr },
- { "ascii decr noreply", test_ascii_decr_noreply },
- { "ascii append", test_ascii_append },
- { "ascii append noreply", test_ascii_append_noreply },
- { "ascii prepend", test_ascii_prepend },
- { "ascii prepend noreply", test_ascii_prepend_noreply },
- { "ascii stat", test_ascii_stat },
- { "binary noop", test_binary_noop },
- { "binary quit", test_binary_quit },
- { "binary quitq", test_binary_quitq },
- { "binary set", test_binary_set },
- { "binary setq", test_binary_setq },
- { "binary flush", test_binary_flush },
- { "binary flushq", test_binary_flushq },
- { "binary add", test_binary_add },
- { "binary addq", test_binary_addq },
- { "binary replace", test_binary_replace },
- { "binary replaceq", test_binary_replaceq },
- { "binary delete", test_binary_delete },
- { "binary deleteq", test_binary_deleteq },
- { "binary get", test_binary_get },
- { "binary getq", test_binary_getq },
- { "binary getk", test_binary_getk },
- { "binary getkq", test_binary_getkq },
- { "binary incr", test_binary_incr },
- { "binary incrq", test_binary_incrq },
- { "binary decr", test_binary_decr },
- { "binary decrq", test_binary_decrq },
- { "binary version", test_binary_version },
- { "binary append", test_binary_append },
- { "binary appendq", test_binary_appendq },
- { "binary prepend", test_binary_prepend },
- { "binary prependq", test_binary_prependq },
- { "binary stat", test_binary_stat },
- { NULL, NULL}
-};
-
-const int ascii_tests = 1;
-const int binary_tests = 2;
-
-struct test_type_st
-{
- bool ascii;
- bool binary;
-};
-
-int main(int argc, char **argv)
-{
- static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"};
- struct test_type_st tests= { true, true };
- int total= 0;
- int failed= 0;
- const char *hostname= "localhost";
- const char *port= "11211";
- int cmd;
- bool prompt= false;
- const char *testname= NULL;
-
-
-
- while ((cmd= getopt(argc, argv, "t:vch:p:PT:?ab")) != EOF)
- {
- switch (cmd) {
- case 'a':
- tests.ascii= true;
- tests.binary= false;
- break;
- case 'b':
- tests.ascii= false;
- tests.binary= true;
- break;
- case 't':
- timeout= atoi(optarg);
- if (timeout == 0)
- {
- fprintf(stderr, "Invalid timeout. Please specify a number for -t\n");
- return EXIT_FAILURE;
- }
- break;
- case 'v': verbose= true;
- break;
- case 'c': do_core= true;
- break;
- case 'h': hostname= optarg;
- break;
- case 'p': port= optarg;
- break;
- case 'P': prompt= true;
- break;
- case 'T': testname= optarg;
- break;
- default:
- fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n"
- "\t-c\tGenerate coredump if a test fails\n"
- "\t-v\tVerbose test output (print out the assertion)\n"
- "\t-t n\tSet the timeout for io-operations to n seconds\n"
- "\t-P\tPrompt the user before starting a test.\n"
- "\t\t\t\"skip\" will skip the test\n"
- "\t\t\t\"quit\" will terminate memcapable\n"
- "\t\t\tEverything else will start the test\n"
- "\t-T n\tJust run the test named n\n"
- "\t-a\tOnly test the ascii protocol\n"
- "\t-b\tOnly test the binary protocol\n",
- argv[0]);
- return EXIT_FAILURE;
- }
- }
-
- initialize_sockets();
- sock= connect_server(hostname, port);
- if (sock == INVALID_SOCKET)
- {
- fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
- hostname, port, strerror(get_socket_errno()));
- return EXIT_FAILURE;
- }
-
- for (int ii= 0; testcases[ii].description != NULL; ++ii)
- {
- if (testname != NULL && strcmp(testcases[ii].description, testname) != 0)
- continue;
-
- if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) ||
- (testcases[ii].description[0] == 'b' && (tests.binary) == 0))
- {
- continue;
- }
- ++total;
- fprintf(stdout, "%-40s", testcases[ii].description);
- fflush(stdout);
-
- if (prompt)
- {
- fprintf(stdout, "\nPress <return> when you are ready? ");
- char buffer[80] = {0};
- if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
- if (strncmp(buffer, "skip", 4) == 0)
- {
- fprintf(stdout, "%-40s%s\n", testcases[ii].description,
- status_msg[TEST_SKIP]);
- fflush(stdout);
- continue;
- }
- if (strncmp(buffer, "quit", 4) == 0)
- exit(0);
- }
-
- fprintf(stdout, "%-40s", testcases[ii].description);
- fflush(stdout);
- }
-
- bool reconnect= false;
- enum test_return ret= testcases[ii].function();
- if (ret == TEST_FAIL)
- {
- reconnect= true;
- ++failed;
- if (verbose)
- fprintf(stderr, "\n");
- }
- else if (ret == TEST_PASS_RECONNECT)
- reconnect= true;
-
- fprintf(stderr, "%s\n", status_msg[ret]);
- if (reconnect)
- {
- closesocket(sock);
- if ((sock= connect_server(hostname, port)) == INVALID_SOCKET)
- {
- fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
- hostname, port, strerror(get_socket_errno()));
- fprintf(stderr, "%d of %d tests failed\n", failed, total);
- return EXIT_FAILURE;
- }
- }
- }
-
- closesocket(sock);
- if (failed == 0)
- fprintf(stdout, "All tests passed\n");
- else
- fprintf(stderr, "%d of %d tests failed\n", failed, total);
-
- return (failed == 0) ? 0 : 1;
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+#undef NDEBUG
+
+#include "config.h"
+#include <pthread.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <libmemcached/memcached.h>
+#include <libmemcached/memcached/protocol_binary.h>
+#include <libmemcached/byteorder.h>
+#include "utilities.h"
+
+#ifdef linux
+/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
+ * optimize the conversion functions, but the prototypes generate warnings
+ * from gcc. The conversion methods isn't the bottleneck for my app, so
+ * just remove the warnings by undef'ing the optimization ..
+ */
+#undef ntohs
+#undef ntohl
+#endif
+
+/* Should we generate coredumps when we enounter an error (-c) */
+static bool do_core= false;
+/* connection to the server */
+static memcached_socket_t sock;
+/* Should the output from test failures be verbose or quiet? */
+static bool verbose= false;
+
+/* The number of seconds to wait for an IO-operation */
+static int timeout= 2;
+
+/*
+ * Instead of having to cast between the different datatypes we create
+ * a union of all of the different types of pacages we want to send.
+ * A lot of the different commands use the same packet layout, so I'll
+ * just define the different types I need. The typedefs only contain
+ * the header of the message, so we need some space for keys and body
+ * To avoid to have to do multiple writes, lets add a chunk of memory
+ * to use. 1k should be more than enough for header, key and body.
+ */
+typedef union
+{
+ protocol_binary_request_no_extras plain;
+ protocol_binary_request_flush flush;
+ protocol_binary_request_incr incr;
+ protocol_binary_request_set set;
+ char bytes[1024];
+} command;
+
+typedef union
+{
+ protocol_binary_response_no_extras plain;
+ protocol_binary_response_incr incr;
+ protocol_binary_response_decr decr;
+ char bytes[1024];
+} response;
+
+enum test_return
+{
+ TEST_SKIP, TEST_PASS, TEST_PASS_RECONNECT, TEST_FAIL
+};
+
+/**
+ * Try to get an addrinfo struct for a given port on a given host
+ */
+static struct addrinfo *lookuphost(const char *hostname, const char *port)
+{
+ struct addrinfo *ai= 0;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family=AF_UNSPEC;
+ hints.ai_protocol=IPPROTO_TCP;
+ hints.ai_socktype=SOCK_STREAM;
+
+ int error= getaddrinfo(hostname, port, &hints, &ai);
+ if (error != 0)
+ {
+ if (error != EAI_SYSTEM)
+ fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
+ else
+ perror("getaddrinfo()");
+ }
+
+ return ai;
+}
+
+/**
+ * Set the socket in nonblocking mode
+ * @return -1 if failure, the socket otherwise
+ */
+static memcached_socket_t set_noblock(void)
+{
+#ifdef WIN32
+ u_long arg = 1;
+ if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
+ {
+ perror("Failed to set nonblocking io");
+ closesocket(sock);
+ return INVALID_SOCKET;
+ }
+#else
+ int flags= fcntl(sock, F_GETFL, 0);
+ if (flags == -1)
+ {
+ perror("Failed to get socket flags");
+ closesocket(sock);
+ return INVALID_SOCKET;
+ }
+
+ if ((flags & O_NONBLOCK) != O_NONBLOCK)
+ {
+ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
+ {
+ perror("Failed to set socket to nonblocking mode");
+ closesocket(sock);
+ return INVALID_SOCKET;
+ }
+ }
+#endif
+ return sock;
+}
+
+/**
+ * Try to open a connection to the server
+ * @param hostname the name of the server to connect to
+ * @param port the port number (or service) to connect to
+ * @return positive integer if success, -1 otherwise
+ */
+static memcached_socket_t connect_server(const char *hostname, const char *port)
+{
+ struct addrinfo *ai= lookuphost(hostname, port);
+ sock= INVALID_SOCKET;
+ if (ai != NULL)
+ {
+ if ((sock= socket(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol)) != INVALID_SOCKET)
+ {
+ if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR)
+ {
+ fprintf(stderr, "Failed to connect socket: %s\n",
+ strerror(get_socket_errno()));
+ closesocket(sock);
+ sock= INVALID_SOCKET;
+ }
+ else
+ {
+ sock= set_noblock();
+ }
+ }
+ else
+ fprintf(stderr, "Failed to create socket: %s\n",
+ strerror(get_socket_errno()));
+
+ freeaddrinfo(ai);
+ }
+
+ return sock;
+}
+
+static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len)
+{
+ ssize_t ret;
+
+ if (direction == POLLOUT)
+ {
+ ret= send(fd, buf, len, 0);
+ }
+ else
+ {
+ ret= recv(fd, buf, len, 0);
+ }
+
+ if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK)
+ {
+ struct pollfd fds;
+ memset(&fds, 0, sizeof(struct pollfd));
+ fds.events= direction;
+ fds.fd= fd;
+
+ int err= poll(&fds, 1, timeout * 1000);
+ if (err == 1)
+ {
+ if (direction == POLLOUT)
+ {
+ ret= send(fd, buf, len, 0);
+ }
+ else
+ {
+ ret= recv(fd, buf, len, 0);
+ }
+ }
+ else if (err == 0)
+ {
+ errno= ETIMEDOUT;
+ }
+ else
+ {
+ perror("Failed to poll");
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Ensure that an expression is true. If it isn't print out a message similar
+ * to assert() and create a coredump if the user wants that. If not an error
+ * message is returned.
+ *
+ */
+static enum test_return ensure(bool val, const char *expression, const char *file, int line)
+{
+ if (!val)
+ {
+ if (verbose)
+ fprintf(stderr, "\n%s:%d: %s", file, line, expression);
+
+ if (do_core)
+ abort();
+
+ return TEST_FAIL;
+ }
+
+ return TEST_PASS;
+}
+
+#define verify(expression) do { if (ensure(expression, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
+#define execute(expression) do { if (ensure(expression == TEST_PASS, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
+
+/**
+ * Send a chunk of memory over the socket (retry if the call is iterrupted
+ */
+static enum test_return retry_write(const void* buf, size_t len)
+{
+ size_t offset= 0;
+ const char* ptr= static_cast<const char *>(buf);
+
+ do
+ {
+ size_t num_bytes= len - offset;
+ ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes);
+ if (nw == -1)
+ verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
+ else
+ offset+= (size_t)nw;
+ } while (offset < len);
+
+ return TEST_PASS;
+}
+
+/**
+ * Resend a packet to the server (All fields in the command header should
+ * be in network byte order)
+ */
+static enum test_return resend_packet(command *cmd)
+{
+ size_t length= sizeof (protocol_binary_request_no_extras) +
+ ntohl(cmd->plain.message.header.request.bodylen);
+
+ execute(retry_write(cmd, length));
+ return TEST_PASS;
+}
+
+/**
+ * Send a command to the server. The command header needs to be updated
+ * to network byte order
+ */
+static enum test_return send_packet(command *cmd)
+{
+ /* Fix the byteorder of the header */
+ cmd->plain.message.header.request.keylen=
+ ntohs(cmd->plain.message.header.request.keylen);
+ cmd->plain.message.header.request.bodylen=
+ ntohl(cmd->plain.message.header.request.bodylen);
+ cmd->plain.message.header.request.cas=
+ ntohll(cmd->plain.message.header.request.cas);
+
+ execute(resend_packet(cmd));
+ return TEST_PASS;
+}
+
+/**
+ * Read a fixed length chunk of data from the server
+ */
+static enum test_return retry_read(void *buf, size_t len)
+{
+ size_t offset= 0;
+ do
+ {
+ ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset);
+ switch (nr) {
+ case -1 :
+ fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno));
+ verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
+ break;
+ case 0:
+ return TEST_FAIL;
+ default:
+ offset+= (size_t)nr;
+ }
+ } while (offset < len);
+
+ return TEST_PASS;
+}
+
+/**
+ * Receive a response from the server and conver the fields in the header
+ * to local byte order
+ */
+static enum test_return recv_packet(response *rsp)
+{
+ execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras)));
+
+ /* Fix the byte order in the packet header */
+ rsp->plain.message.header.response.keylen=
+ ntohs(rsp->plain.message.header.response.keylen);
+ rsp->plain.message.header.response.status=
+ ntohs(rsp->plain.message.header.response.status);
+ rsp->plain.message.header.response.bodylen=
+ ntohl(rsp->plain.message.header.response.bodylen);
+ rsp->plain.message.header.response.cas=
+ ntohll(rsp->plain.message.header.response.cas);
+
+ size_t bodysz= rsp->plain.message.header.response.bodylen;
+ if (bodysz > 0)
+ execute(retry_read(rsp->bytes + sizeof (protocol_binary_response_no_extras), bodysz));
+
+ return TEST_PASS;
+}
+
+/**
+ * Create a storage command (add, set, replace etc)
+ *
+ * @param cmd destination buffer
+ * @param cc the storage command to create
+ * @param key the key to store
+ * @param keylen the length of the key
+ * @param dta the data to store with the key
+ * @param dtalen the length of the data to store with the key
+ * @param flags the flags to store along with the key
+ * @param exptime the expiry time for the key
+ */
+static void storage_command(command *cmd,
+ uint8_t cc,
+ const void* key,
+ size_t keylen,
+ const void* dta,
+ size_t dtalen,
+ uint32_t flags,
+ uint32_t exptime)
+{
+ /* all of the storage commands use the same command layout */
+ protocol_binary_request_set *request= &cmd->set;
+
+ memset(request, 0, sizeof (*request));
+ request->message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request->message.header.request.opcode= cc;
+ request->message.header.request.keylen= (uint16_t)keylen;
+ request->message.header.request.extlen= 8;
+ request->message.header.request.bodylen= (uint32_t)(keylen + 8 + dtalen);
+ request->message.header.request.opaque= 0xdeadbeef;
+ request->message.body.flags= flags;
+ request->message.body.expiration= exptime;
+
+ off_t key_offset= sizeof (protocol_binary_request_no_extras) + 8;
+ memcpy(cmd->bytes + key_offset, key, keylen);
+ if (dta != NULL)
+ memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
+}
+
+/**
+ * Create a basic command to send to the server
+ * @param cmd destination buffer
+ * @param cc the command to create
+ * @param key the key to store
+ * @param keylen the length of the key
+ * @param dta the data to store with the key
+ * @param dtalen the length of the data to store with the key
+ */
+static void raw_command(command *cmd,
+ uint8_t cc,
+ const void* key,
+ size_t keylen,
+ const void* dta,
+ size_t dtalen)
+{
+ /* all of the storage commands use the same command layout */
+ memset(cmd, 0, sizeof (*cmd));
+ cmd->plain.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ cmd->plain.message.header.request.opcode= cc;
+ cmd->plain.message.header.request.keylen= (uint16_t)keylen;
+ cmd->plain.message.header.request.bodylen= (uint32_t)(keylen + dtalen);
+ cmd->plain.message.header.request.opaque= 0xdeadbeef;
+
+ off_t key_offset= sizeof (protocol_binary_request_no_extras);
+
+ if (key != NULL)
+ memcpy(cmd->bytes + key_offset, key, keylen);
+
+ if (dta != NULL)
+ memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
+}
+
+/**
+ * Create the flush command
+ * @param cmd destination buffer
+ * @param cc the command to create (FLUSH/FLUSHQ)
+ * @param exptime when to flush
+ * @param use_extra to force using of the extra field?
+ */
+static void flush_command(command *cmd,
+ uint8_t cc, uint32_t exptime, bool use_extra)
+{
+ memset(cmd, 0, sizeof (cmd->flush));
+ cmd->flush.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ cmd->flush.message.header.request.opcode= cc;
+ cmd->flush.message.header.request.opaque= 0xdeadbeef;
+
+ if (exptime != 0 || use_extra)
+ {
+ cmd->flush.message.header.request.extlen= 4;
+ cmd->flush.message.body.expiration= htonl(exptime);
+ cmd->flush.message.header.request.bodylen= 4;
+ }
+}
+
+/**
+ * Create a incr/decr command
+ * @param cc the cmd to create (FLUSH/FLUSHQ)
+ * @param key the key to operate on
+ * @param keylen the number of bytes in the key
+ * @param delta the number to add/subtract
+ * @param initial the initial value if the key doesn't exist
+ * @param exptime when the key should expire if it isn't set
+ */
+static void arithmetic_command(command *cmd,
+ uint8_t cc,
+ const void* key,
+ size_t keylen,
+ uint64_t delta,
+ uint64_t initial,
+ uint32_t exptime)
+{
+ memset(cmd, 0, sizeof (cmd->incr));
+ cmd->incr.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ cmd->incr.message.header.request.opcode= cc;
+ cmd->incr.message.header.request.keylen= (uint16_t)keylen;
+ cmd->incr.message.header.request.extlen= 20;
+ cmd->incr.message.header.request.bodylen= (uint32_t)(keylen + 20);
+ cmd->incr.message.header.request.opaque= 0xdeadbeef;
+ cmd->incr.message.body.delta= htonll(delta);
+ cmd->incr.message.body.initial= htonll(initial);
+ cmd->incr.message.body.expiration= htonl(exptime);
+
+ off_t key_offset= sizeof (protocol_binary_request_no_extras) + 20;
+ memcpy(cmd->bytes + key_offset, key, keylen);
+}
+
+/**
+ * Validate the response header from the server
+ * @param rsp the response to check
+ * @param cc the expected command
+ * @param status the expected status
+ */
+static enum test_return do_validate_response_header(response *rsp,
+ uint8_t cc, uint16_t status)
+{
+ verify(rsp->plain.message.header.response.magic == PROTOCOL_BINARY_RES);
+ verify(rsp->plain.message.header.response.opcode == cc);
+ verify(rsp->plain.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
+ verify(rsp->plain.message.header.response.status == status);
+ verify(rsp->plain.message.header.response.opaque == 0xdeadbeef);
+
+ if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS)
+ {
+ switch (cc) {
+ case PROTOCOL_BINARY_CMD_ADDQ:
+ case PROTOCOL_BINARY_CMD_APPENDQ:
+ case PROTOCOL_BINARY_CMD_DECREMENTQ:
+ case PROTOCOL_BINARY_CMD_DELETEQ:
+ case PROTOCOL_BINARY_CMD_FLUSHQ:
+ case PROTOCOL_BINARY_CMD_INCREMENTQ:
+ case PROTOCOL_BINARY_CMD_PREPENDQ:
+ case PROTOCOL_BINARY_CMD_QUITQ:
+ case PROTOCOL_BINARY_CMD_REPLACEQ:
+ case PROTOCOL_BINARY_CMD_SETQ:
+ verify("Quiet command shouldn't return on success" == NULL);
+ default:
+ break;
+ }
+
+ switch (cc) {
+ case PROTOCOL_BINARY_CMD_ADD:
+ case PROTOCOL_BINARY_CMD_REPLACE:
+ case PROTOCOL_BINARY_CMD_SET:
+ case PROTOCOL_BINARY_CMD_APPEND:
+ case PROTOCOL_BINARY_CMD_PREPEND:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ verify(rsp->plain.message.header.response.bodylen == 0);
+ verify(rsp->plain.message.header.response.cas != 0);
+ break;
+ case PROTOCOL_BINARY_CMD_FLUSH:
+ case PROTOCOL_BINARY_CMD_NOOP:
+ case PROTOCOL_BINARY_CMD_QUIT:
+ case PROTOCOL_BINARY_CMD_DELETE:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ verify(rsp->plain.message.header.response.bodylen == 0);
+ verify(rsp->plain.message.header.response.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_DECREMENT:
+ case PROTOCOL_BINARY_CMD_INCREMENT:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ verify(rsp->plain.message.header.response.bodylen == 8);
+ verify(rsp->plain.message.header.response.cas != 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_STAT:
+ verify(rsp->plain.message.header.response.extlen == 0);
+ /* key and value exists in all packets except in the terminating */
+ verify(rsp->plain.message.header.response.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_VERSION:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ verify(rsp->plain.message.header.response.bodylen != 0);
+ verify(rsp->plain.message.header.response.cas == 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_GET:
+ case PROTOCOL_BINARY_CMD_GETQ:
+ verify(rsp->plain.message.header.response.keylen == 0);
+ verify(rsp->plain.message.header.response.extlen == 4);
+ verify(rsp->plain.message.header.response.cas != 0);
+ break;
+
+ case PROTOCOL_BINARY_CMD_GETK:
+ case PROTOCOL_BINARY_CMD_GETKQ:
+ verify(rsp->plain.message.header.response.keylen != 0);
+ verify(rsp->plain.message.header.response.extlen == 4);
+ verify(rsp->plain.message.header.response.cas != 0);
+ break;
+
+ default:
+ /* Undefined command code */
+ break;
+ }
+ }
+ else
+ {
+ verify(rsp->plain.message.header.response.cas == 0);
+ verify(rsp->plain.message.header.response.extlen == 0);
+ if (cc != PROTOCOL_BINARY_CMD_GETK)
+ {
+ verify(rsp->plain.message.header.response.keylen == 0);
+ }
+ }
+
+ return TEST_PASS;
+}
+
+/* We call verify(validate_response_header), but that macro
+ * expects a boolean expression, and the function returns
+ * an enum.... Let's just create a macro to avoid cluttering
+ * the code with all of the == TEST_PASS ;-)
+ */
+#define validate_response_header(a,b,c) \
+ do_validate_response_header(a,b,c) == TEST_PASS
+
+
+static enum test_return send_binary_noop(void)
+{
+ command cmd;
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_NOOP, NULL, 0, NULL, 0);
+ execute(send_packet(&cmd));
+ return TEST_PASS;
+}
+
+static enum test_return receive_binary_noop(void)
+{
+ response rsp;
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_NOOP,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_noop(void)
+{
+ execute(send_binary_noop());
+ execute(receive_binary_noop());
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_quit_impl(uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ raw_command(&cmd, cc, NULL, 0, NULL, 0);
+
+ execute(send_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_QUIT)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_QUIT,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+
+ /* Socket should be closed now, read should return EXIT_SUCCESS */
+ verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0);
+
+ return TEST_PASS_RECONNECT;
+}
+
+static enum test_return test_binary_quit(void)
+{
+ return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
+}
+
+static enum test_return test_binary_quitq(void)
+{
+ return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
+}
+
+static enum test_return test_binary_set_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+
+ uint64_t value= 0xdeadbeefdeadcafe;
+ storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
+
+ /* set should always work */
+ for (int ii= 0; ii < 10; ii++)
+ {
+ if (ii == 0)
+ execute(send_packet(&cmd));
+ else
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_SET)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ execute(test_binary_noop());
+ }
+
+ /*
+ * We need to get the current CAS id, and at this time we haven't
+ * verified that we have a working get
+ */
+ if (cc == PROTOCOL_BINARY_CMD_SETQ)
+ {
+ cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET;
+ execute(resend_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
+ }
+
+ /* try to set with the correct CAS value */
+ cmd.plain.message.header.request.cas=
+ htonll(rsp.plain.message.header.response.cas);
+ execute(resend_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_SET)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ execute(test_binary_noop());
+
+ /* try to set with an incorrect CAS value */
+ cmd.plain.message.header.request.cas=
+ htonll(rsp.plain.message.header.response.cas - 1);
+ execute(resend_packet(&cmd));
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
+ execute(receive_binary_noop());
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_set(void)
+{
+ return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
+}
+
+static enum test_return test_binary_setq(void)
+{
+ return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
+}
+
+static enum test_return test_binary_add_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ uint64_t value= 0xdeadbeefdeadcafe;
+ storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
+
+ /* first add should work, rest of them should fail (even with cas
+ as wildcard */
+ for (int ii=0; ii < 10; ii++)
+ {
+ if (ii == 0)
+ execute(send_packet(&cmd));
+ else
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_ADD || ii > 0)
+ {
+ uint16_t expected_result;
+ if (ii == 0)
+ expected_result= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ else
+ expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ execute(receive_binary_noop());
+ verify(validate_response_header(&rsp, cc, expected_result));
+ }
+ else
+ execute(test_binary_noop());
+ }
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_add(void)
+{
+ return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
+}
+
+static enum test_return test_binary_addq(void)
+{
+ return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
+}
+
+static enum test_return binary_set_item(const char *key, const char *value)
+{
+ command cmd;
+ response rsp;
+ storage_command(&cmd, PROTOCOL_BINARY_CMD_SET, key, strlen(key),
+ value, strlen(value), 0, 0);
+ execute(send_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_replace_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ uint64_t value= 0xdeadbeefdeadcafe;
+ storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
+
+ /* first replace should fail, successive should succeed (when the
+ item is added! */
+ for (int ii= 0; ii < 10; ii++)
+ {
+ if (ii == 0)
+ execute(send_packet(&cmd));
+ else
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0)
+ {
+ uint16_t expected_result;
+ if (ii == 0)
+ expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
+ else
+ expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS;
+
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ execute(receive_binary_noop());
+ verify(validate_response_header(&rsp, cc, expected_result));
+
+ if (ii == 0)
+ execute(binary_set_item(key, key));
+ }
+ else
+ execute(test_binary_noop());
+ }
+
+ /* verify that replace with CAS value works! */
+ cmd.plain.message.header.request.cas=
+ htonll(rsp.plain.message.header.response.cas);
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_REPLACE)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ execute(test_binary_noop());
+
+ /* try to set with an incorrect CAS value */
+ cmd.plain.message.header.request.cas=
+ htonll(rsp.plain.message.header.response.cas - 1);
+ execute(resend_packet(&cmd));
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ execute(receive_binary_noop());
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_replace(void)
+{
+ return test_binary_replace_impl("test_binary_replace", PROTOCOL_BINARY_CMD_REPLACE);
+}
+
+static enum test_return test_binary_replaceq(void)
+{
+ return test_binary_replace_impl("test_binary_replaceq", PROTOCOL_BINARY_CMD_REPLACEQ);
+}
+
+static enum test_return test_binary_delete_impl(const char *key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ raw_command(&cmd, cc, key, strlen(key), NULL, 0);
+
+ /* The delete shouldn't work the first time, because the item isn't there */
+ execute(send_packet(&cmd));
+ execute(send_binary_noop());
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
+ execute(receive_binary_noop());
+ execute(binary_set_item(key, key));
+
+ /* The item should be present now, resend*/
+ execute(resend_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_DELETE)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+
+ execute(test_binary_noop());
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_delete(void)
+{
+ return test_binary_delete_impl("test_binary_delete", PROTOCOL_BINARY_CMD_DELETE);
+}
+
+static enum test_return test_binary_deleteq(void)
+{
+ return test_binary_delete_impl("test_binary_deleteq", PROTOCOL_BINARY_CMD_DELETEQ);
+}
+
+static enum test_return test_binary_get_impl(const char *key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+
+ raw_command(&cmd, cc, key, strlen(key), NULL, 0);
+ execute(send_packet(&cmd));
+ execute(send_binary_noop());
+
+ if (cc == PROTOCOL_BINARY_CMD_GET || cc == PROTOCOL_BINARY_CMD_GETK)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
+ }
+
+ execute(receive_binary_noop());
+
+ execute(binary_set_item(key, key));
+ execute(resend_packet(&cmd));
+ execute(send_binary_noop());
+
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ execute(receive_binary_noop());
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_get(void)
+{
+ return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
+}
+
+static enum test_return test_binary_getk(void)
+{
+ return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
+}
+
+static enum test_return test_binary_getq(void)
+{
+ return test_binary_get_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
+}
+
+static enum test_return test_binary_getkq(void)
+{
+ return test_binary_get_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
+}
+
+static enum test_return test_binary_incr_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ arithmetic_command(&cmd, cc, key, strlen(key), 1, 0, 0);
+
+ uint64_t ii;
+ for (ii= 0; ii < 10; ++ii)
+ {
+ if (ii == 0)
+ execute(send_packet(&cmd));
+ else
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_INCREMENT)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ verify(ntohll(rsp.incr.message.body.value) == ii);
+ }
+ else
+ execute(test_binary_noop());
+ }
+
+ /* @todo add incorrect CAS */
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_incr(void)
+{
+ return test_binary_incr_impl("test_binary_incr", PROTOCOL_BINARY_CMD_INCREMENT);
+}
+
+static enum test_return test_binary_incrq(void)
+{
+ return test_binary_incr_impl("test_binary_incrq", PROTOCOL_BINARY_CMD_INCREMENTQ);
+}
+
+static enum test_return test_binary_decr_impl(const char* key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ arithmetic_command(&cmd, cc, key, strlen(key), 1, 9, 0);
+
+ int ii;
+ for (ii= 9; ii > -1; --ii)
+ {
+ if (ii == 9)
+ execute(send_packet(&cmd));
+ else
+ execute(resend_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ verify(ntohll(rsp.decr.message.body.value) == (uint64_t)ii);
+ }
+ else
+ execute(test_binary_noop());
+ }
+
+ /* decr 0 should not wrap */
+ execute(resend_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ verify(ntohll(rsp.decr.message.body.value) == 0);
+ }
+ else
+ {
+ /* @todo get the value and verify! */
+
+ }
+
+ /* @todo add incorrect cas */
+ execute(test_binary_noop());
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_decr(void)
+{
+ return test_binary_decr_impl("test_binary_decr",
+ PROTOCOL_BINARY_CMD_DECREMENT);
+}
+
+static enum test_return test_binary_decrq(void)
+{
+ return test_binary_decr_impl("test_binary_decrq",
+ PROTOCOL_BINARY_CMD_DECREMENTQ);
+}
+
+static enum test_return test_binary_version(void)
+{
+ command cmd;
+ response rsp;
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_VERSION, NULL, 0, NULL, 0);
+
+ execute(send_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_VERSION,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_flush_impl(const char *key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+
+ for (int ii= 0; ii < 2; ++ii)
+ {
+ execute(binary_set_item(key, key));
+ flush_command(&cmd, cc, 0, ii == 0);
+ execute(send_packet(&cmd));
+
+ if (cc == PROTOCOL_BINARY_CMD_FLUSH)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ execute(test_binary_noop());
+
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
+ execute(send_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
+ PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
+ }
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_flush(void)
+{
+ return test_binary_flush_impl("test_binary_flush", PROTOCOL_BINARY_CMD_FLUSH);
+}
+
+static enum test_return test_binary_flushq(void)
+{
+ return test_binary_flush_impl("test_binary_flushq", PROTOCOL_BINARY_CMD_FLUSHQ);
+}
+
+static enum test_return test_binary_concat_impl(const char *key, uint8_t cc)
+{
+ command cmd;
+ response rsp;
+ const char *value;
+
+ if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
+ value="hello";
+ else
+ value=" world";
+
+ execute(binary_set_item(key, value));
+
+ if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
+ value=" world";
+ else
+ value="hello";
+
+ raw_command(&cmd, cc, key, strlen(key), value, strlen(value));
+ execute(send_packet(&cmd));
+ if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_PREPEND)
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ }
+ else
+ execute(test_binary_noop());
+
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
+ execute(send_packet(&cmd));
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ verify(rsp.plain.message.header.response.bodylen - 4 == 11);
+ verify(memcmp(rsp.bytes + 28, "hello world", 11) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return test_binary_append(void)
+{
+ return test_binary_concat_impl("test_binary_append", PROTOCOL_BINARY_CMD_APPEND);
+}
+
+static enum test_return test_binary_prepend(void)
+{
+ return test_binary_concat_impl("test_binary_prepend", PROTOCOL_BINARY_CMD_PREPEND);
+}
+
+static enum test_return test_binary_appendq(void)
+{
+ return test_binary_concat_impl("test_binary_appendq", PROTOCOL_BINARY_CMD_APPENDQ);
+}
+
+static enum test_return test_binary_prependq(void)
+{
+ return test_binary_concat_impl("test_binary_prependq", PROTOCOL_BINARY_CMD_PREPENDQ);
+}
+
+static enum test_return test_binary_stat(void)
+{
+ command cmd;
+ response rsp;
+
+ raw_command(&cmd, PROTOCOL_BINARY_CMD_STAT, NULL, 0, NULL, 0);
+ execute(send_packet(&cmd));
+
+ do
+ {
+ execute(recv_packet(&rsp));
+ verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_STAT,
+ PROTOCOL_BINARY_RESPONSE_SUCCESS));
+ } while (rsp.plain.message.header.response.keylen != 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return send_string(const char *cmd)
+{
+ execute(retry_write(cmd, strlen(cmd)));
+ return TEST_PASS;
+}
+
+static enum test_return receive_line(char *buffer, size_t size)
+{
+ size_t offset= 0;
+ while (offset < size)
+ {
+ execute(retry_read(buffer + offset, 1));
+ if (buffer[offset] == '\n')
+ {
+ if (offset + 1 < size)
+ {
+ buffer[offset + 1]= '\0';
+ return TEST_PASS;
+ }
+ else
+ return TEST_FAIL;
+ }
+ ++offset;
+ }
+
+ return TEST_FAIL;
+}
+
+static enum test_return receive_response(const char *msg) {
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ if (strcmp(msg, buffer) != 0) {
+ fprintf(stderr, "[%s]\n", buffer);
+ }
+ verify(strcmp(msg, buffer) == 0);
+ return TEST_PASS;
+}
+
+static enum test_return receive_error_response(void)
+{
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "ERROR", 5) == 0 ||
+ strncmp(buffer, "CLIENT_ERROR", 12) == 0 ||
+ strncmp(buffer, "SERVER_ERROR", 12) == 0);
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_quit(void)
+{
+ /* Verify that quit handles unknown options */
+ execute(send_string("quit foo bar\r\n"));
+ execute(receive_error_response());
+
+ /* quit doesn't support noreply */
+ execute(send_string("quit noreply\r\n"));
+ execute(receive_error_response());
+
+ /* Verify that quit works */
+ execute(send_string("quit\r\n"));
+
+ /* Socket should be closed now, read should return EXIT_SUCCESS */
+ char buffer[80];
+ verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0);
+ return TEST_PASS_RECONNECT;
+
+}
+
+static enum test_return test_ascii_version(void)
+{
+ /* Verify that version command handles unknown options */
+ execute(send_string("version foo bar\r\n"));
+ execute(receive_error_response());
+
+ /* version doesn't support noreply */
+ execute(send_string("version noreply\r\n"));
+ execute(receive_error_response());
+
+ /* Verify that verify works */
+ execute(send_string("version\r\n"));
+ char buffer[256];
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "VERSION ", 8) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_verbosity(void)
+{
+ /* This command does not adhere to the spec! */
+ execute(send_string("verbosity foo bar my\r\n"));
+ execute(receive_error_response());
+
+ execute(send_string("verbosity noreply\r\n"));
+ execute(receive_error_response());
+
+ execute(send_string("verbosity 0 noreply\r\n"));
+ execute(test_ascii_version());
+
+ execute(send_string("verbosity\r\n"));
+ execute(receive_error_response());
+
+ execute(send_string("verbosity 1\r\n"));
+ execute(receive_response("OK\r\n"));
+
+ execute(send_string("verbosity 0\r\n"));
+ execute(receive_response("OK\r\n"));
+
+ return TEST_PASS;
+}
+
+
+
+static enum test_return test_ascii_set_impl(const char* key, bool noreply)
+{
+ /* @todo add tests for bogus format! */
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (!noreply)
+ execute(receive_response("STORED\r\n"));
+
+ return test_ascii_version();
+}
+
+static enum test_return test_ascii_set(void)
+{
+ return test_ascii_set_impl("test_ascii_set", false);
+}
+
+static enum test_return test_ascii_set_noreply(void)
+{
+ return test_ascii_set_impl("test_ascii_set_noreply", true);
+}
+
+static enum test_return test_ascii_add_impl(const char* key, bool noreply)
+{
+ /* @todo add tests for bogus format! */
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (!noreply)
+ execute(receive_response("STORED\r\n"));
+
+ execute(send_string(buffer));
+
+ if (!noreply)
+ execute(receive_response("NOT_STORED\r\n"));
+
+ return test_ascii_version();
+}
+
+static enum test_return test_ascii_add(void)
+{
+ return test_ascii_add_impl("test_ascii_add", false);
+}
+
+static enum test_return test_ascii_add_noreply(void)
+{
+ return test_ascii_add_impl("test_ascii_add_noreply", true);
+}
+
+static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata)
+{
+ char buffer[1024];
+
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "VALUE ", 6) == 0);
+ char *end= strchr(buffer + 6, ' ');
+ verify(end != NULL);
+ *end= '\0';
+ *key= strdup(buffer + 6);
+ verify(*key != NULL);
+ char *ptr= end + 1;
+
+ unsigned long val= strtoul(ptr, &end, 10); /* flags */
+ verify(ptr != end);
+ verify(val == 0);
+ verify(end != NULL);
+ *ndata = (ssize_t)strtoul(end, &end, 10); /* size */
+ verify(ptr != end);
+ verify(end != NULL);
+ while (*end != '\n' && isspace(*end))
+ ++end;
+ verify(*end == '\n');
+
+ *value= static_cast<char*>(malloc((size_t)*ndata));
+ verify(*value != NULL);
+
+ execute(retry_read(*value, (size_t)*ndata));
+
+ execute(retry_read(buffer, 2));
+ verify(memcmp(buffer, "\r\n", 2) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_get_value(const char *key, const char *value)
+{
+
+ char buffer[1024];
+ size_t datasize= strlen(value);
+
+ verify(datasize < sizeof(buffer));
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "VALUE ", 6) == 0);
+ verify(strncmp(buffer + 6, key, strlen(key)) == 0);
+ char *ptr= buffer + 6 + strlen(key) + 1;
+ char *end;
+
+ unsigned long val= strtoul(ptr, &end, 10); /* flags */
+ verify(ptr != end);
+ verify(val == 0);
+ verify(end != NULL);
+ val= strtoul(end, &end, 10); /* size */
+ verify(ptr != end);
+ verify(val == datasize);
+ verify(end != NULL);
+ while (*end != '\n' && isspace(*end))
+ ++end;
+ verify(*end == '\n');
+
+ execute(retry_read(buffer, datasize));
+ verify(memcmp(buffer, value, datasize) == 0);
+
+ execute(retry_read(buffer, 2));
+ verify(memcmp(buffer, "\r\n", 2) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_get_item(const char *key, const char *value,
+ bool exist)
+{
+ char buffer[1024];
+ size_t datasize= 0;
+ if (value != NULL)
+ datasize= strlen(value);
+
+ verify(datasize < sizeof(buffer));
+ snprintf(buffer, sizeof(buffer), "get %s\r\n", key);
+ execute(send_string(buffer));
+
+ if (exist)
+ execute(ascii_get_value(key, value));
+
+ execute(retry_read(buffer, 5));
+ verify(memcmp(buffer, "END\r\n", 5) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_gets_value(const char *key, const char *value,
+ unsigned long *cas)
+{
+
+ char buffer[1024];
+ size_t datasize= strlen(value);
+
+ verify(datasize < sizeof(buffer));
+ execute(receive_line(buffer, sizeof(buffer)));
+ verify(strncmp(buffer, "VALUE ", 6) == 0);
+ verify(strncmp(buffer + 6, key, strlen(key)) == 0);
+ char *ptr= buffer + 6 + strlen(key) + 1;
+ char *end;
+
+ unsigned long val= strtoul(ptr, &end, 10); /* flags */
+ verify(ptr != end);
+ verify(val == 0);
+ verify(end != NULL);
+ val= strtoul(end, &end, 10); /* size */
+ verify(ptr != end);
+ verify(val == datasize);
+ verify(end != NULL);
+ *cas= strtoul(end, &end, 10); /* cas */
+ verify(ptr != end);
+ verify(val == datasize);
+ verify(end != NULL);
+
+ while (*end != '\n' && isspace(*end))
+ ++end;
+ verify(*end == '\n');
+
+ execute(retry_read(buffer, datasize));
+ verify(memcmp(buffer, value, datasize) == 0);
+
+ execute(retry_read(buffer, 2));
+ verify(memcmp(buffer, "\r\n", 2) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_gets_item(const char *key, const char *value,
+ bool exist, unsigned long *cas)
+{
+ char buffer[1024];
+ size_t datasize= 0;
+ if (value != NULL)
+ datasize= strlen(value);
+
+ verify(datasize < sizeof(buffer));
+ snprintf(buffer, sizeof(buffer), "gets %s\r\n", key);
+ execute(send_string(buffer));
+
+ if (exist)
+ execute(ascii_gets_value(key, value, cas));
+
+ execute(retry_read(buffer, 5));
+ verify(memcmp(buffer, "END\r\n", 5) == 0);
+
+ return TEST_PASS;
+}
+
+static enum test_return ascii_set_item(const char *key, const char *value)
+{
+ char buffer[300];
+ size_t len= strlen(value);
+ snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len);
+ execute(send_string(buffer));
+ execute(retry_write(value, len));
+ execute(send_string("\r\n"));
+ execute(receive_response("STORED\r\n"));
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_replace_impl(const char* key, bool noreply)
+{
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("NOT_STORED\r\n"));
+
+ execute(ascii_set_item(key, "value"));
+ execute(ascii_get_item(key, "value", true));
+
+
+ execute(send_string(buffer));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("STORED\r\n"));
+
+ return test_ascii_version();
+}
+
+static enum test_return test_ascii_replace(void)
+{
+ return test_ascii_replace_impl("test_ascii_replace", false);
+}
+
+static enum test_return test_ascii_replace_noreply(void)
+{
+ return test_ascii_replace_impl("test_ascii_replace_noreply", true);
+}
+
+static enum test_return test_ascii_cas_impl(const char* key, bool noreply)
+{
+ char buffer[1024];
+ unsigned long cas;
+
+ execute(ascii_set_item(key, "value"));
+ execute(ascii_gets_item(key, "value", true, &cas));
+
+ snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("STORED\r\n"));
+
+ /* reexecute the same command should fail due to illegal cas */
+ execute(send_string(buffer));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("EXISTS\r\n"));
+
+ return test_ascii_version();
+}
+
+static enum test_return test_ascii_cas(void)
+{
+ return test_ascii_cas_impl("test_ascii_cas", false);
+}
+
+static enum test_return test_ascii_cas_noreply(void)
+{
+ return test_ascii_cas_impl("test_ascii_cas_noreply", true);
+}
+
+static enum test_return test_ascii_delete_impl(const char *key, bool noreply)
+{
+ execute(ascii_set_item(key, "value"));
+
+ execute(send_string("delete\r\n"));
+ execute(receive_error_response());
+ /* BUG: the server accepts delete a b */
+ execute(send_string("delete a b c d e\r\n"));
+ execute(receive_error_response());
+
+ char buffer[1024];
+ snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : "");
+ execute(send_string(buffer));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("DELETED\r\n"));
+
+ execute(ascii_get_item(key, "value", false));
+ execute(send_string(buffer));
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("NOT_FOUND\r\n"));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_delete(void)
+{
+ return test_ascii_delete_impl("test_ascii_delete", false);
+}
+
+static enum test_return test_ascii_delete_noreply(void)
+{
+ return test_ascii_delete_impl("test_ascii_delete_noreply", true);
+}
+
+static enum test_return test_ascii_get(void)
+{
+ execute(ascii_set_item("test_ascii_get", "value"));
+
+ execute(send_string("get\r\n"));
+ execute(receive_error_response());
+ execute(ascii_get_item("test_ascii_get", "value", true));
+ execute(ascii_get_item("test_ascii_get_notfound", "value", false));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_gets(void)
+{
+ execute(ascii_set_item("test_ascii_gets", "value"));
+
+ execute(send_string("gets\r\n"));
+ execute(receive_error_response());
+ unsigned long cas;
+ execute(ascii_gets_item("test_ascii_gets", "value", true, &cas));
+ execute(ascii_gets_item("test_ascii_gets_notfound", "value", false, &cas));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_mget(void)
+{
+ const uint32_t nkeys= 5;
+ const char * const keys[]= {
+ "test_ascii_mget1",
+ "test_ascii_mget2",
+ /* test_ascii_mget_3 does not exist :) */
+ "test_ascii_mget4",
+ "test_ascii_mget5",
+ "test_ascii_mget6"
+ };
+
+ for (uint32_t x= 0; x < nkeys; ++x)
+ execute(ascii_set_item(keys[x], "value"));
+
+ /* Ask for a key that doesn't exist as well */
+ execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 "
+ "test_ascii_mget4 test_ascii_mget5 "
+ "test_ascii_mget6\r\n"));
+
+ char *returned[nkeys];
+
+ for (uint32_t x= 0; x < nkeys; ++x)
+ {
+ ssize_t nbytes = 0;
+ char *v= NULL;
+ execute(ascii_get_unknown_value(&returned[x], &v, &nbytes));
+ verify(nbytes == 5);
+ verify(memcmp(v, "value", 5) == 0);
+ free(v);
+ }
+
+ char buffer[5];
+ execute(retry_read(buffer, 5));
+ verify(memcmp(buffer, "END\r\n", 5) == 0);
+
+ /* verify that we got all the keys we expected */
+ for (uint32_t x= 0; x < nkeys; ++x)
+ {
+ bool found= false;
+ for (uint32_t y= 0; y < nkeys; ++y)
+ {
+ if (strcmp(keys[x], returned[y]) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+ verify(found);
+ }
+
+ for (uint32_t x= 0; x < nkeys; ++x)
+ free(returned[x]);
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_incr_impl(const char* key, bool noreply)
+{
+ char cmd[300];
+ snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : "");
+
+ execute(ascii_set_item(key, "0"));
+ for (int x= 1; x < 11; ++x)
+ {
+ execute(send_string(cmd));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ {
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ int val= atoi(buffer);
+ verify(val == x);
+ }
+ }
+
+ execute(ascii_get_item(key, "10", true));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_incr(void)
+{
+ return test_ascii_incr_impl("test_ascii_incr", false);
+}
+
+static enum test_return test_ascii_incr_noreply(void)
+{
+ return test_ascii_incr_impl("test_ascii_incr_noreply", true);
+}
+
+static enum test_return test_ascii_decr_impl(const char* key, bool noreply)
+{
+ char cmd[300];
+ snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : "");
+
+ execute(ascii_set_item(key, "9"));
+ for (int x= 8; x > -1; --x)
+ {
+ execute(send_string(cmd));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ {
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ int val= atoi(buffer);
+ verify(val == x);
+ }
+ }
+
+ execute(ascii_get_item(key, "0", true));
+
+ /* verify that it doesn't wrap */
+ execute(send_string(cmd));
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ {
+ char buffer[80];
+ execute(receive_line(buffer, sizeof(buffer)));
+ }
+ execute(ascii_get_item(key, "0", true));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_decr(void)
+{
+ return test_ascii_decr_impl("test_ascii_decr", false);
+}
+
+static enum test_return test_ascii_decr_noreply(void)
+{
+ return test_ascii_decr_impl("test_ascii_decr_noreply", true);
+}
+
+
+static enum test_return test_ascii_flush_impl(const char *key, bool noreply)
+{
+#if 0
+ /* Verify that the flush_all command handles unknown options */
+ /* Bug in the current memcached server! */
+ execute(send_string("flush_all foo bar\r\n"));
+ execute(receive_error_response());
+#endif
+
+ execute(ascii_set_item(key, key));
+ execute(ascii_get_item(key, key, true));
+
+ if (noreply)
+ {
+ execute(send_string("flush_all noreply\r\n"));
+ execute(test_ascii_version());
+ }
+ else
+ {
+ execute(send_string("flush_all\r\n"));
+ execute(receive_response("OK\r\n"));
+ }
+
+ execute(ascii_get_item(key, key, false));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_flush(void)
+{
+ return test_ascii_flush_impl("test_ascii_flush", false);
+}
+
+static enum test_return test_ascii_flush_noreply(void)
+{
+ return test_ascii_flush_impl("test_ascii_flush_noreply", true);
+}
+
+static enum test_return test_ascii_concat_impl(const char *key,
+ bool append,
+ bool noreply)
+{
+ const char *value;
+
+ if (append)
+ value="hello";
+ else
+ value=" world";
+
+ execute(ascii_set_item(key, value));
+
+ if (append)
+ value=" world";
+ else
+ value="hello";
+
+ char cmd[400];
+ snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n",
+ append ? "append" : "prepend",
+ key, (unsigned int)strlen(value), noreply ? " noreply" : "",
+ value);
+ execute(send_string(cmd));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("STORED\r\n"));
+
+ execute(ascii_get_item(key, "hello world", true));
+
+ snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n",
+ append ? "append" : "prepend",
+ key, (unsigned int)strlen(value), noreply ? " noreply" : "",
+ value);
+ execute(send_string(cmd));
+
+ if (noreply)
+ execute(test_ascii_version());
+ else
+ execute(receive_response("NOT_STORED\r\n"));
+
+ return TEST_PASS;
+}
+
+static enum test_return test_ascii_append(void)
+{
+ return test_ascii_concat_impl("test_ascii_append", true, false);
+}
+
+static enum test_return test_ascii_prepend(void)
+{
+ return test_ascii_concat_impl("test_ascii_prepend", false, false);
+}
+
+static enum test_return test_ascii_append_noreply(void)
+{
+ return test_ascii_concat_impl("test_ascii_append_noreply", true, true);
+}
+
+static enum test_return test_ascii_prepend_noreply(void)
+{
+ return test_ascii_concat_impl("test_ascii_prepend_noreply", false, true);
+}
+
+static enum test_return test_ascii_stat(void)
+{
+ execute(send_string("stats noreply\r\n"));
+ execute(receive_error_response());
+ execute(send_string("stats\r\n"));
+ char buffer[1024];
+ do {
+ execute(receive_line(buffer, sizeof(buffer)));
+ } while (strcmp(buffer, "END\r\n") != 0);
+
+ return TEST_PASS_RECONNECT;
+}
+
+typedef enum test_return(*TEST_FUNC)(void);
+
+struct testcase
+{
+ const char *description;
+ TEST_FUNC function;
+};
+
+struct testcase testcases[]= {
+ { "ascii quit", test_ascii_quit },
+ { "ascii version", test_ascii_version },
+ { "ascii verbosity", test_ascii_verbosity },
+ { "ascii set", test_ascii_set },
+ { "ascii set noreply", test_ascii_set_noreply },
+ { "ascii get", test_ascii_get },
+ { "ascii gets", test_ascii_gets },
+ { "ascii mget", test_ascii_mget },
+ { "ascii flush", test_ascii_flush },
+ { "ascii flush noreply", test_ascii_flush_noreply },
+ { "ascii add", test_ascii_add },
+ { "ascii add noreply", test_ascii_add_noreply },
+ { "ascii replace", test_ascii_replace },
+ { "ascii replace noreply", test_ascii_replace_noreply },
+ { "ascii cas", test_ascii_cas },
+ { "ascii cas noreply", test_ascii_cas_noreply },
+ { "ascii delete", test_ascii_delete },
+ { "ascii delete noreply", test_ascii_delete_noreply },
+ { "ascii incr", test_ascii_incr },
+ { "ascii incr noreply", test_ascii_incr_noreply },
+ { "ascii decr", test_ascii_decr },
+ { "ascii decr noreply", test_ascii_decr_noreply },
+ { "ascii append", test_ascii_append },
+ { "ascii append noreply", test_ascii_append_noreply },
+ { "ascii prepend", test_ascii_prepend },
+ { "ascii prepend noreply", test_ascii_prepend_noreply },
+ { "ascii stat", test_ascii_stat },
+ { "binary noop", test_binary_noop },
+ { "binary quit", test_binary_quit },
+ { "binary quitq", test_binary_quitq },
+ { "binary set", test_binary_set },
+ { "binary setq", test_binary_setq },
+ { "binary flush", test_binary_flush },
+ { "binary flushq", test_binary_flushq },
+ { "binary add", test_binary_add },
+ { "binary addq", test_binary_addq },
+ { "binary replace", test_binary_replace },
+ { "binary replaceq", test_binary_replaceq },
+ { "binary delete", test_binary_delete },
+ { "binary deleteq", test_binary_deleteq },
+ { "binary get", test_binary_get },
+ { "binary getq", test_binary_getq },
+ { "binary getk", test_binary_getk },
+ { "binary getkq", test_binary_getkq },
+ { "binary incr", test_binary_incr },
+ { "binary incrq", test_binary_incrq },
+ { "binary decr", test_binary_decr },
+ { "binary decrq", test_binary_decrq },
+ { "binary version", test_binary_version },
+ { "binary append", test_binary_append },
+ { "binary appendq", test_binary_appendq },
+ { "binary prepend", test_binary_prepend },
+ { "binary prependq", test_binary_prependq },
+ { "binary stat", test_binary_stat },
+ { NULL, NULL}
+};
+
+const int ascii_tests = 1;
+const int binary_tests = 2;
+
+struct test_type_st
+{
+ bool ascii;
+ bool binary;
+};
+
+int main(int argc, char **argv)
+{
+ static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"};
+ struct test_type_st tests= { true, true };
+ int total= 0;
+ int failed= 0;
+ const char *hostname= "localhost";
+ const char *port= "11211";
+ int cmd;
+ bool prompt= false;
+ const char *testname= NULL;
+
+
+
+ while ((cmd= getopt(argc, argv, "t:vch:p:PT:?ab")) != EOF)
+ {
+ switch (cmd) {
+ case 'a':
+ tests.ascii= true;
+ tests.binary= false;
+ break;
+ case 'b':
+ tests.ascii= false;
+ tests.binary= true;
+ break;
+ case 't':
+ timeout= atoi(optarg);
+ if (timeout == 0)
+ {
+ fprintf(stderr, "Invalid timeout. Please specify a number for -t\n");
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'v': verbose= true;
+ break;
+ case 'c': do_core= true;
+ break;
+ case 'h': hostname= optarg;
+ break;
+ case 'p': port= optarg;
+ break;
+ case 'P': prompt= true;
+ break;
+ case 'T': testname= optarg;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n"
+ "\t-c\tGenerate coredump if a test fails\n"
+ "\t-v\tVerbose test output (print out the assertion)\n"
+ "\t-t n\tSet the timeout for io-operations to n seconds\n"
+ "\t-P\tPrompt the user before starting a test.\n"
+ "\t\t\t\"skip\" will skip the test\n"
+ "\t\t\t\"quit\" will terminate memcapable\n"
+ "\t\t\tEverything else will start the test\n"
+ "\t-T n\tJust run the test named n\n"
+ "\t-a\tOnly test the ascii protocol\n"
+ "\t-b\tOnly test the binary protocol\n",
+ argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ initialize_sockets();
+ sock= connect_server(hostname, port);
+ if (sock == INVALID_SOCKET)
+ {
+ fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
+ hostname, port, strerror(get_socket_errno()));
+ return EXIT_FAILURE;
+ }
+
+ for (int ii= 0; testcases[ii].description != NULL; ++ii)
+ {
+ if (testname != NULL && strcmp(testcases[ii].description, testname) != 0)
+ continue;
+
+ if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) ||
+ (testcases[ii].description[0] == 'b' && (tests.binary) == 0))
+ {
+ continue;
+ }
+ ++total;
+ fprintf(stdout, "%-40s", testcases[ii].description);
+ fflush(stdout);
+
+ if (prompt)
+ {
+ fprintf(stdout, "\nPress <return> when you are ready? ");
+ char buffer[80] = {0};
+ if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
+ if (strncmp(buffer, "skip", 4) == 0)
+ {
+ fprintf(stdout, "%-40s%s\n", testcases[ii].description,
+ status_msg[TEST_SKIP]);
+ fflush(stdout);
+ continue;
+ }
+ if (strncmp(buffer, "quit", 4) == 0)
+ exit(0);
+ }
+
+ fprintf(stdout, "%-40s", testcases[ii].description);
+ fflush(stdout);
+ }
+
+ bool reconnect= false;
+ enum test_return ret= testcases[ii].function();
+ if (ret == TEST_FAIL)
+ {
+ reconnect= true;
+ ++failed;
+ if (verbose)
+ fprintf(stderr, "\n");
+ }
+ else if (ret == TEST_PASS_RECONNECT)
+ reconnect= true;
+
+ fprintf(stderr, "%s\n", status_msg[ret]);
+ if (reconnect)
+ {
+ closesocket(sock);
+ if ((sock= connect_server(hostname, port)) == INVALID_SOCKET)
+ {
+ fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
+ hostname, port, strerror(get_socket_errno()));
+ fprintf(stderr, "%d of %d tests failed\n", failed, total);
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ closesocket(sock);
+ if (failed == 0)
+ fprintf(stdout, "All tests passed\n");
+ else
+ fprintf(stderr, "%d of %d tests failed\n", failed, total);
+
+ return (failed == 0) ? 0 : 1;
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <libmemcached/memcached.h>
-
-#include "utilities.h"
-
-#define PROGRAM_NAME "memcat"
-#define PROGRAM_DESCRIPTION "Cat a set of key values to stdout."
-
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static int opt_displayflag= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-static char *opt_file;
-
-int main(int argc, char *argv[])
-{
- memcached_st *memc;
- char *string;
- size_t string_length;
- uint32_t flags;
- memcached_return_t rc;
- memcached_server_st *servers;
-
- int return_code= 0;
-
- options_parse(argc, argv);
- initialize_sockets();
-
- if (!opt_servers)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- opt_servers= strdup(temp);
- else
- {
- fprintf(stderr, "No Servers provided\n");
- exit(1);
- }
- }
-
- memc= memcached_create(NULL);
- process_hash_option(memc, opt_hash);
-
- servers= memcached_servers_parse(opt_servers);
-
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t)opt_binary);
-
- if (!initialize_sasl(memc, opt_username, opt_passwd))
- {
- memcached_free(memc);
- return EXIT_FAILURE;
- }
-
- while (optind < argc)
- {
- string= memcached_get(memc, argv[optind], strlen(argv[optind]),
- &string_length, &flags, &rc);
- if (rc == MEMCACHED_SUCCESS)
- {
- if (opt_displayflag)
- {
- if (opt_verbose)
- printf("key: %s\nflags: ", argv[optind]);
- printf("%x\n", flags);
- }
- else
- {
- if (opt_verbose)
- {
- printf("key: %s\nflags: %x\nlength: %zu\nvalue: ",
- argv[optind], flags, string_length);
- }
-
- if (opt_file)
- {
- FILE *fp;
- size_t written;
-
- fp= fopen(opt_file, "w");
- if (!fp)
- {
- perror("fopen");
- return_code= -1;
- break;
- }
-
- written= fwrite(string, 1, string_length, fp);
- if (written != string_length)
- {
- fprintf(stderr, "error writing file (written %zu, should be %zu)\n", written, string_length);
- return_code= -1;
- break;
- }
-
- if (fclose(fp))
- {
- fprintf(stderr, "error closing file\n");
- return_code= -1;
- break;
- }
- }
- else
- {
- printf("%.*s\n", (int)string_length, string);
- }
- free(string);
- }
- }
- else if (rc != MEMCACHED_NOTFOUND)
- {
- fprintf(stderr, "memcat: %s: memcache error %s",
- argv[optind], memcached_strerror(memc, rc));
- if (memcached_last_error_errno(memc))
- {
- fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
- }
- fprintf(stderr, "\n");
-
- return_code= -1;
- break;
- }
- else // Unknown Issue
- {
- fprintf(stderr, "memcat: %s not found\n", argv[optind]);
- return_code= -1;
- }
- optind++;
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- free(opt_servers);
- if (opt_hash)
- free(opt_hash);
-
- shutdown_sasl();
-
- return return_code;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
- int option_index= 0;
- int option_rv;
-
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {(OPTIONSTRING)"file", required_argument, NULL, OPT_FILE},
- {0, 0, 0, 0},
- };
-
- while (1)
- {
- option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1) break;
- switch (option_rv)
- {
- case 0:
- break;
- case OPT_BINARY:
- opt_binary = 1;
- break;
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- break;
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
- case OPT_USERNAME:
- opt_username= optarg;
- break;
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
- case OPT_FILE:
- opt_file= optarg;
- break;
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <libmemcached/memcached.h>
+
+#include "utilities.h"
+
+#define PROGRAM_NAME "memcat"
+#define PROGRAM_DESCRIPTION "Cat a set of key values to stdout."
+
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static int opt_displayflag= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+static char *opt_file;
+
+int main(int argc, char *argv[])
+{
+ memcached_st *memc;
+ char *string;
+ size_t string_length;
+ uint32_t flags;
+ memcached_return_t rc;
+ memcached_server_st *servers;
+
+ int return_code= 0;
+
+ options_parse(argc, argv);
+ initialize_sockets();
+
+ if (!opt_servers)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ opt_servers= strdup(temp);
+ else
+ {
+ fprintf(stderr, "No Servers provided\n");
+ exit(1);
+ }
+ }
+
+ memc= memcached_create(NULL);
+ process_hash_option(memc, opt_hash);
+
+ servers= memcached_servers_parse(opt_servers);
+
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t)opt_binary);
+
+ if (!initialize_sasl(memc, opt_username, opt_passwd))
+ {
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+
+ while (optind < argc)
+ {
+ string= memcached_get(memc, argv[optind], strlen(argv[optind]),
+ &string_length, &flags, &rc);
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ if (opt_displayflag)
+ {
+ if (opt_verbose)
+ printf("key: %s\nflags: ", argv[optind]);
+ printf("%x\n", flags);
+ }
+ else
+ {
+ if (opt_verbose)
+ {
+ printf("key: %s\nflags: %x\nlength: %lu\nvalue: ",
+ argv[optind], flags, (unsigned long)string_length);
+ }
+
+ if (opt_file)
+ {
+ FILE *fp;
+ size_t written;
+
+ fp= fopen(opt_file, "w");
+ if (!fp)
+ {
+ perror("fopen");
+ return_code= -1;
+ break;
+ }
+
+ written= fwrite(string, 1, string_length, fp);
+ if (written != string_length)
+ {
+ fprintf(stderr, "error writing file (written %lu, should be %lu)\n", (unsigned long)written, (unsigned long)string_length);
+ return_code= -1;
+ break;
+ }
+
+ if (fclose(fp))
+ {
+ fprintf(stderr, "error closing file\n");
+ return_code= -1;
+ break;
+ }
+ }
+ else
+ {
+ printf("%.*s\n", (int)string_length, string);
+ }
+ free(string);
+ }
+ }
+ else if (rc != MEMCACHED_NOTFOUND)
+ {
+ fprintf(stderr, "memcat: %s: memcache error %s",
+ argv[optind], memcached_strerror(memc, rc));
+ if (memcached_last_error_errno(memc))
+ {
+ fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+ }
+ fprintf(stderr, "\n");
+
+ return_code= -1;
+ break;
+ }
+ else // Unknown Issue
+ {
+ fprintf(stderr, "memcat: %s not found\n", argv[optind]);
+ return_code= -1;
+ }
+ optind++;
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ free(opt_servers);
+ if (opt_hash)
+ free(opt_hash);
+
+ shutdown_sasl();
+
+ return return_code;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+ int option_index= 0;
+ int option_rv;
+
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {(OPTIONSTRING)"file", required_argument, NULL, OPT_FILE},
+ {0, 0, 0, 0},
+ };
+
+ while (1)
+ {
+ option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1) break;
+ switch (option_rv)
+ {
+ case 0:
+ break;
+ case OPT_BINARY:
+ opt_binary = 1;
+ break;
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ break;
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+ case OPT_FILE:
+ opt_file= optarg;
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <strings.h>
-#include <string.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <limits.h>
-
-
-#include <libmemcached/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-
-#define PROGRAM_NAME "memcp"
-#define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-static int opt_binary=0;
-static int opt_verbose= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static int opt_method= OPT_SET;
-static uint32_t opt_flags= 0;
-static time_t opt_expires= 0;
-static char *opt_username;
-static char *opt_passwd;
-
-static long strtol_wrapper(const char *nptr, int base, bool *error)
-{
- long val;
- char *endptr;
-
- errno= 0; /* To distinguish success/failure after call */
- val= strtol(nptr, &endptr, base);
-
- /* Check for various possible errors */
-
- if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
- || (errno != 0 && val == 0))
- {
- *error= true;
- return EXIT_SUCCESS;
- }
-
- if (endptr == nptr)
- {
- *error= true;
- return EXIT_SUCCESS;
- }
-
- *error= false;
- return val;
-}
-
-int main(int argc, char *argv[])
-{
- memcached_st *memc;
- memcached_return_t rc;
- memcached_server_st *servers;
-
- int return_code= 0;
-
- options_parse(argc, argv);
- initialize_sockets();
-
- memc= memcached_create(NULL);
- process_hash_option(memc, opt_hash);
-
- if (!opt_servers)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- {
- opt_servers= strdup(temp);
- }
- else
- {
- fprintf(stderr, "No Servers provided\n");
- exit(1);
- }
- }
-
- if (opt_servers)
- servers= memcached_servers_parse(opt_servers);
- else
- servers= memcached_servers_parse(argv[--argc]);
-
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t)opt_binary);
- if (!initialize_sasl(memc, opt_username, opt_passwd))
- {
- memcached_free(memc);
- return EXIT_FAILURE;
- }
-
- while (optind < argc)
- {
- struct stat sbuf;
- int fd;
- char *ptr;
- ssize_t read_length;
- char *file_buffer_ptr;
-
- fd= open(argv[optind], O_RDONLY);
- if (fd < 0)
- {
- fprintf(stderr, "memcp: %s: %s\n", argv[optind], strerror(errno));
- optind++;
- continue;
- }
-
- (void)fstat(fd, &sbuf);
-
- ptr= rindex(argv[optind], '/');
- if (ptr)
- ptr++;
- else
- ptr= argv[optind];
-
- if (opt_verbose)
- {
- static const char *opstr[] = { "set", "add", "replace" };
- printf("op: %s\nsource file: %s\nlength: %zu\n"
- "key: %s\nflags: %x\nexpires: %llu\n",
- opstr[opt_method - OPT_SET], argv[optind], (size_t)sbuf.st_size,
- ptr, opt_flags, (unsigned long long)opt_expires);
- }
-
- if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL)
- {
- fprintf(stderr, "malloc: %s\n", strerror(errno));
- exit(1);
- }
-
- if ((read_length= read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1)
- {
- fprintf(stderr, "read: %s\n", strerror(errno));
- exit(1);
- }
-
- if (read_length != sbuf.st_size)
- {
- fprintf(stderr, "Failure reading from file\n");
- exit(1);
- }
-
- if (opt_method == OPT_ADD)
- rc= memcached_add(memc, ptr, strlen(ptr),
- file_buffer_ptr, (size_t)sbuf.st_size,
- opt_expires, opt_flags);
- else if (opt_method == OPT_REPLACE)
- rc= memcached_replace(memc, ptr, strlen(ptr),
- file_buffer_ptr, (size_t)sbuf.st_size,
- opt_expires, opt_flags);
- else
- rc= memcached_set(memc, ptr, strlen(ptr),
- file_buffer_ptr, (size_t)sbuf.st_size,
- opt_expires, opt_flags);
-
- if (rc != MEMCACHED_SUCCESS)
- {
- fprintf(stderr, "memcp: %s: memcache error %s",
- ptr, memcached_strerror(memc, rc));
- if (memcached_last_error_errno(memc))
- fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
- fprintf(stderr, "\n");
-
- return_code= -1;
- }
-
- free(file_buffer_ptr);
- close(fd);
- optind++;
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- free(opt_servers);
- if (opt_hash)
- free(opt_hash);
- shutdown_sasl();
-
- return return_code;
-}
-
-static void options_parse(int argc, char *argv[])
-{
- int option_index= 0;
- int option_rv;
-
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG},
- {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
- {(OPTIONSTRING)"set", no_argument, NULL, OPT_SET},
- {(OPTIONSTRING)"add", no_argument, NULL, OPT_ADD},
- {(OPTIONSTRING)"replace", no_argument, NULL, OPT_REPLACE},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0},
- };
-
- while (1)
- {
- option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-
- if (option_rv == -1) break;
-
- switch (option_rv)
- {
- case 0:
- break;
- case OPT_BINARY:
- opt_binary = 1;
- break;
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- break;
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
- case OPT_FLAG: /* --flag */
- {
- bool strtol_error;
- opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error);
- if (strtol_error == true)
- {
- fprintf(stderr, "Bad value passed via --flag\n");
- exit(1);
- }
- break;
- }
- case OPT_EXPIRE: /* --expire */
- {
- bool strtol_error;
- opt_expires= (time_t)strtol_wrapper(optarg, 16, &strtol_error);
- if (strtol_error == true)
- {
- fprintf(stderr, "Bad value passed via --flag\n");
- exit(1);
- }
- }
- case OPT_SET:
- opt_method= OPT_SET;
- break;
- case OPT_REPLACE:
- opt_method= OPT_REPLACE;
- break;
- case OPT_ADD:
- opt_method= OPT_ADD;
- break;
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
- case OPT_USERNAME:
- opt_username= optarg;
- break;
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <limits.h>
+
+
+#include <libmemcached/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+
+#define PROGRAM_NAME "memcp"
+#define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+static int opt_binary=0;
+static int opt_verbose= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static int opt_method= OPT_SET;
+static uint32_t opt_flags= 0;
+static time_t opt_expires= 0;
+static char *opt_username;
+static char *opt_passwd;
+
+static long strtol_wrapper(const char *nptr, int base, bool *error)
+{
+ long val;
+ char *endptr;
+
+ errno= 0; /* To distinguish success/failure after call */
+ val= strtol(nptr, &endptr, base);
+
+ /* Check for various possible errors */
+
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+ || (errno != 0 && val == 0))
+ {
+ *error= true;
+ return EXIT_SUCCESS;
+ }
+
+ if (endptr == nptr)
+ {
+ *error= true;
+ return EXIT_SUCCESS;
+ }
+
+ *error= false;
+ return val;
+}
+
+int main(int argc, char *argv[])
+{
+ memcached_st *memc;
+ memcached_return_t rc;
+ memcached_server_st *servers;
+
+ int return_code= 0;
+
+ options_parse(argc, argv);
+ initialize_sockets();
+
+ memc= memcached_create(NULL);
+ process_hash_option(memc, opt_hash);
+
+ if (!opt_servers)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ {
+ opt_servers= strdup(temp);
+ }
+ else
+ {
+ fprintf(stderr, "No Servers provided\n");
+ exit(1);
+ }
+ }
+
+ if (opt_servers)
+ servers= memcached_servers_parse(opt_servers);
+ else
+ servers= memcached_servers_parse(argv[--argc]);
+
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t)opt_binary);
+ if (!initialize_sasl(memc, opt_username, opt_passwd))
+ {
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+
+ while (optind < argc)
+ {
+ struct stat sbuf;
+ int fd;
+ char *ptr;
+ ssize_t read_length;
+ char *file_buffer_ptr;
+
+ fd= open(argv[optind], O_RDONLY);
+ if (fd < 0)
+ {
+ fprintf(stderr, "memcp: %s: %s\n", argv[optind], strerror(errno));
+ optind++;
+ continue;
+ }
+
+ (void)fstat(fd, &sbuf);
+
+ ptr= rindex(argv[optind], '/');
+ if (ptr)
+ ptr++;
+ else
+ ptr= argv[optind];
+
+ if (opt_verbose)
+ {
+ static const char *opstr[] = { "set", "add", "replace" };
+ printf("op: %s\nsource file: %s\nlength: %lu\n"
+ "key: %s\nflags: %x\nexpires: %lu\n",
+ opstr[opt_method - OPT_SET], argv[optind], (unsigned long)sbuf.st_size,
+ ptr, opt_flags, (unsigned long)opt_expires);
+ }
+
+ if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL)
+ {
+ fprintf(stderr, "malloc: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if ((read_length= read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1)
+ {
+ fprintf(stderr, "read: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (read_length != sbuf.st_size)
+ {
+ fprintf(stderr, "Failure reading from file\n");
+ exit(1);
+ }
+
+ if (opt_method == OPT_ADD)
+ rc= memcached_add(memc, ptr, strlen(ptr),
+ file_buffer_ptr, (size_t)sbuf.st_size,
+ opt_expires, opt_flags);
+ else if (opt_method == OPT_REPLACE)
+ rc= memcached_replace(memc, ptr, strlen(ptr),
+ file_buffer_ptr, (size_t)sbuf.st_size,
+ opt_expires, opt_flags);
+ else
+ rc= memcached_set(memc, ptr, strlen(ptr),
+ file_buffer_ptr, (size_t)sbuf.st_size,
+ opt_expires, opt_flags);
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ fprintf(stderr, "memcp: %s: memcache error %s",
+ ptr, memcached_strerror(memc, rc));
+ if (memcached_last_error_errno(memc))
+ fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+ fprintf(stderr, "\n");
+
+ return_code= -1;
+ }
+
+ free(file_buffer_ptr);
+ close(fd);
+ optind++;
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ free(opt_servers);
+ if (opt_hash)
+ free(opt_hash);
+ shutdown_sasl();
+
+ return return_code;
+}
+
+static void options_parse(int argc, char *argv[])
+{
+ int option_index= 0;
+ int option_rv;
+
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG},
+ {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+ {(OPTIONSTRING)"set", no_argument, NULL, OPT_SET},
+ {(OPTIONSTRING)"add", no_argument, NULL, OPT_ADD},
+ {(OPTIONSTRING)"replace", no_argument, NULL, OPT_REPLACE},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0},
+ };
+
+ while (1)
+ {
+ option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+
+ if (option_rv == -1) break;
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+ case OPT_BINARY:
+ opt_binary = 1;
+ break;
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ break;
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+ case OPT_FLAG: /* --flag */
+ {
+ bool strtol_error;
+ opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error);
+ if (strtol_error == true)
+ {
+ fprintf(stderr, "Bad value passed via --flag\n");
+ exit(1);
+ }
+ break;
+ }
+ case OPT_EXPIRE: /* --expire */
+ {
+ bool strtol_error;
+ opt_expires= (time_t)strtol_wrapper(optarg, 16, &strtol_error);
+ if (strtol_error == true)
+ {
+ fprintf(stderr, "Bad value passed via --flag\n");
+ exit(1);
+ }
+ }
+ case OPT_SET:
+ opt_method= OPT_SET;
+ break;
+ case OPT_REPLACE:
+ opt_method= OPT_REPLACE;
+ break;
+ case OPT_ADD:
+ opt_method= OPT_ADD;
+ break;
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <strings.h>
-#include <string.h>
-
-#include <libmemcached/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-
-#define PROGRAM_NAME "memdump"
-#define PROGRAM_DESCRIPTION "Dump all values from one or many servers."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-static int opt_binary=0;
-static int opt_verbose= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-/* Print the keys and counter how many were found */
-static memcached_return_t key_printer(const memcached_st *ptr,
- const char *key, size_t key_length,
- void *context)
-{
- (void)ptr;(void)context;
- printf("%.*s\n", (uint32_t)key_length, key);
-
- return MEMCACHED_SUCCESS;
-}
-
-int main(int argc, char *argv[])
-{
- memcached_st *memc;
- memcached_return_t rc;
- memcached_server_st *servers;
- memcached_dump_fn callbacks[1];
-
- callbacks[0]= &key_printer;
-
- options_parse(argc, argv);
-
- memc= memcached_create(NULL);
- process_hash_option(memc, opt_hash);
-
- if (!opt_servers)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- opt_servers= strdup(temp);
- else
- {
- fprintf(stderr, "No Servers provided\n");
- exit(1);
- }
- }
-
- if (opt_servers)
- servers= memcached_servers_parse(opt_servers);
- else
- servers= memcached_servers_parse(argv[--argc]);
-
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t)opt_binary);
- if (!initialize_sasl(memc, opt_username, opt_passwd))
- {
- memcached_free(memc);
- return EXIT_FAILURE;
- }
-
- rc= memcached_dump(memc, callbacks, NULL, 1);
-
- if (rc != MEMCACHED_SUCCESS)
- {
- fprintf(stderr, "memdump: memcache error %s", memcached_strerror(memc, rc));
- if (memcached_last_error_errno(memc))
- fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
- fprintf(stderr, "\n");
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- free(opt_servers);
- if (opt_hash)
- free(opt_hash);
-
- shutdown_sasl();
-
- return EXIT_SUCCESS;
-}
-
-static void options_parse(int argc, char *argv[])
-{
- int option_index= 0;
- int option_rv;
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0}
- };
-
- while (1)
- {
- option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-
- if (option_rv == -1) break;
-
- switch (option_rv)
- {
- case 0:
- break;
- case OPT_BINARY:
- opt_binary = 1;
- break;
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
- break;
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
- case OPT_USERNAME:
- opt_username= optarg;
- break;
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <string.h>
+
+#include <libmemcached/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+
+#define PROGRAM_NAME "memdump"
+#define PROGRAM_DESCRIPTION "Dump all values from one or many servers."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+static int opt_binary=0;
+static int opt_verbose= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+/* Print the keys and counter how many were found */
+static memcached_return_t key_printer(const memcached_st *ptr,
+ const char *key, size_t key_length,
+ void *context)
+{
+ (void)ptr;(void)context;
+ printf("%.*s\n", (uint32_t)key_length, key);
+
+ return MEMCACHED_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ memcached_st *memc;
+ memcached_return_t rc;
+ memcached_server_st *servers;
+ memcached_dump_fn callbacks[1];
+
+ callbacks[0]= &key_printer;
+
+ options_parse(argc, argv);
+
+ memc= memcached_create(NULL);
+ process_hash_option(memc, opt_hash);
+
+ if (!opt_servers)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ opt_servers= strdup(temp);
+ else
+ {
+ fprintf(stderr, "No Servers provided\n");
+ exit(1);
+ }
+ }
+
+ if (opt_servers)
+ servers= memcached_servers_parse(opt_servers);
+ else
+ servers= memcached_servers_parse(argv[--argc]);
+
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t)opt_binary);
+ if (!initialize_sasl(memc, opt_username, opt_passwd))
+ {
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+
+ rc= memcached_dump(memc, callbacks, NULL, 1);
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ fprintf(stderr, "memdump: memcache error %s", memcached_strerror(memc, rc));
+ if (memcached_last_error_errno(memc))
+ fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+ fprintf(stderr, "\n");
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ free(opt_servers);
+ if (opt_hash)
+ free(opt_hash);
+
+ shutdown_sasl();
+
+ return EXIT_SUCCESS;
+}
+
+static void options_parse(int argc, char *argv[])
+{
+ int option_index= 0;
+ int option_rv;
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0}
+ };
+
+ while (1)
+ {
+ option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+
+ if (option_rv == -1) break;
+
+ switch (option_rv)
+ {
+ case 0:
+ break;
+ case OPT_BINARY:
+ opt_binary = 1;
+ break;
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
+ break;
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <libmemcached/memcached.h>
-
-#include "utilities.h"
-
-#define PROGRAM_NAME "memerror"
-#define PROGRAM_DESCRIPTION "Translate a memcached errror code into a string."
-
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-static int opt_verbose= 0;
-
-int main(int argc, char *argv[])
-{
- unsigned long value;
- options_parse(argc, argv);
-
- if (argc != 2)
- return EXIT_FAILURE;
-
- value= strtoul(argv[1], (char **) NULL, 10);
-
- if (value < MEMCACHED_MAXIMUM_RETURN)
- {
- printf("%s\n", memcached_strerror(NULL, (memcached_return_t)value));
- }
- else
- {
- fprintf(stderr, "Unknown Error Code\n");
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
- int option_index= 0;
- int option_rv;
-
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {0, 0, 0, 0},
- };
-
- while (1)
- {
- option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1) break;
- switch (option_rv)
- {
- case 0:
- break;
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- break;
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <libmemcached/memcached.h>
+
+#include "utilities.h"
+
+#define PROGRAM_NAME "memerror"
+#define PROGRAM_DESCRIPTION "Translate a memcached errror code into a string."
+
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+static int opt_verbose= 0;
+
+int main(int argc, char *argv[])
+{
+ unsigned long value;
+ options_parse(argc, argv);
+
+ if (argc != 2)
+ return EXIT_FAILURE;
+
+ value= strtoul(argv[1], (char **) NULL, 10);
+
+ if (value < MEMCACHED_MAXIMUM_RETURN)
+ {
+ printf("%s\n", memcached_strerror(NULL, (memcached_return_t)value));
+ }
+ else
+ {
+ fprintf(stderr, "Unknown Error Code\n");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+ int option_index= 0;
+ int option_rv;
+
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {0, 0, 0, 0},
+ };
+
+ while (1)
+ {
+ option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1) break;
+ switch (option_rv)
+ {
+ case 0:
+ break;
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <getopt.h>
-#include <libmemcached/memcached.h>
-#include "client_options.h"
-#include "utilities.h"
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static time_t opt_expire= 0;
-static char *opt_servers= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-#define PROGRAM_NAME "memflush"
-#define PROGRAM_DESCRIPTION "Erase all data in a server of memcached servers."
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
- memcached_st *memc;
- memcached_return_t rc;
- memcached_server_st *servers;
-
- options_parse(argc, argv);
-
- if (!opt_servers)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- opt_servers= strdup(temp);
- else
- {
- fprintf(stderr, "No Servers provided\n");
- exit(1);
- }
- }
-
- memc= memcached_create(NULL);
-
- servers= memcached_servers_parse(opt_servers);
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t) opt_binary);
-
- if (!initialize_sasl(memc, opt_username, opt_passwd))
- {
- memcached_free(memc);
- return EXIT_FAILURE;
- }
-
- rc = memcached_flush(memc, opt_expire);
- if (rc != MEMCACHED_SUCCESS)
- {
- fprintf(stderr, "memflush: memcache error %s",
- memcached_strerror(memc, rc));
- if (memcached_last_error_errno(memc))
- fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
- fprintf(stderr, "\n");
- }
-
- memcached_free(memc);
-
- free(opt_servers);
-
- shutdown_sasl();
-
- return EXIT_SUCCESS;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0},
- };
- int option_index= 0;
- int option_rv;
-
- while (1)
- {
- option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1) break;
- switch (option_rv)
- {
- case 0:
- break;
- case OPT_BINARY:
- opt_binary = 1;
- break;
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- break;
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
- case OPT_EXPIRE: /* --expire */
- opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
- break;
- case OPT_USERNAME:
- opt_username= optarg;
- break;
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <libmemcached/memcached.h>
+#include "client_options.h"
+#include "utilities.h"
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static time_t opt_expire= 0;
+static char *opt_servers= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+#define PROGRAM_NAME "memflush"
+#define PROGRAM_DESCRIPTION "Erase all data in a server of memcached servers."
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+ memcached_st *memc;
+ memcached_return_t rc;
+ memcached_server_st *servers;
+
+ options_parse(argc, argv);
+
+ if (!opt_servers)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ opt_servers= strdup(temp);
+ else
+ {
+ fprintf(stderr, "No Servers provided\n");
+ exit(1);
+ }
+ }
+
+ memc= memcached_create(NULL);
+
+ servers= memcached_servers_parse(opt_servers);
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t) opt_binary);
+
+ if (!initialize_sasl(memc, opt_username, opt_passwd))
+ {
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+
+ rc = memcached_flush(memc, opt_expire);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ fprintf(stderr, "memflush: memcache error %s",
+ memcached_strerror(memc, rc));
+ if (memcached_last_error_errno(memc))
+ fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+ fprintf(stderr, "\n");
+ }
+
+ memcached_free(memc);
+
+ free(opt_servers);
+
+ shutdown_sasl();
+
+ return EXIT_SUCCESS;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0},
+ };
+ int option_index= 0;
+ int option_rv;
+
+ while (1)
+ {
+ option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1) break;
+ switch (option_rv)
+ {
+ case 0:
+ break;
+ case OPT_BINARY:
+ opt_binary = 1;
+ break;
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ break;
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+ case OPT_EXPIRE: /* --expire */
+ opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
+ break;
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <libmemcached/memcached.h>
-#include <string.h>
-#include "client_options.h"
-#include "utilities.h"
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static time_t opt_expire= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-#define PROGRAM_NAME "memrm"
-#define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
- memcached_st *memc;
- memcached_return_t rc;
- memcached_server_st *servers;
-
- int return_code= 0;
-
- options_parse(argc, argv);
- initialize_sockets();
-
- if (!opt_servers)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- opt_servers= strdup(temp);
- else
- {
- fprintf(stderr, "No Servers provided\n");
- exit(1);
- }
- }
-
- memc= memcached_create(NULL);
- process_hash_option(memc, opt_hash);
-
- servers= memcached_servers_parse(opt_servers);
- memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t) opt_binary);
-
- if (!initialize_sasl(memc, opt_username, opt_passwd))
- {
- memcached_free(memc);
- return EXIT_FAILURE;
- }
-
- while (optind < argc)
- {
- if (opt_verbose)
- printf("key: %s\nexpires: %llu\n", argv[optind], (unsigned long long)opt_expire);
- rc = memcached_delete(memc, argv[optind], strlen(argv[optind]), opt_expire);
-
- if (rc != MEMCACHED_SUCCESS)
- {
- fprintf(stderr, "memrm: %s: memcache error %s",
- argv[optind], memcached_strerror(memc, rc));
- if (memcached_last_error_errno(memc))
- fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
- fprintf(stderr, "\n");
-
- return_code= -1;
- }
-
- optind++;
- }
-
- memcached_free(memc);
-
- if (opt_servers)
- free(opt_servers);
-
- if (opt_hash)
- free(opt_hash);
-
- shutdown_sasl();
-
- return return_code;
-}
-
-
-static void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
- {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
- {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
- {0, 0, 0, 0},
- };
- int option_index= 0;
- int option_rv;
-
- while (1)
- {
- option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1) break;
- switch (option_rv)
- {
- case 0:
- break;
- case OPT_BINARY:
- opt_binary = 1;
- break;
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- break;
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
- case OPT_EXPIRE: /* --expire */
- opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
- break;
- case OPT_HASH:
- opt_hash= strdup(optarg);
- break;
- case OPT_USERNAME:
- opt_username= optarg;
- break;
- case OPT_PASSWD:
- opt_passwd= optarg;
- break;
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <libmemcached/memcached.h>
+#include <string.h>
+#include "client_options.h"
+#include "utilities.h"
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static time_t opt_expire= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+#define PROGRAM_NAME "memrm"
+#define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+ memcached_st *memc;
+ memcached_return_t rc;
+ memcached_server_st *servers;
+
+ int return_code= 0;
+
+ options_parse(argc, argv);
+ initialize_sockets();
+
+ if (!opt_servers)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ opt_servers= strdup(temp);
+ else
+ {
+ fprintf(stderr, "No Servers provided\n");
+ exit(1);
+ }
+ }
+
+ memc= memcached_create(NULL);
+ process_hash_option(memc, opt_hash);
+
+ servers= memcached_servers_parse(opt_servers);
+ memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t) opt_binary);
+
+ if (!initialize_sasl(memc, opt_username, opt_passwd))
+ {
+ memcached_free(memc);
+ return EXIT_FAILURE;
+ }
+
+ while (optind < argc)
+ {
+ if (opt_verbose)
+ printf("key: %s\nexpires: %llu\n", argv[optind], (unsigned long long)opt_expire);
+ rc = memcached_delete(memc, argv[optind], strlen(argv[optind]), opt_expire);
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ fprintf(stderr, "memrm: %s: memcache error %s",
+ argv[optind], memcached_strerror(memc, rc));
+ if (memcached_last_error_errno(memc))
+ fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+ fprintf(stderr, "\n");
+
+ return_code= -1;
+ }
+
+ optind++;
+ }
+
+ memcached_free(memc);
+
+ if (opt_servers)
+ free(opt_servers);
+
+ if (opt_hash)
+ free(opt_hash);
+
+ shutdown_sasl();
+
+ return return_code;
+}
+
+
+static void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+ {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+ {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+ {0, 0, 0, 0},
+ };
+ int option_index= 0;
+ int option_rv;
+
+ while (1)
+ {
+ option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1) break;
+ switch (option_rv)
+ {
+ case 0:
+ break;
+ case OPT_BINARY:
+ opt_binary = 1;
+ break;
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ break;
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+ case OPT_EXPIRE: /* --expire */
+ opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
+ break;
+ case OPT_HASH:
+ opt_hash= strdup(optarg);
+ break;
+ case OPT_USERNAME:
+ opt_username= optarg;
+ break;
+ case OPT_PASSWD:
+ opt_passwd= optarg;
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <getopt.h>
-#include <pthread.h>
-#include <assert.h>
-
-#include <libmemcached/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-#include "generator.h"
-#include "execute.h"
-
-#define DEFAULT_INITIAL_LOAD 10000
-#define DEFAULT_EXECUTE_NUMBER 10000
-#define DEFAULT_CONCURRENCY 1
-
-#define PROGRAM_NAME "memslap"
-#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
-
-/* Global Thread counter */
-volatile unsigned int thread_counter;
-pthread_mutex_t counter_mutex;
-pthread_cond_t count_threshhold;
-volatile unsigned int master_wakeup;
-pthread_mutex_t sleeper_mutex;
-pthread_cond_t sleep_threshhold;
-
-void *run_task(void *p);
-
-/* Types */
-typedef struct conclusions_st conclusions_st;
-typedef struct thread_context_st thread_context_st;
-typedef enum {
- SET_TEST,
- GET_TEST,
- MGET_TEST
-} test_type;
-
-struct thread_context_st {
- unsigned int key_count;
- pairs_st *initial_pairs;
- unsigned int initial_number;
- pairs_st *execute_pairs;
- unsigned int execute_number;
- char **keys;
- size_t *key_lengths;
- test_type test;
- memcached_st *memc;
-};
-
-struct conclusions_st {
- long int load_time;
- long int read_time;
- unsigned int rows_loaded;
- unsigned int rows_read;
-};
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-void conclusions_print(conclusions_st *conclusion);
-void scheduler(memcached_server_st *servers, conclusions_st *conclusion);
-pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
- unsigned int *actual_loaded);
-void flush_all(memcached_st *memc);
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static int opt_flush= 0;
-static int opt_non_blocking_io= 0;
-static int opt_tcp_nodelay= 0;
-static unsigned int opt_execute_number= 0;
-static unsigned int opt_createial_load= 0;
-static unsigned int opt_concurrency= 0;
-static int opt_displayflag= 0;
-static char *opt_servers= NULL;
-static int opt_udp_io= 0;
-test_type opt_test= SET_TEST;
-
-int main(int argc, char *argv[])
-{
- conclusions_st conclusion;
- memcached_server_st *servers;
-
- memset(&conclusion, 0, sizeof(conclusions_st));
-
- srandom((unsigned int)time(NULL));
- options_parse(argc, argv);
-
- if (!opt_servers)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- opt_servers= strdup(temp);
- else
- {
- fprintf(stderr, "No Servers provided\n");
- exit(1);
- }
- }
-
- servers= memcached_servers_parse(opt_servers);
-
- pthread_mutex_init(&counter_mutex, NULL);
- pthread_cond_init(&count_threshhold, NULL);
- pthread_mutex_init(&sleeper_mutex, NULL);
- pthread_cond_init(&sleep_threshhold, NULL);
-
- scheduler(servers, &conclusion);
-
- free(opt_servers);
-
- (void)pthread_mutex_destroy(&counter_mutex);
- (void)pthread_cond_destroy(&count_threshhold);
- (void)pthread_mutex_destroy(&sleeper_mutex);
- (void)pthread_cond_destroy(&sleep_threshhold);
- conclusions_print(&conclusion);
- memcached_server_list_free(servers);
-
- return 0;
-}
-
-void scheduler(memcached_server_st *servers, conclusions_st *conclusion)
-{
- unsigned int actual_loaded= 0; /* Fix warning */
- memcached_st *memc;
-
- struct timeval start_time, end_time;
- pthread_t mainthread; /* Thread descriptor */
- pthread_attr_t attr; /* Thread attributes */
- pairs_st *pairs= NULL;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr,
- PTHREAD_CREATE_DETACHED);
-
- memc= memcached_create(NULL);
-
- /* We need to set udp behavior before adding servers to the client */
- if (opt_udp_io)
- {
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP,
- (uint64_t)opt_udp_io);
- for (uint32_t x= 0; x < memcached_server_list_count(servers); x++ )
- {
- servers[x].type= MEMCACHED_CONNECTION_UDP;
- }
- }
- memcached_server_push(memc, servers);
-
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- (uint64_t)opt_binary);
-
- if (opt_flush)
- flush_all(memc);
- if (opt_createial_load)
- pairs= load_create_data(memc, opt_createial_load, &actual_loaded);
-
- char **keys= calloc(actual_loaded, sizeof(char*));
- size_t *key_lengths= calloc(actual_loaded, sizeof(size_t));
-
- if (keys == NULL || key_lengths == NULL)
- {
- free(keys);
- free(key_lengths);
- keys= NULL;
- key_lengths= NULL;
- }
- else
- {
- for (uint32_t x= 0; x < actual_loaded; ++x)
- {
- keys[x]= pairs[x].key;
- key_lengths[x]= pairs[x].key_length;
- }
- }
-
- /* We set this after we have loaded */
- {
- if (opt_non_blocking_io)
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
- if (opt_tcp_nodelay)
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
- }
-
- pthread_mutex_lock(&counter_mutex);
- thread_counter= 0;
-
- pthread_mutex_lock(&sleeper_mutex);
- master_wakeup= 1;
- pthread_mutex_unlock(&sleeper_mutex);
-
- for (uint32_t x= 0; x < opt_concurrency; x++)
- {
- thread_context_st *context;
- context= (thread_context_st *)calloc(1, sizeof(thread_context_st));
-
- context->memc= memcached_clone(NULL, memc);
- context->test= opt_test;
-
- context->initial_pairs= pairs;
- context->initial_number= actual_loaded;
- context->keys= keys;
- context->key_lengths= key_lengths;
-
- if (opt_test == SET_TEST)
- {
- context->execute_pairs= pairs_generate(opt_execute_number, 400);
- context->execute_number= opt_execute_number;
- }
-
- /* now you create the thread */
- if (pthread_create(&mainthread, &attr, run_task,
- (void *)context) != 0)
- {
- fprintf(stderr,"Could not create thread\n");
- exit(1);
- }
- thread_counter++;
- }
-
- pthread_mutex_unlock(&counter_mutex);
- pthread_attr_destroy(&attr);
-
- pthread_mutex_lock(&sleeper_mutex);
- master_wakeup= 0;
- pthread_mutex_unlock(&sleeper_mutex);
- pthread_cond_broadcast(&sleep_threshhold);
-
- gettimeofday(&start_time, NULL);
- /*
- We loop until we know that all children have cleaned up.
- */
- pthread_mutex_lock(&counter_mutex);
- while (thread_counter)
- pthread_cond_wait(&count_threshhold, &counter_mutex);
- pthread_mutex_unlock(&counter_mutex);
-
- gettimeofday(&end_time, NULL);
-
- conclusion->load_time= timedif(end_time, start_time);
- conclusion->read_time= timedif(end_time, start_time);
- free(keys);
- free(key_lengths);
- pairs_free(pairs);
- memcached_free(memc);
-}
-
-void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- static struct option long_options[]=
- {
- {(OPTIONSTRING)"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"execute-number", required_argument, NULL, OPT_SLAP_EXECUTE_NUMBER},
- {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
- {(OPTIONSTRING)"flush", no_argument, &opt_flush, OPT_FLUSH},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"initial-load", required_argument, NULL, OPT_SLAP_INITIAL_LOAD}, /* Number to load initially */
- {(OPTIONSTRING)"non-blocking", no_argument, &opt_non_blocking_io, OPT_SLAP_NON_BLOCK},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"tcp-nodelay", no_argument, &opt_tcp_nodelay, OPT_SLAP_TCP_NODELAY},
- {(OPTIONSTRING)"test", required_argument, NULL, OPT_SLAP_TEST},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
- {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP},
- {0, 0, 0, 0},
- };
-
- int option_index= 0;
- int option_rv;
-
- while (1)
- {
- option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
- if (option_rv == -1) break;
- switch (option_rv)
- {
- case 0:
- break;
- case OPT_UDP:
- if (opt_test == GET_TEST)
- {
- fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
- "does not currently support get ops.\n");
- exit(1);
- }
- opt_udp_io= 1;
- break;
- case OPT_BINARY:
- opt_binary = 1;
- break;
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- break;
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
- case OPT_SLAP_TEST:
- if (!strcmp(optarg, "get"))
- {
- if (opt_udp_io == 1)
- {
- fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
- "does not currently support get ops.\n");
- exit(1);
- }
- opt_test= GET_TEST ;
- }
- else if (!strcmp(optarg, "set"))
- opt_test= SET_TEST;
- else if (!strcmp(optarg, "mget"))
- {
- opt_test= MGET_TEST;
- }
- else
- {
- fprintf(stderr, "Your test, %s, is not a known test\n", optarg);
- exit(1);
- }
- break;
- case OPT_SLAP_CONCURRENCY:
- opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10);
- break;
- case OPT_SLAP_EXECUTE_NUMBER:
- opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10);
- break;
- case OPT_SLAP_INITIAL_LOAD:
- opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10);
- break;
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-
- if ((opt_test == GET_TEST || opt_test == MGET_TEST) && opt_createial_load == 0)
- opt_createial_load= DEFAULT_INITIAL_LOAD;
-
- if (opt_execute_number == 0)
- opt_execute_number= DEFAULT_EXECUTE_NUMBER;
-
- if (opt_concurrency == 0)
- opt_concurrency= DEFAULT_CONCURRENCY;
-}
-
-void conclusions_print(conclusions_st *conclusion)
-{
- printf("\tThreads connecting to servers %u\n", opt_concurrency);
-#ifdef NOT_FINISHED
- printf("\tLoaded %u rows\n", conclusion->rows_loaded);
- printf("\tRead %u rows\n", conclusion->rows_read);
-#endif
- if (opt_test == SET_TEST)
- printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000,
- conclusion->load_time % 1000);
- else
- printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000,
- conclusion->read_time % 1000);
-}
-
-void *run_task(void *p)
-{
- thread_context_st *context= (thread_context_st *)p;
- memcached_st *memc;
-
- memc= context->memc;
-
- pthread_mutex_lock(&sleeper_mutex);
- while (master_wakeup)
- {
- pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
- }
- pthread_mutex_unlock(&sleeper_mutex);
-
- /* Do Stuff */
- switch (context->test)
- {
- case SET_TEST:
- assert(context->execute_pairs);
- execute_set(memc, context->execute_pairs, context->execute_number);
- break;
- case GET_TEST:
- execute_get(memc, context->initial_pairs, context->initial_number);
- break;
- case MGET_TEST:
- execute_mget(memc, (const char*const*)context->keys, context->key_lengths,
- context->initial_number);
- break;
- default:
- WATCHPOINT_ASSERT(context->test);
- break;
- }
-
- memcached_free(memc);
-
- if (context->execute_pairs)
- pairs_free(context->execute_pairs);
-
- free(context);
-
- pthread_mutex_lock(&counter_mutex);
- thread_counter--;
- pthread_cond_signal(&count_threshhold);
- pthread_mutex_unlock(&counter_mutex);
-
- return NULL;
-}
-
-void flush_all(memcached_st *memc)
-{
- memcached_flush(memc, 0);
-}
-
-pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
- unsigned int *actual_loaded)
-{
- memcached_st *memc_clone;
- pairs_st *pairs;
-
- memc_clone= memcached_clone(NULL, memc);
- /* We always used non-blocking IO for load since it is faster */
- memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
-
- pairs= pairs_generate(number_of, 400);
- *actual_loaded= execute_set(memc_clone, pairs, number_of);
-
- memcached_free(memc_clone);
-
- return pairs;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <assert.h>
+
+#include <libmemcached/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+#include "generator.h"
+#include "execute.h"
+
+#define DEFAULT_INITIAL_LOAD 10000
+#define DEFAULT_EXECUTE_NUMBER 10000
+#define DEFAULT_CONCURRENCY 1
+
+#define PROGRAM_NAME "memslap"
+#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
+
+/* Global Thread counter */
+volatile unsigned int thread_counter;
+pthread_mutex_t counter_mutex;
+pthread_cond_t count_threshhold;
+volatile unsigned int master_wakeup;
+pthread_mutex_t sleeper_mutex;
+pthread_cond_t sleep_threshhold;
+
+void *run_task(void *p);
+
+/* Types */
+typedef struct conclusions_st conclusions_st;
+typedef struct thread_context_st thread_context_st;
+typedef enum {
+ SET_TEST,
+ GET_TEST,
+ MGET_TEST
+} test_type;
+
+struct thread_context_st {
+ unsigned int key_count;
+ pairs_st *initial_pairs;
+ unsigned int initial_number;
+ pairs_st *execute_pairs;
+ unsigned int execute_number;
+ char **keys;
+ size_t *key_lengths;
+ test_type test;
+ memcached_st *memc;
+};
+
+struct conclusions_st {
+ long int load_time;
+ long int read_time;
+ unsigned int rows_loaded;
+ unsigned int rows_read;
+};
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+void conclusions_print(conclusions_st *conclusion);
+void scheduler(memcached_server_st *servers, conclusions_st *conclusion);
+pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
+ unsigned int *actual_loaded);
+void flush_all(memcached_st *memc);
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static int opt_flush= 0;
+static int opt_non_blocking_io= 0;
+static int opt_tcp_nodelay= 0;
+static unsigned int opt_execute_number= 0;
+static unsigned int opt_createial_load= 0;
+static unsigned int opt_concurrency= 0;
+static int opt_displayflag= 0;
+static char *opt_servers= NULL;
+static int opt_udp_io= 0;
+test_type opt_test= SET_TEST;
+
+int main(int argc, char *argv[])
+{
+ conclusions_st conclusion;
+ memcached_server_st *servers;
+
+ memset(&conclusion, 0, sizeof(conclusions_st));
+
+ srandom((unsigned int)time(NULL));
+ options_parse(argc, argv);
+
+ if (!opt_servers)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ opt_servers= strdup(temp);
+ else
+ {
+ fprintf(stderr, "No Servers provided\n");
+ exit(1);
+ }
+ }
+
+ servers= memcached_servers_parse(opt_servers);
+
+ pthread_mutex_init(&counter_mutex, NULL);
+ pthread_cond_init(&count_threshhold, NULL);
+ pthread_mutex_init(&sleeper_mutex, NULL);
+ pthread_cond_init(&sleep_threshhold, NULL);
+
+ scheduler(servers, &conclusion);
+
+ free(opt_servers);
+
+ (void)pthread_mutex_destroy(&counter_mutex);
+ (void)pthread_cond_destroy(&count_threshhold);
+ (void)pthread_mutex_destroy(&sleeper_mutex);
+ (void)pthread_cond_destroy(&sleep_threshhold);
+ conclusions_print(&conclusion);
+ memcached_server_list_free(servers);
+
+ return 0;
+}
+
+void scheduler(memcached_server_st *servers, conclusions_st *conclusion)
+{
+ unsigned int actual_loaded= 0; /* Fix warning */
+ memcached_st *memc;
+
+ struct timeval start_time, end_time;
+ pthread_t mainthread; /* Thread descriptor */
+ pthread_attr_t attr; /* Thread attributes */
+ pairs_st *pairs= NULL;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr,
+ PTHREAD_CREATE_DETACHED);
+
+ memc= memcached_create(NULL);
+
+ /* We need to set udp behavior before adding servers to the client */
+ if (opt_udp_io)
+ {
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP,
+ (uint64_t)opt_udp_io);
+ for (uint32_t x= 0; x < memcached_server_list_count(servers); x++ )
+ {
+ servers[x].type= MEMCACHED_CONNECTION_UDP;
+ }
+ }
+ memcached_server_push(memc, servers);
+
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ (uint64_t)opt_binary);
+
+ if (opt_flush)
+ flush_all(memc);
+ if (opt_createial_load)
+ pairs= load_create_data(memc, opt_createial_load, &actual_loaded);
+
+ char **keys= static_cast<char **>(calloc(actual_loaded, sizeof(char*)));
+ size_t *key_lengths= static_cast<size_t *>(calloc(actual_loaded, sizeof(size_t)));
+
+ if (keys == NULL || key_lengths == NULL)
+ {
+ free(keys);
+ free(key_lengths);
+ keys= NULL;
+ key_lengths= NULL;
+ }
+ else
+ {
+ for (uint32_t x= 0; x < actual_loaded; ++x)
+ {
+ keys[x]= pairs[x].key;
+ key_lengths[x]= pairs[x].key_length;
+ }
+ }
+
+ /* We set this after we have loaded */
+ {
+ if (opt_non_blocking_io)
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
+ if (opt_tcp_nodelay)
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
+ }
+
+ pthread_mutex_lock(&counter_mutex);
+ thread_counter= 0;
+
+ pthread_mutex_lock(&sleeper_mutex);
+ master_wakeup= 1;
+ pthread_mutex_unlock(&sleeper_mutex);
+
+ for (uint32_t x= 0; x < opt_concurrency; x++)
+ {
+ thread_context_st *context;
+ context= (thread_context_st *)calloc(1, sizeof(thread_context_st));
+
+ context->memc= memcached_clone(NULL, memc);
+ context->test= opt_test;
+
+ context->initial_pairs= pairs;
+ context->initial_number= actual_loaded;
+ context->keys= keys;
+ context->key_lengths= key_lengths;
+
+ if (opt_test == SET_TEST)
+ {
+ context->execute_pairs= pairs_generate(opt_execute_number, 400);
+ context->execute_number= opt_execute_number;
+ }
+
+ /* now you create the thread */
+ if (pthread_create(&mainthread, &attr, run_task,
+ (void *)context) != 0)
+ {
+ fprintf(stderr,"Could not create thread\n");
+ exit(1);
+ }
+ thread_counter++;
+ }
+
+ pthread_mutex_unlock(&counter_mutex);
+ pthread_attr_destroy(&attr);
+
+ pthread_mutex_lock(&sleeper_mutex);
+ master_wakeup= 0;
+ pthread_mutex_unlock(&sleeper_mutex);
+ pthread_cond_broadcast(&sleep_threshhold);
+
+ gettimeofday(&start_time, NULL);
+ /*
+ We loop until we know that all children have cleaned up.
+ */
+ pthread_mutex_lock(&counter_mutex);
+ while (thread_counter)
+ pthread_cond_wait(&count_threshhold, &counter_mutex);
+ pthread_mutex_unlock(&counter_mutex);
+
+ gettimeofday(&end_time, NULL);
+
+ conclusion->load_time= timedif(end_time, start_time);
+ conclusion->read_time= timedif(end_time, start_time);
+ free(keys);
+ free(key_lengths);
+ pairs_free(pairs);
+ memcached_free(memc);
+}
+
+void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ static struct option long_options[]=
+ {
+ {(OPTIONSTRING)"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"execute-number", required_argument, NULL, OPT_SLAP_EXECUTE_NUMBER},
+ {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
+ {(OPTIONSTRING)"flush", no_argument, &opt_flush, OPT_FLUSH},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"initial-load", required_argument, NULL, OPT_SLAP_INITIAL_LOAD}, /* Number to load initially */
+ {(OPTIONSTRING)"non-blocking", no_argument, &opt_non_blocking_io, OPT_SLAP_NON_BLOCK},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"tcp-nodelay", no_argument, &opt_tcp_nodelay, OPT_SLAP_TCP_NODELAY},
+ {(OPTIONSTRING)"test", required_argument, NULL, OPT_SLAP_TEST},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+ {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP},
+ {0, 0, 0, 0},
+ };
+
+ int option_index= 0;
+ int option_rv;
+
+ while (1)
+ {
+ option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+ if (option_rv == -1) break;
+ switch (option_rv)
+ {
+ case 0:
+ break;
+ case OPT_UDP:
+ if (opt_test == GET_TEST)
+ {
+ fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
+ "does not currently support get ops.\n");
+ exit(1);
+ }
+ opt_udp_io= 1;
+ break;
+ case OPT_BINARY:
+ opt_binary = 1;
+ break;
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ break;
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+ case OPT_SLAP_TEST:
+ if (!strcmp(optarg, "get"))
+ {
+ if (opt_udp_io == 1)
+ {
+ fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
+ "does not currently support get ops.\n");
+ exit(1);
+ }
+ opt_test= GET_TEST ;
+ }
+ else if (!strcmp(optarg, "set"))
+ opt_test= SET_TEST;
+ else if (!strcmp(optarg, "mget"))
+ {
+ opt_test= MGET_TEST;
+ }
+ else
+ {
+ fprintf(stderr, "Your test, %s, is not a known test\n", optarg);
+ exit(1);
+ }
+ break;
+ case OPT_SLAP_CONCURRENCY:
+ opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+ break;
+ case OPT_SLAP_EXECUTE_NUMBER:
+ opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+ break;
+ case OPT_SLAP_INITIAL_LOAD:
+ opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+
+ if ((opt_test == GET_TEST || opt_test == MGET_TEST) && opt_createial_load == 0)
+ opt_createial_load= DEFAULT_INITIAL_LOAD;
+
+ if (opt_execute_number == 0)
+ opt_execute_number= DEFAULT_EXECUTE_NUMBER;
+
+ if (opt_concurrency == 0)
+ opt_concurrency= DEFAULT_CONCURRENCY;
+}
+
+void conclusions_print(conclusions_st *conclusion)
+{
+ printf("\tThreads connecting to servers %u\n", opt_concurrency);
+#ifdef NOT_FINISHED
+ printf("\tLoaded %u rows\n", conclusion->rows_loaded);
+ printf("\tRead %u rows\n", conclusion->rows_read);
+#endif
+ if (opt_test == SET_TEST)
+ printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000,
+ conclusion->load_time % 1000);
+ else
+ printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000,
+ conclusion->read_time % 1000);
+}
+
+void *run_task(void *p)
+{
+ thread_context_st *context= (thread_context_st *)p;
+ memcached_st *memc;
+
+ memc= context->memc;
+
+ pthread_mutex_lock(&sleeper_mutex);
+ while (master_wakeup)
+ {
+ pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
+ }
+ pthread_mutex_unlock(&sleeper_mutex);
+
+ /* Do Stuff */
+ switch (context->test)
+ {
+ case SET_TEST:
+ assert(context->execute_pairs);
+ execute_set(memc, context->execute_pairs, context->execute_number);
+ break;
+ case GET_TEST:
+ execute_get(memc, context->initial_pairs, context->initial_number);
+ break;
+ case MGET_TEST:
+ execute_mget(memc, (const char*const*)context->keys, context->key_lengths,
+ context->initial_number);
+ break;
+ default:
+ WATCHPOINT_ASSERT(context->test);
+ break;
+ }
+
+ memcached_free(memc);
+
+ if (context->execute_pairs)
+ pairs_free(context->execute_pairs);
+
+ free(context);
+
+ pthread_mutex_lock(&counter_mutex);
+ thread_counter--;
+ pthread_cond_signal(&count_threshhold);
+ pthread_mutex_unlock(&counter_mutex);
+
+ return NULL;
+}
+
+void flush_all(memcached_st *memc)
+{
+ memcached_flush(memc, 0);
+}
+
+pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
+ unsigned int *actual_loaded)
+{
+ memcached_st *memc_clone;
+ pairs_st *pairs;
+
+ memc_clone= memcached_clone(NULL, memc);
+ /* We always used non-blocking IO for load since it is faster */
+ memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
+
+ pairs= pairs_generate(number_of, 400);
+ *actual_loaded= execute_set(memc_clone, pairs, number_of);
+
+ memcached_free(memc_clone);
+
+ return pairs;
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- * Authors:
- * Brian Aker
- * Toru Maesaka
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/time.h>
-
-#include <libmemcached/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-
-#define PROGRAM_NAME "memstat"
-#define PROGRAM_DESCRIPTION "Output the state of a memcached cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat);
-static void print_analysis_report(memcached_st *memc,
- memcached_analysis_st *report);
-
-static int opt_verbose= 0;
-static int opt_displayflag= 0;
-static int opt_analyze= 0;
-static char *opt_servers= NULL;
-static char *stat_args= NULL;
-static char *analyze_mode= NULL;
-
-static struct option long_options[]=
-{
- {(OPTIONSTRING)"args", required_argument, NULL, OPT_STAT_ARGS},
- {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
- {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
- {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
- {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
- {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
- {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
- {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE},
- {0, 0, 0, 0},
-};
-
-
-static memcached_return_t stat_printer(memcached_server_instance_st instance,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- void *context)
-{
- static memcached_server_instance_st last= NULL;
- (void)context;
-
- if (last != instance)
- {
- printf("Server: %s (%u)\n", memcached_server_name(instance),
- (uint32_t)memcached_server_port(instance));
- last= instance;
- }
-
- printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value);
-
- return MEMCACHED_SUCCESS;
-}
-
-int main(int argc, char *argv[])
-{
- options_parse(argc, argv);
- initialize_sockets();
-
- if (! opt_servers)
- {
- char *temp;
-
- if ((temp= getenv("MEMCACHED_SERVERS")))
- opt_servers= strdup(temp);
- else
- {
- fprintf(stderr, "No Servers provided\n\n");
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, 0);
- exit(1);
- }
- }
-
- memcached_st *memc= memcached_create(NULL);
-
- memcached_server_st *servers= memcached_servers_parse(opt_servers);
- free(opt_servers);
-
- memcached_return_t rc= memcached_server_push(memc, servers);
- memcached_server_list_free(servers);
-
- if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS)
- {
- printf("Failure to communicate with servers (%s)\n",
- memcached_strerror(memc, rc));
- exit(1);
- }
-
- if (opt_analyze)
- {
- memcached_stat_st *memc_stat;
-
- memc_stat= memcached_stat(memc, NULL, &rc);
-
- if (! memc_stat)
- exit(-1);
-
- run_analyzer(memc, memc_stat);
-
- memcached_stat_free(memc, memc_stat);
- }
- else
- {
- rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL);
- }
-
- memcached_free(memc);
-
- return rc == MEMCACHED_SUCCESS ? EXIT_SUCCESS: EXIT_FAILURE;
-}
-
-static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat)
-{
- memcached_return_t rc;
-
- if (analyze_mode == NULL)
- {
- memcached_analysis_st *report;
- report= memcached_analyze(memc, memc_stat, &rc);
- if (rc != MEMCACHED_SUCCESS || report == NULL)
- {
- printf("Failure to analyze servers (%s)\n",
- memcached_strerror(memc, rc));
- exit(1);
- }
- print_analysis_report(memc, report);
- free(report);
- }
- else if (strcmp(analyze_mode, "latency") == 0)
- {
- memcached_st **servers;
- uint32_t flags, server_count= memcached_server_count(memc);
- uint32_t num_of_tests= 32;
- const char *test_key= "libmemcached_test_key";
-
- servers= malloc(sizeof(memcached_st*) * server_count);
- if (!servers)
- {
- fprintf(stderr, "Failed to allocate memory\n");
- return;
- }
-
- for (uint32_t x= 0; x < server_count; x++)
- {
- memcached_server_instance_st instance=
- memcached_server_instance_by_position(memc, x);
-
- if ((servers[x]= memcached_create(NULL)) == NULL)
- {
- fprintf(stderr, "Failed to memcached_create()\n");
- if (x > 0)
- memcached_free(servers[0]);
- x--;
- for (; x > 0; x--)
- memcached_free(servers[x]);
-
- free(servers);
- return;
- }
- memcached_server_add(servers[x],
- memcached_server_name(instance),
- memcached_server_port(instance));
- }
-
- printf("Network Latency Test:\n\n");
- struct timeval start_time, end_time;
- uint32_t slowest_server= 0;
- long elapsed_time, slowest_time= 0;
-
- for (uint32_t x= 0; x < server_count; x++)
- {
- memcached_server_instance_st instance=
- memcached_server_instance_by_position(memc, x);
- gettimeofday(&start_time, NULL);
-
- for (uint32_t y= 0; y < num_of_tests; y++)
- {
- size_t vlen;
- char *val= memcached_get(servers[x], test_key, strlen(test_key),
- &vlen, &flags, &rc);
- if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
- break;
- free(val);
- }
- gettimeofday(&end_time, NULL);
-
- elapsed_time= (long) timedif(end_time, start_time);
- elapsed_time /= (long) num_of_tests;
-
- if (elapsed_time > slowest_time)
- {
- slowest_server= x;
- slowest_time= elapsed_time;
- }
-
- if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
- {
- printf("\t %s (%d) => failed to reach the server\n",
- memcached_server_name(instance),
- memcached_server_port(instance));
- }
- else
- {
- printf("\t %s (%d) => %ld.%ld seconds\n",
- memcached_server_name(instance),
- memcached_server_port(instance),
- elapsed_time / 1000, elapsed_time % 1000);
- }
- }
-
- if (server_count > 1 && slowest_time > 0)
- {
- memcached_server_instance_st slowest=
- memcached_server_instance_by_position(memc, slowest_server);
-
- printf("---\n");
- printf("Slowest Server: %s (%d) => %ld.%ld seconds\n",
- memcached_server_name(slowest),
- memcached_server_port(slowest),
- slowest_time / 1000, slowest_time % 1000);
- }
- printf("\n");
-
- for (uint32_t x= 0; x < server_count; x++)
- memcached_free(servers[x]);
-
- free(servers);
- free(analyze_mode);
- }
- else
- {
- fprintf(stderr, "Invalid Analyzer Option provided\n");
- free(analyze_mode);
- }
-}
-
-static void print_analysis_report(memcached_st *memc,
- memcached_analysis_st *report)
-
-{
- uint32_t server_count= memcached_server_count(memc);
- memcached_server_instance_st most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server);
- memcached_server_instance_st least_free_server= memcached_server_instance_by_position(memc, report->least_free_server);
- memcached_server_instance_st oldest_server= memcached_server_instance_by_position(memc, report->oldest_server);
-
- printf("Memcached Cluster Analysis Report\n\n");
-
- printf("\tNumber of Servers Analyzed : %u\n", server_count);
- printf("\tAverage Item Size (incl/overhead) : %u bytes\n",
- report->average_item_size);
-
- if (server_count == 1)
- {
- printf("\nFor a detailed report, you must supply multiple servers.\n");
- return;
- }
-
- printf("\n");
- printf("\tNode with most memory consumption : %s:%u (%llu bytes)\n",
- memcached_server_name(most_consumed_server),
- (uint32_t)memcached_server_port(most_consumed_server),
- (unsigned long long)report->most_used_bytes);
- printf("\tNode with least free space : %s:%u (%llu bytes remaining)\n",
- memcached_server_name(least_free_server),
- (uint32_t)memcached_server_port(least_free_server),
- (unsigned long long)report->least_remaining_bytes);
- printf("\tNode with longest uptime : %s:%u (%us)\n",
- memcached_server_name(oldest_server),
- (uint32_t)memcached_server_port(oldest_server),
- report->longest_uptime);
- printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio);
- printf("\n");
-}
-
-static void options_parse(int argc, char *argv[])
-{
- memcached_programs_help_st help_options[]=
- {
- {0},
- };
-
- int option_index= 0;
- int option_rv;
-
- while (1)
- {
- option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index);
- if (option_rv == -1) break;
- switch (option_rv)
- {
- case 0:
- break;
- case OPT_VERBOSE: /* --verbose or -v */
- opt_verbose = OPT_VERBOSE;
- break;
- case OPT_DEBUG: /* --debug or -d */
- opt_verbose = OPT_DEBUG;
- break;
- case OPT_VERSION: /* --version or -V */
- version_command(PROGRAM_NAME);
- break;
- case OPT_HELP: /* --help or -h */
- help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
- break;
- case OPT_SERVERS: /* --servers or -s */
- opt_servers= strdup(optarg);
- break;
- case OPT_STAT_ARGS:
- stat_args= strdup(optarg);
- break;
- case OPT_ANALYZE: /* --analyze or -a */
- opt_analyze= OPT_ANALYZE;
- analyze_mode= (optarg) ? strdup(optarg) : NULL;
- break;
- case '?':
- /* getopt_long already printed an error message. */
- exit(1);
- default:
- abort();
- }
- }
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ * Authors:
+ * Brian Aker
+ * Toru Maesaka
+ */
+#include "config.h"
+
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/types.h>
+
+#include <libmemcached/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+
+#define PROGRAM_NAME "memstat"
+#define PROGRAM_DESCRIPTION "Output the state of a memcached cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat);
+static void print_analysis_report(memcached_st *memc,
+ memcached_analysis_st *report);
+
+static int opt_verbose= 0;
+static int opt_displayflag= 0;
+static int opt_analyze= 0;
+static char *opt_servers= NULL;
+static char *stat_args= NULL;
+static char *analyze_mode= NULL;
+
+static struct option long_options[]=
+{
+ {(OPTIONSTRING)"args", required_argument, NULL, OPT_STAT_ARGS},
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+ {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
+ {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE},
+ {0, 0, 0, 0},
+};
+
+
+static memcached_return_t stat_printer(memcached_server_instance_st instance,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ void *context)
+{
+ static memcached_server_instance_st last= NULL;
+ (void)context;
+
+ if (last != instance)
+ {
+ printf("Server: %s (%u)\n", memcached_server_name(instance),
+ (uint32_t)memcached_server_port(instance));
+ last= instance;
+ }
+
+ printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value);
+
+ return MEMCACHED_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ options_parse(argc, argv);
+ initialize_sockets();
+
+ if (! opt_servers)
+ {
+ char *temp;
+
+ if ((temp= getenv("MEMCACHED_SERVERS")))
+ opt_servers= strdup(temp);
+ else
+ {
+ fprintf(stderr, "No Servers provided\n\n");
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, 0);
+ exit(1);
+ }
+ }
+
+ memcached_st *memc= memcached_create(NULL);
+
+ memcached_server_st *servers= memcached_servers_parse(opt_servers);
+ free(opt_servers);
+
+ memcached_return_t rc= memcached_server_push(memc, servers);
+ memcached_server_list_free(servers);
+
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS)
+ {
+ printf("Failure to communicate with servers (%s)\n",
+ memcached_strerror(memc, rc));
+ exit(1);
+ }
+
+ if (opt_analyze)
+ {
+ memcached_stat_st *memc_stat;
+
+ memc_stat= memcached_stat(memc, NULL, &rc);
+
+ if (! memc_stat)
+ exit(-1);
+
+ run_analyzer(memc, memc_stat);
+
+ memcached_stat_free(memc, memc_stat);
+ }
+ else
+ {
+ rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL);
+ }
+
+ memcached_free(memc);
+
+ return rc == MEMCACHED_SUCCESS ? EXIT_SUCCESS: EXIT_FAILURE;
+}
+
+static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat)
+{
+ memcached_return_t rc;
+
+ if (analyze_mode == NULL)
+ {
+ memcached_analysis_st *report;
+ report= memcached_analyze(memc, memc_stat, &rc);
+ if (rc != MEMCACHED_SUCCESS || report == NULL)
+ {
+ printf("Failure to analyze servers (%s)\n",
+ memcached_strerror(memc, rc));
+ exit(1);
+ }
+ print_analysis_report(memc, report);
+ free(report);
+ }
+ else if (strcmp(analyze_mode, "latency") == 0)
+ {
+ uint32_t flags, server_count= memcached_server_count(memc);
+ uint32_t num_of_tests= 32;
+ const char *test_key= "libmemcached_test_key";
+
+ memcached_st **servers;
+ servers= static_cast<memcached_st**>(malloc(sizeof(memcached_st*) * server_count));
+ if (not servers)
+ {
+ fprintf(stderr, "Failed to allocate memory\n");
+ return;
+ }
+
+ for (uint32_t x= 0; x < server_count; x++)
+ {
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(memc, x);
+
+ if ((servers[x]= memcached_create(NULL)) == NULL)
+ {
+ fprintf(stderr, "Failed to memcached_create()\n");
+ if (x > 0)
+ memcached_free(servers[0]);
+ x--;
+
+ for (; x > 0; x--)
+ memcached_free(servers[x]);
+
+ free(servers);
+ return;
+ }
+ memcached_server_add(servers[x],
+ memcached_server_name(instance),
+ memcached_server_port(instance));
+ }
+
+ printf("Network Latency Test:\n\n");
+ struct timeval start_time, end_time;
+ uint32_t slowest_server= 0;
+ long elapsed_time, slowest_time= 0;
+
+ for (uint32_t x= 0; x < server_count; x++)
+ {
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(memc, x);
+ gettimeofday(&start_time, NULL);
+
+ for (uint32_t y= 0; y < num_of_tests; y++)
+ {
+ size_t vlen;
+ char *val= memcached_get(servers[x], test_key, strlen(test_key),
+ &vlen, &flags, &rc);
+ if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
+ break;
+ free(val);
+ }
+ gettimeofday(&end_time, NULL);
+
+ elapsed_time= (long) timedif(end_time, start_time);
+ elapsed_time /= (long) num_of_tests;
+
+ if (elapsed_time > slowest_time)
+ {
+ slowest_server= x;
+ slowest_time= elapsed_time;
+ }
+
+ if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
+ {
+ printf("\t %s (%d) => failed to reach the server\n",
+ memcached_server_name(instance),
+ memcached_server_port(instance));
+ }
+ else
+ {
+ printf("\t %s (%d) => %ld.%ld seconds\n",
+ memcached_server_name(instance),
+ memcached_server_port(instance),
+ elapsed_time / 1000, elapsed_time % 1000);
+ }
+ }
+
+ if (server_count > 1 && slowest_time > 0)
+ {
+ memcached_server_instance_st slowest=
+ memcached_server_instance_by_position(memc, slowest_server);
+
+ printf("---\n");
+ printf("Slowest Server: %s (%d) => %ld.%ld seconds\n",
+ memcached_server_name(slowest),
+ memcached_server_port(slowest),
+ slowest_time / 1000, slowest_time % 1000);
+ }
+ printf("\n");
+
+ for (uint32_t x= 0; x < server_count; x++)
+ memcached_free(servers[x]);
+
+ free(servers);
+ free(analyze_mode);
+ }
+ else
+ {
+ fprintf(stderr, "Invalid Analyzer Option provided\n");
+ free(analyze_mode);
+ }
+}
+
+static void print_analysis_report(memcached_st *memc,
+ memcached_analysis_st *report)
+
+{
+ uint32_t server_count= memcached_server_count(memc);
+ memcached_server_instance_st most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server);
+ memcached_server_instance_st least_free_server= memcached_server_instance_by_position(memc, report->least_free_server);
+ memcached_server_instance_st oldest_server= memcached_server_instance_by_position(memc, report->oldest_server);
+
+ printf("Memcached Cluster Analysis Report\n\n");
+
+ printf("\tNumber of Servers Analyzed : %u\n", server_count);
+ printf("\tAverage Item Size (incl/overhead) : %u bytes\n",
+ report->average_item_size);
+
+ if (server_count == 1)
+ {
+ printf("\nFor a detailed report, you must supply multiple servers.\n");
+ return;
+ }
+
+ printf("\n");
+ printf("\tNode with most memory consumption : %s:%u (%llu bytes)\n",
+ memcached_server_name(most_consumed_server),
+ (uint32_t)memcached_server_port(most_consumed_server),
+ (unsigned long long)report->most_used_bytes);
+ printf("\tNode with least free space : %s:%u (%llu bytes remaining)\n",
+ memcached_server_name(least_free_server),
+ (uint32_t)memcached_server_port(least_free_server),
+ (unsigned long long)report->least_remaining_bytes);
+ printf("\tNode with longest uptime : %s:%u (%us)\n",
+ memcached_server_name(oldest_server),
+ (uint32_t)memcached_server_port(oldest_server),
+ report->longest_uptime);
+ printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio);
+ printf("\n");
+}
+
+static void options_parse(int argc, char *argv[])
+{
+ memcached_programs_help_st help_options[]=
+ {
+ {0},
+ };
+
+ int option_index= 0;
+ int option_rv;
+
+ while (1)
+ {
+ option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index);
+ if (option_rv == -1) break;
+ switch (option_rv)
+ {
+ case 0:
+ break;
+ case OPT_VERBOSE: /* --verbose or -v */
+ opt_verbose = OPT_VERBOSE;
+ break;
+ case OPT_DEBUG: /* --debug or -d */
+ opt_verbose = OPT_DEBUG;
+ break;
+ case OPT_VERSION: /* --version or -V */
+ version_command(PROGRAM_NAME);
+ break;
+ case OPT_HELP: /* --help or -h */
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+ break;
+ case OPT_SERVERS: /* --servers or -s */
+ opt_servers= strdup(optarg);
+ break;
+ case OPT_STAT_ARGS:
+ stat_args= strdup(optarg);
+ break;
+ case OPT_ANALYZE: /* --analyze or -a */
+ opt_analyze= OPT_ANALYZE;
+ analyze_mode= (optarg) ? strdup(optarg) : NULL;
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ exit(1);
+ default:
+ abort();
+ }
+ }
+}
{
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 */
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 */
enum protocol
{
ascii_prot = 3, /* ASCII protocol */
- binary_prot, /* binary protocol */
+ binary_prot /* binary protocol */
};
/**
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 */
{
CMD_SET,
CMD_GET,
- CMD_NULL,
+ CMD_NULL
} ms_cmd_type_t;
/* types in the configuration file */
CONF_KEY,
CONF_VALUE,
CONF_CMD,
- CONF_NULL,
+ CONF_NULL
} ms_conf_type_t;
/* information of command distribution */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include "utilities.h"
-
-
-long int timedif(struct timeval a, struct timeval b)
-{
- long us, s;
-
- us = (int)(a.tv_usec - b.tv_usec);
- us /= 1000;
- s = (int)(a.tv_sec - b.tv_sec);
- s *= 1000;
- return s + us;
-}
-
-void version_command(const char *command_name)
-{
- printf("%s v%u.%u\n", command_name, 1U, 0U);
- exit(0);
-}
-
-static const char *lookup_help(memcached_options option)
-{
- switch (option)
- {
- case OPT_SERVERS: return("List which servers you wish to connect to.");
- case OPT_VERSION: return("Display the version of the application and then exit.");
- case OPT_HELP: return("Display this message and then exit.");
- case OPT_VERBOSE: return("Give more details on the progression of the application.");
- case OPT_DEBUG: return("Provide output only useful for debugging.");
- case OPT_FLAG: return("Provide flag information for storage operation.");
- case OPT_EXPIRE: return("Set the expire option for the object.");
- case OPT_SET: return("Use set command with memcached when storing.");
- case OPT_REPLACE: return("Use replace command with memcached when storing.");
- case OPT_ADD: return("Use add command with memcached when storing.");
- case OPT_SLAP_EXECUTE_NUMBER: return("Number of times to execute the given test.");
- case OPT_SLAP_INITIAL_LOAD: return("Number of key pairs to load before executing tests.");
- case OPT_SLAP_TEST: return("Test to run (currently \"get\" or \"set\").");
- case OPT_SLAP_CONCURRENCY: return("Number of users to simulate with load.");
- case OPT_SLAP_NON_BLOCK: return("Set TCP up to use non-blocking IO.");
- case OPT_SLAP_TCP_NODELAY: return("Set TCP socket up to use nodelay.");
- case OPT_FLUSH: return("Flush servers before running tests.");
- case OPT_HASH: return("Select hash type.");
- case OPT_BINARY: return("Switch to binary protocol.");
- case OPT_ANALYZE: return("Analyze the provided servers.");
- case OPT_UDP: return("Use UDP protocol when communicating with server.");
- case OPT_USERNAME: return "Username to use for SASL authentication";
- case OPT_PASSWD: return "Password to use for SASL authentication";
- case OPT_FILE: return "Path to file in which to save result";
- case OPT_STAT_ARGS: return "Argument for statistics";
- default: WATCHPOINT_ASSERT(0);
- };
-
- WATCHPOINT_ASSERT(0);
- return "forgot to document this function :)";
-}
-
-void help_command(const char *command_name, const char *description,
- const struct option *long_options,
- memcached_programs_help_st *options)
-{
- unsigned int x;
- (void)options;
-
- printf("%s v%u.%u\n\n", command_name, 1U, 0U);
- printf("\t%s\n\n", description);
- printf("Current options. A '=' means the option takes a value.\n\n");
-
- for (x= 0; long_options[x].name; x++)
- {
- const char *help_message;
-
- printf("\t --%s%c\n", long_options[x].name,
- long_options[x].has_arg ? '=' : ' ');
- if ((help_message= lookup_help(long_options[x].val)))
- printf("\t\t%s\n", help_message);
- }
-
- printf("\n");
- exit(0);
-}
-
-void process_hash_option(memcached_st *memc, char *opt_hash)
-{
- uint64_t set;
- memcached_return_t rc;
-
- if (opt_hash == NULL)
- return;
-
- set= MEMCACHED_HASH_DEFAULT; /* Just here to solve warning */
- if (!strcasecmp(opt_hash, "CRC"))
- set= MEMCACHED_HASH_CRC;
- else if (!strcasecmp(opt_hash, "FNV1_64"))
- set= MEMCACHED_HASH_FNV1_64;
- else if (!strcasecmp(opt_hash, "FNV1A_64"))
- set= MEMCACHED_HASH_FNV1A_64;
- else if (!strcasecmp(opt_hash, "FNV1_32"))
- set= MEMCACHED_HASH_FNV1_32;
- else if (!strcasecmp(opt_hash, "FNV1A_32"))
- set= MEMCACHED_HASH_FNV1A_32;
- else
- {
- fprintf(stderr, "hash: type not recognized %s\n", opt_hash);
- exit(1);
- }
-
- rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
- if (rc != MEMCACHED_SUCCESS)
- {
- fprintf(stderr, "hash: memcache error %s\n", memcached_strerror(memc, rc));
- exit(1);
- }
-}
-
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
-static char *username;
-static char *passwd;
-
-static int get_username(void *context, int id, const char **result,
- unsigned int *len)
-{
- (void)context;
- if (!result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME))
- return SASL_BADPARAM;
-
- *result= username;
- if (len)
- *len= (username == NULL) ? 0 : (unsigned int)strlen(username);
-
- return SASL_OK;
-}
-
-static int get_password(sasl_conn_t *conn, void *context, int id,
- sasl_secret_t **psecret)
-{
- (void)context;
- static sasl_secret_t* ptr;
-
- if (!conn || ! psecret || id != SASL_CB_PASS)
- return SASL_BADPARAM;
-
- if (passwd == NULL)
- {
- *psecret= NULL;
- return SASL_OK;
- }
-
- size_t len= strlen(passwd);
- ptr= malloc(sizeof(sasl_secret_t) + len +1);
- if (! ptr)
- return SASL_NOMEM;
-
- ptr->len= len;
- memcpy(ptr->data, passwd, len);
- ptr->data[len]= 0;
-
- *psecret= ptr;
- return SASL_OK;
-}
-
-/* callbacks we support */
-static sasl_callback_t sasl_callbacks[] = {
- {
- SASL_CB_USER, &get_username, NULL
- }, {
- SASL_CB_AUTHNAME, &get_username, NULL
- }, {
- SASL_CB_PASS, &get_password, NULL
- }, {
- SASL_CB_LIST_END, NULL, NULL
- }
-};
-#endif
-
-bool initialize_sasl(memcached_st *memc, char *user, char *password)
-{
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
- if (user != NULL && password != NULL)
- {
- username= user;
- passwd= password;
-
- if (sasl_client_init(NULL) != SASL_OK)
- {
- fprintf(stderr, "Failed to initialize sasl library!\n");
- return false;
- }
- memcached_set_sasl_callbacks(memc, sasl_callbacks);
- }
-#else
- (void)memc;
- (void)user;
- (void)password;
-#endif
-
- return true;
-}
-
-void shutdown_sasl(void)
-{
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
- if (username != NULL || passwd != NULL)
- sasl_done();
-#endif
-}
-
-void initialize_sockets(void)
-{
- /* Define the function for all platforms to avoid #ifdefs in each program */
-#ifdef WIN32
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0)
- {
- fprintf(stderr, "Socket Initialization Error. Program aborted\n");
- exit(EXIT_FAILURE);
- }
-#endif
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+#include "config.h"
+
+#include <clients/utilities.h>
+#include <cstdio>
+#include <cstring>
+#include <ctype.h>
+
+
+long int timedif(struct timeval a, struct timeval b)
+{
+ long us, s;
+
+ us = (int)(a.tv_usec - b.tv_usec);
+ us /= 1000;
+ s = (int)(a.tv_sec - b.tv_sec);
+ s *= 1000;
+ return s + us;
+}
+
+void version_command(const char *command_name)
+{
+ printf("%s v%u.%u\n", command_name, 1U, 0U);
+ exit(0);
+}
+
+static const char *lookup_help(memcached_options option)
+{
+ switch (option)
+ {
+ case OPT_SERVERS: return("List which servers you wish to connect to.");
+ case OPT_VERSION: return("Display the version of the application and then exit.");
+ case OPT_HELP: return("Display this message and then exit.");
+ case OPT_VERBOSE: return("Give more details on the progression of the application.");
+ case OPT_DEBUG: return("Provide output only useful for debugging.");
+ case OPT_FLAG: return("Provide flag information for storage operation.");
+ case OPT_EXPIRE: return("Set the expire option for the object.");
+ case OPT_SET: return("Use set command with memcached when storing.");
+ case OPT_REPLACE: return("Use replace command with memcached when storing.");
+ case OPT_ADD: return("Use add command with memcached when storing.");
+ case OPT_SLAP_EXECUTE_NUMBER: return("Number of times to execute the given test.");
+ case OPT_SLAP_INITIAL_LOAD: return("Number of key pairs to load before executing tests.");
+ case OPT_SLAP_TEST: return("Test to run (currently \"get\" or \"set\").");
+ case OPT_SLAP_CONCURRENCY: return("Number of users to simulate with load.");
+ case OPT_SLAP_NON_BLOCK: return("Set TCP up to use non-blocking IO.");
+ case OPT_SLAP_TCP_NODELAY: return("Set TCP socket up to use nodelay.");
+ case OPT_FLUSH: return("Flush servers before running tests.");
+ case OPT_HASH: return("Select hash type.");
+ case OPT_BINARY: return("Switch to binary protocol.");
+ case OPT_ANALYZE: return("Analyze the provided servers.");
+ case OPT_UDP: return("Use UDP protocol when communicating with server.");
+ case OPT_USERNAME: return "Username to use for SASL authentication";
+ case OPT_PASSWD: return "Password to use for SASL authentication";
+ case OPT_FILE: return "Path to file in which to save result";
+ case OPT_STAT_ARGS: return "Argument for statistics";
+ default: WATCHPOINT_ASSERT(0);
+ };
+
+ WATCHPOINT_ASSERT(0);
+ return "forgot to document this function :)";
+}
+
+void help_command(const char *command_name, const char *description,
+ const struct option *long_options,
+ memcached_programs_help_st *options)
+{
+ unsigned int x;
+ (void)options;
+
+ printf("%s v%u.%u\n\n", command_name, 1U, 0U);
+ printf("\t%s\n\n", description);
+ printf("Current options. A '=' means the option takes a value.\n\n");
+
+ for (x= 0; long_options[x].name; x++)
+ {
+ const char *help_message;
+
+ printf("\t --%s%c\n", long_options[x].name,
+ long_options[x].has_arg ? '=' : ' ');
+ if ((help_message= lookup_help(memcached_options(long_options[x].val))))
+ printf("\t\t%s\n", help_message);
+ }
+
+ printf("\n");
+ exit(0);
+}
+
+void process_hash_option(memcached_st *memc, char *opt_hash)
+{
+ uint64_t set;
+ memcached_return_t rc;
+
+ if (opt_hash == NULL)
+ return;
+
+ set= MEMCACHED_HASH_DEFAULT; /* Just here to solve warning */
+ if (!strcasecmp(opt_hash, "CRC"))
+ set= MEMCACHED_HASH_CRC;
+ else if (!strcasecmp(opt_hash, "FNV1_64"))
+ set= MEMCACHED_HASH_FNV1_64;
+ else if (!strcasecmp(opt_hash, "FNV1A_64"))
+ set= MEMCACHED_HASH_FNV1A_64;
+ else if (!strcasecmp(opt_hash, "FNV1_32"))
+ set= MEMCACHED_HASH_FNV1_32;
+ else if (!strcasecmp(opt_hash, "FNV1A_32"))
+ set= MEMCACHED_HASH_FNV1A_32;
+ else
+ {
+ fprintf(stderr, "hash: type not recognized %s\n", opt_hash);
+ exit(1);
+ }
+
+ rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ fprintf(stderr, "hash: memcache error %s\n", memcached_strerror(memc, rc));
+ exit(1);
+ }
+}
+
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+static char *username;
+static char *passwd;
+
+static int get_username(void *context, int id, const char **result, unsigned int *len)
+{
+ (void)context;
+ if (!result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME))
+ return SASL_BADPARAM;
+
+ *result= username;
+ if (len)
+ *len= (username == NULL) ? 0 : (unsigned int)strlen(username);
+
+ return SASL_OK;
+}
+
+static int get_password(sasl_conn_t *conn, void *context, int id,
+ sasl_secret_t **psecret)
+{
+ (void)context;
+ static sasl_secret_t* ptr;
+
+ if (!conn || ! psecret || id != SASL_CB_PASS)
+ return SASL_BADPARAM;
+
+ if (passwd == NULL)
+ {
+ *psecret= NULL;
+ return SASL_OK;
+ }
+
+ size_t len= strlen(passwd);
+ ptr= (sasl_secret_t *)malloc(sizeof(sasl_secret_t) + len +1);
+ if (not ptr)
+ return SASL_NOMEM;
+
+ ptr->len= len;
+ memcpy(ptr->data, passwd, len);
+ ptr->data[len]= 0;
+
+ *psecret= ptr;
+ return SASL_OK;
+}
+
+typedef int (*local_sasl_fn)(void);
+
+/* callbacks we support */
+static sasl_callback_t sasl_callbacks[] = {
+ { SASL_CB_USER, (local_sasl_fn)get_username, NULL },
+ { SASL_CB_AUTHNAME, (local_sasl_fn)get_username, NULL },
+ { SASL_CB_PASS, (local_sasl_fn)get_password, NULL },
+ { SASL_CB_LIST_END, NULL, NULL }
+};
+#endif
+
+bool initialize_sasl(memcached_st *memc, char *user, char *password)
+{
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+ if (user != NULL && password != NULL)
+ {
+ username= user;
+ passwd= password;
+
+ if (sasl_client_init(NULL) != SASL_OK)
+ {
+ fprintf(stderr, "Failed to initialize sasl library!\n");
+ return false;
+ }
+ memcached_set_sasl_callbacks(memc, sasl_callbacks);
+ }
+#else
+ (void)memc;
+ (void)user;
+ (void)password;
+#endif
+
+ return true;
+}
+
+void shutdown_sasl(void)
+{
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+ if (username != NULL || passwd != NULL)
+ sasl_done();
+#endif
+}
+
+void initialize_sockets(void)
+{
+ /* Define the function for all platforms to avoid #ifdefs in each program */
+#ifdef WIN32
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0)
+ {
+ fprintf(stderr, "Socket Initialization Error. Program aborted\n");
+ exit(EXIT_FAILURE);
+ }
+#endif
+}
*
*/
+#pragma once
+
#include <getopt.h>
#include <libmemcached/memcached.h>
#include "libmemcached/watchpoint.h"
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);
bool initialize_sasl(memcached_st *memc, char *user, char *password);
void shutdown_sasl(void);
void initialize_sockets(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
AC_PREREQ(2.59)
AC_INIT([libmemcached],[0.49],[http://libmemcached.org/])
-AC_CONFIG_SRCDIR([libmemcached/memcached.c])
+AC_CONFIG_SRCDIR([libmemcached/memcached.cc])
AC_CONFIG_AUX_DIR(config)
PANDORA_CANONICAL_TARGET(no-vc-changelog)
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
+++ /dev/null
-/* HashKit
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length)
-{
- return hashkit_one_at_a_time(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1_64(const char *key, size_t key_length)
-{
- return hashkit_fnv1_64(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length)
-{
- return hashkit_fnv1a_64(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1_32(const char *key, size_t key_length)
-{
- return hashkit_fnv1_32(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length)
-{
- return hashkit_fnv1a_32(key, key_length, NULL);
-}
-
-uint32_t libhashkit_crc32(const char *key, size_t key_length)
-{
- return hashkit_crc32(key, key_length, NULL);
-}
-
-#ifdef HAVE_HSIEH_HASH
-uint32_t libhashkit_hsieh(const char *key, size_t key_length)
-{
- return hashkit_hsieh(key, key_length, NULL);
-}
-#endif
-
-#ifdef HAVE_MURMUR_HASH
-uint32_t libhashkit_murmur(const char *key, size_t key_length)
-{
- return hashkit_murmur(key, key_length, NULL);
-}
-#endif
-
-uint32_t libhashkit_jenkins(const char *key, size_t key_length)
-{
- return hashkit_jenkins(key, key_length, NULL);
-}
-
-uint32_t libhashkit_md5(const char *key, size_t key_length)
-{
- return hashkit_md5(key, key_length, NULL);
-}
-
-void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result)
-{
- md5_signature(key, (uint32_t)length, result);
-}
-
--- /dev/null
+/* HashKit
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length)
+{
+ return hashkit_one_at_a_time(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1_64(const char *key, size_t key_length)
+{
+ return hashkit_fnv1_64(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length)
+{
+ return hashkit_fnv1a_64(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1_32(const char *key, size_t key_length)
+{
+ return hashkit_fnv1_32(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length)
+{
+ return hashkit_fnv1a_32(key, key_length, NULL);
+}
+
+uint32_t libhashkit_crc32(const char *key, size_t key_length)
+{
+ return hashkit_crc32(key, key_length, NULL);
+}
+
+#ifdef HAVE_HSIEH_HASH
+uint32_t libhashkit_hsieh(const char *key, size_t key_length)
+{
+ return hashkit_hsieh(key, key_length, NULL);
+}
+#endif
+
+#ifdef HAVE_MURMUR_HASH
+uint32_t libhashkit_murmur(const char *key, size_t key_length)
+{
+ return hashkit_murmur(key, key_length, NULL);
+}
+#endif
+
+uint32_t libhashkit_jenkins(const char *key, size_t key_length)
+{
+ return hashkit_jenkins(key, key_length, NULL);
+}
+
+uint32_t libhashkit_md5(const char *key, size_t key_length)
+{
+ return hashkit_md5(key, key_length, NULL);
+}
+
+void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result)
+{
+ md5_signature(key, (uint32_t)length, result);
+}
+
+++ /dev/null
-/* HashKit
- * Copyright (C) 2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
--- /dev/null
+/* HashKit
+ * Copyright (C) 2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
* the COPYING file in the parent directory for full text.
*/
-#ifndef HASHKIT_COMMON_H
-#define HASHKIT_COMMON_H
+#pragma once
#include <config.h>
#ifdef __cplusplus
}
#endif
-
-#endif /* HASHKIT_COMMON_H */
+++ /dev/null
-/* The crc32 functions and data was originally written by Spencer
- * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source
- * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at
- * src/usr.bin/cksum/crc32.c.
- */
-
-#include <libhashkit/common.h>
-
-static const uint32_t crc32tab[256] = {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
- 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
- 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
- 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
- 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
- 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
- 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
- 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
- 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
- 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
- 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
- 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
- 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
- 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
- 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
- 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
- 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
- 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
- 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
- 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
- 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
- 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
- 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
- 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
- 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
- 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
- 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
- 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
- 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
- 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
- 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
-};
-
-uint32_t hashkit_crc32(const char *key, size_t key_length, void *context)
-{
- uint64_t x;
- uint32_t crc= UINT32_MAX;
- (void)context;
-
- for (x= 0; x < key_length; x++)
- crc= (crc >> 8) ^ crc32tab[(crc ^ (uint64_t)key[x]) & 0xff];
-
- return ((~crc) >> 16) & 0x7fff;
-}
--- /dev/null
+/* The crc32 functions and data was originally written by Spencer
+ * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source
+ * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at
+ * src/usr.bin/cksum/crc32.c.
+ */
+
+#include <libhashkit/common.h>
+
+static const uint32_t crc32tab[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+uint32_t hashkit_crc32(const char *key, size_t key_length, void *context)
+{
+ uint64_t x;
+ uint32_t crc= UINT32_MAX;
+ (void)context;
+
+ for (x= 0; x < key_length; x++)
+ crc= (crc >> 8) ^ crc32tab[(crc ^ (uint64_t)key[x]) & 0xff];
+
+ return ((~crc) >> 16) & 0x7fff;
+}
+++ /dev/null
-/* HashKit
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-uint32_t hashkit_digest(const hashkit_st *self, const char *key, size_t key_length)
-{
- return self->base_hash.function(key, key_length, self->base_hash.context);
-}
-
-uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm)
-{
- switch (hash_algorithm)
- {
- case HASHKIT_HASH_DEFAULT:
- return libhashkit_one_at_a_time(key, key_length);
- case HASHKIT_HASH_MD5:
- return libhashkit_md5(key, key_length);
- case HASHKIT_HASH_CRC:
- return libhashkit_crc32(key, key_length);
- case HASHKIT_HASH_FNV1_64:
- return libhashkit_fnv1_64(key, key_length);
- case HASHKIT_HASH_FNV1A_64:
- return libhashkit_fnv1a_64(key, key_length);
- case HASHKIT_HASH_FNV1_32:
- return libhashkit_fnv1_32(key, key_length);
- case HASHKIT_HASH_FNV1A_32:
- return libhashkit_fnv1a_32(key, key_length);
- case HASHKIT_HASH_HSIEH:
-#ifdef HAVE_HSIEH_HASH
- return libhashkit_hsieh(key, key_length);
-#else
- return 1;
-#endif
- case HASHKIT_HASH_MURMUR:
-#ifdef HAVE_MURMUR_HASH
- return libhashkit_murmur(key, key_length);
-#else
- return 1;
-#endif
- case HASHKIT_HASH_JENKINS:
- return libhashkit_jenkins(key, key_length);
- case HASHKIT_HASH_CUSTOM:
- case HASHKIT_HASH_MAX:
- default:
-#ifdef HAVE_DEBUG
- fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n");
- fflush(stderr);
- assert(0);
-#endif
- break;
- }
-
- return 1;
-}
--- /dev/null
+/* HashKit
+ * Copyright (C) 2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+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;
+}
+++ /dev/null
-/* HashKit
- * Copyright (C) 2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-/* FNV hash'es lifted from Dustin Sallings work */
-static uint64_t FNV_64_INIT= UINT64_C(0xcbf29ce484222325);
-static uint64_t FNV_64_PRIME= UINT64_C(0x100000001b3);
-static uint32_t FNV_32_INIT= 2166136261UL;
-static uint32_t FNV_32_PRIME= 16777619;
-
-uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *context)
-{
- /* Thanks to pierre@demartines.com for the pointer */
- uint64_t hash= FNV_64_INIT;
- (void)context;
-
- for (size_t x= 0; x < key_length; x++)
- {
- hash *= FNV_64_PRIME;
- hash ^= (uint64_t)key[x];
- }
-
- return (uint32_t)hash;
-}
-
-uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *context)
-{
- uint32_t hash= (uint32_t) FNV_64_INIT;
- (void)context;
-
- for (size_t x= 0; x < key_length; x++)
- {
- uint32_t val= (uint32_t)key[x];
- hash ^= val;
- hash *= (uint32_t) FNV_64_PRIME;
- }
-
- return hash;
-}
-
-uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context)
-{
- uint32_t hash= FNV_32_INIT;
- (void)context;
-
- for (size_t x= 0; x < key_length; x++)
- {
- uint32_t val= (uint32_t)key[x];
- hash *= FNV_32_PRIME;
- hash ^= val;
- }
-
- return hash;
-}
-
-uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context)
-{
- uint32_t hash= FNV_32_INIT;
- (void)context;
-
- for (size_t x= 0; x < key_length; x++)
- {
- uint32_t val= (uint32_t)key[x];
- hash ^= val;
- hash *= FNV_32_PRIME;
- }
-
- return hash;
-}
--- /dev/null
+/* HashKit
+ * Copyright (C) 2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+/* FNV hash'es lifted from Dustin Sallings work */
+static uint64_t FNV_64_INIT= UINT64_C(0xcbf29ce484222325);
+static uint64_t FNV_64_PRIME= UINT64_C(0x100000001b3);
+static uint32_t FNV_32_INIT= 2166136261UL;
+static uint32_t FNV_32_PRIME= 16777619;
+
+uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *context)
+{
+ /* Thanks to pierre@demartines.com for the pointer */
+ uint64_t hash= FNV_64_INIT;
+ (void)context;
+
+ for (size_t x= 0; x < key_length; x++)
+ {
+ hash *= FNV_64_PRIME;
+ hash ^= (uint64_t)key[x];
+ }
+
+ return (uint32_t)hash;
+}
+
+uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *context)
+{
+ uint32_t hash= (uint32_t) FNV_64_INIT;
+ (void)context;
+
+ for (size_t x= 0; x < key_length; x++)
+ {
+ uint32_t val= (uint32_t)key[x];
+ hash ^= val;
+ hash *= (uint32_t) FNV_64_PRIME;
+ }
+
+ return hash;
+}
+
+uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context)
+{
+ uint32_t hash= FNV_32_INIT;
+ (void)context;
+
+ for (size_t x= 0; x < key_length; x++)
+ {
+ uint32_t val= (uint32_t)key[x];
+ hash *= FNV_32_PRIME;
+ hash ^= val;
+ }
+
+ return hash;
+}
+
+uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context)
+{
+ uint32_t hash= FNV_32_INIT;
+ (void)context;
+
+ for (size_t x= 0; x < key_length; x++)
+ {
+ uint32_t val= (uint32_t)key[x];
+ hash ^= val;
+ hash *= FNV_32_PRIME;
+ }
+
+ return hash;
+}
+++ /dev/null
-/* HashKit
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-static hashkit_return_t _set_function(struct hashkit_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);
-}
--- /dev/null
+/* HashKit
+ * Copyright (C) 2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+static hashkit_return_t _set_function(struct hashkit_st::hashkit_function_st *self, hashkit_hash_algorithm_t hash_algorithm)
+{
+ 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);
+}
+++ /dev/null
-/* HashKit
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-static const hashkit_st global_default_hash= {
- .base_hash= {
- .function= hashkit_one_at_a_time,
- .context= NULL
- },
- .flags= {
- .is_base_same_distributed= false,
- }
-};
-
-static inline bool _hashkit_init(hashkit_st *self)
-{
- self->base_hash= global_default_hash.base_hash;
- self->distribution_hash= global_default_hash.base_hash;
- self->flags= global_default_hash.flags;
-
- return true;
-}
-
-static inline hashkit_st *_hashkit_create(hashkit_st *self)
-{
- if (self == NULL)
- {
- self= (hashkit_st *)malloc(sizeof(hashkit_st));
- if (self == NULL)
- {
- return NULL;
- }
-
- self->options.is_allocated= true;
- }
- else
- {
- self->options.is_allocated= false;
- }
-
- return self;
-}
-
-hashkit_st *hashkit_create(hashkit_st *self)
-{
- self= _hashkit_create(self);
- if (! self)
- return self;
-
- if (! _hashkit_init(self))
- {
- hashkit_free(self);
- }
-
- return self;
-}
-
-
-void hashkit_free(hashkit_st *self)
-{
- if (hashkit_is_allocated(self))
- {
- free(self);
- }
-}
-
-hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source)
-{
- if (source == NULL)
- {
- return hashkit_create(destination);
- }
-
- /* new_clone will be a pointer to destination */
- destination= _hashkit_create(destination);
-
- // Should only happen on allocation failure.
- if (destination == NULL)
- {
- return NULL;
- }
-
- destination->base_hash= source->base_hash;
- destination->distribution_hash= source->distribution_hash;
- destination->flags= source->flags;
-
- return destination;
-}
-
-bool hashkit_compare(const hashkit_st *first, const hashkit_st *second)
-{
- if (first->base_hash.function == second->base_hash.function &&
- first->base_hash.context == second->base_hash.context &&
- first->distribution_hash.function == second->distribution_hash.function &&
- first->distribution_hash.context == second->distribution_hash.context &&
- first->flags.is_base_same_distributed == second->flags.is_base_same_distributed)
- {
- return true;
- }
-
- return false;
-}
--- /dev/null
+/* HashKit
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+static inline bool _hashkit_init(hashkit_st *self)
+{
+ self->base_hash.function= hashkit_one_at_a_time;
+ self->base_hash.context= NULL;
+ self->distribution_hash.function= self->base_hash.function;
+ self->flags.is_base_same_distributed= false;
+
+ return true;
+}
+
+static inline hashkit_st *_hashkit_create(hashkit_st *self)
+{
+ if (self == NULL)
+ {
+ self= (hashkit_st *)malloc(sizeof(hashkit_st));
+ if (self == NULL)
+ {
+ return NULL;
+ }
+
+ self->options.is_allocated= true;
+ }
+ else
+ {
+ self->options.is_allocated= false;
+ }
+
+ return self;
+}
+
+hashkit_st *hashkit_create(hashkit_st *self)
+{
+ self= _hashkit_create(self);
+ if (! self)
+ return self;
+
+ if (! _hashkit_init(self))
+ {
+ hashkit_free(self);
+ }
+
+ return self;
+}
+
+
+void hashkit_free(hashkit_st *self)
+{
+ if (hashkit_is_allocated(self))
+ {
+ free(self);
+ }
+}
+
+hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source)
+{
+ if (source == NULL)
+ {
+ return hashkit_create(destination);
+ }
+
+ /* new_clone will be a pointer to destination */
+ destination= _hashkit_create(destination);
+
+ // Should only happen on allocation failure.
+ if (destination == NULL)
+ {
+ return NULL;
+ }
+
+ destination->base_hash= source->base_hash;
+ destination->distribution_hash= source->distribution_hash;
+ destination->flags= source->flags;
+
+ return destination;
+}
+
+bool hashkit_compare(const hashkit_st *first, const hashkit_st *second)
+{
+ if (first->base_hash.function == second->base_hash.function &&
+ first->base_hash.context == second->base_hash.context &&
+ first->distribution_hash.function == second->distribution_hash.function &&
+ first->distribution_hash.context == second->distribution_hash.context &&
+ first->flags.is_base_same_distributed == second->flags.is_base_same_distributed)
+ {
+ return true;
+ }
+
+ return false;
+}
-/* 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)
#endif
#include <inttypes.h>
#include <sys/types.h>
+
#include <libhashkit/visibility.h>
#include <libhashkit/configure.h>
#include <libhashkit/types.h>
#include <libhashkit/str_algorithm.h>
#include <libhashkit/strerror.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HASHKIT_API
-hashkit_st *hashkit_create(hashkit_st *hash);
-
-HASHKIT_API
-hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
-
-HASHKIT_API
-bool hashkit_compare(const hashkit_st *first, const hashkit_st *second);
-
-HASHKIT_API
-void hashkit_free(hashkit_st *hash);
-
-#define hashkit_is_allocated(__object) ((__object)->options.is_allocated)
-#define hashkit_is_initialized(__object) ((__object)->options.is_initialized)
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
struct hashkit_st
{
struct hashkit_function_st {
};
#ifdef __cplusplus
+extern "C" {
+#endif
-#include <string>
-
-class Hashkit {
-
-public:
-
- Hashkit()
- {
- hashkit_create(&self);
- }
-
- Hashkit(const Hashkit& source)
- {
- hashkit_clone(&self, &source.self);
- }
-
- Hashkit& operator=(const Hashkit& source)
- {
- hashkit_free(&self);
- hashkit_clone(&self, &source.self);
-
- return *this;
- }
-
- friend bool operator==(const Hashkit &left, const Hashkit &right)
- {
- return hashkit_compare(&left.self, &right.self);
- }
-
- uint32_t digest(std::string& str)
- {
- return hashkit_digest(&self, str.c_str(), str.length());
- }
+HASHKIT_API
+hashkit_st *hashkit_create(hashkit_st *hash);
- uint32_t digest(const char *key, size_t key_length)
- {
- return hashkit_digest(&self, key, key_length);
- }
+HASHKIT_API
+hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
- hashkit_return_t set_function(hashkit_hash_algorithm_t hash_algorithm)
- {
- return hashkit_set_function(&self, hash_algorithm);
- }
+HASHKIT_API
+bool hashkit_compare(const hashkit_st *first, const hashkit_st *second);
- hashkit_return_t set_distribution_function(hashkit_hash_algorithm_t hash_algorithm)
- {
- return hashkit_set_function(&self, hash_algorithm);
- }
+HASHKIT_API
+void hashkit_free(hashkit_st *hash);
- ~Hashkit()
- {
- hashkit_free(&self);
- }
-private:
+#define hashkit_is_allocated(__object) ((__object)->options.is_allocated)
+#define hashkit_is_initialized(__object) ((__object)->options.is_initialized)
- hashkit_st self;
-};
+#ifdef __cplusplus
+} // extern "C"
#endif
-
-
-#endif /* HASHKIT_H */
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libhashkit/hashkit.h>
+#include <string>
+
+class Hashkit {
+
+public:
+
+ Hashkit()
+ {
+ hashkit_create(&self);
+ }
+
+ Hashkit(const Hashkit& source)
+ {
+ hashkit_clone(&self, &source.self);
+ }
+
+ Hashkit& operator=(const Hashkit& source)
+ {
+ hashkit_free(&self);
+ hashkit_clone(&self, &source.self);
+
+ return *this;
+ }
+
+ friend bool operator==(const Hashkit &left, const Hashkit &right)
+ {
+ return hashkit_compare(&left.self, &right.self);
+ }
+
+ uint32_t digest(std::string& str)
+ {
+ return hashkit_digest(&self, str.c_str(), str.length());
+ }
+
+ uint32_t digest(const char *key, size_t key_length)
+ {
+ return hashkit_digest(&self, key, key_length);
+ }
+
+ hashkit_return_t set_function(hashkit_hash_algorithm_t hash_algorithm)
+ {
+ return hashkit_set_function(&self, hash_algorithm);
+ }
+
+ hashkit_return_t set_distribution_function(hashkit_hash_algorithm_t hash_algorithm)
+ {
+ return hashkit_set_function(&self, hash_algorithm);
+ }
+
+ ~Hashkit()
+ {
+ hashkit_free(&self);
+ }
+private:
+
+ hashkit_st self;
+};
+++ /dev/null
-/* By Paul Hsieh (C) 2004, 2005. Covered under the Paul Hsieh
- * derivative license.
- * See: http://www.azillionmonkeys.com/qed/weblicense.html for license
- * details.
- * http://www.azillionmonkeys.com/qed/hash.html
-*/
-
-#include <libhashkit/common.h>
-
-#undef get16bits
-#if (defined(__GNUC__) && defined(__i386__))
-#define get16bits(d) (*((const uint16_t *) (d)))
-#endif
-
-#if !defined (get16bits)
-#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
- +(uint32_t)(((const uint8_t *)(d))[0]) )
-#endif
-
-uint32_t hashkit_hsieh(const char *key, size_t key_length, void *context __attribute__((unused)))
-{
- uint32_t hash = 0, tmp;
- int rem;
-
- if (key_length <= 0 || key == NULL)
- return 0;
-
- rem = key_length & 3;
- key_length >>= 2;
-
- /* Main loop */
- for (;key_length > 0; key_length--)
- {
- hash += get16bits (key);
- tmp = (get16bits (key+2) << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- key += 2*sizeof (uint16_t);
- hash += hash >> 11;
- }
-
- /* Handle end cases */
- switch (rem)
- {
- case 3: hash += get16bits (key);
- hash ^= hash << 16;
- hash ^= (uint32_t)key[sizeof (uint16_t)] << 18;
- hash += hash >> 11;
- break;
- case 2: hash += get16bits (key);
- hash ^= hash << 11;
- hash += hash >> 17;
- break;
- case 1: hash += (unsigned char)(*key);
- hash ^= hash << 10;
- hash += hash >> 1;
- default:
- break;
- }
-
- /* Force "avalanching" of final 127 bits */
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 4;
- hash += hash >> 17;
- hash ^= hash << 25;
- hash += hash >> 6;
-
- return hash;
-}
-
--- /dev/null
+/* By Paul Hsieh (C) 2004, 2005. Covered under the Paul Hsieh
+ * derivative license.
+ * See: http://www.azillionmonkeys.com/qed/weblicense.html for license
+ * details.
+ * http://www.azillionmonkeys.com/qed/hash.html
+*/
+
+#include <libhashkit/common.h>
+
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__))
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+uint32_t hashkit_hsieh(const char *key, size_t key_length, void *context __attribute__((unused)))
+{
+ uint32_t hash = 0, tmp;
+ int rem;
+
+ if (key_length <= 0 || key == NULL)
+ return 0;
+
+ rem = key_length & 3;
+ key_length >>= 2;
+
+ /* Main loop */
+ for (;key_length > 0; key_length--)
+ {
+ hash += get16bits (key);
+ tmp = (get16bits (key+2) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ key += 2*sizeof (uint16_t);
+ hash += hash >> 11;
+ }
+
+ /* Handle end cases */
+ switch (rem)
+ {
+ case 3: hash += get16bits (key);
+ hash ^= hash << 16;
+ hash ^= (uint32_t)key[sizeof (uint16_t)] << 18;
+ hash += hash >> 11;
+ break;
+ case 2: hash += get16bits (key);
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ break;
+ case 1: hash += (unsigned char)(*key);
+ hash ^= hash << 10;
+ hash += hash >> 1;
+ default:
+ break;
+ }
+
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+
+ return hash;
+}
+
libhashkit/digest.h \
libhashkit/function.h \
libhashkit/hashkit.h \
+ libhashkit/hashkit.hpp \
libhashkit/strerror.h \
libhashkit/str_algorithm.h \
libhashkit/types.h \
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) \
+++ /dev/null
-/*
-*
-* By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
-* code any way you wish, private, educational, or commercial. It's free.
-* Use for hash table lookup, or anything where one collision in 2^^32 is
-* acceptable. Do NOT use for cryptographic purposes.
-* http://burtleburtle.net/bob/hash/index.html
-*
-* Modified by Brian Pontz for libmemcached
-* TODO:
-* Add big endian support
-*/
-
-#include <libhashkit/common.h>
-
-#define hashsize(n) ((uint32_t)1<<(n))
-#define hashmask(n) (hashsize(n)-1)
-#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
-
-#define mix(a,b,c) \
-{ \
- a -= c; a ^= rot(c, 4); c += b; \
- b -= a; b ^= rot(a, 6); a += c; \
- c -= b; c ^= rot(b, 8); b += a; \
- a -= c; a ^= rot(c,16); c += b; \
- b -= a; b ^= rot(a,19); a += c; \
- c -= b; c ^= rot(b, 4); b += a; \
-}
-
-#define final(a,b,c) \
-{ \
- c ^= b; c -= rot(b,14); \
- a ^= c; a -= rot(c,11); \
- b ^= a; b -= rot(a,25); \
- c ^= b; c -= rot(b,16); \
- a ^= c; a -= rot(c,4); \
- b ^= a; b -= rot(a,14); \
- c ^= b; c -= rot(b,24); \
-}
-
-#define JENKINS_INITVAL 13
-
-/*
-jenkins_hash() -- hash a variable-length key into a 32-bit value
- k : the key (the unaligned variable-length array of bytes)
- length : the length of the key, counting by bytes
- initval : can be any 4-byte value
-Returns a 32-bit value. Every bit of the key affects every bit of
-the return value. Two keys differing by one or two bits will have
-totally different hash values.
-
-The best hash table sizes are powers of 2. There is no need to do
-mod a prime (mod is sooo slow!). If you need less than 32 bits,
-use a bitmask. For example, if you need only 10 bits, do
- h = (h & hashmask(10));
-In which case, the hash table should have hashsize(10) elements.
-*/
-
-uint32_t hashkit_jenkins(const char *key, size_t length, void *context)
-{
- uint32_t a,b,c; /* internal state */
- union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
- (void)context;
-
- /* Set up the internal state */
- a = b = c = 0xdeadbeef + ((uint32_t)length) + JENKINS_INITVAL;
-
- u.ptr = key;
-#ifndef WORDS_BIGENDIAN
- if ((u.i & 0x3) == 0)
- {
- const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
-
- /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
- while (length > 12)
- {
- a += k[0];
- b += k[1];
- c += k[2];
- mix(a,b,c);
- length -= 12;
- k += 3;
- }
-
- /*----------------------------- handle the last (probably partial) block */
- /*
- * "k[2]&0xffffff" actually reads beyond the end of the string, but
- * then masks off the part it's not allowed to read. Because the
- * string is aligned, the masked-off tail is in the same word as the
- * rest of the string. Every machine with memory protection I've seen
- * does it on word boundaries, so is OK with this. But VALGRIND will
- * still catch it and complain. The masking trick does make the hash
- * noticably faster for short strings (like English words).
- */
- switch(length)
- {
- case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
- case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
- case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
- case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
- case 8 : b+=k[1]; a+=k[0]; break;
- case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
- case 6 : b+=k[1]&0xffff; a+=k[0]; break;
- case 5 : b+=k[1]&0xff; a+=k[0]; break;
- case 4 : a+=k[0]; break;
- case 3 : a+=k[0]&0xffffff; break;
- case 2 : a+=k[0]&0xffff; break;
- case 1 : a+=k[0]&0xff; break;
- case 0 : return c; /* zero length strings require no mixing */
- default: return c;
- }
-
- }
- else if ((u.i & 0x1) == 0)
- {
- const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
- const uint8_t *k8;
-
- /*--------------- all but last block: aligned reads and different mixing */
- while (length > 12)
- {
- a += k[0] + (((uint32_t)k[1])<<16);
- b += k[2] + (((uint32_t)k[3])<<16);
- c += k[4] + (((uint32_t)k[5])<<16);
- mix(a,b,c);
- length -= 12;
- k += 6;
- }
-
- /*----------------------------- handle the last (probably partial) block */
- k8 = (const uint8_t *)k;
- switch(length)
- {
- case 12: c+=k[4]+(((uint32_t)k[5])<<16);
- b+=k[2]+(((uint32_t)k[3])<<16);
- a+=k[0]+(((uint32_t)k[1])<<16);
- break;
- case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
- case 10: c+=k[4];
- b+=k[2]+(((uint32_t)k[3])<<16);
- a+=k[0]+(((uint32_t)k[1])<<16);
- break;
- case 9 : c+=k8[8]; /* fall through */
- case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
- a+=k[0]+(((uint32_t)k[1])<<16);
- break;
- case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
- case 6 : b+=k[2];
- a+=k[0]+(((uint32_t)k[1])<<16);
- break;
- case 5 : b+=k8[4]; /* fall through */
- case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
- break;
- case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
- case 2 : a+=k[0];
- break;
- case 1 : a+=k8[0];
- break;
- case 0 : return c; /* zero length requires no mixing */
- default: return c;
- }
-
- }
- else
- { /* need to read the key one byte at a time */
-#endif /* little endian */
- const uint8_t *k = (const uint8_t *)key;
-
- /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
- while (length > 12)
- {
- a += k[0];
- a += ((uint32_t)k[1])<<8;
- a += ((uint32_t)k[2])<<16;
- a += ((uint32_t)k[3])<<24;
- b += k[4];
- b += ((uint32_t)k[5])<<8;
- b += ((uint32_t)k[6])<<16;
- b += ((uint32_t)k[7])<<24;
- c += k[8];
- c += ((uint32_t)k[9])<<8;
- c += ((uint32_t)k[10])<<16;
- c += ((uint32_t)k[11])<<24;
- mix(a,b,c);
- length -= 12;
- k += 12;
- }
-
- /*-------------------------------- last block: affect all 32 bits of (c) */
- switch(length) /* all the case statements fall through */
- {
- case 12: c+=((uint32_t)k[11])<<24;
- case 11: c+=((uint32_t)k[10])<<16;
- case 10: c+=((uint32_t)k[9])<<8;
- case 9 : c+=k[8];
- case 8 : b+=((uint32_t)k[7])<<24;
- case 7 : b+=((uint32_t)k[6])<<16;
- case 6 : b+=((uint32_t)k[5])<<8;
- case 5 : b+=k[4];
- case 4 : a+=((uint32_t)k[3])<<24;
- case 3 : a+=((uint32_t)k[2])<<16;
- case 2 : a+=((uint32_t)k[1])<<8;
- case 1 : a+=k[0];
- break;
- case 0 : return c;
- default : return c;
- }
-#ifndef WORDS_BIGENDIAN
- }
-#endif
-
- final(a,b,c);
- return c;
-}
--- /dev/null
+/*
+*
+* By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+* code any way you wish, private, educational, or commercial. It's free.
+* Use for hash table lookup, or anything where one collision in 2^^32 is
+* acceptable. Do NOT use for cryptographic purposes.
+* http://burtleburtle.net/bob/hash/index.html
+*
+* Modified by Brian Pontz for libmemcached
+* TODO:
+* Add big endian support
+*/
+
+#include <libhashkit/common.h>
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+#define JENKINS_INITVAL 13
+
+/*
+jenkins_hash() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+*/
+
+uint32_t hashkit_jenkins(const char *key, size_t length, void *context)
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+ (void)context;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + JENKINS_INITVAL;
+
+ u.ptr = key;
+#ifndef WORDS_BIGENDIAN
+ if ((u.i & 0x3) == 0)
+ {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ default: return c;
+ }
+
+ }
+ else if ((u.i & 0x1) == 0)
+ {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ default: return c;
+ }
+
+ }
+ else
+ { /* need to read the key one byte at a time */
+#endif /* little endian */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ default : return c;
+ }
+#ifndef WORDS_BIGENDIAN
+ }
+#endif
+
+ final(a,b,c);
+ return c;
+}
+++ /dev/null
-/* HashKit
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-#include <math.h>
-
-#if 0
-static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment)
-{
- unsigned char results[16];
-
- md5_signature((unsigned char*)key, key_length, results);
- return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
- | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
- | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
- | (results[0 + alignment * 4] & 0xFF);
-}
-
-static int continuum_points_cmp(const void *t1, const void *t2)
-{
- hashkit_continuum_point_st *ct1= (hashkit_continuum_point_st *)t1;
- hashkit_continuum_point_st *ct2= (hashkit_continuum_point_st *)t2;
-
- if (ct1->value == ct2->value)
- return 0;
- else if (ct1->value > ct2->value)
- return 1;
- else
- return -1;
-}
-
-int update_continuum(hashkit_st *hashkit)
-{
- uint32_t count;
- uint32_t continuum_index= 0;
- uint32_t value;
- uint32_t points_index;
- uint32_t points_count= 0;
- uint32_t points_per_server;
- uint32_t points_per_hash;
- uint64_t total_weight= 0;
- uint32_t live_servers;
- uint8_t *context;
-
- if (hashkit->active_fn != NULL || hashkit->weight_fn != NULL)
- {
- live_servers= 0;
-
- for (count= 0, context= hashkit->list; count < hashkit->list_size;
- count++, context+= hashkit->context_size)
- {
- if (hashkit->active_fn != NULL)
- {
- if (hashkit->active_fn(context))
- live_servers++;
- else
- continue;
- }
-
- if (hashkit->weight_fn != NULL)
- total_weight+= hashkit->weight_fn(context);
- }
- }
-
- if (hashkit->active_fn == NULL)
- live_servers= (uint32_t)hashkit->list_size;
-
- if (live_servers == 0)
- return 0;
-
- if (hashkit->weight_fn == NULL)
- {
- points_per_server= HASHKIT_POINTS_PER_NODE;
- points_per_hash= 1;
- }
- else
- {
- points_per_server= HASHKIT_POINTS_PER_NODE_WEIGHTED;
- points_per_hash= 4;
- }
-
- if (live_servers > hashkit->continuum_count)
- {
- hashkit_continuum_point_st *new_continuum;
-
- new_continuum= realloc(hashkit->continuum,
- sizeof(hashkit_continuum_point_st) *
- (live_servers + HASHKIT_CONTINUUM_ADDITION) *
- points_per_server);
-
- if (new_continuum == NULL)
- return ENOMEM;
-
- hashkit->continuum= new_continuum;
- hashkit->continuum_count= live_servers + HASHKIT_CONTINUUM_ADDITION;
- }
-
- for (count= 0, context= hashkit->list; count < hashkit->list_size;
- count++, context+= hashkit->context_size)
- {
- if (hashkit->active_fn != NULL && hashkit->active_fn(context) == false)
- continue;
-
- if (hashkit->weight_fn != NULL)
- {
- float pct = (float)hashkit->weight_fn(context) / (float)total_weight;
- points_per_server= (uint32_t) ((floorf((float) (pct * HASHKIT_POINTS_PER_NODE_WEIGHTED / 4 * (float)live_servers + 0.0000000001))) * 4);
- }
-
- for (points_index= 0;
- points_index < points_per_server / points_per_hash;
- points_index++)
- {
- char sort_host[HASHKIT_CONTINUUM_KEY_SIZE]= "";
- size_t sort_host_length;
-
- if (hashkit->continuum_key_fn == NULL)
- {
- sort_host_length= (size_t) snprintf(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, "%u",
- points_index);
- }
- else
- {
- sort_host_length= hashkit->continuum_key_fn(sort_host, HASHKIT_CONTINUUM_KEY_SIZE,
- points_index, context);
- }
-
- if (hashkit->weight_fn == NULL)
- {
- if (hashkit->continuum_hash_fn == NULL)
- value= hashkit_default(sort_host, sort_host_length);
- else
- value= hashkit->continuum_hash_fn(sort_host, sort_host_length);
-
- hashkit->continuum[continuum_index].index= count;
- hashkit->continuum[continuum_index++].value= value;
- }
- else
- {
- unsigned int i;
- for (i = 0; i < points_per_hash; i++)
- {
- value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
- hashkit->continuum[continuum_index].index= count;
- hashkit->continuum[continuum_index++].value= value;
- }
- }
- }
-
- points_count+= points_per_server;
- }
-
- hashkit->continuum_points_count= points_count;
- qsort(hashkit->continuum, hashkit->continuum_points_count, sizeof(hashkit_continuum_point_st),
- continuum_points_cmp);
-
- return 0;
-}
-#endif
--- /dev/null
+/* HashKit
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+#include <math.h>
+
+#if 0
+static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment)
+{
+ unsigned char results[16];
+
+ md5_signature((unsigned char*)key, key_length, results);
+ return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
+ | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
+ | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
+ | (results[0 + alignment * 4] & 0xFF);
+}
+
+static int continuum_points_cmp(const void *t1, const void *t2)
+{
+ hashkit_continuum_point_st *ct1= (hashkit_continuum_point_st *)t1;
+ hashkit_continuum_point_st *ct2= (hashkit_continuum_point_st *)t2;
+
+ if (ct1->value == ct2->value)
+ return 0;
+ else if (ct1->value > ct2->value)
+ return 1;
+ else
+ return -1;
+}
+
+int update_continuum(hashkit_st *hashkit)
+{
+ uint32_t count;
+ uint32_t continuum_index= 0;
+ uint32_t value;
+ uint32_t points_index;
+ uint32_t points_count= 0;
+ uint32_t points_per_server;
+ uint32_t points_per_hash;
+ uint64_t total_weight= 0;
+ uint32_t live_servers;
+ uint8_t *context;
+
+ if (hashkit->active_fn != NULL || hashkit->weight_fn != NULL)
+ {
+ live_servers= 0;
+
+ for (count= 0, context= hashkit->list; count < hashkit->list_size;
+ count++, context+= hashkit->context_size)
+ {
+ if (hashkit->active_fn != NULL)
+ {
+ if (hashkit->active_fn(context))
+ live_servers++;
+ else
+ continue;
+ }
+
+ if (hashkit->weight_fn != NULL)
+ total_weight+= hashkit->weight_fn(context);
+ }
+ }
+
+ if (hashkit->active_fn == NULL)
+ live_servers= (uint32_t)hashkit->list_size;
+
+ if (live_servers == 0)
+ return 0;
+
+ if (hashkit->weight_fn == NULL)
+ {
+ points_per_server= HASHKIT_POINTS_PER_NODE;
+ points_per_hash= 1;
+ }
+ else
+ {
+ points_per_server= HASHKIT_POINTS_PER_NODE_WEIGHTED;
+ points_per_hash= 4;
+ }
+
+ if (live_servers > hashkit->continuum_count)
+ {
+ hashkit_continuum_point_st *new_continuum;
+
+ new_continuum= realloc(hashkit->continuum,
+ sizeof(hashkit_continuum_point_st) *
+ (live_servers + HASHKIT_CONTINUUM_ADDITION) *
+ points_per_server);
+
+ if (new_continuum == NULL)
+ return ENOMEM;
+
+ hashkit->continuum= new_continuum;
+ hashkit->continuum_count= live_servers + HASHKIT_CONTINUUM_ADDITION;
+ }
+
+ for (count= 0, context= hashkit->list; count < hashkit->list_size;
+ count++, context+= hashkit->context_size)
+ {
+ if (hashkit->active_fn != NULL && hashkit->active_fn(context) == false)
+ continue;
+
+ if (hashkit->weight_fn != NULL)
+ {
+ float pct = (float)hashkit->weight_fn(context) / (float)total_weight;
+ points_per_server= (uint32_t) ((floorf((float) (pct * HASHKIT_POINTS_PER_NODE_WEIGHTED / 4 * (float)live_servers + 0.0000000001))) * 4);
+ }
+
+ for (points_index= 0;
+ points_index < points_per_server / points_per_hash;
+ points_index++)
+ {
+ char sort_host[HASHKIT_CONTINUUM_KEY_SIZE]= "";
+ size_t sort_host_length;
+
+ if (hashkit->continuum_key_fn == NULL)
+ {
+ sort_host_length= (size_t) snprintf(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, "%u",
+ points_index);
+ }
+ else
+ {
+ sort_host_length= hashkit->continuum_key_fn(sort_host, HASHKIT_CONTINUUM_KEY_SIZE,
+ points_index, context);
+ }
+
+ if (hashkit->weight_fn == NULL)
+ {
+ if (hashkit->continuum_hash_fn == NULL)
+ value= hashkit_default(sort_host, sort_host_length);
+ else
+ value= hashkit->continuum_hash_fn(sort_host, sort_host_length);
+
+ hashkit->continuum[continuum_index].index= count;
+ hashkit->continuum[continuum_index++].value= value;
+ }
+ else
+ {
+ unsigned int i;
+ for (i = 0; i < points_per_hash; i++)
+ {
+ value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
+ hashkit->continuum[continuum_index].index= count;
+ hashkit->continuum[continuum_index++].value= value;
+ }
+ }
+ }
+
+ points_count+= points_per_server;
+ }
+
+ hashkit->continuum_points_count= points_count;
+ qsort(hashkit->continuum, hashkit->continuum_points_count, sizeof(hashkit_continuum_point_st),
+ continuum_points_cmp);
+
+ return 0;
+}
+#endif
+++ /dev/null
-/*
- This Library has been modified from its original form by
- Brian Aker (brian@tangent.org)
-
- See below for original Copyright.
-*/
-/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
- */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
-*/
-
-#include <libhashkit/common.h>
-
-#include <string.h>
-#include <sys/types.h>
-
-/* POINTER defines a generic pointer type */
-typedef unsigned char *POINTER;
-
-
-/* UINT4 defines a four byte word */
-typedef unsigned int UINT4;
-
-
-/* MD5 context. */
-typedef struct {
- UINT4 state[4]; /* state (ABCD) */
- UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
- unsigned char buffer[64]; /* input buffer */
-} MD5_CTX;
-
-static void MD5Init (MD5_CTX *context); /* context */
-static void MD5Update ( MD5_CTX *context, /* context */
- const unsigned char *input, /* input block */
- unsigned int inputLen); /* length of input block */
-static void MD5Final ( unsigned char digest[16], /* message digest */
- MD5_CTX *context); /* context */
-
-/* Constants for MD5Transform routine. */
-
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-
-
-static void MD5Transform (UINT4 state[4],
- unsigned char block[64]);
-static void Encode (unsigned char *output,
- UINT4 *input,
- unsigned int len);
-static void Decode(UINT4 *output, unsigned char *input, unsigned int len);
-
-static unsigned char PADDING[64] = {
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G, H and I are basic MD5 functions.
- */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE_LEFT rotates x left n bits.
- */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-Rotation is separate from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-
-
-/*
- Just a simple method for getting the signature
- result must be == 16
-*/
-void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result)
-{
- MD5_CTX my_md5;
-
- MD5Init(&my_md5);
- (void)MD5Update(&my_md5, key, length);
- MD5Final(result, &my_md5);
-}
-
-/* MD5 initialization. Begins an MD5 operation, writing a new context.
- */
-static void MD5Init (MD5_CTX *context) /* context */
-{
- context->count[0] = context->count[1] = 0;
- /* Load magic initialization constants.
-*/
- context->state[0] = 0x67452301;
- context->state[1] = 0xefcdab89;
- context->state[2] = 0x98badcfe;
- context->state[3] = 0x10325476;
-}
-
-/* MD5 block update operation. Continues an MD5 message-digest
- operation, processing another message block, and updating the
- context.
- */
-
-static void MD5Update (
- MD5_CTX *context, /* context */
- const unsigned char *input, /* input block */
- unsigned int inputLen) /* length of input block */
-{
- unsigned int i, idx, partLen;
-
- /* Compute number of bytes mod 64 */
- idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
-
-
- /* Update number of bits */
- if ((context->count[0] += ((UINT4)inputLen << 3))
- < ((UINT4)inputLen << 3))
- context->count[1]++;
- context->count[1] += ((UINT4)inputLen >> 29);
-
- partLen = 64 - idx;
-
- /* Transform as many times as possible.
-*/
- if (inputLen >= partLen) {
- memcpy((POINTER)&context->buffer[idx], (POINTER)input, partLen);
- MD5Transform(context->state, context->buffer);
-
- for (i = partLen; i + 63 < inputLen; i += 64)
- MD5Transform (context->state, (unsigned char *)&input[i]);
-
- idx = 0;
- }
- else
- i = 0;
-
- /* Buffer remaining input */
- memcpy((POINTER)&context->buffer[idx], (POINTER)&input[i],
- inputLen-i);
-}
-
-/* MD5 finalization. Ends an MD5 message-digest operation, writing the
- the message digest and zeroizing the context.
- */
-
-static void MD5Final (
- unsigned char digest[16], /* message digest */
- MD5_CTX *context) /* context */
-{
- unsigned char bits[8];
- unsigned int idx, padLen;
-
- /* Save number of bits */
- Encode (bits, context->count, 8);
-
- /* Pad out to 56 mod 64.
-*/
- idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
- padLen = (idx < 56) ? (56 - idx) : (120 - idx);
- MD5Update (context, PADDING, padLen);
-
- /* Append length (before padding) */
- MD5Update (context, bits, 8);
-
- /* Store state in digest */
- Encode (digest, context->state, 16);
-
- /* Zeroize sensitive information.
-*/
- memset((POINTER)context, 0, sizeof (*context));
-}
-
-/* MD5 basic transformation. Transforms state based on block.
- */
-static void MD5Transform (
- UINT4 state[4],
- unsigned char block[64])
-{
- UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
-
- Decode (x, block, 64);
-
- /* Round 1 */
- FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
- FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
- FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
- FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
- FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
- FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
- FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
- FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
- FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
- FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
- FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
- FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
- FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
- FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
- FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
- FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
- /* Round 2 */
- GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
- GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
- GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
- GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
- GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
- GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
- GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
- GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
- GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
- GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
- GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
- GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
- GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
- GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
- GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
- GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
- /* Round 3 */
- HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
- HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
- HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
- HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
- HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
- HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
- HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
- HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
- HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
- HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
- HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
- HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
- HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
- HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
- HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
- HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
-
- /* Round 4 */
- II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
- II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
- II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
- II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
- II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
- II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
- II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
- II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
- II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
- II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
- II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
- II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
- II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
- II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
- II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
- II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
-
-
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
-
- /* Zeroize sensitive information.
-*/
- memset((POINTER)x, 0, sizeof (x));
-}
-
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is
- a multiple of 4.
- */
-static void Encode (
-unsigned char *output,
-UINT4 *input,
-unsigned int len)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
- }
-}
-
-
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is
- a multiple of 4.
- */
-static void Decode (
-UINT4 *output,
-unsigned char *input,
-unsigned int len)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4)
- output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
- (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
-}
-
-uint32_t hashkit_md5(const char *key, size_t key_length, void *context)
-{
- unsigned char results[16];
- (void)context;
-
- md5_signature((unsigned char*)key, (unsigned int)key_length, results);
-
- return ((uint32_t) (results[3] & 0xFF) << 24)
- | ((uint32_t) (results[2] & 0xFF) << 16)
- | ((uint32_t) (results[1] & 0xFF) << 8)
- | (results[0] & 0xFF);
-}
--- /dev/null
+/*
+ This Library has been modified from its original form by
+ Brian Aker (brian@tangent.org)
+
+ See below for original Copyright.
+*/
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+#include <libhashkit/common.h>
+
+#include <string.h>
+#include <sys/types.h>
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+typedef const unsigned char *CONST_POINTER;
+
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4;
+
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+static void MD5Init (MD5_CTX *context); /* context */
+static void MD5Update ( MD5_CTX *context, /* context */
+ const unsigned char *input, /* input block */
+ unsigned int inputLen); /* length of input block */
+static void MD5Final ( unsigned char digest[16], /* message digest */
+ MD5_CTX *context); /* context */
+
+/* Constants for MD5Transform routine. */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+
+static void MD5Transform (UINT4 state[4],
+ const unsigned char block[64]);
+static void Encode (unsigned char *output,
+ UINT4 *input,
+ unsigned int len);
+static void Decode(UINT4 *output, const unsigned char *input, unsigned int len);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+
+/*
+ Just a simple method for getting the signature
+ result must be == 16
+*/
+void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result)
+{
+ MD5_CTX my_md5;
+
+ MD5Init(&my_md5);
+ (void)MD5Update(&my_md5, key, length);
+ MD5Final(result, &my_md5);
+}
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+static void MD5Init (MD5_CTX *context) /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+
+static void MD5Update (
+ MD5_CTX *context, /* context */
+ const unsigned char *input, /* input block */
+ unsigned int inputLen) /* length of input block */
+{
+ unsigned int i, idx, partLen;
+
+ /* Compute number of bytes mod 64 */
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - idx;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, (CONST_POINTER)&input[i]);
+
+ idx = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+
+static void MD5Final (
+ unsigned char digest[16], /* message digest */
+ MD5_CTX *context) /* context */
+{
+ unsigned char bits[8];
+ unsigned int idx, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ memset((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (
+ UINT4 state[4],
+ const unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ memset((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (
+unsigned char *output,
+UINT4 *input,
+unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (
+ UINT4 *output,
+ const unsigned char *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+uint32_t hashkit_md5(const char *key, size_t key_length, void *context)
+{
+ unsigned char results[16];
+ (void)context;
+
+ md5_signature((unsigned char*)key, (unsigned int)key_length, results);
+
+ return ((uint32_t) (results[3] & 0xFF) << 24)
+ | ((uint32_t) (results[2] & 0xFF) << 16)
+ | ((uint32_t) (results[1] & 0xFF) << 8)
+ | (results[0] & 0xFF);
+}
+++ /dev/null
-/*
- "Murmur" hash provided by Austin, tanjent@gmail.com
- http://murmurhash.googlepages.com/
-
- Note - This code makes a few assumptions about how your machine behaves -
-
- 1. We can read a 4-byte value from any address without crashing
- 2. sizeof(int) == 4
-
- And it has a few limitations -
- 1. It will not work incrementally.
- 2. It will not produce the same results on little-endian and big-endian
- machines.
-
- Updated to murmur2 hash - BP
-*/
-
-#include <libhashkit/common.h>
-
-uint32_t hashkit_murmur(const char *key, size_t length, void *context)
-{
- /*
- 'm' and 'r' are mixing constants generated offline. They're not
- really 'magic', they just happen to work well.
- */
-
- const unsigned int m= 0x5bd1e995;
- const uint32_t seed= (0xdeadbeef * (uint32_t)length);
- const int r= 24;
-
-
- // Initialize the hash to a 'random' value
-
- uint32_t h= seed ^ (uint32_t)length;
-
- // Mix 4 bytes at a time into the hash
-
- const unsigned char * data= (const unsigned char *)key;
- (void)context;
-
- while(length >= 4)
- {
- unsigned int k = *(unsigned int *)data;
-
- k *= m;
- k ^= k >> r;
- k *= m;
-
- h *= m;
- h ^= k;
-
- data += 4;
- length -= 4;
- }
-
- // Handle the last few bytes of the input array
-
- switch(length)
- {
- case 3: h ^= ((uint32_t)data[2]) << 16;
- case 2: h ^= ((uint32_t)data[1]) << 8;
- case 1: h ^= data[0];
- h *= m;
- default: break;
- };
-
- /*
- Do a few final mixes of the hash to ensure the last few bytes are
- well-incorporated.
- */
-
- h ^= h >> 13;
- h *= m;
- h ^= h >> 15;
-
- return h;
-}
--- /dev/null
+/*
+ "Murmur" hash provided by Austin, tanjent@gmail.com
+ http://murmurhash.googlepages.com/
+
+ Note - This code makes a few assumptions about how your machine behaves -
+
+ 1. We can read a 4-byte value from any address without crashing
+ 2. sizeof(int) == 4
+
+ And it has a few limitations -
+ 1. It will not work incrementally.
+ 2. It will not produce the same results on little-endian and big-endian
+ machines.
+
+ Updated to murmur2 hash - BP
+*/
+
+#include <libhashkit/common.h>
+
+uint32_t hashkit_murmur(const char *key, size_t length, void *context)
+{
+ /*
+ 'm' and 'r' are mixing constants generated offline. They're not
+ really 'magic', they just happen to work well.
+ */
+
+ const unsigned int m= 0x5bd1e995;
+ const uint32_t seed= (0xdeadbeef * (uint32_t)length);
+ const int r= 24;
+
+
+ // Initialize the hash to a 'random' value
+
+ uint32_t h= seed ^ (uint32_t)length;
+
+ // Mix 4 bytes at a time into the hash
+
+ const unsigned char * data= (const unsigned char *)key;
+ (void)context;
+
+ while(length >= 4)
+ {
+ unsigned int k = *(unsigned int *)data;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ length -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+
+ switch(length)
+ {
+ case 3: h ^= ((uint32_t)data[2]) << 16;
+ case 2: h ^= ((uint32_t)data[1]) << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ default: break;
+ };
+
+ /*
+ Do a few final mixes of the hash to ensure the last few bytes are
+ well-incorporated.
+ */
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+++ /dev/null
-/* HashKit
- * Copyright (C) 2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-/*
- This has is Jenkin's "One at A time Hash".
-http://en.wikipedia.org/wiki/Jenkins_hash_function
-*/
-
-#include <libhashkit/common.h>
-
-uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context)
-{
- const char *ptr= key;
- uint32_t value= 0;
- (void)context;
-
- while (key_length--)
- {
- uint32_t val= (uint32_t) *ptr++;
- value += val;
- value += (value << 10);
- value ^= (value >> 6);
- }
- value += (value << 3);
- value ^= (value >> 11);
- value += (value << 15);
-
- return value;
-}
--- /dev/null
+/* HashKit
+ * Copyright (C) 2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+/*
+ This has is Jenkin's "One at A time Hash".
+http://en.wikipedia.org/wiki/Jenkins_hash_function
+*/
+
+#include <libhashkit/common.h>
+
+uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context)
+{
+ const char *ptr= key;
+ uint32_t value= 0;
+ (void)context;
+
+ while (key_length--)
+ {
+ uint32_t val= (uint32_t) *ptr++;
+ value += val;
+ value += (value << 10);
+ value ^= (value >> 6);
+ }
+ value += (value << 3);
+ value ^= (value >> 11);
+ value += (value << 15);
+
+ return value;
+}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * HashKit
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libhashkit/common.h>
-
-const char * libhashkit_string_hash(hashkit_hash_algorithm_t type)
-{
- switch(type)
- {
- case HASHKIT_HASH_DEFAULT: return "DEFAULT";
- case HASHKIT_HASH_MD5: return "MD5";
- case HASHKIT_HASH_CRC: return "CRC";
- case HASHKIT_HASH_FNV1_64: return "FNV1_64";
- case HASHKIT_HASH_FNV1A_64: return "FNV1A_64";
- case HASHKIT_HASH_FNV1_32: return "FNV1_32";
- case HASHKIT_HASH_FNV1A_32: return "FNV1A_32";
- case HASHKIT_HASH_HSIEH: return "HSIEH";
- case HASHKIT_HASH_MURMUR: return "MURMUR";
- case HASHKIT_HASH_JENKINS: return "JENKINS";
- case HASHKIT_HASH_CUSTOM: return "CUSTOM";
- default:
- case HASHKIT_HASH_MAX: return "INVALID";
- }
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * HashKit
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libhashkit/common.h>
+
+const char * libhashkit_string_hash(hashkit_hash_algorithm_t type)
+{
+ switch(type)
+ {
+ case HASHKIT_HASH_DEFAULT: return "DEFAULT";
+ case HASHKIT_HASH_MD5: return "MD5";
+ case HASHKIT_HASH_CRC: return "CRC";
+ case HASHKIT_HASH_FNV1_64: return "FNV1_64";
+ case HASHKIT_HASH_FNV1A_64: return "FNV1A_64";
+ case HASHKIT_HASH_FNV1_32: return "FNV1_32";
+ case HASHKIT_HASH_FNV1A_32: return "FNV1A_32";
+ case HASHKIT_HASH_HSIEH: return "HSIEH";
+ case HASHKIT_HASH_MURMUR: return "MURMUR";
+ case HASHKIT_HASH_JENKINS: return "JENKINS";
+ case HASHKIT_HASH_CUSTOM: return "CUSTOM";
+ default:
+ case HASHKIT_HASH_MAX: return "INVALID";
+ }
+}
+++ /dev/null
-/* HashKit
- * Copyright (C) 2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc)
-{
- (void)ptr;
- switch (rc)
- {
- case HASHKIT_SUCCESS: return "SUCCESS";
- case HASHKIT_FAILURE: return "FAILURE";
- case HASHKIT_MEMORY_ALLOCATION_FAILURE: return "MEMORY ALLOCATION FAILURE";
- case HASHKIT_INVALID_ARGUMENT: return "INVALID ARGUMENT";
- case HASHKIT_INVALID_HASH: return "INVALID hashkit_hash_algorithm_t";
- case HASHKIT_MAXIMUM_RETURN:
- default:
- return "INVALID hashkit_return_t";
- }
-}
--- /dev/null
+/* HashKit
+ * Copyright (C) 2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc)
+{
+ (void)ptr;
+ switch (rc)
+ {
+ case HASHKIT_SUCCESS: return "SUCCESS";
+ case HASHKIT_FAILURE: return "FAILURE";
+ case HASHKIT_MEMORY_ALLOCATION_FAILURE: return "MEMORY ALLOCATION FAILURE";
+ case HASHKIT_INVALID_ARGUMENT: return "INVALID ARGUMENT";
+ case HASHKIT_INVALID_HASH: return "INVALID hashkit_hash_algorithm_t";
+ case HASHKIT_MAXIMUM_RETURN:
+ default:
+ return "INVALID hashkit_return_t";
+ }
+}
* @brief Visibility control macros
*/
-#ifndef HASHKIT_VISIBILITY_H
-#define HASHKIT_VISIBILITY_H
+#pragma once
/**
*
# define HASHKIT_LOCAL
# endif /* defined(_MSC_VER) */
#endif /* defined(BUILDING_HASHKIT) */
-
-#endif /* HASHKIT_VISIBILITY_H */
+++ /dev/null
-#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;
-}
--- /dev/null
+#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;
+}
-/* 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" {
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__ */
+++ /dev/null
-#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);
-}
--- /dev/null
+#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);
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: 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;
-}
-
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static memcached_return_t 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;
+}
+
-/* 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" {
#ifdef __cplusplus
}
#endif
-
-#endif /* __LIBMEMCACHED_AUTO_H__ */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: Change the behavior of the memcached connection.
- *
- */
-
-#include <libmemcached/common.h>
-#include <libmemcached/virtual_bucket.h>
-
-#include <time.h>
-#include <sys/types.h>
-
-static bool set_flag(uint64_t data)
-{
- // Wordy :)
- return data ? true : false;
-}
-
-/*
- This function is used to modify the behavior of running client.
-
- We quit all connections so we can reset the sockets.
-*/
-
-memcached_return_t memcached_behavior_set(memcached_st *ptr,
- const memcached_behavior_t flag,
- uint64_t data)
-{
- switch (flag)
- {
- case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
- ptr->number_of_replicas= (uint32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
- ptr->io_msg_watermark= (uint32_t) data;
- break;
- case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
- ptr->io_bytes_watermark= (uint32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
- ptr->io_key_prefetch = (uint32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
- ptr->snd_timeout= (int32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
- ptr->rcv_timeout= (int32_t)data;
- break;
-
- case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
- ptr->flags.auto_eject_hosts= set_flag(data);
- case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
- ptr->server_failure_limit= (uint32_t)data;
- break;
-
- case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
- send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
- if (data)
- {
- ptr->flags.verify_key= false;
- }
- ptr->flags.binary_protocol= set_flag(data);
- break;
- case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
- ptr->flags.support_cas= set_flag(data);
- break;
- case MEMCACHED_BEHAVIOR_NO_BLOCK:
- ptr->flags.no_block= set_flag(data);
- send_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
- ptr->flags.buffer_requests= set_flag(data);
- send_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_USE_UDP:
- if (memcached_server_count(ptr))
- {
- return MEMCACHED_FAILURE;
- }
- ptr->flags.use_udp= set_flag(data);
- if (data)
- {
- ptr->flags.no_reply= set_flag(data);
- }
- break;
- case MEMCACHED_BEHAVIOR_TCP_NODELAY:
- ptr->flags.tcp_nodelay= set_flag(data);
- send_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
- ptr->flags.tcp_keepalive= set_flag(data);
- send_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_DISTRIBUTION:
- return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data);
- case MEMCACHED_BEHAVIOR_KETAMA:
- {
- if (data) // Turn on
- return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
-
- return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA);
- }
- case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
- {
- (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
- (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
- ptr->ketama.weighted= set_flag(data);
- /**
- @note We try to keep the same distribution going. This should be deprecated and rewritten.
- */
- return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
- }
- case MEMCACHED_BEHAVIOR_HASH:
- return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data));
- case MEMCACHED_BEHAVIOR_KETAMA_HASH:
- return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data));
-
- case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
- return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED,
- memcached_string_with_size("MEMCACHED_BEHAVIOR_CACHE_LOOKUPS has been deprecated."));
-
- case MEMCACHED_BEHAVIOR_VERIFY_KEY:
- if (ptr->flags.binary_protocol)
- return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
- memcached_string_with_size("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled."));
- ptr->flags.verify_key= set_flag(data);
- break;
- case MEMCACHED_BEHAVIOR_SORT_HOSTS:
- {
- ptr->flags.use_sort_hosts= set_flag(data);
- run_distribution(ptr);
-
- break;
- }
- case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
- ptr->poll_timeout= (int32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
- ptr->connect_timeout= (int32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
- ptr->retry_timeout= (int32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
- ptr->send_size= (int32_t)data;
- send_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
- ptr->recv_size= (int32_t)data;
- send_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
- ptr->tcp_keepidle= (uint32_t)data;
- send_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_USER_DATA:
- return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED,
- memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
- case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
- ptr->flags.hash_with_prefix_key= set_flag(data);
- break;
- case MEMCACHED_BEHAVIOR_NOREPLY:
- ptr->flags.no_reply= set_flag(data);
- break;
- case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
- ptr->flags.auto_eject_hosts= set_flag(data);
- break;
- case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
- srandom((uint32_t) time(NULL));
- ptr->flags.randomize_replica_read= set_flag(data);
- break;
- case MEMCACHED_BEHAVIOR_CORK:
- {
- return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED,
- memcached_string_with_size("MEMCACHED_BEHAVIOR_CORK is now incorporated into the driver by default."));
- }
- break;
- case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
- return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
- memcached_string_with_size("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()"));
- case MEMCACHED_BEHAVIOR_MAX:
- default:
- /* Shouldn't get here */
- WATCHPOINT_ASSERT(0);
- return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
- memcached_string_with_size("Invalid behavior passed to memcached_behavior_set()"));
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-bool _is_auto_eject_host(const memcached_st *ptr)
-{
- return ptr->flags.auto_eject_hosts;
-}
-
-uint64_t memcached_behavior_get(memcached_st *ptr,
- const memcached_behavior_t flag)
-{
- switch (flag)
- {
- case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
- return ptr->number_of_replicas;
- case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
- return ptr->io_msg_watermark;
- case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
- return ptr->io_bytes_watermark;
- case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
- return ptr->io_key_prefetch;
- case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
- return ptr->flags.binary_protocol;
- case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
- return ptr->flags.support_cas;
-
- case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
- return true;
-
- case MEMCACHED_BEHAVIOR_NO_BLOCK:
- return ptr->flags.no_block;
- case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
- return ptr->flags.buffer_requests;
- case MEMCACHED_BEHAVIOR_USE_UDP:
- return ptr->flags.use_udp;
- case MEMCACHED_BEHAVIOR_TCP_NODELAY:
- return ptr->flags.tcp_nodelay;
- case MEMCACHED_BEHAVIOR_VERIFY_KEY:
- return ptr->flags.verify_key;
- case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
- return ptr->ketama.weighted;
- case MEMCACHED_BEHAVIOR_DISTRIBUTION:
- return ptr->distribution;
- case MEMCACHED_BEHAVIOR_KETAMA:
- return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0;
- case MEMCACHED_BEHAVIOR_HASH:
- return hashkit_get_function(&ptr->hashkit);
- case MEMCACHED_BEHAVIOR_KETAMA_HASH:
- return hashkit_get_function(&ptr->distribution_hashkit);
- case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
- case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
- return ptr->server_failure_limit;
- case MEMCACHED_BEHAVIOR_SORT_HOSTS:
- return ptr->flags.use_sort_hosts;
- case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
- return (uint64_t)ptr->poll_timeout;
- case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
- return (uint64_t)ptr->connect_timeout;
- case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
- return (uint64_t)ptr->retry_timeout;
- case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
- return (uint64_t)ptr->snd_timeout;
- case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
- return (uint64_t)ptr->rcv_timeout;
- case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
- return (uint64_t)ptr->tcp_keepidle;
- case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
- {
- int sock_size= 0;
- socklen_t sock_length= sizeof(int);
- memcached_server_write_instance_st instance;
-
- if (ptr->send_size != -1) // If value is -1 then we are using the default
- return (uint64_t) ptr->send_size;
-
- instance= memcached_server_instance_fetch(ptr, 0);
-
- if (instance) // If we have an instance we test, otherwise we just set and pray
- {
- /* REFACTOR */
- /* We just try the first host, and if it is down we return zero */
- if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
- {
- return 0;
- }
-
- if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS)
- {
- return 0;
- }
-
- if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, &sock_size, &sock_length) < 0)
- {
- memcached_set_errno(ptr, errno, NULL);
- return 0; /* Zero means error */
- }
- }
-
- return (uint64_t) sock_size;
- }
- case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
- {
- int sock_size= 0;
- socklen_t sock_length= sizeof(int);
- memcached_server_write_instance_st instance;
-
- if (ptr->recv_size != -1) // If value is -1 then we are using the default
- return (uint64_t) ptr->recv_size;
-
- instance= memcached_server_instance_fetch(ptr, 0);
-
- /**
- @note REFACTOR
- */
- if (instance)
- {
- /* We just try the first host, and if it is down we return zero */
- if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
- {
- return 0;
- }
-
- if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS)
- {
- return 0;
- }
-
- if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, &sock_size, &sock_length) < 0)
- {
- memcached_set_errno(ptr, errno, NULL);
- return 0; /* Zero means error */
- }
-
- }
-
- return (uint64_t) sock_size;
- }
- case MEMCACHED_BEHAVIOR_USER_DATA:
- memcached_set_error_string(ptr, MEMCACHED_DEPRECATED,
- memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
- return 0;
- case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
- return ptr->flags.hash_with_prefix_key;
- case MEMCACHED_BEHAVIOR_NOREPLY:
- return ptr->flags.no_reply;
- case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
- return ptr->flags.auto_eject_hosts;
- case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
- return ptr->flags.randomize_replica_read;
- case MEMCACHED_BEHAVIOR_CORK:
-#ifdef HAVE_MSG_MORE
- return true;
-#else
- return false;
-#endif
- case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
- return ptr->flags.tcp_keepalive;
- case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
- return ptr->configure.filename ? true : false;
- case MEMCACHED_BEHAVIOR_MAX:
- default:
- WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */
- return 0;
- }
-
- /* NOTREACHED */
-}
-
-
-memcached_return_t memcached_behavior_set_distribution(memcached_st *ptr, memcached_server_distribution_t type)
-{
- if (type < MEMCACHED_DISTRIBUTION_CONSISTENT_MAX)
- {
- if (MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED)
- {
- ptr->ketama.weighted= true;
- }
- else
- {
- ptr->ketama.weighted= false;
- }
- ptr->distribution= type;
- run_distribution(ptr);
- return MEMCACHED_SUCCESS;
- }
-
- return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
- memcached_string_with_size("Invalid memcached_server_distribution_t"));
-}
-
-
-memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *ptr)
-{
- return ptr->distribution;
-}
-
-memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type)
-{
- if (hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
- return MEMCACHED_SUCCESS;
-
- return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
- memcached_string_with_size("Invalid memcached_hash_t()"));
-}
-
-memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr)
-{
- return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
-}
-
-memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type)
-{
- if (hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
- return MEMCACHED_SUCCESS;
-
- return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
- memcached_string_with_size("Invalid memcached_hash_t()"));
-}
-
-memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr)
-{
- return (memcached_hash_t)hashkit_get_function(&ptr->distribution_hashkit);
-}
-
-const char *libmemcached_string_behavior(const memcached_behavior_t flag)
-{
- switch (flag)
- {
- case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK";
- case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY";
- case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH";
- case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA";
- case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE";
- case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE";
- case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS";
- case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS";
- case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT";
- case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION";
- case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS";
- case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA";
- case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS";
- case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY";
- case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT";
- case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT";
- case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED";
- case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH";
- case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL";
- case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT";
- case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT";
- case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT";
- case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK";
- case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK";
- case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH";
- case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY";
- case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY";
- case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP";
- case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS";
- case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: return "MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS";
- case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS";
- case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ";
- case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK";
- case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE";
- case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE";
- case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE";
- default:
- case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t";
- }
-}
-
-const char *libmemcached_string_distribution(const memcached_server_distribution_t flag)
-{
- switch (flag)
- {
- case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA";
- case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT";
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA";
- case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM";
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY";
- case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: return "MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED";
- case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: return "MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET";
- default:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t";
- }
-}
-
-memcached_return_t memcached_bucket_set(memcached_st *self,
- const uint32_t *host_map,
- const uint32_t *forward_map,
- const uint32_t buckets,
- const uint32_t replicas)
-{
- memcached_return_t rc;
-
- if (! self)
- return MEMCACHED_INVALID_ARGUMENTS;
-
- if (! host_map)
- return MEMCACHED_INVALID_ARGUMENTS;
-
- memcached_server_distribution_t old;
- old= memcached_behavior_get_distribution(self);
-
- rc =memcached_behavior_set_distribution(self, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET);
- if (rc != MEMCACHED_SUCCESS)
- {
- return rc;
- }
-
- rc= memcached_virtual_bucket_create(self, host_map, forward_map, buckets, replicas);
- if (rc != MEMCACHED_SUCCESS)
- {
- memcached_behavior_set_distribution(self, old);
- }
-
- return rc;
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Change the behavior of the memcached connection.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <libmemcached/virtual_bucket.h>
+
+#include <time.h>
+#include <sys/types.h>
+
+static bool set_flag(uint64_t data)
+{
+ // Wordy :)
+ return data ? true : false;
+}
+
+/*
+ This function is used to modify the behavior of running client.
+
+ We quit all connections so we can reset the sockets.
+*/
+
+memcached_return_t memcached_behavior_set(memcached_st *ptr,
+ const memcached_behavior_t flag,
+ uint64_t data)
+{
+ switch (flag)
+ {
+ case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
+ ptr->number_of_replicas= (uint32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
+ ptr->io_msg_watermark= (uint32_t) data;
+ break;
+ case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
+ ptr->io_bytes_watermark= (uint32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
+ ptr->io_key_prefetch = (uint32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
+ ptr->snd_timeout= (int32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
+ ptr->rcv_timeout= (int32_t)data;
+ break;
+
+ case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
+ ptr->flags.auto_eject_hosts= set_flag(data);
+ case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
+ ptr->server_failure_limit= (uint32_t)data;
+ break;
+
+ case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
+ send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
+ if (data)
+ {
+ ptr->flags.verify_key= false;
+ }
+ ptr->flags.binary_protocol= set_flag(data);
+ break;
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+ ptr->flags.support_cas= set_flag(data);
+ break;
+ case MEMCACHED_BEHAVIOR_NO_BLOCK:
+ ptr->flags.no_block= set_flag(data);
+ send_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
+ ptr->flags.buffer_requests= set_flag(data);
+ send_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_USE_UDP:
+ if (memcached_server_count(ptr))
+ {
+ return MEMCACHED_FAILURE;
+ }
+ ptr->flags.use_udp= set_flag(data);
+ if (data)
+ {
+ ptr->flags.no_reply= set_flag(data);
+ }
+ break;
+ case MEMCACHED_BEHAVIOR_TCP_NODELAY:
+ ptr->flags.tcp_nodelay= set_flag(data);
+ send_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
+ ptr->flags.tcp_keepalive= set_flag(data);
+ send_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_DISTRIBUTION:
+ return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data);
+ case MEMCACHED_BEHAVIOR_KETAMA:
+ {
+ if (data) // Turn on
+ return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
+
+ return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA);
+ }
+ case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
+ {
+ (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
+ (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
+ ptr->ketama.weighted= set_flag(data);
+ /**
+ @note We try to keep the same distribution going. This should be deprecated and rewritten.
+ */
+ return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
+ }
+ case MEMCACHED_BEHAVIOR_HASH:
+ return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data));
+ case MEMCACHED_BEHAVIOR_KETAMA_HASH:
+ return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data));
+
+ case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
+ return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_CACHE_LOOKUPS has been deprecated."));
+
+ case MEMCACHED_BEHAVIOR_VERIFY_KEY:
+ if (ptr->flags.binary_protocol)
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled."));
+ ptr->flags.verify_key= set_flag(data);
+ break;
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+ {
+ ptr->flags.use_sort_hosts= set_flag(data);
+ run_distribution(ptr);
+
+ break;
+ }
+ case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
+ ptr->poll_timeout= (int32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
+ ptr->connect_timeout= (int32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
+ ptr->retry_timeout= (int32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
+ ptr->send_size= (int32_t)data;
+ send_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
+ ptr->recv_size= (int32_t)data;
+ send_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
+ ptr->tcp_keepidle= (uint32_t)data;
+ send_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_USER_DATA:
+ return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
+ case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
+ ptr->flags.hash_with_prefix_key= set_flag(data);
+ break;
+ case MEMCACHED_BEHAVIOR_NOREPLY:
+ ptr->flags.no_reply= set_flag(data);
+ break;
+ case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
+ ptr->flags.auto_eject_hosts= set_flag(data);
+ break;
+ case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
+ srandom((uint32_t) time(NULL));
+ ptr->flags.randomize_replica_read= set_flag(data);
+ break;
+ case MEMCACHED_BEHAVIOR_CORK:
+ {
+ return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_CORK is now incorporated into the driver by default."));
+ }
+ break;
+ case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()"));
+ case MEMCACHED_BEHAVIOR_MAX:
+ default:
+ /* Shouldn't get here */
+ WATCHPOINT_ASSERT(0);
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("Invalid behavior passed to memcached_behavior_set()"));
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+bool _is_auto_eject_host(const memcached_st *ptr)
+{
+ return ptr->flags.auto_eject_hosts;
+}
+
+uint64_t memcached_behavior_get(memcached_st *ptr,
+ const memcached_behavior_t flag)
+{
+ switch (flag)
+ {
+ case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
+ return ptr->number_of_replicas;
+ case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
+ return ptr->io_msg_watermark;
+ case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
+ return ptr->io_bytes_watermark;
+ case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
+ return ptr->io_key_prefetch;
+ case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
+ return ptr->flags.binary_protocol;
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+ return ptr->flags.support_cas;
+
+ case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
+ return true;
+
+ case MEMCACHED_BEHAVIOR_NO_BLOCK:
+ return ptr->flags.no_block;
+ case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
+ return ptr->flags.buffer_requests;
+ case MEMCACHED_BEHAVIOR_USE_UDP:
+ return ptr->flags.use_udp;
+ case MEMCACHED_BEHAVIOR_TCP_NODELAY:
+ return ptr->flags.tcp_nodelay;
+ case MEMCACHED_BEHAVIOR_VERIFY_KEY:
+ return ptr->flags.verify_key;
+ case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
+ return ptr->ketama.weighted;
+ case MEMCACHED_BEHAVIOR_DISTRIBUTION:
+ return ptr->distribution;
+ case MEMCACHED_BEHAVIOR_KETAMA:
+ return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0;
+ case MEMCACHED_BEHAVIOR_HASH:
+ return hashkit_get_function(&ptr->hashkit);
+ case MEMCACHED_BEHAVIOR_KETAMA_HASH:
+ return hashkit_get_function(&ptr->distribution_hashkit);
+ case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
+ case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
+ return ptr->server_failure_limit;
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+ return ptr->flags.use_sort_hosts;
+ case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
+ return (uint64_t)ptr->poll_timeout;
+ case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
+ return (uint64_t)ptr->connect_timeout;
+ case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
+ return (uint64_t)ptr->retry_timeout;
+ case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
+ return (uint64_t)ptr->snd_timeout;
+ case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
+ return (uint64_t)ptr->rcv_timeout;
+ case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
+ return (uint64_t)ptr->tcp_keepidle;
+ case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
+ {
+ int sock_size= 0;
+ socklen_t sock_length= sizeof(int);
+ memcached_server_write_instance_st instance;
+
+ if (ptr->send_size != -1) // If value is -1 then we are using the default
+ return (uint64_t) ptr->send_size;
+
+ instance= memcached_server_instance_fetch(ptr, 0);
+
+ if (instance) // If we have an instance we test, otherwise we just set and pray
+ {
+ /* REFACTOR */
+ /* We just try the first host, and if it is down we return zero */
+ if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
+ {
+ return 0;
+ }
+
+ if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS)
+ {
+ return 0;
+ }
+
+ if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, &sock_size, &sock_length) < 0)
+ {
+ memcached_set_errno(ptr, errno, NULL);
+ return 0; /* Zero means error */
+ }
+ }
+
+ return (uint64_t) sock_size;
+ }
+ case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
+ {
+ int sock_size= 0;
+ socklen_t sock_length= sizeof(int);
+ memcached_server_write_instance_st instance;
+
+ if (ptr->recv_size != -1) // If value is -1 then we are using the default
+ return (uint64_t) ptr->recv_size;
+
+ instance= memcached_server_instance_fetch(ptr, 0);
+
+ /**
+ @note REFACTOR
+ */
+ if (instance)
+ {
+ /* We just try the first host, and if it is down we return zero */
+ if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
+ {
+ return 0;
+ }
+
+ if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS)
+ {
+ return 0;
+ }
+
+ if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, &sock_size, &sock_length) < 0)
+ {
+ memcached_set_errno(ptr, errno, NULL);
+ return 0; /* Zero means error */
+ }
+
+ }
+
+ return (uint64_t) sock_size;
+ }
+ case MEMCACHED_BEHAVIOR_USER_DATA:
+ memcached_set_error_string(ptr, MEMCACHED_DEPRECATED,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
+ return 0;
+ case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
+ return ptr->flags.hash_with_prefix_key;
+ case MEMCACHED_BEHAVIOR_NOREPLY:
+ return ptr->flags.no_reply;
+ case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
+ return ptr->flags.auto_eject_hosts;
+ case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
+ return ptr->flags.randomize_replica_read;
+ case MEMCACHED_BEHAVIOR_CORK:
+#ifdef HAVE_MSG_MORE
+ return true;
+#else
+ return false;
+#endif
+ case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
+ return ptr->flags.tcp_keepalive;
+ case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
+ return ptr->configure.filename ? true : false;
+ case MEMCACHED_BEHAVIOR_MAX:
+ default:
+ WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */
+ return 0;
+ }
+
+ /* NOTREACHED */
+}
+
+
+memcached_return_t memcached_behavior_set_distribution(memcached_st *ptr, memcached_server_distribution_t type)
+{
+ if (type < MEMCACHED_DISTRIBUTION_CONSISTENT_MAX)
+ {
+ if (MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED)
+ {
+ ptr->ketama.weighted= true;
+ }
+ else
+ {
+ ptr->ketama.weighted= false;
+ }
+ ptr->distribution= type;
+ run_distribution(ptr);
+ return MEMCACHED_SUCCESS;
+ }
+
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("Invalid memcached_server_distribution_t"));
+}
+
+
+memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *ptr)
+{
+ return ptr->distribution;
+}
+
+memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type)
+{
+ if (hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
+ return MEMCACHED_SUCCESS;
+
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("Invalid memcached_hash_t()"));
+}
+
+memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr)
+{
+ return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
+}
+
+memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type)
+{
+ if (hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
+ return MEMCACHED_SUCCESS;
+
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("Invalid memcached_hash_t()"));
+}
+
+memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr)
+{
+ return (memcached_hash_t)hashkit_get_function(&ptr->distribution_hashkit);
+}
+
+const char *libmemcached_string_behavior(const memcached_behavior_t flag)
+{
+ switch (flag)
+ {
+ case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK";
+ case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY";
+ case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH";
+ case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA";
+ case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE";
+ case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE";
+ case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS";
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS";
+ case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION";
+ case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS";
+ case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA";
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS";
+ case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY";
+ case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED";
+ case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH";
+ case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL";
+ case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT";
+ case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK";
+ case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK";
+ case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH";
+ case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY";
+ case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY";
+ case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP";
+ case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS";
+ case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: return "MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS";
+ case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS";
+ case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ";
+ case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK";
+ case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE";
+ case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE";
+ case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE";
+ default:
+ case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t";
+ }
+}
+
+const char *libmemcached_string_distribution(const memcached_server_distribution_t flag)
+{
+ switch (flag)
+ {
+ case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA";
+ case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: return "MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED";
+ case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: return "MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET";
+ default:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t";
+ }
+}
+
+memcached_return_t memcached_bucket_set(memcached_st *self,
+ const uint32_t *host_map,
+ const uint32_t *forward_map,
+ const uint32_t buckets,
+ const uint32_t replicas)
+{
+ memcached_return_t rc;
+
+ if (! self)
+ return MEMCACHED_INVALID_ARGUMENTS;
+
+ if (! host_map)
+ return MEMCACHED_INVALID_ARGUMENTS;
+
+ memcached_server_distribution_t old;
+ old= memcached_behavior_get_distribution(self);
+
+ rc =memcached_behavior_set_distribution(self, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ return rc;
+ }
+
+ rc= memcached_virtual_bucket_create(self, host_map, forward_map, buckets, replicas);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ memcached_behavior_set_distribution(self, old);
+ }
+
+ return rc;
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-#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);
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+/* 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);
+}
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
*
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
*
- * Summary:
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-#ifndef __LIBMEMCACHED_BYTEORDER_H__
-#define __LIBMEMCACHED_BYTEORDER_H__
-
-#include "config.h"
+#pragma once
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
-
-/* Define this here, which will turn on the visibilty controls while we're
- * building libmemcached.
- */
-#define BUILDING_LIBMEMCACHED 1
-
-#include "libmemcached/memcached.h"
-
#ifndef HAVE_HTONLL
#define ntohll(a) memcached_ntohll(a)
#define htonll(a) memcached_htonll(a)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
LIBMEMCACHED_LOCAL
uint64_t memcached_ntohll(uint64_t);
LIBMEMCACHED_LOCAL
uint64_t memcached_htonll(uint64_t);
+#ifdef __cplusplus
+}
+#endif
+
#endif
#ifdef linux
#undef htons
#undef htonl
#endif
-
-#endif /*__LIBMEMCACHED_BYTEORDER_H__ */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: Change any of the possible callbacks.
- *
- */
-
-#include "libmemcached/common.h"
-#include <sys/types.h>
-
-/*
- 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;
- }
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Change any of the possible callbacks.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <sys/types.h>
+
+#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;
+ }
+}
*
*/
+#pragma once
#ifndef __LIBMEMCACHED_CALLBACK_H__
#define __LIBMEMCACHED_CALLBACK_H__
# endif
#endif
-/* Define this here, which will turn on the visibilty controls while we're
- * building libmemcached.
- */
-#define BUILDING_LIBMEMCACHED 1
-
#include <libmemcached/memcached.h>
#include <libmemcached/watchpoint.h>
#include <libmemcached/is.h>
-#include <libmemcached/prefix_key.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
typedef struct memcached_server_st * memcached_server_write_instance_st;
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 */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: Server IO, Not public!
- *
- */
-
-#include <libmemcached/common.h>
-#include <assert.h>
-#include <sys/time.h>
-#include <time.h>
-
-static memcached_return_t connect_poll(memcached_server_st *ptr)
-{
- struct pollfd fds[1];
- fds[0].fd = ptr->fd;
- fds[0].events = POLLOUT;
-
- int error;
- size_t loop_max= 5;
-
- while (--loop_max) // Should only loop on cases of ERESTART or EINTR
- {
- error= poll(fds, 1, ptr->root->connect_timeout);
-
- switch (error)
- {
- case 1:
- {
- int err;
- socklen_t len= sizeof (err);
- (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-
- // We check the value to see what happened wth the socket.
- if (err == 0)
- {
- return MEMCACHED_SUCCESS;
- }
- else
- {
- ptr->cached_errno= errno;
-
- return MEMCACHED_ERRNO;
- }
- }
- case 0:
- return MEMCACHED_TIMEOUT;
- default: // A real error occurred and we need to completely bail
- WATCHPOINT_ERRNO(get_socket_errno());
- switch (get_socket_errno())
- {
-#ifdef TARGET_OS_LINUX
- case ERESTART:
-#endif
- case EINTR:
- continue;
- default:
- if (fds[0].revents & POLLERR)
- {
- int err;
- socklen_t len= sizeof (err);
- (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
- ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
- }
- else
- {
- ptr->cached_errno= get_socket_errno();
- }
-
- (void)closesocket(ptr->fd);
- ptr->fd= INVALID_SOCKET;
-
- return MEMCACHED_ERRNO;
- }
- }
- }
-
- // This should only be possible from ERESTART or EINTR;
- ptr->cached_errno= get_socket_errno();
-
- return MEMCACHED_ERRNO;
-}
-
-static memcached_return_t set_hostinfo(memcached_server_st *server)
-{
- struct addrinfo hints;
- char str_port[NI_MAXSERV];
-
- assert(! server->address_info); // We cover the case where a programming mistake has been made.
- if (server->address_info)
- {
- freeaddrinfo(server->address_info);
- server->address_info= NULL;
- server->address_info_next= NULL;
- }
-
- int length= snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port);
- if (length >= NI_MAXSERV || length < 0)
- return MEMCACHED_FAILURE;
-
- memset(&hints, 0, sizeof(hints));
-
-#if 0
- hints.ai_family= AF_INET;
-#endif
- if (server->type == MEMCACHED_CONNECTION_UDP)
- {
- hints.ai_protocol= IPPROTO_UDP;
- hints.ai_socktype= SOCK_DGRAM;
- }
- else
- {
- hints.ai_socktype= SOCK_STREAM;
- hints.ai_protocol= IPPROTO_TCP;
- }
-
- uint32_t counter= 5;
- while (--counter)
- {
- int e= getaddrinfo(server->hostname, str_port, &hints, &server->address_info);
-
- if (e == 0)
- {
- break;
- }
- else if (e == EAI_AGAIN)
- {
-#ifndef WIN32
- struct timespec dream, rem;
-
- dream.tv_nsec= 1000;
- dream.tv_sec= 0;
-
- nanosleep(&dream, &rem);
-#endif
- continue;
- }
- else
- {
- WATCHPOINT_STRING(server->hostname);
- WATCHPOINT_STRING(gai_strerror(e));
- return MEMCACHED_HOST_LOOKUP_FAILURE;
- }
- }
-
- server->address_info_next= server->address_info;
-
- return MEMCACHED_SUCCESS;
-}
-
-static inline memcached_return_t set_socket_nonblocking(memcached_server_st *ptr)
-{
-#ifdef WIN32
- u_long arg = 1;
- if (ioctlsocket(ptr->fd, FIONBIO, &arg) == SOCKET_ERROR)
- {
- ptr->cached_errno= get_socket_errno();
- return MEMCACHED_CONNECTION_FAILURE;
- }
-#else
- int flags;
-
- do
- {
- flags= fcntl(ptr->fd, F_GETFL, 0);
- }
- while (flags == -1 && (errno == EINTR || errno == EAGAIN));
-
- unlikely (flags == -1)
- {
- ptr->cached_errno= errno;
- return MEMCACHED_CONNECTION_FAILURE;
- }
- else if ((flags & O_NONBLOCK) == 0)
- {
- int rval;
-
- do
- {
- rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
- }
- while (rval == -1 && (errno == EINTR || errno == EAGAIN));
-
- unlikely (rval == -1)
- {
- ptr->cached_errno= errno;
- return MEMCACHED_CONNECTION_FAILURE;
- }
- }
-#endif
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t set_socket_options(memcached_server_st *ptr)
-{
- WATCHPOINT_ASSERT(ptr->fd != -1);
-
- if (ptr->type == MEMCACHED_CONNECTION_UDP)
- return MEMCACHED_SUCCESS;
-
-#ifdef HAVE_SNDTIMEO
- if (ptr->root->snd_timeout)
- {
- int error;
- struct timeval waittime;
-
- waittime.tv_sec= 0;
- waittime.tv_usec= ptr->root->snd_timeout;
-
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO,
- &waittime, (socklen_t)sizeof(struct timeval));
- WATCHPOINT_ASSERT(error == 0);
- if (error)
- return MEMCACHED_FAILURE;
- }
-#endif
-
-#ifdef HAVE_RCVTIMEO
- if (ptr->root->rcv_timeout)
- {
- int error;
- struct timeval waittime;
-
- waittime.tv_sec= 0;
- waittime.tv_usec= ptr->root->rcv_timeout;
-
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO,
- &waittime, (socklen_t)sizeof(struct timeval));
- WATCHPOINT_ASSERT(error == 0);
- if (error)
- return MEMCACHED_FAILURE;
- }
-#endif
-
-
-#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
- {
- int set = 1;
- int error= setsockopt(ptr->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
-
- // This is not considered a fatal error
- if (error == -1)
- {
- WATCHPOINT_ERRNO(get_socket_errno());
- perror("setsockopt(SO_NOSIGPIPE)");
- }
- }
-#endif
-
- if (ptr->root->flags.no_block)
- {
- int error;
- struct linger linger;
-
- linger.l_onoff= 1;
- linger.l_linger= 0; /* By default on close() just drop the socket */
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER,
- &linger, (socklen_t)sizeof(struct linger));
- WATCHPOINT_ASSERT(error == 0);
- if (error)
- return MEMCACHED_FAILURE;
- }
-
- if (ptr->root->flags.tcp_nodelay)
- {
- int flag= 1;
- int error;
-
- error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY,
- &flag, (socklen_t)sizeof(int));
- WATCHPOINT_ASSERT(error == 0);
- if (error)
- return MEMCACHED_FAILURE;
- }
-
- if (ptr->root->flags.tcp_keepalive)
- {
- int flag= 1;
- int error;
-
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_KEEPALIVE,
- &flag, (socklen_t)sizeof(int));
- WATCHPOINT_ASSERT(error == 0);
- if (error)
- return MEMCACHED_FAILURE;
- }
-
-#ifdef TCP_KEEPIDLE
- if (ptr->root->tcp_keepidle > 0)
- {
- int error;
-
- error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_KEEPIDLE,
- &ptr->root->tcp_keepidle, (socklen_t)sizeof(int));
- WATCHPOINT_ASSERT(error == 0);
- if (error)
- return MEMCACHED_FAILURE;
- }
-#endif
-
- if (ptr->root->send_size > 0)
- {
- int error;
-
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
- &ptr->root->send_size, (socklen_t)sizeof(int));
- WATCHPOINT_ASSERT(error == 0);
- if (error)
- return MEMCACHED_FAILURE;
- }
-
- if (ptr->root->recv_size > 0)
- {
- int error;
-
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF,
- &ptr->root->recv_size, (socklen_t)sizeof(int));
- WATCHPOINT_ASSERT(error == 0);
- if (error)
- return MEMCACHED_FAILURE;
- }
-
-
- /* libmemcached will always use nonblocking IO to avoid write deadlocks */
- return set_socket_nonblocking(ptr);
-}
-
-static memcached_return_t unix_socket_connect(memcached_server_st *ptr)
-{
-#ifndef WIN32
- struct sockaddr_un servAddr;
-
- WATCHPOINT_ASSERT(ptr->fd == -1);
-
- if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
- {
- ptr->cached_errno= errno;
- return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
- }
-
- memset(&servAddr, 0, sizeof (struct sockaddr_un));
- servAddr.sun_family= AF_UNIX;
- strncpy(servAddr.sun_path, ptr->hostname, sizeof(servAddr.sun_path)); /* Copy filename */
-
-test_connect:
- if (connect(ptr->fd,
- (struct sockaddr *)&servAddr,
- sizeof(servAddr)) < 0)
- {
- switch (errno)
- {
- case EINPROGRESS:
- case EALREADY:
- case EINTR:
- goto test_connect;
- case EISCONN: /* We were spinning waiting on connect */
- break;
- default:
- WATCHPOINT_ERRNO(errno);
- ptr->cached_errno= errno;
- return MEMCACHED_ERRNO;
- }
- }
-
- WATCHPOINT_ASSERT(ptr->fd != -1);
-
- return MEMCACHED_SUCCESS;
-#else
- (void)ptr;
- return MEMCACHED_NOT_SUPPORTED;
-#endif
-}
-
-static memcached_return_t network_connect(memcached_server_st *ptr)
-{
- bool timeout_error_occured= false;
-
- WATCHPOINT_ASSERT(ptr->fd == INVALID_SOCKET);
- WATCHPOINT_ASSERT(ptr->cursor_active == 0);
-
- if (! ptr->address_info)
- {
- memcached_return_t rc= set_hostinfo(ptr);
- if (rc != MEMCACHED_SUCCESS)
- return rc;
- }
-
- /* Create the socket */
- while (ptr->address_info_next && ptr->fd == INVALID_SOCKET)
- {
- /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
- if (ptr->type == MEMCACHED_CONNECTION_UDP && ptr->address_info_next->ai_family != AF_INET)
- {
- ptr->address_info_next= ptr->address_info_next->ai_next;
- continue;
- }
-
- if ((ptr->fd= socket(ptr->address_info_next->ai_family,
- ptr->address_info_next->ai_socktype,
- ptr->address_info_next->ai_protocol)) < 0)
- {
- ptr->cached_errno= get_socket_errno();
- WATCHPOINT_ERRNO(get_socket_errno());
- return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
- }
-
- (void)set_socket_options(ptr);
-
- /* connect to server */
- if ((connect(ptr->fd, ptr->address_info_next->ai_addr, ptr->address_info_next->ai_addrlen) != SOCKET_ERROR))
- {
- break; // Success
- }
-
- /* An error occurred */
- ptr->cached_errno= get_socket_errno();
- switch (ptr->cached_errno)
- {
- case EWOULDBLOCK:
- case EINPROGRESS: // nonblocking mode - first return
- case EALREADY: // nonblocking mode - subsequent returns
- {
- memcached_return_t rc;
- rc= connect_poll(ptr);
-
- if (rc == MEMCACHED_TIMEOUT)
- timeout_error_occured= true;
-
- if (rc == MEMCACHED_SUCCESS)
- break;
- }
-
- case EISCONN: // we are connected :-)
- break;
-
- case EINTR: // Special case, we retry ai_addr
- (void)closesocket(ptr->fd);
- ptr->fd= INVALID_SOCKET;
- continue;
-
- default:
- (void)closesocket(ptr->fd);
- ptr->fd= INVALID_SOCKET;
- ptr->address_info_next= ptr->address_info_next->ai_next;
- break;
- }
- }
-
- if (ptr->fd == INVALID_SOCKET)
- {
- WATCHPOINT_STRING("Never got a good file descriptor");
-
- /* Failed to connect. schedule next retry */
- if (ptr->root->retry_timeout)
- {
- struct timeval next_time;
-
- if (gettimeofday(&next_time, NULL) == 0)
- ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
- }
-
- if (timeout_error_occured)
- return MEMCACHED_TIMEOUT;
-
- return MEMCACHED_ERRNO; /* The last error should be from connect() */
- }
-
- return MEMCACHED_SUCCESS; /* The last error should be from connect() */
-}
-
-void set_last_disconnected_host(memcached_server_write_instance_st ptr)
-{
- // const_cast
- memcached_st *root= (memcached_st *)ptr->root;
-
-#if 0
- WATCHPOINT_STRING(ptr->hostname);
- WATCHPOINT_NUMBER(ptr->port);
- WATCHPOINT_ERRNO(ptr->cached_errno);
-#endif
- if (root->last_disconnected_server)
- memcached_server_free(root->last_disconnected_server);
- root->last_disconnected_server= memcached_server_clone(NULL, ptr);
-}
-
-memcached_return_t memcached_connect(memcached_server_write_instance_st ptr)
-{
- memcached_return_t rc= MEMCACHED_NO_SERVERS;
-
- if (ptr->fd != INVALID_SOCKET)
- return MEMCACHED_SUCCESS;
-
- LIBMEMCACHED_MEMCACHED_CONNECT_START();
-
- /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */
- WATCHPOINT_ASSERT(ptr->root);
- if (ptr->root->retry_timeout && ptr->next_retry)
- {
- struct timeval curr_time;
-
- gettimeofday(&curr_time, NULL);
-
- // We should optimize this to remove the allocation if the server was
- // the last server to die
- if (ptr->next_retry > curr_time.tv_sec)
- {
- set_last_disconnected_host(ptr);
-
- return MEMCACHED_SERVER_MARKED_DEAD;
- }
- }
-
- // If we are over the counter failure, we just fail. Reject host only
- // works if you have a set number of failures.
- if (ptr->root->server_failure_limit && ptr->server_failure_counter >= ptr->root->server_failure_limit)
- {
- set_last_disconnected_host(ptr);
-
- // @todo fix this by fixing behavior to no longer make use of
- // memcached_st
- if (_is_auto_eject_host(ptr->root))
- {
- run_distribution((memcached_st *)ptr->root);
- }
-
- return MEMCACHED_SERVER_MARKED_DEAD;
- }
-
- /* We need to clean up the multi startup piece */
- switch (ptr->type)
- {
- case MEMCACHED_CONNECTION_UNKNOWN:
- WATCHPOINT_ASSERT(0);
- rc= MEMCACHED_NOT_SUPPORTED;
- break;
- case MEMCACHED_CONNECTION_UDP:
- case MEMCACHED_CONNECTION_TCP:
- rc= network_connect(ptr);
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
- if (ptr->fd != INVALID_SOCKET && ptr->root->sasl.callbacks)
- {
- rc= memcached_sasl_authenticate_connection(ptr);
- if (rc != MEMCACHED_SUCCESS)
- {
- (void)closesocket(ptr->fd);
- ptr->fd= INVALID_SOCKET;
- }
- }
-#endif
- break;
- case MEMCACHED_CONNECTION_UNIX_SOCKET:
- rc= unix_socket_connect(ptr);
- break;
- case MEMCACHED_CONNECTION_MAX:
- default:
- WATCHPOINT_ASSERT(0);
- }
-
- if (rc == MEMCACHED_SUCCESS)
- {
- ptr->server_failure_counter= 0;
- ptr->next_retry= 0;
- }
- else
- {
- ptr->server_failure_counter++;
-
- set_last_disconnected_host(ptr);
- }
-
- LIBMEMCACHED_MEMCACHED_CONNECT_END();
-
- return rc;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <time.h>
+
+static memcached_return_t connect_poll(memcached_server_st *ptr)
+{
+ struct pollfd fds[1];
+ fds[0].fd = ptr->fd;
+ fds[0].events = POLLOUT;
+
+ int error;
+ size_t loop_max= 5;
+
+ while (--loop_max) // Should only loop on cases of ERESTART or EINTR
+ {
+ error= poll(fds, 1, ptr->root->connect_timeout);
+
+ switch (error)
+ {
+ case 1:
+ {
+ int err;
+ socklen_t len= sizeof (err);
+ (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
+
+ // We check the value to see what happened wth the socket.
+ if (err == 0)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+ else
+ {
+ ptr->cached_errno= errno;
+
+ return MEMCACHED_ERRNO;
+ }
+ }
+ case 0:
+ return MEMCACHED_TIMEOUT;
+ default: // A real error occurred and we need to completely bail
+ WATCHPOINT_ERRNO(get_socket_errno());
+ switch (get_socket_errno())
+ {
+#ifdef TARGET_OS_LINUX
+ case ERESTART:
+#endif
+ case EINTR:
+ continue;
+ default:
+ if (fds[0].revents & POLLERR)
+ {
+ int err;
+ socklen_t len= sizeof (err);
+ (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
+ ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
+ }
+ else
+ {
+ ptr->cached_errno= get_socket_errno();
+ }
+
+ (void)closesocket(ptr->fd);
+ ptr->fd= INVALID_SOCKET;
+
+ return MEMCACHED_ERRNO;
+ }
+ }
+ }
+
+ // This should only be possible from ERESTART or EINTR;
+ ptr->cached_errno= get_socket_errno();
+
+ return MEMCACHED_ERRNO;
+}
+
+static memcached_return_t set_hostinfo(memcached_server_st *server)
+{
+ char str_port[NI_MAXSERV];
+
+ assert(! server->address_info); // We cover the case where a programming mistake has been made.
+ if (server->address_info)
+ {
+ freeaddrinfo(server->address_info);
+ server->address_info= NULL;
+ server->address_info_next= NULL;
+ }
+
+ int length= snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port);
+ if (length >= NI_MAXSERV || length < 0)
+ return MEMCACHED_FAILURE;
+
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+
+#if 0
+ hints.ai_family= AF_INET;
+#endif
+ if (server->type == MEMCACHED_CONNECTION_UDP)
+ {
+ hints.ai_protocol= IPPROTO_UDP;
+ hints.ai_socktype= SOCK_DGRAM;
+ }
+ else
+ {
+ hints.ai_socktype= SOCK_STREAM;
+ hints.ai_protocol= IPPROTO_TCP;
+ }
+
+ uint32_t counter= 5;
+ while (--counter)
+ {
+ int e= getaddrinfo(server->hostname, str_port, &hints, &server->address_info);
+
+ if (e == 0)
+ {
+ break;
+ }
+ else if (e == EAI_AGAIN)
+ {
+#ifndef WIN32
+ struct timespec dream, rem;
+
+ dream.tv_nsec= 1000;
+ dream.tv_sec= 0;
+
+ nanosleep(&dream, &rem);
+#endif
+ continue;
+ }
+ else
+ {
+ WATCHPOINT_STRING(server->hostname);
+ WATCHPOINT_STRING(gai_strerror(e));
+ return MEMCACHED_HOST_LOOKUP_FAILURE;
+ }
+ }
+
+ server->address_info_next= server->address_info;
+
+ return MEMCACHED_SUCCESS;
+}
+
+static inline memcached_return_t set_socket_nonblocking(memcached_server_st *ptr)
+{
+#ifdef WIN32
+ u_long arg = 1;
+ if (ioctlsocket(ptr->fd, FIONBIO, &arg) == SOCKET_ERROR)
+ {
+ ptr->cached_errno= get_socket_errno();
+ return MEMCACHED_CONNECTION_FAILURE;
+ }
+#else
+ int flags;
+
+ do
+ {
+ flags= fcntl(ptr->fd, F_GETFL, 0);
+ }
+ while (flags == -1 && (errno == EINTR || errno == EAGAIN));
+
+ unlikely (flags == -1)
+ {
+ ptr->cached_errno= errno;
+ return MEMCACHED_CONNECTION_FAILURE;
+ }
+ else if ((flags & O_NONBLOCK) == 0)
+ {
+ int rval;
+
+ do
+ {
+ rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
+ }
+ while (rval == -1 && (errno == EINTR || errno == EAGAIN));
+
+ unlikely (rval == -1)
+ {
+ ptr->cached_errno= errno;
+ return MEMCACHED_CONNECTION_FAILURE;
+ }
+ }
+#endif
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t set_socket_options(memcached_server_st *ptr)
+{
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+
+ if (ptr->type == MEMCACHED_CONNECTION_UDP)
+ return MEMCACHED_SUCCESS;
+
+#ifdef HAVE_SNDTIMEO
+ if (ptr->root->snd_timeout)
+ {
+ int error;
+ struct timeval waittime;
+
+ waittime.tv_sec= 0;
+ waittime.tv_usec= ptr->root->snd_timeout;
+
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO,
+ &waittime, (socklen_t)sizeof(struct timeval));
+ WATCHPOINT_ASSERT(error == 0);
+ if (error)
+ return MEMCACHED_FAILURE;
+ }
+#endif
+
+#ifdef HAVE_RCVTIMEO
+ if (ptr->root->rcv_timeout)
+ {
+ int error;
+ struct timeval waittime;
+
+ waittime.tv_sec= 0;
+ waittime.tv_usec= ptr->root->rcv_timeout;
+
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO,
+ &waittime, (socklen_t)sizeof(struct timeval));
+ WATCHPOINT_ASSERT(error == 0);
+ if (error)
+ return MEMCACHED_FAILURE;
+ }
+#endif
+
+
+#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+ {
+ int set = 1;
+ int error= setsockopt(ptr->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
+
+ // This is not considered a fatal error
+ if (error == -1)
+ {
+ WATCHPOINT_ERRNO(get_socket_errno());
+ perror("setsockopt(SO_NOSIGPIPE)");
+ }
+ }
+#endif
+
+ if (ptr->root->flags.no_block)
+ {
+ int error;
+ struct linger linger;
+
+ linger.l_onoff= 1;
+ linger.l_linger= 0; /* By default on close() just drop the socket */
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER,
+ &linger, (socklen_t)sizeof(struct linger));
+ WATCHPOINT_ASSERT(error == 0);
+ if (error)
+ return MEMCACHED_FAILURE;
+ }
+
+ if (ptr->root->flags.tcp_nodelay)
+ {
+ int flag= 1;
+ int error;
+
+ error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY,
+ &flag, (socklen_t)sizeof(int));
+ WATCHPOINT_ASSERT(error == 0);
+ if (error)
+ return MEMCACHED_FAILURE;
+ }
+
+ if (ptr->root->flags.tcp_keepalive)
+ {
+ int flag= 1;
+ int error;
+
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_KEEPALIVE,
+ &flag, (socklen_t)sizeof(int));
+ WATCHPOINT_ASSERT(error == 0);
+ if (error)
+ return MEMCACHED_FAILURE;
+ }
+
+#ifdef TCP_KEEPIDLE
+ if (ptr->root->tcp_keepidle > 0)
+ {
+ int error;
+
+ error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_KEEPIDLE,
+ &ptr->root->tcp_keepidle, (socklen_t)sizeof(int));
+ WATCHPOINT_ASSERT(error == 0);
+ if (error)
+ return MEMCACHED_FAILURE;
+ }
+#endif
+
+ if (ptr->root->send_size > 0)
+ {
+ int error;
+
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
+ &ptr->root->send_size, (socklen_t)sizeof(int));
+ WATCHPOINT_ASSERT(error == 0);
+ if (error)
+ return MEMCACHED_FAILURE;
+ }
+
+ if (ptr->root->recv_size > 0)
+ {
+ int error;
+
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF,
+ &ptr->root->recv_size, (socklen_t)sizeof(int));
+ WATCHPOINT_ASSERT(error == 0);
+ if (error)
+ return MEMCACHED_FAILURE;
+ }
+
+
+ /* libmemcached will always use nonblocking IO to avoid write deadlocks */
+ return set_socket_nonblocking(ptr);
+}
+
+static memcached_return_t unix_socket_connect(memcached_server_st *ptr)
+{
+#ifndef WIN32
+ WATCHPOINT_ASSERT(ptr->fd == -1);
+
+ if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ ptr->cached_errno= errno;
+ return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
+ }
+
+ struct sockaddr_un servAddr;
+
+ memset(&servAddr, 0, sizeof (struct sockaddr_un));
+ servAddr.sun_family= AF_UNIX;
+ strncpy(servAddr.sun_path, ptr->hostname, sizeof(servAddr.sun_path)); /* Copy filename */
+
+test_connect:
+ if (connect(ptr->fd,
+ (struct sockaddr *)&servAddr,
+ sizeof(servAddr)) < 0)
+ {
+ switch (errno)
+ {
+ case EINPROGRESS:
+ case EALREADY:
+ case EINTR:
+ goto test_connect;
+ case EISCONN: /* We were spinning waiting on connect */
+ break;
+ default:
+ WATCHPOINT_ERRNO(errno);
+ ptr->cached_errno= errno;
+ return MEMCACHED_ERRNO;
+ }
+ }
+
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+
+ return MEMCACHED_SUCCESS;
+#else
+ (void)ptr;
+ return MEMCACHED_NOT_SUPPORTED;
+#endif
+}
+
+static memcached_return_t network_connect(memcached_server_st *ptr)
+{
+ bool timeout_error_occured= false;
+
+ WATCHPOINT_ASSERT(ptr->fd == INVALID_SOCKET);
+ WATCHPOINT_ASSERT(ptr->cursor_active == 0);
+
+ if (! ptr->address_info)
+ {
+ memcached_return_t rc= set_hostinfo(ptr);
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+ }
+
+ /* Create the socket */
+ while (ptr->address_info_next && ptr->fd == INVALID_SOCKET)
+ {
+ /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
+ if (ptr->type == MEMCACHED_CONNECTION_UDP && ptr->address_info_next->ai_family != AF_INET)
+ {
+ ptr->address_info_next= ptr->address_info_next->ai_next;
+ continue;
+ }
+
+ if ((ptr->fd= socket(ptr->address_info_next->ai_family,
+ ptr->address_info_next->ai_socktype,
+ ptr->address_info_next->ai_protocol)) < 0)
+ {
+ ptr->cached_errno= get_socket_errno();
+ WATCHPOINT_ERRNO(get_socket_errno());
+ return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
+ }
+
+ (void)set_socket_options(ptr);
+
+ /* connect to server */
+ if ((connect(ptr->fd, ptr->address_info_next->ai_addr, ptr->address_info_next->ai_addrlen) != SOCKET_ERROR))
+ {
+ break; // Success
+ }
+
+ /* An error occurred */
+ ptr->cached_errno= get_socket_errno();
+ switch (ptr->cached_errno)
+ {
+ case EWOULDBLOCK:
+ case EINPROGRESS: // nonblocking mode - first return
+ case EALREADY: // nonblocking mode - subsequent returns
+ {
+ memcached_return_t rc;
+ rc= connect_poll(ptr);
+
+ if (rc == MEMCACHED_TIMEOUT)
+ timeout_error_occured= true;
+
+ if (rc == MEMCACHED_SUCCESS)
+ break;
+ }
+
+ case EISCONN: // we are connected :-)
+ break;
+
+ case EINTR: // Special case, we retry ai_addr
+ (void)closesocket(ptr->fd);
+ ptr->fd= INVALID_SOCKET;
+ continue;
+
+ default:
+ (void)closesocket(ptr->fd);
+ ptr->fd= INVALID_SOCKET;
+ ptr->address_info_next= ptr->address_info_next->ai_next;
+ break;
+ }
+ }
+
+ if (ptr->fd == INVALID_SOCKET)
+ {
+ WATCHPOINT_STRING("Never got a good file descriptor");
+
+ /* Failed to connect. schedule next retry */
+ if (ptr->root->retry_timeout)
+ {
+ struct timeval next_time;
+
+ if (gettimeofday(&next_time, NULL) == 0)
+ ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
+ }
+
+ if (timeout_error_occured)
+ return MEMCACHED_TIMEOUT;
+
+ return MEMCACHED_ERRNO; /* The last error should be from connect() */
+ }
+
+ return MEMCACHED_SUCCESS; /* The last error should be from connect() */
+}
+
+void set_last_disconnected_host(memcached_server_write_instance_st ptr)
+{
+ // const_cast
+ memcached_st *root= (memcached_st *)ptr->root;
+
+#if 0
+ WATCHPOINT_STRING(ptr->hostname);
+ WATCHPOINT_NUMBER(ptr->port);
+ WATCHPOINT_ERRNO(ptr->cached_errno);
+#endif
+ if (root->last_disconnected_server)
+ memcached_server_free(root->last_disconnected_server);
+ root->last_disconnected_server= memcached_server_clone(NULL, ptr);
+}
+
+memcached_return_t memcached_connect(memcached_server_write_instance_st ptr)
+{
+ memcached_return_t rc= MEMCACHED_NO_SERVERS;
+
+ if (ptr->fd != INVALID_SOCKET)
+ return MEMCACHED_SUCCESS;
+
+ LIBMEMCACHED_MEMCACHED_CONNECT_START();
+
+ /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */
+ WATCHPOINT_ASSERT(ptr->root);
+ if (ptr->root->retry_timeout && ptr->next_retry)
+ {
+ struct timeval curr_time;
+
+ gettimeofday(&curr_time, NULL);
+
+ // We should optimize this to remove the allocation if the server was
+ // the last server to die
+ if (ptr->next_retry > curr_time.tv_sec)
+ {
+ set_last_disconnected_host(ptr);
+
+ return MEMCACHED_SERVER_MARKED_DEAD;
+ }
+ }
+
+ // If we are over the counter failure, we just fail. Reject host only
+ // works if you have a set number of failures.
+ if (ptr->root->server_failure_limit && ptr->server_failure_counter >= ptr->root->server_failure_limit)
+ {
+ set_last_disconnected_host(ptr);
+
+ // @todo fix this by fixing behavior to no longer make use of
+ // memcached_st
+ if (_is_auto_eject_host(ptr->root))
+ {
+ run_distribution((memcached_st *)ptr->root);
+ }
+
+ return MEMCACHED_SERVER_MARKED_DEAD;
+ }
+
+ /* We need to clean up the multi startup piece */
+ switch (ptr->type)
+ {
+ case MEMCACHED_CONNECTION_UNKNOWN:
+ WATCHPOINT_ASSERT(0);
+ rc= MEMCACHED_NOT_SUPPORTED;
+ break;
+ case MEMCACHED_CONNECTION_UDP:
+ case MEMCACHED_CONNECTION_TCP:
+ rc= network_connect(ptr);
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+ if (ptr->fd != INVALID_SOCKET && ptr->root->sasl.callbacks)
+ {
+ rc= memcached_sasl_authenticate_connection(ptr);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ (void)closesocket(ptr->fd);
+ ptr->fd= INVALID_SOCKET;
+ }
+ }
+#endif
+ break;
+ case MEMCACHED_CONNECTION_UNIX_SOCKET:
+ rc= unix_socket_connect(ptr);
+ break;
+ case MEMCACHED_CONNECTION_MAX:
+ default:
+ WATCHPOINT_ASSERT(0);
+ }
+
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ ptr->server_failure_counter= 0;
+ ptr->next_retry= 0;
+ }
+ else
+ {
+ ptr->server_failure_counter++;
+
+ set_last_disconnected_host(ptr);
+ }
+
+ LIBMEMCACHED_MEMCACHED_CONNECT_END();
+
+ return rc;
+}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-#include <libmemcached/memcached/protocol_binary.h>
-
-memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
- time_t expiration)
-{
- return memcached_delete_by_key(ptr, key, key_length,
- key, key_length, expiration);
-}
-
-static inline memcached_return_t binary_delete(memcached_st *ptr,
- uint32_t server_key,
- const char *key,
- size_t key_length,
- bool flush);
-
-memcached_return_t memcached_delete_by_key(memcached_st *ptr,
- const char *group_key, size_t group_key_length,
- const char *key, size_t key_length,
- time_t expiration)
-{
- bool to_write;
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- uint32_t server_key;
- memcached_server_write_instance_st instance;
-
- LIBMEMCACHED_MEMCACHED_DELETE_START();
-
- memcached_return_t rc;
- if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS)
- {
- return rc;
- }
-
- rc= memcached_validate_key_length(key_length,
- ptr->flags.binary_protocol);
- unlikely (rc != MEMCACHED_SUCCESS)
- return rc;
-
- unlikely (memcached_server_count(ptr) == 0)
- return MEMCACHED_NO_SERVERS;
-
- server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
- instance= memcached_server_instance_fetch(ptr, server_key);
-
- to_write= (ptr->flags.buffer_requests) ? false : true;
-
- bool no_reply= (ptr->flags.no_reply);
-
- if (ptr->flags.binary_protocol)
- {
- likely (! expiration)
- {
- rc= binary_delete(ptr, server_key, key, key_length, to_write);
- }
- else
- {
- rc= MEMCACHED_INVALID_ARGUMENTS;
- }
- }
- else
- {
- int send_length;
-
- unlikely (expiration)
- {
- if ((instance->major_version == 1 &&
- instance->minor_version > 2) ||
- instance->major_version > 1)
- {
- rc= MEMCACHED_INVALID_ARGUMENTS;
- goto error;
- }
- else
- {
- /* ensure that we are connected, otherwise we might bump the
- * command counter before connection */
- if ((rc= memcached_connect(instance)) != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ERROR(rc);
- return rc;
- }
-
- if (instance->minor_version == 0)
- {
- if (no_reply || ! to_write)
- {
- /* We might get out of sync with the server if we
- * send this command to a server newer than 1.2.x..
- * disable no_reply and buffered mode.
- */
- to_write= true;
- if (no_reply)
- memcached_server_response_increment(instance);
- no_reply= false;
- }
- }
- send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "delete %.*s%.*s %u%s\r\n",
- memcached_print_array(ptr->prefix_key),
- (int) key_length, key,
- (uint32_t)expiration,
- no_reply ? " noreply" :"" );
- }
- }
- else
- {
- send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "delete %.*s%.*s%s\r\n",
- memcached_print_array(ptr->prefix_key),
- (int)key_length, key, no_reply ? " noreply" :"");
- }
-
- if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
- {
- rc= MEMCACHED_WRITE_FAILURE;
- goto error;
- }
-
- if (ptr->flags.use_udp && ! to_write)
- {
- if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
- return MEMCACHED_WRITE_FAILURE;
- if (send_length + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
- memcached_io_write(instance, NULL, 0, true);
- }
-
- rc= memcached_do(instance, buffer, (size_t)send_length, to_write);
- }
-
- if (rc != MEMCACHED_SUCCESS)
- goto error;
-
- if (! to_write)
- {
- rc= MEMCACHED_BUFFERED;
- }
- else if (!no_reply)
- {
- rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
- if (rc == MEMCACHED_DELETED)
- rc= MEMCACHED_SUCCESS;
- }
-
- if (rc == MEMCACHED_SUCCESS && ptr->delete_trigger)
- ptr->delete_trigger(ptr, key, key_length);
-
-error:
- LIBMEMCACHED_MEMCACHED_DELETE_END();
- return rc;
-}
-
-static inline memcached_return_t binary_delete(memcached_st *ptr,
- uint32_t server_key,
- const char *key,
- size_t key_length,
- bool flush)
-{
- memcached_server_write_instance_st instance;
- protocol_binary_request_delete request= {.bytes= {0}};
-
- instance= memcached_server_instance_fetch(ptr, server_key);
-
- request.message.header.request.magic= PROTOCOL_BINARY_REQ;
- if (ptr->flags.no_reply)
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
- else
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
- request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key)));
-
- if (ptr->flags.use_udp && ! flush)
- {
- size_t cmd_size= sizeof(request.bytes) + key_length;
- if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
- return MEMCACHED_WRITE_FAILURE;
- if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
- memcached_io_write(instance, NULL, 0, true);
- }
-
- struct libmemcached_io_vector_st vector[]=
- {
- { .length= sizeof(request.bytes), .buffer= request.bytes},
- { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
- { .length= key_length, .buffer= key },
- };
-
- memcached_return_t rc= MEMCACHED_SUCCESS;
-
- if ((rc= memcached_vdo(instance, vector, 3, flush)) != MEMCACHED_SUCCESS)
- {
- memcached_io_reset(instance);
- rc= (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
- }
-
- unlikely (ptr->number_of_replicas > 0)
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
-
- for (uint32_t x= 0; x < ptr->number_of_replicas; ++x)
- {
- memcached_server_write_instance_st replica;
-
- ++server_key;
- if (server_key == memcached_server_count(ptr))
- server_key= 0;
-
- replica= memcached_server_instance_fetch(ptr, server_key);
-
- if (memcached_vdo(replica, vector, 3, flush) != MEMCACHED_SUCCESS)
- {
- memcached_io_reset(replica);
- }
- else
- {
- memcached_server_response_decrement(replica);
- }
- }
- }
-
- return rc;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <libmemcached/memcached/protocol_binary.h>
+
+memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
+ time_t expiration)
+{
+ return memcached_delete_by_key(ptr, key, key_length,
+ key, key_length, expiration);
+}
+
+static inline memcached_return_t binary_delete(memcached_st *ptr,
+ uint32_t server_key,
+ const char *key,
+ size_t key_length,
+ bool flush);
+
+memcached_return_t memcached_delete_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ time_t expiration)
+{
+ bool to_write;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ uint32_t server_key;
+ memcached_server_write_instance_st instance;
+
+ LIBMEMCACHED_MEMCACHED_DELETE_START();
+
+ memcached_return_t rc;
+ if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS)
+ {
+ return rc;
+ }
+
+ rc= memcached_validate_key_length(key_length,
+ ptr->flags.binary_protocol);
+ unlikely (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ unlikely (memcached_server_count(ptr) == 0)
+ return MEMCACHED_NO_SERVERS;
+
+ server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+ instance= memcached_server_instance_fetch(ptr, server_key);
+
+ to_write= (ptr->flags.buffer_requests) ? false : true;
+
+ bool no_reply= (ptr->flags.no_reply);
+
+ if (ptr->flags.binary_protocol)
+ {
+ likely (! expiration)
+ {
+ rc= binary_delete(ptr, server_key, key, key_length, to_write);
+ }
+ else
+ {
+ rc= MEMCACHED_INVALID_ARGUMENTS;
+ }
+ }
+ else
+ {
+ int send_length;
+
+ unlikely (expiration)
+ {
+ if ((instance->major_version == 1 &&
+ instance->minor_version > 2) ||
+ instance->major_version > 1)
+ {
+ rc= MEMCACHED_INVALID_ARGUMENTS;
+ goto error;
+ }
+ else
+ {
+ /* ensure that we are connected, otherwise we might bump the
+ * command counter before connection */
+ if ((rc= memcached_connect(instance)) != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ERROR(rc);
+ return rc;
+ }
+
+ if (instance->minor_version == 0)
+ {
+ if (no_reply || ! to_write)
+ {
+ /* We might get out of sync with the server if we
+ * send this command to a server newer than 1.2.x..
+ * disable no_reply and buffered mode.
+ */
+ to_write= true;
+ if (no_reply)
+ memcached_server_response_increment(instance);
+ no_reply= false;
+ }
+ }
+ send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "delete %.*s%.*s %u%s\r\n",
+ memcached_print_array(ptr->prefix_key),
+ (int) key_length, key,
+ (uint32_t)expiration,
+ no_reply ? " noreply" :"" );
+ }
+ }
+ else
+ {
+ send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "delete %.*s%.*s%s\r\n",
+ memcached_print_array(ptr->prefix_key),
+ (int)key_length, key, no_reply ? " noreply" :"");
+ }
+
+ if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
+ {
+ rc= MEMCACHED_WRITE_FAILURE;
+ goto error;
+ }
+
+ if (ptr->flags.use_udp && ! to_write)
+ {
+ if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+ return MEMCACHED_WRITE_FAILURE;
+ if (send_length + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+ memcached_io_write(instance, NULL, 0, true);
+ }
+
+ rc= memcached_do(instance, buffer, (size_t)send_length, to_write);
+ }
+
+ if (rc != MEMCACHED_SUCCESS)
+ goto error;
+
+ if (! to_write)
+ {
+ rc= MEMCACHED_BUFFERED;
+ }
+ else if (!no_reply)
+ {
+ rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+ if (rc == MEMCACHED_DELETED)
+ rc= MEMCACHED_SUCCESS;
+ }
+
+ if (rc == MEMCACHED_SUCCESS && ptr->delete_trigger)
+ ptr->delete_trigger(ptr, key, key_length);
+
+error:
+ LIBMEMCACHED_MEMCACHED_DELETE_END();
+ return rc;
+}
+
+static inline memcached_return_t binary_delete(memcached_st *ptr,
+ uint32_t server_key,
+ const char *key,
+ size_t key_length,
+ bool flush)
+{
+ memcached_server_write_instance_st instance;
+ protocol_binary_request_delete request= {};
+
+ instance= memcached_server_instance_fetch(ptr, server_key);
+
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ if (ptr->flags.no_reply)
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
+ }
+ else
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
+ }
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key)));
+
+ if (ptr->flags.use_udp && ! flush)
+ {
+ size_t cmd_size= sizeof(request.bytes) + key_length;
+ if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+ return MEMCACHED_WRITE_FAILURE;
+ if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+ memcached_io_write(instance, NULL, 0, true);
+ }
+
+ struct libmemcached_io_vector_st vector[]=
+ {
+ { sizeof(request.bytes), request.bytes},
+ { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+ { key_length, key },
+ };
+
+ memcached_return_t rc= MEMCACHED_SUCCESS;
+
+ if ((rc= memcached_vdo(instance, vector, 3, flush)) != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(instance);
+ rc= (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
+ }
+
+ unlikely (ptr->number_of_replicas > 0)
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
+
+ for (uint32_t x= 0; x < ptr->number_of_replicas; ++x)
+ {
+ memcached_server_write_instance_st replica;
+
+ ++server_key;
+ if (server_key == memcached_server_count(ptr))
+ server_key= 0;
+
+ replica= memcached_server_instance_fetch(ptr, server_key);
+
+ if (memcached_vdo(replica, vector, 3, flush) != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(replica);
+ }
+ else
+ {
+ memcached_server_response_decrement(replica);
+ }
+ }
+ }
+
+ return rc;
+}
-/* 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" {
#ifdef __cplusplus
}
#endif
-
-#endif /* __LIBMEMCACHED_DELETE_H__ */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-#include "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;
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+#include "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;
+}
+++ /dev/null
-/*
- 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);
-}
--- /dev/null
+/*
+ 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);
+}
static void _error_free(memcached_error_t *error)
{
- if (! error)
+ if (not error)
return;
_error_free(error->next);
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)
+++ /dev/null
-#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;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static memcached_return_t memcached_flush_binary(memcached_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;
+}
-/* 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" {
#ifdef __cplusplus
}
#endif
-
-#endif /* __LIBMEMCACHED_FLUSH_H__ */
+++ /dev/null
-#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;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+memcached_return_t memcached_flush_buffers(memcached_st *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;
+}
-/* 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" {
#ifdef __cplusplus
}
#endif
-
-#endif /* __LIBMEMCACHED_FLUSH_BUFFERS_H__ */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: 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;
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Get functions for libmemcached
+ *
+ */
+
+#include "common.h"
+
+/*
+ What happens if no servers exist?
+*/
+char *memcached_get(memcached_st *ptr, const char *key,
+ size_t key_length,
+ size_t *value_length,
+ uint32_t *flags,
+ memcached_return_t *error)
+{
+ return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length,
+ flags, error);
+}
+
+static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ bool mget_mode);
+
+char *memcached_get_by_key(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char *key, size_t key_length,
+ size_t *value_length,
+ uint32_t *flags,
+ memcached_return_t *error)
+{
+ char *value;
+ size_t dummy_length;
+ uint32_t dummy_flags;
+ memcached_return_t dummy_error;
+
+ unlikely (ptr->flags.use_udp)
+ {
+ *error= MEMCACHED_NOT_SUPPORTED;
+ return NULL;
+ }
+
+ /* Request the key */
+ *error= memcached_mget_by_key_real(ptr, group_key, group_key_length,
+ (const char * const *)&key,
+ &key_length, 1, false);
+
+ value= memcached_fetch(ptr, NULL, NULL,
+ value_length, flags, error);
+ /* This is for historical reasons */
+ if (*error == MEMCACHED_END)
+ *error= MEMCACHED_NOTFOUND;
+
+ if (value == NULL)
+ {
+ if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND)
+ {
+ memcached_return_t rc;
+
+ memcached_result_reset(&ptr->result);
+ rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result);
+
+ /* On all failure drop to returning NULL */
+ if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
+ {
+ if (rc == MEMCACHED_BUFFERED)
+ {
+ uint64_t latch; /* We use latch to track the state of the original socket */
+ latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
+ if (latch == 0)
+ memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
+
+ rc= memcached_set(ptr, key, key_length,
+ (memcached_result_value(&ptr->result)),
+ (memcached_result_length(&ptr->result)),
+ 0,
+ (memcached_result_flags(&ptr->result)));
+
+ if (rc == MEMCACHED_BUFFERED && latch == 0)
+ memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
+ }
+ else
+ {
+ rc= memcached_set(ptr, key, key_length,
+ (memcached_result_value(&ptr->result)),
+ (memcached_result_length(&ptr->result)),
+ 0,
+ (memcached_result_flags(&ptr->result)));
+ }
+
+ if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
+ {
+ *error= rc;
+ *value_length= memcached_result_length(&ptr->result);
+ *flags= memcached_result_flags(&ptr->result);
+ return memcached_string_c_copy(&ptr->result.value);
+ }
+ }
+ }
+
+ return NULL;
+ }
+
+ (void)memcached_fetch(ptr, NULL, NULL,
+ &dummy_length, &dummy_flags,
+ &dummy_error);
+ WATCHPOINT_ASSERT(dummy_length == 0);
+
+ return value;
+}
+
+memcached_return_t memcached_mget(memcached_st *ptr,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys)
+{
+ return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
+}
+
+static memcached_return_t binary_mget_by_key(memcached_st *ptr,
+ uint32_t master_server_key,
+ bool is_group_key_set,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ bool mget_mode);
+
+static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ bool mget_mode)
+{
+ bool failures_occured_in_sending= false;
+ const char *get_command= "get ";
+ uint8_t get_command_length= 4;
+ unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */
+ bool is_group_key_set= false;
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(ptr)))
+ {
+ return rc;
+ }
+
+ unlikely (ptr->flags.use_udp)
+ return MEMCACHED_NOT_SUPPORTED;
+
+ LIBMEMCACHED_MEMCACHED_MGET_START();
+
+ if (number_of_keys == 0)
+ return MEMCACHED_NOTFOUND;
+
+ if (ptr->flags.verify_key && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
+ {
+ return MEMCACHED_BAD_KEY_PROVIDED;
+ }
+
+ if (group_key && group_key_length)
+ {
+ if (ptr->flags.verify_key and (memcached_key_test((const char * const *)&group_key, &group_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+ return MEMCACHED_BAD_KEY_PROVIDED;
+
+ master_server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+ is_group_key_set= true;
+ }
+
+ /*
+ Here is where we pay for the non-block API. We need to remove any data sitting
+ in the queue before we start our get.
+
+ It might be optimum to bounce the connection if count > some number.
+ */
+ for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ {
+ memcached_server_write_instance_st instance=
+ memcached_server_instance_fetch(ptr, x);
+
+ if (memcached_server_response_count(instance))
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+ if (ptr->flags.no_block)
+ (void)memcached_io_write(instance, NULL, 0, true);
+
+ while(memcached_server_response_count(instance))
+ (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
+ }
+ }
+
+ if (ptr->flags.binary_protocol)
+ {
+ return binary_mget_by_key(ptr, master_server_key, is_group_key_set, keys,
+ key_length, number_of_keys, mget_mode);
+ }
+
+ if (ptr->flags.support_cas)
+ {
+ get_command= "gets ";
+ get_command_length= 5;
+ }
+
+ /*
+ If a server fails we warn about errors and start all over with sending keys
+ to the server.
+ */
+ WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
+ size_t hosts_connected= 0;
+ for (uint32_t x= 0; x < number_of_keys; x++)
+ {
+ memcached_server_write_instance_st instance;
+ uint32_t server_key;
+
+ if (is_group_key_set)
+ {
+ server_key= master_server_key;
+ }
+ else
+ {
+ server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
+ }
+
+ instance= memcached_server_instance_fetch(ptr, server_key);
+
+ struct libmemcached_io_vector_st vector[]=
+ {
+ { get_command_length, get_command },
+ { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+ { key_length[x], keys[x] },
+ { 1, " " }
+ };
+
+
+ if (memcached_server_response_count(instance) == 0)
+ {
+ rc= memcached_connect(instance);
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ continue;
+ }
+ hosts_connected++;
+
+ if ((memcached_io_writev(instance, vector, 4, false)) == -1)
+ {
+ failures_occured_in_sending= true;
+ continue;
+ }
+ WATCHPOINT_ASSERT(instance->cursor_active == 0);
+ memcached_server_response_increment(instance);
+ WATCHPOINT_ASSERT(instance->cursor_active == 1);
+ }
+ else
+ {
+ if ((memcached_io_writev(instance, (vector + 1), 3, false)) == -1)
+ {
+ memcached_server_response_reset(instance);
+ failures_occured_in_sending= true;
+ continue;
+ }
+ }
+ }
+
+ if (hosts_connected == 0)
+ {
+ LIBMEMCACHED_MEMCACHED_MGET_END();
+
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ return MEMCACHED_NO_SERVERS;
+ }
+
+
+ /*
+ Should we muddle on if some servers are dead?
+ */
+ bool success_happened= false;
+ for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ {
+ memcached_server_write_instance_st instance=
+ memcached_server_instance_fetch(ptr, x);
+
+ if (memcached_server_response_count(instance))
+ {
+ /* We need to do something about non-connnected hosts in the future */
+ if ((memcached_io_write(instance, "\r\n", 2, true)) == -1)
+ {
+ failures_occured_in_sending= true;
+ }
+ else
+ {
+ success_happened= true;
+ }
+ }
+ }
+
+ LIBMEMCACHED_MEMCACHED_MGET_END();
+
+ if (failures_occured_in_sending && success_happened)
+ return MEMCACHED_SOME_ERRORS;
+
+ if (success_happened)
+ return MEMCACHED_SUCCESS;
+
+ return MEMCACHED_FAILURE;
+}
+
+memcached_return_t memcached_mget_by_key(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys)
+{
+ return memcached_mget_by_key_real(ptr, group_key, group_key_length, keys,
+ key_length, number_of_keys, true);
+}
+
+memcached_return_t memcached_mget_execute(memcached_st *ptr,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ memcached_execute_fn *callback,
+ void *context,
+ unsigned int number_of_callbacks)
+{
+ return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length,
+ number_of_keys, callback,
+ context, number_of_callbacks);
+}
+
+memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ memcached_execute_fn *callback,
+ void *context,
+ unsigned int number_of_callbacks)
+{
+ if ((ptr->flags.binary_protocol) == 0)
+ return MEMCACHED_NOT_SUPPORTED;
+
+ memcached_return_t rc;
+ memcached_callback_st *original_callbacks= ptr->callbacks;
+ memcached_callback_st cb= {
+ callback,
+ context,
+ number_of_callbacks
+ };
+
+ ptr->callbacks= &cb;
+ rc= memcached_mget_by_key(ptr, group_key, group_key_length, keys,
+ key_length, number_of_keys);
+ ptr->callbacks= original_callbacks;
+ return rc;
+}
+
+static memcached_return_t simple_binary_mget(memcached_st *ptr,
+ uint32_t master_server_key,
+ bool is_group_key_set,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys, bool mget_mode)
+{
+ memcached_return_t rc= MEMCACHED_NOTFOUND;
+
+ bool flush= (number_of_keys == 1);
+
+ /*
+ If a server fails we warn about errors and start all over with sending keys
+ to the server.
+ */
+ for (uint32_t x= 0; x < number_of_keys; ++x)
+ {
+ uint32_t server_key;
+ memcached_server_write_instance_st instance;
+
+ if (is_group_key_set)
+ {
+ server_key= master_server_key;
+ }
+ else
+ {
+ server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
+ }
+
+ instance= memcached_server_instance_fetch(ptr, server_key);
+
+ if (memcached_server_response_count(instance) == 0)
+ {
+ rc= memcached_connect(instance);
+ if (rc != MEMCACHED_SUCCESS)
+ continue;
+ }
+
+ protocol_binary_request_getk request= { }; //= {.bytes= {0}};
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ if (mget_mode)
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ;
+ else
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
+
+ memcached_return_t vk;
+ vk= memcached_validate_key_length(key_length[x],
+ ptr->flags.binary_protocol);
+ unlikely (vk != MEMCACHED_SUCCESS)
+ {
+ if (x > 0)
+ {
+ memcached_io_reset(instance);
+ }
+
+ return vk;
+ }
+
+ request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->prefix_key)));
+
+ struct libmemcached_io_vector_st vector[]=
+ {
+ { sizeof(request.bytes), request.bytes },
+ { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+ { key_length[x], keys[x] }
+ };
+
+ if (memcached_io_writev(instance, vector, 3, flush) == -1)
+ {
+ memcached_server_response_reset(instance);
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+
+ /* We just want one pending response per server */
+ memcached_server_response_reset(instance);
+ memcached_server_response_increment(instance);
+ if ((x > 0 && x == ptr->io_key_prefetch) && memcached_flush_buffers(ptr) != MEMCACHED_SUCCESS)
+ {
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+ }
+
+ if (mget_mode)
+ {
+ /*
+ Send a noop command to flush the buffers
+ */
+ protocol_binary_request_noop request= {}; //= {.bytes= {0}};
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_NOOP;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+ for (uint32_t x= 0; x < memcached_server_count(ptr); ++x)
+ {
+ memcached_server_write_instance_st instance=
+ memcached_server_instance_fetch(ptr, x);
+
+ if (memcached_server_response_count(instance))
+ {
+ if (memcached_io_write(instance, NULL, 0, true) == -1)
+ {
+ memcached_server_response_reset(instance);
+ memcached_io_reset(instance);
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+
+ if (memcached_io_write(instance, request.bytes,
+ sizeof(request.bytes), true) == -1)
+ {
+ memcached_server_response_reset(instance);
+ memcached_io_reset(instance);
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+ }
+ }
+ }
+
+
+ return rc;
+}
+
+static memcached_return_t replication_binary_mget(memcached_st *ptr,
+ uint32_t* hash,
+ bool* dead_servers,
+ const char *const *keys,
+ const size_t *key_length,
+ size_t number_of_keys)
+{
+ memcached_return_t rc= MEMCACHED_NOTFOUND;
+ uint32_t start= 0;
+ uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
+
+ if (randomize_read)
+ start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1);
+
+ /* Loop for each replica */
+ for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica)
+ {
+ bool success= true;
+
+ for (uint32_t x= 0; x < number_of_keys; ++x)
+ {
+ memcached_server_write_instance_st instance;
+
+ if (hash[x] == memcached_server_count(ptr))
+ continue; /* Already successfully sent */
+
+ uint32_t server= hash[x] + replica;
+
+ /* In case of randomized reads */
+ if (randomize_read && ((server + start) <= (hash[x] + ptr->number_of_replicas)))
+ server += start;
+
+ while (server >= memcached_server_count(ptr))
+ server -= memcached_server_count(ptr);
+
+ if (dead_servers[server])
+ continue;
+
+ instance= memcached_server_instance_fetch(ptr, server);
+
+ if (memcached_server_response_count(instance) == 0)
+ {
+ rc= memcached_connect(instance);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(instance);
+ dead_servers[server]= true;
+ success= false;
+ continue;
+ }
+ }
+
+ protocol_binary_request_getk request= {};
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
+ request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t)(key_length[x] + memcached_array_size(ptr->prefix_key)));
+
+ /*
+ * We need to disable buffering to actually know that the request was
+ * successfully sent to the server (so that we should expect a result
+ * back). It would be nice to do this in buffered mode, but then it
+ * would be complex to handle all error situations if we got to send
+ * some of the messages, and then we failed on writing out some others
+ * and we used the callback interface from memcached_mget_execute so
+ * that we might have processed some of the responses etc. For now,
+ * just make sure we work _correctly_
+ */
+ struct libmemcached_io_vector_st vector[]=
+ {
+ { sizeof(request.bytes), request.bytes },
+ { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+ { key_length[x], keys[x] }
+ };
+
+ if (memcached_io_writev(instance, vector, 3, true) == -1)
+ {
+ memcached_io_reset(instance);
+ dead_servers[server]= true;
+ success= false;
+ continue;
+ }
+
+ memcached_server_response_increment(instance);
+ hash[x]= memcached_server_count(ptr);
+ }
+
+ if (success)
+ break;
+ }
+
+ return rc;
+}
+
+static memcached_return_t binary_mget_by_key(memcached_st *ptr,
+ uint32_t master_server_key,
+ bool is_group_key_set,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ bool mget_mode)
+{
+ memcached_return_t rc;
+
+ if (ptr->number_of_replicas == 0)
+ {
+ rc= simple_binary_mget(ptr, master_server_key, is_group_key_set,
+ keys, key_length, number_of_keys, mget_mode);
+ }
+ else
+ {
+ uint32_t* hash;
+ bool* dead_servers;
+
+ hash= static_cast<uint32_t*>(libmemcached_malloc(ptr, sizeof(uint32_t) * number_of_keys));
+ dead_servers= static_cast<bool*>(libmemcached_calloc(ptr, memcached_server_count(ptr), sizeof(bool)));
+
+ if (hash == NULL || dead_servers == NULL)
+ {
+ libmemcached_free(ptr, hash);
+ libmemcached_free(ptr, dead_servers);
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ if (is_group_key_set)
+ {
+ for (size_t x= 0; x < number_of_keys; x++)
+ {
+ hash[x]= master_server_key;
+ }
+ }
+ else
+ {
+ for (size_t x= 0; x < number_of_keys; x++)
+ {
+ hash[x]= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
+ }
+ }
+
+ rc= replication_binary_mget(ptr, hash, dead_servers, keys,
+ key_length, number_of_keys);
+
+ libmemcached_free(ptr, hash);
+ libmemcached_free(ptr, dead_servers);
+
+ return MEMCACHED_SUCCESS;
+ }
+
+ return rc;
+}
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include <libmemcached/common.h>
-#include <libmemcached/virtual_bucket.h>
-
-
-uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm)
-{
- return libhashkit_digest(key, key_length, (hashkit_hash_algorithm_t)hash_algorithm);
-}
-
-static inline uint32_t generate_hash(const memcached_st *ptr, const char *key, size_t key_length)
-{
- return hashkit_digest(&ptr->hashkit, key, key_length);
-}
-
-static uint32_t dispatch_host(const memcached_st *ptr, uint32_t hash)
-{
- switch (ptr->distribution)
- {
- case MEMCACHED_DISTRIBUTION_CONSISTENT:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
- {
- uint32_t num= ptr->ketama.continuum_points_counter;
- WATCHPOINT_ASSERT(ptr->continuum);
-
- hash= hash;
- memcached_continuum_item_st *begin, *end, *left, *right, *middle;
- begin= left= ptr->ketama.continuum;
- end= right= ptr->ketama.continuum + num;
-
- while (left < right)
- {
- middle= left + (right - left) / 2;
- if (middle->value < hash)
- left= middle + 1;
- else
- right= middle;
- }
- if (right == end)
- right= begin;
- return right->index;
- }
- case MEMCACHED_DISTRIBUTION_MODULA:
- return hash % memcached_server_count(ptr);
- case MEMCACHED_DISTRIBUTION_RANDOM:
- return (uint32_t) random() % memcached_server_count(ptr);
- case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
- {
- return memcached_virtual_bucket_get(ptr, hash);
- }
- default:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
- WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
- return hash % memcached_server_count(ptr);
- }
- /* NOTREACHED */
-}
-
-/*
- One version is public and will not modify the distribution hash, the other will.
-*/
-static inline uint32_t _generate_hash_wrapper(const memcached_st *ptr, const char *key, size_t key_length)
-{
- WATCHPOINT_ASSERT(memcached_server_count(ptr));
-
- if (memcached_server_count(ptr) == 1)
- return 0;
-
- if (ptr->flags.hash_with_prefix_key)
- {
- size_t temp_length= memcached_array_size(ptr->prefix_key) + key_length;
- char temp[temp_length];
-
- if (temp_length > MEMCACHED_MAX_KEY -1)
- return 0;
-
- strncpy(temp, memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
- strncpy(temp + memcached_array_size(ptr->prefix_key), key, key_length);
-
- return generate_hash(ptr, temp, temp_length);
- }
- else
- {
- return generate_hash(ptr, key, key_length);
- }
-}
-
-static inline void _regen_for_auto_eject(memcached_st *ptr)
-{
- if (_is_auto_eject_host(ptr) && ptr->ketama.next_distribution_rebuild)
- {
- struct timeval now;
-
- if (gettimeofday(&now, NULL) == 0 &&
- now.tv_sec > ptr->ketama.next_distribution_rebuild)
- {
- run_distribution(ptr);
- }
- }
-}
-
-void memcached_autoeject(memcached_st *ptr)
-{
- _regen_for_auto_eject(ptr);
-}
-
-uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length)
-{
- uint32_t hash= _generate_hash_wrapper(ptr, key, key_length);
-
- _regen_for_auto_eject(ptr);
-
- return dispatch_host(ptr, hash);
-}
-
-uint32_t memcached_generate_hash(const memcached_st *ptr, const char *key, size_t key_length)
-{
- return dispatch_host(ptr, _generate_hash_wrapper(ptr, key, key_length));
-}
-
-const hashkit_st *memcached_get_hashkit(const memcached_st *ptr)
-{
- return &ptr->hashkit;
-}
-
-memcached_return_t memcached_set_hashkit(memcached_st *self, hashkit_st *hashk)
-{
- hashkit_free(&self->hashkit);
- hashkit_clone(&self->hashkit, hashk);
-
- return MEMCACHED_SUCCESS;
-}
-
-const char * libmemcached_string_hash(memcached_hash_t type)
-{
- return libhashkit_string_hash((hashkit_hash_algorithm_t)type);
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+#include <libmemcached/virtual_bucket.h>
+
+
+uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm)
+{
+ return libhashkit_digest(key, key_length, (hashkit_hash_algorithm_t)hash_algorithm);
+}
+
+static inline uint32_t generate_hash(const memcached_st *ptr, const char *key, size_t key_length)
+{
+ return hashkit_digest(&ptr->hashkit, key, key_length);
+}
+
+static uint32_t dispatch_host(const memcached_st *ptr, uint32_t hash)
+{
+ switch (ptr->distribution)
+ {
+ case MEMCACHED_DISTRIBUTION_CONSISTENT:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+ {
+ uint32_t num= ptr->ketama.continuum_points_counter;
+ WATCHPOINT_ASSERT(ptr->continuum);
+
+ hash= hash;
+ memcached_continuum_item_st *begin, *end, *left, *right, *middle;
+ begin= left= ptr->ketama.continuum;
+ end= right= ptr->ketama.continuum + num;
+
+ while (left < right)
+ {
+ middle= left + (right - left) / 2;
+ if (middle->value < hash)
+ left= middle + 1;
+ else
+ right= middle;
+ }
+ if (right == end)
+ right= begin;
+ return right->index;
+ }
+ case MEMCACHED_DISTRIBUTION_MODULA:
+ return hash % memcached_server_count(ptr);
+ case MEMCACHED_DISTRIBUTION_RANDOM:
+ return (uint32_t) random() % memcached_server_count(ptr);
+ case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
+ {
+ return memcached_virtual_bucket_get(ptr, hash);
+ }
+ default:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
+ WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
+ return hash % memcached_server_count(ptr);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ One version is public and will not modify the distribution hash, the other will.
+*/
+static inline uint32_t _generate_hash_wrapper(const memcached_st *ptr, const char *key, size_t key_length)
+{
+ WATCHPOINT_ASSERT(memcached_server_count(ptr));
+
+ if (memcached_server_count(ptr) == 1)
+ return 0;
+
+ if (ptr->flags.hash_with_prefix_key)
+ {
+ size_t temp_length= memcached_array_size(ptr->prefix_key) + key_length;
+ char temp[MEMCACHED_MAX_KEY];
+
+ if (temp_length > MEMCACHED_MAX_KEY -1)
+ return 0;
+
+ strncpy(temp, memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
+ strncpy(temp + memcached_array_size(ptr->prefix_key), key, key_length);
+
+ return generate_hash(ptr, temp, temp_length);
+ }
+ else
+ {
+ return generate_hash(ptr, key, key_length);
+ }
+}
+
+static inline void _regen_for_auto_eject(memcached_st *ptr)
+{
+ if (_is_auto_eject_host(ptr) && ptr->ketama.next_distribution_rebuild)
+ {
+ struct timeval now;
+
+ if (gettimeofday(&now, NULL) == 0 &&
+ now.tv_sec > ptr->ketama.next_distribution_rebuild)
+ {
+ run_distribution(ptr);
+ }
+ }
+}
+
+void memcached_autoeject(memcached_st *ptr)
+{
+ _regen_for_auto_eject(ptr);
+}
+
+uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length)
+{
+ uint32_t hash= _generate_hash_wrapper(ptr, key, key_length);
+
+ _regen_for_auto_eject(ptr);
+
+ return dispatch_host(ptr, hash);
+}
+
+uint32_t memcached_generate_hash(const memcached_st *ptr, const char *key, size_t key_length)
+{
+ return dispatch_host(ptr, _generate_hash_wrapper(ptr, key, key_length));
+}
+
+const hashkit_st *memcached_get_hashkit(const memcached_st *ptr)
+{
+ return &ptr->hashkit;
+}
+
+memcached_return_t memcached_set_hashkit(memcached_st *self, hashkit_st *hashk)
+{
+ hashkit_free(&self->hashkit);
+ hashkit_clone(&self->hashkit, hashk);
+
+ return MEMCACHED_SUCCESS;
+}
+
+const char * libmemcached_string_hash(memcached_hash_t type)
+{
+ return libhashkit_string_hash((hashkit_hash_algorithm_t)type);
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-#include "common.h"
-#include <math.h>
-
-/* Protoypes (static) */
-static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
- in_port_t port,
- uint32_t weight,
- memcached_connection_t type);
-
-static memcached_return_t update_continuum(memcached_st *ptr);
-
-static int compare_servers(const void *p1, const void *p2)
-{
- int return_value;
- memcached_server_instance_st a= (memcached_server_instance_st)p1;
- memcached_server_instance_st b= (memcached_server_instance_st)p2;
-
- return_value= strcmp(a->hostname, b->hostname);
-
- if (return_value == 0)
- {
- return_value= (int) (a->port - b->port);
- }
-
- return return_value;
-}
-
-static void sort_hosts(memcached_st *ptr)
-{
- if (memcached_server_count(ptr))
- {
- memcached_server_write_instance_st instance;
-
- qsort(memcached_server_list(ptr), memcached_server_count(ptr), sizeof(memcached_server_st), compare_servers);
- instance= memcached_server_instance_fetch(ptr, 0);
- instance->number_of_hosts= memcached_server_count(ptr);
- }
-}
-
-
-memcached_return_t run_distribution(memcached_st *ptr)
-{
- if (ptr->flags.use_sort_hosts)
- sort_hosts(ptr);
-
- switch (ptr->distribution)
- {
- case MEMCACHED_DISTRIBUTION_CONSISTENT:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
- return update_continuum(ptr);
- case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
- case MEMCACHED_DISTRIBUTION_MODULA:
- break;
- case MEMCACHED_DISTRIBUTION_RANDOM:
- srandom((uint32_t) time(NULL));
- break;
- case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
- default:
- WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-static uint32_t ketama_server_hash(const char *key, size_t key_length, uint32_t alignment)
-{
- unsigned char results[16];
-
- libhashkit_md5_signature((unsigned char*)key, key_length, results);
-
- return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
- | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
- | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
- | (results[0 + alignment * 4] & 0xFF);
-}
-
-static int continuum_item_cmp(const void *t1, const void *t2)
-{
- memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1;
- memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2;
-
- /* Why 153? Hmmm... */
- WATCHPOINT_ASSERT(ct1->value != 153);
- if (ct1->value == ct2->value)
- return 0;
- else if (ct1->value > ct2->value)
- return 1;
- else
- return -1;
-}
-
-static memcached_return_t update_continuum(memcached_st *ptr)
-{
- uint32_t continuum_index= 0;
- memcached_server_st *list;
- uint32_t pointer_counter= 0;
- uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
- uint32_t pointer_per_hash= 1;
- uint32_t live_servers= 0;
- struct timeval now;
-
- if (gettimeofday(&now, NULL) != 0)
- {
- memcached_set_errno(ptr, errno, NULL);
- return MEMCACHED_ERRNO;
- }
-
- list= memcached_server_list(ptr);
-
- /* count live servers (those without a retry delay set) */
- bool is_auto_ejecting= _is_auto_eject_host(ptr);
- if (is_auto_ejecting)
- {
- live_servers= 0;
- ptr->ketama.next_distribution_rebuild= 0;
- for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
- {
- if (list[host_index].next_retry <= now.tv_sec)
- live_servers++;
- else
- {
- if (ptr->ketama.next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->ketama.next_distribution_rebuild)
- ptr->ketama.next_distribution_rebuild= list[host_index].next_retry;
- }
- }
- }
- else
- {
- live_servers= memcached_server_count(ptr);
- }
-
- uint64_t is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
- uint32_t points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER);
-
- if (live_servers == 0)
- return MEMCACHED_SUCCESS;
-
- if (live_servers > ptr->ketama.continuum_count)
- {
- memcached_continuum_item_st *new_ptr;
-
- new_ptr= libmemcached_realloc(ptr, ptr->ketama.continuum,
- sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);
-
- if (new_ptr == 0)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- ptr->ketama.continuum= new_ptr;
- ptr->ketama.continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
- }
-
- uint64_t total_weight= 0;
- if (is_ketama_weighted)
- {
- for (uint32_t host_index = 0; host_index < memcached_server_count(ptr); ++host_index)
- {
- if (! is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
- {
- total_weight += list[host_index].weight;
- }
- }
- }
-
- for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
- {
- if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec)
- continue;
-
- if (is_ketama_weighted)
- {
- float pct = (float)list[host_index].weight / (float)total_weight;
- pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
- pointer_per_hash= 4;
-#ifdef DEBUG
- printf("ketama_weighted:%s|%d|%llu|%u\n",
- list[host_index].hostname,
- list[host_index].port,
- (unsigned long long)list[host_index].weight,
- pointer_per_server);
-#endif
- }
-
-
- if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY)
- {
- for (uint32_t pointer_index= 0;
- pointer_index < pointer_per_server / pointer_per_hash;
- pointer_index++)
- {
- char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
- int sort_host_length;
-
- // Spymemcached ketema key format is: hostname/ip:port-index
- // If hostname is not available then: /ip:port-index
- sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
- "/%s:%u-%u",
- list[host_index].hostname,
- (uint32_t)list[host_index].port,
- pointer_index);
-
- if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0)
- {
- return MEMCACHED_FAILURE;
- }
-#ifdef DEBUG
- printf("update_continuum: key is %s\n", sort_host);
-#endif
-
- WATCHPOINT_ASSERT(sort_host_length);
-
- if (is_ketama_weighted)
- {
- for (uint32_t x= 0; x < pointer_per_hash; x++)
- {
- uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
- ptr->ketama.continuum[continuum_index].index= host_index;
- ptr->ketama.continuum[continuum_index++].value= value;
- }
- }
- else
- {
- uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length);
- ptr->ketama.continuum[continuum_index].index= host_index;
- ptr->ketama.continuum[continuum_index++].value= value;
- }
- }
- }
- else
- {
- for (uint32_t pointer_index= 1;
- pointer_index <= pointer_per_server / pointer_per_hash;
- pointer_index++)
- {
- char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
- int sort_host_length;
-
- if (list[host_index].port == MEMCACHED_DEFAULT_PORT)
- {
- sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
- "%s-%u",
- list[host_index].hostname,
- pointer_index - 1);
- }
- else
- {
- sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
- "%s:%u-%u",
- list[host_index].hostname,
- (uint32_t)list[host_index].port,
- pointer_index - 1);
- }
-
- if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0)
- {
- return MEMCACHED_FAILURE;
- }
-
- WATCHPOINT_ASSERT(sort_host_length);
-
- if (is_ketama_weighted)
- {
- for (uint32_t x = 0; x < pointer_per_hash; x++)
- {
- uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
- ptr->ketama.continuum[continuum_index].index= host_index;
- ptr->ketama.continuum[continuum_index++].value= value;
- }
- }
- else
- {
- uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length);
- ptr->ketama.continuum[continuum_index].index= host_index;
- ptr->ketama.continuum[continuum_index++].value= value;
- }
- }
- }
-
- pointer_counter+= pointer_per_server;
- }
-
- WATCHPOINT_ASSERT(ptr);
- WATCHPOINT_ASSERT(ptr->continuum);
- WATCHPOINT_ASSERT(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE);
- ptr->ketama.continuum_points_counter= pointer_counter;
- qsort(ptr->ketama.continuum, ptr->ketama.continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
-
-#ifdef DEBUG
- for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
- {
- WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value);
- }
-#endif
-
- return MEMCACHED_SUCCESS;
-}
-
-
-memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list)
-{
- uint32_t count;
- memcached_server_st *new_host_list;
-
- if (! list)
- return MEMCACHED_SUCCESS;
-
- count= memcached_server_list_count(list);
- new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr),
- sizeof(memcached_server_st) * (count + memcached_server_count(ptr)));
-
- if (! new_host_list)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- memcached_server_list_set(ptr, new_host_list);
-
- for (uint32_t x= 0; x < count; x++)
- {
- memcached_server_write_instance_st instance;
-
- if ((ptr->flags.use_udp && list[x].type != MEMCACHED_CONNECTION_UDP)
- || ((list[x].type == MEMCACHED_CONNECTION_UDP)
- && ! (ptr->flags.use_udp)) )
- {
- return MEMCACHED_INVALID_HOST_PROTOCOL;
- }
-
- WATCHPOINT_ASSERT(list[x].hostname[0] != 0);
-
- instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
- WATCHPOINT_ASSERT(instance);
-
- /* TODO check return type */
- instance= memcached_server_create_with(ptr, instance, list[x].hostname,
- list[x].port, list[x].weight, list[x].type);
- if (! instance)
- {
- return memcached_set_error(ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, NULL);
- }
- ptr->number_of_hosts++;
- }
-
- // Provides backwards compatibility with server list.
- {
- memcached_server_write_instance_st instance;
- instance= memcached_server_instance_fetch(ptr, 0);
- instance->number_of_hosts= memcached_server_count(ptr);
- }
-
- return run_distribution(ptr);
-}
-
-memcached_return_t memcached_server_add_unix_socket(memcached_st *ptr,
- const char *filename)
-{
- return memcached_server_add_unix_socket_with_weight(ptr, filename, 0);
-}
-
-memcached_return_t memcached_server_add_unix_socket_with_weight(memcached_st *ptr,
- const char *filename,
- uint32_t weight)
-{
- if (! filename)
- return MEMCACHED_FAILURE;
-
- return server_add(ptr, filename, 0, weight, MEMCACHED_CONNECTION_UNIX_SOCKET);
-}
-
-memcached_return_t memcached_server_add_udp(memcached_st *ptr,
- const char *hostname,
- in_port_t port)
-{
- return memcached_server_add_udp_with_weight(ptr, hostname, port, 0);
-}
-
-memcached_return_t memcached_server_add_udp_with_weight(memcached_st *ptr,
- const char *hostname,
- in_port_t port,
- uint32_t weight)
-{
- if (! port)
- port= MEMCACHED_DEFAULT_PORT;
-
- if (! hostname)
- hostname= "localhost";
-
- return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_UDP);
-}
-
-memcached_return_t memcached_server_add(memcached_st *ptr,
- const char *hostname,
- in_port_t port)
-{
- return memcached_server_add_with_weight(ptr, hostname, port, 0);
-}
-
-memcached_return_t memcached_server_add_with_weight(memcached_st *ptr,
- const char *hostname,
- in_port_t port,
- uint32_t weight)
-{
- if (! port)
- port= MEMCACHED_DEFAULT_PORT;
-
- if (! hostname)
- hostname= "localhost";
-
- return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_TCP);
-}
-
-static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
- in_port_t port,
- uint32_t weight,
- memcached_connection_t type)
-{
- memcached_server_st *new_host_list;
- memcached_server_write_instance_st instance;
-
- if ( (ptr->flags.use_udp && type != MEMCACHED_CONNECTION_UDP)
- || ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) )
- return MEMCACHED_INVALID_HOST_PROTOCOL;
-
- new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr),
- sizeof(memcached_server_st) * (ptr->number_of_hosts + 1));
-
- if (new_host_list == NULL)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- memcached_server_list_set(ptr, new_host_list);
-
- /* TODO: Check return type */
- instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
- (void)memcached_server_create_with(ptr, instance, hostname, port, weight, type);
- ptr->number_of_hosts++;
-
- instance= memcached_server_instance_fetch(ptr, 0);
- memcached_servers_set_count(instance, memcached_server_count(ptr));
-
- return run_distribution(ptr);
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+#include "common.h"
+#include <math.h>
+
+/* Protoypes (static) */
+static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
+ in_port_t port,
+ uint32_t weight,
+ memcached_connection_t type);
+
+static memcached_return_t update_continuum(memcached_st *ptr);
+
+static int compare_servers(const void *p1, const void *p2)
+{
+ int return_value;
+ memcached_server_instance_st a= (memcached_server_instance_st)p1;
+ memcached_server_instance_st b= (memcached_server_instance_st)p2;
+
+ return_value= strcmp(a->hostname, b->hostname);
+
+ if (return_value == 0)
+ {
+ return_value= (int) (a->port - b->port);
+ }
+
+ return return_value;
+}
+
+static void sort_hosts(memcached_st *ptr)
+{
+ if (memcached_server_count(ptr))
+ {
+ memcached_server_write_instance_st instance;
+
+ qsort(memcached_server_list(ptr), memcached_server_count(ptr), sizeof(memcached_server_st), compare_servers);
+ instance= memcached_server_instance_fetch(ptr, 0);
+ instance->number_of_hosts= memcached_server_count(ptr);
+ }
+}
+
+
+memcached_return_t run_distribution(memcached_st *ptr)
+{
+ if (ptr->flags.use_sort_hosts)
+ sort_hosts(ptr);
+
+ switch (ptr->distribution)
+ {
+ case MEMCACHED_DISTRIBUTION_CONSISTENT:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
+ return update_continuum(ptr);
+ case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
+ case MEMCACHED_DISTRIBUTION_MODULA:
+ break;
+ case MEMCACHED_DISTRIBUTION_RANDOM:
+ srandom((uint32_t) time(NULL));
+ break;
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
+ default:
+ WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+static uint32_t ketama_server_hash(const char *key, size_t key_length, uint32_t alignment)
+{
+ unsigned char results[16];
+
+ libhashkit_md5_signature((unsigned char*)key, key_length, results);
+
+ return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
+ | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
+ | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
+ | (results[0 + alignment * 4] & 0xFF);
+}
+
+static int continuum_item_cmp(const void *t1, const void *t2)
+{
+ memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1;
+ memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2;
+
+ /* Why 153? Hmmm... */
+ WATCHPOINT_ASSERT(ct1->value != 153);
+ if (ct1->value == ct2->value)
+ return 0;
+ else if (ct1->value > ct2->value)
+ return 1;
+ else
+ return -1;
+}
+
+static memcached_return_t update_continuum(memcached_st *ptr)
+{
+ uint32_t continuum_index= 0;
+ memcached_server_st *list;
+ uint32_t pointer_counter= 0;
+ uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
+ uint32_t pointer_per_hash= 1;
+ uint32_t live_servers= 0;
+ struct timeval now;
+
+ if (gettimeofday(&now, NULL) != 0)
+ {
+ memcached_set_errno(ptr, errno, NULL);
+ return MEMCACHED_ERRNO;
+ }
+
+ list= memcached_server_list(ptr);
+
+ /* count live servers (those without a retry delay set) */
+ bool is_auto_ejecting= _is_auto_eject_host(ptr);
+ if (is_auto_ejecting)
+ {
+ live_servers= 0;
+ ptr->ketama.next_distribution_rebuild= 0;
+ for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
+ {
+ if (list[host_index].next_retry <= now.tv_sec)
+ live_servers++;
+ else
+ {
+ if (ptr->ketama.next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->ketama.next_distribution_rebuild)
+ ptr->ketama.next_distribution_rebuild= list[host_index].next_retry;
+ }
+ }
+ }
+ else
+ {
+ live_servers= memcached_server_count(ptr);
+ }
+
+ uint64_t is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+ uint32_t points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER);
+
+ if (live_servers == 0)
+ return MEMCACHED_SUCCESS;
+
+ if (live_servers > ptr->ketama.continuum_count)
+ {
+ memcached_continuum_item_st *new_ptr;
+
+ new_ptr= static_cast<memcached_continuum_item_st*>(libmemcached_realloc(ptr, ptr->ketama.continuum,
+ sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server));
+
+ if (new_ptr == 0)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ ptr->ketama.continuum= new_ptr;
+ ptr->ketama.continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
+ }
+
+ uint64_t total_weight= 0;
+ if (is_ketama_weighted)
+ {
+ for (uint32_t host_index = 0; host_index < memcached_server_count(ptr); ++host_index)
+ {
+ if (! is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
+ {
+ total_weight += list[host_index].weight;
+ }
+ }
+ }
+
+ for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
+ {
+ if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec)
+ continue;
+
+ if (is_ketama_weighted)
+ {
+ float pct = (float)list[host_index].weight / (float)total_weight;
+ pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
+ pointer_per_hash= 4;
+#ifdef DEBUG
+ printf("ketama_weighted:%s|%d|%llu|%u\n",
+ list[host_index].hostname,
+ list[host_index].port,
+ (unsigned long long)list[host_index].weight,
+ pointer_per_server);
+#endif
+ }
+
+
+ if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY)
+ {
+ for (uint32_t pointer_index= 0;
+ pointer_index < pointer_per_server / pointer_per_hash;
+ pointer_index++)
+ {
+ char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
+ int sort_host_length;
+
+ // Spymemcached ketema key format is: hostname/ip:port-index
+ // If hostname is not available then: /ip:port-index
+ sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+ "/%s:%u-%u",
+ list[host_index].hostname,
+ (uint32_t)list[host_index].port,
+ pointer_index);
+
+ if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+#ifdef DEBUG
+ printf("update_continuum: key is %s\n", sort_host);
+#endif
+
+ WATCHPOINT_ASSERT(sort_host_length);
+
+ if (is_ketama_weighted)
+ {
+ for (uint32_t x= 0; x < pointer_per_hash; x++)
+ {
+ uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
+ ptr->ketama.continuum[continuum_index].index= host_index;
+ ptr->ketama.continuum[continuum_index++].value= value;
+ }
+ }
+ else
+ {
+ uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length);
+ ptr->ketama.continuum[continuum_index].index= host_index;
+ ptr->ketama.continuum[continuum_index++].value= value;
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t pointer_index= 1;
+ pointer_index <= pointer_per_server / pointer_per_hash;
+ pointer_index++)
+ {
+ char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
+ int sort_host_length;
+
+ if (list[host_index].port == MEMCACHED_DEFAULT_PORT)
+ {
+ sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+ "%s-%u",
+ list[host_index].hostname,
+ pointer_index - 1);
+ }
+ else
+ {
+ sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+ "%s:%u-%u",
+ list[host_index].hostname,
+ (uint32_t)list[host_index].port,
+ pointer_index - 1);
+ }
+
+ if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0)
+ {
+ return MEMCACHED_FAILURE;
+ }
+
+ WATCHPOINT_ASSERT(sort_host_length);
+
+ if (is_ketama_weighted)
+ {
+ for (uint32_t x = 0; x < pointer_per_hash; x++)
+ {
+ uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
+ ptr->ketama.continuum[continuum_index].index= host_index;
+ ptr->ketama.continuum[continuum_index++].value= value;
+ }
+ }
+ else
+ {
+ uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length);
+ ptr->ketama.continuum[continuum_index].index= host_index;
+ ptr->ketama.continuum[continuum_index++].value= value;
+ }
+ }
+ }
+
+ pointer_counter+= pointer_per_server;
+ }
+
+ WATCHPOINT_ASSERT(ptr);
+ WATCHPOINT_ASSERT(ptr->continuum);
+ WATCHPOINT_ASSERT(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE);
+ ptr->ketama.continuum_points_counter= pointer_counter;
+ qsort(ptr->ketama.continuum, ptr->ketama.continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
+
+#ifdef DEBUG
+ for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
+ {
+ WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value);
+ }
+#endif
+
+ return MEMCACHED_SUCCESS;
+}
+
+
+memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list)
+{
+ if (not list)
+ return MEMCACHED_SUCCESS;
+
+ uint32_t count= memcached_server_list_count(list);
+
+ memcached_server_st *new_host_list;
+ new_host_list= static_cast<memcached_server_st*>(libmemcached_realloc(ptr, memcached_server_list(ptr),
+ sizeof(memcached_server_st) * (count + memcached_server_count(ptr))));
+
+ if (not new_host_list)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ memcached_server_list_set(ptr, new_host_list);
+
+ for (uint32_t x= 0; x < count; x++)
+ {
+ memcached_server_write_instance_st instance;
+
+ if ((ptr->flags.use_udp && list[x].type != MEMCACHED_CONNECTION_UDP)
+ || ((list[x].type == MEMCACHED_CONNECTION_UDP)
+ && ! (ptr->flags.use_udp)) )
+ {
+ return MEMCACHED_INVALID_HOST_PROTOCOL;
+ }
+
+ WATCHPOINT_ASSERT(list[x].hostname[0] != 0);
+
+ instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
+ WATCHPOINT_ASSERT(instance);
+
+ /* TODO check return type */
+ instance= memcached_server_create_with(ptr, instance, list[x].hostname,
+ list[x].port, list[x].weight, list[x].type);
+ if (! instance)
+ {
+ return memcached_set_error(ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, NULL);
+ }
+ ptr->number_of_hosts++;
+ }
+
+ // Provides backwards compatibility with server list.
+ {
+ memcached_server_write_instance_st instance;
+ instance= memcached_server_instance_fetch(ptr, 0);
+ instance->number_of_hosts= memcached_server_count(ptr);
+ }
+
+ return run_distribution(ptr);
+}
+
+memcached_return_t memcached_server_add_unix_socket(memcached_st *ptr,
+ const char *filename)
+{
+ return memcached_server_add_unix_socket_with_weight(ptr, filename, 0);
+}
+
+memcached_return_t memcached_server_add_unix_socket_with_weight(memcached_st *ptr,
+ const char *filename,
+ uint32_t weight)
+{
+ if (! filename)
+ return MEMCACHED_FAILURE;
+
+ return server_add(ptr, filename, 0, weight, MEMCACHED_CONNECTION_UNIX_SOCKET);
+}
+
+memcached_return_t memcached_server_add_udp(memcached_st *ptr,
+ const char *hostname,
+ in_port_t port)
+{
+ return memcached_server_add_udp_with_weight(ptr, hostname, port, 0);
+}
+
+memcached_return_t memcached_server_add_udp_with_weight(memcached_st *ptr,
+ const char *hostname,
+ in_port_t port,
+ uint32_t weight)
+{
+ if (! port)
+ port= MEMCACHED_DEFAULT_PORT;
+
+ if (! hostname)
+ hostname= "localhost";
+
+ return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_UDP);
+}
+
+memcached_return_t memcached_server_add(memcached_st *ptr,
+ const char *hostname,
+ in_port_t port)
+{
+ return memcached_server_add_with_weight(ptr, hostname, port, 0);
+}
+
+memcached_return_t memcached_server_add_with_weight(memcached_st *ptr,
+ const char *hostname,
+ in_port_t port,
+ uint32_t weight)
+{
+ if (! port)
+ port= MEMCACHED_DEFAULT_PORT;
+
+ if (! hostname)
+ hostname= "localhost";
+
+ return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_TCP);
+}
+
+static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
+ in_port_t port,
+ uint32_t weight,
+ memcached_connection_t type)
+{
+ memcached_server_st *new_host_list;
+ memcached_server_write_instance_st instance;
+
+ if ( (ptr->flags.use_udp && type != MEMCACHED_CONNECTION_UDP)
+ || ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) )
+ return MEMCACHED_INVALID_HOST_PROTOCOL;
+
+ new_host_list= static_cast<memcached_server_st*>(libmemcached_realloc(ptr, memcached_server_list(ptr),
+ sizeof(memcached_server_st) * (ptr->number_of_hosts + 1)));
+
+ if (new_host_list == NULL)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ memcached_server_list_set(ptr, new_host_list);
+
+ /* TODO: Check return type */
+ instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
+ (void)memcached_server_create_with(ptr, instance, hostname, port, weight, type);
+ ptr->number_of_hosts++;
+
+ instance= memcached_server_instance_fetch(ptr, 0);
+ memcached_servers_set_count(instance, memcached_server_count(ptr));
+
+ return run_distribution(ptr);
+}
libmemcached/visibility.h \
libmemcached/watchpoint.h
-lib_LTLIBRARIES+= libmemcached/libmemcachedprotocol.la
-libmemcached_libmemcachedprotocol_la_SOURCES = \
- libmemcached/protocol/ascii_handler.c \
- libmemcached/protocol/binary_handler.c \
- libmemcached/protocol/cache.c \
- libmemcached/protocol/pedantic.c \
- libmemcached/protocol/protocol_handler.c
-
-libmemcached_libmemcachedprotocol_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION} ${PTHREAD_CFLAGS}
-libmemcached_libmemcachedprotocol_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_PROTOCAL_LIBRARY_VERSION}
-
-noinst_LTLIBRARIES+= \
- libmemcached/libmemcachedcallbacks.la
-
-libmemcached_libmemcachedcallbacks_la_CFLAGS = ${AM_CFLAGS} ${NO_STRICT_ALIASING}
-libmemcached_libmemcachedcallbacks_la_SOURCES = libmemcached/callback.c
-
# This noinst lib contains things we want to be ABI private but still want to
# either use in client programs or be able to test in test cases
# These symbols will not be exposed in the shipped .so
noinst_LTLIBRARIES+= libmemcached/libmemcachedinternal.la
libmemcached_libmemcachedinternal_la_SOURCES= \
libmemcached/error.cc \
- libmemcached/string.c
+ libmemcached/string.cc
lib_LTLIBRARIES+= libmemcached/libmemcached.la
-libmemcached_libmemcached_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION}
+libmemcached_libmemcached_la_CFLAGS= \
+ ${AM_CFLAGS} \
+ ${NO_CONVERSION} \
+ -DBUILDING_LIBMEMCACHED
+
+libmemcached_libmemcached_la_CXXFLAGS= \
+ ${AM_CXXFLAGS} \
+ ${NO_CONVERSION} \
+ -DBUILDING_LIBMEMCACHED
+
libmemcached_libmemcached_la_SOURCES+= \
- libmemcached/allocators.c \
- libmemcached/analyze.c \
+ ${libhashkit_libhashkit_la_SOURCES} \
+ libmemcached/allocators.cc \
+ libmemcached/analyze.cc \
libmemcached/array.c \
- libmemcached/auto.c \
- libmemcached/behavior.c \
- libmemcached/connect.c \
- libmemcached/delete.c \
- libmemcached/do.c \
- libmemcached/dump.c \
+ libmemcached/auto.cc \
+ libmemcached/behavior.cc \
+ libmemcached/byteorder.cc \
+ libmemcached/callback.cc \
+ libmemcached/connect.cc \
+ libmemcached/delete.cc \
+ libmemcached/do.cc \
+ libmemcached/dump.cc \
+ libmemcached/error.cc \
libmemcached/fetch.c \
- libmemcached/flush.c \
- libmemcached/flush_buffers.c \
- libmemcached/get.c \
- libmemcached/hash.c \
- libmemcached/hosts.c \
+ libmemcached/flush.cc \
+ libmemcached/flush_buffers.cc \
+ libmemcached/get.cc \
+ libmemcached/hash.cc \
+ libmemcached/hosts.cc \
libmemcached/initialize_query.cc \
- libmemcached/io.c \
- libmemcached/key.c \
- libmemcached/memcached.c \
+ libmemcached/io.cc \
+ libmemcached/key.cc \
+ libmemcached/memcached.cc \
libmemcached/options.cc \
- libmemcached/parse.c \
+ libmemcached/parse.cc \
libmemcached/prefix_key.cc \
- libmemcached/purge.c \
- libmemcached/quit.c \
- libmemcached/response.c \
- libmemcached/result.c \
- libmemcached/server.c \
- libmemcached/server_list.c \
- libmemcached/stats.c \
- libmemcached/storage.c \
- libmemcached/strerror.c \
- libmemcached/verbosity.c \
- libmemcached/version.c \
+ libmemcached/purge.cc \
+ libmemcached/quit.cc \
+ libmemcached/response.cc \
+ libmemcached/result.cc \
+ libmemcached/server.cc \
+ libmemcached/server_list.cc \
+ libmemcached/stats.cc \
+ libmemcached/storage.cc \
+ libmemcached/strerror.cc \
+ libmemcached/string.cc \
+ libmemcached/verbosity.cc \
+ libmemcached/version.cc \
libmemcached/virtual_bucket.c
libmemcached/options.cc: libmemcached/options/parser.h
-libmemcached_libmemcached_la_DEPENDENCIES= libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la libhashkit/libhashkitinc.la
-libmemcached_libmemcached_la_LIBADD= $(LIBM) libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la libhashkit/libhashkitinc.la
+libmemcached_libmemcached_la_DEPENDENCIES=
+libmemcached_libmemcached_la_LIBADD= $(LIBM)
libmemcached_libmemcached_la_LDFLAGS= ${AM_LDFLAGS} -version-info ${MEMCACHED_LIBRARY_VERSION}
-if BUILD_LIBMEMCACHEDUTIL
-nobase_include_HEADERS+= \
- libmemcached/memcached_util.h \
- libmemcached/util.h \
- libmemcached/util/ping.h \
- libmemcached/util/pool.h \
- libmemcached/util/version.h
-lib_LTLIBRARIES+= libmemcached/libmemcachedutil.la
-endif
-
-libmemcached_libmemcachedutil_la_SOURCES= \
- libmemcached/util/ping.cc \
- libmemcached/util/pool.cc \
- libmemcached/util/version.cc
-libmemcached_libmemcachedutil_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION} ${PTHREAD_CFLAGS}
-libmemcached_libmemcachedutil_la_LIBADD= libmemcached/libmemcached.la
-libmemcached_libmemcachedutil_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_UTIL_LIBRARY_VERSION}
-libmemcached_libmemcachedutil_la_DEPENDENCIES= libmemcached/libmemcached.la
-
-if BUILD_BYTEORDER
-noinst_LTLIBRARIES += libmemcached/libbyteorder.la
-libmemcached_libbyteorder_la_SOURCES= libmemcached/byteorder.c
-libmemcached_libmemcached_la_LIBADD += libmemcached/libbyteorder.la
-libmemcached_libmemcached_la_DEPENDENCIES+= libmemcached/libbyteorder.la
-libmemcached_libmemcachedprotocol_la_LIBADD=libmemcached/libbyteorder.la
-libmemcached_libmemcachedprotocol_la_DEPENDENCIES=libmemcached/libbyteorder.la
-endif
-
if HAVE_SASL
libmemcached_libmemcached_la_LDFLAGS+= $(LTLIBSASL) $(LTLIBSASL2)
libmemcached_libmemcached_la_SOURCES += libmemcached/sasl.c
*/
#include <libmemcached/common.h>
-#include <libmemcached/initialize_query.h>
memcached_return_t initialize_query(memcached_st *self)
{
- if (! self)
+ if (not self)
return MEMCACHED_INVALID_ARGUMENTS;
+ self->query_id++;
+
if (self->state.is_time_for_rebuild)
{
memcached_reset(self);
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)
-/* 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" {
#ifdef __cplusplus
}
#endif
-
-#endif /* BUILDING_LIBMEMCACHED */
-#endif /* __LIBMEMCACHED_INTERNAL_H__ */
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * LibMemcached
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#include "libmemcached/common.h"
-
-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;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include "libmemcached/common.h"
+
+typedef enum {
+ MEM_READ,
+ MEM_WRITE
+} memc_read_or_write;
+
+static ssize_t io_flush(memcached_server_write_instance_st ptr,
+ const bool with_flush,
+ memcached_return_t *error);
+static void increment_udp_message_id(memcached_server_write_instance_st ptr);
+
+static memcached_return_t io_wait(memcached_server_write_instance_st ptr,
+ memc_read_or_write read_or_write)
+{
+ struct pollfd fds;
+ fds.fd= ptr->fd;
+ fds.events= POLLIN;
+
+ int error;
+
+ if (read_or_write == MEM_WRITE) /* write */
+ {
+ fds.events= POLLOUT;
+ WATCHPOINT_SET(ptr->io_wait_count.write++);
+ }
+ else
+ {
+ WATCHPOINT_SET(ptr->io_wait_count.read++);
+ }
+
+ /*
+ ** We are going to block on write, but at least on Solaris we might block
+ ** on write if we haven't read anything from our input buffer..
+ ** Try to purge the input buffer if we don't do any flow control in the
+ ** application layer (just sending a lot of data etc)
+ ** The test is moved down in the purge function to avoid duplication of
+ ** the test.
+ */
+ if (read_or_write == MEM_WRITE)
+ {
+ memcached_return_t rc= memcached_purge(ptr);
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
+ return MEMCACHED_FAILURE;
+ }
+
+ size_t loop_max= 5;
+ while (--loop_max) // While loop is for ERESTART or EINTR
+ {
+ error= poll(&fds, 1, ptr->root->poll_timeout);
+
+ switch (error)
+ {
+ case 1: // Success!
+ WATCHPOINT_IF_LABELED_NUMBER(read_or_write && loop_max < 4, "read() times we had to loop, decremented down from 5", loop_max);
+ WATCHPOINT_IF_LABELED_NUMBER(!read_or_write && loop_max < 4, "write() times we had to loop, decremented down from 5", loop_max);
+
+ return MEMCACHED_SUCCESS;
+ case 0: // Timeout occured, we let the while() loop do its thing.
+ return MEMCACHED_TIMEOUT;
+ default:
+ WATCHPOINT_ERRNO(get_socket_errno());
+ switch (get_socket_errno())
+ {
+#ifdef TARGET_OS_LINUX
+ case ERESTART:
+#endif
+ case EINTR:
+ break;
+ default:
+ if (fds.revents & POLLERR)
+ {
+ int err;
+ socklen_t len= sizeof (err);
+ (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
+ ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
+ }
+ else
+ {
+ ptr->cached_errno= get_socket_errno();
+ }
+ memcached_quit_server(ptr, true);
+
+ return MEMCACHED_FAILURE;
+ }
+ }
+ }
+
+ /* Imposssible for anything other then -1 */
+ WATCHPOINT_ASSERT(error == -1);
+ ptr->cached_errno= get_socket_errno();
+ memcached_quit_server(ptr, true);
+
+ return MEMCACHED_FAILURE;
+}
+
+memcached_return_t memcached_io_wait_for_write(memcached_server_write_instance_st ptr)
+{
+ return io_wait(ptr, MEM_WRITE);
+}
+
+/**
+ * Try to fill the input buffer for a server with as much
+ * data as possible.
+ *
+ * @param ptr the server to pack
+ */
+static bool repack_input_buffer(memcached_server_write_instance_st ptr)
+{
+ if (ptr->read_ptr != ptr->read_buffer)
+ {
+ /* Move all of the data to the beginning of the buffer so
+ ** that we can fit more data into the buffer...
+ */
+ memmove(ptr->read_buffer, ptr->read_ptr, ptr->read_buffer_length);
+ ptr->read_ptr= ptr->read_buffer;
+ ptr->read_data_length= ptr->read_buffer_length;
+ }
+
+ /* There is room in the buffer, try to fill it! */
+ if (ptr->read_buffer_length != MEMCACHED_MAX_BUFFER)
+ {
+ /* Just try a single read to grab what's available */
+ ssize_t nr= recv(ptr->fd,
+ ptr->read_ptr + ptr->read_data_length,
+ MEMCACHED_MAX_BUFFER - ptr->read_data_length,
+ 0);
+
+ if (nr > 0)
+ {
+ ptr->read_data_length+= (size_t)nr;
+ ptr->read_buffer_length+= (size_t)nr;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * If the we have callbacks connected to this server structure
+ * we may start process the input queue and fire the callbacks
+ * for the incomming messages. This function is _only_ called
+ * when the input buffer is full, so that we _know_ that we have
+ * at least _one_ message to process.
+ *
+ * @param ptr the server to star processing iput messages for
+ * @return true if we processed anything, false otherwise
+ */
+static bool process_input_buffer(memcached_server_write_instance_st ptr)
+{
+ /*
+ ** We might be able to process some of the response messages if we
+ ** have a callback set up
+ */
+ if (ptr->root->callbacks != NULL && ptr->root->flags.use_udp == false)
+ {
+ /*
+ * We might have responses... try to read them out and fire
+ * callbacks
+ */
+ memcached_callback_st cb= *ptr->root->callbacks;
+
+ memcached_set_processing_input((memcached_st *)ptr->root, true);
+
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ memcached_return_t error;
+ memcached_st *root= (memcached_st *)ptr->root;
+ error= memcached_response(ptr, buffer, sizeof(buffer),
+ &root->result);
+
+ memcached_set_processing_input(root, false);
+
+ if (error == MEMCACHED_SUCCESS)
+ {
+ for (unsigned int x= 0; x < cb.number_of_callback; x++)
+ {
+ error= (*cb.callback[x])(ptr->root, &root->result, cb.context);
+ if (error != MEMCACHED_SUCCESS)
+ break;
+ }
+
+ /* @todo what should I do with the error message??? */
+ }
+ /* @todo what should I do with other error messages?? */
+ return true;
+ }
+
+ return false;
+}
+
+#if 0 // Dead code, this should be removed.
+void memcached_io_preread(memcached_st *ptr)
+{
+ unsigned int x;
+
+ return;
+
+ for (x= 0; x < memcached_server_count(ptr); x++)
+ {
+ if (memcached_server_response_count(ptr, x) &&
+ ptr->hosts[x].read_data_length < MEMCACHED_MAX_BUFFER )
+ {
+ size_t data_read;
+
+ data_read= recv(ptr->hosts[x].fd,
+ ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length,
+ MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length, 0);
+ if (data_read == SOCKET_ERROR)
+ continue;
+
+ ptr->hosts[x].read_buffer_length+= data_read;
+ ptr->hosts[x].read_data_length+= data_read;
+ }
+ }
+}
+#endif
+
+memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr,
+ void *buffer, size_t length, ssize_t *nread)
+{
+ char *buffer_ptr;
+
+ buffer_ptr= static_cast<char *>(buffer);
+
+ while (length)
+ {
+ if (not ptr->read_buffer_length)
+ {
+ ssize_t data_read;
+
+ while (1)
+ {
+ data_read= recv(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER, 0);
+ if (data_read > 0)
+ {
+ break;
+ }
+ else if (data_read == SOCKET_ERROR)
+ {
+ ptr->cached_errno= get_socket_errno();
+ memcached_return_t rc= MEMCACHED_ERRNO;
+ switch (get_socket_errno())
+ {
+ case EWOULDBLOCK:
+#ifdef USE_EAGAIN
+ case EAGAIN:
+#endif
+ case EINTR:
+#ifdef TARGET_OS_LINUX
+ case ERESTART:
+#endif
+ if ((rc= io_wait(ptr, MEM_READ)) == MEMCACHED_SUCCESS)
+ continue;
+ /* fall through */
+
+ default:
+ {
+ memcached_quit_server(ptr, true);
+ *nread= -1;
+ return rc;
+ }
+ }
+ }
+ else
+ {
+ /*
+ EOF. Any data received so far is incomplete
+ so discard it. This always reads by byte in case of TCP
+ and protocol enforcement happens at memcached_response()
+ looking for '\n'. We do not care for UDB which requests 8 bytes
+ at once. Generally, this means that connection went away. Since
+ for blocking I/O we do not return 0 and for non-blocking case
+ it will return EGAIN if data is not immediatly available.
+ */
+ WATCHPOINT_STRING("We had a zero length recv()");
+ memcached_quit_server(ptr, true);
+ *nread= -1;
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ }
+
+ ptr->io_bytes_sent = 0;
+ ptr->read_data_length= (size_t) data_read;
+ ptr->read_buffer_length= (size_t) data_read;
+ ptr->read_ptr= ptr->read_buffer;
+ }
+
+ if (length > 1)
+ {
+ size_t difference;
+
+ difference= (length > ptr->read_buffer_length) ? ptr->read_buffer_length : length;
+
+ memcpy(buffer_ptr, ptr->read_ptr, difference);
+ length -= difference;
+ ptr->read_ptr+= difference;
+ ptr->read_buffer_length-= difference;
+ buffer_ptr+= difference;
+ }
+ else
+ {
+ *buffer_ptr= *ptr->read_ptr;
+ ptr->read_ptr++;
+ ptr->read_buffer_length--;
+ buffer_ptr++;
+ break;
+ }
+ }
+
+ ptr->server_failure_counter= 0;
+ *nread = (ssize_t)(buffer_ptr - (char*)buffer);
+ return MEMCACHED_SUCCESS;
+}
+
+static ssize_t _io_write(memcached_server_write_instance_st ptr,
+ const void *buffer, size_t length, bool with_flush)
+{
+ size_t original_length;
+ const char* buffer_ptr;
+
+ WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+
+ original_length= length;
+ buffer_ptr= static_cast<const char *>(buffer);
+
+ while (length)
+ {
+ char *write_ptr;
+ size_t should_write;
+ size_t buffer_end;
+
+ if (ptr->type == MEMCACHED_CONNECTION_UDP)
+ {
+ //UDP does not support partial writes
+ buffer_end= MAX_UDP_DATAGRAM_LENGTH;
+ should_write= length;
+ if (ptr->write_buffer_offset + should_write > buffer_end)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ buffer_end= MEMCACHED_MAX_BUFFER;
+ should_write= buffer_end - ptr->write_buffer_offset;
+ should_write= (should_write < length) ? should_write : length;
+ }
+
+ write_ptr= ptr->write_buffer + ptr->write_buffer_offset;
+ memcpy(write_ptr, buffer_ptr, should_write);
+ ptr->write_buffer_offset+= should_write;
+ buffer_ptr+= should_write;
+ length-= should_write;
+
+ if (ptr->write_buffer_offset == buffer_end && ptr->type != MEMCACHED_CONNECTION_UDP)
+ {
+ memcached_return_t rc;
+ ssize_t sent_length;
+
+ WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+ sent_length= io_flush(ptr, with_flush, &rc);
+ if (sent_length == -1)
+ {
+ return -1;
+ }
+
+ /* If io_flush calls memcached_purge, sent_length may be 0 */
+ unlikely (sent_length != 0)
+ {
+ WATCHPOINT_ASSERT(sent_length == (ssize_t)buffer_end);
+ }
+ }
+ }
+
+ if (with_flush)
+ {
+ memcached_return_t rc;
+ WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+ if (io_flush(ptr, with_flush, &rc) == -1)
+ {
+ return -1;
+ }
+ }
+
+ return (ssize_t) original_length;
+}
+
+ssize_t memcached_io_write(memcached_server_write_instance_st ptr,
+ const void *buffer, size_t length, bool with_flush)
+{
+ return _io_write(ptr, buffer, length, with_flush);
+}
+
+ssize_t memcached_io_writev(memcached_server_write_instance_st ptr,
+ const struct libmemcached_io_vector_st *vector,
+ size_t number_of, bool with_flush)
+{
+ ssize_t total= 0;
+
+ for (size_t x= 0; x < number_of; x++, vector++)
+ {
+ ssize_t returnable;
+
+ if ((returnable= _io_write(ptr, vector->buffer, vector->length, false)) == -1)
+ {
+ return -1;
+ }
+ total+= returnable;
+ }
+
+ if (with_flush)
+ {
+ if (memcached_io_write(ptr, NULL, 0, true) == -1)
+ {
+ return -1;
+ }
+ }
+
+ return total;
+}
+
+
+memcached_return_t memcached_io_close(memcached_server_write_instance_st ptr)
+{
+ if (ptr->fd == INVALID_SOCKET)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ /* in case of death shutdown to avoid blocking at close() */
+ if (shutdown(ptr->fd, SHUT_RDWR) == SOCKET_ERROR && get_socket_errno() != ENOTCONN)
+ {
+ WATCHPOINT_NUMBER(ptr->fd);
+ WATCHPOINT_ERRNO(get_socket_errno());
+ WATCHPOINT_ASSERT(get_socket_errno());
+ }
+
+ if (closesocket(ptr->fd) == SOCKET_ERROR)
+ {
+ WATCHPOINT_ERRNO(get_socket_errno());
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st *memc)
+{
+#define MAX_SERVERS_TO_POLL 100
+ struct pollfd fds[MAX_SERVERS_TO_POLL];
+ unsigned int host_index= 0;
+
+ for (uint32_t x= 0;
+ x< memcached_server_count(memc) && host_index < MAX_SERVERS_TO_POLL;
+ ++x)
+ {
+ memcached_server_write_instance_st instance=
+ memcached_server_instance_fetch(memc, x);
+
+ if (instance->read_buffer_length > 0) /* I have data in the buffer */
+ return instance;
+
+ if (memcached_server_response_count(instance) > 0)
+ {
+ fds[host_index].events = POLLIN;
+ fds[host_index].revents = 0;
+ fds[host_index].fd = instance->fd;
+ ++host_index;
+ }
+ }
+
+ if (host_index < 2)
+ {
+ /* We have 0 or 1 server with pending events.. */
+ for (uint32_t x= 0; x< memcached_server_count(memc); ++x)
+ {
+ memcached_server_write_instance_st instance=
+ memcached_server_instance_fetch(memc, x);
+
+ if (memcached_server_response_count(instance) > 0)
+ {
+ return instance;
+ }
+ }
+
+ return NULL;
+ }
+
+ int err= poll(fds, host_index, memc->poll_timeout);
+ switch (err) {
+ case -1:
+ memcached_set_errno(memc, get_socket_errno(), NULL);
+ /* FALLTHROUGH */
+ case 0:
+ break;
+ default:
+ for (size_t x= 0; x < host_index; ++x)
+ {
+ if (fds[x].revents & POLLIN)
+ {
+ for (uint32_t y= 0; y < memcached_server_count(memc); ++y)
+ {
+ memcached_server_write_instance_st instance=
+ memcached_server_instance_fetch(memc, y);
+
+ if (instance->fd == fds[x].fd)
+ return instance;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static ssize_t io_flush(memcached_server_write_instance_st ptr,
+ const bool with_flush,
+ memcached_return_t *error)
+{
+ /*
+ ** We might want to purge the input buffer if we haven't consumed
+ ** any output yet... The test for the limits is the purge is inline
+ ** in the purge function to avoid duplicating the logic..
+ */
+ {
+ memcached_return_t rc;
+ WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+ rc= memcached_purge(ptr);
+
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
+ {
+ return -1;
+ }
+ }
+ ssize_t sent_length;
+ size_t return_length;
+ char *local_write_ptr= ptr->write_buffer;
+ size_t write_length= ptr->write_buffer_offset;
+
+ *error= MEMCACHED_SUCCESS;
+
+ WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+
+ // UDP Sanity check, make sure that we are not sending somthing too big
+ if (ptr->type == MEMCACHED_CONNECTION_UDP && write_length > MAX_UDP_DATAGRAM_LENGTH)
+ {
+ return -1;
+ }
+
+ if (ptr->write_buffer_offset == 0 || (ptr->type == MEMCACHED_CONNECTION_UDP
+ && ptr->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH))
+ return 0;
+
+ /* Looking for memory overflows */
+#if defined(DEBUG)
+ if (write_length == MEMCACHED_MAX_BUFFER)
+ WATCHPOINT_ASSERT(ptr->write_buffer == local_write_ptr);
+ WATCHPOINT_ASSERT((ptr->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length));
+#endif
+
+ return_length= 0;
+ while (write_length)
+ {
+ WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+ WATCHPOINT_ASSERT(write_length > 0);
+ sent_length= 0;
+ if (ptr->type == MEMCACHED_CONNECTION_UDP)
+ increment_udp_message_id(ptr);
+
+ WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+ if (with_flush)
+ {
+ sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT);
+ }
+ else
+ {
+ sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT|MSG_MORE);
+ }
+
+ if (sent_length == SOCKET_ERROR)
+ {
+ ptr->cached_errno= get_socket_errno();
+#if 0 // @todo I should look at why we hit this bit of code hard frequently
+ WATCHPOINT_ERRNO(get_socket_errno());
+ WATCHPOINT_NUMBER(get_socket_errno());
+#endif
+ switch (get_socket_errno())
+ {
+ case ENOBUFS:
+ continue;
+ case EWOULDBLOCK:
+#ifdef USE_EAGAIN
+ case EAGAIN:
+#endif
+ {
+ /*
+ * We may be blocked on write because the input buffer
+ * is full. Let's check if we have room in our input
+ * buffer for more data and retry the write before
+ * waiting..
+ */
+ if (repack_input_buffer(ptr) ||
+ process_input_buffer(ptr))
+ continue;
+
+ memcached_return_t rc;
+ rc= io_wait(ptr, MEM_WRITE);
+
+ if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_TIMEOUT)
+ continue;
+
+ memcached_quit_server(ptr, true);
+ return -1;
+ }
+ case ENOTCONN:
+ case EPIPE:
+ default:
+ memcached_quit_server(ptr, true);
+ *error= MEMCACHED_ERRNO;
+ WATCHPOINT_ASSERT(ptr->fd == -1);
+ return -1;
+ }
+ }
+
+ if (ptr->type == MEMCACHED_CONNECTION_UDP &&
+ (size_t)sent_length != write_length)
+ {
+ memcached_quit_server(ptr, true);
+ return -1;
+ }
+
+ ptr->io_bytes_sent += (uint32_t) sent_length;
+
+ local_write_ptr+= sent_length;
+ write_length-= (uint32_t) sent_length;
+ return_length+= (uint32_t) sent_length;
+ }
+
+ WATCHPOINT_ASSERT(write_length == 0);
+ // Need to study this assert() WATCHPOINT_ASSERT(return_length ==
+ // ptr->write_buffer_offset);
+
+ // if we are a udp server, the begining of the buffer is reserverd for
+ // the upd frame header
+ if (ptr->type == MEMCACHED_CONNECTION_UDP)
+ ptr->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
+ else
+ ptr->write_buffer_offset= 0;
+
+ return (ssize_t) return_length;
+}
+
+/*
+ Eventually we will just kill off the server with the problem.
+*/
+void memcached_io_reset(memcached_server_write_instance_st ptr)
+{
+ memcached_quit_server(ptr, true);
+}
+
+/**
+ * Read a given number of bytes from the server and place it into a specific
+ * buffer. Reset the IO channel on this server if an error occurs.
+ */
+memcached_return_t memcached_safe_read(memcached_server_write_instance_st ptr,
+ void *dta,
+ size_t size)
+{
+ size_t offset= 0;
+ char *data= static_cast<char *>(dta);
+
+ while (offset < size)
+ {
+ ssize_t nread;
+ memcached_return_t rc= memcached_io_read(ptr, data + offset, size - offset,
+ &nread);
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ offset+= (size_t) nread;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr,
+ char *buffer_ptr,
+ size_t size)
+{
+ bool line_complete= false;
+ size_t total_nr= 0;
+
+ while (!line_complete)
+ {
+ if (ptr->read_buffer_length == 0)
+ {
+ /*
+ * We don't have any data in the buffer, so let's fill the read
+ * buffer. Call the standard read function to avoid duplicating
+ * the logic.
+ */
+ ssize_t nread;
+ memcached_return_t rc= memcached_io_read(ptr, buffer_ptr, 1, &nread);
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ if (*buffer_ptr == '\n')
+ line_complete= true;
+
+ ++buffer_ptr;
+ ++total_nr;
+ }
+
+ /* Now let's look in the buffer and copy as we go! */
+ while (ptr->read_buffer_length && total_nr < size && !line_complete)
+ {
+ *buffer_ptr = *ptr->read_ptr;
+ if (*buffer_ptr == '\n')
+ line_complete = true;
+ --ptr->read_buffer_length;
+ ++ptr->read_ptr;
+ ++total_nr;
+ ++buffer_ptr;
+ }
+
+ if (total_nr == size)
+ return MEMCACHED_PROTOCOL_ERROR;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+/*
+ * The udp request id consists of two seperate sections
+ * 1) The thread id
+ * 2) The message number
+ * The thread id should only be set when the memcached_st struct is created
+ * and should not be changed.
+ *
+ * The message num is incremented for each new message we send, this function
+ * extracts the message number from message_id, increments it and then
+ * writes the new value back into the header
+ */
+static void increment_udp_message_id(memcached_server_write_instance_st ptr)
+{
+ struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer;
+ uint16_t cur_req= get_udp_datagram_request_id(header);
+ int msg_num= get_msg_num_from_request_id(cur_req);
+ int thread_id= get_thread_id_from_request_id(cur_req);
+
+ if (((++msg_num) & UDP_REQUEST_ID_THREAD_MASK) != 0)
+ msg_num= 0;
+
+ header->request_id= htons((uint16_t) (thread_id | msg_num));
+}
+
+memcached_return_t memcached_io_init_udp_header(memcached_server_write_instance_st ptr, uint16_t thread_id)
+{
+ if (thread_id > UDP_REQUEST_ID_MAX_THREAD_ID)
+ return MEMCACHED_FAILURE;
+
+ struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer;
+ header->request_id= htons((uint16_t) (generate_udp_request_thread_id(thread_id)));
+ header->num_datagrams= htons(1);
+ header->sequence_number= htons(0);
+
+ return MEMCACHED_SUCCESS;
+}
*
*/
-#ifndef __LIBMEMCACHED_IO_H__
-#define __LIBMEMCACHED_IO_H__
+#pragma once
-#if defined(BUILDING_LIBMEMCACHED)
-
-#include "libmemcached/memcached.h"
+#include <libmemcached/memcached.h>
#define MAX_UDP_DATAGRAM_LENGTH 1400
#define UDP_DATAGRAM_HEADER_LENGTH 8
#ifdef __cplusplus
}
#endif
-
-#endif /* BUILDING_LIBMEMCACHED */
-
-#endif /* __LIBMEMCACHED_IO_H__ */
+++ /dev/null
-#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;
-}
-
--- /dev/null
+#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;
+}
+
+++ /dev/null
-/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- *
- * Libmemcached library
- *
- * Copyright (C) 2011 Data Differential, http://datadifferential.com/
- * Copyright (C) 2006-2009 Brian Aker All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * * The names of its contributors may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <libmemcached/common.h>
-#include <libmemcached/virtual_bucket.h>
-
-static const memcached_st global_copy= {
- .state= {
- .is_purging= false,
- .is_processing_input= false,
- .is_time_for_rebuild= false,
- },
- .flags= {
- .auto_eject_hosts= false,
- .binary_protocol= false,
- .buffer_requests= false,
- .hash_with_prefix_key= false,
- .no_block= false,
- .no_reply= false,
- .randomize_replica_read= false,
- .support_cas= false,
- .tcp_nodelay= false,
- .use_sort_hosts= false,
- .use_udp= false,
- .verify_key= false,
- .tcp_keepalive= false,
- },
-};
-
-static inline bool _memcached_init(memcached_st *self)
-{
- self->state= global_copy.state;
- self->flags= global_copy.flags;
- self->virtual_bucket= NULL;
-
- self->distribution= MEMCACHED_DISTRIBUTION_MODULA;
-
- hashkit_st *hash_ptr;
- hash_ptr= hashkit_create(&self->hashkit);
- if (! hash_ptr)
- return false;
-
- self->ketama.continuum= NULL;
- self->ketama.continuum_count= 0;
- self->ketama.continuum_points_counter= 0;
- self->ketama.next_distribution_rebuild= 0;
- self->ketama.weighted= false;
-
- self->number_of_hosts= 0;
- self->servers= NULL;
- self->last_disconnected_server= NULL;
-
- self->snd_timeout= 0;
- self->rcv_timeout= 0;
- self->server_failure_limit= 0;
- self->query_id= 0;
-
- /* TODO, Document why we picked these defaults */
- self->io_msg_watermark= 500;
- self->io_bytes_watermark= 65 * 1024;
-
- self->tcp_keepidle= 0;
-
- self->io_key_prefetch= 0;
- self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
- self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
- self->retry_timeout= 0;
-
- self->send_size= -1;
- self->recv_size= -1;
-
- self->user_data= NULL;
- self->number_of_replicas= 0;
- hash_ptr= hashkit_create(&self->distribution_hashkit);
- if (! hash_ptr)
- return false;
-
- self->allocators= memcached_allocators_return_default();
-
- self->on_clone= NULL;
- self->on_cleanup= NULL;
- self->get_key_failure= NULL;
- self->delete_trigger= NULL;
- self->callbacks= NULL;
- self->sasl.callbacks= NULL;
- self->sasl.is_allocated= false;
-
- self->error_messages= NULL;
- self->prefix_key= NULL;
- self->configure.initial_pool_size= 1;
- self->configure.max_pool_size= 1;
- self->configure.version= -1;
- self->configure.filename= NULL;
-
- return true;
-}
-
-static void _free(memcached_st *ptr, bool release_st)
-{
- /* If we have anything open, lets close it now */
- send_quit(ptr);
- memcached_server_list_free(memcached_server_list(ptr));
- memcached_result_free(&ptr->result);
-
- memcached_virtual_bucket_free(ptr);
-
- if (ptr->last_disconnected_server)
- memcached_server_free(ptr->last_disconnected_server);
-
- if (ptr->on_cleanup)
- ptr->on_cleanup(ptr);
-
- if (ptr->ketama.continuum)
- libmemcached_free(ptr, ptr->ketama.continuum);
-
- memcached_array_free(ptr->prefix_key);
- ptr->prefix_key= NULL;
-
- memcached_error_free(ptr);
-
- if (ptr->sasl.callbacks)
- {
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
- memcached_destroy_sasl_auth_data(ptr);
-#endif
- }
-
- if (release_st)
- {
- memcached_array_free(ptr->configure.filename);
- ptr->configure.filename= NULL;
- }
-
- if (memcached_is_allocated(ptr) && release_st)
- {
- libmemcached_free(ptr, ptr);
- }
-}
-
-memcached_st *memcached_create(memcached_st *ptr)
-{
- if (ptr == NULL)
- {
- ptr= (memcached_st *)malloc(sizeof(memcached_st));
-
- if (! ptr)
- {
- return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
- }
-
- ptr->options.is_allocated= true;
- }
- else
- {
- ptr->options.is_allocated= false;
- }
-
-#if 0
- memcached_set_purging(ptr, false);
- memcached_set_processing_input(ptr, false);
-#endif
-
- if (! _memcached_init(ptr))
- {
- memcached_free(ptr);
- return NULL;
- }
-
- if (! memcached_result_create(ptr, &ptr->result))
- {
- memcached_free(ptr);
- return NULL;
- }
-
- WATCHPOINT_ASSERT_INITIALIZED(&ptr->result);
-
- return ptr;
-}
-
-memcached_st *memcached(const char *string, size_t length)
-{
- if (! length || ! string)
- {
- errno= EINVAL;
- return NULL;
- }
-
- memcached_st *self= memcached_create(NULL);
- if (! self)
- {
- errno= ENOMEM;
- return NULL;
- }
-
- memcached_return_t rc;
- rc= memcached_parse_configuration(self, string, length);
-
- if (rc == MEMCACHED_SUCCESS && memcached_parse_filename(self))
- {
- rc= memcached_parse_configure_file(self, memcached_parse_filename(self), memcached_parse_filename_length(self));
- }
-
- if (rc != MEMCACHED_SUCCESS)
- {
- memcached_free(self);
- errno= EINVAL;
- return NULL;
- }
-
- errno= 0;
-
- return self;
-}
-
-memcached_return_t memcached_reset(memcached_st *ptr)
-{
- WATCHPOINT_ASSERT(ptr);
- if (! ptr)
- return MEMCACHED_INVALID_ARGUMENTS;
-
- bool stored_is_allocated= memcached_is_allocated(ptr);
- uint64_t query_id= ptr->query_id;
- _free(ptr, false);
- memcached_create(ptr);
- memcached_set_allocated(ptr, stored_is_allocated);
- ptr->query_id= query_id;
-
- if (ptr->configure.filename)
- {
- return memcached_parse_configure_file(ptr, memcached_param_array(ptr->configure.filename));
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-void memcached_servers_reset(memcached_st *ptr)
-{
- if (! ptr)
- return;
-
- memcached_server_list_free(memcached_server_list(ptr));
-
- memcached_server_list_set(ptr, NULL);
- ptr->number_of_hosts= 0;
- if (ptr->last_disconnected_server)
- {
- memcached_server_free(ptr->last_disconnected_server);
- }
- ptr->last_disconnected_server= NULL;
- ptr->server_failure_limit= 0;
-}
-
-void memcached_reset_last_disconnected_server(memcached_st *ptr)
-{
- if (! ptr)
- return;
-
- if (ptr->last_disconnected_server)
- {
- memcached_server_free(ptr->last_disconnected_server);
- ptr->last_disconnected_server= NULL;
- }
-}
-
-void memcached_free(memcached_st *ptr)
-{
- if (! ptr)
- return;
-
- _free(ptr, true);
-}
-
-/*
- clone is the destination, while source is the structure to clone.
- If source is NULL the call is the same as if a memcached_create() was
- called.
-*/
-memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
-{
- memcached_return_t rc= MEMCACHED_SUCCESS;
- memcached_st *new_clone;
-
- if (source == NULL)
- return memcached_create(clone);
-
- if (clone && memcached_is_allocated(clone))
- {
- return NULL;
- }
-
- new_clone= memcached_create(clone);
-
- if (new_clone == NULL)
- return NULL;
-
- new_clone->flags= source->flags;
- new_clone->send_size= source->send_size;
- new_clone->recv_size= source->recv_size;
- new_clone->poll_timeout= source->poll_timeout;
- new_clone->connect_timeout= source->connect_timeout;
- new_clone->retry_timeout= source->retry_timeout;
- new_clone->distribution= source->distribution;
-
- hashkit_st *hash_ptr;
-
- hash_ptr= hashkit_clone(&new_clone->hashkit, &source->hashkit);
- if (! hash_ptr)
- {
- memcached_free(new_clone);
- return NULL;
- }
-
- hash_ptr= hashkit_clone(&new_clone->distribution_hashkit, &source->distribution_hashkit);
- if (! hash_ptr)
- {
- memcached_free(new_clone);
- return NULL;
- }
-
- new_clone->user_data= source->user_data;
-
- new_clone->snd_timeout= source->snd_timeout;
- new_clone->rcv_timeout= source->rcv_timeout;
-
- new_clone->on_clone= source->on_clone;
- new_clone->on_cleanup= source->on_cleanup;
-
- new_clone->allocators= source->allocators;
-
- new_clone->get_key_failure= source->get_key_failure;
- new_clone->delete_trigger= source->delete_trigger;
- new_clone->server_failure_limit= source->server_failure_limit;
- new_clone->io_msg_watermark= source->io_msg_watermark;
- new_clone->io_bytes_watermark= source->io_bytes_watermark;
- new_clone->io_key_prefetch= source->io_key_prefetch;
- new_clone->number_of_replicas= source->number_of_replicas;
- new_clone->tcp_keepidle= source->tcp_keepidle;
-
- if (memcached_server_count(source))
- rc= memcached_push(new_clone, source);
-
- if (rc != MEMCACHED_SUCCESS)
- {
- memcached_free(new_clone);
-
- return NULL;
- }
-
-
- new_clone->prefix_key= memcached_array_clone(new_clone, source->prefix_key);
-
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
- if (source->sasl.callbacks)
- {
- if (memcached_clone_sasl(new_clone, source) != MEMCACHED_SUCCESS)
- {
- memcached_free(new_clone);
- return NULL;
- }
- }
-#endif
-
- rc= run_distribution(new_clone);
-
- if (rc != MEMCACHED_SUCCESS)
- {
- memcached_free(new_clone);
-
- return NULL;
- }
-
- if (source->on_clone)
- source->on_clone(new_clone, source);
-
- return new_clone;
-}
-
-void *memcached_get_user_data(const memcached_st *ptr)
-{
- return ptr->user_data;
-}
-
-void *memcached_set_user_data(memcached_st *ptr, void *data)
-{
- void *ret= ptr->user_data;
- ptr->user_data= data;
-
- return ret;
-}
-
-memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
-{
- return memcached_server_push(destination, source->servers);
-}
-
-memcached_server_write_instance_st memcached_server_instance_fetch(memcached_st *ptr, uint32_t server_key)
-{
- return &ptr->servers[server_key];
-}
-
-memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key)
-{
- return &ptr->servers[server_key];
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <libmemcached/virtual_bucket.h>
+
+#if 0
+static const memcached_st global_copy= {
+ .state= {
+ .is_purging= false, // .is_purging
+ .is_processing_input= false, // is_processing_input
+ .is_time_for_rebuild= false,
+ },
+ .flags= {
+ .auto_eject_hosts= false,
+ .binary_protocol= false,
+ .buffer_requests= false,
+ .hash_with_prefix_key= false,
+ .no_block= false,
+ .no_reply= false,
+ .randomize_replica_read= false,
+ .support_cas= false,
+ .tcp_nodelay= false,
+ .use_sort_hosts= false,
+ .use_udp= false,
+ .verify_key= false,
+ .tcp_keepalive= false,
+ },
+};
+#endif
+
+static inline bool _memcached_init(memcached_st *self)
+{
+ self->state.is_purging= false;
+ self->state.is_processing_input= false;
+ self->state.is_time_for_rebuild= false;
+
+ self->flags.auto_eject_hosts= false;
+ self->flags.binary_protocol= false;
+ self->flags.buffer_requests= false;
+ self->flags.hash_with_prefix_key= false;
+ self->flags.no_block= false;
+ self->flags.no_reply= false;
+ self->flags.randomize_replica_read= false;
+ self->flags.support_cas= false;
+ self->flags.tcp_nodelay= false;
+ self->flags.use_sort_hosts= false;
+ self->flags.use_udp= false;
+ self->flags.verify_key= false;
+ self->flags.tcp_keepalive= false;
+
+ self->virtual_bucket= NULL;
+
+ self->distribution= MEMCACHED_DISTRIBUTION_MODULA;
+
+ hashkit_st *hash_ptr;
+ hash_ptr= hashkit_create(&self->hashkit);
+ if (! hash_ptr)
+ return false;
+
+ self->ketama.continuum= NULL;
+ self->ketama.continuum_count= 0;
+ self->ketama.continuum_points_counter= 0;
+ self->ketama.next_distribution_rebuild= 0;
+ self->ketama.weighted= false;
+
+ self->number_of_hosts= 0;
+ self->servers= NULL;
+ self->last_disconnected_server= NULL;
+
+ self->snd_timeout= 0;
+ self->rcv_timeout= 0;
+ self->server_failure_limit= 0;
+ self->query_id= 1; // 0 is considered invalid
+
+ /* TODO, Document why we picked these defaults */
+ self->io_msg_watermark= 500;
+ self->io_bytes_watermark= 65 * 1024;
+
+ self->tcp_keepidle= 0;
+
+ self->io_key_prefetch= 0;
+ self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
+ self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
+ self->retry_timeout= 0;
+
+ self->send_size= -1;
+ self->recv_size= -1;
+
+ self->user_data= NULL;
+ self->number_of_replicas= 0;
+ hash_ptr= hashkit_create(&self->distribution_hashkit);
+ if (! hash_ptr)
+ return false;
+
+ self->allocators= memcached_allocators_return_default();
+
+ self->on_clone= NULL;
+ self->on_cleanup= NULL;
+ self->get_key_failure= NULL;
+ self->delete_trigger= NULL;
+ self->callbacks= NULL;
+ self->sasl.callbacks= NULL;
+ self->sasl.is_allocated= false;
+
+ self->error_messages= NULL;
+ self->prefix_key= NULL;
+ self->configure.initial_pool_size= 1;
+ self->configure.max_pool_size= 1;
+ self->configure.version= -1;
+ self->configure.filename= NULL;
+
+ return true;
+}
+
+static void _free(memcached_st *ptr, bool release_st)
+{
+ /* If we have anything open, lets close it now */
+ send_quit(ptr);
+ memcached_server_list_free(memcached_server_list(ptr));
+ memcached_result_free(&ptr->result);
+
+ memcached_virtual_bucket_free(ptr);
+
+ if (ptr->last_disconnected_server)
+ memcached_server_free(ptr->last_disconnected_server);
+
+ if (ptr->on_cleanup)
+ ptr->on_cleanup(ptr);
+
+ if (ptr->ketama.continuum)
+ libmemcached_free(ptr, ptr->ketama.continuum);
+
+ memcached_array_free(ptr->prefix_key);
+ ptr->prefix_key= NULL;
+
+ memcached_error_free(ptr);
+
+ if (ptr->sasl.callbacks)
+ {
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+ memcached_destroy_sasl_auth_data(ptr);
+#endif
+ }
+
+ if (release_st)
+ {
+ memcached_array_free(ptr->configure.filename);
+ ptr->configure.filename= NULL;
+ }
+
+ if (memcached_is_allocated(ptr) && release_st)
+ {
+ libmemcached_free(ptr, ptr);
+ }
+}
+
+memcached_st *memcached_create(memcached_st *ptr)
+{
+ if (ptr == NULL)
+ {
+ ptr= (memcached_st *)malloc(sizeof(memcached_st));
+
+ if (! ptr)
+ {
+ return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+ }
+
+ ptr->options.is_allocated= true;
+ }
+ else
+ {
+ ptr->options.is_allocated= false;
+ }
+
+#if 0
+ memcached_set_purging(ptr, false);
+ memcached_set_processing_input(ptr, false);
+#endif
+
+ if (! _memcached_init(ptr))
+ {
+ memcached_free(ptr);
+ return NULL;
+ }
+
+ if (! memcached_result_create(ptr, &ptr->result))
+ {
+ memcached_free(ptr);
+ return NULL;
+ }
+
+ WATCHPOINT_ASSERT_INITIALIZED(&ptr->result);
+
+ return ptr;
+}
+
+memcached_st *memcached(const char *string, size_t length)
+{
+ if (! length || ! string)
+ {
+ errno= EINVAL;
+ return NULL;
+ }
+
+ memcached_st *self= memcached_create(NULL);
+ if (! self)
+ {
+ errno= ENOMEM;
+ return NULL;
+ }
+
+ memcached_return_t rc;
+ rc= memcached_parse_configuration(self, string, length);
+
+ if (rc == MEMCACHED_SUCCESS && memcached_parse_filename(self))
+ {
+ rc= memcached_parse_configure_file(self, memcached_parse_filename(self), memcached_parse_filename_length(self));
+ }
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ memcached_free(self);
+ errno= EINVAL;
+ return NULL;
+ }
+
+ errno= 0;
+
+ return self;
+}
+
+memcached_return_t memcached_reset(memcached_st *ptr)
+{
+ WATCHPOINT_ASSERT(ptr);
+ if (not ptr)
+ return MEMCACHED_INVALID_ARGUMENTS;
+
+ bool stored_is_allocated= memcached_is_allocated(ptr);
+ uint64_t query_id= ptr->query_id;
+ _free(ptr, false);
+ memcached_create(ptr);
+ memcached_set_allocated(ptr, stored_is_allocated);
+ ptr->query_id= query_id;
+
+ if (ptr->configure.filename)
+ {
+ return memcached_parse_configure_file(ptr, memcached_param_array(ptr->configure.filename));
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+void memcached_servers_reset(memcached_st *ptr)
+{
+ if (! ptr)
+ return;
+
+ memcached_server_list_free(memcached_server_list(ptr));
+
+ memcached_server_list_set(ptr, NULL);
+ ptr->number_of_hosts= 0;
+ if (ptr->last_disconnected_server)
+ {
+ memcached_server_free(ptr->last_disconnected_server);
+ }
+ ptr->last_disconnected_server= NULL;
+ ptr->server_failure_limit= 0;
+}
+
+void memcached_reset_last_disconnected_server(memcached_st *ptr)
+{
+ if (! ptr)
+ return;
+
+ if (ptr->last_disconnected_server)
+ {
+ memcached_server_free(ptr->last_disconnected_server);
+ ptr->last_disconnected_server= NULL;
+ }
+}
+
+void memcached_free(memcached_st *ptr)
+{
+ if (! ptr)
+ return;
+
+ _free(ptr, true);
+}
+
+/*
+ clone is the destination, while source is the structure to clone.
+ If source is NULL the call is the same as if a memcached_create() was
+ called.
+*/
+memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
+{
+ memcached_return_t rc= MEMCACHED_SUCCESS;
+ memcached_st *new_clone;
+
+ if (source == NULL)
+ return memcached_create(clone);
+
+ if (clone && memcached_is_allocated(clone))
+ {
+ return NULL;
+ }
+
+ new_clone= memcached_create(clone);
+
+ if (new_clone == NULL)
+ return NULL;
+
+ new_clone->flags= source->flags;
+ new_clone->send_size= source->send_size;
+ new_clone->recv_size= source->recv_size;
+ new_clone->poll_timeout= source->poll_timeout;
+ new_clone->connect_timeout= source->connect_timeout;
+ new_clone->retry_timeout= source->retry_timeout;
+ new_clone->distribution= source->distribution;
+
+ hashkit_st *hash_ptr;
+
+ hash_ptr= hashkit_clone(&new_clone->hashkit, &source->hashkit);
+ if (! hash_ptr)
+ {
+ memcached_free(new_clone);
+ return NULL;
+ }
+
+ hash_ptr= hashkit_clone(&new_clone->distribution_hashkit, &source->distribution_hashkit);
+ if (! hash_ptr)
+ {
+ memcached_free(new_clone);
+ return NULL;
+ }
+
+ new_clone->user_data= source->user_data;
+
+ new_clone->snd_timeout= source->snd_timeout;
+ new_clone->rcv_timeout= source->rcv_timeout;
+
+ new_clone->on_clone= source->on_clone;
+ new_clone->on_cleanup= source->on_cleanup;
+
+ new_clone->allocators= source->allocators;
+
+ new_clone->get_key_failure= source->get_key_failure;
+ new_clone->delete_trigger= source->delete_trigger;
+ new_clone->server_failure_limit= source->server_failure_limit;
+ new_clone->io_msg_watermark= source->io_msg_watermark;
+ new_clone->io_bytes_watermark= source->io_bytes_watermark;
+ new_clone->io_key_prefetch= source->io_key_prefetch;
+ new_clone->number_of_replicas= source->number_of_replicas;
+ new_clone->tcp_keepidle= source->tcp_keepidle;
+
+ if (memcached_server_count(source))
+ rc= memcached_push(new_clone, source);
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ memcached_free(new_clone);
+
+ return NULL;
+ }
+
+
+ new_clone->prefix_key= memcached_array_clone(new_clone, source->prefix_key);
+
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+ if (source->sasl.callbacks)
+ {
+ if (memcached_clone_sasl(new_clone, source) != MEMCACHED_SUCCESS)
+ {
+ memcached_free(new_clone);
+ return NULL;
+ }
+ }
+#endif
+
+ rc= run_distribution(new_clone);
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ memcached_free(new_clone);
+
+ return NULL;
+ }
+
+ if (source->on_clone)
+ source->on_clone(new_clone, source);
+
+ return new_clone;
+}
+
+void *memcached_get_user_data(const memcached_st *ptr)
+{
+ return ptr->user_data;
+}
+
+void *memcached_set_user_data(memcached_st *ptr, void *data)
+{
+ void *ret= ptr->user_data;
+ ptr->user_data= data;
+
+ return ret;
+}
+
+memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
+{
+ return memcached_server_push(destination, source->servers);
+}
+
+memcached_server_write_instance_st memcached_server_instance_fetch(memcached_st *ptr, uint32_t server_key)
+{
+ return &ptr->servers[server_key];
+}
+
+memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key)
+{
+ return &ptr->servers[server_key];
+}
+
+uint64_t memcached_query_id(const memcached_st *self)
+{
+ if (not self)
+ return 0;
+
+ return self->query_id;
+}
#include <libmemcached/error.h>
#include <libmemcached/stats.h>
#include <libhashkit/hashkit.h>
+
// Everything above this line must be in the order specified.
#include <libmemcached/allocators.h>
#include <libmemcached/analyze.h>
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;
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
*/
#pragma once
-#ifndef LIBMEMCACHEDPP_H
-#define LIBMEMCACHEDPP_H
#include <libmemcached/memcached.h>
#include <libmemcached/exception.hpp>
{
public:
- Memcache()
- :
+ Memcache() :
servers_list(),
memc(),
result()
* this vector
* @return true on success; false otherwise
*/
- bool get(const std::string &key,
- std::vector<char> &ret_val) throw (Error)
+ bool get(const std::string &key, std::vector<char> &ret_val)
{
uint32_t flags= 0;
memcached_return_t rc;
size_t value_length= 0;
- if (key.empty())
- {
- throw(Error("the key supplied is empty!", false));
- }
char *value= memcached_get(&memc, key.c_str(), key.length(),
&value_length, &flags, &rc);
if (value != NULL && ret_val.empty())
*/
bool getByKey(const std::string &master_key,
const std::string &key,
- std::vector<char> &ret_val) throw(Error)
+ std::vector<char> &ret_val)
{
uint32_t flags= 0;
memcached_return_t rc;
size_t value_length= 0;
- if (master_key.empty() || key.empty())
- {
- throw(Error("the master key or key supplied is empty!", false));
- }
char *value= memcached_get_by_key(&memc,
master_key.c_str(), master_key.length(),
key.c_str(), key.length(),
bool set(const std::string &key,
const std::vector<char> &value,
time_t expiration,
- uint32_t flags) throw(Error)
+ uint32_t flags)
{
- if (key.empty() || value.empty())
- {
- throw(Error("the key or value supplied is empty!", false));
- }
memcached_return_t rc= memcached_set(&memc,
key.c_str(), key.length(),
&value[0], value.size(),
const std::string &key,
const std::vector<char> &value,
time_t expiration,
- uint32_t flags) throw(Error)
+ uint32_t flags)
{
- if (master_key.empty() ||
- key.empty() ||
- value.empty())
- {
- throw(Error("the key or value supplied is empty!", false));
- }
memcached_return_t rc= memcached_set_by_key(&memc, master_key.c_str(),
master_key.length(),
key.c_str(), key.length(),
bool setAll(std::vector<std::string> &keys,
std::vector< std::vector<char> *> &values,
time_t expiration,
- uint32_t flags) throw(Error)
+ uint32_t flags)
{
- if (keys.size() != values.size())
- {
- throw(Error("The number of keys and values do not match!", false));
- }
bool retval= true;
std::vector<std::string>::iterator key_it= keys.begin();
std::vector< std::vector<char> *>::iterator val_it= values.begin();
*/
bool setAll(std::map<const std::string, std::vector<char> > &key_value_map,
time_t expiration,
- uint32_t flags) throw(Error)
+ uint32_t flags)
{
- if (key_value_map.empty())
- {
- throw(Error("The key/values are not properly set!", false));
- }
bool retval= true;
- std::map<const std::string, std::vector<char> >::iterator it=
- key_value_map.begin();
+ std::map<const std::string, std::vector<char> >::iterator it= key_value_map.begin();
+
while (it != key_value_map.end())
{
retval= set(it->first, it->second, expiration, flags);
if (retval == false)
{
- std::string err_buff("There was an error setting the key ");
- err_buff.append(it->first);
- throw(Error(err_buff, false));
+ // We should tell the user what the key that failed was
+ return false;
}
++it;
}
* @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);
* @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);
* @return true on success; false otherwise
*/
bool add(const std::string &key, const std::vector<char> &value)
- throw(Error)
{
- if (key.empty() || value.empty())
- {
- throw(Error("the key or value supplied is empty!", false));
- }
memcached_return_t rc= memcached_add(&memc, key.c_str(), key.length(),
&value[0], value.size(), 0, 0);
return (rc == MEMCACHED_SUCCESS);
*/
bool addByKey(const std::string &master_key,
const std::string &key,
- const std::vector<char> &value) throw(Error)
+ const std::vector<char> &value)
{
- if (master_key.empty() ||
- key.empty() ||
- value.empty())
- {
- throw(Error("the master key or key supplied is empty!", false));
- }
memcached_return_t rc= memcached_add_by_key(&memc,
master_key.c_str(),
master_key.length(),
* @param[in[ value value to replace object with
* @return true on success; false otherwise
*/
- bool replace(const std::string &key, const std::vector<char> &value) throw(Error)
+ bool replace(const std::string &key, const std::vector<char> &value)
{
- if (key.empty() ||
- value.empty())
- {
- throw(Error("the key or value supplied is empty!", false));
- }
memcached_return_t rc= memcached_replace(&memc, key.c_str(), key.length(),
&value[0], value.size(),
0, 0);
const std::string &key,
const std::vector<char> &value)
{
- if (master_key.empty() ||
- key.empty() ||
- value.empty())
- {
- throw(Error("the master key or key supplied is empty!", false));
- }
memcached_return_t rc= memcached_replace_by_key(&memc,
master_key.c_str(),
master_key.length(),
* @return true on success; false otherwise
*/
bool prepend(const std::string &key, const std::vector<char> &value)
- throw(Error)
{
- if (key.empty() || value.empty())
- {
- throw(Error("the key or value supplied is empty!", false));
- }
memcached_return_t rc= memcached_prepend(&memc, key.c_str(), key.length(),
&value[0], value.size(), 0, 0);
return (rc == MEMCACHED_SUCCESS);
bool prependByKey(const std::string &master_key,
const std::string &key,
const std::vector<char> &value)
- throw(Error)
{
- if (master_key.empty() ||
- key.empty() ||
- value.empty())
- {
- throw(Error("the master key or key supplied is empty!", false));
- }
memcached_return_t rc= memcached_prepend_by_key(&memc,
master_key.c_str(),
master_key.length(),
* @return true on success; false otherwise
*/
bool append(const std::string &key, const std::vector<char> &value)
- throw(Error)
{
- if (key.empty() || value.empty())
- {
- throw(Error("the key or value supplied is empty!", false));
- }
memcached_return_t rc= memcached_append(&memc,
- key.c_str(),
- key.length(),
- &value[0],
- value.size(),
- 0, 0);
+ key.c_str(),
+ key.length(),
+ &value[0],
+ value.size(),
+ 0, 0);
return (rc == MEMCACHED_SUCCESS);
}
bool appendByKey(const std::string &master_key,
const std::string &key,
const std::vector<char> &value)
- throw(Error)
{
- if (master_key.empty() ||
- key.empty() ||
- value.empty())
- {
- throw(Error("the master key or key supplied is empty!", false));
- }
memcached_return_t rc= memcached_append_by_key(&memc,
- master_key.c_str(),
- master_key.length(),
- key.c_str(),
- key.length(),
- &value[0],
- value.size(),
- 0, 0);
+ master_key.c_str(),
+ master_key.length(),
+ key.c_str(),
+ key.length(),
+ &value[0],
+ value.size(),
+ 0, 0);
return (rc == MEMCACHED_SUCCESS);
}
*/
bool cas(const std::string &key,
const std::vector<char> &value,
- uint64_t cas_arg) throw(Error)
+ uint64_t cas_arg)
{
- if (key.empty() || value.empty())
- {
- throw(Error("the key or value supplied is empty!", false));
- }
memcached_return_t rc= memcached_cas(&memc, key.c_str(), key.length(),
&value[0], value.size(),
0, 0, cas_arg);
bool casByKey(const std::string &master_key,
const std::string &key,
const std::vector<char> &value,
- uint64_t cas_arg) throw(Error)
+ uint64_t cas_arg)
{
- if (master_key.empty() ||
- key.empty() ||
- value.empty())
- {
- throw(Error("the master key, key or value supplied is empty!", false));
- }
memcached_return_t rc= memcached_cas_by_key(&memc,
master_key.c_str(),
master_key.length(),
* @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);
}
* @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(),
* @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(),
*/
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(),
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.
};
}
-
-#endif /* LIBMEMCACHEDPP_H */
/**
* 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
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;
+++ /dev/null
-/*
- 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;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ I debated about putting this in the client library since it does an
+ action I don't really believe belongs in the library.
+
+ Frankly its too damn useful not to be here though.
+*/
+
+#include <libmemcached/common.h>
+
+memcached_server_list_st memcached_servers_parse(const char *server_strings)
+{
+ char *string;
+ const char *begin_ptr;
+ const char *end_ptr;
+ memcached_server_st *servers= NULL;
+ memcached_return_t rc;
+
+ WATCHPOINT_ASSERT(server_strings);
+
+ end_ptr= server_strings + strlen(server_strings);
+
+ for (begin_ptr= server_strings, string= (char *)index(server_strings, ',');
+ begin_ptr != end_ptr;
+ string= (char *)index(begin_ptr, ','))
+ {
+ char buffer[HUGE_STRING_LEN];
+ char *ptr, *ptr2;
+ uint32_t weight= 0;
+
+ if (string)
+ {
+ memcpy(buffer, begin_ptr, (size_t) (string - begin_ptr));
+ buffer[(unsigned int)(string - begin_ptr)]= 0;
+ begin_ptr= string+1;
+ }
+ else
+ {
+ size_t length= strlen(begin_ptr);
+ memcpy(buffer, begin_ptr, length);
+ buffer[length]= 0;
+ begin_ptr= end_ptr;
+ }
+
+ ptr= index(buffer, ':');
+
+ in_port_t port= 0;
+ if (ptr)
+ {
+ ptr[0]= 0;
+
+ ptr++;
+
+ 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;
+}
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/protocol/common.h"
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+
+#include <libmemcached/protocol/common.h>
+#include <libmemcached/byteorder.h>
#include <ctype.h>
-#include <string.h>
-#include <strings.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
/**
* Try to parse a key from the string.
-/* -*- 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
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/protocol/common.h"
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/protocol/common.h>
+#include <libmemcached/byteorder.h>
#include <stdlib.h>
#include <sys/types.h>
-/* -*- 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);
LIBMEMCACHED_LOCAL
memcached_protocol_event_t memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr);
-
-#endif
-/* -*- 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)
#endif
#include <assert.h>
-/* Define this here, which will turn on the visibilty controls while we're
- * building libmemcached.
- */
-#define BUILDING_LIBMEMCACHED 1
-
-#include <libmemcached/byteorder.h>
+#include <libmemcached/visibility.h>
#include <libmemcached/protocol_handler.h>
#include <libmemcached/protocol/cache.h>
#include "ascii_handler.h"
#include "binary_handler.h"
-
-#endif
--- /dev/null
+# 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}
+++ /dev/null
-#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;
-}
--- /dev/null
+#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;
+}
+++ /dev/null
-#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);
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+/*
+ 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);
+}
-/* 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" {
#ifdef __cplusplus
}
#endif
-
-#endif /* __LIBMEMCACHED_QUIT_H__ */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: 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;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+static memcached_return_t 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;
+}
-/* 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" {
#ifdef __cplusplus
}
#endif
-
-#endif /* __LIBMEMCACHED_RESPONSE_H__ */
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: 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;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/*
+ memcached_result_st are used to internally represent the return values from
+ memcached. We use a structure so that long term as identifiers are added
+ to memcached we will be able to absorb new attributes without having
+ to addjust the entire API.
+*/
+#include <libmemcached/common.h>
+
+static inline void _result_init(memcached_result_st *self,
+ memcached_st *memc)
+{
+ self->item_flags= 0;
+ self->item_expiration= 0;
+ self->key_length= 0;
+ self->item_cas= 0;
+ self->root= memc;
+ self->item_key[0]= 0;
+}
+
+memcached_result_st *memcached_result_create(const memcached_st *memc,
+ memcached_result_st *ptr)
+{
+ WATCHPOINT_ASSERT(memc);
+
+ /* Saving malloc calls :) */
+ if (ptr)
+ {
+ ptr->options.is_allocated= false;
+ }
+ else
+ {
+ ptr= static_cast<memcached_result_st *>(libmemcached_malloc(memc, sizeof(memcached_result_st)));
+
+ if (ptr == NULL)
+ return NULL;
+
+ ptr->options.is_allocated= true;
+ }
+
+ ptr->options.is_initialized= true;
+
+ _result_init(ptr, (memcached_st *)memc);
+
+ WATCHPOINT_SET(ptr->value.options.is_initialized= false);
+ memcached_string_create(memc, &ptr->value, 0);
+ WATCHPOINT_ASSERT_INITIALIZED(&ptr->value);
+ WATCHPOINT_ASSERT(ptr->value.string == NULL);
+
+ return ptr;
+}
+
+void memcached_result_reset(memcached_result_st *ptr)
+{
+ ptr->key_length= 0;
+ memcached_string_reset(&ptr->value);
+ ptr->item_flags= 0;
+ ptr->item_cas= 0;
+ ptr->item_expiration= 0;
+}
+
+void memcached_result_free(memcached_result_st *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ memcached_string_free(&ptr->value);
+
+ if (memcached_is_allocated(ptr))
+ {
+ WATCHPOINT_ASSERT(ptr->root); // Without a root, that means that result was not properly initialized.
+ libmemcached_free(ptr->root, ptr);
+ }
+ else
+ {
+ ptr->options.is_initialized= false;
+ }
+}
+
+memcached_return_t memcached_result_set_value(memcached_result_st *ptr,
+ const char *value,
+ size_t length)
+{
+ memcached_return_t rc= memcached_string_append(&ptr->value, value, length);
+
+ if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
+ {
+ memcached_set_errno(ptr->root, errno, NULL);
+ }
+
+ return rc;
+}
+
+const char *memcached_result_key_value(const memcached_result_st *self)
+{
+ return self->key_length ? self->item_key : NULL;
+}
+
+size_t memcached_result_key_length(const memcached_result_st *self)
+{
+ return self->key_length;
+}
+
+const char *memcached_result_value(const memcached_result_st *self)
+{
+ const memcached_string_st *sptr= &self->value;
+ return memcached_string_value(sptr);
+}
+
+size_t memcached_result_length(const memcached_result_st *self)
+{
+ const memcached_string_st *sptr= &self->value;
+ return memcached_string_length(sptr);
+}
+
+uint32_t memcached_result_flags(const memcached_result_st *self)
+{
+ return self->item_flags;
+}
+
+uint64_t memcached_result_cas(const memcached_result_st *self)
+{
+ return self->item_cas;
+}
+
+void memcached_result_set_flags(memcached_result_st *self, uint32_t flags)
+{
+ self->item_flags= flags;
+}
+
+void memcached_result_set_expiration(memcached_result_st *self, time_t expiration)
+{
+ self->item_expiration= expiration;
+}
typedef enum memcached_return_t memcached_return_t;
#endif
+#define memcached_failed(A) (A) != MEMCACHED_SUCCESS ? true : false
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: String structure used for libmemcached.
- *
- */
-
-/*
- This is a partial implementation for fetching/creating memcached_server_st objects.
-*/
-#include <libmemcached/common.h>
-
-static inline void _server_init(memcached_server_st *self, const memcached_st *root,
- const char *hostname, in_port_t port,
- uint32_t weight, memcached_connection_t type)
-{
- self->options.is_shutting_down= false;
- self->options.is_dead= false;
- self->number_of_hosts= 0;
- self->cursor_active= 0;
- self->port= port;
- self->cached_errno= 0;
- self->fd= -1;
- self->io_bytes_sent= 0;
- self->server_failure_counter= 0;
- self->weight= weight ? weight : 1; // 1 is the default weight value
- WATCHPOINT_SET(self->io_wait_count.read= 0);
- WATCHPOINT_SET(self->io_wait_count.write= 0);
- self->major_version= UINT8_MAX;
- self->micro_version= UINT8_MAX;
- self->minor_version= UINT8_MAX;
- self->type= type;
- self->read_ptr= self->read_buffer;
- self->cached_server_error= NULL;
- self->read_buffer_length= 0;
- self->read_data_length= 0;
- self->write_buffer_offset= 0;
- self->address_info= NULL;
- self->address_info_next= NULL;
-
- if (root)
- {
- self->next_retry= root->retry_timeout;
- }
- else
- {
- self->next_retry= 0;
- }
-
- if (self->weight > 1 && root)
- {
- ((memcached_st *)root)->ketama.weighted= true;
- }
-
- self->root= root;
- self->limit_maxbytes= 0;
- if (hostname == NULL)
- {
- self->hostname[0]= 0;
- }
- else
- {
- strncpy(self->hostname, hostname, NI_MAXHOST - 1);
- }
-}
-
-static memcached_server_st *_server_create(memcached_server_st *self, const memcached_st *memc)
-{
- if (self == NULL)
- {
- self= (memcached_server_st *)libmemcached_malloc(memc, sizeof(memcached_server_st));
-
- if (! self)
- return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
-
- self->options.is_allocated= true;
- }
- else
- {
- self->options.is_allocated= false;
- }
-
- self->options.is_initialized= true;
-
- return self;
-}
-
-memcached_server_st *memcached_server_create_with(const memcached_st *memc,
- memcached_server_write_instance_st self,
- const char *hostname, in_port_t port,
- uint32_t weight, memcached_connection_t type)
-{
- self= _server_create(self, memc);
-
- if (self == NULL)
- return NULL;
-
- _server_init(self, memc, hostname, port, weight, type);
-
-
- if (type == MEMCACHED_CONNECTION_UDP)
- {
- self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
- memcached_io_init_udp_header(self, 0);
- }
-
- return self;
-}
-
-void memcached_server_free(memcached_server_st *self)
-{
- memcached_quit_server(self, false);
-
- if (self->cached_server_error)
- free(self->cached_server_error);
-
- if (self->address_info)
- freeaddrinfo(self->address_info);
-
- if (memcached_is_allocated(self))
- {
- if (self->root)
- {
- libmemcached_free(self->root, self);
- }
- else
- {
- free(self);
- }
- }
- else
- {
- self->options.is_initialized= false;
- }
-}
-
-/*
- If we do not have a valid object to clone from, we toss an error.
-*/
-memcached_server_st *memcached_server_clone(memcached_server_st *destination,
- const memcached_server_st *source)
-{
- /* We just do a normal create if source is missing */
- if (source == NULL)
- return NULL;
-
- destination= memcached_server_create_with(source->root, destination,
- source->hostname, source->port, source->weight,
- source->type);
- if (destination != NULL)
- {
- destination->cached_errno= source->cached_errno;
-
- if (source->cached_server_error)
- destination->cached_server_error= strdup(source->cached_server_error);
- }
-
- return destination;
-
-}
-
-memcached_return_t memcached_server_cursor(const memcached_st *ptr,
- const memcached_server_fn *callback,
- void *context,
- uint32_t number_of_callbacks)
-{
- memcached_return_t rc;
- if ((rc= initialize_const_query(ptr)) != MEMCACHED_SUCCESS)
- {
- return rc;
- }
-
- for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
- {
- memcached_server_instance_st instance=
- memcached_server_instance_by_position(ptr, x);
-
- for (uint32_t y= 0; y < number_of_callbacks; y++)
- {
- unsigned int iferror;
-
- iferror= (*callback[y])(ptr, instance, context);
-
- if (iferror)
- continue;
- }
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_server_execute(memcached_st *ptr,
- memcached_server_execute_fn callback,
- void *context)
-{
- for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
- {
- memcached_server_write_instance_st instance=
- memcached_server_instance_fetch(ptr, x);
-
- unsigned int iferror;
-
- iferror= (*callback)(ptr, instance, context);
-
- if (iferror)
- continue;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_server_instance_st memcached_server_by_key(const memcached_st *ptr,
- const char *key,
- size_t key_length,
- memcached_return_t *error)
-{
- uint32_t server_key;
- memcached_server_instance_st instance;
-
- memcached_return_t rc;
- if ((rc= initialize_const_query(ptr)) != MEMCACHED_SUCCESS)
- {
- if (error)
- *error= rc;
-
- return NULL;
- }
-
- if ((rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)) != MEMCACHED_SUCCESS)
- {
- if (error)
- *error= rc;
-
- return NULL;
- }
-
- if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
- {
- *error= MEMCACHED_BAD_KEY_PROVIDED;
- return NULL;
- }
-
- server_key= memcached_generate_hash(ptr, key, key_length);
- instance= memcached_server_instance_by_position(ptr, server_key);
-
- return instance;
-
-}
-
-void memcached_server_error_reset(memcached_server_st *self)
-{
- WATCHPOINT_ASSERT(self);
- if (! self)
- return;
-
- self->cached_server_error[0]= 0;
-}
-
-memcached_server_instance_st memcached_server_get_last_disconnect(const memcached_st *self)
-{
- WATCHPOINT_ASSERT(self);
- if (! self)
- return 0;
-
- return self->last_disconnected_server;
-}
-
-void memcached_server_list_free(memcached_server_list_st self)
-{
- if (self == NULL)
- return;
-
- for (uint32_t x= 0; x < memcached_server_list_count(self); x++)
- {
- if (self[x].address_info)
- {
- freeaddrinfo(self[x].address_info);
- self[x].address_info= NULL;
- }
- }
-
- const memcached_st *root= self->root;
- if (root)
- {
- libmemcached_free(root, self);
- }
- else
- {
- free(self);
- }
-}
-
-uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count)
-{
- WATCHPOINT_ASSERT(servers);
- if (! servers)
- return 0;
-
- return servers->number_of_hosts= count;
-}
-
-uint32_t memcached_server_count(const memcached_st *self)
-{
- WATCHPOINT_ASSERT(self);
- if (! self)
- return 0;
-
- return self->number_of_hosts;
-}
-
-const char *memcached_server_name(memcached_server_instance_st self)
-{
- WATCHPOINT_ASSERT(self);
- if (! self)
- return NULL;
-
- return self->hostname;
-}
-
-in_port_t memcached_server_port(memcached_server_instance_st self)
-{
- WATCHPOINT_ASSERT(self);
- if (! self)
- return 0;
-
- return self->port;
-}
-
-uint32_t memcached_server_response_count(memcached_server_instance_st self)
-{
- WATCHPOINT_ASSERT(self);
- if (! self)
- return 0;
-
- return self->cursor_active;
-}
-
-const char *memcached_server_error(memcached_server_instance_st ptr)
-{
- return ptr
- ? ptr->cached_server_error
- : NULL;
-}
-
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: String structure used for libmemcached.
+ *
+ */
+
+/*
+ This is a partial implementation for fetching/creating memcached_server_st objects.
+*/
+#include <libmemcached/common.h>
+
+static inline void _server_init(memcached_server_st *self, const memcached_st *root,
+ const char *hostname, in_port_t port,
+ uint32_t weight, memcached_connection_t type)
+{
+ self->options.is_shutting_down= false;
+ self->options.is_dead= false;
+ self->number_of_hosts= 0;
+ self->cursor_active= 0;
+ self->port= port;
+ self->cached_errno= 0;
+ self->fd= -1;
+ self->io_bytes_sent= 0;
+ self->server_failure_counter= 0;
+ self->weight= weight ? weight : 1; // 1 is the default weight value
+ WATCHPOINT_SET(self->io_wait_count.read= 0);
+ WATCHPOINT_SET(self->io_wait_count.write= 0);
+ self->major_version= UINT8_MAX;
+ self->micro_version= UINT8_MAX;
+ self->minor_version= UINT8_MAX;
+ self->type= type;
+ self->read_ptr= self->read_buffer;
+ self->cached_server_error= NULL;
+ self->read_buffer_length= 0;
+ self->read_data_length= 0;
+ self->write_buffer_offset= 0;
+ self->address_info= NULL;
+ self->address_info_next= NULL;
+
+ if (root)
+ {
+ self->next_retry= root->retry_timeout;
+ }
+ else
+ {
+ self->next_retry= 0;
+ }
+
+ if (self->weight > 1 && root)
+ {
+ ((memcached_st *)root)->ketama.weighted= true;
+ }
+
+ self->root= root;
+ self->limit_maxbytes= 0;
+ if (hostname == NULL)
+ {
+ self->hostname[0]= 0;
+ }
+ else
+ {
+ strncpy(self->hostname, hostname, NI_MAXHOST - 1);
+ }
+}
+
+static memcached_server_st *_server_create(memcached_server_st *self, const memcached_st *memc)
+{
+ if (self == NULL)
+ {
+ self= (memcached_server_st *)libmemcached_malloc(memc, sizeof(memcached_server_st));
+
+ if (! self)
+ return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+
+ self->options.is_allocated= true;
+ }
+ else
+ {
+ self->options.is_allocated= false;
+ }
+
+ self->options.is_initialized= true;
+
+ return self;
+}
+
+memcached_server_st *memcached_server_create_with(const memcached_st *memc,
+ memcached_server_write_instance_st self,
+ const char *hostname, in_port_t port,
+ uint32_t weight, memcached_connection_t type)
+{
+ self= _server_create(self, memc);
+
+ if (self == NULL)
+ return NULL;
+
+ _server_init(self, memc, hostname, port, weight, type);
+
+
+ if (type == MEMCACHED_CONNECTION_UDP)
+ {
+ self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
+ memcached_io_init_udp_header(self, 0);
+ }
+
+ return self;
+}
+
+void memcached_server_free(memcached_server_st *self)
+{
+ memcached_quit_server(self, false);
+
+ if (self->cached_server_error)
+ free(self->cached_server_error);
+
+ if (self->address_info)
+ freeaddrinfo(self->address_info);
+
+ if (memcached_is_allocated(self))
+ {
+ if (self->root)
+ {
+ libmemcached_free(self->root, self);
+ }
+ else
+ {
+ free(self);
+ }
+ }
+ else
+ {
+ self->options.is_initialized= false;
+ }
+}
+
+/*
+ If we do not have a valid object to clone from, we toss an error.
+*/
+memcached_server_st *memcached_server_clone(memcached_server_st *destination,
+ const memcached_server_st *source)
+{
+ /* We just do a normal create if source is missing */
+ if (source == NULL)
+ return NULL;
+
+ destination= memcached_server_create_with(source->root, destination,
+ source->hostname, source->port, source->weight,
+ source->type);
+ if (destination != NULL)
+ {
+ destination->cached_errno= source->cached_errno;
+
+ if (source->cached_server_error)
+ destination->cached_server_error= strdup(source->cached_server_error);
+ }
+
+ return destination;
+
+}
+
+memcached_return_t memcached_server_cursor(const memcached_st *ptr,
+ const memcached_server_fn *callback,
+ void *context,
+ uint32_t number_of_callbacks)
+{
+ memcached_return_t rc;
+ if ((rc= initialize_const_query(ptr)) != MEMCACHED_SUCCESS)
+ {
+ return rc;
+ }
+
+ for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ {
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(ptr, x);
+
+ for (uint32_t y= 0; y < number_of_callbacks; y++)
+ {
+ unsigned int iferror;
+
+ iferror= (*callback[y])(ptr, instance, context);
+
+ if (iferror)
+ continue;
+ }
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_server_execute(memcached_st *ptr,
+ memcached_server_execute_fn callback,
+ void *context)
+{
+ for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ {
+ memcached_server_write_instance_st instance=
+ memcached_server_instance_fetch(ptr, x);
+
+ unsigned int iferror;
+
+ iferror= (*callback)(ptr, instance, context);
+
+ if (iferror)
+ continue;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_server_instance_st memcached_server_by_key(const memcached_st *ptr,
+ const char *key,
+ size_t key_length,
+ memcached_return_t *error)
+{
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_const_query(ptr)))
+ {
+ if (error)
+ *error= rc;
+
+ return NULL;
+ }
+
+ if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
+ {
+ if (error)
+ *error= rc;
+
+ return NULL;
+ }
+
+ if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+ {
+ if (error)
+ *error= MEMCACHED_BAD_KEY_PROVIDED;
+ return NULL;
+ }
+
+ uint32_t server_key= memcached_generate_hash(ptr, key, key_length);
+ return memcached_server_instance_by_position(ptr, server_key);
+
+}
+
+void memcached_server_error_reset(memcached_server_st *self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (not self)
+ return;
+
+ self->cached_server_error[0]= 0;
+}
+
+memcached_server_instance_st memcached_server_get_last_disconnect(const memcached_st *self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (not self)
+ return 0;
+
+ return self->last_disconnected_server;
+}
+
+void memcached_server_list_free(memcached_server_list_st self)
+{
+ if (not self)
+ return;
+
+ for (uint32_t x= 0; x < memcached_server_list_count(self); x++)
+ {
+ if (self[x].address_info)
+ {
+ freeaddrinfo(self[x].address_info);
+ self[x].address_info= NULL;
+ }
+ }
+
+ const memcached_st *root= self->root;
+ if (root)
+ {
+ libmemcached_free(root, self);
+ }
+ else
+ {
+ free(self);
+ }
+}
+
+uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count)
+{
+ WATCHPOINT_ASSERT(servers);
+ if (not servers)
+ return 0;
+
+ return servers->number_of_hosts= count;
+}
+
+uint32_t memcached_server_count(const memcached_st *self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (not self)
+ return 0;
+
+ return self->number_of_hosts;
+}
+
+const char *memcached_server_name(memcached_server_instance_st self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (not self)
+ return NULL;
+
+ return self->hostname;
+}
+
+in_port_t memcached_server_port(memcached_server_instance_st self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (not self)
+ return 0;
+
+ return self->port;
+}
+
+uint32_t memcached_server_response_count(memcached_server_instance_st self)
+{
+ WATCHPOINT_ASSERT(self);
+ if (not self)
+ return 0;
+
+ return self->cursor_active;
+}
+
+const char *memcached_server_error(memcached_server_instance_st ptr)
+{
+ return ptr ? ptr->cached_server_error : NULL;
+}
+
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary:
- *
- */
-
-
-#include "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;
-}
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+
+#include "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;
+}
+++ /dev/null
-/*
-*/
-
-#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);
-}
--- /dev/null
+/*
+*/
+
+#include "common.h"
+
+static const char *memcached_stat_keys[] = {
+ "pid",
+ "uptime",
+ "time",
+ "version",
+ "pointer_size",
+ "rusage_user",
+ "rusage_system",
+ "curr_items",
+ "total_items",
+ "bytes",
+ "curr_connections",
+ "total_connections",
+ "connection_structures",
+ "cmd_get",
+ "cmd_set",
+ "get_hits",
+ "get_misses",
+ "evictions",
+ "bytes_read",
+ "bytes_written",
+ "limit_maxbytes",
+ "threads",
+ NULL
+};
+
+struct local_context
+{
+ memcached_stat_fn func;
+ void *context;
+ const char *args;
+
+ local_context(memcached_stat_fn func_arg,
+ void *context_arg,
+ const char *args_arg) :
+ func(func_arg),
+ context(context_arg),
+ args(args_arg)
+ { }
+};
+
+
+static memcached_return_t set_data(memcached_stat_st *memc_stat, char *key, char *value)
+{
+
+ if (strlen(key) < 1)
+ {
+ WATCHPOINT_STRING(key);
+ return MEMCACHED_UNKNOWN_STAT_KEY;
+ }
+ else if (!strcmp("pid", key))
+ {
+ memc_stat->pid= (uint32_t) strtol(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("uptime", key))
+ {
+ memc_stat->uptime= (uint32_t) strtol(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("time", key))
+ {
+ memc_stat->time= (uint32_t) strtol(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("version", key))
+ {
+ memcpy(memc_stat->version, value, strlen(value));
+ memc_stat->version[strlen(value)]= 0;
+ }
+ else if (!strcmp("pointer_size", key))
+ {
+ memc_stat->pointer_size= (uint32_t) strtol(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("rusage_user", key))
+ {
+ char *walk_ptr;
+ for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++);
+ *walk_ptr= 0;
+ walk_ptr++;
+ memc_stat->rusage_user_seconds= (uint32_t) strtol(value, (char **)NULL, 10);
+ memc_stat->rusage_user_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10);
+ }
+ else if (!strcmp("rusage_system", key))
+ {
+ char *walk_ptr;
+ for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++);
+ *walk_ptr= 0;
+ walk_ptr++;
+ memc_stat->rusage_system_seconds= (uint32_t) strtol(value, (char **)NULL, 10);
+ memc_stat->rusage_system_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10);
+ }
+ else if (!strcmp("curr_items", key))
+ {
+ memc_stat->curr_items= (uint32_t) strtol(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("total_items", key))
+ {
+ memc_stat->total_items= (uint32_t) strtol(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("bytes_read", key))
+ {
+ memc_stat->bytes_read= (uint32_t) strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("bytes_written", key))
+ {
+ memc_stat->bytes_written= (uint32_t) strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("bytes", key))
+ {
+ memc_stat->bytes= (uint32_t) strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("curr_connections", key))
+ {
+ memc_stat->curr_connections= (uint32_t) strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("total_connections", key))
+ {
+ memc_stat->total_connections= (uint32_t) strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("connection_structures", key))
+ {
+ memc_stat->connection_structures= (uint32_t) strtol(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("cmd_get", key))
+ {
+ memc_stat->cmd_get= (uint64_t) strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("cmd_set", key))
+ {
+ memc_stat->cmd_set= (uint64_t) strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("get_hits", key))
+ {
+ memc_stat->get_hits= (uint64_t) strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("get_misses", key))
+ {
+ memc_stat->get_misses= (uint64_t)strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("evictions", key))
+ {
+ memc_stat->evictions= (uint64_t)strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("limit_maxbytes", key))
+ {
+ memc_stat->limit_maxbytes= (uint64_t) strtoll(value, (char **)NULL, 10);
+ }
+ else if (!strcmp("threads", key))
+ {
+ memc_stat->threads= (uint32_t) strtol(value, (char **)NULL, 10);
+ }
+ else if (!(strcmp("delete_misses", key) == 0 ||/* New stats in the 1.3 beta */
+ strcmp("delete_hits", key) == 0 ||/* Just swallow them for now.. */
+ strcmp("incr_misses", key) == 0 ||
+ strcmp("incr_hits", key) == 0 ||
+ strcmp("decr_misses", key) == 0 ||
+ strcmp("decr_hits", key) == 0 ||
+ strcmp("cas_misses", key) == 0 ||
+ strcmp("cas_hits", key) == 0 ||
+ strcmp("cas_badval", key) == 0 ||
+ strcmp("cmd_flush", key) == 0 ||
+ strcmp("accepting_conns", key) == 0 ||
+ strcmp("listen_disabled_num", key) == 0 ||
+ strcmp("conn_yields", key) == 0 ||
+ strcmp("auth_cmds", key) == 0 ||
+ strcmp("auth_errors", key) == 0 ||
+ strcmp("reclaimed", key) == 0))
+ {
+ WATCHPOINT_STRING(key);
+ /* return MEMCACHED_UNKNOWN_STAT_KEY; */
+ return MEMCACHED_SUCCESS;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+char *memcached_stat_get_value(const memcached_st *ptr, memcached_stat_st *memc_stat,
+ const char *key, memcached_return_t *error)
+{
+ char buffer[SMALL_STRING_LEN];
+ int length;
+ char *ret;
+
+ *error= MEMCACHED_SUCCESS;
+
+ if (!memcmp("pid", key, sizeof("pid") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pid);
+ else if (!memcmp("uptime", key, sizeof("uptime") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->uptime);
+ else if (!memcmp("time", key, sizeof("time") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time);
+ else if (!memcmp("version", key, sizeof("version") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version);
+ else if (!memcmp("pointer_size", key, sizeof("pointer_size") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pointer_size);
+ else if (!memcmp("rusage_user", key, sizeof("rusage_user") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds);
+ else if (!memcmp("rusage_system", key, sizeof("rusage_system") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds);
+ else if (!memcmp("curr_items", key, sizeof("curr_items") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_items);
+ else if (!memcmp("total_items", key, sizeof("total_items") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_items);
+ else if (!memcmp("curr_connections", key, sizeof("curr_connections") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_connections);
+ else if (!memcmp("total_connections", key, sizeof("total_connections") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_connections);
+ else if (!memcmp("connection_structures", key, sizeof("connection_structures") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->connection_structures);
+ else if (!memcmp("cmd_get", key, sizeof("cmd_get") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get);
+ else if (!memcmp("cmd_set", key, sizeof("cmd_set") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set);
+ else if (!memcmp("get_hits", key, sizeof("get_hits") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits);
+ else if (!memcmp("get_misses", key, sizeof("get_misses") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses);
+ else if (!memcmp("evictions", key, sizeof("evictions") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions);
+ else if (!memcmp("bytes_read", key, sizeof("bytes_read") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read);
+ else if (!memcmp("bytes_written", key, sizeof("bytes_written") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written);
+ else if (!memcmp("bytes", key, sizeof("bytes") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes);
+ else if (!memcmp("limit_maxbytes", key, sizeof("limit_maxbytes") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes);
+ else if (! memcmp("threads", key, sizeof("threads") -1))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->threads);
+ else
+ {
+ *error= MEMCACHED_NOTFOUND;
+ return NULL;
+ }
+
+ if (length >= SMALL_STRING_LEN || length < 0)
+ {
+ *error= MEMCACHED_FAILURE;
+ return NULL;
+ }
+
+ ret= static_cast<char *>(libmemcached_malloc(ptr, (size_t) (length + 1)));
+ memcpy(ret, buffer, (size_t) length);
+ ret[length]= '\0';
+
+ return ret;
+}
+
+static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat,
+ const char *args,
+ memcached_server_write_instance_st instance,
+ struct local_context *check)
+{
+ memcached_return_t rc;
+
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ protocol_binary_request_stats request= {}; // = {.bytes= {0}};
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+ if (args != NULL)
+ {
+ size_t len= strlen(args);
+
+ rc= memcached_validate_key_length(len, true);
+ unlikely (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ request.message.header.request.keylen= htons((uint16_t)len);
+ request.message.header.request.bodylen= htonl((uint32_t) len);
+
+ struct libmemcached_io_vector_st vector[]=
+ {
+ { sizeof(request.bytes), request.bytes },
+ { len, args }
+ };
+
+ if (memcached_vdo(instance, vector, 2, true) != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(instance);
+ return MEMCACHED_WRITE_FAILURE;
+ }
+ }
+ else
+ {
+ if (memcached_do(instance, request.bytes,
+ sizeof(request.bytes), true) != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(instance);
+ return MEMCACHED_WRITE_FAILURE;
+ }
+ }
+
+ memcached_server_response_decrement(instance);
+ do
+ {
+ rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
+
+ if (rc == MEMCACHED_END)
+ break;
+
+ unlikely (rc != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(instance);
+ return rc;
+ }
+
+ if (memc_stat)
+ {
+ unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
+ {
+ WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+ WATCHPOINT_ASSERT(0);
+ }
+ }
+
+ if (check && check->func)
+ {
+ size_t key_length= strlen(buffer);
+
+ check->func(instance,
+ buffer, key_length,
+ buffer+key_length+1, strlen(buffer+key_length+1),
+ check->context);
+ }
+ } while (1);
+
+ /* shit... memcached_response will decrement the counter, so I need to
+ ** reset it.. todo: look at this and try to find a better solution.
+ */
+ instance->cursor_active= 0;
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat,
+ const char *args,
+ memcached_server_write_instance_st instance,
+ struct local_context *check)
+{
+ memcached_return_t rc;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ int send_length;
+
+ if (args)
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "stats %s\r\n", args);
+ else
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "stats\r\n");
+
+ if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
+ return MEMCACHED_WRITE_FAILURE;
+
+ rc= memcached_do(instance, buffer, (size_t)send_length, true);
+ if (rc != MEMCACHED_SUCCESS)
+ goto error;
+
+ while (1)
+ {
+ rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+ if (rc == MEMCACHED_STAT)
+ {
+ char *string_ptr, *end_ptr;
+ char *key, *value;
+
+ string_ptr= buffer;
+ string_ptr+= 5; /* Move past STAT */
+ for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
+ key= string_ptr;
+ key[(size_t)(end_ptr-string_ptr)]= 0;
+
+ string_ptr= end_ptr + 1;
+ for (end_ptr= string_ptr; !(isspace(*end_ptr)); end_ptr++);
+ value= string_ptr;
+ value[(size_t)(end_ptr-string_ptr)]= 0;
+ string_ptr= end_ptr + 2;
+ if (memc_stat)
+ {
+ unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY)
+ {
+ WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+ WATCHPOINT_ASSERT(0);
+ }
+ }
+
+ if (check && check->func)
+ {
+ check->func(instance,
+ key, strlen(key),
+ value, strlen(value),
+ check->context);
+ }
+ }
+ else
+ break;
+ }
+
+error:
+ if (rc == MEMCACHED_END)
+ return MEMCACHED_SUCCESS;
+ else
+ return rc;
+}
+
+memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_return_t *error)
+{
+ memcached_return_t rc;
+ memcached_stat_st *stats;
+
+ if ((rc= initialize_query(self)) != MEMCACHED_SUCCESS)
+ {
+ if (error)
+ *error= rc;
+
+ return NULL;
+ }
+
+ WATCHPOINT_ASSERT(error);
+
+ unlikely (self->flags.use_udp)
+ {
+ if (error)
+ *error= MEMCACHED_NOT_SUPPORTED;
+
+ return NULL;
+ }
+
+ stats= static_cast<memcached_stat_st *>(libmemcached_calloc(self, memcached_server_count(self), sizeof(memcached_stat_st)));
+
+ if (! stats)
+ {
+ if (error)
+ *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ return NULL;
+ }
+
+ WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
+ rc= MEMCACHED_SUCCESS;
+ for (uint32_t x= 0; x < memcached_server_count(self); x++)
+ {
+ memcached_return_t temp_return;
+ memcached_server_write_instance_st instance;
+ memcached_stat_st *stat_instance;
+
+ stat_instance= stats + x;
+
+ stat_instance->root= self;
+
+ instance= memcached_server_instance_fetch(self, x);
+
+ if (self->flags.binary_protocol)
+ {
+ temp_return= binary_stats_fetch(stat_instance, args, instance, NULL);
+ }
+ else
+ {
+ temp_return= ascii_stats_fetch(stat_instance, args, instance, NULL);
+ }
+
+ if (temp_return != MEMCACHED_SUCCESS)
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+
+ if (error)
+ *error= rc;
+
+ return stats;
+}
+
+memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args,
+ const char *hostname, in_port_t port)
+{
+ memcached_st memc;
+ memcached_st *memc_ptr;
+ memcached_server_write_instance_st instance;
+
+ memset(memc_stat, 0, sizeof(memcached_stat_st));
+
+ memc_ptr= memcached_create(&memc);
+ if (! memc_ptr)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ memcached_server_add(&memc, hostname, port);
+
+ memcached_return_t rc;
+ if ((rc= initialize_query(memc_ptr)) != MEMCACHED_SUCCESS)
+ {
+ return rc;
+ }
+
+ instance= memcached_server_instance_fetch(memc_ptr, 0);
+
+ if (memc.flags.binary_protocol)
+ {
+ rc= binary_stats_fetch(memc_stat, args, instance, NULL);
+ }
+ else
+ {
+ rc= ascii_stats_fetch(memc_stat, args, instance, NULL);
+ }
+
+ memcached_free(&memc);
+
+ return rc;
+}
+
+/*
+ We make a copy of the keys since at some point in the not so distant future
+ we will add support for "found" keys.
+*/
+char ** memcached_stat_get_keys(const memcached_st *ptr,
+ memcached_stat_st *memc_stat,
+ memcached_return_t *error)
+{
+ char **list;
+ size_t length= sizeof(memcached_stat_keys);
+
+ (void)memc_stat;
+
+ list= static_cast<char **>(libmemcached_malloc(ptr, length));
+
+ if (not list)
+ {
+ *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return NULL;
+ }
+
+ memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys));
+
+ *error= MEMCACHED_SUCCESS;
+
+ return list;
+}
+
+void memcached_stat_free(const memcached_st *ptr, memcached_stat_st *memc_stat)
+{
+ if (memc_stat == NULL)
+ {
+ WATCHPOINT_ASSERT(0); /* Be polite, but when debugging catch this as an error */
+ return;
+ }
+
+ if (memc_stat->root)
+ {
+ libmemcached_free(memc_stat->root, memc_stat);
+ }
+ else if (ptr)
+ {
+ libmemcached_free(ptr, memc_stat);
+ }
+ else
+ {
+ free(memc_stat);
+ }
+}
+
+static memcached_return_t call_stat_fn(memcached_st *ptr,
+ memcached_server_write_instance_st instance,
+ void *context)
+{
+ memcached_return_t rc;
+ struct local_context *check= (struct local_context *)context;
+
+ if (ptr->flags.binary_protocol)
+ {
+ rc= binary_stats_fetch(NULL, check->args, instance, check);
+ }
+ else
+ {
+ rc= ascii_stats_fetch(NULL, check->args, instance, check);
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_stat_execute(memcached_st *memc, const char *args, memcached_stat_fn func, void *context)
+{
+ memcached_version(memc);
+
+ struct local_context check(func, context, args);
+
+ return memcached_server_execute(memc, call_stat_fn, (void *)&check);
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: 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);
-}
-
--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Storage related functions, aka set, replace,..
+ *
+ */
+
+#include <libmemcached/common.h>
+
+enum memcached_storage_action_t {
+ SET_OP,
+ REPLACE_OP,
+ ADD_OP,
+ PREPEND_OP,
+ APPEND_OP,
+ CAS_OP
+};
+
+/* Inline this */
+static inline const char *storage_op_string(memcached_storage_action_t verb)
+{
+ switch (verb)
+ {
+ case SET_OP:
+ return "set ";
+ case REPLACE_OP:
+ return "replace ";
+ case ADD_OP:
+ return "add ";
+ case PREPEND_OP:
+ return "prepend ";
+ case APPEND_OP:
+ return "append ";
+ case CAS_OP:
+ return "cas ";
+ default:
+ return "tosserror"; /* This is impossible, fixes issue for compiler warning in VisualStudio */
+ }
+
+ /* NOTREACHED */
+}
+
+static memcached_return_t memcached_send_binary(memcached_st *ptr,
+ memcached_server_write_instance_st server,
+ uint32_t server_key,
+ const char *key,
+ size_t key_length,
+ const char *value,
+ size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas,
+ memcached_storage_action_t verb);
+
+static inline memcached_return_t memcached_send(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas,
+ memcached_storage_action_t verb)
+{
+ bool to_write;
+ size_t write_length;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ uint32_t server_key;
+ memcached_server_write_instance_st instance;
+
+ WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));
+
+ memcached_return_t rc;
+ if (memcached_failed(rc= initialize_query(ptr)))
+ {
+ return rc;
+ }
+
+ if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
+ return rc;
+
+ if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+ return MEMCACHED_BAD_KEY_PROVIDED;
+
+ server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+ instance= memcached_server_instance_fetch(ptr, server_key);
+
+ WATCHPOINT_SET(instance->io_wait_count.read= 0);
+ WATCHPOINT_SET(instance->io_wait_count.write= 0);
+
+ if (ptr->flags.binary_protocol)
+ {
+ rc= memcached_send_binary(ptr, instance, server_key,
+ key, key_length,
+ value, value_length, expiration,
+ flags, cas, verb);
+ WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read);
+ WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write);
+ }
+ else
+ {
+
+ if (cas)
+ {
+ int check_length;
+ check_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "%s %.*s%.*s %u %llu %lu %llu%s\r\n",
+ storage_op_string(verb),
+ memcached_print_array(ptr->prefix_key),
+ (int)key_length, key, flags,
+ (unsigned long long)expiration, (unsigned long)value_length,
+ (unsigned long long)cas,
+ (ptr->flags.no_reply) ? " noreply" : "");
+ if (check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || check_length < 0)
+ {
+ rc= MEMCACHED_WRITE_FAILURE;
+ memcached_io_reset(instance);
+
+ return rc;
+ }
+ write_length= check_length;
+ }
+ else
+ {
+ char *buffer_ptr= buffer;
+ const char *command= storage_op_string(verb);
+
+ /* Copy in the command, no space needed, we handle that in the command function*/
+ memcpy(buffer_ptr, command, strlen(command));
+
+ /* Copy in the key prefix, switch to the buffer_ptr */
+ buffer_ptr= (char *)memcpy((char *)(buffer_ptr + strlen(command)), (char *)memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
+
+ /* Copy in the key, adjust point if a key prefix was used. */
+ buffer_ptr= (char *)memcpy(buffer_ptr + memcached_array_size(ptr->prefix_key),
+ key, key_length);
+ buffer_ptr+= key_length;
+ buffer_ptr[0]= ' ';
+ buffer_ptr++;
+
+ write_length= (size_t)(buffer_ptr - buffer);
+ int check_length;
+ check_length= snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer),
+ "%u %llu %lu%s\r\n",
+ flags,
+ (unsigned long long)expiration, (unsigned long)value_length,
+ ptr->flags.no_reply ? " noreply" : "");
+ if ((size_t)check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer) || check_length < 0)
+ {
+ rc= MEMCACHED_WRITE_FAILURE;
+ memcached_io_reset(instance);
+
+ return rc;
+ }
+
+ write_length+= (size_t)check_length;
+ WATCHPOINT_ASSERT(write_length < MEMCACHED_DEFAULT_COMMAND_SIZE);
+ }
+
+ if (ptr->flags.use_udp && ptr->flags.buffer_requests)
+ {
+ size_t cmd_size= write_length + value_length + 2;
+ if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+ return MEMCACHED_WRITE_FAILURE;
+ if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+ memcached_io_write(instance, NULL, 0, true);
+ }
+
+ if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+ {
+ rc= MEMCACHED_WRITE_FAILURE;
+ }
+ else
+ {
+ struct libmemcached_io_vector_st vector[]=
+ {
+ { write_length, buffer },
+ { value_length, value },
+ { 2, "\r\n" }
+ };
+
+ if (ptr->flags.buffer_requests && verb == SET_OP)
+ {
+ to_write= false;
+ }
+ else
+ {
+ to_write= true;
+ }
+
+ /* Send command header */
+ rc= memcached_vdo(instance, vector, 3, to_write);
+ if (rc == MEMCACHED_SUCCESS)
+ {
+
+ if (ptr->flags.no_reply)
+ {
+ rc= (to_write == false) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;
+ }
+ else if (to_write == false)
+ {
+ rc= MEMCACHED_BUFFERED;
+ }
+ else
+ {
+ rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+ if (rc == MEMCACHED_STORED)
+ rc= MEMCACHED_SUCCESS;
+ }
+ }
+ }
+
+ if (rc == MEMCACHED_WRITE_FAILURE)
+ memcached_io_reset(instance);
+ }
+
+ WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read);
+ WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write);
+
+ return rc;
+}
+
+
+memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_SET_START();
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, SET_OP);
+ LIBMEMCACHED_MEMCACHED_SET_END();
+ return rc;
+}
+
+memcached_return_t memcached_add(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_ADD_START();
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, ADD_OP);
+ LIBMEMCACHED_MEMCACHED_ADD_END();
+ return rc;
+}
+
+memcached_return_t memcached_replace(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_REPLACE_START();
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, REPLACE_OP);
+ LIBMEMCACHED_MEMCACHED_REPLACE_END();
+ return rc;
+}
+
+memcached_return_t memcached_prepend(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, PREPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_append(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, APPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_cas(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, cas, CAS_OP);
+ return rc;
+}
+
+memcached_return_t memcached_set_by_key(memcached_st *ptr,
+ const char *group_key,
+ size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_SET_START();
+ rc= memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, SET_OP);
+ LIBMEMCACHED_MEMCACHED_SET_END();
+ return rc;
+}
+
+memcached_return_t memcached_add_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_ADD_START();
+ rc= memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, ADD_OP);
+ LIBMEMCACHED_MEMCACHED_ADD_END();
+ return rc;
+}
+
+memcached_return_t memcached_replace_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_REPLACE_START();
+ rc= memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, REPLACE_OP);
+ LIBMEMCACHED_MEMCACHED_REPLACE_END();
+ return rc;
+}
+
+memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, PREPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_append_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, APPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_cas_by_key(memcached_st *ptr,
+ const char *group_key, size_t group_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, group_key, group_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, cas, CAS_OP);
+ return rc;
+}
+
+static inline uint8_t get_com_code(memcached_storage_action_t verb, bool noreply)
+{
+ /* 0 isn't a value we want, but GCC 4.2 seems to think ret can otherwise
+ * be used uninitialized in this function. FAIL */
+ uint8_t ret= 0;
+
+ if (noreply)
+ switch (verb)
+ {
+ case SET_OP:
+ ret=PROTOCOL_BINARY_CMD_SETQ;
+ break;
+ case ADD_OP:
+ ret=PROTOCOL_BINARY_CMD_ADDQ;
+ break;
+ case CAS_OP: /* FALLTHROUGH */
+ case REPLACE_OP:
+ ret=PROTOCOL_BINARY_CMD_REPLACEQ;
+ break;
+ case APPEND_OP:
+ ret=PROTOCOL_BINARY_CMD_APPENDQ;
+ break;
+ case PREPEND_OP:
+ ret=PROTOCOL_BINARY_CMD_PREPENDQ;
+ break;
+ default:
+ WATCHPOINT_ASSERT(verb);
+ break;
+ }
+ else
+ switch (verb)
+ {
+ case SET_OP:
+ ret=PROTOCOL_BINARY_CMD_SET;
+ break;
+ case ADD_OP:
+ ret=PROTOCOL_BINARY_CMD_ADD;
+ break;
+ case CAS_OP: /* FALLTHROUGH */
+ case REPLACE_OP:
+ ret=PROTOCOL_BINARY_CMD_REPLACE;
+ break;
+ case APPEND_OP:
+ ret=PROTOCOL_BINARY_CMD_APPEND;
+ break;
+ case PREPEND_OP:
+ ret=PROTOCOL_BINARY_CMD_PREPEND;
+ break;
+ default:
+ WATCHPOINT_ASSERT(verb);
+ break;
+ }
+
+ return ret;
+}
+
+
+
+static memcached_return_t memcached_send_binary(memcached_st *ptr,
+ memcached_server_write_instance_st server,
+ uint32_t server_key,
+ const char *key,
+ size_t key_length,
+ const char *value,
+ size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas,
+ memcached_storage_action_t verb)
+{
+ bool flush;
+ protocol_binary_request_set request= {};
+ size_t send_length= sizeof(request.bytes);
+
+ bool noreply= server->root->flags.no_reply;
+
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= get_com_code(verb, noreply);
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ if (verb == APPEND_OP || verb == PREPEND_OP)
+ send_length -= 8; /* append & prepend does not contain extras! */
+ else
+ {
+ request.message.header.request.extlen= 8;
+ request.message.body.flags= htonl(flags);
+ request.message.body.expiration= htonl((uint32_t)expiration);
+ }
+
+ request.message.header.request.bodylen= htonl((uint32_t) (key_length + memcached_array_size(ptr->prefix_key) + value_length +
+ request.message.header.request.extlen));
+
+ if (cas)
+ request.message.header.request.cas= htonll(cas);
+
+ flush= (bool) ((server->root->flags.buffer_requests && verb == SET_OP) ? 0 : 1);
+
+ if (server->root->flags.use_udp && ! flush)
+ {
+ size_t cmd_size= send_length + key_length + value_length;
+
+ if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+ {
+ return MEMCACHED_WRITE_FAILURE;
+ }
+ if (cmd_size + server->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+ {
+ memcached_io_write(server, NULL, 0, true);
+ }
+ }
+
+ struct libmemcached_io_vector_st vector[]=
+ {
+ { send_length, request.bytes },
+ { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+ { key_length, key },
+ { value_length, value }
+ };
+
+ /* write the header */
+ memcached_return_t rc;
+ if ((rc= memcached_vdo(server, vector, 4, flush)) != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(server);
+ return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
+ }
+
+ if (verb == SET_OP && ptr->number_of_replicas > 0)
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
+ WATCHPOINT_STRING("replicating");
+
+ for (uint32_t x= 0; x < ptr->number_of_replicas; x++)
+ {
+ memcached_server_write_instance_st instance;
+
+ ++server_key;
+ if (server_key == memcached_server_count(ptr))
+ server_key= 0;
+
+ instance= memcached_server_instance_fetch(ptr, server_key);
+
+ if (memcached_vdo(instance, vector, 4, false) != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(instance);
+ }
+ else
+ {
+ memcached_server_response_decrement(instance);
+ }
+ }
+ }
+
+ if (flush == false)
+ {
+ return MEMCACHED_BUFFERED;
+ }
+
+ if (noreply)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ return memcached_response(server, NULL, 0, NULL);
+}
+
+++ /dev/null
-#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!";
- }
-}
--- /dev/null
+#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!";
+ }
+}
+++ /dev/null
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: 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;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2009 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+
+inline static memcached_return_t _string_check(memcached_string_st *string, size_t need)
+{
+ if (need && need > (size_t)(string->current_size - (size_t)(string->end - string->string)))
+ {
+ size_t current_offset= (size_t) (string->end - string->string);
+ char *new_value;
+ size_t adjust;
+ size_t new_size;
+
+ /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
+ adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / MEMCACHED_BLOCK_SIZE;
+ adjust++;
+
+ new_size= sizeof(char) * (size_t)((adjust * MEMCACHED_BLOCK_SIZE) + string->current_size);
+ /* Test for overflow */
+ if (new_size < need)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ new_value= static_cast<char *>(libmemcached_realloc(string->root, string->string, new_size));
+
+ if (new_value == NULL)
+ {
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ string->string= new_value;
+ string->end= string->string + current_offset;
+
+ string->current_size+= (MEMCACHED_BLOCK_SIZE * adjust);
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+static inline void _init_string(memcached_string_st *self)
+{
+ self->current_size= 0;
+ self->end= self->string= NULL;
+}
+
+memcached_string_st *memcached_string_create(const memcached_st *memc, memcached_string_st *self, size_t initial_size)
+{
+ memcached_return_t rc;
+
+ WATCHPOINT_ASSERT(memc);
+
+ /* Saving malloc calls :) */
+ if (self)
+ {
+ WATCHPOINT_ASSERT(self->options.is_initialized == false);
+
+ self->options.is_allocated= false;
+ }
+ else
+ {
+ self= static_cast<memcached_string_st *>(libmemcached_malloc(memc, sizeof(memcached_string_st)));
+
+ if (self == NULL)
+ {
+ return NULL;
+ }
+
+ self->options.is_allocated= true;
+ }
+ self->root= const_cast<memcached_st *>(memc);
+
+ _init_string(self);
+
+ rc= _string_check(self, initial_size);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
+ {
+ memcached_set_errno(self->root, errno, NULL);
+ }
+ libmemcached_free(memc, self);
+
+ return NULL;
+ }
+
+ self->options.is_initialized= true;
+
+ WATCHPOINT_ASSERT(self->string == self->end);
+
+ return self;
+}
+
+memcached_return_t memcached_string_append_character(memcached_string_st *string,
+ char character)
+{
+ memcached_return_t rc;
+
+ rc= _string_check(string, 1);
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ return rc;
+ }
+
+ *string->end= character;
+ string->end++;
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_string_append(memcached_string_st *string,
+ const char *value, size_t length)
+{
+ memcached_return_t rc;
+
+ rc= _string_check(string, length);
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ return rc;
+ }
+
+ WATCHPOINT_ASSERT(length <= string->current_size);
+ WATCHPOINT_ASSERT(string->string);
+ WATCHPOINT_ASSERT(string->end >= string->string);
+
+ memcpy(string->end, value, length);
+ string->end+= length;
+
+ return MEMCACHED_SUCCESS;
+}
+
+char *memcached_string_c_copy(memcached_string_st *string)
+{
+ char *c_ptr;
+
+ if (memcached_string_length(string) == 0)
+ return NULL;
+
+ c_ptr= static_cast<char *>(libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char)));
+
+ if (c_ptr == NULL)
+ return NULL;
+
+ memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string));
+ c_ptr[memcached_string_length(string)]= 0;
+
+ return c_ptr;
+}
+
+memcached_return_t memcached_string_reset(memcached_string_st *string)
+{
+ string->end= string->string;
+
+ return MEMCACHED_SUCCESS;
+}
+
+void memcached_string_free(memcached_string_st *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ if (ptr->string)
+ {
+ libmemcached_free(ptr->root, ptr->string);
+ }
+
+ if (memcached_is_allocated(ptr))
+ {
+ libmemcached_free(ptr->root, ptr);
+ }
+ else
+ {
+ ptr->options.is_initialized= false;
+ }
+}
+
+memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
+{
+ return _string_check(string, need);
+}
+
+size_t memcached_string_length(const memcached_string_st *self)
+{
+ return (size_t)(self->end - self->string);
+}
+
+size_t memcached_string_size(const memcached_string_st *self)
+{
+ return self->current_size;
+}
+
+const char *memcached_string_value(const memcached_string_st *self)
+{
+ return self->string;
+}
+
+char *memcached_string_value_mutable(const memcached_string_st *self)
+{
+ return self->string;
+}
+
+void memcached_string_set_length(memcached_string_st *self, size_t length)
+{
+ self->end= self->string + length;
+}
-/* 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
#define memcached_string_make_from_cstr(X) (X), ((X) ? strlen(X) : 0)
#endif
-
-#endif /* __LIBMEMCACHED_STRING_H__ */
*
*/
+#pragma once
#ifndef __LIBMEMCACHED_TYPES_H__
#define __LIBMEMCACHED_TYPES_H__
--- /dev/null
+# 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
+
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
*
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
*
- * Summary: connect to all hosts, and make sure they meet a minimum version
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_util.h"
+
+#include <libmemcached/common.h>
+#include <libmemcached/memcached_util.h>
struct local_context
{
uint8_t minor_version,
uint8_t micro_version)
{
- memcached_server_fn callbacks[1];
- memcached_return_t rc= memcached_version(memc);
-
- if (rc != MEMCACHED_SUCCESS)
+ if (memcached_version(memc) != MEMCACHED_SUCCESS)
return false;
struct local_context check= { major_version, minor_version, micro_version, true };
+ memcached_server_fn callbacks[1];
callbacks[0]= check_server_version;
memcached_server_cursor(memc, callbacks, (void *)&check, 1);
+++ /dev/null
-#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);
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/common.h>
+
+struct context_st
+{
+ size_t length;
+ const char *buffer;
+};
+
+static memcached_return_t _set_verbosity(const memcached_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);
+}
-/* 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" {
#ifdef __cplusplus
}
#endif
-
-#endif /* __LIBMEMCACHED_VERBOSITY_H__ */
+++ /dev/null
-#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;
-}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <libmemcached/common.h>
+
+const char * memcached_lib_version(void)
+{
+ return LIBMEMCACHED_VERSION_STRING;
+}
+
+static inline memcached_return_t memcached_version_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;
+}
-/* 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" {
#ifdef __cplusplus
}
#endif
-
-#endif /* __LIBMEMCACHED_VERSION_H__ */
* @brief Visibility control macros
*/
-#ifndef __LIBMEMCACHED_VISIBILITY_H__
-#define __LIBMEMCACHED_VISIBILITY_H__
+#pragma once
/**
*
# define LIBMEMCACHED_LOCAL
# endif /* defined(_MSC_VER) */
#endif /* defined(BUILDING_LIBMEMCACHED) */
-
-#endif /* __LIBMEMCACHED_VISIBILITY_H__ */
#include <time.h>
#include <stdint.h>
-#include <libmemcached/memcached.h>
-
#include <libtest/test.h>
#include <libtest/failed.h>
world_stats_print(&stats);
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
- sasl_done();
-#endif
-
return stats.failed == 0 ? 0 : 1;
}
} \
} 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 \
{ \
} \
} 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)
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
-#include "../clients/generator.h"
-#include "../clients/execute.h"
+#include <clients/generator.h>
+#include <clients/execute.h>
#include <libtest/server.h>
#include <libtest/test.h>
/*
C++ to libhashkit
*/
+
+#include <config.h>
+
#include <libtest/test.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <libhashkit/hashkit.h>
+#include <libhashkit/hashkit.hpp>
#include "hash_results.h"
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= \
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
server_shutdown(construct);
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+ sasl_done();
+#endif
+
return TEST_SUCCESS;
}
{
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;
}
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);
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);
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;
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);
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);
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);
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 */
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);
/* 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);
{
test_true(return_value);
}
- test_true(!return_value);
+ test_false(return_value);
test_true(return_value_length == 0);
test_true(rc == MEMCACHED_NO_SERVERS);
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++;
}
{0, 0, 0, 0}
};
-#include "libmemcached_world.h"
+#include "tests/libmemcached_world.h"
void get_world(world_st *world)
{
/*
C++ interface test
*/
-#include "libmemcached/memcached.hpp"
+#include <libmemcached/memcached.hpp>
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <time.h>
+#include <ctime>
#include <libtest/server.h>
static void copy_vec_to_string(vector<char> &vec, string &str)
{
str.clear();
- if (! vec.empty())
+ if (not vec.empty())
{
str.assign(vec.begin(), vec.end());
}
populate_vector(value, value_set);
- foo.set("mine", value, 0, 0);
- foo.get("mine", test_value);
+ test_true(foo.set("mine", value, 0, 0));
+ test_true(foo.get("mine", test_value));
- assert((memcmp(&test_value[0], &value[0], test_value.size()) == 0));
+ test_memcmp(&test_value[0], &value[0], test_value.size());
+ test_false(foo.set("", value, 0, 0));
- /*
- * Simple test of the exceptions here...this should throw an exception
- * saying that the key is empty.
- */
- try
- {
- foo.set("", value, 0, 0);
- }
- catch (Error &err)
- {
- return TEST_SUCCESS;
- }
-
- return TEST_FAILURE;
+ return TEST_SUCCESS;
}
-test_return_t increment_test(memcached_st *memc)
+test_return_t increment_test(memcached_st *original)
{
- Memcache mcach(memc);
- bool rc;
+ Memcache mcach(original);
const string key("blah");
const string inc_value("1");
std::vector<char> inc_val;
populate_vector(inc_val, inc_value);
- rc= mcach.set(key, inc_val, 0, 0);
- if (rc == false)
- {
- return TEST_FAILURE;
- }
- mcach.get(key, ret_value);
- if (ret_value.empty())
- {
- return TEST_FAILURE;
- }
+ test_true(mcach.set(key, inc_val, 0, 0));
+
+ test_true(mcach.get(key, ret_value));
+ test_false(ret_value.empty());
copy_vec_to_string(ret_value, ret_string);
int_inc_value= uint64_t(atol(inc_value.c_str()));
int_ret_value= uint64_t(atol(ret_string.c_str()));
- assert(int_ret_value == int_inc_value);
+ test_compare(int_inc_value, int_ret_value);
- rc= mcach.increment(key, 1, &int_ret_value);
- assert(rc == true);
- assert(int_ret_value == 2);
+ test_true(mcach.increment(key, 1, &int_ret_value));
+ test_compare(2, int_ret_value);
- rc= mcach.increment(key, 1, &int_ret_value);
- assert(rc == true);
- assert(int_ret_value == 3);
+ test_true(mcach.increment(key, 1, &int_ret_value));
+ test_compare(3, int_ret_value);
- rc= mcach.increment(key, 5, &int_ret_value);
- assert(rc == true);
- assert(int_ret_value == 8);
+ test_true(mcach.increment(key, 5, &int_ret_value));
+ test_compare(8, int_ret_value);
return TEST_SUCCESS;
}
-test_return_t basic_master_key_test(memcached_st *memc)
+test_return_t basic_master_key_test(memcached_st *original)
{
- Memcache foo(memc);
+ Memcache foo(original);
const string value_set("Data for server A");
vector<char> value;
vector<char> test_value;
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;
}
return MEMCACHED_SUCCESS;
}
-test_return_t mget_result_function(memcached_st *memc)
-{
- Memcache mc(memc);
- bool rc;
- string key1("fudge");
- string key2("son");
- string key3("food");
- vector<string> keys;
- vector< vector<char> *> values;
- vector<char> val1;
- vector<char> val2;
- vector<char> val3;
- populate_vector(val1, key1);
- populate_vector(val2, key2);
- populate_vector(val3, key3);
- keys.reserve(3);
- keys.push_back(key1);
- keys.push_back(key2);
- keys.push_back(key3);
- values.reserve(3);
- values.push_back(&val1);
- values.push_back(&val2);
- values.push_back(&val3);
- unsigned int counter;
- memcached_execute_fn callbacks[1];
-
- /* We need to empty the server before we continue the test */
- rc= mc.flush(0);
- rc= mc.setAll(keys, values, 50, 9);
- assert(rc == true);
-
- rc= mc.mget(keys);
- assert(rc == true);
-
- callbacks[0]= &callback_counter;
- counter= 0;
- rc= mc.fetchExecute(callbacks, static_cast<void *>(&counter), 1);
-
- assert(counter == 3);
-
- return TEST_SUCCESS;
-}
-
-test_return_t mget_test(memcached_st *memc)
+test_return_t mget_test(memcached_st *original)
{
- Memcache mc(memc);
- bool rc;
+ Memcache memc(original);
memcached_return_t mc_rc;
vector<string> keys;
vector< vector<char> *> values;
vector<char> return_value;
/* We need to empty the server before we continue the test */
- rc= mc.flush(0);
- assert(rc == true);
+ test_true(memc.flush(0));
- rc= mc.mget(keys);
- assert(rc == true);
+ test_true(memc.mget(keys));
- while ((mc_rc= mc.fetch(return_key, return_value)) != MEMCACHED_END)
+ while ((mc_rc= memc.fetch(return_key, return_value)) != MEMCACHED_END)
{
- assert(return_value.size() != 0);
+ test_true(return_value.size());
return_value.clear();
}
- assert(mc_rc == MEMCACHED_END);
+ test_compare(mc_rc, MEMCACHED_END);
- rc= mc.setAll(keys, values, 50, 9);
- assert(rc == true);
+ test_true(memc.setAll(keys, values, 50, 9));
- rc= mc.mget(keys);
- assert(rc == true);
+ test_true(memc.mget(keys));
- while ((mc_rc= mc.fetch(return_key, return_value)) != MEMCACHED_END)
+ while ((mc_rc= memc.fetch(return_key, return_value)) != MEMCACHED_END)
{
- assert(return_key.length() == return_value.size());
- assert(!memcmp(&return_value[0], return_key.c_str(), return_value.size()));
+ test_compare(return_key.length(), return_value.size());
+ test_memcmp(&return_value[0], return_key.c_str(), return_value.size());
}
return TEST_SUCCESS;
}
-test_return_t basic_behavior(memcached_st *memc)
+test_return_t basic_behavior(memcached_st *original)
{
- Memcache mc(memc);
- bool rc;
- uint64_t value = 1;
- rc = mc.setBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY, value);
- assert(rc);
- uint64_t behavior = mc.getBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY);
- assert(behavior == value);
+ Memcache memc(original);
+ uint64_t value= 1;
+ test_true(memc.setBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY, value));
+ uint64_t behavior= memc.getBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY);
+ test_compare(behavior, value);
return TEST_SUCCESS;
}
reinterpret_cast<test_callback_fn>(increment_test) },
{ "mget", 1,
reinterpret_cast<test_callback_fn>(mget_test) },
- { "mget_result_function", 1,
- reinterpret_cast<test_callback_fn>(mget_result_function) },
{ "basic_behavior", 0,
reinterpret_cast<test_callback_fn>(basic_behavior) },
{0, 0, 0}
*
*/
-#include "libmemcached/common.h"
-#include "libmemcached/error.h"
-#include "tests/string.h"
+#define BUILDING_LIBMEMCACHED
+
+#include <libmemcached/common.h>
+#include <libmemcached/error.h>
+#include <tests/string.h>
test_return_t string_static_null(memcached_st *memc)
{