-EXTRA_DIST = libmemcached.ver \
- libmemcached_probes.d \
- memcached/README.txt \
- memcached_configure.h.in \
- protocol/libmemcachedprotocol.ver \
- util/libmemcachedutil.ver
+EXTRA_DIST = \
+ libmemcached.ver \
+ libmemcached_probes.d \
+ memcached/README.txt \
+ memcached_configure.h.in \
+ protocol/libmemcachedprotocol.ver \
+ util/libmemcachedutil.ver
EXTRA_HEADERS =
BUILT_SOURCES=
noinst_HEADERS = libmemcached_probes.h \
- memcached_io.h \
- memcached_internal.h \
+ io.h \
+ internal.h \
common.h \
memcached/protocol_binary.h \
protocol/common.h \
protocol/ascii_handler.h \
protocol/binary_handler.h
-pkginclude_HEADERS= memcached.h \
- memcached.hpp \
+pkginclude_HEADERS= \
+ behavior.h \
+ callback.h \
+ constants.h \
exception.hpp \
- memcached_behavior.h \
- memcached_callback.h \
- memcached_configure.h \
- memcached_constants.h \
- memcached_get.h \
- memcached_result.h \
- memcached_server.h \
- memcached_storage.h \
- memcached_string.h \
- memcached_types.h \
- memcached_watchpoint.h \
- protocol_handler.h \
- visibility.h
-
-nobase_pkginclude_HEADERS=protocol/cache.h \
- protocol/callback.h
-
-
-libmemcachedprotocol_la_SOURCES= protocol/ascii_handler.c \
- protocol/binary_handler.c \
- protocol/cache.c \
- protocol/pedantic.c \
- protocol/protocol_handler.c
+ get.h \
+ memcached.h \
+ memcached.hpp \
+ memcached_configure.h \
+ protocol_handler.h \
+ result.h \
+ server.h \
+ storage.h \
+ string.h \
+ types.h \
+ visibility.h \
+ watchpoint.h
+
+nobase_pkginclude_HEADERS = \
+ protocol/cache.h \
+ protocol/callback.h
+
+
+libmemcachedprotocol_la_SOURCES = \
+ protocol/ascii_handler.c \
+ protocol/binary_handler.c \
+ protocol/cache.c \
+ protocol/pedantic.c \
+ protocol/protocol_handler.c
libmemcachedprotocol_la_LDFLAGS= ${AM_LDFLAGS} -version-info 0:0:0
lib_LTLIBRARIES = libmemcached.la libmemcachedprotocol.la
noinst_LTLIBRARIES = libmemcachedcallbacks.la
libmemcachedcallbacks_la_CFLAGS = ${AM_CFLAGS} ${NO_STRICT_ALIASING}
-libmemcachedcallbacks_la_SOURCES = memcached_callback.c
+libmemcachedcallbacks_la_SOURCES = callback.c
libmemcached_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION}
-libmemcached_la_SOURCES = crc.c \
- memcached.c \
- memcached_auto.c \
- memcached_analyze.c \
- memcached_behavior.c \
- memcached_connect.c \
- memcached_delete.c \
- memcached_do.c \
- memcached_dump.c \
- memcached_fetch.c \
- memcached_flush.c \
- memcached_get.c \
- memcached_hash.c \
- memcached_hosts.c \
- memcached_io.c \
- memcached_purge.c \
- memcached_flush_buffers.c \
+libmemcached_la_SOURCES = \
+ allocators.c \
+ analyze.c \
+ auto.c \
+ behavior.c \
+ connect.c \
+ crc.c \
+ delete.c \
+ do.c \
+ dump.c \
+ fetch.c \
+ flush.c \
+ flush_buffers.c \
+ get.c \
+ hash.c \
+ hosts.c \
+ io.c \
+ jenkins_hash.c \
+ key.c \
md5.c \
- memcached_key.c \
- memcached_quit.c \
- memcached_parse.c \
- memcached_response.c \
- memcached_result.c \
- memcached_server.c \
- memcached_storage.c \
- memcached_string.c \
- memcached_stats.c \
- memcached_strerror.c \
- memcached_verbosity.c \
- memcached_version.c \
+ memcached.c \
murmur_hash.c \
- jenkins_hash.c \
- memcached_allocators.c
+ parse.c \
+ purge.c \
+ quit.c \
+ response.c \
+ result.c \
+ server.c \
+ stats.c \
+ storage.c \
+ strerror.c \
+ string.c \
+ verbosity.c \
+ version.c
if INCLUDE_HSIEH_SRC
libmemcached_la_LDFLAGS= ${AM_LDFLAGS} -version-info 3:0:0
if BUILD_LIBMEMCACHEDUTIL
-pkginclude_HEADERS+= memcached_util.h memcached_pool.h
+pkginclude_HEADERS+= memcached_util.h pool.h
lib_LTLIBRARIES+= libmemcachedutil.la
endif
-libmemcachedutil_la_SOURCES= util/memcached_pool.c
+libmemcachedutil_la_SOURCES= util/pool.c
libmemcachedutil_la_LIBADD= libmemcached.la
libmemcachedutil_la_LDFLAGS= ${AM_LDFLAGS} -version-info 0:0:0
libmemcachedutil_la_DEPENDENCIES=libmemcached.la
--- /dev/null
+#include "common.h"
+
+void libmemcached_free(memcached_st *ptr, void *mem)
+{
+ (void) ptr;
+ free(mem);
+}
+
+void *libmemcached_malloc(memcached_st *ptr, size_t size)
+{
+ (void) ptr;
+ return malloc(size);
+}
+
+void *libmemcached_realloc(memcached_st *ptr, void *mem, size_t size)
+{
+ (void) ptr;
+ return realloc(mem, size);
+}
+
+void *libmemcached_calloc(memcached_st *ptr, size_t nelem, size_t size)
+{
+ if (ptr->call_malloc != libmemcached_malloc)
+ {
+ void *ret = libmemcached_malloc(ptr, nelem * size);
+ if (ret != NULL)
+ memset(ret, 0, nelem * size);
+
+ return ret;
+ }
+
+ return calloc(nelem, size);
+}
+
+memcached_return_t memcached_set_memory_allocators(memcached_st *ptr,
+ memcached_malloc_fn mem_malloc,
+ memcached_free_fn mem_free,
+ memcached_realloc_fn mem_realloc,
+ memcached_calloc_fn mem_calloc)
+{
+ /* All should be set, or none should be set */
+ if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL)
+ {
+ ptr->call_malloc= libmemcached_malloc;
+ ptr->call_free= libmemcached_free;
+ ptr->call_realloc= libmemcached_realloc;
+ ptr->call_calloc= libmemcached_calloc;
+ }
+ else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL)
+ return MEMCACHED_FAILURE;
+ else
+ {
+ ptr->call_malloc= mem_malloc;
+ ptr->call_free= mem_free;
+ ptr->call_realloc= mem_realloc;
+ ptr->call_calloc= mem_calloc;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+void memcached_get_memory_allocators(memcached_st *ptr,
+ memcached_malloc_fn *mem_malloc,
+ memcached_free_fn *mem_free,
+ memcached_realloc_fn *mem_realloc,
+ memcached_calloc_fn *mem_calloc)
+{
+ *mem_malloc= ptr->call_malloc;
+ *mem_free= ptr->call_free;
+ *mem_realloc= ptr->call_realloc;
+ *mem_calloc= ptr->call_calloc;
+}
--- /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(memc->number_of_hosts,
+ sizeof(memcached_analysis_st));
+
+ if (!result)
+ {
+ *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return NULL;
+ }
+
+ for (x= 0; x < server_count; x++)
+ {
+ calc_largest_consumption(result, x, memc_stat[x].bytes);
+ calc_oldest_node(result, x, memc_stat[x].uptime);
+ calc_least_free_node(result, x,
+ memc_stat[x].limit_maxbytes,
+ memc_stat[x].bytes);
+
+ total_get_hits+= memc_stat[x].get_hits;
+ total_get_cmds+= memc_stat[x].cmd_get;
+ total_items+= memc_stat[x].curr_items;
+ total_bytes+= memc_stat[x].bytes;
+ }
+
+ calc_average_item_size(result, total_items, total_bytes);
+ calc_hit_ratio(result, total_get_hits, total_get_cmds);
+
+ return result;
+}
--- /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 "common.h"
+
+static memcached_return_t memcached_auto(memcached_st *ptr,
+ const char *verb,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ uint64_t offset,
+ uint64_t *value)
+{
+ size_t send_length;
+ memcached_return_t rc;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ unsigned int server_key;
+ bool no_reply= ptr->flags.no_reply;
+
+ unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
+ return MEMCACHED_NO_SERVERS;
+
+ if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+ return MEMCACHED_BAD_KEY_PROVIDED;
+
+ server_key= memcached_generate_hash(ptr, master_key, master_key_length);
+
+ send_length= (size_t)snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "%s %s%.*s %" PRIu64 "%s\r\n", verb,
+ ptr->prefix_key,
+ (int)key_length, key,
+ offset, no_reply ? " noreply" : "");
+ unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+ return MEMCACHED_WRITE_FAILURE;
+
+ rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
+ if (no_reply || rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+ /*
+ So why recheck responce? Because the protocol is brain dead :)
+ The number returned might end up equaling one of the string
+ values. Less chance of a mistake with strncmp() so we will
+ use it. We still called memcached_response() though since it
+ worked its magic for non-blocking IO.
+ */
+ if (!strncmp(buffer, "ERROR\r\n", 7))
+ {
+ *value= 0;
+ rc= MEMCACHED_PROTOCOL_ERROR;
+ }
+ else if (!strncmp(buffer, "NOT_FOUND\r\n", 11))
+ {
+ *value= 0;
+ rc= MEMCACHED_NOTFOUND;
+ }
+ else
+ {
+ *value= strtoull(buffer, (char **)NULL, 10);
+ rc= MEMCACHED_SUCCESS;
+ }
+
+ return rc;
+}
+
+static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ uint64_t offset, uint64_t initial,
+ uint32_t expiration,
+ uint64_t *value)
+{
+ unsigned int server_key;
+ bool no_reply= ptr->flags.no_reply;
+
+ unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
+ return MEMCACHED_NO_SERVERS;
+
+ server_key= memcached_generate_hash(ptr, master_key, master_key_length);
+
+ if (no_reply)
+ {
+ if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
+ cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
+ if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
+ cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
+ }
+ protocol_binary_request_incr request= {.bytes= {0}};
+
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= cmd;
+ request.message.header.request.keylen= htons((uint16_t) key_length);
+ request.message.header.request.extlen= 20;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t) (key_length + request.message.header.request.extlen));
+ request.message.body.delta= htonll(offset);
+ request.message.body.initial= htonll(initial);
+ request.message.body.expiration= htonl((uint32_t) expiration);
+
+ if ((memcached_do(&ptr->hosts[server_key], request.bytes,
+ sizeof(request.bytes), 0)!=MEMCACHED_SUCCESS) ||
+ (memcached_io_write(&ptr->hosts[server_key], key, key_length, 1) == -1))
+ {
+ memcached_io_reset(&ptr->hosts[server_key]);
+ return MEMCACHED_WRITE_FAILURE;
+ }
+
+ if (no_reply)
+ return MEMCACHED_SUCCESS;
+ return memcached_response(&ptr->hosts[server_key], (char*)value, sizeof(*value), NULL);
+}
+
+memcached_return_t memcached_increment(memcached_st *ptr,
+ const char *key, size_t key_length,
+ uint32_t offset,
+ uint64_t *value)
+{
+ return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
+}
+
+memcached_return_t memcached_decrement(memcached_st *ptr,
+ const char *key, size_t key_length,
+ uint32_t offset,
+ uint64_t *value)
+{
+ return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
+}
+
+memcached_return_t memcached_increment_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ uint64_t offset,
+ uint64_t *value)
+{
+ memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
+ unlikely (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ LIBMEMCACHED_MEMCACHED_INCREMENT_START();
+ if (ptr->flags.binary_protocol)
+ {
+ rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
+ master_key, master_key_length, key, key_length,
+ (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
+ value);
+ }
+ else
+ {
+ rc= memcached_auto(ptr, "incr", master_key, master_key_length, key, key_length, offset, value);
+ }
+
+ LIBMEMCACHED_MEMCACHED_INCREMENT_END();
+
+ return rc;
+}
+
+memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ uint64_t offset,
+ uint64_t *value)
+{
+ memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
+ unlikely (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ LIBMEMCACHED_MEMCACHED_DECREMENT_START();
+ if (ptr->flags.binary_protocol)
+ rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
+ master_key, master_key_length, key, key_length,
+ (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
+ value);
+ else
+ rc= memcached_auto(ptr, "decr", master_key, master_key_length, key, key_length, offset, value);
+
+ LIBMEMCACHED_MEMCACHED_DECREMENT_END();
+
+ return rc;
+}
+
+memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value)
+{
+ return memcached_increment_with_initial_by_key(ptr, key, key_length,
+ key, key_length,
+ offset, initial, expiration, value);
+}
+
+memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value)
+{
+ memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
+ unlikely (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
+ if (ptr->flags.binary_protocol)
+ rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
+ master_key, master_key_length, key, key_length,
+ offset, initial, (uint32_t)expiration,
+ value);
+ else
+ rc= MEMCACHED_PROTOCOL_ERROR;
+
+ LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
+
+ return rc;
+}
+
+memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value)
+{
+ return memcached_decrement_with_initial_by_key(ptr, key, key_length,
+ key, key_length,
+ offset, initial, expiration, value);
+}
+
+memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value)
+{
+ memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
+ unlikely (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
+ if (ptr->flags.binary_protocol)
+ {
+ rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
+ master_key, master_key_length, key, key_length,
+ offset, initial, (uint32_t)expiration,
+ value);
+ }
+ else
+ {
+ rc= MEMCACHED_PROTOCOL_ERROR;
+ }
+
+ LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
+
+ return rc;
+}
+
--- /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 "common.h"
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+
+/*
+ This function is used to modify the behavior of running client.
+
+ We quit all connections so we can reset the sockets.
+*/
+
+memcached_return_t memcached_behavior_set(memcached_st *ptr,
+ memcached_behavior_t flag,
+ uint64_t data)
+{
+ switch (flag)
+ {
+ case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
+ ptr->number_of_replicas= (uint32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
+ ptr->io_msg_watermark= (uint32_t) data;
+ break;
+ case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
+ ptr->io_bytes_watermark= (uint32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
+ ptr->io_key_prefetch = (uint32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
+ ptr->snd_timeout= (int32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
+ ptr->rcv_timeout= (int32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
+ ptr->server_failure_limit= (uint32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
+ if (data)
+ ptr->flags.verify_key= false;
+
+ ptr->flags.binary_protocol= data ? true : false;
+ break;
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+ ptr->flags.support_cas= data ? true: false;
+ break;
+ case MEMCACHED_BEHAVIOR_NO_BLOCK:
+ ptr->flags.no_block= data ? true: false;
+ memcached_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
+ ptr->flags.buffer_requests= data ? true : false;
+ memcached_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_USE_UDP:
+ if (ptr->number_of_hosts)
+ return MEMCACHED_FAILURE;
+ ptr->flags.use_udp= data ? true : false;
+
+ if (data)
+ ptr->flags.no_reply= data ? true : false;
+ break;
+
+ case MEMCACHED_BEHAVIOR_TCP_NODELAY:
+ ptr->flags.tcp_nodelay= data ? true : false;
+ memcached_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_DISTRIBUTION:
+ {
+ ptr->distribution= (memcached_server_distribution_t)(data);
+ if (ptr->distribution == MEMCACHED_DISTRIBUTION_RANDOM)
+ {
+ srandom((uint32_t) time(NULL));
+ }
+ run_distribution(ptr);
+ break;
+ }
+ case MEMCACHED_BEHAVIOR_KETAMA:
+ {
+ if (data)
+ {
+ ptr->hash= MEMCACHED_HASH_MD5;
+ ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
+ }
+ else
+ {
+ ptr->hash= 0;
+ ptr->distribution= 0;
+ }
+ run_distribution(ptr);
+ break;
+ }
+ case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
+ {
+ ptr->hash= MEMCACHED_HASH_MD5;
+ ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
+ ptr->flags.ketama_weighted= data ? true : false;
+ run_distribution(ptr);
+ break;
+ }
+ case MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE:
+ switch (data)
+ {
+ case MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED:
+ ptr->hash= MEMCACHED_HASH_MD5;
+ ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
+ break;
+ case MEMCACHED_KETAMA_COMPAT_SPY:
+ ptr->hash= MEMCACHED_HASH_MD5;
+ ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY;
+ break;
+ default:
+ return MEMCACHED_FAILURE;
+ }
+ run_distribution(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_HASH:
+#ifndef HAVE_HSIEH_HASH
+ if ((memcached_hash_t)(data) == MEMCACHED_HASH_HSIEH)
+ return MEMCACHED_FAILURE;
+#endif
+ ptr->hash= (memcached_hash_t)(data);
+ break;
+ case MEMCACHED_BEHAVIOR_KETAMA_HASH:
+ ptr->hash_continuum= (memcached_hash_t)(data);
+ run_distribution(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
+ ptr->flags.use_cache_lookups= data ? true : false;
+ memcached_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_VERIFY_KEY:
+ if (ptr->flags.binary_protocol)
+ break;
+ ptr->flags.verify_key= data ? true : false;
+ break;
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+ {
+ ptr->flags.use_sort_hosts= data ? true : false;
+ run_distribution(ptr);
+
+ break;
+ }
+ case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
+ ptr->poll_timeout= (int32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
+ ptr->connect_timeout= (int32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
+ ptr->retry_timeout= (int32_t)data;
+ break;
+ case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
+ ptr->send_size= (int32_t)data;
+ memcached_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
+ ptr->recv_size= (int32_t)data;
+ memcached_quit(ptr);
+ break;
+ case MEMCACHED_BEHAVIOR_USER_DATA:
+ return MEMCACHED_FAILURE;
+ case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
+ ptr->flags.hash_with_prefix_key= data ? true : false;
+ break;
+ case MEMCACHED_BEHAVIOR_NOREPLY:
+ ptr->flags.no_reply= data ? true : false;
+ break;
+ case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
+ ptr->flags.auto_eject_hosts= data ? true : false;
+ break;
+ case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
+ srandom((uint32_t) time(NULL));
+ ptr->flags.randomize_replica_read= data ? true : false;
+ break;
+ default:
+ /* Shouldn't get here */
+ WATCHPOINT_ASSERT(flag);
+ break;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+uint64_t memcached_behavior_get(memcached_st *ptr,
+ memcached_behavior_t flag)
+{
+ switch (flag)
+ {
+ case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
+ return ptr->number_of_replicas;
+ case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
+ return ptr->io_msg_watermark;
+ case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
+ return ptr->io_bytes_watermark;
+ case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
+ return ptr->io_key_prefetch;
+ case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
+ return ptr->flags.binary_protocol;
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+ return ptr->flags.support_cas;
+ case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
+ return ptr->flags.use_cache_lookups;
+ case MEMCACHED_BEHAVIOR_NO_BLOCK:
+ return ptr->flags.no_block;
+ case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
+ return ptr->flags.buffer_requests;
+ case MEMCACHED_BEHAVIOR_USE_UDP:
+ return ptr->flags.use_udp;
+ case MEMCACHED_BEHAVIOR_TCP_NODELAY:
+ return ptr->flags.tcp_nodelay;
+ case MEMCACHED_BEHAVIOR_VERIFY_KEY:
+ return ptr->flags.verify_key;
+ case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
+ return ptr->flags.ketama_weighted;
+ case MEMCACHED_BEHAVIOR_DISTRIBUTION:
+ return ptr->distribution;
+ case MEMCACHED_BEHAVIOR_KETAMA:
+ return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0;
+ case MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE:
+ switch (ptr->distribution)
+ {
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+ return MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED;
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+ return MEMCACHED_KETAMA_COMPAT_SPY;
+ case MEMCACHED_DISTRIBUTION_MODULA:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT:
+ case MEMCACHED_DISTRIBUTION_RANDOM:
+ default:
+ return (uint64_t)-1;
+ }
+ /* NOTREACHED */
+ case MEMCACHED_BEHAVIOR_HASH:
+ return ptr->hash;
+ case MEMCACHED_BEHAVIOR_KETAMA_HASH:
+ return ptr->hash_continuum;
+ case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
+ return ptr->server_failure_limit;
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+ return ptr->flags.use_sort_hosts;
+ case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
+ return (uint64_t)ptr->poll_timeout;
+ case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
+ return (uint64_t)ptr->connect_timeout;
+ case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
+ return (uint64_t)ptr->retry_timeout;
+ case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
+ return (uint64_t)ptr->snd_timeout;
+ case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
+ return (uint64_t)ptr->rcv_timeout;
+ case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
+ {
+ int sock_size;
+ socklen_t sock_length= sizeof(int);
+
+ /* REFACTOR */
+ /* We just try the first host, and if it is down we return zero */
+ if ((memcached_connect(&ptr->hosts[0])) != MEMCACHED_SUCCESS)
+ return 0;
+
+ if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET,
+ SO_SNDBUF, &sock_size, &sock_length))
+ return 0; /* Zero means error */
+
+ return (uint64_t) sock_size;
+ }
+ case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
+ {
+ int sock_size;
+ socklen_t sock_length= sizeof(int);
+
+ /* REFACTOR */
+ /* We just try the first host, and if it is down we return zero */
+ if ((memcached_connect(&ptr->hosts[0])) != MEMCACHED_SUCCESS)
+ return 0;
+
+ if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET,
+ SO_RCVBUF, &sock_size, &sock_length))
+ return 0; /* Zero means error */
+
+ return (uint64_t) sock_size;
+ }
+ case MEMCACHED_BEHAVIOR_USER_DATA:
+ return MEMCACHED_FAILURE;
+ case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
+ 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;
+ default:
+ WATCHPOINT_ASSERT(flag);
+ break;
+ }
+
+ WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */
+ return 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: Change the behavior of the memcached connection.
+ *
+ */
+
+#ifndef __MEMCACHED_BEHAVIOR_H__
+#define __MEMCACHED_BEHAVIOR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_behavior_set(memcached_st *ptr, memcached_behavior_t flag, uint64_t data);
+
+LIBMEMCACHED_API
+uint64_t memcached_behavior_get(memcached_st *ptr, memcached_behavior_t flag);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_BEHAVIOR_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 "common.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+
+/*
+ These functions provide data and function callback support
+*/
+
+memcached_return_t memcached_callback_set(memcached_st *ptr,
+ memcached_callback_t flag,
+ void *data)
+{
+ switch (flag)
+ {
+ case MEMCACHED_CALLBACK_PREFIX_KEY:
+ {
+ char *key= (char *)data;
+
+ if (key)
+ {
+ size_t key_length= strlen(key);
+
+ if (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)
+ {
+ return MEMCACHED_BAD_KEY_PROVIDED;
+ }
+
+ if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1)
+ || (strcpy(ptr->prefix_key, key) == NULL))
+ {
+ ptr->prefix_key_length= 0;
+ return MEMCACHED_BAD_KEY_PROVIDED;
+ }
+ else
+ {
+ ptr->prefix_key_length= key_length;
+ }
+ }
+ else
+ {
+ memset(ptr->prefix_key, 0, MEMCACHED_PREFIX_KEY_MAX_SIZE);
+ ptr->prefix_key_length= 0;
+ }
+
+ break;
+ }
+ case MEMCACHED_CALLBACK_USER_DATA:
+ {
+ ptr->user_data= data;
+ break;
+ }
+ case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
+ {
+ memcached_cleanup_fn func= *(memcached_cleanup_fn *)&data;
+ ptr->on_cleanup= func;
+ break;
+ }
+ case MEMCACHED_CALLBACK_CLONE_FUNCTION:
+ {
+ memcached_clone_fn func= *(memcached_clone_fn *)&data;
+ ptr->on_clone= func;
+ break;
+ }
+#ifdef MEMCACHED_ENABLE_DEPRECATED
+ case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
+ {
+ memcached_malloc_function func= *(memcached_malloc_fn *)&data;
+ ptr->call_malloc= func;
+ break;
+ }
+ case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
+ {
+ memcached_realloc_function func= *(memcached_realloc_fn *)&data;
+ ptr->call_realloc= func;
+ break;
+ }
+ case MEMCACHED_CALLBACK_FREE_FUNCTION:
+ {
+ memcached_free_function func= *(memcached_free_fn *)&data;
+ ptr->call_free= func;
+ break;
+ }
+#endif
+ case MEMCACHED_CALLBACK_GET_FAILURE:
+ {
+ memcached_trigger_key_fn func= *(memcached_trigger_key_fn *)&data;
+ ptr->get_key_failure= func;
+ break;
+ }
+ case MEMCACHED_CALLBACK_DELETE_TRIGGER:
+ {
+ memcached_trigger_delete_key_fn func= *(memcached_trigger_delete_key_fn *)&data;
+ ptr->delete_trigger= func;
+ break;
+ }
+ default:
+ return MEMCACHED_FAILURE;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+void *memcached_callback_get(memcached_st *ptr,
+ memcached_callback_t flag,
+ memcached_return_t *error)
+{
+ memcached_return_t local_error;
+
+ if (!error)
+ error = &local_error;
+
+ switch (flag)
+ {
+ case MEMCACHED_CALLBACK_PREFIX_KEY:
+ {
+ if (ptr->prefix_key[0] == 0)
+ {
+ *error= MEMCACHED_FAILURE;
+ return NULL;
+ }
+ else
+ {
+ *error= MEMCACHED_SUCCESS;
+ return (void *)ptr->prefix_key;
+ }
+ }
+ case MEMCACHED_CALLBACK_USER_DATA:
+ {
+ *error= ptr->user_data ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return (void *)ptr->user_data;
+ }
+ case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
+ {
+ *error= ptr->on_cleanup ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return *(void **)&ptr->on_cleanup;
+ }
+ case MEMCACHED_CALLBACK_CLONE_FUNCTION:
+ {
+ *error= ptr->on_clone ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return *(void **)&ptr->on_clone;
+ }
+#ifdef MEMCACHED_ENABLE_DEPRECATED
+ case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
+ {
+ *error= ptr->call_malloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return *(void **)&ptr->call_malloc;
+ }
+ case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
+ {
+ *error= ptr->call_realloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return *(void **)&ptr->call_realloc;
+ }
+ case MEMCACHED_CALLBACK_FREE_FUNCTION:
+ {
+ *error= ptr->call_free ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return *(void **)&ptr->call_free;
+ }
+#endif
+ case MEMCACHED_CALLBACK_GET_FAILURE:
+ {
+ *error= ptr->get_key_failure ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return *(void **)&ptr->get_key_failure;
+ }
+ case MEMCACHED_CALLBACK_DELETE_TRIGGER:
+ {
+ *error= ptr->delete_trigger ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return *(void **)&ptr->delete_trigger;
+ }
+ 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.
+ *
+ */
+
+#ifndef __MEMCACHED_CALLBACK_H__
+#define __MEMCACHED_CALLBACK_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_callback_set(memcached_st *ptr,
+ memcached_callback_t flag,
+ void *data);
+LIBMEMCACHED_API
+void *memcached_callback_get(memcached_st *ptr,
+ memcached_callback_t flag,
+ memcached_return_t *error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_CALLBACK_H__ */
#include "libmemcached/memcached.h"
-#include "libmemcached/memcached_watchpoint.h"
+#include "libmemcached/watchpoint.h"
/* These are private not to be installed headers */
-#include "libmemcached/memcached_io.h"
-#include "libmemcached/memcached_internal.h"
+#include "libmemcached/io.h"
+#include "libmemcached/internal.h"
#include "libmemcached/libmemcached_probes.h"
#include "libmemcached/memcached/protocol_binary.h"
#include "libmemcached/byteorder.h"
--- /dev/null
+#include "common.h"
+#include <netdb.h>
+#include <poll.h>
+#include <sys/time.h>
+
+static memcached_return_t set_hostinfo(memcached_server_st *server)
+{
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ int e;
+ char str_port[NI_MAXSERV];
+
+ sprintf(str_port, "%u", server->port);
+
+ memset(&hints, 0, sizeof(hints));
+
+ // hints.ai_family= AF_INET;
+ if (server->type == MEMCACHED_CONNECTION_UDP)
+ {
+ hints.ai_protocol= IPPROTO_UDP;
+ hints.ai_socktype= SOCK_DGRAM;
+ }
+ else
+ {
+ hints.ai_socktype= SOCK_STREAM;
+ hints.ai_protocol= IPPROTO_TCP;
+ }
+
+ e= getaddrinfo(server->hostname, str_port, &hints, &ai);
+ if (e != 0)
+ {
+ WATCHPOINT_STRING(server->hostname);
+ WATCHPOINT_STRING(gai_strerror(e));
+ return MEMCACHED_HOST_LOOKUP_FAILURE;
+ }
+
+ if (server->address_info)
+ {
+ freeaddrinfo(server->address_info);
+ server->address_info= NULL;
+ }
+ server->address_info= ai;
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_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);
+ }
+#endif
+
+#ifdef HAVE_RCVTIMEO
+ if (ptr->root->rcv_timeout)
+ {
+ int error;
+ struct timeval waittime;
+
+ waittime.tv_sec= 0;
+ waittime.tv_usec= ptr->root->rcv_timeout;
+
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO,
+ &waittime, (socklen_t)sizeof(struct timeval));
+ WATCHPOINT_ASSERT(error == 0);
+ }
+#endif
+
+ if (ptr->root->flags.no_block)
+ {
+ int error;
+ struct linger linger;
+
+ linger.l_onoff= 1;
+ linger.l_linger= 0; /* By default on close() just drop the socket */
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER,
+ &linger, (socklen_t)sizeof(struct linger));
+ WATCHPOINT_ASSERT(error == 0);
+ }
+
+ if (ptr->root->flags.tcp_nodelay)
+ {
+ int flag= 1;
+ int error;
+
+ error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY,
+ &flag, (socklen_t)sizeof(int));
+ WATCHPOINT_ASSERT(error == 0);
+ }
+
+ if (ptr->root->send_size)
+ {
+ int error;
+
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
+ &ptr->root->send_size, (socklen_t)sizeof(int));
+ WATCHPOINT_ASSERT(error == 0);
+ }
+
+ if (ptr->root->recv_size)
+ {
+ int error;
+
+ error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF,
+ &ptr->root->recv_size, (socklen_t)sizeof(int));
+ WATCHPOINT_ASSERT(error == 0);
+ }
+
+ /* libmemcached will always use nonblocking IO to avoid write deadlocks */
+ int flags;
+
+ do
+ flags= fcntl(ptr->fd, F_GETFL, 0);
+ while (flags == -1 && (errno == EINTR || errno == EAGAIN));
+
+ unlikely (flags == -1)
+ return MEMCACHED_CONNECTION_FAILURE;
+ else if ((flags & O_NONBLOCK) == 0)
+ {
+ int rval;
+
+ do
+ rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
+ while (rval == -1 && (errno == EINTR || errno == EAGAIN));
+
+ unlikely (rval == -1)
+ return MEMCACHED_CONNECTION_FAILURE;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t unix_socket_connect(memcached_server_st *ptr)
+{
+ struct sockaddr_un servAddr;
+ socklen_t addrlen;
+
+ if (ptr->fd == -1)
+ {
+ if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ ptr->cached_errno= errno;
+ return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
+ }
+
+ memset(&servAddr, 0, sizeof (struct sockaddr_un));
+ servAddr.sun_family= AF_UNIX;
+ strcpy(servAddr.sun_path, ptr->hostname); /* Copy filename */
+
+ addrlen= (socklen_t) (strlen(servAddr.sun_path) + sizeof(servAddr.sun_family));
+
+test_connect:
+ if (connect(ptr->fd,
+ (struct sockaddr *)&servAddr,
+ sizeof(servAddr)) < 0)
+ {
+ switch (errno)
+ {
+ case EINPROGRESS:
+ case EALREADY:
+ case EINTR:
+ goto test_connect;
+ case EISCONN: /* We were spinning waiting on connect */
+ break;
+ default:
+ WATCHPOINT_ERRNO(errno);
+ ptr->cached_errno= errno;
+ return MEMCACHED_ERRNO;
+ }
+ }
+ }
+
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t network_connect(memcached_server_st *ptr)
+{
+ if (ptr->fd == -1)
+ {
+ struct addrinfo *use;
+
+ if (!ptr->sockaddr_inited ||
+ (!(ptr->root->flags.use_cache_lookups)))
+ {
+ memcached_return_t rc;
+
+ rc= set_hostinfo(ptr);
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+ ptr->sockaddr_inited= true;
+ }
+
+ use= ptr->address_info;
+ /* Create the socket */
+ while (use != NULL)
+ {
+ /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
+ if (ptr->type == MEMCACHED_CONNECTION_UDP && use->ai_family != AF_INET)
+ {
+ use= use->ai_next;
+ continue;
+ }
+
+ if ((ptr->fd= socket(use->ai_family,
+ use->ai_socktype,
+ use->ai_protocol)) < 0)
+ {
+ ptr->cached_errno= errno;
+ WATCHPOINT_ERRNO(errno);
+ return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
+ }
+
+ (void)set_socket_options(ptr);
+
+ /* connect to server */
+ while (ptr->fd != -1 &&
+ connect(ptr->fd, use->ai_addr, use->ai_addrlen) < 0)
+ {
+ ptr->cached_errno= errno;
+ if (errno == EINPROGRESS || /* nonblocking mode - first return, */
+ errno == EALREADY) /* nonblocking mode - subsequent returns */
+ {
+ struct pollfd fds[1];
+ fds[0].fd = ptr->fd;
+ fds[0].events = POLLOUT;
+ int error= poll(fds, 1, ptr->root->connect_timeout);
+
+ if (error != 1 || fds[0].revents & POLLERR)
+ {
+ if (fds[0].revents & POLLERR)
+ {
+ int err;
+ socklen_t len = sizeof (err);
+ (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
+ ptr->cached_errno= (err == 0) ? errno : err;
+ }
+
+ (void)close(ptr->fd);
+ ptr->fd= -1;
+ }
+ }
+ else if (errno == EISCONN) /* we are connected :-) */
+ {
+ break;
+ }
+ else if (errno != EINTR)
+ {
+ (void)close(ptr->fd);
+ ptr->fd= -1;
+ break;
+ }
+ }
+
+ if (ptr->fd != -1)
+ {
+ WATCHPOINT_ASSERT(ptr->cursor_active == 0);
+ ptr->server_failure_counter= 0;
+ return MEMCACHED_SUCCESS;
+ }
+ use = use->ai_next;
+ }
+ }
+
+ if (ptr->fd == -1)
+ {
+ /* Failed to connect. schedule next retry */
+ if (ptr->root->retry_timeout)
+ {
+ struct timeval next_time;
+
+ if (gettimeofday(&next_time, NULL) == 0)
+ ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
+ }
+ ptr->server_failure_counter++;
+ if (ptr->cached_errno == 0)
+ return MEMCACHED_TIMEOUT;
+
+ return MEMCACHED_ERRNO; /* The last error should be from connect() */
+ }
+
+ ptr->server_failure_counter= 0;
+ return MEMCACHED_SUCCESS; /* The last error should be from connect() */
+}
+
+
+memcached_return_t memcached_connect(memcached_server_st *ptr)
+{
+ memcached_return_t rc= MEMCACHED_NO_SERVERS;
+ LIBMEMCACHED_MEMCACHED_CONNECT_START();
+
+ /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */
+ WATCHPOINT_ASSERT(ptr->root);
+ if (ptr->root->retry_timeout && ptr->root->server_failure_limit)
+ {
+ struct timeval curr_time;
+
+ gettimeofday(&curr_time, NULL);
+
+ /* if we've had too many consecutive errors on this server, mark it dead. */
+ if (ptr->server_failure_counter >= ptr->root->server_failure_limit)
+ {
+ ptr->next_retry= curr_time.tv_sec + ptr->root->retry_timeout;
+ ptr->server_failure_counter= 0;
+ }
+
+ if (curr_time.tv_sec < ptr->next_retry)
+ {
+ if (memcached_behavior_get(ptr->root, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS))
+ run_distribution(ptr->root);
+
+ ptr->root->last_disconnected_server = ptr;
+ return MEMCACHED_SERVER_MARKED_DEAD;
+ }
+ }
+
+ /* We need to clean up the multi startup piece */
+ switch (ptr->type)
+ {
+ case MEMCACHED_CONNECTION_UNKNOWN:
+ WATCHPOINT_ASSERT(0);
+ rc= MEMCACHED_NOT_SUPPORTED;
+ break;
+ case MEMCACHED_CONNECTION_UDP:
+ case MEMCACHED_CONNECTION_TCP:
+ rc= network_connect(ptr);
+ break;
+ case MEMCACHED_CONNECTION_UNIX_SOCKET:
+ rc= unix_socket_connect(ptr);
+ break;
+ default:
+ WATCHPOINT_ASSERT(0);
+ }
+
+ unlikely ( rc != MEMCACHED_SUCCESS) ptr->root->last_disconnected_server = ptr;
+
+ LIBMEMCACHED_MEMCACHED_CONNECT_END();
+
+ 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: Constants for libmemcached
+ *
+ */
+
+#ifndef __MEMCACHED_CONSTANTS_H__
+#define __MEMCACHED_CONSTANTS_H__
+
+/* Public defines */
+#define MEMCACHED_DEFAULT_PORT 11211
+#define MEMCACHED_MAX_KEY 251 /* We add one to have it null terminated */
+#define MEMCACHED_MAX_BUFFER 8196
+#define MEMCACHED_MAX_HOST_LENGTH 64
+#define MEMCACHED_MAX_HOST_SORT_LENGTH 86 /* Used for Ketama */
+#define MEMCACHED_POINTS_PER_SERVER 100
+#define MEMCACHED_POINTS_PER_SERVER_KETAMA 160
+#define MEMCACHED_CONTINUUM_SIZE MEMCACHED_POINTS_PER_SERVER*100 /* This would then set max hosts to 100 */
+#define MEMCACHED_STRIDE 4
+#define MEMCACHED_DEFAULT_TIMEOUT 1000
+#define MEMCACHED_CONTINUUM_ADDITION 10 /* How many extra slots we should build for in the continuum */
+#define MEMCACHED_PREFIX_KEY_MAX_SIZE 128
+#define MEMCACHED_EXPIRATION_NOT_ADD 0xffffffffU
+
+typedef enum {
+ MEMCACHED_SUCCESS,
+ MEMCACHED_FAILURE,
+ MEMCACHED_HOST_LOOKUP_FAILURE,
+ MEMCACHED_CONNECTION_FAILURE,
+ MEMCACHED_CONNECTION_BIND_FAILURE,
+ MEMCACHED_WRITE_FAILURE,
+ MEMCACHED_READ_FAILURE,
+ MEMCACHED_UNKNOWN_READ_FAILURE,
+ MEMCACHED_PROTOCOL_ERROR,
+ MEMCACHED_CLIENT_ERROR,
+ MEMCACHED_SERVER_ERROR,
+ MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE,
+ MEMCACHED_DATA_EXISTS,
+ MEMCACHED_DATA_DOES_NOT_EXIST,
+ MEMCACHED_NOTSTORED,
+ MEMCACHED_STORED,
+ MEMCACHED_NOTFOUND,
+ MEMCACHED_MEMORY_ALLOCATION_FAILURE,
+ MEMCACHED_PARTIAL_READ,
+ MEMCACHED_SOME_ERRORS,
+ MEMCACHED_NO_SERVERS,
+ MEMCACHED_END,
+ MEMCACHED_DELETED,
+ MEMCACHED_VALUE,
+ MEMCACHED_STAT,
+ MEMCACHED_ITEM,
+ MEMCACHED_ERRNO,
+ MEMCACHED_FAIL_UNIX_SOCKET,
+ MEMCACHED_NOT_SUPPORTED,
+ MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */
+ MEMCACHED_FETCH_NOTFINISHED,
+ MEMCACHED_TIMEOUT,
+ MEMCACHED_BUFFERED,
+ MEMCACHED_BAD_KEY_PROVIDED,
+ MEMCACHED_INVALID_HOST_PROTOCOL,
+ MEMCACHED_SERVER_MARKED_DEAD,
+ MEMCACHED_UNKNOWN_STAT_KEY,
+ MEMCACHED_E2BIG,
+ MEMCACHED_INVALID_ARGUMENTS,
+ MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */
+} memcached_return_t;
+
+
+typedef enum {
+ MEMCACHED_DISTRIBUTION_MODULA,
+ MEMCACHED_DISTRIBUTION_CONSISTENT,
+ MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA,
+ MEMCACHED_DISTRIBUTION_RANDOM,
+ MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY
+} memcached_server_distribution_t;
+
+typedef enum {
+ MEMCACHED_BEHAVIOR_NO_BLOCK,
+ MEMCACHED_BEHAVIOR_TCP_NODELAY,
+ MEMCACHED_BEHAVIOR_HASH,
+ MEMCACHED_BEHAVIOR_KETAMA,
+ MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE,
+ MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE,
+ MEMCACHED_BEHAVIOR_CACHE_LOOKUPS,
+ MEMCACHED_BEHAVIOR_SUPPORT_CAS,
+ MEMCACHED_BEHAVIOR_POLL_TIMEOUT,
+ MEMCACHED_BEHAVIOR_DISTRIBUTION,
+ MEMCACHED_BEHAVIOR_BUFFER_REQUESTS,
+ MEMCACHED_BEHAVIOR_USER_DATA,
+ MEMCACHED_BEHAVIOR_SORT_HOSTS,
+ MEMCACHED_BEHAVIOR_VERIFY_KEY,
+ MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT,
+ MEMCACHED_BEHAVIOR_RETRY_TIMEOUT,
+ MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED,
+ MEMCACHED_BEHAVIOR_KETAMA_HASH,
+ MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+ MEMCACHED_BEHAVIOR_SND_TIMEOUT,
+ MEMCACHED_BEHAVIOR_RCV_TIMEOUT,
+ MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT,
+ MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK,
+ MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK,
+ MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH,
+ MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY,
+ MEMCACHED_BEHAVIOR_NOREPLY,
+ MEMCACHED_BEHAVIOR_USE_UDP,
+ MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS,
+ MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS,
+ MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE,
+ MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ
+} memcached_behavior_t;
+
+#define MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED 0
+#define MEMCACHED_KETAMA_COMPAT_SPY 1
+
+typedef enum {
+ MEMCACHED_CALLBACK_PREFIX_KEY = 0,
+ MEMCACHED_CALLBACK_USER_DATA = 1,
+ MEMCACHED_CALLBACK_CLEANUP_FUNCTION = 2,
+ MEMCACHED_CALLBACK_CLONE_FUNCTION = 3,
+#ifdef MEMCACHED_ENABLE_DEPRECATED
+ MEMCACHED_CALLBACK_MALLOC_FUNCTION = 4,
+ MEMCACHED_CALLBACK_REALLOC_FUNCTION = 5,
+ MEMCACHED_CALLBACK_FREE_FUNCTION = 6,
+#endif
+ MEMCACHED_CALLBACK_GET_FAILURE = 7,
+ MEMCACHED_CALLBACK_DELETE_TRIGGER = 8
+} memcached_callback_t;
+
+typedef enum {
+ MEMCACHED_HASH_DEFAULT= 0,
+ MEMCACHED_HASH_MD5,
+ MEMCACHED_HASH_CRC,
+ MEMCACHED_HASH_FNV1_64,
+ MEMCACHED_HASH_FNV1A_64,
+ MEMCACHED_HASH_FNV1_32,
+ MEMCACHED_HASH_FNV1A_32,
+ MEMCACHED_HASH_HSIEH,
+ MEMCACHED_HASH_MURMUR,
+ MEMCACHED_HASH_JENKINS
+} memcached_hash_t;
+
+typedef enum {
+ MEMCACHED_CONNECTION_UNKNOWN,
+ MEMCACHED_CONNECTION_TCP,
+ MEMCACHED_CONNECTION_UDP,
+ MEMCACHED_CONNECTION_UNIX_SOCKET
+} memcached_connection_t;
+
+#endif /* __MEMCACHED_CONSTANTS_H__ */
--- /dev/null
+#include "common.h"
+#include "memcached/protocol_binary.h"
+
+memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
+ time_t expiration)
+{
+ return memcached_delete_by_key(ptr, key, key_length,
+ key, key_length, expiration);
+}
+
+static inline memcached_return_t binary_delete(memcached_st *ptr,
+ unsigned int server_key,
+ const char *key,
+ size_t key_length,
+ uint8_t flush);
+
+memcached_return_t memcached_delete_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ time_t expiration)
+{
+ uint8_t to_write;
+ size_t send_length;
+ memcached_return_t rc;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ unsigned int server_key;
+
+ LIBMEMCACHED_MEMCACHED_DELETE_START();
+
+ rc= memcached_validate_key_length(key_length,
+ ptr->flags.binary_protocol);
+ unlikely (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
+ return MEMCACHED_NO_SERVERS;
+
+ server_key= memcached_generate_hash(ptr, master_key, master_key_length);
+ to_write= (uint8_t)((ptr->flags.buffer_requests) ? 0 : 1);
+ bool no_reply= (ptr->flags.no_reply);
+
+ if (ptr->flags.binary_protocol)
+ {
+ likely (!expiration)
+ rc= binary_delete(ptr, server_key, key, key_length, to_write);
+ else
+ rc= MEMCACHED_INVALID_ARGUMENTS;
+ }
+ else
+ {
+ unlikely (expiration)
+ {
+ if ((ptr->hosts[server_key].major_version == 1 &&
+ ptr->hosts[server_key].minor_version > 2) ||
+ ptr->hosts[server_key].major_version > 1)
+ {
+ rc= MEMCACHED_INVALID_ARGUMENTS;
+ goto error;
+ }
+ else
+ {
+ if (ptr->hosts[server_key].minor_version == 0)
+ {
+ if (no_reply || !to_write)
+ {
+ /* We might get out of sync with the server if we
+ * send this command to a server newer than 1.2.x..
+ * disable no_reply and buffered mode.
+ */
+ to_write= 1;
+ if (no_reply)
+ memcached_server_response_increment(&ptr->hosts[server_key]);
+ no_reply= false;
+ }
+ }
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "delete %s%.*s %u%s\r\n",
+ ptr->prefix_key,
+ (int) key_length, key,
+ (uint32_t)expiration,
+ no_reply ? " noreply" :"" );
+ }
+ }
+ else
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "delete %s%.*s%s\r\n",
+ ptr->prefix_key,
+ (int)key_length, key, no_reply ? " noreply" :"");
+
+ if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+ {
+ rc= MEMCACHED_WRITE_FAILURE;
+ goto error;
+ }
+
+ if (ptr->flags.use_udp && !to_write)
+ {
+ if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+ return MEMCACHED_WRITE_FAILURE;
+ if (send_length + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+ memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
+ }
+
+ rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, to_write);
+ }
+
+ if (rc != MEMCACHED_SUCCESS)
+ goto error;
+
+ if (!to_write)
+ rc= MEMCACHED_BUFFERED;
+ else if (!no_reply)
+ {
+ rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+ if (rc == MEMCACHED_DELETED)
+ rc= MEMCACHED_SUCCESS;
+ }
+
+ if (rc == MEMCACHED_SUCCESS && ptr->delete_trigger)
+ ptr->delete_trigger(ptr, key, key_length);
+
+error:
+ LIBMEMCACHED_MEMCACHED_DELETE_END();
+ return rc;
+}
+
+static inline memcached_return_t binary_delete(memcached_st *ptr,
+ unsigned int server_key,
+ const char *key,
+ size_t key_length,
+ uint8_t flush)
+{
+ protocol_binary_request_delete request= {.bytes= {0}};
+
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ if (ptr->flags.no_reply)
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
+ else
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
+ request.message.header.request.keylen= htons((uint16_t)key_length);
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t) key_length);
+
+ if (ptr->flags.use_udp && !flush)
+ {
+ size_t cmd_size= sizeof(request.bytes) + key_length;
+ if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+ return MEMCACHED_WRITE_FAILURE;
+ if (cmd_size + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+ memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
+ }
+
+ memcached_return_t rc= MEMCACHED_SUCCESS;
+
+ if ((memcached_do(&ptr->hosts[server_key], request.bytes,
+ sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
+ (memcached_io_write(&ptr->hosts[server_key], key,
+ key_length, (char) flush) == -1))
+ {
+ memcached_io_reset(&ptr->hosts[server_key]);
+ rc= MEMCACHED_WRITE_FAILURE;
+ }
+
+ unlikely (ptr->number_of_replicas > 0)
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
+
+ for (uint32_t x= 0; x < ptr->number_of_replicas; ++x)
+ {
+ ++server_key;
+ if (server_key == ptr->number_of_hosts)
+ server_key= 0;
+
+ memcached_server_st* server= &ptr->hosts[server_key];
+ if ((memcached_do(server, (const char*)request.bytes,
+ sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
+ (memcached_io_write(server, key, key_length, (char) flush) == -1))
+ memcached_io_reset(server);
+ else
+ memcached_server_response_decrement(server);
+ }
+ }
+
+ return rc;
+}
--- /dev/null
+#include "common.h"
+
+memcached_return_t memcached_do(memcached_server_st *ptr, const void *command,
+ size_t command_length, uint8_t with_flush)
+{
+ memcached_return_t rc;
+ ssize_t sent_length;
+
+ WATCHPOINT_ASSERT(command_length);
+ WATCHPOINT_ASSERT(command);
+
+ if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ERROR(rc);
+ return rc;
+ }
+
+ /*
+ ** Since non buffering ops in UDP mode dont check to make sure they will fit
+ ** before they start writing, if there is any data in buffer, clear it out,
+ ** otherwise we might get a partial write.
+ **/
+ if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH)
+ memcached_io_write(ptr, NULL, 0, 1);
+
+ sent_length= memcached_io_write(ptr, command, command_length, (char) with_flush);
+
+ if (sent_length == -1 || (size_t)sent_length != command_length)
+ rc= MEMCACHED_WRITE_FAILURE;
+ else if ((ptr->root->flags.no_reply) == 0)
+ memcached_server_response_increment(ptr);
+
+ return rc;
+}
--- /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= 0;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ size_t send_length;
+ uint32_t server_key;
+ uint32_t x;
+
+ unlikely (ptr->number_of_hosts == 0)
+ return MEMCACHED_NO_SERVERS;
+
+ for (server_key= 0; server_key < ptr->number_of_hosts; server_key++)
+ {
+ /* 256 I BELIEVE is the upper limit of slabs */
+ for (x= 0; x < 256; x++)
+ {
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "stats cachedump %u 0 0\r\n", x);
+
+ rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
+
+ unlikely (rc != MEMCACHED_SUCCESS)
+ goto error;
+
+ while (1)
+ {
+ uint32_t callback_counter;
+ rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+ if (rc == MEMCACHED_ITEM)
+ {
+ char *string_ptr, *end_ptr;
+ char *key;
+
+ string_ptr= buffer;
+ string_ptr+= 5; /* Move past ITEM */
+ for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
+ key= string_ptr;
+ key[(size_t)(end_ptr-string_ptr)]= 0;
+ for (callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++)
+ {
+ rc= (*callback[callback_counter])(ptr, key, (size_t)(end_ptr-string_ptr), context);
+ if (rc != MEMCACHED_SUCCESS)
+ break;
+ }
+ }
+ else if (rc == MEMCACHED_END)
+ break;
+ else if (rc == MEMCACHED_SERVER_ERROR || rc == MEMCACHED_CLIENT_ERROR)
+ {
+ /* If we try to request stats cachedump for a slab class that is too big
+ * the server will return an incorrect error message:
+ * "MEMCACHED_SERVER_ERROR failed to allocate memory"
+ * This isn't really a fatal error, so let's just skip it. I want to
+ * fix the return value from the memcached server to a CLIENT_ERROR,
+ * so let's add support for that as well right now.
+ */
+ rc= MEMCACHED_END;
+ break;
+ }
+ else
+ goto error;
+ }
+ }
+ }
+
+error:
+ if (rc == MEMCACHED_END)
+ return MEMCACHED_SUCCESS;
+ else
+ return rc;
+}
+
+memcached_return_t memcached_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
+{
+ /* No support for Binary protocol yet */
+ if (ptr->flags.binary_protocol)
+ return MEMCACHED_FAILURE;
+
+ return ascii_dump(ptr, callback, context, number_of_callbacks);
+}
+
--- /dev/null
+#include "common.h"
+
+char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
+ size_t *value_length,
+ uint32_t *flags,
+ memcached_return_t *error)
+{
+ memcached_result_st *result_buffer= &ptr->result;
+
+ unlikely (ptr->flags.use_udp)
+ {
+ *error= MEMCACHED_NOT_SUPPORTED;
+ return NULL;
+ }
+
+ result_buffer= memcached_fetch_result(ptr, result_buffer, error);
+
+ if (result_buffer == NULL || *error != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ASSERT(result_buffer == NULL);
+ *value_length= 0;
+ return NULL;
+ }
+
+ *value_length= memcached_string_length(&result_buffer->value);
+
+ if (key)
+ {
+ strncpy(key, result_buffer->key, result_buffer->key_length);
+ *key_length= result_buffer->key_length;
+ }
+
+ if (result_buffer->flags)
+ *flags= result_buffer->flags;
+ else
+ *flags= 0;
+
+ return memcached_string_c_copy(&result_buffer->value);
+}
+
+memcached_result_st *memcached_fetch_result(memcached_st *ptr,
+ memcached_result_st *result,
+ memcached_return_t *error)
+{
+ memcached_server_st *server;
+
+ unlikely (ptr->flags.use_udp)
+ {
+ *error= MEMCACHED_NOT_SUPPORTED;
+ return NULL;
+ }
+
+ if (result == NULL)
+ if ((result= memcached_result_create(ptr, NULL)) == NULL)
+ return NULL;
+
+ while ((server = memcached_io_get_readable_server(ptr)) != NULL)
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ *error= memcached_response(server, buffer, sizeof(buffer), result);
+
+ if (*error == MEMCACHED_SUCCESS)
+ return result;
+ else if (*error == MEMCACHED_END)
+ memcached_server_response_reset(server);
+ else if (*error != MEMCACHED_NOTFOUND)
+ break;
+ }
+
+ /* We have completed reading data */
+ if (memcached_is_allocated(result))
+ {
+ memcached_result_free(result);
+ }
+ else
+ {
+ memcached_string_reset(&result->value);
+ }
+
+ return NULL;
+}
+
+memcached_return_t memcached_fetch_execute(memcached_st *ptr,
+ memcached_execute_fn *callback,
+ void *context,
+ uint32_t number_of_callbacks)
+{
+ memcached_result_st *result= &ptr->result;
+ memcached_return_t rc= MEMCACHED_FAILURE;
+ unsigned int x;
+
+ while ((result= memcached_fetch_result(ptr, result, &rc)) != NULL)
+ {
+ if (rc == MEMCACHED_SUCCESS)
+ {
+ for (x= 0; x < number_of_callbacks; x++)
+ {
+ rc= (*callback[x])(ptr, result, context);
+ if (rc != MEMCACHED_SUCCESS)
+ break;
+ }
+ }
+ }
+ return rc;
+}
--- /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;
+
+ LIBMEMCACHED_MEMCACHED_FLUSH_START();
+ if (ptr->flags.binary_protocol)
+ rc= memcached_flush_binary(ptr, expiration);
+ else
+ rc= memcached_flush_textual(ptr, expiration);
+ LIBMEMCACHED_MEMCACHED_FLUSH_END();
+ return rc;
+}
+
+static memcached_return_t memcached_flush_textual(memcached_st *ptr,
+ time_t expiration)
+{
+ unsigned int x;
+ size_t send_length;
+ memcached_return_t rc;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+ unlikely (ptr->number_of_hosts == 0)
+ return MEMCACHED_NO_SERVERS;
+
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ bool no_reply= ptr->flags.no_reply;
+
+ if (expiration)
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "flush_all %llu%s\r\n",
+ (unsigned long long)expiration, no_reply ? " noreply" : "");
+ else
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "flush_all%s\r\n", no_reply ? " noreply" : "");
+
+ rc= memcached_do(&ptr->hosts[x], buffer, send_length, 1);
+
+ if (rc == MEMCACHED_SUCCESS && !no_reply)
+ (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t memcached_flush_binary(memcached_st *ptr,
+ time_t expiration)
+{
+ unsigned int x;
+ protocol_binary_request_flush request= {.bytes= {0}};
+
+ unlikely (ptr->number_of_hosts == 0)
+ return MEMCACHED_NO_SERVERS;
+
+ request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
+ request.message.header.request.extlen= 4;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl(request.message.header.request.extlen);
+ request.message.body.expiration= htonl((uint32_t) expiration);
+
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ if (ptr->flags.no_reply)
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ;
+ else
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
+ if (memcached_do(&ptr->hosts[x], request.bytes,
+ sizeof(request.bytes), 1) != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(&ptr->hosts[x]);
+ return MEMCACHED_WRITE_FAILURE;
+ }
+ }
+
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ if (memcached_server_response_count(&ptr->hosts[x]) > 0)
+ (void)memcached_response(&ptr->hosts[x], NULL, 0, NULL);
+ }
+
+ return MEMCACHED_SUCCESS;
+}
--- /dev/null
+#include "common.h"
+
+memcached_return_t memcached_flush_buffers(memcached_st *mem)
+{
+ memcached_return_t ret= MEMCACHED_SUCCESS;
+
+ for (uint32_t x= 0; x < mem->number_of_hosts; ++x)
+ if (mem->hosts[x].write_buffer_offset != 0)
+ {
+ if (mem->hosts[x].fd == -1 &&
+ (ret= memcached_connect(&mem->hosts[x])) != MEMCACHED_SUCCESS)
+ {
+ WATCHPOINT_ERROR(ret);
+ return ret;
+ }
+ if (memcached_io_write(&mem->hosts[x], NULL, 0, 1) == -1)
+ ret= MEMCACHED_SOME_ERRORS;
+ }
+
+ return ret;
+}
--- /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 *master_key,
+ size_t master_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ bool mget_mode);
+
+char *memcached_get_by_key(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char *key, size_t key_length,
+ size_t *value_length,
+ uint32_t *flags,
+ memcached_return_t *error)
+{
+ char *value;
+ size_t dummy_length;
+ uint32_t dummy_flags;
+ memcached_return_t dummy_error;
+
+ unlikely (ptr->flags.use_udp)
+ {
+ *error= MEMCACHED_NOT_SUPPORTED;
+ return NULL;
+ }
+
+ /* Request the key */
+ *error= memcached_mget_by_key_real(ptr, master_key, master_key_length,
+ (const char * const *)&key,
+ &key_length, 1, false);
+
+ value= memcached_fetch(ptr, NULL, NULL,
+ value_length, flags, error);
+ /* This is for historical reasons */
+ if (*error == MEMCACHED_END)
+ *error= MEMCACHED_NOTFOUND;
+
+ if (value == NULL)
+ {
+ if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND)
+ {
+ memcached_return_t rc;
+
+ memcached_result_reset(&ptr->result);
+ rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result);
+
+ /* On all failure drop to returning NULL */
+ if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
+ {
+ if (rc == MEMCACHED_BUFFERED)
+ {
+ uint64_t latch; /* We use latch to track the state of the original socket */
+ latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
+ if (latch == 0)
+ memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
+
+ rc= memcached_set(ptr, key, key_length,
+ memcached_result_value(&ptr->result),
+ memcached_result_length(&ptr->result),
+ 0, memcached_result_flags(&ptr->result));
+
+ if (rc == MEMCACHED_BUFFERED && latch == 0)
+ memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
+ }
+ else
+ {
+ rc= memcached_set(ptr, key, key_length,
+ memcached_result_value(&ptr->result),
+ memcached_result_length(&ptr->result),
+ 0, memcached_result_flags(&ptr->result));
+ }
+
+ if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
+ {
+ *error= rc;
+ *value_length= memcached_result_length(&ptr->result);
+ *flags= memcached_result_flags(&ptr->result);
+ return memcached_string_c_copy(&ptr->result.value);
+ }
+ }
+ }
+
+ return NULL;
+ }
+
+ (void)memcached_fetch(ptr, NULL, NULL,
+ &dummy_length, &dummy_flags,
+ &dummy_error);
+ WATCHPOINT_ASSERT(dummy_length == 0);
+
+ return value;
+}
+
+memcached_return_t memcached_mget(memcached_st *ptr,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys)
+{
+ return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
+}
+
+static memcached_return_t binary_mget_by_key(memcached_st *ptr,
+ unsigned int master_server_key,
+ bool is_master_key_set,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ bool mget_mode);
+
+static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ bool mget_mode)
+{
+ unsigned int x;
+ memcached_return_t rc= MEMCACHED_NOTFOUND;
+ const char *get_command= "get ";
+ uint8_t get_command_length= 4;
+ unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */
+ bool is_master_key_set= false;
+
+ unlikely (ptr->flags.use_udp)
+ return MEMCACHED_NOT_SUPPORTED;
+
+ LIBMEMCACHED_MEMCACHED_MGET_START();
+ ptr->cursor_server= 0;
+
+ if (number_of_keys == 0)
+ return MEMCACHED_NOTFOUND;
+
+ if (ptr->number_of_hosts == 0)
+ return MEMCACHED_NO_SERVERS;
+
+ if (ptr->flags.verify_key && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
+ return MEMCACHED_BAD_KEY_PROVIDED;
+
+ if (master_key && master_key_length)
+ {
+ if (ptr->flags.verify_key && (memcached_key_test((const char * const *)&master_key, &master_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+ return MEMCACHED_BAD_KEY_PROVIDED;
+ master_server_key= memcached_generate_hash(ptr, master_key, master_key_length);
+ is_master_key_set= true;
+ }
+
+ /*
+ Here is where we pay for the non-block API. We need to remove any data sitting
+ in the queue before we start our get.
+
+ It might be optimum to bounce the connection if count > some number.
+ */
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ if (memcached_server_response_count(&ptr->hosts[x]))
+ {
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+ if (ptr->flags.no_block)
+ (void)memcached_io_write(&ptr->hosts[x], NULL, 0, 1);
+
+ while(memcached_server_response_count(&ptr->hosts[x]))
+ (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
+ }
+ }
+
+ if (ptr->flags.binary_protocol)
+ return binary_mget_by_key(ptr, master_server_key, is_master_key_set, keys,
+ key_length, number_of_keys, mget_mode);
+
+ if (ptr->flags.support_cas)
+ {
+ get_command= "gets ";
+ get_command_length= 5;
+ }
+
+ /*
+ If a server fails we warn about errors and start all over with sending keys
+ to the server.
+ */
+ for (x= 0; x < number_of_keys; x++)
+ {
+ unsigned int server_key;
+
+ if (is_master_key_set)
+ server_key= master_server_key;
+ else
+ server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
+
+ if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
+ {
+ rc= memcached_connect(&ptr->hosts[server_key]);
+
+ if (rc != MEMCACHED_SUCCESS)
+ continue;
+
+ if ((memcached_io_write(&ptr->hosts[server_key], get_command, get_command_length, 0)) == -1)
+ {
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+ WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 0);
+ memcached_server_response_increment(&ptr->hosts[server_key]);
+ WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 1);
+ }
+
+ /* Only called when we have a prefix key */
+ if (ptr->prefix_key[0] != 0)
+ {
+ if ((memcached_io_write(&ptr->hosts[server_key], ptr->prefix_key, ptr->prefix_key_length, 0)) == -1)
+ {
+ memcached_server_response_reset(&ptr->hosts[server_key]);
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+ }
+
+ if ((memcached_io_write(&ptr->hosts[server_key], keys[x], key_length[x], 0)) == -1)
+ {
+ memcached_server_response_reset(&ptr->hosts[server_key]);
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+
+ if ((memcached_io_write(&ptr->hosts[server_key], " ", 1, 0)) == -1)
+ {
+ memcached_server_response_reset(&ptr->hosts[server_key]);
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+ }
+
+ /*
+ Should we muddle on if some servers are dead?
+ */
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ if (memcached_server_response_count(&ptr->hosts[x]))
+ {
+ /* We need to do something about non-connnected hosts in the future */
+ if ((memcached_io_write(&ptr->hosts[x], "\r\n", 2, 1)) == -1)
+ {
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+ }
+ }
+
+ LIBMEMCACHED_MEMCACHED_MGET_END();
+ return rc;
+}
+
+memcached_return_t memcached_mget_by_key(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys)
+{
+ return memcached_mget_by_key_real(ptr, master_key, master_key_length, keys,
+ key_length, number_of_keys, true);
+}
+
+memcached_return_t memcached_mget_execute(memcached_st *ptr,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ memcached_execute_fn *callback,
+ void *context,
+ unsigned int number_of_callbacks)
+{
+ return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length,
+ number_of_keys, callback,
+ context, number_of_callbacks);
+}
+
+memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ memcached_execute_fn *callback,
+ void *context,
+ unsigned int number_of_callbacks)
+{
+ if ((ptr->flags.binary_protocol) == 0)
+ return MEMCACHED_NOT_SUPPORTED;
+
+ memcached_return_t rc;
+ memcached_callback_st *original_callbacks= ptr->callbacks;
+ memcached_callback_st cb= {
+ .callback= callback,
+ .context= context,
+ .number_of_callback= number_of_callbacks
+ };
+
+ ptr->callbacks= &cb;
+ rc= memcached_mget_by_key(ptr, master_key, master_key_length, keys,
+ key_length, number_of_keys);
+ ptr->callbacks= original_callbacks;
+ return rc;
+}
+
+static memcached_return_t simple_binary_mget(memcached_st *ptr,
+ unsigned int master_server_key,
+ bool is_master_key_set,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys, bool mget_mode)
+{
+ memcached_return_t rc= MEMCACHED_NOTFOUND;
+ uint32_t x;
+
+ int flush= number_of_keys == 1;
+
+ /*
+ If a server fails we warn about errors and start all over with sending keys
+ to the server.
+ */
+ for (x= 0; x < number_of_keys; x++)
+ {
+ unsigned int server_key;
+
+ if (is_master_key_set)
+ server_key= master_server_key;
+ else
+ server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
+
+ if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
+ {
+ rc= memcached_connect(&ptr->hosts[server_key]);
+ if (rc != MEMCACHED_SUCCESS)
+ continue;
+ }
+
+ protocol_binary_request_getk request= {.bytes= {0}};
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ if (mget_mode)
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ;
+ else
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
+
+ memcached_return_t vk;
+ vk= memcached_validate_key_length(key_length[x],
+ ptr->flags.binary_protocol);
+ unlikely (vk != MEMCACHED_SUCCESS)
+ {
+ if (x > 0)
+ memcached_io_reset(&ptr->hosts[server_key]);
+ return vk;
+ }
+
+ request.message.header.request.keylen= htons((uint16_t)key_length[x]);
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ request.message.header.request.bodylen= htonl((uint32_t) key_length[x]);
+
+ if ((memcached_io_write(&ptr->hosts[server_key], request.bytes,
+ sizeof(request.bytes), 0) == -1) ||
+ (memcached_io_write(&ptr->hosts[server_key], keys[x],
+ key_length[x], (char) flush) == -1))
+ {
+ memcached_server_response_reset(&ptr->hosts[server_key]);
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+
+ /* We just want one pending response per server */
+ memcached_server_response_reset(&ptr->hosts[server_key]);
+ memcached_server_response_increment(&ptr->hosts[server_key]);
+ if ((x > 0 && x == ptr->io_key_prefetch) &&
+ memcached_flush_buffers(ptr) != MEMCACHED_SUCCESS)
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+
+ if (mget_mode)
+ {
+ /*
+ * Send a noop command to flush the buffers
+ */
+ protocol_binary_request_noop request= {.bytes= {0}};
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_NOOP;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ if (memcached_server_response_count(&ptr->hosts[x]))
+ {
+ if (memcached_io_write(&ptr->hosts[x], NULL, 0, 1) == -1)
+ {
+ memcached_server_response_reset(&ptr->hosts[x]);
+ memcached_io_reset(&ptr->hosts[x]);
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+
+ if (memcached_io_write(&ptr->hosts[x], request.bytes,
+ sizeof(request.bytes), 1) == -1)
+ {
+ memcached_server_response_reset(&ptr->hosts[x]);
+ memcached_io_reset(&ptr->hosts[x]);
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+ }
+ }
+
+
+ return rc;
+}
+
+static memcached_return_t replication_binary_mget(memcached_st *ptr,
+ uint32_t* hash,
+ bool* dead_servers,
+ const char *const *keys,
+ const size_t *key_length,
+ size_t number_of_keys)
+{
+ memcached_return_t rc= MEMCACHED_NOTFOUND;
+ uint32_t x, start= 0;
+ uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
+
+ if (randomize_read)
+ start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1);
+
+ /* Loop for each replica */
+ for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica)
+ {
+ bool success= true;
+
+ for (x= 0; x < number_of_keys; ++x)
+ {
+ if (hash[x] == ptr->number_of_hosts)
+ 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 >= ptr->number_of_hosts)
+ server -= ptr->number_of_hosts;
+
+ if (dead_servers[server])
+ continue;
+
+ if (memcached_server_response_count(&ptr->hosts[server]) == 0)
+ {
+ rc= memcached_connect(&ptr->hosts[server]);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(&ptr->hosts[server]);
+ dead_servers[server]= true;
+ success= false;
+ continue;
+ }
+ }
+
+ protocol_binary_request_getk request= {
+ .message.header.request= {
+ .magic= PROTOCOL_BINARY_REQ,
+ .opcode= PROTOCOL_BINARY_CMD_GETK,
+ .keylen= htons((uint16_t)key_length[x]),
+ .datatype= PROTOCOL_BINARY_RAW_BYTES,
+ .bodylen= htonl((uint32_t)key_length[x])
+ }
+ };
+
+ /*
+ * We need to disable buffering to actually know that the request was
+ * successfully sent to the server (so that we should expect a result
+ * back). It would be nice to do this in buffered mode, but then it
+ * would be complex to handle all error situations if we got to send
+ * some of the messages, and then we failed on writing out some others
+ * and we used the callback interface from memcached_mget_execute so
+ * that we might have processed some of the responses etc. For now,
+ * just make sure we work _correctly_
+ */
+ if ((memcached_io_write(&ptr->hosts[server], request.bytes,
+ sizeof(request.bytes), 0) == -1) ||
+ (memcached_io_write(&ptr->hosts[server], keys[x],
+ key_length[x], 1) == -1))
+ {
+ memcached_io_reset(&ptr->hosts[server]);
+ dead_servers[server]= true;
+ success= false;
+ continue;
+ }
+
+ memcached_server_response_increment(&ptr->hosts[server]);
+ hash[x]= ptr->number_of_hosts;
+ }
+
+ if (success)
+ break;
+ }
+
+ return rc;
+}
+
+static memcached_return_t binary_mget_by_key(memcached_st *ptr,
+ unsigned int master_server_key,
+ bool is_master_key_set,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ bool mget_mode)
+{
+ memcached_return_t rc;
+
+ if (ptr->number_of_replicas == 0)
+ {
+ rc= simple_binary_mget(ptr, master_server_key, is_master_key_set,
+ keys, key_length, number_of_keys, mget_mode);
+ }
+ else
+ {
+ uint32_t* hash;
+ bool* dead_servers;
+
+ hash= ptr->call_malloc(ptr, sizeof(uint32_t) * number_of_keys);
+ dead_servers= ptr->call_calloc(ptr, ptr->number_of_hosts, sizeof(bool));
+
+ if (hash == NULL || dead_servers == NULL)
+ {
+ ptr->call_free(ptr, hash);
+ ptr->call_free(ptr, dead_servers);
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ if (is_master_key_set)
+ for (unsigned int x= 0; x < number_of_keys; x++)
+ hash[x]= master_server_key;
+ else
+ for (unsigned int x= 0; x < number_of_keys; x++)
+ hash[x]= memcached_generate_hash(ptr, keys[x], key_length[x]);
+
+ rc= replication_binary_mget(ptr, hash, dead_servers, keys,
+ key_length, number_of_keys);
+
+ ptr->call_free(ptr, hash);
+ ptr->call_free(ptr, dead_servers);
+
+ return MEMCACHED_SUCCESS;
+ }
+
+ return rc;
+}
--- /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
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_GET_H
+#define LIBMEMCACHED_MEMCACHED_GET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Public defines */
+LIBMEMCACHED_API
+char *memcached_get(memcached_st *ptr,
+ const char *key, size_t key_length,
+ size_t *value_length,
+ uint32_t *flags,
+ memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_mget(memcached_st *ptr,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys);
+
+LIBMEMCACHED_API
+char *memcached_get_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ size_t *value_length,
+ uint32_t *flags,
+ memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_mget_by_key(memcached_st *ptr,
+ const char *master_key, size_t
+ master_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys);
+
+LIBMEMCACHED_API
+char *memcached_fetch(memcached_st *ptr,
+ char *key, size_t *key_length,
+ size_t *value_length, uint32_t *flags,
+ memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_result_st *memcached_fetch_result(memcached_st *ptr,
+ memcached_result_st *result,
+ memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_mget_execute(memcached_st *ptr,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ memcached_execute_fn *callback,
+ void *context,
+ unsigned int number_of_callbacks);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char * const *keys,
+ const size_t *key_length,
+ size_t number_of_keys,
+ memcached_execute_fn *callback,
+ void *context,
+ unsigned int number_of_callbacks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBMEMCACHED_MEMCACHED_GET_H */
--- /dev/null
+#include "common.h"
+
+
+/* Defines */
+static uint64_t FNV_64_INIT= UINT64_C(0xcbf29ce484222325);
+static uint64_t FNV_64_PRIME= UINT64_C(0x100000001b3);
+
+static uint32_t FNV_32_INIT= 2166136261UL;
+static uint32_t FNV_32_PRIME= 16777619;
+
+/* Prototypes */
+static uint32_t internal_generate_hash(const char *key, size_t key_length);
+static uint32_t internal_generate_md5(const char *key, size_t key_length);
+
+uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm)
+{
+ uint32_t hash= 1; /* Just here to remove compile warning */
+ uint32_t x= 0;
+
+ switch (hash_algorithm)
+ {
+ case MEMCACHED_HASH_DEFAULT:
+ hash= internal_generate_hash(key, key_length);
+ break;
+ case MEMCACHED_HASH_MD5:
+ hash= internal_generate_md5(key, key_length);
+ break;
+ case MEMCACHED_HASH_CRC:
+ hash= ((hash_crc32(key, key_length) >> 16) & 0x7fff);
+ if (hash == 0)
+ hash= 1;
+ break;
+ /* FNV hash'es lifted from Dustin Sallings work */
+ case MEMCACHED_HASH_FNV1_64:
+ {
+ /* Thanks to pierre@demartines.com for the pointer */
+ uint64_t temp_hash;
+
+ temp_hash= FNV_64_INIT;
+ for (x= 0; x < key_length; x++)
+ {
+ temp_hash *= FNV_64_PRIME;
+ temp_hash ^= (uint64_t)key[x];
+ }
+ hash= (uint32_t)temp_hash;
+ }
+ break;
+ case MEMCACHED_HASH_FNV1A_64:
+ {
+ hash= (uint32_t) FNV_64_INIT;
+ for (x= 0; x < key_length; x++)
+ {
+ uint32_t val= (uint32_t)key[x];
+ hash ^= val;
+ hash *= (uint32_t) FNV_64_PRIME;
+ }
+ }
+ break;
+ case MEMCACHED_HASH_FNV1_32:
+ {
+ hash= FNV_32_INIT;
+ for (x= 0; x < key_length; x++)
+ {
+ uint32_t val= (uint32_t)key[x];
+ hash *= FNV_32_PRIME;
+ hash ^= val;
+ }
+ }
+ break;
+ case MEMCACHED_HASH_FNV1A_32:
+ {
+ hash= FNV_32_INIT;
+ for (x= 0; x < key_length; x++)
+ {
+ uint32_t val= (uint32_t)key[x];
+ hash ^= val;
+ hash *= FNV_32_PRIME;
+ }
+ }
+ break;
+ case MEMCACHED_HASH_HSIEH:
+ {
+#ifdef HAVE_HSIEH_HASH
+ hash= hsieh_hash(key, key_length);
+#endif
+ break;
+ }
+ case MEMCACHED_HASH_MURMUR:
+ {
+ hash= murmur_hash(key, key_length);
+ break;
+ }
+ case MEMCACHED_HASH_JENKINS:
+ {
+ hash=jenkins_hash(key, key_length, 13);
+ break;
+ }
+ default:
+ {
+ WATCHPOINT_ASSERT(hash_algorithm);
+ break;
+ }
+ }
+ return hash;
+}
+
+uint32_t generate_hash(memcached_st *ptr, const char *key, size_t key_length)
+{
+ uint32_t hash= 1; /* Just here to remove compile warning */
+
+
+ WATCHPOINT_ASSERT(ptr->number_of_hosts);
+
+ if (ptr->number_of_hosts == 1)
+ return 0;
+
+ hash= memcached_generate_hash_value(key, key_length, ptr->hash);
+ WATCHPOINT_ASSERT(hash);
+ return hash;
+}
+
+static uint32_t dispatch_host(memcached_st *ptr, uint32_t hash)
+{
+ switch (ptr->distribution)
+ {
+ case MEMCACHED_DISTRIBUTION_CONSISTENT:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+ {
+ uint32_t num= ptr->continuum_points_counter;
+ WATCHPOINT_ASSERT(ptr->continuum);
+
+ hash= hash;
+ memcached_continuum_item_st *begin, *end, *left, *right, *middle;
+ begin= left= ptr->continuum;
+ end= right= ptr->continuum + num;
+
+ while (left < right)
+ {
+ middle= left + (right - left) / 2;
+ if (middle->value < hash)
+ left= middle + 1;
+ else
+ right= middle;
+ }
+ if (right == end)
+ right= begin;
+ return right->index;
+ }
+ case MEMCACHED_DISTRIBUTION_MODULA:
+ return hash % ptr->number_of_hosts;
+ case MEMCACHED_DISTRIBUTION_RANDOM:
+ return (uint32_t) random() % ptr->number_of_hosts;
+ default:
+ WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
+ return hash % ptr->number_of_hosts;
+ }
+
+ /* NOTREACHED */
+}
+
+/*
+ One day make this public, and have it return the actual memcached_server_st
+ to the calling application.
+*/
+uint32_t memcached_generate_hash(memcached_st *ptr, const char *key, size_t key_length)
+{
+ uint32_t hash= 1; /* Just here to remove compile warning */
+
+ WATCHPOINT_ASSERT(ptr->number_of_hosts);
+
+ if (ptr->number_of_hosts == 1)
+ return 0;
+
+ if (ptr->flags.hash_with_prefix_key)
+ {
+ size_t temp_length= ptr->prefix_key_length + key_length;
+ char temp[temp_length];
+
+ if (temp_length > MEMCACHED_MAX_KEY -1)
+ return 0;
+
+ strncpy(temp, ptr->prefix_key, ptr->prefix_key_length);
+ strncpy(temp + ptr->prefix_key_length, key, key_length);
+ hash= generate_hash(ptr, temp, temp_length);
+ }
+ else
+ {
+ hash= generate_hash(ptr, key, key_length);
+ }
+
+ WATCHPOINT_ASSERT(hash);
+
+ if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS) && ptr->next_distribution_rebuild) {
+ struct timeval now;
+
+ if (gettimeofday(&now, NULL) == 0 &&
+ now.tv_sec > ptr->next_distribution_rebuild)
+ run_distribution(ptr);
+ }
+
+ return dispatch_host(ptr, hash);
+}
+
+static uint32_t internal_generate_hash(const char *key, size_t key_length)
+{
+ const char *ptr= key;
+ uint32_t value= 0;
+
+ while (key_length--)
+ {
+ uint32_t val= (uint32_t) *ptr++;
+ value += val;
+ value += (value << 10);
+ value ^= (value >> 6);
+ }
+ value += (value << 3);
+ value ^= (value >> 11);
+ value += (value << 15);
+
+ return value == 0 ? 1 : (uint32_t) value;
+}
+
+static uint32_t internal_generate_md5(const char *key, size_t key_length)
+{
+ unsigned char results[16];
+
+ md5_signature((unsigned char*)key, (unsigned int)key_length, results);
+
+ return ((uint32_t) (results[3] & 0xFF) << 24)
+ | ((uint32_t) (results[2] & 0xFF) << 16)
+ | ((uint32_t) (results[1] & 0xFF) << 8)
+ | (results[0] & 0xFF);
+}
--- /dev/null
+#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);
+memcached_return_t update_continuum(memcached_st *ptr);
+
+static int compare_servers(const void *p1, const void *p2)
+{
+ int return_value;
+ memcached_server_st *a= (memcached_server_st *)p1;
+ memcached_server_st *b= (memcached_server_st *)p2;
+
+ return_value= strcmp(a->hostname, b->hostname);
+
+ if (return_value == 0)
+ {
+ return_value= (int) (a->port - b->port);
+ }
+
+ return return_value;
+}
+
+static void sort_hosts(memcached_st *ptr)
+{
+ if (ptr->number_of_hosts)
+ {
+ qsort(ptr->hosts, ptr->number_of_hosts, sizeof(memcached_server_st), compare_servers);
+ ptr->hosts[0].count= (uint16_t) ptr->number_of_hosts;
+ }
+}
+
+
+memcached_return_t run_distribution(memcached_st *ptr)
+{
+ switch (ptr->distribution)
+ {
+ case MEMCACHED_DISTRIBUTION_CONSISTENT:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+ return update_continuum(ptr);
+ case MEMCACHED_DISTRIBUTION_MODULA:
+ if (ptr->flags.use_sort_hosts)
+ sort_hosts(ptr);
+ break;
+ case MEMCACHED_DISTRIBUTION_RANDOM:
+ break;
+ default:
+ WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
+ }
+
+ ptr->last_disconnected_server = NULL;
+
+ return MEMCACHED_SUCCESS;
+}
+
+void server_list_free(memcached_st *ptr, memcached_server_st *servers)
+{
+ unsigned int x;
+
+ if (servers == NULL)
+ return;
+
+ for (x= 0; x < servers->count; x++)
+ if (servers[x].address_info)
+ {
+ freeaddrinfo(servers[x].address_info);
+ servers[x].address_info= NULL;
+ }
+
+ if (ptr)
+ ptr->call_free(ptr, servers);
+ else
+ free(servers);
+}
+
+static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment)
+{
+ unsigned char results[16];
+
+ md5_signature((unsigned char*)key, key_length, results);
+ return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
+ | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
+ | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
+ | (results[0 + alignment * 4] & 0xFF);
+}
+
+static int continuum_item_cmp(const void *t1, const void *t2)
+{
+ memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1;
+ memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2;
+
+ /* Why 153? Hmmm... */
+ WATCHPOINT_ASSERT(ct1->value != 153);
+ if (ct1->value == ct2->value)
+ return 0;
+ else if (ct1->value > ct2->value)
+ return 1;
+ else
+ return -1;
+}
+
+memcached_return_t update_continuum(memcached_st *ptr)
+{
+ uint32_t host_index;
+ uint32_t continuum_index= 0;
+ uint32_t value;
+ memcached_server_st *list;
+ uint32_t pointer_index;
+ uint32_t pointer_counter= 0;
+ uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
+ uint32_t pointer_per_hash= 1;
+ uint64_t total_weight= 0;
+ uint64_t is_ketama_weighted= 0;
+ uint64_t is_auto_ejecting= 0;
+ uint32_t points_per_server= 0;
+ uint32_t live_servers= 0;
+ struct timeval now;
+
+ if (gettimeofday(&now, NULL) != 0)
+ {
+ ptr->cached_errno = errno;
+ return MEMCACHED_ERRNO;
+ }
+
+ list = ptr->hosts;
+
+ /* count live servers (those without a retry delay set) */
+ is_auto_ejecting= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
+ if (is_auto_ejecting)
+ {
+ live_servers= 0;
+ ptr->next_distribution_rebuild= 0;
+ for (host_index= 0; host_index < ptr->number_of_hosts; ++host_index)
+ {
+ if (list[host_index].next_retry <= now.tv_sec)
+ live_servers++;
+ else
+ {
+ if (ptr->next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->next_distribution_rebuild)
+ ptr->next_distribution_rebuild= list[host_index].next_retry;
+ }
+ }
+ }
+ else
+ live_servers= ptr->number_of_hosts;
+
+ is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+ points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER);
+
+ if (live_servers == 0)
+ return MEMCACHED_SUCCESS;
+
+ if (live_servers > ptr->continuum_count)
+ {
+ memcached_continuum_item_st *new_ptr;
+
+ new_ptr= ptr->call_realloc(ptr, ptr->continuum,
+ sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);
+
+ if (new_ptr == 0)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ ptr->continuum= new_ptr;
+ ptr->continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
+ }
+
+ if (is_ketama_weighted)
+ {
+ for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index)
+ {
+ if (list[host_index].weight == 0)
+ {
+ list[host_index].weight = 1;
+ }
+ if (!is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
+ total_weight += list[host_index].weight;
+ }
+ }
+
+ for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index)
+ {
+ if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec)
+ continue;
+
+ if (is_ketama_weighted)
+ {
+ float pct = (float)list[host_index].weight / (float)total_weight;
+ pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
+ pointer_per_hash= 4;
+#ifdef DEBUG
+ printf("ketama_weighted:%s|%d|%llu|%u\n",
+ list[host_index].hostname,
+ list[host_index].port,
+ (unsigned long long)list[host_index].weight,
+ pointer_per_server);
+#endif
+ }
+
+
+ if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY)
+ {
+ for (pointer_index= 0;
+ pointer_index < pointer_per_server / pointer_per_hash;
+ pointer_index++)
+ {
+ char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
+ size_t sort_host_length;
+
+ // Spymemcached ketema key format is: hostname/ip:port-index
+ // If hostname is not available then: /ip:port-index
+ sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+ "/%s:%d-%d",
+ list[host_index].hostname,
+ list[host_index].port,
+ pointer_index);
+#ifdef DEBUG
+ printf("update_continuum: key is %s\n", sort_host);
+#endif
+
+ WATCHPOINT_ASSERT(sort_host_length);
+
+ if (is_ketama_weighted)
+ {
+ unsigned int i;
+ for (i = 0; i < pointer_per_hash; i++)
+ {
+ value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
+ ptr->continuum[continuum_index].index= host_index;
+ ptr->continuum[continuum_index++].value= value;
+ }
+ }
+ else
+ {
+ value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum);
+ ptr->continuum[continuum_index].index= host_index;
+ ptr->continuum[continuum_index++].value= value;
+ }
+ }
+ }
+ else
+ {
+ for (pointer_index= 1;
+ pointer_index <= pointer_per_server / pointer_per_hash;
+ pointer_index++)
+ {
+ char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
+ size_t sort_host_length;
+
+ if (list[host_index].port == MEMCACHED_DEFAULT_PORT)
+ {
+ sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+ "%s-%d",
+ list[host_index].hostname,
+ pointer_index - 1);
+ }
+ else
+ {
+ sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+ "%s:%d-%d",
+ list[host_index].hostname,
+ list[host_index].port, pointer_index - 1);
+ }
+
+ WATCHPOINT_ASSERT(sort_host_length);
+
+ if (is_ketama_weighted)
+ {
+ unsigned int i;
+ for (i = 0; i < pointer_per_hash; i++)
+ {
+ value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
+ ptr->continuum[continuum_index].index= host_index;
+ ptr->continuum[continuum_index++].value= value;
+ }
+ }
+ else
+ {
+ value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum);
+ ptr->continuum[continuum_index].index= host_index;
+ ptr->continuum[continuum_index++].value= value;
+ }
+ }
+ }
+
+ pointer_counter+= pointer_per_server;
+ }
+
+ WATCHPOINT_ASSERT(ptr);
+ WATCHPOINT_ASSERT(ptr->continuum);
+ WATCHPOINT_ASSERT(ptr->number_of_hosts * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE);
+ ptr->continuum_points_counter= pointer_counter;
+ qsort(ptr->continuum, ptr->continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
+
+#ifdef DEBUG
+ for (pointer_index= 0; ptr->number_of_hosts && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
+ {
+ WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value);
+ }
+#endif
+
+ return MEMCACHED_SUCCESS;
+}
+
+
+memcached_return_t memcached_server_push(memcached_st *ptr, memcached_server_st *list)
+{
+ unsigned int x;
+ uint16_t count;
+ memcached_server_st *new_host_list;
+
+ if (!list)
+ return MEMCACHED_SUCCESS;
+
+ count= list[0].count;
+ new_host_list= ptr->call_realloc(ptr, ptr->hosts,
+ sizeof(memcached_server_st) * (count + ptr->number_of_hosts));
+
+ if (!new_host_list)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ ptr->hosts= new_host_list;
+
+ for (x= 0; x < count; x++)
+ {
+ if ((ptr->flags.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);
+ memcached_server_create(ptr, &ptr->hosts[ptr->number_of_hosts]);
+ /* TODO check return type */
+ (void)memcached_server_create_with(ptr, &ptr->hosts[ptr->number_of_hosts], list[x].hostname,
+ list[x].port, list[x].weight, list[x].type);
+ ptr->number_of_hosts++;
+ }
+ ptr->hosts[0].count= (uint16_t) ptr->number_of_hosts;
+
+ return run_distribution(ptr);
+}
+
+memcached_return_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;
+
+ if ( (ptr->flags.use_udp && type != MEMCACHED_CONNECTION_UDP)
+ || ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) )
+ return MEMCACHED_INVALID_HOST_PROTOCOL;
+
+ new_host_list= ptr->call_realloc(ptr, ptr->hosts,
+ sizeof(memcached_server_st) * (ptr->number_of_hosts+1));
+
+ if (new_host_list == NULL)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ ptr->hosts= new_host_list;
+
+ /* TODO: Check return type */
+ (void)memcached_server_create_with(ptr, &ptr->hosts[ptr->number_of_hosts], hostname, port, weight, type);
+ ptr->number_of_hosts++;
+ ptr->hosts[0].count= (uint16_t) ptr->number_of_hosts;
+
+ return run_distribution(ptr);
+}
+
+memcached_return_t memcached_server_remove(memcached_server_st *st_ptr)
+{
+ uint32_t x, host_index;
+ memcached_st *ptr= st_ptr->root;
+ memcached_server_st *list= ptr->hosts;
+
+ for (x= 0, host_index= 0; x < ptr->number_of_hosts; x++)
+ {
+ if (strncmp(list[x].hostname, st_ptr->hostname, MEMCACHED_MAX_HOST_LENGTH) != 0 || list[x].port != st_ptr->port)
+ {
+ if (host_index != x)
+ memcpy(list+host_index, list+x, sizeof(memcached_server_st));
+ host_index++;
+ }
+ }
+ ptr->number_of_hosts= host_index;
+
+ if (st_ptr->address_info)
+ {
+ freeaddrinfo(st_ptr->address_info);
+ st_ptr->address_info= NULL;
+ }
+ run_distribution(ptr);
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_server_st *memcached_server_list_append(memcached_server_st *ptr,
+ const char *hostname, in_port_t port,
+ memcached_return_t *error)
+{
+ return memcached_server_list_append_with_weight(ptr, hostname, port, 0, error);
+}
+
+memcached_server_st *memcached_server_list_append_with_weight(memcached_server_st *ptr,
+ const char *hostname, in_port_t port,
+ uint32_t weight,
+ memcached_return_t *error)
+{
+ unsigned int count;
+ memcached_server_st *new_host_list;
+
+ if (hostname == NULL || error == NULL)
+ return NULL;
+
+ if (!port)
+ port= MEMCACHED_DEFAULT_PORT;
+
+ /* Increment count for hosts */
+ count= 1;
+ if (ptr != NULL)
+ {
+ count+= ptr[0].count;
+ }
+
+ new_host_list= (memcached_server_st *)realloc(ptr, sizeof(memcached_server_st) * count);
+ if (!new_host_list)
+ {
+ *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return NULL;
+ }
+
+ /* TODO: Check return type */
+ memcached_server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, MEMCACHED_CONNECTION_TCP);
+
+ /* Backwards compatibility hack */
+ new_host_list[0].count= (uint16_t) count;
+
+ *error= MEMCACHED_SUCCESS;
+ return new_host_list;
+}
+
+unsigned int memcached_server_list_count(memcached_server_st *ptr)
+{
+ if (ptr == NULL)
+ return 0;
+
+ return ptr[0].count;
+}
+
+void memcached_server_list_free(memcached_server_st *ptr)
+{
+ server_list_free(NULL, ptr);
+}
--- /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: Internal functions used by the library. Not for public use!
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_INTERNAL_H
+#define LIBMEMCACHED_MEMCACHED_INTERNAL_H
+
+#if defined(BUILDING_LIBMEMCACHED)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_LOCAL
+void libmemcached_free(memcached_st *ptr, void *mem);
+LIBMEMCACHED_LOCAL
+void *libmemcached_malloc(memcached_st *ptr, const size_t size);
+LIBMEMCACHED_LOCAL
+void *libmemcached_realloc(memcached_st *ptr, void *mem, const size_t size);
+LIBMEMCACHED_LOCAL
+void *libmemcached_calloc(memcached_st *ptr, size_t nelem, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BUILDING_LIBMEMCACHED */
+#endif /* LIBMEMCACHED_MEMCACHED_INTERNAL_H */
--- /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: Server IO, Not public!
+ *
+ */
+
+
+#include "common.h"
+#include <sys/select.h>
+#include <poll.h>
+
+typedef enum {
+ MEM_READ,
+ MEM_WRITE
+} memc_read_or_write;
+
+static ssize_t io_flush(memcached_server_st *ptr, memcached_return_t *error);
+static void increment_udp_message_id(memcached_server_st *ptr);
+
+static memcached_return_t io_wait(memcached_server_st *ptr,
+ memc_read_or_write read_or_write)
+{
+ struct pollfd fds= {
+ .fd= ptr->fd,
+ .events = POLLIN
+ };
+ int error;
+
+ unlikely (read_or_write == MEM_WRITE) /* write */
+ fds.events= POLLOUT;
+
+ /*
+ ** We are going to block on write, but at least on Solaris we might block
+ ** on write if we haven't read anything from our input buffer..
+ ** Try to purge the input buffer if we don't do any flow control in the
+ ** application layer (just sending a lot of data etc)
+ ** The test is moved down in the purge function to avoid duplication of
+ ** the test.
+ */
+ if (read_or_write == MEM_WRITE)
+ {
+ memcached_return_t rc= memcached_purge(ptr);
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
+ return MEMCACHED_FAILURE;
+ }
+
+ int timeout= ptr->root->poll_timeout;
+ if (ptr->root->flags.no_block == false)
+ timeout= -1;
+
+ error= poll(&fds, 1, timeout);
+
+ if (error == 1)
+ return MEMCACHED_SUCCESS;
+ else if (error == 0)
+ return MEMCACHED_TIMEOUT;
+
+ /* Imposssible for anything other then -1 */
+ WATCHPOINT_ASSERT(error == -1);
+ memcached_quit_server(ptr, 1);
+
+ return MEMCACHED_FAILURE;
+}
+
+/**
+ * Try to fill the input buffer for a server with as much
+ * data as possible.
+ *
+ * @param ptr the server to pack
+ */
+static bool repack_input_buffer(memcached_server_st *ptr)
+{
+ if (ptr->read_ptr != ptr->read_buffer)
+ {
+ /* Move all of the data to the beginning of the buffer so
+ ** that we can fit more data into the buffer...
+ */
+ memmove(ptr->read_buffer, ptr->read_ptr, ptr->read_buffer_length);
+ ptr->read_ptr= ptr->read_buffer;
+ ptr->read_data_length= ptr->read_buffer_length;
+ }
+
+ /* There is room in the buffer, try to fill it! */
+ if (ptr->read_buffer_length != MEMCACHED_MAX_BUFFER)
+ {
+ /* Just try a single read to grab what's available */
+ ssize_t nr= read(ptr->fd,
+ ptr->read_ptr + ptr->read_data_length,
+ MEMCACHED_MAX_BUFFER - ptr->read_data_length);
+
+ if (nr > 0)
+ {
+ ptr->read_data_length+= (size_t)nr;
+ ptr->read_buffer_length+= (size_t)nr;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * If the we have callbacks connected to this server structure
+ * we may start process the input queue and fire the callbacks
+ * for the incomming messages. This function is _only_ called
+ * when the input buffer is full, so that we _know_ that we have
+ * at least _one_ message to process.
+ *
+ * @param ptr the server to star processing iput messages for
+ * @return true if we processed anything, false otherwise
+ */
+static bool process_input_buffer(memcached_server_st *ptr)
+{
+ /*
+ ** We might be able to process some of the response messages if we
+ ** have a callback set up
+ */
+ if (ptr->root->callbacks != NULL && ptr->root->flags.use_udp == false)
+ {
+ /*
+ * We might have responses... try to read them out and fire
+ * callbacks
+ */
+ memcached_callback_st cb= *ptr->root->callbacks;
+
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ memcached_return_t error;
+ error= memcached_response(ptr, buffer, sizeof(buffer),
+ &ptr->root->result);
+ if (error == MEMCACHED_SUCCESS)
+ {
+ for (unsigned int x= 0; x < cb.number_of_callback; x++)
+ {
+ error= (*cb.callback[x])(ptr->root, &ptr->root->result, cb.context);
+ if (error != MEMCACHED_SUCCESS)
+ break;
+ }
+
+ /* @todo what should I do with the error message??? */
+ }
+ /* @todo what should I do with other error messages?? */
+ return true;
+ }
+
+ return false;
+}
+
+#ifdef UNUSED
+void memcached_io_preread(memcached_st *ptr)
+{
+ unsigned int x;
+
+ return;
+
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ if (memcached_server_response_count(ptr, x) &&
+ ptr->hosts[x].read_data_length < MEMCACHED_MAX_BUFFER )
+ {
+ size_t data_read;
+
+ data_read= read(ptr->hosts[x].fd,
+ ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length,
+ MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length);
+ if (data_read == -1)
+ continue;
+
+ ptr->hosts[x].read_buffer_length+= data_read;
+ ptr->hosts[x].read_data_length+= data_read;
+ }
+ }
+}
+#endif
+
+memcached_return_t memcached_io_read(memcached_server_st *ptr,
+ void *buffer, size_t length, ssize_t *nread)
+{
+ char *buffer_ptr;
+
+ buffer_ptr= buffer;
+
+ while (length)
+ {
+ if (!ptr->read_buffer_length)
+ {
+ ssize_t data_read;
+
+ while (1)
+ {
+ data_read= read(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER);
+ if (data_read > 0)
+ break;
+ else if (data_read == -1)
+ {
+ ptr->cached_errno= errno;
+ memcached_return_t rc= MEMCACHED_UNKNOWN_READ_FAILURE;
+ switch (errno)
+ {
+ case EAGAIN:
+ case EINTR:
+ if ((rc= io_wait(ptr, MEM_READ)) == MEMCACHED_SUCCESS)
+ continue;
+ /* fall through */
+
+ default:
+ {
+ memcached_quit_server(ptr, 1);
+ *nread= -1;
+ return rc;
+ }
+ }
+ }
+ else
+ {
+ /*
+ EOF. Any data received so far is incomplete
+ so discard it. This always reads by byte in case of TCP
+ and protocol enforcement happens at memcached_response()
+ looking for '\n'. We do not care for UDB which requests 8 bytes
+ at once. Generally, this means that connection went away. Since
+ for blocking I/O we do not return 0 and for non-blocking case
+ it will return EGAIN if data is not immediatly available.
+ */
+ memcached_quit_server(ptr, 1);
+ *nread= -1;
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ }
+
+ ptr->io_bytes_sent = 0;
+ ptr->read_data_length= (size_t) data_read;
+ ptr->read_buffer_length= (size_t) data_read;
+ ptr->read_ptr= ptr->read_buffer;
+ }
+
+ if (length > 1)
+ {
+ size_t difference;
+
+ difference= (length > ptr->read_buffer_length) ? ptr->read_buffer_length : length;
+
+ memcpy(buffer_ptr, ptr->read_ptr, difference);
+ length -= difference;
+ ptr->read_ptr+= difference;
+ ptr->read_buffer_length-= difference;
+ buffer_ptr+= difference;
+ }
+ else
+ {
+ *buffer_ptr= *ptr->read_ptr;
+ ptr->read_ptr++;
+ ptr->read_buffer_length--;
+ buffer_ptr++;
+ break;
+ }
+ }
+
+ ptr->server_failure_counter= 0;
+ *nread = (ssize_t)(buffer_ptr - (char*)buffer);
+ return MEMCACHED_SUCCESS;
+}
+
+ssize_t memcached_io_write(memcached_server_st *ptr,
+ const void *buffer, size_t length, char with_flush)
+{
+ size_t original_length;
+ const char* buffer_ptr;
+
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+
+ original_length= length;
+ buffer_ptr= buffer;
+
+ while (length)
+ {
+ char *write_ptr;
+ size_t should_write;
+ size_t buffer_end;
+
+ if (ptr->type == MEMCACHED_CONNECTION_UDP)
+ {
+ //UDP does not support partial writes
+ buffer_end= MAX_UDP_DATAGRAM_LENGTH;
+ should_write= length;
+ if (ptr->write_buffer_offset + should_write > buffer_end)
+ return -1;
+ }
+ else
+ {
+ buffer_end= MEMCACHED_MAX_BUFFER;
+ should_write= buffer_end - ptr->write_buffer_offset;
+ should_write= (should_write < length) ? should_write : length;
+ }
+
+ write_ptr= ptr->write_buffer + ptr->write_buffer_offset;
+ memcpy(write_ptr, buffer_ptr, should_write);
+ ptr->write_buffer_offset+= should_write;
+ buffer_ptr+= should_write;
+ length-= should_write;
+
+ if (ptr->write_buffer_offset == buffer_end && ptr->type != MEMCACHED_CONNECTION_UDP)
+ {
+ memcached_return_t rc;
+ ssize_t sent_length;
+
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+ sent_length= io_flush(ptr, &rc);
+ if (sent_length == -1)
+ return -1;
+
+ /* If io_flush calls memcached_purge, sent_length may be 0 */
+ unlikely (sent_length != 0)
+ {
+ WATCHPOINT_ASSERT(sent_length == (ssize_t)buffer_end);
+ }
+ }
+ }
+
+ if (with_flush)
+ {
+ memcached_return_t rc;
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+ if (io_flush(ptr, &rc) == -1)
+ return -1;
+ }
+
+ return (ssize_t) original_length;
+}
+
+memcached_return_t memcached_io_close(memcached_server_st *ptr)
+{
+ int r;
+
+ if (ptr->fd == -1)
+ return MEMCACHED_SUCCESS;
+
+ /* in case of death shutdown to avoid blocking at close() */
+ if (1)
+ {
+ r= shutdown(ptr->fd, SHUT_RDWR);
+
+#ifdef DEBUG
+ if (r && errno != ENOTCONN)
+ {
+ WATCHPOINT_NUMBER(ptr->fd);
+ WATCHPOINT_ERRNO(errno);
+ WATCHPOINT_ASSERT(errno);
+ }
+#endif
+ }
+
+ r= close(ptr->fd);
+#ifdef DEBUG
+ if (r != 0)
+ WATCHPOINT_ERRNO(errno);
+#endif
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_server_st *memcached_io_get_readable_server(memcached_st *memc)
+{
+#define MAX_SERVERS_TO_POLL 100
+ struct pollfd fds[MAX_SERVERS_TO_POLL];
+ unsigned int host_index= 0;
+
+ for (unsigned int x= 0;
+ x< memc->number_of_hosts && host_index < MAX_SERVERS_TO_POLL;
+ ++x)
+ {
+ if (memc->hosts[x].read_buffer_length > 0) /* I have data in the buffer */
+ return &memc->hosts[x];
+
+ if (memcached_server_response_count(&memc->hosts[x]) > 0)
+ {
+ fds[host_index].events = POLLIN;
+ fds[host_index].revents = 0;
+ fds[host_index].fd = memc->hosts[x].fd;
+ ++host_index;
+ }
+ }
+
+ if (host_index < 2)
+ {
+ /* We have 0 or 1 server with pending events.. */
+ for (unsigned int x= 0; x< memc->number_of_hosts; ++x)
+ if (memcached_server_response_count(&memc->hosts[x]) > 0)
+ return &memc->hosts[x];
+
+ return NULL;
+ }
+
+ int err= poll(fds, host_index, memc->poll_timeout);
+ switch (err) {
+ case -1:
+ memc->cached_errno = errno;
+ /* FALLTHROUGH */
+ case 0:
+ break;
+ default:
+ for (unsigned int x= 0; x < host_index; ++x)
+ if (fds[x].revents & POLLIN)
+ for (unsigned int y= 0; y < memc->number_of_hosts; ++y)
+ if (memc->hosts[y].fd == fds[x].fd)
+ return &memc->hosts[y];
+ }
+
+ return NULL;
+}
+
+static ssize_t io_flush(memcached_server_st *ptr,
+ memcached_return_t *error)
+{
+ /*
+ ** We might want to purge the input buffer if we haven't consumed
+ ** any output yet... The test for the limits is the purge is inline
+ ** in the purge function to avoid duplicating the logic..
+ */
+ {
+ memcached_return_t rc;
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+ rc= memcached_purge(ptr);
+
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
+ return -1;
+ }
+ ssize_t sent_length;
+ size_t return_length;
+ char *local_write_ptr= ptr->write_buffer;
+ size_t write_length= ptr->write_buffer_offset;
+
+ *error= MEMCACHED_SUCCESS;
+
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+
+ // UDP Sanity check, make sure that we are not sending somthing too big
+ if (ptr->type == MEMCACHED_CONNECTION_UDP && write_length > MAX_UDP_DATAGRAM_LENGTH)
+ return -1;
+
+ if (ptr->write_buffer_offset == 0 || (ptr->type == MEMCACHED_CONNECTION_UDP
+ && ptr->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH))
+ return 0;
+
+ /* Looking for memory overflows */
+#if defined(DEBUG)
+ if (write_length == MEMCACHED_MAX_BUFFER)
+ WATCHPOINT_ASSERT(ptr->write_buffer == local_write_ptr);
+ WATCHPOINT_ASSERT((ptr->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length));
+#endif
+
+ return_length= 0;
+ while (write_length)
+ {
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+ WATCHPOINT_ASSERT(write_length > 0);
+ sent_length= 0;
+ if (ptr->type == MEMCACHED_CONNECTION_UDP)
+ increment_udp_message_id(ptr);
+ sent_length= write(ptr->fd, local_write_ptr, write_length);
+
+ if (sent_length == -1)
+ {
+ ptr->cached_errno= errno;
+ switch (errno)
+ {
+ case ENOBUFS:
+ continue;
+ case EAGAIN:
+ {
+ /*
+ * We may be blocked on write because the input buffer
+ * is full. Let's check if we have room in our input
+ * buffer for more data and retry the write before
+ * waiting..
+ */
+ if (repack_input_buffer(ptr) ||
+ process_input_buffer(ptr))
+ continue;
+
+ memcached_return_t rc;
+ rc= io_wait(ptr, MEM_WRITE);
+
+ if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_TIMEOUT)
+ continue;
+
+ memcached_quit_server(ptr, 1);
+ return -1;
+ }
+ default:
+ memcached_quit_server(ptr, 1);
+ *error= MEMCACHED_ERRNO;
+ return -1;
+ }
+ }
+
+ if (ptr->type == MEMCACHED_CONNECTION_UDP &&
+ (size_t)sent_length != write_length)
+ {
+ memcached_quit_server(ptr, 1);
+ return -1;
+ }
+
+ ptr->io_bytes_sent += (uint32_t) sent_length;
+
+ local_write_ptr+= sent_length;
+ write_length-= (uint32_t) sent_length;
+ return_length+= (uint32_t) sent_length;
+ }
+
+ WATCHPOINT_ASSERT(write_length == 0);
+ // Need to study this assert() WATCHPOINT_ASSERT(return_length ==
+ // ptr->write_buffer_offset);
+
+ // if we are a udp server, the begining of the buffer is reserverd for
+ // the upd frame header
+ if (ptr->type == MEMCACHED_CONNECTION_UDP)
+ ptr->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
+ else
+ ptr->write_buffer_offset= 0;
+
+ return (ssize_t) return_length;
+}
+
+/*
+ Eventually we will just kill off the server with the problem.
+*/
+void memcached_io_reset(memcached_server_st *ptr)
+{
+ memcached_quit_server(ptr, 1);
+}
+
+/**
+ * Read a given number of bytes from the server and place it into a specific
+ * buffer. Reset the IO channel on this server if an error occurs.
+ */
+memcached_return_t memcached_safe_read(memcached_server_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_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_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_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
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Server IO, Not public!
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_IO_H
+#define LIBMEMCACHED_MEMCACHED_IO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(BUILDING_LIBMEMCACHED)
+
+#include "libmemcached/memcached.h"
+
+#define MAX_UDP_DATAGRAM_LENGTH 1400
+#define UDP_DATAGRAM_HEADER_LENGTH 8
+#define UDP_REQUEST_ID_MSG_SIG_DIGITS 10
+#define UDP_REQUEST_ID_THREAD_MASK 0xFFFF << UDP_REQUEST_ID_MSG_SIG_DIGITS
+#define get_udp_datagram_request_id(A) ntohs((A)->request_id)
+#define get_udp_datagram_seq_num(A) ntohs((A)->sequence_number)
+#define get_udp_datagram_num_datagrams(A) ntohs((A)->num_datagrams)
+#define get_msg_num_from_request_id(A) ( (A) & (~(UDP_REQUEST_ID_THREAD_MASK)) )
+#define get_thread_id_from_request_id(A) ( (A) & (UDP_REQUEST_ID_THREAD_MASK) ) >> UDP_REQUEST_ID_MSG_SIG_DIGITS
+#define generate_udp_request_thread_id(A) (A) << UDP_REQUEST_ID_MSG_SIG_DIGITS
+#define UDP_REQUEST_ID_MAX_THREAD_ID get_thread_id_from_request_id(0xFFFF)
+
+struct udp_datagram_header_st {
+ uint16_t request_id;
+ uint16_t sequence_number;
+ uint16_t num_datagrams;
+ uint16_t reserved;
+};
+
+ssize_t memcached_io_write(memcached_server_st *ptr,
+ const void *buffer, size_t length, char with_flush);
+void memcached_io_reset(memcached_server_st *ptr);
+memcached_return_t memcached_io_read(memcached_server_st *ptr,
+ void *buffer, size_t length, ssize_t *nread);
+/* Read a line (terminated by '\n') into the buffer */
+memcached_return_t memcached_io_readline(memcached_server_st *ptr,
+ char *buffer_ptr,
+ size_t size);
+memcached_return_t memcached_io_close(memcached_server_st *ptr);
+/* Read n bytes of data from the server and store them in dta */
+memcached_return_t memcached_safe_read(memcached_server_st *ptr,
+ void *dta,
+ size_t size);
+/* Read a single response from the server */
+memcached_return_t memcached_read_one_response(memcached_server_st *ptr,
+ char *buffer, size_t buffer_length,
+ memcached_result_st *result);
+memcached_return_t memcached_io_init_udp_header(memcached_server_st *ptr,
+ uint16_t thread_id);
+
+memcached_server_st *memcached_io_get_readable_server(memcached_st *memc);
+
+#endif /* BUILDING_LIBMEMCACHED */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBMEMCACHED_MEMCACHED_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;
+}
+
#include <libmemcached/visibility.h>
#include <libmemcached/memcached_configure.h>
-#include <libmemcached/memcached_constants.h>
-#include <libmemcached/memcached_types.h>
-#include <libmemcached/memcached_behavior.h>
-#include <libmemcached/memcached_callback.h>
-#include <libmemcached/memcached_get.h>
-#include <libmemcached/memcached_server.h>
-#include <libmemcached/memcached_string.h>
-#include <libmemcached/memcached_result.h>
-#include <libmemcached/memcached_storage.h>
+#include <libmemcached/constants.h>
+#include <libmemcached/types.h>
+#include <libmemcached/string.h>
+// Everything above this line must be in the order specified.
+#include <libmemcached/behavior.h>
+#include <libmemcached/callback.h>
+#include <libmemcached/get.h>
+#include <libmemcached/result.h>
+#include <libmemcached/server.h>
+#include <libmemcached/storage.h>
#ifdef __cplusplus
extern "C" {
+++ /dev/null
-#include "common.h"
-
-void libmemcached_free(memcached_st *ptr, void *mem)
-{
- (void) ptr;
- free(mem);
-}
-
-void *libmemcached_malloc(memcached_st *ptr, size_t size)
-{
- (void) ptr;
- return malloc(size);
-}
-
-void *libmemcached_realloc(memcached_st *ptr, void *mem, size_t size)
-{
- (void) ptr;
- return realloc(mem, size);
-}
-
-void *libmemcached_calloc(memcached_st *ptr, size_t nelem, size_t size)
-{
- if (ptr->call_malloc != libmemcached_malloc)
- {
- void *ret = libmemcached_malloc(ptr, nelem * size);
- if (ret != NULL)
- memset(ret, 0, nelem * size);
-
- return ret;
- }
-
- return calloc(nelem, size);
-}
-
-memcached_return_t memcached_set_memory_allocators(memcached_st *ptr,
- memcached_malloc_fn mem_malloc,
- memcached_free_fn mem_free,
- memcached_realloc_fn mem_realloc,
- memcached_calloc_fn mem_calloc)
-{
- /* All should be set, or none should be set */
- if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL)
- {
- ptr->call_malloc= libmemcached_malloc;
- ptr->call_free= libmemcached_free;
- ptr->call_realloc= libmemcached_realloc;
- ptr->call_calloc= libmemcached_calloc;
- }
- else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL)
- return MEMCACHED_FAILURE;
- else
- {
- ptr->call_malloc= mem_malloc;
- ptr->call_free= mem_free;
- ptr->call_realloc= mem_realloc;
- ptr->call_calloc= mem_calloc;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-void memcached_get_memory_allocators(memcached_st *ptr,
- memcached_malloc_fn *mem_malloc,
- memcached_free_fn *mem_free,
- memcached_realloc_fn *mem_realloc,
- memcached_calloc_fn *mem_calloc)
-{
- *mem_malloc= ptr->call_malloc;
- *mem_free= ptr->call_free;
- *mem_realloc= ptr->call_realloc;
- *mem_calloc= ptr->call_calloc;
-}
+++ /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(memc->number_of_hosts,
- sizeof(memcached_analysis_st));
-
- if (!result)
- {
- *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return NULL;
- }
-
- for (x= 0; x < server_count; x++)
- {
- calc_largest_consumption(result, x, memc_stat[x].bytes);
- calc_oldest_node(result, x, memc_stat[x].uptime);
- calc_least_free_node(result, x,
- memc_stat[x].limit_maxbytes,
- memc_stat[x].bytes);
-
- total_get_hits+= memc_stat[x].get_hits;
- total_get_cmds+= memc_stat[x].cmd_get;
- total_items+= memc_stat[x].curr_items;
- total_bytes+= memc_stat[x].bytes;
- }
-
- calc_average_item_size(result, total_items, total_bytes);
- calc_hit_ratio(result, total_get_hits, total_get_cmds);
-
- return result;
-}
+++ /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 "common.h"
-
-static memcached_return_t memcached_auto(memcached_st *ptr,
- const char *verb,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- uint64_t offset,
- uint64_t *value)
-{
- size_t send_length;
- memcached_return_t rc;
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- unsigned int server_key;
- bool no_reply= ptr->flags.no_reply;
-
- unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
- return MEMCACHED_NO_SERVERS;
-
- if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
- return MEMCACHED_BAD_KEY_PROVIDED;
-
- server_key= memcached_generate_hash(ptr, master_key, master_key_length);
-
- send_length= (size_t)snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "%s %s%.*s %" PRIu64 "%s\r\n", verb,
- ptr->prefix_key,
- (int)key_length, key,
- offset, no_reply ? " noreply" : "");
- unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
- return MEMCACHED_WRITE_FAILURE;
-
- rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
- if (no_reply || rc != MEMCACHED_SUCCESS)
- return rc;
-
- rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
- /*
- So why recheck responce? Because the protocol is brain dead :)
- The number returned might end up equaling one of the string
- values. Less chance of a mistake with strncmp() so we will
- use it. We still called memcached_response() though since it
- worked its magic for non-blocking IO.
- */
- if (!strncmp(buffer, "ERROR\r\n", 7))
- {
- *value= 0;
- rc= MEMCACHED_PROTOCOL_ERROR;
- }
- else if (!strncmp(buffer, "NOT_FOUND\r\n", 11))
- {
- *value= 0;
- rc= MEMCACHED_NOTFOUND;
- }
- else
- {
- *value= strtoull(buffer, (char **)NULL, 10);
- rc= MEMCACHED_SUCCESS;
- }
-
- return rc;
-}
-
-static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- uint64_t offset, uint64_t initial,
- uint32_t expiration,
- uint64_t *value)
-{
- unsigned int server_key;
- bool no_reply= ptr->flags.no_reply;
-
- unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
- return MEMCACHED_NO_SERVERS;
-
- server_key= memcached_generate_hash(ptr, master_key, master_key_length);
-
- if (no_reply)
- {
- if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
- cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
- if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
- cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
- }
- protocol_binary_request_incr request= {.bytes= {0}};
-
- request.message.header.request.magic= PROTOCOL_BINARY_REQ;
- request.message.header.request.opcode= cmd;
- request.message.header.request.keylen= htons((uint16_t) key_length);
- request.message.header.request.extlen= 20;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t) (key_length + request.message.header.request.extlen));
- request.message.body.delta= htonll(offset);
- request.message.body.initial= htonll(initial);
- request.message.body.expiration= htonl((uint32_t) expiration);
-
- if ((memcached_do(&ptr->hosts[server_key], request.bytes,
- sizeof(request.bytes), 0)!=MEMCACHED_SUCCESS) ||
- (memcached_io_write(&ptr->hosts[server_key], key, key_length, 1) == -1))
- {
- memcached_io_reset(&ptr->hosts[server_key]);
- return MEMCACHED_WRITE_FAILURE;
- }
-
- if (no_reply)
- return MEMCACHED_SUCCESS;
- return memcached_response(&ptr->hosts[server_key], (char*)value, sizeof(*value), NULL);
-}
-
-memcached_return_t memcached_increment(memcached_st *ptr,
- const char *key, size_t key_length,
- uint32_t offset,
- uint64_t *value)
-{
- return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
-}
-
-memcached_return_t memcached_decrement(memcached_st *ptr,
- const char *key, size_t key_length,
- uint32_t offset,
- uint64_t *value)
-{
- return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
-}
-
-memcached_return_t memcached_increment_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- uint64_t offset,
- uint64_t *value)
-{
- memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
- unlikely (rc != MEMCACHED_SUCCESS)
- return rc;
-
- LIBMEMCACHED_MEMCACHED_INCREMENT_START();
- if (ptr->flags.binary_protocol)
- {
- rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
- master_key, master_key_length, key, key_length,
- (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
- value);
- }
- else
- {
- rc= memcached_auto(ptr, "incr", master_key, master_key_length, key, key_length, offset, value);
- }
-
- LIBMEMCACHED_MEMCACHED_INCREMENT_END();
-
- return rc;
-}
-
-memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- uint64_t offset,
- uint64_t *value)
-{
- memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
- unlikely (rc != MEMCACHED_SUCCESS)
- return rc;
-
- LIBMEMCACHED_MEMCACHED_DECREMENT_START();
- if (ptr->flags.binary_protocol)
- rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
- master_key, master_key_length, key, key_length,
- (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
- value);
- else
- rc= memcached_auto(ptr, "decr", master_key, master_key_length, key, key_length, offset, value);
-
- LIBMEMCACHED_MEMCACHED_DECREMENT_END();
-
- return rc;
-}
-
-memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value)
-{
- return memcached_increment_with_initial_by_key(ptr, key, key_length,
- key, key_length,
- offset, initial, expiration, value);
-}
-
-memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value)
-{
- memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
- unlikely (rc != MEMCACHED_SUCCESS)
- return rc;
-
- LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
- if (ptr->flags.binary_protocol)
- rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
- master_key, master_key_length, key, key_length,
- offset, initial, (uint32_t)expiration,
- value);
- else
- rc= MEMCACHED_PROTOCOL_ERROR;
-
- LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
-
- return rc;
-}
-
-memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value)
-{
- return memcached_decrement_with_initial_by_key(ptr, key, key_length,
- key, key_length,
- offset, initial, expiration, value);
-}
-
-memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value)
-{
- memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
- unlikely (rc != MEMCACHED_SUCCESS)
- return rc;
-
- LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
- if (ptr->flags.binary_protocol)
- {
- rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
- master_key, master_key_length, key, key_length,
- offset, initial, (uint32_t)expiration,
- value);
- }
- else
- {
- rc= MEMCACHED_PROTOCOL_ERROR;
- }
-
- LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
-
- return rc;
-}
-
+++ /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 "common.h"
-#include <time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/tcp.h>
-
-/*
- This function is used to modify the behavior of running client.
-
- We quit all connections so we can reset the sockets.
-*/
-
-memcached_return_t memcached_behavior_set(memcached_st *ptr,
- memcached_behavior_t flag,
- uint64_t data)
-{
- switch (flag)
- {
- case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
- ptr->number_of_replicas= (uint32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
- ptr->io_msg_watermark= (uint32_t) data;
- break;
- case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
- ptr->io_bytes_watermark= (uint32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
- ptr->io_key_prefetch = (uint32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
- ptr->snd_timeout= (int32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
- ptr->rcv_timeout= (int32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
- ptr->server_failure_limit= (uint32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
- if (data)
- ptr->flags.verify_key= false;
-
- ptr->flags.binary_protocol= data ? true : false;
- break;
- case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
- ptr->flags.support_cas= data ? true: false;
- break;
- case MEMCACHED_BEHAVIOR_NO_BLOCK:
- ptr->flags.no_block= data ? true: false;
- memcached_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
- ptr->flags.buffer_requests= data ? true : false;
- memcached_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_USE_UDP:
- if (ptr->number_of_hosts)
- return MEMCACHED_FAILURE;
- ptr->flags.use_udp= data ? true : false;
-
- if (data)
- ptr->flags.no_reply= data ? true : false;
- break;
-
- case MEMCACHED_BEHAVIOR_TCP_NODELAY:
- ptr->flags.tcp_nodelay= data ? true : false;
- memcached_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_DISTRIBUTION:
- {
- ptr->distribution= (memcached_server_distribution_t)(data);
- if (ptr->distribution == MEMCACHED_DISTRIBUTION_RANDOM)
- {
- srandom((uint32_t) time(NULL));
- }
- run_distribution(ptr);
- break;
- }
- case MEMCACHED_BEHAVIOR_KETAMA:
- {
- if (data)
- {
- ptr->hash= MEMCACHED_HASH_MD5;
- ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
- }
- else
- {
- ptr->hash= 0;
- ptr->distribution= 0;
- }
- run_distribution(ptr);
- break;
- }
- case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
- {
- ptr->hash= MEMCACHED_HASH_MD5;
- ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
- ptr->flags.ketama_weighted= data ? true : false;
- run_distribution(ptr);
- break;
- }
- case MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE:
- switch (data)
- {
- case MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED:
- ptr->hash= MEMCACHED_HASH_MD5;
- ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
- break;
- case MEMCACHED_KETAMA_COMPAT_SPY:
- ptr->hash= MEMCACHED_HASH_MD5;
- ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY;
- break;
- default:
- return MEMCACHED_FAILURE;
- }
- run_distribution(ptr);
- break;
- case MEMCACHED_BEHAVIOR_HASH:
-#ifndef HAVE_HSIEH_HASH
- if ((memcached_hash_t)(data) == MEMCACHED_HASH_HSIEH)
- return MEMCACHED_FAILURE;
-#endif
- ptr->hash= (memcached_hash_t)(data);
- break;
- case MEMCACHED_BEHAVIOR_KETAMA_HASH:
- ptr->hash_continuum= (memcached_hash_t)(data);
- run_distribution(ptr);
- break;
- case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
- ptr->flags.use_cache_lookups= data ? true : false;
- memcached_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_VERIFY_KEY:
- if (ptr->flags.binary_protocol)
- break;
- ptr->flags.verify_key= data ? true : false;
- break;
- case MEMCACHED_BEHAVIOR_SORT_HOSTS:
- {
- ptr->flags.use_sort_hosts= data ? true : false;
- run_distribution(ptr);
-
- break;
- }
- case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
- ptr->poll_timeout= (int32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
- ptr->connect_timeout= (int32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
- ptr->retry_timeout= (int32_t)data;
- break;
- case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
- ptr->send_size= (int32_t)data;
- memcached_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
- ptr->recv_size= (int32_t)data;
- memcached_quit(ptr);
- break;
- case MEMCACHED_BEHAVIOR_USER_DATA:
- return MEMCACHED_FAILURE;
- case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
- ptr->flags.hash_with_prefix_key= data ? true : false;
- break;
- case MEMCACHED_BEHAVIOR_NOREPLY:
- ptr->flags.no_reply= data ? true : false;
- break;
- case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
- ptr->flags.auto_eject_hosts= data ? true : false;
- break;
- case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
- srandom((uint32_t) time(NULL));
- ptr->flags.randomize_replica_read= data ? true : false;
- break;
- default:
- /* Shouldn't get here */
- WATCHPOINT_ASSERT(flag);
- break;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-uint64_t memcached_behavior_get(memcached_st *ptr,
- memcached_behavior_t flag)
-{
- switch (flag)
- {
- case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
- return ptr->number_of_replicas;
- case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
- return ptr->io_msg_watermark;
- case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
- return ptr->io_bytes_watermark;
- case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
- return ptr->io_key_prefetch;
- case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
- return ptr->flags.binary_protocol;
- case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
- return ptr->flags.support_cas;
- case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
- return ptr->flags.use_cache_lookups;
- case MEMCACHED_BEHAVIOR_NO_BLOCK:
- return ptr->flags.no_block;
- case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
- return ptr->flags.buffer_requests;
- case MEMCACHED_BEHAVIOR_USE_UDP:
- return ptr->flags.use_udp;
- case MEMCACHED_BEHAVIOR_TCP_NODELAY:
- return ptr->flags.tcp_nodelay;
- case MEMCACHED_BEHAVIOR_VERIFY_KEY:
- return ptr->flags.verify_key;
- case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
- return ptr->flags.ketama_weighted;
- case MEMCACHED_BEHAVIOR_DISTRIBUTION:
- return ptr->distribution;
- case MEMCACHED_BEHAVIOR_KETAMA:
- return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0;
- case MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE:
- switch (ptr->distribution)
- {
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
- return MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED;
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
- return MEMCACHED_KETAMA_COMPAT_SPY;
- case MEMCACHED_DISTRIBUTION_MODULA:
- case MEMCACHED_DISTRIBUTION_CONSISTENT:
- case MEMCACHED_DISTRIBUTION_RANDOM:
- default:
- return (uint64_t)-1;
- }
- /* NOTREACHED */
- case MEMCACHED_BEHAVIOR_HASH:
- return ptr->hash;
- case MEMCACHED_BEHAVIOR_KETAMA_HASH:
- return ptr->hash_continuum;
- case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
- return ptr->server_failure_limit;
- case MEMCACHED_BEHAVIOR_SORT_HOSTS:
- return ptr->flags.use_sort_hosts;
- case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
- return (uint64_t)ptr->poll_timeout;
- case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
- return (uint64_t)ptr->connect_timeout;
- case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
- return (uint64_t)ptr->retry_timeout;
- case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
- return (uint64_t)ptr->snd_timeout;
- case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
- return (uint64_t)ptr->rcv_timeout;
- case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
- {
- int sock_size;
- socklen_t sock_length= sizeof(int);
-
- /* REFACTOR */
- /* We just try the first host, and if it is down we return zero */
- if ((memcached_connect(&ptr->hosts[0])) != MEMCACHED_SUCCESS)
- return 0;
-
- if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET,
- SO_SNDBUF, &sock_size, &sock_length))
- return 0; /* Zero means error */
-
- return (uint64_t) sock_size;
- }
- case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
- {
- int sock_size;
- socklen_t sock_length= sizeof(int);
-
- /* REFACTOR */
- /* We just try the first host, and if it is down we return zero */
- if ((memcached_connect(&ptr->hosts[0])) != MEMCACHED_SUCCESS)
- return 0;
-
- if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET,
- SO_RCVBUF, &sock_size, &sock_length))
- return 0; /* Zero means error */
-
- return (uint64_t) sock_size;
- }
- case MEMCACHED_BEHAVIOR_USER_DATA:
- return MEMCACHED_FAILURE;
- case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
- 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;
- default:
- WATCHPOINT_ASSERT(flag);
- break;
- }
-
- WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */
- return 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: Change the behavior of the memcached connection.
- *
- */
-
-#ifndef __MEMCACHED_BEHAVIOR_H__
-#define __MEMCACHED_BEHAVIOR_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_behavior_set(memcached_st *ptr, memcached_behavior_t flag, uint64_t data);
-
-LIBMEMCACHED_API
-uint64_t memcached_behavior_get(memcached_st *ptr, memcached_behavior_t flag);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_BEHAVIOR_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 "common.h"
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/tcp.h>
-
-/*
- These functions provide data and function callback support
-*/
-
-memcached_return_t memcached_callback_set(memcached_st *ptr,
- memcached_callback_t flag,
- void *data)
-{
- switch (flag)
- {
- case MEMCACHED_CALLBACK_PREFIX_KEY:
- {
- char *key= (char *)data;
-
- if (key)
- {
- size_t key_length= strlen(key);
-
- if (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)
- {
- return MEMCACHED_BAD_KEY_PROVIDED;
- }
-
- if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1)
- || (strcpy(ptr->prefix_key, key) == NULL))
- {
- ptr->prefix_key_length= 0;
- return MEMCACHED_BAD_KEY_PROVIDED;
- }
- else
- {
- ptr->prefix_key_length= key_length;
- }
- }
- else
- {
- memset(ptr->prefix_key, 0, MEMCACHED_PREFIX_KEY_MAX_SIZE);
- ptr->prefix_key_length= 0;
- }
-
- break;
- }
- case MEMCACHED_CALLBACK_USER_DATA:
- {
- ptr->user_data= data;
- break;
- }
- case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
- {
- memcached_cleanup_fn func= *(memcached_cleanup_fn *)&data;
- ptr->on_cleanup= func;
- break;
- }
- case MEMCACHED_CALLBACK_CLONE_FUNCTION:
- {
- memcached_clone_fn func= *(memcached_clone_fn *)&data;
- ptr->on_clone= func;
- break;
- }
-#ifdef MEMCACHED_ENABLE_DEPRECATED
- case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
- {
- memcached_malloc_function func= *(memcached_malloc_fn *)&data;
- ptr->call_malloc= func;
- break;
- }
- case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
- {
- memcached_realloc_function func= *(memcached_realloc_fn *)&data;
- ptr->call_realloc= func;
- break;
- }
- case MEMCACHED_CALLBACK_FREE_FUNCTION:
- {
- memcached_free_function func= *(memcached_free_fn *)&data;
- ptr->call_free= func;
- break;
- }
-#endif
- case MEMCACHED_CALLBACK_GET_FAILURE:
- {
- memcached_trigger_key_fn func= *(memcached_trigger_key_fn *)&data;
- ptr->get_key_failure= func;
- break;
- }
- case MEMCACHED_CALLBACK_DELETE_TRIGGER:
- {
- memcached_trigger_delete_key_fn func= *(memcached_trigger_delete_key_fn *)&data;
- ptr->delete_trigger= func;
- break;
- }
- default:
- return MEMCACHED_FAILURE;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-void *memcached_callback_get(memcached_st *ptr,
- memcached_callback_t flag,
- memcached_return_t *error)
-{
- memcached_return_t local_error;
-
- if (!error)
- error = &local_error;
-
- switch (flag)
- {
- case MEMCACHED_CALLBACK_PREFIX_KEY:
- {
- if (ptr->prefix_key[0] == 0)
- {
- *error= MEMCACHED_FAILURE;
- return NULL;
- }
- else
- {
- *error= MEMCACHED_SUCCESS;
- return (void *)ptr->prefix_key;
- }
- }
- case MEMCACHED_CALLBACK_USER_DATA:
- {
- *error= ptr->user_data ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return (void *)ptr->user_data;
- }
- case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
- {
- *error= ptr->on_cleanup ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return *(void **)&ptr->on_cleanup;
- }
- case MEMCACHED_CALLBACK_CLONE_FUNCTION:
- {
- *error= ptr->on_clone ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return *(void **)&ptr->on_clone;
- }
-#ifdef MEMCACHED_ENABLE_DEPRECATED
- case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
- {
- *error= ptr->call_malloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return *(void **)&ptr->call_malloc;
- }
- case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
- {
- *error= ptr->call_realloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return *(void **)&ptr->call_realloc;
- }
- case MEMCACHED_CALLBACK_FREE_FUNCTION:
- {
- *error= ptr->call_free ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return *(void **)&ptr->call_free;
- }
-#endif
- case MEMCACHED_CALLBACK_GET_FAILURE:
- {
- *error= ptr->get_key_failure ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return *(void **)&ptr->get_key_failure;
- }
- case MEMCACHED_CALLBACK_DELETE_TRIGGER:
- {
- *error= ptr->delete_trigger ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
- return *(void **)&ptr->delete_trigger;
- }
- 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.
- *
- */
-
-#ifndef __MEMCACHED_CALLBACK_H__
-#define __MEMCACHED_CALLBACK_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_API
-memcached_return_t memcached_callback_set(memcached_st *ptr,
- memcached_callback_t flag,
- void *data);
-LIBMEMCACHED_API
-void *memcached_callback_get(memcached_st *ptr,
- memcached_callback_t flag,
- memcached_return_t *error);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_CALLBACK_H__ */
+++ /dev/null
-#include "common.h"
-#include <netdb.h>
-#include <poll.h>
-#include <sys/time.h>
-
-static memcached_return_t set_hostinfo(memcached_server_st *server)
-{
- struct addrinfo *ai;
- struct addrinfo hints;
- int e;
- char str_port[NI_MAXSERV];
-
- sprintf(str_port, "%u", server->port);
-
- memset(&hints, 0, sizeof(hints));
-
- // hints.ai_family= AF_INET;
- if (server->type == MEMCACHED_CONNECTION_UDP)
- {
- hints.ai_protocol= IPPROTO_UDP;
- hints.ai_socktype= SOCK_DGRAM;
- }
- else
- {
- hints.ai_socktype= SOCK_STREAM;
- hints.ai_protocol= IPPROTO_TCP;
- }
-
- e= getaddrinfo(server->hostname, str_port, &hints, &ai);
- if (e != 0)
- {
- WATCHPOINT_STRING(server->hostname);
- WATCHPOINT_STRING(gai_strerror(e));
- return MEMCACHED_HOST_LOOKUP_FAILURE;
- }
-
- if (server->address_info)
- {
- freeaddrinfo(server->address_info);
- server->address_info= NULL;
- }
- server->address_info= ai;
-
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_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);
- }
-#endif
-
-#ifdef HAVE_RCVTIMEO
- if (ptr->root->rcv_timeout)
- {
- int error;
- struct timeval waittime;
-
- waittime.tv_sec= 0;
- waittime.tv_usec= ptr->root->rcv_timeout;
-
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO,
- &waittime, (socklen_t)sizeof(struct timeval));
- WATCHPOINT_ASSERT(error == 0);
- }
-#endif
-
- if (ptr->root->flags.no_block)
- {
- int error;
- struct linger linger;
-
- linger.l_onoff= 1;
- linger.l_linger= 0; /* By default on close() just drop the socket */
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER,
- &linger, (socklen_t)sizeof(struct linger));
- WATCHPOINT_ASSERT(error == 0);
- }
-
- if (ptr->root->flags.tcp_nodelay)
- {
- int flag= 1;
- int error;
-
- error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY,
- &flag, (socklen_t)sizeof(int));
- WATCHPOINT_ASSERT(error == 0);
- }
-
- if (ptr->root->send_size)
- {
- int error;
-
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
- &ptr->root->send_size, (socklen_t)sizeof(int));
- WATCHPOINT_ASSERT(error == 0);
- }
-
- if (ptr->root->recv_size)
- {
- int error;
-
- error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF,
- &ptr->root->recv_size, (socklen_t)sizeof(int));
- WATCHPOINT_ASSERT(error == 0);
- }
-
- /* libmemcached will always use nonblocking IO to avoid write deadlocks */
- int flags;
-
- do
- flags= fcntl(ptr->fd, F_GETFL, 0);
- while (flags == -1 && (errno == EINTR || errno == EAGAIN));
-
- unlikely (flags == -1)
- return MEMCACHED_CONNECTION_FAILURE;
- else if ((flags & O_NONBLOCK) == 0)
- {
- int rval;
-
- do
- rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
- while (rval == -1 && (errno == EINTR || errno == EAGAIN));
-
- unlikely (rval == -1)
- return MEMCACHED_CONNECTION_FAILURE;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t unix_socket_connect(memcached_server_st *ptr)
-{
- struct sockaddr_un servAddr;
- socklen_t addrlen;
-
- if (ptr->fd == -1)
- {
- if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
- {
- ptr->cached_errno= errno;
- return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
- }
-
- memset(&servAddr, 0, sizeof (struct sockaddr_un));
- servAddr.sun_family= AF_UNIX;
- strcpy(servAddr.sun_path, ptr->hostname); /* Copy filename */
-
- addrlen= (socklen_t) (strlen(servAddr.sun_path) + sizeof(servAddr.sun_family));
-
-test_connect:
- if (connect(ptr->fd,
- (struct sockaddr *)&servAddr,
- sizeof(servAddr)) < 0)
- {
- switch (errno)
- {
- case EINPROGRESS:
- case EALREADY:
- case EINTR:
- goto test_connect;
- case EISCONN: /* We were spinning waiting on connect */
- break;
- default:
- WATCHPOINT_ERRNO(errno);
- ptr->cached_errno= errno;
- return MEMCACHED_ERRNO;
- }
- }
- }
-
- WATCHPOINT_ASSERT(ptr->fd != -1);
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t network_connect(memcached_server_st *ptr)
-{
- if (ptr->fd == -1)
- {
- struct addrinfo *use;
-
- if (!ptr->sockaddr_inited ||
- (!(ptr->root->flags.use_cache_lookups)))
- {
- memcached_return_t rc;
-
- rc= set_hostinfo(ptr);
- if (rc != MEMCACHED_SUCCESS)
- return rc;
- ptr->sockaddr_inited= true;
- }
-
- use= ptr->address_info;
- /* Create the socket */
- while (use != NULL)
- {
- /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
- if (ptr->type == MEMCACHED_CONNECTION_UDP && use->ai_family != AF_INET)
- {
- use= use->ai_next;
- continue;
- }
-
- if ((ptr->fd= socket(use->ai_family,
- use->ai_socktype,
- use->ai_protocol)) < 0)
- {
- ptr->cached_errno= errno;
- WATCHPOINT_ERRNO(errno);
- return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
- }
-
- (void)set_socket_options(ptr);
-
- /* connect to server */
- while (ptr->fd != -1 &&
- connect(ptr->fd, use->ai_addr, use->ai_addrlen) < 0)
- {
- ptr->cached_errno= errno;
- if (errno == EINPROGRESS || /* nonblocking mode - first return, */
- errno == EALREADY) /* nonblocking mode - subsequent returns */
- {
- struct pollfd fds[1];
- fds[0].fd = ptr->fd;
- fds[0].events = POLLOUT;
- int error= poll(fds, 1, ptr->root->connect_timeout);
-
- if (error != 1 || fds[0].revents & POLLERR)
- {
- if (fds[0].revents & POLLERR)
- {
- int err;
- socklen_t len = sizeof (err);
- (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
- ptr->cached_errno= (err == 0) ? errno : err;
- }
-
- (void)close(ptr->fd);
- ptr->fd= -1;
- }
- }
- else if (errno == EISCONN) /* we are connected :-) */
- {
- break;
- }
- else if (errno != EINTR)
- {
- (void)close(ptr->fd);
- ptr->fd= -1;
- break;
- }
- }
-
- if (ptr->fd != -1)
- {
- WATCHPOINT_ASSERT(ptr->cursor_active == 0);
- ptr->server_failure_counter= 0;
- return MEMCACHED_SUCCESS;
- }
- use = use->ai_next;
- }
- }
-
- if (ptr->fd == -1)
- {
- /* Failed to connect. schedule next retry */
- if (ptr->root->retry_timeout)
- {
- struct timeval next_time;
-
- if (gettimeofday(&next_time, NULL) == 0)
- ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
- }
- ptr->server_failure_counter++;
- if (ptr->cached_errno == 0)
- return MEMCACHED_TIMEOUT;
-
- return MEMCACHED_ERRNO; /* The last error should be from connect() */
- }
-
- ptr->server_failure_counter= 0;
- return MEMCACHED_SUCCESS; /* The last error should be from connect() */
-}
-
-
-memcached_return_t memcached_connect(memcached_server_st *ptr)
-{
- memcached_return_t rc= MEMCACHED_NO_SERVERS;
- LIBMEMCACHED_MEMCACHED_CONNECT_START();
-
- /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */
- WATCHPOINT_ASSERT(ptr->root);
- if (ptr->root->retry_timeout && ptr->root->server_failure_limit)
- {
- struct timeval curr_time;
-
- gettimeofday(&curr_time, NULL);
-
- /* if we've had too many consecutive errors on this server, mark it dead. */
- if (ptr->server_failure_counter >= ptr->root->server_failure_limit)
- {
- ptr->next_retry= curr_time.tv_sec + ptr->root->retry_timeout;
- ptr->server_failure_counter= 0;
- }
-
- if (curr_time.tv_sec < ptr->next_retry)
- {
- if (memcached_behavior_get(ptr->root, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS))
- run_distribution(ptr->root);
-
- ptr->root->last_disconnected_server = ptr;
- return MEMCACHED_SERVER_MARKED_DEAD;
- }
- }
-
- /* We need to clean up the multi startup piece */
- switch (ptr->type)
- {
- case MEMCACHED_CONNECTION_UNKNOWN:
- WATCHPOINT_ASSERT(0);
- rc= MEMCACHED_NOT_SUPPORTED;
- break;
- case MEMCACHED_CONNECTION_UDP:
- case MEMCACHED_CONNECTION_TCP:
- rc= network_connect(ptr);
- break;
- case MEMCACHED_CONNECTION_UNIX_SOCKET:
- rc= unix_socket_connect(ptr);
- break;
- default:
- WATCHPOINT_ASSERT(0);
- }
-
- unlikely ( rc != MEMCACHED_SUCCESS) ptr->root->last_disconnected_server = ptr;
-
- LIBMEMCACHED_MEMCACHED_CONNECT_END();
-
- 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: Constants for libmemcached
- *
- */
-
-#ifndef __MEMCACHED_CONSTANTS_H__
-#define __MEMCACHED_CONSTANTS_H__
-
-/* Public defines */
-#define MEMCACHED_DEFAULT_PORT 11211
-#define MEMCACHED_MAX_KEY 251 /* We add one to have it null terminated */
-#define MEMCACHED_MAX_BUFFER 8196
-#define MEMCACHED_MAX_HOST_LENGTH 64
-#define MEMCACHED_MAX_HOST_SORT_LENGTH 86 /* Used for Ketama */
-#define MEMCACHED_POINTS_PER_SERVER 100
-#define MEMCACHED_POINTS_PER_SERVER_KETAMA 160
-#define MEMCACHED_CONTINUUM_SIZE MEMCACHED_POINTS_PER_SERVER*100 /* This would then set max hosts to 100 */
-#define MEMCACHED_STRIDE 4
-#define MEMCACHED_DEFAULT_TIMEOUT 1000
-#define MEMCACHED_CONTINUUM_ADDITION 10 /* How many extra slots we should build for in the continuum */
-#define MEMCACHED_PREFIX_KEY_MAX_SIZE 128
-#define MEMCACHED_EXPIRATION_NOT_ADD 0xffffffffU
-
-typedef enum {
- MEMCACHED_SUCCESS,
- MEMCACHED_FAILURE,
- MEMCACHED_HOST_LOOKUP_FAILURE,
- MEMCACHED_CONNECTION_FAILURE,
- MEMCACHED_CONNECTION_BIND_FAILURE,
- MEMCACHED_WRITE_FAILURE,
- MEMCACHED_READ_FAILURE,
- MEMCACHED_UNKNOWN_READ_FAILURE,
- MEMCACHED_PROTOCOL_ERROR,
- MEMCACHED_CLIENT_ERROR,
- MEMCACHED_SERVER_ERROR,
- MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE,
- MEMCACHED_DATA_EXISTS,
- MEMCACHED_DATA_DOES_NOT_EXIST,
- MEMCACHED_NOTSTORED,
- MEMCACHED_STORED,
- MEMCACHED_NOTFOUND,
- MEMCACHED_MEMORY_ALLOCATION_FAILURE,
- MEMCACHED_PARTIAL_READ,
- MEMCACHED_SOME_ERRORS,
- MEMCACHED_NO_SERVERS,
- MEMCACHED_END,
- MEMCACHED_DELETED,
- MEMCACHED_VALUE,
- MEMCACHED_STAT,
- MEMCACHED_ITEM,
- MEMCACHED_ERRNO,
- MEMCACHED_FAIL_UNIX_SOCKET,
- MEMCACHED_NOT_SUPPORTED,
- MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */
- MEMCACHED_FETCH_NOTFINISHED,
- MEMCACHED_TIMEOUT,
- MEMCACHED_BUFFERED,
- MEMCACHED_BAD_KEY_PROVIDED,
- MEMCACHED_INVALID_HOST_PROTOCOL,
- MEMCACHED_SERVER_MARKED_DEAD,
- MEMCACHED_UNKNOWN_STAT_KEY,
- MEMCACHED_E2BIG,
- MEMCACHED_INVALID_ARGUMENTS,
- MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */
-} memcached_return_t;
-
-
-typedef enum {
- MEMCACHED_DISTRIBUTION_MODULA,
- MEMCACHED_DISTRIBUTION_CONSISTENT,
- MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA,
- MEMCACHED_DISTRIBUTION_RANDOM,
- MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY
-} memcached_server_distribution_t;
-
-typedef enum {
- MEMCACHED_BEHAVIOR_NO_BLOCK,
- MEMCACHED_BEHAVIOR_TCP_NODELAY,
- MEMCACHED_BEHAVIOR_HASH,
- MEMCACHED_BEHAVIOR_KETAMA,
- MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE,
- MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE,
- MEMCACHED_BEHAVIOR_CACHE_LOOKUPS,
- MEMCACHED_BEHAVIOR_SUPPORT_CAS,
- MEMCACHED_BEHAVIOR_POLL_TIMEOUT,
- MEMCACHED_BEHAVIOR_DISTRIBUTION,
- MEMCACHED_BEHAVIOR_BUFFER_REQUESTS,
- MEMCACHED_BEHAVIOR_USER_DATA,
- MEMCACHED_BEHAVIOR_SORT_HOSTS,
- MEMCACHED_BEHAVIOR_VERIFY_KEY,
- MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT,
- MEMCACHED_BEHAVIOR_RETRY_TIMEOUT,
- MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED,
- MEMCACHED_BEHAVIOR_KETAMA_HASH,
- MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
- MEMCACHED_BEHAVIOR_SND_TIMEOUT,
- MEMCACHED_BEHAVIOR_RCV_TIMEOUT,
- MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT,
- MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK,
- MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK,
- MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH,
- MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY,
- MEMCACHED_BEHAVIOR_NOREPLY,
- MEMCACHED_BEHAVIOR_USE_UDP,
- MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS,
- MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS,
- MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE,
- MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ
-} memcached_behavior_t;
-
-#define MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED 0
-#define MEMCACHED_KETAMA_COMPAT_SPY 1
-
-typedef enum {
- MEMCACHED_CALLBACK_PREFIX_KEY = 0,
- MEMCACHED_CALLBACK_USER_DATA = 1,
- MEMCACHED_CALLBACK_CLEANUP_FUNCTION = 2,
- MEMCACHED_CALLBACK_CLONE_FUNCTION = 3,
-#ifdef MEMCACHED_ENABLE_DEPRECATED
- MEMCACHED_CALLBACK_MALLOC_FUNCTION = 4,
- MEMCACHED_CALLBACK_REALLOC_FUNCTION = 5,
- MEMCACHED_CALLBACK_FREE_FUNCTION = 6,
-#endif
- MEMCACHED_CALLBACK_GET_FAILURE = 7,
- MEMCACHED_CALLBACK_DELETE_TRIGGER = 8
-} memcached_callback_t;
-
-typedef enum {
- MEMCACHED_HASH_DEFAULT= 0,
- MEMCACHED_HASH_MD5,
- MEMCACHED_HASH_CRC,
- MEMCACHED_HASH_FNV1_64,
- MEMCACHED_HASH_FNV1A_64,
- MEMCACHED_HASH_FNV1_32,
- MEMCACHED_HASH_FNV1A_32,
- MEMCACHED_HASH_HSIEH,
- MEMCACHED_HASH_MURMUR,
- MEMCACHED_HASH_JENKINS
-} memcached_hash_t;
-
-typedef enum {
- MEMCACHED_CONNECTION_UNKNOWN,
- MEMCACHED_CONNECTION_TCP,
- MEMCACHED_CONNECTION_UDP,
- MEMCACHED_CONNECTION_UNIX_SOCKET
-} memcached_connection_t;
-
-#endif /* __MEMCACHED_CONSTANTS_H__ */
+++ /dev/null
-#include "common.h"
-#include "memcached/protocol_binary.h"
-
-memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
- time_t expiration)
-{
- return memcached_delete_by_key(ptr, key, key_length,
- key, key_length, expiration);
-}
-
-static inline memcached_return_t binary_delete(memcached_st *ptr,
- unsigned int server_key,
- const char *key,
- size_t key_length,
- uint8_t flush);
-
-memcached_return_t memcached_delete_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- time_t expiration)
-{
- uint8_t to_write;
- size_t send_length;
- memcached_return_t rc;
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- unsigned int server_key;
-
- LIBMEMCACHED_MEMCACHED_DELETE_START();
-
- rc= memcached_validate_key_length(key_length,
- ptr->flags.binary_protocol);
- unlikely (rc != MEMCACHED_SUCCESS)
- return rc;
-
- unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
- return MEMCACHED_NO_SERVERS;
-
- server_key= memcached_generate_hash(ptr, master_key, master_key_length);
- to_write= (uint8_t)((ptr->flags.buffer_requests) ? 0 : 1);
- bool no_reply= (ptr->flags.no_reply);
-
- if (ptr->flags.binary_protocol)
- {
- likely (!expiration)
- rc= binary_delete(ptr, server_key, key, key_length, to_write);
- else
- rc= MEMCACHED_INVALID_ARGUMENTS;
- }
- else
- {
- unlikely (expiration)
- {
- if ((ptr->hosts[server_key].major_version == 1 &&
- ptr->hosts[server_key].minor_version > 2) ||
- ptr->hosts[server_key].major_version > 1)
- {
- rc= MEMCACHED_INVALID_ARGUMENTS;
- goto error;
- }
- else
- {
- if (ptr->hosts[server_key].minor_version == 0)
- {
- if (no_reply || !to_write)
- {
- /* We might get out of sync with the server if we
- * send this command to a server newer than 1.2.x..
- * disable no_reply and buffered mode.
- */
- to_write= 1;
- if (no_reply)
- memcached_server_response_increment(&ptr->hosts[server_key]);
- no_reply= false;
- }
- }
- send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "delete %s%.*s %u%s\r\n",
- ptr->prefix_key,
- (int) key_length, key,
- (uint32_t)expiration,
- no_reply ? " noreply" :"" );
- }
- }
- else
- send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "delete %s%.*s%s\r\n",
- ptr->prefix_key,
- (int)key_length, key, no_reply ? " noreply" :"");
-
- if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
- {
- rc= MEMCACHED_WRITE_FAILURE;
- goto error;
- }
-
- if (ptr->flags.use_udp && !to_write)
- {
- if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
- return MEMCACHED_WRITE_FAILURE;
- if (send_length + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
- memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
- }
-
- rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, to_write);
- }
-
- if (rc != MEMCACHED_SUCCESS)
- goto error;
-
- if (!to_write)
- rc= MEMCACHED_BUFFERED;
- else if (!no_reply)
- {
- rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
- if (rc == MEMCACHED_DELETED)
- rc= MEMCACHED_SUCCESS;
- }
-
- if (rc == MEMCACHED_SUCCESS && ptr->delete_trigger)
- ptr->delete_trigger(ptr, key, key_length);
-
-error:
- LIBMEMCACHED_MEMCACHED_DELETE_END();
- return rc;
-}
-
-static inline memcached_return_t binary_delete(memcached_st *ptr,
- unsigned int server_key,
- const char *key,
- size_t key_length,
- uint8_t flush)
-{
- protocol_binary_request_delete request= {.bytes= {0}};
-
- request.message.header.request.magic= PROTOCOL_BINARY_REQ;
- if (ptr->flags.no_reply)
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
- else
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
- request.message.header.request.keylen= htons((uint16_t)key_length);
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t) key_length);
-
- if (ptr->flags.use_udp && !flush)
- {
- size_t cmd_size= sizeof(request.bytes) + key_length;
- if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
- return MEMCACHED_WRITE_FAILURE;
- if (cmd_size + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
- memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
- }
-
- memcached_return_t rc= MEMCACHED_SUCCESS;
-
- if ((memcached_do(&ptr->hosts[server_key], request.bytes,
- sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
- (memcached_io_write(&ptr->hosts[server_key], key,
- key_length, (char) flush) == -1))
- {
- memcached_io_reset(&ptr->hosts[server_key]);
- rc= MEMCACHED_WRITE_FAILURE;
- }
-
- unlikely (ptr->number_of_replicas > 0)
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
-
- for (uint32_t x= 0; x < ptr->number_of_replicas; ++x)
- {
- ++server_key;
- if (server_key == ptr->number_of_hosts)
- server_key= 0;
-
- memcached_server_st* server= &ptr->hosts[server_key];
- if ((memcached_do(server, (const char*)request.bytes,
- sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
- (memcached_io_write(server, key, key_length, (char) flush) == -1))
- memcached_io_reset(server);
- else
- memcached_server_response_decrement(server);
- }
- }
-
- return rc;
-}
+++ /dev/null
-#include "common.h"
-
-memcached_return_t memcached_do(memcached_server_st *ptr, const void *command,
- size_t command_length, uint8_t with_flush)
-{
- memcached_return_t rc;
- ssize_t sent_length;
-
- WATCHPOINT_ASSERT(command_length);
- WATCHPOINT_ASSERT(command);
-
- if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ERROR(rc);
- return rc;
- }
-
- /*
- ** Since non buffering ops in UDP mode dont check to make sure they will fit
- ** before they start writing, if there is any data in buffer, clear it out,
- ** otherwise we might get a partial write.
- **/
- if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH)
- memcached_io_write(ptr, NULL, 0, 1);
-
- sent_length= memcached_io_write(ptr, command, command_length, (char) with_flush);
-
- if (sent_length == -1 || (size_t)sent_length != command_length)
- rc= MEMCACHED_WRITE_FAILURE;
- else if ((ptr->root->flags.no_reply) == 0)
- memcached_server_response_increment(ptr);
-
- return rc;
-}
+++ /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= 0;
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- size_t send_length;
- uint32_t server_key;
- uint32_t x;
-
- unlikely (ptr->number_of_hosts == 0)
- return MEMCACHED_NO_SERVERS;
-
- for (server_key= 0; server_key < ptr->number_of_hosts; server_key++)
- {
- /* 256 I BELIEVE is the upper limit of slabs */
- for (x= 0; x < 256; x++)
- {
- send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "stats cachedump %u 0 0\r\n", x);
-
- rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
-
- unlikely (rc != MEMCACHED_SUCCESS)
- goto error;
-
- while (1)
- {
- uint32_t callback_counter;
- rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
- if (rc == MEMCACHED_ITEM)
- {
- char *string_ptr, *end_ptr;
- char *key;
-
- string_ptr= buffer;
- string_ptr+= 5; /* Move past ITEM */
- for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
- key= string_ptr;
- key[(size_t)(end_ptr-string_ptr)]= 0;
- for (callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++)
- {
- rc= (*callback[callback_counter])(ptr, key, (size_t)(end_ptr-string_ptr), context);
- if (rc != MEMCACHED_SUCCESS)
- break;
- }
- }
- else if (rc == MEMCACHED_END)
- break;
- else if (rc == MEMCACHED_SERVER_ERROR || rc == MEMCACHED_CLIENT_ERROR)
- {
- /* If we try to request stats cachedump for a slab class that is too big
- * the server will return an incorrect error message:
- * "MEMCACHED_SERVER_ERROR failed to allocate memory"
- * This isn't really a fatal error, so let's just skip it. I want to
- * fix the return value from the memcached server to a CLIENT_ERROR,
- * so let's add support for that as well right now.
- */
- rc= MEMCACHED_END;
- break;
- }
- else
- goto error;
- }
- }
- }
-
-error:
- if (rc == MEMCACHED_END)
- return MEMCACHED_SUCCESS;
- else
- return rc;
-}
-
-memcached_return_t memcached_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
-{
- /* No support for Binary protocol yet */
- if (ptr->flags.binary_protocol)
- return MEMCACHED_FAILURE;
-
- return ascii_dump(ptr, callback, context, number_of_callbacks);
-}
-
+++ /dev/null
-#include "common.h"
-#include "memcached_io.h"
-
-char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length,
- size_t *value_length,
- uint32_t *flags,
- memcached_return_t *error)
-{
- memcached_result_st *result_buffer= &ptr->result;
-
- unlikely (ptr->flags.use_udp)
- {
- *error= MEMCACHED_NOT_SUPPORTED;
- return NULL;
- }
-
- result_buffer= memcached_fetch_result(ptr, result_buffer, error);
-
- if (result_buffer == NULL || *error != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ASSERT(result_buffer == NULL);
- *value_length= 0;
- return NULL;
- }
-
- *value_length= memcached_string_length(&result_buffer->value);
-
- if (key)
- {
- strncpy(key, result_buffer->key, result_buffer->key_length);
- *key_length= result_buffer->key_length;
- }
-
- if (result_buffer->flags)
- *flags= result_buffer->flags;
- else
- *flags= 0;
-
- return memcached_string_c_copy(&result_buffer->value);
-}
-
-memcached_result_st *memcached_fetch_result(memcached_st *ptr,
- memcached_result_st *result,
- memcached_return_t *error)
-{
- memcached_server_st *server;
-
- unlikely (ptr->flags.use_udp)
- {
- *error= MEMCACHED_NOT_SUPPORTED;
- return NULL;
- }
-
- if (result == NULL)
- if ((result= memcached_result_create(ptr, NULL)) == NULL)
- return NULL;
-
- while ((server = memcached_io_get_readable_server(ptr)) != NULL)
- {
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- *error= memcached_response(server, buffer, sizeof(buffer), result);
-
- if (*error == MEMCACHED_SUCCESS)
- return result;
- else if (*error == MEMCACHED_END)
- memcached_server_response_reset(server);
- else if (*error != MEMCACHED_NOTFOUND)
- break;
- }
-
- /* We have completed reading data */
- if (memcached_is_allocated(result))
- {
- memcached_result_free(result);
- }
- else
- {
- memcached_string_reset(&result->value);
- }
-
- return NULL;
-}
-
-memcached_return_t memcached_fetch_execute(memcached_st *ptr,
- memcached_execute_fn *callback,
- void *context,
- uint32_t number_of_callbacks)
-{
- memcached_result_st *result= &ptr->result;
- memcached_return_t rc= MEMCACHED_FAILURE;
- unsigned int x;
-
- while ((result= memcached_fetch_result(ptr, result, &rc)) != NULL)
- {
- if (rc == MEMCACHED_SUCCESS)
- {
- for (x= 0; x < number_of_callbacks; x++)
- {
- rc= (*callback[x])(ptr, result, context);
- if (rc != MEMCACHED_SUCCESS)
- break;
- }
- }
- }
- return rc;
-}
+++ /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;
-
- LIBMEMCACHED_MEMCACHED_FLUSH_START();
- if (ptr->flags.binary_protocol)
- rc= memcached_flush_binary(ptr, expiration);
- else
- rc= memcached_flush_textual(ptr, expiration);
- LIBMEMCACHED_MEMCACHED_FLUSH_END();
- return rc;
-}
-
-static memcached_return_t memcached_flush_textual(memcached_st *ptr,
- time_t expiration)
-{
- unsigned int x;
- size_t send_length;
- memcached_return_t rc;
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
- unlikely (ptr->number_of_hosts == 0)
- return MEMCACHED_NO_SERVERS;
-
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- bool no_reply= ptr->flags.no_reply;
-
- if (expiration)
- send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "flush_all %llu%s\r\n",
- (unsigned long long)expiration, no_reply ? " noreply" : "");
- else
- send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "flush_all%s\r\n", no_reply ? " noreply" : "");
-
- rc= memcached_do(&ptr->hosts[x], buffer, send_length, 1);
-
- if (rc == MEMCACHED_SUCCESS && !no_reply)
- (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t memcached_flush_binary(memcached_st *ptr,
- time_t expiration)
-{
- unsigned int x;
- protocol_binary_request_flush request= {.bytes= {0}};
-
- unlikely (ptr->number_of_hosts == 0)
- return MEMCACHED_NO_SERVERS;
-
- request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ;
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
- request.message.header.request.extlen= 4;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl(request.message.header.request.extlen);
- request.message.body.expiration= htonl((uint32_t) expiration);
-
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- if (ptr->flags.no_reply)
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ;
- else
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
- if (memcached_do(&ptr->hosts[x], request.bytes,
- sizeof(request.bytes), 1) != MEMCACHED_SUCCESS)
- {
- memcached_io_reset(&ptr->hosts[x]);
- return MEMCACHED_WRITE_FAILURE;
- }
- }
-
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- if (memcached_server_response_count(&ptr->hosts[x]) > 0)
- (void)memcached_response(&ptr->hosts[x], NULL, 0, NULL);
- }
-
- return MEMCACHED_SUCCESS;
-}
+++ /dev/null
-#include "common.h"
-#include "memcached_io.h"
-
-memcached_return_t memcached_flush_buffers(memcached_st *mem)
-{
- memcached_return_t ret= MEMCACHED_SUCCESS;
-
- for (uint32_t x= 0; x < mem->number_of_hosts; ++x)
- if (mem->hosts[x].write_buffer_offset != 0)
- {
- if (mem->hosts[x].fd == -1 &&
- (ret= memcached_connect(&mem->hosts[x])) != MEMCACHED_SUCCESS)
- {
- WATCHPOINT_ERROR(ret);
- return ret;
- }
- if (memcached_io_write(&mem->hosts[x], NULL, 0, 1) == -1)
- ret= MEMCACHED_SOME_ERRORS;
- }
-
- return ret;
-}
+++ /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"
-#include "memcached_io.h"
-
-/*
- What happens if no servers exist?
-*/
-char *memcached_get(memcached_st *ptr, const char *key,
- size_t key_length,
- size_t *value_length,
- uint32_t *flags,
- memcached_return_t *error)
-{
- return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length,
- flags, error);
-}
-
-static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- bool mget_mode);
-
-char *memcached_get_by_key(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char *key, size_t key_length,
- size_t *value_length,
- uint32_t *flags,
- memcached_return_t *error)
-{
- char *value;
- size_t dummy_length;
- uint32_t dummy_flags;
- memcached_return_t dummy_error;
-
- unlikely (ptr->flags.use_udp)
- {
- *error= MEMCACHED_NOT_SUPPORTED;
- return NULL;
- }
-
- /* Request the key */
- *error= memcached_mget_by_key_real(ptr, master_key, master_key_length,
- (const char * const *)&key,
- &key_length, 1, false);
-
- value= memcached_fetch(ptr, NULL, NULL,
- value_length, flags, error);
- /* This is for historical reasons */
- if (*error == MEMCACHED_END)
- *error= MEMCACHED_NOTFOUND;
-
- if (value == NULL)
- {
- if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND)
- {
- memcached_return_t rc;
-
- memcached_result_reset(&ptr->result);
- rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result);
-
- /* On all failure drop to returning NULL */
- if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
- {
- if (rc == MEMCACHED_BUFFERED)
- {
- uint64_t latch; /* We use latch to track the state of the original socket */
- latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
- if (latch == 0)
- memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
-
- rc= memcached_set(ptr, key, key_length,
- memcached_result_value(&ptr->result),
- memcached_result_length(&ptr->result),
- 0, memcached_result_flags(&ptr->result));
-
- if (rc == MEMCACHED_BUFFERED && latch == 0)
- memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
- }
- else
- {
- rc= memcached_set(ptr, key, key_length,
- memcached_result_value(&ptr->result),
- memcached_result_length(&ptr->result),
- 0, memcached_result_flags(&ptr->result));
- }
-
- if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
- {
- *error= rc;
- *value_length= memcached_result_length(&ptr->result);
- *flags= memcached_result_flags(&ptr->result);
- return memcached_string_c_copy(&ptr->result.value);
- }
- }
- }
-
- return NULL;
- }
-
- (void)memcached_fetch(ptr, NULL, NULL,
- &dummy_length, &dummy_flags,
- &dummy_error);
- WATCHPOINT_ASSERT(dummy_length == 0);
-
- return value;
-}
-
-memcached_return_t memcached_mget(memcached_st *ptr,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys)
-{
- return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
-}
-
-static memcached_return_t binary_mget_by_key(memcached_st *ptr,
- unsigned int master_server_key,
- bool is_master_key_set,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- bool mget_mode);
-
-static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- bool mget_mode)
-{
- unsigned int x;
- memcached_return_t rc= MEMCACHED_NOTFOUND;
- const char *get_command= "get ";
- uint8_t get_command_length= 4;
- unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */
- bool is_master_key_set= false;
-
- unlikely (ptr->flags.use_udp)
- return MEMCACHED_NOT_SUPPORTED;
-
- LIBMEMCACHED_MEMCACHED_MGET_START();
- ptr->cursor_server= 0;
-
- if (number_of_keys == 0)
- return MEMCACHED_NOTFOUND;
-
- if (ptr->number_of_hosts == 0)
- return MEMCACHED_NO_SERVERS;
-
- if (ptr->flags.verify_key && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
- return MEMCACHED_BAD_KEY_PROVIDED;
-
- if (master_key && master_key_length)
- {
- if (ptr->flags.verify_key && (memcached_key_test((const char * const *)&master_key, &master_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
- return MEMCACHED_BAD_KEY_PROVIDED;
- master_server_key= memcached_generate_hash(ptr, master_key, master_key_length);
- is_master_key_set= true;
- }
-
- /*
- Here is where we pay for the non-block API. We need to remove any data sitting
- in the queue before we start our get.
-
- It might be optimum to bounce the connection if count > some number.
- */
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- if (memcached_server_response_count(&ptr->hosts[x]))
- {
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
- if (ptr->flags.no_block)
- (void)memcached_io_write(&ptr->hosts[x], NULL, 0, 1);
-
- while(memcached_server_response_count(&ptr->hosts[x]))
- (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
- }
- }
-
- if (ptr->flags.binary_protocol)
- return binary_mget_by_key(ptr, master_server_key, is_master_key_set, keys,
- key_length, number_of_keys, mget_mode);
-
- if (ptr->flags.support_cas)
- {
- get_command= "gets ";
- get_command_length= 5;
- }
-
- /*
- If a server fails we warn about errors and start all over with sending keys
- to the server.
- */
- for (x= 0; x < number_of_keys; x++)
- {
- unsigned int server_key;
-
- if (is_master_key_set)
- server_key= master_server_key;
- else
- server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
-
- if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
- {
- rc= memcached_connect(&ptr->hosts[server_key]);
-
- if (rc != MEMCACHED_SUCCESS)
- continue;
-
- if ((memcached_io_write(&ptr->hosts[server_key], get_command, get_command_length, 0)) == -1)
- {
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
- WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 0);
- memcached_server_response_increment(&ptr->hosts[server_key]);
- WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 1);
- }
-
- /* Only called when we have a prefix key */
- if (ptr->prefix_key[0] != 0)
- {
- if ((memcached_io_write(&ptr->hosts[server_key], ptr->prefix_key, ptr->prefix_key_length, 0)) == -1)
- {
- memcached_server_response_reset(&ptr->hosts[server_key]);
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
- }
-
- if ((memcached_io_write(&ptr->hosts[server_key], keys[x], key_length[x], 0)) == -1)
- {
- memcached_server_response_reset(&ptr->hosts[server_key]);
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
-
- if ((memcached_io_write(&ptr->hosts[server_key], " ", 1, 0)) == -1)
- {
- memcached_server_response_reset(&ptr->hosts[server_key]);
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
- }
-
- /*
- Should we muddle on if some servers are dead?
- */
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- if (memcached_server_response_count(&ptr->hosts[x]))
- {
- /* We need to do something about non-connnected hosts in the future */
- if ((memcached_io_write(&ptr->hosts[x], "\r\n", 2, 1)) == -1)
- {
- rc= MEMCACHED_SOME_ERRORS;
- }
- }
- }
-
- LIBMEMCACHED_MEMCACHED_MGET_END();
- return rc;
-}
-
-memcached_return_t memcached_mget_by_key(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys)
-{
- return memcached_mget_by_key_real(ptr, master_key, master_key_length, keys,
- key_length, number_of_keys, true);
-}
-
-memcached_return_t memcached_mget_execute(memcached_st *ptr,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- memcached_execute_fn *callback,
- void *context,
- unsigned int number_of_callbacks)
-{
- return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length,
- number_of_keys, callback,
- context, number_of_callbacks);
-}
-
-memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- memcached_execute_fn *callback,
- void *context,
- unsigned int number_of_callbacks)
-{
- if ((ptr->flags.binary_protocol) == 0)
- return MEMCACHED_NOT_SUPPORTED;
-
- memcached_return_t rc;
- memcached_callback_st *original_callbacks= ptr->callbacks;
- memcached_callback_st cb= {
- .callback= callback,
- .context= context,
- .number_of_callback= number_of_callbacks
- };
-
- ptr->callbacks= &cb;
- rc= memcached_mget_by_key(ptr, master_key, master_key_length, keys,
- key_length, number_of_keys);
- ptr->callbacks= original_callbacks;
- return rc;
-}
-
-static memcached_return_t simple_binary_mget(memcached_st *ptr,
- unsigned int master_server_key,
- bool is_master_key_set,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys, bool mget_mode)
-{
- memcached_return_t rc= MEMCACHED_NOTFOUND;
- uint32_t x;
-
- int flush= number_of_keys == 1;
-
- /*
- If a server fails we warn about errors and start all over with sending keys
- to the server.
- */
- for (x= 0; x < number_of_keys; x++)
- {
- unsigned int server_key;
-
- if (is_master_key_set)
- server_key= master_server_key;
- else
- server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
-
- if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
- {
- rc= memcached_connect(&ptr->hosts[server_key]);
- if (rc != MEMCACHED_SUCCESS)
- continue;
- }
-
- protocol_binary_request_getk request= {.bytes= {0}};
- request.message.header.request.magic= PROTOCOL_BINARY_REQ;
- if (mget_mode)
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ;
- else
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
-
- memcached_return_t vk;
- vk= memcached_validate_key_length(key_length[x],
- ptr->flags.binary_protocol);
- unlikely (vk != MEMCACHED_SUCCESS)
- {
- if (x > 0)
- memcached_io_reset(&ptr->hosts[server_key]);
- return vk;
- }
-
- request.message.header.request.keylen= htons((uint16_t)key_length[x]);
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t) key_length[x]);
-
- if ((memcached_io_write(&ptr->hosts[server_key], request.bytes,
- sizeof(request.bytes), 0) == -1) ||
- (memcached_io_write(&ptr->hosts[server_key], keys[x],
- key_length[x], (char) flush) == -1))
- {
- memcached_server_response_reset(&ptr->hosts[server_key]);
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
-
- /* We just want one pending response per server */
- memcached_server_response_reset(&ptr->hosts[server_key]);
- memcached_server_response_increment(&ptr->hosts[server_key]);
- if ((x > 0 && x == ptr->io_key_prefetch) &&
- memcached_flush_buffers(ptr) != MEMCACHED_SUCCESS)
- rc= MEMCACHED_SOME_ERRORS;
- }
-
- if (mget_mode)
- {
- /*
- * Send a noop command to flush the buffers
- */
- protocol_binary_request_noop request= {.bytes= {0}};
- request.message.header.request.magic= PROTOCOL_BINARY_REQ;
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_NOOP;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
- for (x= 0; x < ptr->number_of_hosts; x++)
- if (memcached_server_response_count(&ptr->hosts[x]))
- {
- if (memcached_io_write(&ptr->hosts[x], NULL, 0, 1) == -1)
- {
- memcached_server_response_reset(&ptr->hosts[x]);
- memcached_io_reset(&ptr->hosts[x]);
- rc= MEMCACHED_SOME_ERRORS;
- }
-
- if (memcached_io_write(&ptr->hosts[x], request.bytes,
- sizeof(request.bytes), 1) == -1)
- {
- memcached_server_response_reset(&ptr->hosts[x]);
- memcached_io_reset(&ptr->hosts[x]);
- rc= MEMCACHED_SOME_ERRORS;
- }
- }
- }
-
-
- return rc;
-}
-
-static memcached_return_t replication_binary_mget(memcached_st *ptr,
- uint32_t* hash,
- bool* dead_servers,
- const char *const *keys,
- const size_t *key_length,
- size_t number_of_keys)
-{
- memcached_return_t rc= MEMCACHED_NOTFOUND;
- uint32_t x, start= 0;
- uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
-
- if (randomize_read)
- start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1);
-
- /* Loop for each replica */
- for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica)
- {
- bool success= true;
-
- for (x= 0; x < number_of_keys; ++x)
- {
- if (hash[x] == ptr->number_of_hosts)
- 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 >= ptr->number_of_hosts)
- server -= ptr->number_of_hosts;
-
- if (dead_servers[server])
- continue;
-
- if (memcached_server_response_count(&ptr->hosts[server]) == 0)
- {
- rc= memcached_connect(&ptr->hosts[server]);
- if (rc != MEMCACHED_SUCCESS)
- {
- memcached_io_reset(&ptr->hosts[server]);
- dead_servers[server]= true;
- success= false;
- continue;
- }
- }
-
- protocol_binary_request_getk request= {
- .message.header.request= {
- .magic= PROTOCOL_BINARY_REQ,
- .opcode= PROTOCOL_BINARY_CMD_GETK,
- .keylen= htons((uint16_t)key_length[x]),
- .datatype= PROTOCOL_BINARY_RAW_BYTES,
- .bodylen= htonl((uint32_t)key_length[x])
- }
- };
-
- /*
- * We need to disable buffering to actually know that the request was
- * successfully sent to the server (so that we should expect a result
- * back). It would be nice to do this in buffered mode, but then it
- * would be complex to handle all error situations if we got to send
- * some of the messages, and then we failed on writing out some others
- * and we used the callback interface from memcached_mget_execute so
- * that we might have processed some of the responses etc. For now,
- * just make sure we work _correctly_
- */
- if ((memcached_io_write(&ptr->hosts[server], request.bytes,
- sizeof(request.bytes), 0) == -1) ||
- (memcached_io_write(&ptr->hosts[server], keys[x],
- key_length[x], 1) == -1))
- {
- memcached_io_reset(&ptr->hosts[server]);
- dead_servers[server]= true;
- success= false;
- continue;
- }
-
- memcached_server_response_increment(&ptr->hosts[server]);
- hash[x]= ptr->number_of_hosts;
- }
-
- if (success)
- break;
- }
-
- return rc;
-}
-
-static memcached_return_t binary_mget_by_key(memcached_st *ptr,
- unsigned int master_server_key,
- bool is_master_key_set,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- bool mget_mode)
-{
- memcached_return_t rc;
-
- if (ptr->number_of_replicas == 0)
- {
- rc= simple_binary_mget(ptr, master_server_key, is_master_key_set,
- keys, key_length, number_of_keys, mget_mode);
- }
- else
- {
- uint32_t* hash;
- bool* dead_servers;
-
- hash= ptr->call_malloc(ptr, sizeof(uint32_t) * number_of_keys);
- dead_servers= ptr->call_calloc(ptr, ptr->number_of_hosts, sizeof(bool));
-
- if (hash == NULL || dead_servers == NULL)
- {
- ptr->call_free(ptr, hash);
- ptr->call_free(ptr, dead_servers);
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- if (is_master_key_set)
- for (unsigned int x= 0; x < number_of_keys; x++)
- hash[x]= master_server_key;
- else
- for (unsigned int x= 0; x < number_of_keys; x++)
- hash[x]= memcached_generate_hash(ptr, keys[x], key_length[x]);
-
- rc= replication_binary_mget(ptr, hash, dead_servers, keys,
- key_length, number_of_keys);
-
- ptr->call_free(ptr, hash);
- ptr->call_free(ptr, dead_servers);
-
- return MEMCACHED_SUCCESS;
- }
-
- return rc;
-}
+++ /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
- *
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_GET_H
-#define LIBMEMCACHED_MEMCACHED_GET_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Public defines */
-LIBMEMCACHED_API
-char *memcached_get(memcached_st *ptr,
- const char *key, size_t key_length,
- size_t *value_length,
- uint32_t *flags,
- memcached_return_t *error);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_mget(memcached_st *ptr,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys);
-
-LIBMEMCACHED_API
-char *memcached_get_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- size_t *value_length,
- uint32_t *flags,
- memcached_return_t *error);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_mget_by_key(memcached_st *ptr,
- const char *master_key, size_t
- master_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys);
-
-LIBMEMCACHED_API
-char *memcached_fetch(memcached_st *ptr,
- char *key, size_t *key_length,
- size_t *value_length, uint32_t *flags,
- memcached_return_t *error);
-
-LIBMEMCACHED_API
-memcached_result_st *memcached_fetch_result(memcached_st *ptr,
- memcached_result_st *result,
- memcached_return_t *error);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_mget_execute(memcached_st *ptr,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- memcached_execute_fn *callback,
- void *context,
- unsigned int number_of_callbacks);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char * const *keys,
- const size_t *key_length,
- size_t number_of_keys,
- memcached_execute_fn *callback,
- void *context,
- unsigned int number_of_callbacks);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBMEMCACHED_MEMCACHED_GET_H */
+++ /dev/null
-#include "common.h"
-
-
-/* Defines */
-static uint64_t FNV_64_INIT= UINT64_C(0xcbf29ce484222325);
-static uint64_t FNV_64_PRIME= UINT64_C(0x100000001b3);
-
-static uint32_t FNV_32_INIT= 2166136261UL;
-static uint32_t FNV_32_PRIME= 16777619;
-
-/* Prototypes */
-static uint32_t internal_generate_hash(const char *key, size_t key_length);
-static uint32_t internal_generate_md5(const char *key, size_t key_length);
-
-uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm)
-{
- uint32_t hash= 1; /* Just here to remove compile warning */
- uint32_t x= 0;
-
- switch (hash_algorithm)
- {
- case MEMCACHED_HASH_DEFAULT:
- hash= internal_generate_hash(key, key_length);
- break;
- case MEMCACHED_HASH_MD5:
- hash= internal_generate_md5(key, key_length);
- break;
- case MEMCACHED_HASH_CRC:
- hash= ((hash_crc32(key, key_length) >> 16) & 0x7fff);
- if (hash == 0)
- hash= 1;
- break;
- /* FNV hash'es lifted from Dustin Sallings work */
- case MEMCACHED_HASH_FNV1_64:
- {
- /* Thanks to pierre@demartines.com for the pointer */
- uint64_t temp_hash;
-
- temp_hash= FNV_64_INIT;
- for (x= 0; x < key_length; x++)
- {
- temp_hash *= FNV_64_PRIME;
- temp_hash ^= (uint64_t)key[x];
- }
- hash= (uint32_t)temp_hash;
- }
- break;
- case MEMCACHED_HASH_FNV1A_64:
- {
- hash= (uint32_t) FNV_64_INIT;
- for (x= 0; x < key_length; x++)
- {
- uint32_t val= (uint32_t)key[x];
- hash ^= val;
- hash *= (uint32_t) FNV_64_PRIME;
- }
- }
- break;
- case MEMCACHED_HASH_FNV1_32:
- {
- hash= FNV_32_INIT;
- for (x= 0; x < key_length; x++)
- {
- uint32_t val= (uint32_t)key[x];
- hash *= FNV_32_PRIME;
- hash ^= val;
- }
- }
- break;
- case MEMCACHED_HASH_FNV1A_32:
- {
- hash= FNV_32_INIT;
- for (x= 0; x < key_length; x++)
- {
- uint32_t val= (uint32_t)key[x];
- hash ^= val;
- hash *= FNV_32_PRIME;
- }
- }
- break;
- case MEMCACHED_HASH_HSIEH:
- {
-#ifdef HAVE_HSIEH_HASH
- hash= hsieh_hash(key, key_length);
-#endif
- break;
- }
- case MEMCACHED_HASH_MURMUR:
- {
- hash= murmur_hash(key, key_length);
- break;
- }
- case MEMCACHED_HASH_JENKINS:
- {
- hash=jenkins_hash(key, key_length, 13);
- break;
- }
- default:
- {
- WATCHPOINT_ASSERT(hash_algorithm);
- break;
- }
- }
- return hash;
-}
-
-uint32_t generate_hash(memcached_st *ptr, const char *key, size_t key_length)
-{
- uint32_t hash= 1; /* Just here to remove compile warning */
-
-
- WATCHPOINT_ASSERT(ptr->number_of_hosts);
-
- if (ptr->number_of_hosts == 1)
- return 0;
-
- hash= memcached_generate_hash_value(key, key_length, ptr->hash);
- WATCHPOINT_ASSERT(hash);
- return hash;
-}
-
-static uint32_t dispatch_host(memcached_st *ptr, uint32_t hash)
-{
- switch (ptr->distribution)
- {
- case MEMCACHED_DISTRIBUTION_CONSISTENT:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
- {
- uint32_t num= ptr->continuum_points_counter;
- WATCHPOINT_ASSERT(ptr->continuum);
-
- hash= hash;
- memcached_continuum_item_st *begin, *end, *left, *right, *middle;
- begin= left= ptr->continuum;
- end= right= ptr->continuum + num;
-
- while (left < right)
- {
- middle= left + (right - left) / 2;
- if (middle->value < hash)
- left= middle + 1;
- else
- right= middle;
- }
- if (right == end)
- right= begin;
- return right->index;
- }
- case MEMCACHED_DISTRIBUTION_MODULA:
- return hash % ptr->number_of_hosts;
- case MEMCACHED_DISTRIBUTION_RANDOM:
- return (uint32_t) random() % ptr->number_of_hosts;
- default:
- WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
- return hash % ptr->number_of_hosts;
- }
-
- /* NOTREACHED */
-}
-
-/*
- One day make this public, and have it return the actual memcached_server_st
- to the calling application.
-*/
-uint32_t memcached_generate_hash(memcached_st *ptr, const char *key, size_t key_length)
-{
- uint32_t hash= 1; /* Just here to remove compile warning */
-
- WATCHPOINT_ASSERT(ptr->number_of_hosts);
-
- if (ptr->number_of_hosts == 1)
- return 0;
-
- if (ptr->flags.hash_with_prefix_key)
- {
- size_t temp_length= ptr->prefix_key_length + key_length;
- char temp[temp_length];
-
- if (temp_length > MEMCACHED_MAX_KEY -1)
- return 0;
-
- strncpy(temp, ptr->prefix_key, ptr->prefix_key_length);
- strncpy(temp + ptr->prefix_key_length, key, key_length);
- hash= generate_hash(ptr, temp, temp_length);
- }
- else
- {
- hash= generate_hash(ptr, key, key_length);
- }
-
- WATCHPOINT_ASSERT(hash);
-
- if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS) && ptr->next_distribution_rebuild) {
- struct timeval now;
-
- if (gettimeofday(&now, NULL) == 0 &&
- now.tv_sec > ptr->next_distribution_rebuild)
- run_distribution(ptr);
- }
-
- return dispatch_host(ptr, hash);
-}
-
-static uint32_t internal_generate_hash(const char *key, size_t key_length)
-{
- const char *ptr= key;
- uint32_t value= 0;
-
- while (key_length--)
- {
- uint32_t val= (uint32_t) *ptr++;
- value += val;
- value += (value << 10);
- value ^= (value >> 6);
- }
- value += (value << 3);
- value ^= (value >> 11);
- value += (value << 15);
-
- return value == 0 ? 1 : (uint32_t) value;
-}
-
-static uint32_t internal_generate_md5(const char *key, size_t key_length)
-{
- unsigned char results[16];
-
- md5_signature((unsigned char*)key, (unsigned int)key_length, results);
-
- return ((uint32_t) (results[3] & 0xFF) << 24)
- | ((uint32_t) (results[2] & 0xFF) << 16)
- | ((uint32_t) (results[1] & 0xFF) << 8)
- | (results[0] & 0xFF);
-}
+++ /dev/null
-#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);
-memcached_return_t update_continuum(memcached_st *ptr);
-
-static int compare_servers(const void *p1, const void *p2)
-{
- int return_value;
- memcached_server_st *a= (memcached_server_st *)p1;
- memcached_server_st *b= (memcached_server_st *)p2;
-
- return_value= strcmp(a->hostname, b->hostname);
-
- if (return_value == 0)
- {
- return_value= (int) (a->port - b->port);
- }
-
- return return_value;
-}
-
-static void sort_hosts(memcached_st *ptr)
-{
- if (ptr->number_of_hosts)
- {
- qsort(ptr->hosts, ptr->number_of_hosts, sizeof(memcached_server_st), compare_servers);
- ptr->hosts[0].count= (uint16_t) ptr->number_of_hosts;
- }
-}
-
-
-memcached_return_t run_distribution(memcached_st *ptr)
-{
- switch (ptr->distribution)
- {
- case MEMCACHED_DISTRIBUTION_CONSISTENT:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
- case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
- return update_continuum(ptr);
- case MEMCACHED_DISTRIBUTION_MODULA:
- if (ptr->flags.use_sort_hosts)
- sort_hosts(ptr);
- break;
- case MEMCACHED_DISTRIBUTION_RANDOM:
- break;
- default:
- WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
- }
-
- ptr->last_disconnected_server = NULL;
-
- return MEMCACHED_SUCCESS;
-}
-
-void server_list_free(memcached_st *ptr, memcached_server_st *servers)
-{
- unsigned int x;
-
- if (servers == NULL)
- return;
-
- for (x= 0; x < servers->count; x++)
- if (servers[x].address_info)
- {
- freeaddrinfo(servers[x].address_info);
- servers[x].address_info= NULL;
- }
-
- if (ptr)
- ptr->call_free(ptr, servers);
- else
- free(servers);
-}
-
-static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment)
-{
- unsigned char results[16];
-
- md5_signature((unsigned char*)key, key_length, results);
- return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
- | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
- | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
- | (results[0 + alignment * 4] & 0xFF);
-}
-
-static int continuum_item_cmp(const void *t1, const void *t2)
-{
- memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1;
- memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2;
-
- /* Why 153? Hmmm... */
- WATCHPOINT_ASSERT(ct1->value != 153);
- if (ct1->value == ct2->value)
- return 0;
- else if (ct1->value > ct2->value)
- return 1;
- else
- return -1;
-}
-
-memcached_return_t update_continuum(memcached_st *ptr)
-{
- uint32_t host_index;
- uint32_t continuum_index= 0;
- uint32_t value;
- memcached_server_st *list;
- uint32_t pointer_index;
- uint32_t pointer_counter= 0;
- uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
- uint32_t pointer_per_hash= 1;
- uint64_t total_weight= 0;
- uint64_t is_ketama_weighted= 0;
- uint64_t is_auto_ejecting= 0;
- uint32_t points_per_server= 0;
- uint32_t live_servers= 0;
- struct timeval now;
-
- if (gettimeofday(&now, NULL) != 0)
- {
- ptr->cached_errno = errno;
- return MEMCACHED_ERRNO;
- }
-
- list = ptr->hosts;
-
- /* count live servers (those without a retry delay set) */
- is_auto_ejecting= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
- if (is_auto_ejecting)
- {
- live_servers= 0;
- ptr->next_distribution_rebuild= 0;
- for (host_index= 0; host_index < ptr->number_of_hosts; ++host_index)
- {
- if (list[host_index].next_retry <= now.tv_sec)
- live_servers++;
- else
- {
- if (ptr->next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->next_distribution_rebuild)
- ptr->next_distribution_rebuild= list[host_index].next_retry;
- }
- }
- }
- else
- live_servers= ptr->number_of_hosts;
-
- is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
- points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER);
-
- if (live_servers == 0)
- return MEMCACHED_SUCCESS;
-
- if (live_servers > ptr->continuum_count)
- {
- memcached_continuum_item_st *new_ptr;
-
- new_ptr= ptr->call_realloc(ptr, ptr->continuum,
- sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);
-
- if (new_ptr == 0)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- ptr->continuum= new_ptr;
- ptr->continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
- }
-
- if (is_ketama_weighted)
- {
- for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index)
- {
- if (list[host_index].weight == 0)
- {
- list[host_index].weight = 1;
- }
- if (!is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
- total_weight += list[host_index].weight;
- }
- }
-
- for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index)
- {
- if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec)
- continue;
-
- if (is_ketama_weighted)
- {
- float pct = (float)list[host_index].weight / (float)total_weight;
- pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
- pointer_per_hash= 4;
-#ifdef DEBUG
- printf("ketama_weighted:%s|%d|%llu|%u\n",
- list[host_index].hostname,
- list[host_index].port,
- (unsigned long long)list[host_index].weight,
- pointer_per_server);
-#endif
- }
-
-
- if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY)
- {
- for (pointer_index= 0;
- pointer_index < pointer_per_server / pointer_per_hash;
- pointer_index++)
- {
- char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
- size_t sort_host_length;
-
- // Spymemcached ketema key format is: hostname/ip:port-index
- // If hostname is not available then: /ip:port-index
- sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
- "/%s:%d-%d",
- list[host_index].hostname,
- list[host_index].port,
- pointer_index);
-#ifdef DEBUG
- printf("update_continuum: key is %s\n", sort_host);
-#endif
-
- WATCHPOINT_ASSERT(sort_host_length);
-
- if (is_ketama_weighted)
- {
- unsigned int i;
- for (i = 0; i < pointer_per_hash; i++)
- {
- value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
- ptr->continuum[continuum_index].index= host_index;
- ptr->continuum[continuum_index++].value= value;
- }
- }
- else
- {
- value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum);
- ptr->continuum[continuum_index].index= host_index;
- ptr->continuum[continuum_index++].value= value;
- }
- }
- }
- else
- {
- for (pointer_index= 1;
- pointer_index <= pointer_per_server / pointer_per_hash;
- pointer_index++)
- {
- char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
- size_t sort_host_length;
-
- if (list[host_index].port == MEMCACHED_DEFAULT_PORT)
- {
- sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
- "%s-%d",
- list[host_index].hostname,
- pointer_index - 1);
- }
- else
- {
- sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
- "%s:%d-%d",
- list[host_index].hostname,
- list[host_index].port, pointer_index - 1);
- }
-
- WATCHPOINT_ASSERT(sort_host_length);
-
- if (is_ketama_weighted)
- {
- unsigned int i;
- for (i = 0; i < pointer_per_hash; i++)
- {
- value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
- ptr->continuum[continuum_index].index= host_index;
- ptr->continuum[continuum_index++].value= value;
- }
- }
- else
- {
- value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum);
- ptr->continuum[continuum_index].index= host_index;
- ptr->continuum[continuum_index++].value= value;
- }
- }
- }
-
- pointer_counter+= pointer_per_server;
- }
-
- WATCHPOINT_ASSERT(ptr);
- WATCHPOINT_ASSERT(ptr->continuum);
- WATCHPOINT_ASSERT(ptr->number_of_hosts * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE);
- ptr->continuum_points_counter= pointer_counter;
- qsort(ptr->continuum, ptr->continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
-
-#ifdef DEBUG
- for (pointer_index= 0; ptr->number_of_hosts && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
- {
- WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value);
- }
-#endif
-
- return MEMCACHED_SUCCESS;
-}
-
-
-memcached_return_t memcached_server_push(memcached_st *ptr, memcached_server_st *list)
-{
- unsigned int x;
- uint16_t count;
- memcached_server_st *new_host_list;
-
- if (!list)
- return MEMCACHED_SUCCESS;
-
- count= list[0].count;
- new_host_list= ptr->call_realloc(ptr, ptr->hosts,
- sizeof(memcached_server_st) * (count + ptr->number_of_hosts));
-
- if (!new_host_list)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- ptr->hosts= new_host_list;
-
- for (x= 0; x < count; x++)
- {
- if ((ptr->flags.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);
- memcached_server_create(ptr, &ptr->hosts[ptr->number_of_hosts]);
- /* TODO check return type */
- (void)memcached_server_create_with(ptr, &ptr->hosts[ptr->number_of_hosts], list[x].hostname,
- list[x].port, list[x].weight, list[x].type);
- ptr->number_of_hosts++;
- }
- ptr->hosts[0].count= (uint16_t) ptr->number_of_hosts;
-
- return run_distribution(ptr);
-}
-
-memcached_return_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;
-
- if ( (ptr->flags.use_udp && type != MEMCACHED_CONNECTION_UDP)
- || ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) )
- return MEMCACHED_INVALID_HOST_PROTOCOL;
-
- new_host_list= ptr->call_realloc(ptr, ptr->hosts,
- sizeof(memcached_server_st) * (ptr->number_of_hosts+1));
-
- if (new_host_list == NULL)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- ptr->hosts= new_host_list;
-
- /* TODO: Check return type */
- (void)memcached_server_create_with(ptr, &ptr->hosts[ptr->number_of_hosts], hostname, port, weight, type);
- ptr->number_of_hosts++;
- ptr->hosts[0].count= (uint16_t) ptr->number_of_hosts;
-
- return run_distribution(ptr);
-}
-
-memcached_return_t memcached_server_remove(memcached_server_st *st_ptr)
-{
- uint32_t x, host_index;
- memcached_st *ptr= st_ptr->root;
- memcached_server_st *list= ptr->hosts;
-
- for (x= 0, host_index= 0; x < ptr->number_of_hosts; x++)
- {
- if (strncmp(list[x].hostname, st_ptr->hostname, MEMCACHED_MAX_HOST_LENGTH) != 0 || list[x].port != st_ptr->port)
- {
- if (host_index != x)
- memcpy(list+host_index, list+x, sizeof(memcached_server_st));
- host_index++;
- }
- }
- ptr->number_of_hosts= host_index;
-
- if (st_ptr->address_info)
- {
- freeaddrinfo(st_ptr->address_info);
- st_ptr->address_info= NULL;
- }
- run_distribution(ptr);
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_server_st *memcached_server_list_append(memcached_server_st *ptr,
- const char *hostname, in_port_t port,
- memcached_return_t *error)
-{
- return memcached_server_list_append_with_weight(ptr, hostname, port, 0, error);
-}
-
-memcached_server_st *memcached_server_list_append_with_weight(memcached_server_st *ptr,
- const char *hostname, in_port_t port,
- uint32_t weight,
- memcached_return_t *error)
-{
- unsigned int count;
- memcached_server_st *new_host_list;
-
- if (hostname == NULL || error == NULL)
- return NULL;
-
- if (!port)
- port= MEMCACHED_DEFAULT_PORT;
-
- /* Increment count for hosts */
- count= 1;
- if (ptr != NULL)
- {
- count+= ptr[0].count;
- }
-
- new_host_list= (memcached_server_st *)realloc(ptr, sizeof(memcached_server_st) * count);
- if (!new_host_list)
- {
- *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return NULL;
- }
-
- /* TODO: Check return type */
- memcached_server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, MEMCACHED_CONNECTION_TCP);
-
- /* Backwards compatibility hack */
- new_host_list[0].count= (uint16_t) count;
-
- *error= MEMCACHED_SUCCESS;
- return new_host_list;
-}
-
-unsigned int memcached_server_list_count(memcached_server_st *ptr)
-{
- if (ptr == NULL)
- return 0;
-
- return ptr[0].count;
-}
-
-void memcached_server_list_free(memcached_server_st *ptr)
-{
- server_list_free(NULL, ptr);
-}
+++ /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: Internal functions used by the library. Not for public use!
- *
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_INTERNAL_H
-#define LIBMEMCACHED_MEMCACHED_INTERNAL_H
-
-#if defined(BUILDING_LIBMEMCACHED)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_LOCAL
-void libmemcached_free(memcached_st *ptr, void *mem);
-LIBMEMCACHED_LOCAL
-void *libmemcached_malloc(memcached_st *ptr, const size_t size);
-LIBMEMCACHED_LOCAL
-void *libmemcached_realloc(memcached_st *ptr, void *mem, const size_t size);
-LIBMEMCACHED_LOCAL
-void *libmemcached_calloc(memcached_st *ptr, size_t nelem, size_t size);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BUILDING_LIBMEMCACHED */
-#endif /* LIBMEMCACHED_MEMCACHED_INTERNAL_H */
+++ /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: Server IO, Not public!
- *
- */
-
-
-#include "common.h"
-#include "memcached_io.h"
-#include <sys/select.h>
-#include <poll.h>
-
-typedef enum {
- MEM_READ,
- MEM_WRITE
-} memc_read_or_write;
-
-static ssize_t io_flush(memcached_server_st *ptr, memcached_return_t *error);
-static void increment_udp_message_id(memcached_server_st *ptr);
-
-static memcached_return_t io_wait(memcached_server_st *ptr,
- memc_read_or_write read_or_write)
-{
- struct pollfd fds= {
- .fd= ptr->fd,
- .events = POLLIN
- };
- int error;
-
- unlikely (read_or_write == MEM_WRITE) /* write */
- fds.events= POLLOUT;
-
- /*
- ** We are going to block on write, but at least on Solaris we might block
- ** on write if we haven't read anything from our input buffer..
- ** Try to purge the input buffer if we don't do any flow control in the
- ** application layer (just sending a lot of data etc)
- ** The test is moved down in the purge function to avoid duplication of
- ** the test.
- */
- if (read_or_write == MEM_WRITE)
- {
- memcached_return_t rc= memcached_purge(ptr);
- if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
- return MEMCACHED_FAILURE;
- }
-
- int timeout= ptr->root->poll_timeout;
- if (ptr->root->flags.no_block == false)
- timeout= -1;
-
- error= poll(&fds, 1, timeout);
-
- if (error == 1)
- return MEMCACHED_SUCCESS;
- else if (error == 0)
- return MEMCACHED_TIMEOUT;
-
- /* Imposssible for anything other then -1 */
- WATCHPOINT_ASSERT(error == -1);
- memcached_quit_server(ptr, 1);
-
- return MEMCACHED_FAILURE;
-}
-
-/**
- * Try to fill the input buffer for a server with as much
- * data as possible.
- *
- * @param ptr the server to pack
- */
-static bool repack_input_buffer(memcached_server_st *ptr)
-{
- if (ptr->read_ptr != ptr->read_buffer)
- {
- /* Move all of the data to the beginning of the buffer so
- ** that we can fit more data into the buffer...
- */
- memmove(ptr->read_buffer, ptr->read_ptr, ptr->read_buffer_length);
- ptr->read_ptr= ptr->read_buffer;
- ptr->read_data_length= ptr->read_buffer_length;
- }
-
- /* There is room in the buffer, try to fill it! */
- if (ptr->read_buffer_length != MEMCACHED_MAX_BUFFER)
- {
- /* Just try a single read to grab what's available */
- ssize_t nr= read(ptr->fd,
- ptr->read_ptr + ptr->read_data_length,
- MEMCACHED_MAX_BUFFER - ptr->read_data_length);
-
- if (nr > 0)
- {
- ptr->read_data_length+= (size_t)nr;
- ptr->read_buffer_length+= (size_t)nr;
- return true;
- }
- }
- return false;
-}
-
-/**
- * If the we have callbacks connected to this server structure
- * we may start process the input queue and fire the callbacks
- * for the incomming messages. This function is _only_ called
- * when the input buffer is full, so that we _know_ that we have
- * at least _one_ message to process.
- *
- * @param ptr the server to star processing iput messages for
- * @return true if we processed anything, false otherwise
- */
-static bool process_input_buffer(memcached_server_st *ptr)
-{
- /*
- ** We might be able to process some of the response messages if we
- ** have a callback set up
- */
- if (ptr->root->callbacks != NULL && ptr->root->flags.use_udp == false)
- {
- /*
- * We might have responses... try to read them out and fire
- * callbacks
- */
- memcached_callback_st cb= *ptr->root->callbacks;
-
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- memcached_return_t error;
- error= memcached_response(ptr, buffer, sizeof(buffer),
- &ptr->root->result);
- if (error == MEMCACHED_SUCCESS)
- {
- for (unsigned int x= 0; x < cb.number_of_callback; x++)
- {
- error= (*cb.callback[x])(ptr->root, &ptr->root->result, cb.context);
- if (error != MEMCACHED_SUCCESS)
- break;
- }
-
- /* @todo what should I do with the error message??? */
- }
- /* @todo what should I do with other error messages?? */
- return true;
- }
-
- return false;
-}
-
-#ifdef UNUSED
-void memcached_io_preread(memcached_st *ptr)
-{
- unsigned int x;
-
- return;
-
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- if (memcached_server_response_count(ptr, x) &&
- ptr->hosts[x].read_data_length < MEMCACHED_MAX_BUFFER )
- {
- size_t data_read;
-
- data_read= read(ptr->hosts[x].fd,
- ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length,
- MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length);
- if (data_read == -1)
- continue;
-
- ptr->hosts[x].read_buffer_length+= data_read;
- ptr->hosts[x].read_data_length+= data_read;
- }
- }
-}
-#endif
-
-memcached_return_t memcached_io_read(memcached_server_st *ptr,
- void *buffer, size_t length, ssize_t *nread)
-{
- char *buffer_ptr;
-
- buffer_ptr= buffer;
-
- while (length)
- {
- if (!ptr->read_buffer_length)
- {
- ssize_t data_read;
-
- while (1)
- {
- data_read= read(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER);
- if (data_read > 0)
- break;
- else if (data_read == -1)
- {
- ptr->cached_errno= errno;
- memcached_return_t rc= MEMCACHED_UNKNOWN_READ_FAILURE;
- switch (errno)
- {
- case EAGAIN:
- case EINTR:
- if ((rc= io_wait(ptr, MEM_READ)) == MEMCACHED_SUCCESS)
- continue;
- /* fall through */
-
- default:
- {
- memcached_quit_server(ptr, 1);
- *nread= -1;
- return rc;
- }
- }
- }
- else
- {
- /*
- EOF. Any data received so far is incomplete
- so discard it. This always reads by byte in case of TCP
- and protocol enforcement happens at memcached_response()
- looking for '\n'. We do not care for UDB which requests 8 bytes
- at once. Generally, this means that connection went away. Since
- for blocking I/O we do not return 0 and for non-blocking case
- it will return EGAIN if data is not immediatly available.
- */
- memcached_quit_server(ptr, 1);
- *nread= -1;
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- }
-
- ptr->io_bytes_sent = 0;
- ptr->read_data_length= (size_t) data_read;
- ptr->read_buffer_length= (size_t) data_read;
- ptr->read_ptr= ptr->read_buffer;
- }
-
- if (length > 1)
- {
- size_t difference;
-
- difference= (length > ptr->read_buffer_length) ? ptr->read_buffer_length : length;
-
- memcpy(buffer_ptr, ptr->read_ptr, difference);
- length -= difference;
- ptr->read_ptr+= difference;
- ptr->read_buffer_length-= difference;
- buffer_ptr+= difference;
- }
- else
- {
- *buffer_ptr= *ptr->read_ptr;
- ptr->read_ptr++;
- ptr->read_buffer_length--;
- buffer_ptr++;
- break;
- }
- }
-
- ptr->server_failure_counter= 0;
- *nread = (ssize_t)(buffer_ptr - (char*)buffer);
- return MEMCACHED_SUCCESS;
-}
-
-ssize_t memcached_io_write(memcached_server_st *ptr,
- const void *buffer, size_t length, char with_flush)
-{
- size_t original_length;
- const char* buffer_ptr;
-
- WATCHPOINT_ASSERT(ptr->fd != -1);
-
- original_length= length;
- buffer_ptr= buffer;
-
- while (length)
- {
- char *write_ptr;
- size_t should_write;
- size_t buffer_end;
-
- if (ptr->type == MEMCACHED_CONNECTION_UDP)
- {
- //UDP does not support partial writes
- buffer_end= MAX_UDP_DATAGRAM_LENGTH;
- should_write= length;
- if (ptr->write_buffer_offset + should_write > buffer_end)
- return -1;
- }
- else
- {
- buffer_end= MEMCACHED_MAX_BUFFER;
- should_write= buffer_end - ptr->write_buffer_offset;
- should_write= (should_write < length) ? should_write : length;
- }
-
- write_ptr= ptr->write_buffer + ptr->write_buffer_offset;
- memcpy(write_ptr, buffer_ptr, should_write);
- ptr->write_buffer_offset+= should_write;
- buffer_ptr+= should_write;
- length-= should_write;
-
- if (ptr->write_buffer_offset == buffer_end && ptr->type != MEMCACHED_CONNECTION_UDP)
- {
- memcached_return_t rc;
- ssize_t sent_length;
-
- WATCHPOINT_ASSERT(ptr->fd != -1);
- sent_length= io_flush(ptr, &rc);
- if (sent_length == -1)
- return -1;
-
- /* If io_flush calls memcached_purge, sent_length may be 0 */
- unlikely (sent_length != 0)
- {
- WATCHPOINT_ASSERT(sent_length == (ssize_t)buffer_end);
- }
- }
- }
-
- if (with_flush)
- {
- memcached_return_t rc;
- WATCHPOINT_ASSERT(ptr->fd != -1);
- if (io_flush(ptr, &rc) == -1)
- return -1;
- }
-
- return (ssize_t) original_length;
-}
-
-memcached_return_t memcached_io_close(memcached_server_st *ptr)
-{
- int r;
-
- if (ptr->fd == -1)
- return MEMCACHED_SUCCESS;
-
- /* in case of death shutdown to avoid blocking at close() */
- if (1)
- {
- r= shutdown(ptr->fd, SHUT_RDWR);
-
-#ifdef DEBUG
- if (r && errno != ENOTCONN)
- {
- WATCHPOINT_NUMBER(ptr->fd);
- WATCHPOINT_ERRNO(errno);
- WATCHPOINT_ASSERT(errno);
- }
-#endif
- }
-
- r= close(ptr->fd);
-#ifdef DEBUG
- if (r != 0)
- WATCHPOINT_ERRNO(errno);
-#endif
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_server_st *memcached_io_get_readable_server(memcached_st *memc)
-{
-#define MAX_SERVERS_TO_POLL 100
- struct pollfd fds[MAX_SERVERS_TO_POLL];
- unsigned int host_index= 0;
-
- for (unsigned int x= 0;
- x< memc->number_of_hosts && host_index < MAX_SERVERS_TO_POLL;
- ++x)
- {
- if (memc->hosts[x].read_buffer_length > 0) /* I have data in the buffer */
- return &memc->hosts[x];
-
- if (memcached_server_response_count(&memc->hosts[x]) > 0)
- {
- fds[host_index].events = POLLIN;
- fds[host_index].revents = 0;
- fds[host_index].fd = memc->hosts[x].fd;
- ++host_index;
- }
- }
-
- if (host_index < 2)
- {
- /* We have 0 or 1 server with pending events.. */
- for (unsigned int x= 0; x< memc->number_of_hosts; ++x)
- if (memcached_server_response_count(&memc->hosts[x]) > 0)
- return &memc->hosts[x];
-
- return NULL;
- }
-
- int err= poll(fds, host_index, memc->poll_timeout);
- switch (err) {
- case -1:
- memc->cached_errno = errno;
- /* FALLTHROUGH */
- case 0:
- break;
- default:
- for (unsigned int x= 0; x < host_index; ++x)
- if (fds[x].revents & POLLIN)
- for (unsigned int y= 0; y < memc->number_of_hosts; ++y)
- if (memc->hosts[y].fd == fds[x].fd)
- return &memc->hosts[y];
- }
-
- return NULL;
-}
-
-static ssize_t io_flush(memcached_server_st *ptr,
- memcached_return_t *error)
-{
- /*
- ** We might want to purge the input buffer if we haven't consumed
- ** any output yet... The test for the limits is the purge is inline
- ** in the purge function to avoid duplicating the logic..
- */
- {
- memcached_return_t rc;
- WATCHPOINT_ASSERT(ptr->fd != -1);
- rc= memcached_purge(ptr);
-
- if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
- return -1;
- }
- ssize_t sent_length;
- size_t return_length;
- char *local_write_ptr= ptr->write_buffer;
- size_t write_length= ptr->write_buffer_offset;
-
- *error= MEMCACHED_SUCCESS;
-
- WATCHPOINT_ASSERT(ptr->fd != -1);
-
- // UDP Sanity check, make sure that we are not sending somthing too big
- if (ptr->type == MEMCACHED_CONNECTION_UDP && write_length > MAX_UDP_DATAGRAM_LENGTH)
- return -1;
-
- if (ptr->write_buffer_offset == 0 || (ptr->type == MEMCACHED_CONNECTION_UDP
- && ptr->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH))
- return 0;
-
- /* Looking for memory overflows */
-#if defined(DEBUG)
- if (write_length == MEMCACHED_MAX_BUFFER)
- WATCHPOINT_ASSERT(ptr->write_buffer == local_write_ptr);
- WATCHPOINT_ASSERT((ptr->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length));
-#endif
-
- return_length= 0;
- while (write_length)
- {
- WATCHPOINT_ASSERT(ptr->fd != -1);
- WATCHPOINT_ASSERT(write_length > 0);
- sent_length= 0;
- if (ptr->type == MEMCACHED_CONNECTION_UDP)
- increment_udp_message_id(ptr);
- sent_length= write(ptr->fd, local_write_ptr, write_length);
-
- if (sent_length == -1)
- {
- ptr->cached_errno= errno;
- switch (errno)
- {
- case ENOBUFS:
- continue;
- case EAGAIN:
- {
- /*
- * We may be blocked on write because the input buffer
- * is full. Let's check if we have room in our input
- * buffer for more data and retry the write before
- * waiting..
- */
- if (repack_input_buffer(ptr) ||
- process_input_buffer(ptr))
- continue;
-
- memcached_return_t rc;
- rc= io_wait(ptr, MEM_WRITE);
-
- if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_TIMEOUT)
- continue;
-
- memcached_quit_server(ptr, 1);
- return -1;
- }
- default:
- memcached_quit_server(ptr, 1);
- *error= MEMCACHED_ERRNO;
- return -1;
- }
- }
-
- if (ptr->type == MEMCACHED_CONNECTION_UDP &&
- (size_t)sent_length != write_length)
- {
- memcached_quit_server(ptr, 1);
- return -1;
- }
-
- ptr->io_bytes_sent += (uint32_t) sent_length;
-
- local_write_ptr+= sent_length;
- write_length-= (uint32_t) sent_length;
- return_length+= (uint32_t) sent_length;
- }
-
- WATCHPOINT_ASSERT(write_length == 0);
- // Need to study this assert() WATCHPOINT_ASSERT(return_length ==
- // ptr->write_buffer_offset);
-
- // if we are a udp server, the begining of the buffer is reserverd for
- // the upd frame header
- if (ptr->type == MEMCACHED_CONNECTION_UDP)
- ptr->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
- else
- ptr->write_buffer_offset= 0;
-
- return (ssize_t) return_length;
-}
-
-/*
- Eventually we will just kill off the server with the problem.
-*/
-void memcached_io_reset(memcached_server_st *ptr)
-{
- memcached_quit_server(ptr, 1);
-}
-
-/**
- * Read a given number of bytes from the server and place it into a specific
- * buffer. Reset the IO channel on this server if an error occurs.
- */
-memcached_return_t memcached_safe_read(memcached_server_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_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_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_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
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: Server IO, Not public!
- *
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_IO_H
-#define LIBMEMCACHED_MEMCACHED_IO_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(BUILDING_LIBMEMCACHED)
-
-#include "libmemcached/memcached.h"
-
-#define MAX_UDP_DATAGRAM_LENGTH 1400
-#define UDP_DATAGRAM_HEADER_LENGTH 8
-#define UDP_REQUEST_ID_MSG_SIG_DIGITS 10
-#define UDP_REQUEST_ID_THREAD_MASK 0xFFFF << UDP_REQUEST_ID_MSG_SIG_DIGITS
-#define get_udp_datagram_request_id(A) ntohs((A)->request_id)
-#define get_udp_datagram_seq_num(A) ntohs((A)->sequence_number)
-#define get_udp_datagram_num_datagrams(A) ntohs((A)->num_datagrams)
-#define get_msg_num_from_request_id(A) ( (A) & (~(UDP_REQUEST_ID_THREAD_MASK)) )
-#define get_thread_id_from_request_id(A) ( (A) & (UDP_REQUEST_ID_THREAD_MASK) ) >> UDP_REQUEST_ID_MSG_SIG_DIGITS
-#define generate_udp_request_thread_id(A) (A) << UDP_REQUEST_ID_MSG_SIG_DIGITS
-#define UDP_REQUEST_ID_MAX_THREAD_ID get_thread_id_from_request_id(0xFFFF)
-
-struct udp_datagram_header_st {
- uint16_t request_id;
- uint16_t sequence_number;
- uint16_t num_datagrams;
- uint16_t reserved;
-};
-
-ssize_t memcached_io_write(memcached_server_st *ptr,
- const void *buffer, size_t length, char with_flush);
-void memcached_io_reset(memcached_server_st *ptr);
-memcached_return_t memcached_io_read(memcached_server_st *ptr,
- void *buffer, size_t length, ssize_t *nread);
-/* Read a line (terminated by '\n') into the buffer */
-memcached_return_t memcached_io_readline(memcached_server_st *ptr,
- char *buffer_ptr,
- size_t size);
-memcached_return_t memcached_io_close(memcached_server_st *ptr);
-/* Read n bytes of data from the server and store them in dta */
-memcached_return_t memcached_safe_read(memcached_server_st *ptr,
- void *dta,
- size_t size);
-/* Read a single response from the server */
-memcached_return_t memcached_read_one_response(memcached_server_st *ptr,
- char *buffer, size_t buffer_length,
- memcached_result_st *result);
-memcached_return_t memcached_io_init_udp_header(memcached_server_st *ptr,
- uint16_t thread_id);
-
-memcached_server_st *memcached_io_get_readable_server(memcached_st *memc);
-
-#endif /* BUILDING_LIBMEMCACHED */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBMEMCACHED_MEMCACHED_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
-/*
- I debated about putting this in the client library since it does an
- action I don't really believe belongs in the library.
-
- Frankly its too damn useful not to be here though.
-*/
-
-#include "common.h"
-
-memcached_server_st *memcached_servers_parse(const char *server_strings)
-{
- char *string;
- uint32_t port;
- uint32_t weight;
- const char *begin_ptr;
- const char *end_ptr;
- memcached_server_st *servers= NULL;
- memcached_return_t rc;
-
- WATCHPOINT_ASSERT(server_strings);
-
- end_ptr= server_strings + strlen(server_strings);
-
- for (begin_ptr= server_strings, string= index(server_strings, ',');
- begin_ptr != end_ptr;
- string= index(begin_ptr, ','))
- {
- char buffer[HUGE_STRING_LEN];
- char *ptr, *ptr2;
- port= 0;
- weight= 0;
-
- if (string)
- {
- memcpy(buffer, begin_ptr, (size_t) (string - begin_ptr));
- buffer[(unsigned int)(string - begin_ptr)]= 0;
- begin_ptr= string+1;
- }
- else
- {
- size_t length= strlen(begin_ptr);
- memcpy(buffer, begin_ptr, length);
- buffer[length]= 0;
- begin_ptr= end_ptr;
- }
-
- ptr= index(buffer, ':');
-
- if (ptr)
- {
- ptr[0]= 0;
-
- ptr++;
-
- port= (uint32_t) strtoul(ptr, (char **)NULL, 10);
-
- ptr2= index(ptr, ' ');
- if (! ptr2)
- ptr2= index(ptr, ':');
- if (ptr2)
- {
- ptr2++;
- weight = (uint32_t) strtoul(ptr2, (char **)NULL, 10);
- }
- }
-
- servers= memcached_server_list_append_with_weight(servers, buffer, port, weight, &rc);
-
- if (isspace(*begin_ptr))
- begin_ptr++;
- }
-
- return servers;
-}
+++ /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: Connection pool implementation for libmemcached.
- *
- */
-
-
-#ifndef MEMCACHED_POOL_H
-#define MEMCACHED_POOL_H
-
-#include <libmemcached/memcached.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct memcached_pool_st;
-typedef struct memcached_pool_st memcached_pool_st;
-
-LIBMEMCACHED_API
-memcached_pool_st *memcached_pool_create(memcached_st* mmc, uint32_t initial,
- uint32_t max);
-LIBMEMCACHED_API
-memcached_st* memcached_pool_destroy(memcached_pool_st* pool);
-LIBMEMCACHED_API
-memcached_st* memcached_pool_pop(memcached_pool_st* pool,
- bool block,
- memcached_return_t* rc);
-LIBMEMCACHED_API
-memcached_return_t memcached_pool_push(memcached_pool_st* pool,
- memcached_st* mmc);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_pool_behavior_set(memcached_pool_st *ptr,
- memcached_behavior_t flag,
- uint64_t data);
-LIBMEMCACHED_API
-memcached_return_t memcached_pool_behavior_get(memcached_pool_st *ptr,
- memcached_behavior_t flag,
- uint64_t *value);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* MEMCACHED_POOL_H */
+++ /dev/null
-#include "common.h"
-#include "memcached_io.h"
-#include "memcached_constants.h"
-
-memcached_return_t memcached_purge(memcached_server_st *ptr)
-{
- uint32_t x;
- memcached_return_t ret= MEMCACHED_SUCCESS;
-
- if (ptr->root->options.is_purging || /* already purging */
- (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark &&
- ptr->io_bytes_sent < ptr->root->io_bytes_watermark) ||
- (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark &&
- memcached_server_response_count(ptr) < 2))
- {
- return MEMCACHED_SUCCESS;
- }
-
- /* memcached_io_write and memcached_response may call memcached_purge
- so we need to be able stop any recursion.. */
- ptr->root->options.is_purging= true;
-
- WATCHPOINT_ASSERT(ptr->fd != -1);
- /* Force a flush of the buffer to ensure that we don't have the n-1 pending
- requests buffered up.. */
- if (memcached_io_write(ptr, NULL, 0, 1) == -1)
- {
- ptr->root->options.is_purging= true;
- return MEMCACHED_WRITE_FAILURE;
- }
- WATCHPOINT_ASSERT(ptr->fd != -1);
-
- uint32_t no_msg= memcached_server_response_count(ptr) - 1;
- if (no_msg > 0)
- {
- memcached_result_st result;
- memcached_result_st *result_ptr;
- char buffer[SMALL_STRING_LEN];
-
- /*
- * We need to increase the timeout, because we might be waiting for
- * data to be sent from the server (the commands was in the output buffer
- * and just flushed
- */
- int32_t timeo= ptr->root->poll_timeout;
- ptr->root->poll_timeout= 2000;
-
- result_ptr= memcached_result_create(ptr->root, &result);
- WATCHPOINT_ASSERT(result_ptr);
-
- for (x= 0; x < no_msg; x++)
- {
- memcached_result_reset(result_ptr);
- memcached_return_t rc= memcached_read_one_response(ptr, buffer,
- sizeof (buffer),
- result_ptr);
- /*
- * Purge doesn't care for what kind of command results that is received.
- * The only kind of errors I care about if is I'm out of sync with the
- * protocol or have problems reading data from the network..
- */
- if (rc== MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_UNKNOWN_READ_FAILURE)
- {
- WATCHPOINT_ERROR(rc);
- ret = rc;
- memcached_io_reset(ptr);
- }
- }
-
- memcached_result_free(result_ptr);
- ptr->root->poll_timeout= timeo;
- }
- ptr->root->options.is_purging= 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, uint8_t io_death)
-{
- if (ptr->fd != -1)
- {
- if (io_death == 0 && ptr->type != MEMCACHED_CONNECTION_UDP)
- {
- memcached_return_t rc;
- char buffer[MEMCACHED_MAX_BUFFER];
-
- if (ptr->root->flags.binary_protocol)
- {
- protocol_binary_request_quit request = {.bytes= {0}};
- request.message.header.request.magic = PROTOCOL_BINARY_REQ;
- request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT;
- request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
- rc= memcached_do(ptr, request.bytes, sizeof(request.bytes), 1);
- }
- else
- rc= memcached_do(ptr, "quit\r\n", 6, 1);
-
- WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED);
-
- /* read until socket is closed, or there is an error
- * closing the socket before all data is read
- * results in server throwing away all data which is
- * not read
- */
- ssize_t nread;
- while (memcached_io_read(ptr, buffer, sizeof(buffer)/sizeof(*buffer),
- &nread) == MEMCACHED_SUCCESS);
-
- /*
- * memcached_io_read may call memcached_quit_server with io_death if
- * it encounters problems, but we don't care about those occurences.
- * The intention of that loop is to drain the data sent from the
- * server to ensure that the server processed all of the data we
- * sent to the server.
- */
- ptr->server_failure_counter= 0;
- }
- memcached_io_close(ptr);
-
- ptr->fd= -1;
- ptr->write_buffer_offset= (size_t) ((ptr->type == MEMCACHED_CONNECTION_UDP) ? UDP_DATAGRAM_HEADER_LENGTH : 0);
- ptr->read_buffer_length= 0;
- ptr->read_ptr= ptr->read_buffer;
- memcached_server_response_reset(ptr);
- }
-
- if(io_death) ptr->server_failure_counter++;
-}
-
-void memcached_quit(memcached_st *ptr)
-{
- unsigned int x;
-
- if (ptr->hosts == NULL ||
- ptr->number_of_hosts == 0)
- return;
-
- if (ptr->hosts && ptr->number_of_hosts)
- {
- for (x= 0; x < ptr->number_of_hosts; x++)
- memcached_quit_server(&ptr->hosts[x], 0);
- }
-}
+++ /dev/null
-/*
- Memcached library
-
- memcached_response() is used to determine the return result
- from an issued command.
-*/
-
-#include "common.h"
-#include "memcached_io.h"
-
-static memcached_return_t textual_read_one_response(memcached_server_st *ptr,
- char *buffer, size_t buffer_length,
- memcached_result_st *result);
-static memcached_return_t binary_read_one_response(memcached_server_st *ptr,
- char *buffer, size_t buffer_length,
- memcached_result_st *result);
-
-memcached_return_t memcached_read_one_response(memcached_server_st *ptr,
- char *buffer, size_t buffer_length,
- memcached_result_st *result)
-{
- memcached_server_response_decrement(ptr);
-
- if (result == NULL)
- result = &ptr->root->result;
-
- memcached_return_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_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)
- (void)memcached_io_write(ptr, NULL, 0, 1);
-
- /*
- * The previous implementation purged all pending requests and just
- * returned the last one. Purge all pending messages to ensure backwards
- * compatibility.
- */
- if (ptr->root->flags.binary_protocol == false)
- while (memcached_server_response_count(ptr) > 1)
- {
- memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result);
-
- unlikely (rc != MEMCACHED_END &&
- rc != MEMCACHED_STORED &&
- rc != MEMCACHED_SUCCESS &&
- rc != MEMCACHED_STAT &&
- rc != MEMCACHED_DELETED &&
- rc != MEMCACHED_NOTFOUND &&
- rc != MEMCACHED_NOTSTORED &&
- rc != MEMCACHED_DATA_EXISTS)
- return rc;
- }
-
- return memcached_read_one_response(ptr, buffer, buffer_length, result);
-}
-
-static memcached_return_t textual_value_fetch(memcached_server_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;
-
- if (ptr->root->flags.use_udp)
- return MEMCACHED_NOT_SUPPORTED;
-
- WATCHPOINT_ASSERT(ptr->root);
- end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
-
- memcached_result_reset(result);
-
- string_ptr= buffer;
- string_ptr+= 6; /* "VALUE " */
-
-
- /* We load the key */
- {
- char *key;
- size_t prefix_length;
-
- key= result->key;
- result->key_length= 0;
-
- for (prefix_length= ptr->root->prefix_key_length; !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
- {
- if (prefix_length == 0)
- {
- *key= *string_ptr;
- key++;
- result->key_length++;
- }
- else
- prefix_length--;
- }
- result->key[result->key_length]= 0;
- }
-
- if (end_ptr == string_ptr)
- goto read_error;
-
- /* Flags fetch move past space */
- string_ptr++;
- if (end_ptr == string_ptr)
- goto read_error;
- for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
- result->flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10);
-
- if (end_ptr == string_ptr)
- goto read_error;
-
- /* Length fetch move past space*/
- string_ptr++;
- if (end_ptr == string_ptr)
- goto read_error;
-
- for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
- value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
-
- if (end_ptr == string_ptr)
- goto read_error;
-
- /* Skip spaces */
- if (*string_ptr == '\r')
- {
- /* Skip past the \r\n */
- string_ptr+= 2;
- }
- else
- {
- string_ptr++;
- for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
- result->cas= strtoull(next_ptr, &string_ptr, 10);
- }
-
- if (end_ptr < string_ptr)
- goto read_error;
-
- /* We add two bytes so that we can walk the \r\n */
- rc= memcached_string_check(&result->value, value_length+2);
- if (rc != MEMCACHED_SUCCESS)
- {
- value_length= 0;
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- }
-
- value_ptr= memcached_string_value(&result->value);
- /*
- We read the \r\n into the string since not doing so is more
- cycles then the waster of memory to do so.
-
- We are null terminating through, which will most likely make
- some people lazy about using the return length.
- */
- to_read= (value_length) + 2;
- ssize_t read_length= 0;
- memcached_return_t rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length);
- if (rrc != MEMCACHED_SUCCESS)
- return rrc;
-
- if (read_length != (ssize_t)(value_length + 2))
- {
- goto read_error;
- }
-
-/* This next bit blows the API, but this is internal....*/
- {
- char *char_ptr;
- char_ptr= memcached_string_value(&result->value);;
- char_ptr[value_length]= 0;
- char_ptr[value_length + 1]= 0;
- memcached_string_set_length(&result->value, value_length);
- }
-
- return MEMCACHED_SUCCESS;
-
-read_error:
- memcached_io_reset(ptr);
-
- return MEMCACHED_PARTIAL_READ;
-}
-
-static memcached_return_t textual_read_one_response(memcached_server_st *ptr,
- char *buffer, size_t buffer_length,
- memcached_result_st *result)
-{
- memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length);
- if (rc != MEMCACHED_SUCCESS)
- return rc;
-
- switch(buffer[0])
- {
- case 'V': /* VALUE || VERSION */
- if (buffer[1] == 'A') /* VALUE */
- {
- /* We add back in one because we will need to search for END */
- memcached_server_response_increment(ptr);
- return textual_value_fetch(ptr, buffer, result);
- }
- else if (buffer[1] == 'E') /* VERSION */
- {
- return MEMCACHED_SUCCESS;
- }
- else
- {
- WATCHPOINT_STRING(buffer);
- WATCHPOINT_ASSERT(0);
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- case 'O': /* OK */
- return MEMCACHED_SUCCESS;
- case 'S': /* STORED STATS SERVER_ERROR */
- {
- if (buffer[2] == 'A') /* STORED STATS */
- {
- memcached_server_response_increment(ptr);
- return MEMCACHED_STAT;
- }
- else if (buffer[1] == 'E') /* SERVER_ERROR */
- {
- char *rel_ptr;
- char *startptr= buffer + 13, *endptr= startptr;
-
- while (*endptr != '\r' && *endptr != '\n') endptr++;
-
- /*
- Yes, we could make this "efficent" but to do that we would need
- to maintain more state for the size of the buffer. Why waste
- memory in the struct, which is important, for something that
- rarely should happen?
- */
- rel_ptr= (char *)ptr->root->call_realloc(ptr->root,
- ptr->cached_server_error,
- (size_t) (endptr - startptr + 1));
-
- if (rel_ptr == NULL)
- {
- /* If we happened to have some memory, we just null it since we don't know the size */
- if (ptr->cached_server_error)
- ptr->cached_server_error[0]= 0;
- return MEMCACHED_SERVER_ERROR;
- }
- ptr->cached_server_error= rel_ptr;
-
- memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr));
- ptr->cached_server_error[endptr - startptr]= 0;
- return MEMCACHED_SERVER_ERROR;
- }
- else if (buffer[1] == 'T')
- return MEMCACHED_STORED;
- else
- {
- WATCHPOINT_STRING(buffer);
- WATCHPOINT_ASSERT(0);
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- }
- case 'D': /* DELETED */
- return MEMCACHED_DELETED;
- case 'N': /* NOT_FOUND */
- {
- if (buffer[4] == 'F')
- return MEMCACHED_NOTFOUND;
- else if (buffer[4] == 'S')
- return MEMCACHED_NOTSTORED;
- else
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- case 'E': /* PROTOCOL ERROR or END */
- {
- if (buffer[1] == 'N')
- return MEMCACHED_END;
- else if (buffer[1] == 'R')
- return MEMCACHED_PROTOCOL_ERROR;
- else if (buffer[1] == 'X')
- return MEMCACHED_DATA_EXISTS;
- else
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- case 'I': /* CLIENT ERROR */
- /* We add back in one because we will need to search for END */
- memcached_server_response_increment(ptr);
- return MEMCACHED_ITEM;
- case 'C': /* CLIENT ERROR */
- return MEMCACHED_CLIENT_ERROR;
- default:
- {
- unsigned long long auto_return_value;
-
- if (sscanf(buffer, "%llu", &auto_return_value) == 1)
- return MEMCACHED_SUCCESS;
-
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- }
-
- /* NOTREACHED */
-}
-
-char *memcached_result_value(memcached_result_st *ptr)
-{
- memcached_string_st *sptr= &ptr->value;
- return memcached_string_value(sptr);
-}
-
-size_t memcached_result_length(memcached_result_st *ptr)
-{
- memcached_string_st *sptr= &ptr->value;
- return memcached_string_length(sptr);
-}
-
-static memcached_return_t binary_read_one_response(memcached_server_st *ptr,
- char *buffer, size_t buffer_length,
- memcached_result_st *result)
-{
- protocol_binary_response_header header;
-
- unlikely (memcached_safe_read(ptr, &header.bytes,
- sizeof(header.bytes)) != MEMCACHED_SUCCESS)
- return MEMCACHED_UNKNOWN_READ_FAILURE;
-
- unlikely (header.response.magic != PROTOCOL_BINARY_RES)
- return MEMCACHED_PROTOCOL_ERROR;
-
- /*
- ** Convert the header to host local endian!
- */
- header.response.keylen= ntohs(header.response.keylen);
- header.response.status= ntohs(header.response.status);
- header.response.bodylen= ntohl(header.response.bodylen);
- header.response.cas= ntohll(header.response.cas);
- uint32_t bodylen= header.response.bodylen;
-
- if (header.response.status == 0)
- {
- switch (header.response.opcode)
- {
- case PROTOCOL_BINARY_CMD_GETKQ:
- /*
- * We didn't increment the response counter for the GETKQ packet
- * (only the final NOOP), so we need to increment the counter again.
- */
- memcached_server_response_increment(ptr);
- /* FALLTHROUGH */
- case PROTOCOL_BINARY_CMD_GETK:
- {
- uint16_t keylen= header.response.keylen;
- memcached_result_reset(result);
- result->cas= header.response.cas;
-
- if (memcached_safe_read(ptr, &result->flags,
- sizeof (result->flags)) != MEMCACHED_SUCCESS)
- return MEMCACHED_UNKNOWN_READ_FAILURE;
-
- result->flags= ntohl(result->flags);
- bodylen -= header.response.extlen;
-
- result->key_length= keylen;
- if (memcached_safe_read(ptr, result->key, keylen) != MEMCACHED_SUCCESS)
- return MEMCACHED_UNKNOWN_READ_FAILURE;
-
- bodylen -= keylen;
- if (memcached_string_check(&result->value,
- bodylen) != MEMCACHED_SUCCESS)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- char *vptr= memcached_string_value(&result->value);
- if (memcached_safe_read(ptr, vptr, bodylen) != MEMCACHED_SUCCESS)
- return MEMCACHED_UNKNOWN_READ_FAILURE;
-
- memcached_string_set_length(&result->value, bodylen);
- }
- break;
- case PROTOCOL_BINARY_CMD_INCREMENT:
- case PROTOCOL_BINARY_CMD_DECREMENT:
- {
- if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t))
- return MEMCACHED_PROTOCOL_ERROR;
-
- WATCHPOINT_ASSERT(bodylen == buffer_length);
- uint64_t val;
- if (memcached_safe_read(ptr, &val, sizeof(val)) != MEMCACHED_SUCCESS)
- return MEMCACHED_UNKNOWN_READ_FAILURE;
-
- val= ntohll(val);
- memcpy(buffer, &val, sizeof(val));
- }
- break;
- case PROTOCOL_BINARY_CMD_VERSION:
- {
- memset(buffer, 0, buffer_length);
- if (bodylen >= buffer_length)
- /* not enough space in buffer.. should not happen... */
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- else if (memcached_safe_read(ptr, buffer, bodylen) != MEMCACHED_SUCCESS)
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- break;
- case PROTOCOL_BINARY_CMD_FLUSH:
- case PROTOCOL_BINARY_CMD_QUIT:
- case PROTOCOL_BINARY_CMD_SET:
- case PROTOCOL_BINARY_CMD_ADD:
- case PROTOCOL_BINARY_CMD_REPLACE:
- case PROTOCOL_BINARY_CMD_APPEND:
- case PROTOCOL_BINARY_CMD_PREPEND:
- case PROTOCOL_BINARY_CMD_DELETE:
- {
- WATCHPOINT_ASSERT(bodylen == 0);
- return MEMCACHED_SUCCESS;
- }
- case PROTOCOL_BINARY_CMD_NOOP:
- {
- WATCHPOINT_ASSERT(bodylen == 0);
- return MEMCACHED_END;
- }
- case PROTOCOL_BINARY_CMD_STAT:
- {
- if (bodylen == 0)
- return MEMCACHED_END;
- else if (bodylen + 1 > buffer_length)
- /* not enough space in buffer.. should not happen... */
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- else
- {
- size_t keylen= header.response.keylen;
- memset(buffer, 0, buffer_length);
- if (memcached_safe_read(ptr, buffer, keylen) != MEMCACHED_SUCCESS ||
- memcached_safe_read(ptr, buffer + keylen + 1,
- bodylen - keylen) != MEMCACHED_SUCCESS)
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- }
- }
- break;
- default:
- {
- /* Command not implemented yet! */
- WATCHPOINT_ASSERT(0);
- return MEMCACHED_PROTOCOL_ERROR;
- }
- }
- }
- else if (header.response.bodylen)
- {
- /* What should I do with the error message??? just discard it for now */
- char hole[SMALL_STRING_LEN];
- while (bodylen > 0)
- {
- size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
- if (memcached_safe_read(ptr, hole, nr) != MEMCACHED_SUCCESS)
- return MEMCACHED_UNKNOWN_READ_FAILURE;
- bodylen-= (uint32_t) nr;
- }
-
- /* This might be an error from one of the quiet commands.. if
- * so, just throw it away and get the next one. What about creating
- * a callback to the user with the error information?
- */
- switch (header.response.opcode)
- {
- case PROTOCOL_BINARY_CMD_SETQ:
- case PROTOCOL_BINARY_CMD_ADDQ:
- case PROTOCOL_BINARY_CMD_REPLACEQ:
- case PROTOCOL_BINARY_CMD_APPENDQ:
- case PROTOCOL_BINARY_CMD_PREPENDQ:
- return binary_read_one_response(ptr, buffer, buffer_length, result);
- default:
- break;
- }
- }
-
- memcached_return_t rc= MEMCACHED_SUCCESS;
- unlikely(header.response.status != 0)
- switch (header.response.status)
- {
- case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
- rc= MEMCACHED_NOTFOUND;
- break;
- case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
- rc= MEMCACHED_DATA_EXISTS;
- break;
- case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
- rc= MEMCACHED_NOTSTORED;
- break;
- case PROTOCOL_BINARY_RESPONSE_E2BIG:
- rc= MEMCACHED_E2BIG;
- break;
- case PROTOCOL_BINARY_RESPONSE_ENOMEM:
- rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- break;
- case PROTOCOL_BINARY_RESPONSE_EINVAL:
- case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
- default:
- /* @todo fix the error mappings */
- rc= MEMCACHED_PROTOCOL_ERROR;
- break;
- }
-
- return rc;
-}
+++ /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"
-
-memcached_result_st *memcached_result_create(memcached_st *memc,
- memcached_result_st *ptr)
-{
- WATCHPOINT_ASSERT(memc && memc->options.is_initialized);
-
- /* Saving malloc calls :) */
- if (ptr)
- {
- memset(ptr, 0, sizeof(memcached_result_st));
- }
- else
- {
- ptr= memc->call_malloc(memc, sizeof(memcached_result_st));
-
- if (ptr == NULL)
- return NULL;
- ptr->options.is_allocated= true;
- }
-
- ptr->options.is_initialized= true;
-
- ptr->root= memc;
- memcached_string_create(memc, &ptr->value, 0);
- WATCHPOINT_ASSERT_INITIALIZED(&ptr->value);
- WATCHPOINT_ASSERT(ptr->value.string == NULL);
-
- return ptr;
-}
-
-void memcached_result_reset(memcached_result_st *ptr)
-{
- ptr->key_length= 0;
- memcached_string_reset(&ptr->value);
- ptr->flags= 0;
- ptr->cas= 0;
- ptr->expiration= 0;
-}
-
-/*
- NOTE turn into macro
-*/
-memcached_return_t memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length)
-{
- return memcached_string_append(&ptr->value, value, length);
-}
-
-void memcached_result_free(memcached_result_st *ptr)
-{
- if (ptr == NULL)
- return;
-
- memcached_string_free(&ptr->value);
-
- if (memcached_is_allocated(ptr))
- {
- free(ptr);
- }
- else
- {
- ptr->options.is_initialized= 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: Functions to manipulate the result structure.
- *
- */
-
-#ifndef __MEMCACHED_RESULT_H__
-#define __MEMCACHED_RESULT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct memcached_result_st {
- struct {
- bool is_allocated:1;
- bool is_initialized:1;
- } options;
- uint32_t flags;
- time_t expiration;
- memcached_st *root;
- size_t key_length;
- uint64_t cas;
- memcached_string_st value;
- char key[MEMCACHED_MAX_KEY];
- /* Add result callback function */
-};
-
-/* Result Struct */
-LIBMEMCACHED_API
-void memcached_result_free(memcached_result_st *result);
-LIBMEMCACHED_API
-void memcached_result_reset(memcached_result_st *ptr);
-LIBMEMCACHED_API
-memcached_result_st *memcached_result_create(memcached_st *ptr,
- memcached_result_st *result);
-#define memcached_result_key_value(A) (A)->key
-#define memcached_result_key_length(A) (A)->key_length
-#define memcached_result_string_st(A) ((A)->value)
-#ifdef FIX
-#define memcached_result_value(A) memcached_string_value((A)->value)
-#define memcached_result_length(A) memcached_string_length((A)->value)
-#else
-LIBMEMCACHED_API
-char *memcached_result_value(memcached_result_st *ptr);
-LIBMEMCACHED_API
-size_t memcached_result_length(memcached_result_st *ptr);
-#endif
-#define memcached_result_flags(A) (A)->flags
-#define memcached_result_cas(A) (A)->cas
-LIBMEMCACHED_API
-memcached_return_t memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length);
-#define memcached_result_set_flags(A,B) (A)->flags=(B)
-#define memcached_result_set_expiration(A,B) (A)->expiration=(B)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_RESULT_H__ */
+++ /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 "common.h"
-
-memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr)
-{
- if (ptr == NULL)
- {
- ptr= (memcached_server_st *)calloc(1, sizeof(memcached_server_st));
-
- if (!ptr)
- return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
-
- ptr->options.is_allocated= true;
- }
- else
- {
- memset(ptr, 0, sizeof(memcached_server_st));
- }
-
- ptr->root= memc;
-
- return ptr;
-}
-
-memcached_server_st *memcached_server_create_with(memcached_st *memc, memcached_server_st *host,
- const char *hostname, in_port_t port,
- uint32_t weight, memcached_connection_t type)
-{
- host= memcached_server_create(memc, host);
-
- if (host == NULL)
- return NULL;
-
- strncpy(host->hostname, hostname, MEMCACHED_MAX_HOST_LENGTH - 1);
- host->root= memc ? memc : NULL;
- host->port= port;
- host->weight= weight;
- host->fd= -1;
- host->type= type;
- host->read_ptr= host->read_buffer;
- if (memc)
- host->next_retry= memc->retry_timeout;
- if (type == MEMCACHED_CONNECTION_UDP)
- {
- host->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
- memcached_io_init_udp_header(host, 0);
- }
-
- return host;
-}
-
-void memcached_server_free(memcached_server_st *ptr)
-{
- memcached_quit_server(ptr, 0);
-
- if (ptr->cached_server_error)
- free(ptr->cached_server_error);
-
- if (ptr->address_info)
- freeaddrinfo(ptr->address_info);
-
-
- if (memcached_is_allocated(ptr))
- {
- ptr->root->call_free(ptr->root, ptr);
- }
- else
- {
- memset(ptr, 0, sizeof(memcached_server_st));
- }
-}
-
-/*
- If we do not have a valid object to clone from, we toss an error.
-*/
-memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr)
-{
- memcached_server_st *rv= NULL;
-
- /* We just do a normal create if ptr is missing */
- if (ptr == NULL)
- return NULL;
-
- rv = memcached_server_create_with(ptr->root, clone,
- ptr->hostname, ptr->port, ptr->weight,
- ptr->type);
- if (rv != NULL)
- {
- rv->cached_errno= ptr->cached_errno;
- if (ptr->cached_server_error)
- rv->cached_server_error= strdup(ptr->cached_server_error);
- }
-
- return rv;
-
-}
-
-memcached_return_t memcached_server_cursor(memcached_st *ptr,
- memcached_server_fn *callback,
- void *context,
- uint32_t number_of_callbacks)
-{
- unsigned int y;
-
- for (y= 0; y < ptr->number_of_hosts; y++)
- {
- unsigned int x;
-
- for (x= 0; x < number_of_callbacks; x++)
- {
- unsigned int iferror;
-
- iferror= (*callback[x])(ptr, &ptr->hosts[y], context);
-
- if (iferror)
- continue;
- }
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_server_st *memcached_server_by_key(memcached_st *ptr, const char *key, size_t key_length, memcached_return_t *error)
-{
- uint32_t server_key;
-
- *error= memcached_validate_key_length(key_length,
- ptr->flags.binary_protocol);
- unlikely (*error != MEMCACHED_SUCCESS)
- return NULL;
-
- unlikely (ptr->number_of_hosts == 0)
- {
- *error= MEMCACHED_NO_SERVERS;
- return NULL;
- }
-
- if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
- {
- *error= MEMCACHED_BAD_KEY_PROVIDED;
- return NULL;
- }
-
- server_key= memcached_generate_hash(ptr, key, key_length);
-
- return memcached_server_clone(NULL, &ptr->hosts[server_key]);
-
-}
-
-const char *memcached_server_error(memcached_server_st *ptr)
-{
- if (ptr)
- return ptr->cached_server_error;
- else
- return NULL;
-}
-
-void memcached_server_error_reset(memcached_server_st *ptr)
-{
- ptr->cached_server_error[0]= 0;
-}
-
-memcached_server_st *memcached_server_get_last_disconnect(memcached_st *ptr)
-{
- return ptr->last_disconnected_server;
-}
+++ /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.
- *
- */
-
-#ifndef __MEMCACHED_SERVER_H__
-#define __MEMCACHED_SERVER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct memcached_server_st {
- struct {
- bool is_allocated:1;
- } options;
- bool sockaddr_inited;
- uint16_t count;
- uint32_t cursor_active;
- in_port_t port;
- int cached_errno;
- int fd;
- uint32_t io_bytes_sent; /* # bytes sent since last read */
- uint32_t server_failure_counter;
- uint32_t weight;
- uint8_t major_version;
- uint8_t micro_version;
- uint8_t minor_version;
- memcached_connection_t type;
- char *read_ptr;
- char *cached_server_error;
- size_t read_buffer_length;
- size_t read_data_length;
- size_t write_buffer_offset;
- struct addrinfo *address_info;
- time_t next_retry;
- memcached_st *root;
- uint64_t limit_maxbytes;
- char read_buffer[MEMCACHED_MAX_BUFFER];
- char write_buffer[MEMCACHED_MAX_BUFFER];
- char hostname[MEMCACHED_MAX_HOST_LENGTH];
-};
-
-#define memcached_server_count(A) (A)->number_of_hosts
-#define memcached_server_name(A,B) (B).hostname
-#define memcached_server_port(A,B) (B).port
-#define memcached_server_list(A) (A)->hosts
-#define memcached_server_response_count(A) (A)->cursor_active
-
-LIBMEMCACHED_API
-memcached_return_t memcached_server_cursor(memcached_st *ptr,
- memcached_server_fn *callback,
- void *context,
- uint32_t number_of_callbacks);
-
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_by_key(memcached_st *ptr, const char *key,
- size_t key_length, memcached_return_t *error);
-
-LIBMEMCACHED_API
-const char *memcached_server_error(memcached_server_st *ptr);
-
-LIBMEMCACHED_API
-void memcached_server_error_reset(memcached_server_st *ptr);
-
-/* These should not currently be used by end users */
-/* TODO: Is the above comment valid? If so, how can we unit test these if they
- * aren't exported. If not, we should remove the comment */
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr);
-
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_create_with(memcached_st *memc, memcached_server_st *host,
- const char *hostname, in_port_t port,
- uint32_t weight, memcached_connection_t type);
-
-LIBMEMCACHED_API
-void memcached_server_free(memcached_server_st *ptr);
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr);
-LIBMEMCACHED_API
-memcached_analysis_st *memcached_analyze(memcached_st *memc, memcached_stat_st *memc_stat,
- memcached_return_t *error);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_server_remove(memcached_server_st *st_ptr);
-
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_get_last_disconnect(memcached_st *ptr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_SERVER_H__ */
+++ /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
-};
-
-
-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))
- {
- WATCHPOINT_STRING(key);
- return MEMCACHED_UNKNOWN_STAT_KEY;
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-char *memcached_stat_get_value(memcached_st *ptr, memcached_stat_st *memc_stat,
- const char *key, memcached_return_t *error)
-{
- char buffer[SMALL_STRING_LEN];
- int length;
- char *ret;
-
- *error= MEMCACHED_SUCCESS;
-
- if (!memcmp("pid", key, strlen("pid")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pid);
- else if (!memcmp("uptime", key, strlen("uptime")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->uptime);
- else if (!memcmp("time", key, strlen("time")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time);
- else if (!memcmp("version", key, strlen("version")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version);
- else if (!memcmp("pointer_size", key, strlen("pointer_size")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pointer_size);
- else if (!memcmp("rusage_user", key, strlen("rusage_user")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds);
- else if (!memcmp("rusage_system", key, strlen("rusage_system")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds);
- else if (!memcmp("curr_items", key, strlen("curr_items")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_items);
- else if (!memcmp("total_items", key, strlen("total_items")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_items);
- else if (!memcmp("curr_connections", key, strlen("curr_connections")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_connections);
- else if (!memcmp("total_connections", key, strlen("total_connections")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_connections);
- else if (!memcmp("connection_structures", key, strlen("connection_structures")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->connection_structures);
- else if (!memcmp("cmd_get", key, strlen("cmd_get")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get);
- else if (!memcmp("cmd_set", key, strlen("cmd_set")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set);
- else if (!memcmp("get_hits", key, strlen("get_hits")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits);
- else if (!memcmp("get_misses", key, strlen("get_misses")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses);
- else if (!memcmp("evictions", key, strlen("evictions")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions);
- else if (!memcmp("bytes_read", key, strlen("bytes_read")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read);
- else if (!memcmp("bytes_written", key, strlen("bytes_written")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written);
- else if (!memcmp("bytes", key, strlen("bytes")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes);
- else if (!memcmp("limit_maxbytes", key, strlen("limit_maxbytes")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes);
- else if (!memcmp("threads", key, strlen("threads")))
- length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->threads);
- else
- {
- *error= MEMCACHED_NOTFOUND;
- return NULL;
- }
-
- ret= ptr->call_malloc(ptr, (size_t) (length + 1));
- memcpy(ret, buffer, (size_t) length);
- ret[length]= '\0';
-
- return ret;
-}
-
-static memcached_return_t binary_stats_fetch(memcached_st *ptr,
- memcached_stat_st *memc_stat,
- char *args,
- unsigned int server_key)
-{
- memcached_return_t rc;
-
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- protocol_binary_request_stats request= {.bytes= {0}};
- request.message.header.request.magic= PROTOCOL_BINARY_REQ;
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
- if (args != NULL)
- {
- size_t len= strlen(args);
-
- rc= memcached_validate_key_length(len, true);
- unlikely (rc != MEMCACHED_SUCCESS)
- return rc;
-
- request.message.header.request.keylen= htons((uint16_t)len);
- request.message.header.request.bodylen= htonl((uint32_t) len);
-
- if ((memcached_do(&ptr->hosts[server_key], request.bytes,
- sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
- (memcached_io_write(&ptr->hosts[server_key], args, len, 1) == -1))
- {
- memcached_io_reset(&ptr->hosts[server_key]);
- return MEMCACHED_WRITE_FAILURE;
- }
- }
- else
- {
- if (memcached_do(&ptr->hosts[server_key], request.bytes,
- sizeof(request.bytes), 1) != MEMCACHED_SUCCESS)
- {
- memcached_io_reset(&ptr->hosts[server_key]);
- return MEMCACHED_WRITE_FAILURE;
- }
- }
-
- memcached_server_response_decrement(&ptr->hosts[server_key]);
- do
- {
- rc= memcached_response(&ptr->hosts[server_key], buffer,
- sizeof(buffer), NULL);
- if (rc == MEMCACHED_END)
- break;
-
- unlikely (rc != MEMCACHED_SUCCESS)
- {
- memcached_io_reset(&ptr->hosts[server_key]);
- return rc;
- }
-
- unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
- {
- WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
- WATCHPOINT_ASSERT(0);
- }
- } while (1);
-
- /* shit... memcached_response will decrement the counter, so I need to
- ** reset it.. todo: look at this and try to find a better solution.
- */
- ptr->hosts[server_key].cursor_active= 0;
-
- return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t ascii_stats_fetch(memcached_st *ptr,
- memcached_stat_st *memc_stat,
- char *args,
- unsigned int server_key)
-{
- memcached_return_t rc;
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- size_t send_length;
-
- if (args)
- send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "stats %s\r\n", args);
- else
- send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "stats\r\n");
-
- if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
- return MEMCACHED_WRITE_FAILURE;
-
- rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
- if (rc != MEMCACHED_SUCCESS)
- goto error;
-
- while (1)
- {
- rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
- if (rc == MEMCACHED_STAT)
- {
- char *string_ptr, *end_ptr;
- char *key, *value;
-
- string_ptr= buffer;
- string_ptr+= 5; /* Move past STAT */
- for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
- key= string_ptr;
- key[(size_t)(end_ptr-string_ptr)]= 0;
-
- string_ptr= end_ptr + 1;
- for (end_ptr= string_ptr; !(isspace(*end_ptr)); end_ptr++);
- value= string_ptr;
- value[(size_t)(end_ptr-string_ptr)]= 0;
- string_ptr= end_ptr + 2;
- unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY)
- {
- WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
- WATCHPOINT_ASSERT(0);
- }
- }
- else
- break;
- }
-
-error:
- if (rc == MEMCACHED_END)
- return MEMCACHED_SUCCESS;
- else
- return rc;
-}
-
-memcached_stat_st *memcached_stat(memcached_st *ptr, char *args, memcached_return_t *error)
-{
- unsigned int x;
- memcached_return_t rc;
- memcached_stat_st *stats;
-
- unlikely (ptr->flags.use_udp)
- {
- *error= MEMCACHED_NOT_SUPPORTED;
- return NULL;
- }
-
- stats= ptr->call_calloc(ptr, ptr->number_of_hosts, sizeof(memcached_stat_st));
-
- if (!stats)
- {
- *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return NULL;
- }
-
- rc= MEMCACHED_SUCCESS;
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- memcached_return_t temp_return;
-
- if (ptr->flags.binary_protocol)
- temp_return= binary_stats_fetch(ptr, stats + x, args, x);
- else
- temp_return= ascii_stats_fetch(ptr, stats + x, args, x);
-
- if (temp_return != MEMCACHED_SUCCESS)
- rc= MEMCACHED_SOME_ERRORS;
- }
-
- *error= rc;
- return stats;
-}
-
-memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args,
- const char *hostname, in_port_t port)
-{
- memcached_return_t rc;
- memcached_st memc;
- memcached_st *memc_ptr;
-
- memc_ptr= memcached_create(&memc);
- WATCHPOINT_ASSERT(memc_ptr);
-
- memcached_server_add(&memc, hostname, port);
-
- if (memc.flags.binary_protocol)
- rc= binary_stats_fetch(&memc, memc_stat, args, 0);
- else
- rc= ascii_stats_fetch(&memc, memc_stat, args, 0);
-
- memcached_free(&memc);
-
- return rc;
-}
-
-/*
- We make a copy of the keys since at some point in the not so distant future
- we will add support for "found" keys.
-*/
-char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *memc_stat,
- memcached_return_t *error)
-{
- (void) memc_stat;
- char **list;
- size_t length= sizeof(memcached_stat_keys);
-
- list= ptr->call_malloc(ptr, length);
-
- if (!list)
- {
- *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
- return NULL;
- }
-
- memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys));
-
- *error= MEMCACHED_SUCCESS;
-
- return list;
-}
-
-void memcached_stat_free(memcached_st *ptr, memcached_stat_st *memc_stat)
-{
- if (memc_stat == NULL)
- {
- WATCHPOINT_ASSERT(0); /* Be polite, but when debugging catch this as an error */
- return;
- }
-
- if (ptr)
- ptr->call_free(ptr, memc_stat);
- else
- free(memc_stat);
-}
+++ /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"
-#include "memcached_io.h"
-
-typedef enum {
- SET_OP,
- REPLACE_OP,
- ADD_OP,
- PREPEND_OP,
- APPEND_OP,
- CAS_OP,
-} memcached_storage_action_t;
-
-/* Inline this */
-static inline const char *storage_op_string(memcached_storage_action_t verb)
-{
- switch (verb)
- {
- case SET_OP:
- return "set ";
- case REPLACE_OP:
- return "replace ";
- case ADD_OP:
- return "add ";
- case PREPEND_OP:
- return "prepend ";
- case APPEND_OP:
- return "append ";
- case CAS_OP:
- return "cas ";
- default:
- return "tosserror"; /* This is impossible, fixes issue for compiler warning in VisualStudio */
- }
-
- /* NOTREACHED */
-}
-
-static memcached_return_t memcached_send_binary(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char *key,
- size_t key_length,
- const char *value,
- size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas,
- memcached_storage_action_t verb);
-
-static inline memcached_return_t memcached_send(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas,
- memcached_storage_action_t verb)
-{
- char to_write;
- size_t write_length;
- ssize_t sent_length;
- memcached_return_t rc;
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- unsigned int server_key;
-
- WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));
-
- rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
- unlikely (rc != MEMCACHED_SUCCESS)
- return rc;
-
- unlikely (ptr->number_of_hosts == 0)
- return MEMCACHED_NO_SERVERS;
-
- if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
- return MEMCACHED_BAD_KEY_PROVIDED;
-
- if (ptr->flags.binary_protocol)
- {
- return memcached_send_binary(ptr, master_key, master_key_length,
- key, key_length,
- value, value_length, expiration,
- flags, cas, verb);
- }
-
- server_key= memcached_generate_hash(ptr, master_key, master_key_length);
-
- if (cas)
- {
- write_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "%s %s%.*s %u %llu %zu %llu%s\r\n",
- storage_op_string(verb),
- ptr->prefix_key,
- (int)key_length, key, flags,
- (unsigned long long)expiration, value_length,
- (unsigned long long)cas,
- (ptr->flags.no_reply) ? " noreply" : "");
- }
- else
- {
- char *buffer_ptr= buffer;
- const char *command= storage_op_string(verb);
-
- /* Copy in the command, no space needed, we handle that in the command function*/
- memcpy(buffer_ptr, command, strlen(command));
-
- /* Copy in the key prefix, switch to the buffer_ptr */
- buffer_ptr= memcpy(buffer_ptr + strlen(command) , ptr->prefix_key, strlen(ptr->prefix_key));
-
- /* Copy in the key, adjust point if a key prefix was used. */
- buffer_ptr= memcpy(buffer_ptr + (ptr->prefix_key ? strlen(ptr->prefix_key) : 0),
- key, key_length);
- buffer_ptr+= key_length;
- buffer_ptr[0]= ' ';
- buffer_ptr++;
-
- write_length= (size_t)(buffer_ptr - buffer);
- write_length+= (size_t) snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "%u %llu %zu%s\r\n",
- flags,
- (unsigned long long)expiration, value_length,
- ptr->flags.no_reply ? " noreply" : "");
- }
-
- if (ptr->flags.use_udp && ptr->flags.buffer_requests)
- {
- size_t cmd_size= write_length + value_length + 2;
- if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
- return MEMCACHED_WRITE_FAILURE;
- if (cmd_size + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
- memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
- }
-
- if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
- {
- rc= MEMCACHED_WRITE_FAILURE;
- goto error;
- }
-
- /* Send command header */
- rc= memcached_do(&ptr->hosts[server_key], buffer, write_length, 0);
- if (rc != MEMCACHED_SUCCESS)
- goto error;
-
- /* Send command body */
- if ((sent_length= memcached_io_write(&ptr->hosts[server_key], value, value_length, 0)) == -1)
- {
- rc= MEMCACHED_WRITE_FAILURE;
- goto error;
- }
-
- if (ptr->flags.buffer_requests && verb == SET_OP)
- {
- to_write= 0;
- }
- else
- {
- to_write= 1;
- }
-
- if ((sent_length= memcached_io_write(&ptr->hosts[server_key], "\r\n", 2, to_write)) == -1)
- {
- rc= MEMCACHED_WRITE_FAILURE;
- goto error;
- }
-
- if (ptr->flags.no_reply)
- return (to_write == 0) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;
-
- if (to_write == 0)
- return MEMCACHED_BUFFERED;
-
- rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
- if (rc == MEMCACHED_STORED)
- return MEMCACHED_SUCCESS;
- else
- return rc;
-
-error:
- memcached_io_reset(&ptr->hosts[server_key]);
-
- return rc;
-}
-
-
-memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_SET_START();
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, SET_OP);
- LIBMEMCACHED_MEMCACHED_SET_END();
- return rc;
-}
-
-memcached_return_t memcached_add(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_ADD_START();
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, ADD_OP);
- LIBMEMCACHED_MEMCACHED_ADD_END();
- return rc;
-}
-
-memcached_return_t memcached_replace(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_REPLACE_START();
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, REPLACE_OP);
- LIBMEMCACHED_MEMCACHED_REPLACE_END();
- return rc;
-}
-
-memcached_return_t memcached_prepend(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, PREPEND_OP);
- return rc;
-}
-
-memcached_return_t memcached_append(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, APPEND_OP);
- return rc;
-}
-
-memcached_return_t memcached_cas(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas)
-{
- memcached_return_t rc;
- rc= memcached_send(ptr, key, key_length,
- key, key_length, value, value_length,
- expiration, flags, cas, CAS_OP);
- return rc;
-}
-
-memcached_return_t memcached_set_by_key(memcached_st *ptr,
- const char *master_key __attribute__((unused)),
- size_t master_key_length __attribute__((unused)),
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_SET_START();
- rc= memcached_send(ptr, master_key, master_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, SET_OP);
- LIBMEMCACHED_MEMCACHED_SET_END();
- return rc;
-}
-
-memcached_return_t memcached_add_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_ADD_START();
- rc= memcached_send(ptr, master_key, master_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, ADD_OP);
- LIBMEMCACHED_MEMCACHED_ADD_END();
- return rc;
-}
-
-memcached_return_t memcached_replace_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- LIBMEMCACHED_MEMCACHED_REPLACE_START();
- rc= memcached_send(ptr, master_key, master_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, REPLACE_OP);
- LIBMEMCACHED_MEMCACHED_REPLACE_END();
- return rc;
-}
-
-memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- rc= memcached_send(ptr, master_key, master_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, PREPEND_OP);
- return rc;
-}
-
-memcached_return_t memcached_append_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags)
-{
- memcached_return_t rc;
- rc= memcached_send(ptr, master_key, master_key_length,
- key, key_length, value, value_length,
- expiration, flags, 0, APPEND_OP);
- return rc;
-}
-
-memcached_return_t memcached_cas_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas)
-{
- memcached_return_t rc;
- rc= memcached_send(ptr, master_key, master_key_length,
- key, key_length, value, value_length,
- expiration, flags, cas, CAS_OP);
- return rc;
-}
-
-static inline uint8_t get_com_code(memcached_storage_action_t verb, bool noreply)
-{
- /* 0 isn't a value we want, but GCC 4.2 seems to think ret can otherwise
- * be used uninitialized in this function. FAIL */
- uint8_t ret= 0;
-
- if (noreply)
- switch (verb)
- {
- case SET_OP:
- ret=PROTOCOL_BINARY_CMD_SETQ;
- break;
- case ADD_OP:
- ret=PROTOCOL_BINARY_CMD_ADDQ;
- break;
- case CAS_OP: /* FALLTHROUGH */
- case REPLACE_OP:
- ret=PROTOCOL_BINARY_CMD_REPLACEQ;
- break;
- case APPEND_OP:
- ret=PROTOCOL_BINARY_CMD_APPENDQ;
- break;
- case PREPEND_OP:
- ret=PROTOCOL_BINARY_CMD_PREPENDQ;
- break;
- default:
- WATCHPOINT_ASSERT(verb);
- break;
- }
- else
- switch (verb)
- {
- case SET_OP:
- ret=PROTOCOL_BINARY_CMD_SET;
- break;
- case ADD_OP:
- ret=PROTOCOL_BINARY_CMD_ADD;
- break;
- case CAS_OP: /* FALLTHROUGH */
- case REPLACE_OP:
- ret=PROTOCOL_BINARY_CMD_REPLACE;
- break;
- case APPEND_OP:
- ret=PROTOCOL_BINARY_CMD_APPEND;
- break;
- case PREPEND_OP:
- ret=PROTOCOL_BINARY_CMD_PREPEND;
- break;
- default:
- WATCHPOINT_ASSERT(verb);
- break;
- }
-
- return ret;
-}
-
-
-
-static memcached_return_t memcached_send_binary(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char *key,
- size_t key_length,
- const char *value,
- size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas,
- memcached_storage_action_t verb)
-{
- uint8_t flush;
- protocol_binary_request_set request= {.bytes= {0}};
- size_t send_length= sizeof(request.bytes);
- uint32_t server_key= memcached_generate_hash(ptr, master_key,
- master_key_length);
- memcached_server_st *server= &ptr->hosts[server_key];
- bool noreply= server->root->flags.no_reply;
-
- request.message.header.request.magic= PROTOCOL_BINARY_REQ;
- request.message.header.request.opcode= get_com_code(verb, noreply);
- request.message.header.request.keylen= htons((uint16_t)key_length);
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- if (verb == APPEND_OP || verb == PREPEND_OP)
- send_length -= 8; /* append & prepend does not contain extras! */
- else
- {
- request.message.header.request.extlen= 8;
- request.message.body.flags= htonl(flags);
- request.message.body.expiration= htonl((uint32_t)expiration);
- }
-
- request.message.header.request.bodylen= htonl((uint32_t) (key_length + value_length +
- request.message.header.request.extlen));
-
- if (cas)
- request.message.header.request.cas= htonll(cas);
-
- flush= (uint8_t) ((server->root->flags.buffer_requests && verb == SET_OP) ? 0 : 1);
-
- if (server->root->flags.use_udp && !flush)
- {
- size_t cmd_size= send_length + key_length + value_length;
-
- if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
- return MEMCACHED_WRITE_FAILURE;
- if (cmd_size + server->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
- memcached_io_write(server,NULL,0, 1);
- }
-
- /* write the header */
- if ((memcached_do(server, (const char*)request.bytes, send_length, 0) != MEMCACHED_SUCCESS) ||
- (memcached_io_write(server, key, key_length, 0) == -1) ||
- (memcached_io_write(server, value, value_length, (char) flush) == -1))
- {
- memcached_io_reset(server);
- return MEMCACHED_WRITE_FAILURE;
- }
-
- unlikely (verb == SET_OP && ptr->number_of_replicas > 0)
- {
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
-
- for (uint32_t x= 0; x < ptr->number_of_replicas; x++)
- {
- ++server_key;
- if (server_key == ptr->number_of_hosts)
- server_key= 0;
-
- memcached_server_st *srv= &ptr->hosts[server_key];
- if ((memcached_do(srv, (const char*)request.bytes,
- send_length, 0) != MEMCACHED_SUCCESS) ||
- (memcached_io_write(srv, key, key_length, 0) == -1) ||
- (memcached_io_write(srv, value, value_length, (char) flush) == -1))
- memcached_io_reset(srv);
- else
- memcached_server_response_decrement(srv);
- }
- }
-
- if (flush == 0)
- return MEMCACHED_BUFFERED;
-
- if (noreply)
- return MEMCACHED_SUCCESS;
-
- return memcached_response(server, NULL, 0, NULL);
-}
-
+++ /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,..
- *
- */
-
-#ifndef __MEMCACHED_STORAGE_H__
-#define __MEMCACHED_STORAGE_H__
-
-#include "libmemcached/memcached_types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* All of the functions for adding data to the server */
-LIBMEMCACHED_API
-memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-LIBMEMCACHED_API
-memcached_return_t memcached_add(memcached_st *ptr, const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-LIBMEMCACHED_API
-memcached_return_t memcached_replace(memcached_st *ptr, const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-LIBMEMCACHED_API
-memcached_return_t memcached_append(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-LIBMEMCACHED_API
-memcached_return_t memcached_prepend(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-LIBMEMCACHED_API
-memcached_return_t memcached_cas(memcached_st *ptr,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_set_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_add_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_replace_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_append_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_cas_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- const char *value, size_t value_length,
- time_t expiration,
- uint32_t flags,
- uint64_t cas);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_STORAGE_H__ */
+++ /dev/null
-#include "common.h"
-
-const char *memcached_strerror(memcached_st *ptr __attribute__((unused)), memcached_return_t rc)
-{
- switch (rc)
- {
- case MEMCACHED_SUCCESS:
- return "SUCCESS";
- case MEMCACHED_FAILURE:
- return "FAILURE";
- case MEMCACHED_HOST_LOOKUP_FAILURE:
- return "HOSTNAME LOOKUP FAILURE";
- case MEMCACHED_CONNECTION_FAILURE:
- return "CONNECTION FAILURE";
- case MEMCACHED_CONNECTION_BIND_FAILURE:
- return "CONNECTION BIND FAILURE";
- case MEMCACHED_READ_FAILURE:
- return "READ FAILURE";
- case MEMCACHED_UNKNOWN_READ_FAILURE:
- return "UNKNOWN READ FAILURE";
- case MEMCACHED_PROTOCOL_ERROR:
- return "PROTOCOL ERROR";
- case MEMCACHED_CLIENT_ERROR:
- return "CLIENT ERROR";
- case MEMCACHED_SERVER_ERROR:
- return "SERVER ERROR";
- case MEMCACHED_WRITE_FAILURE:
- return "WRITE FAILURE";
- case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE:
- return "CONNECTION SOCKET CREATE FAILURE";
- case MEMCACHED_DATA_EXISTS:
- return "CONNECTION DATA EXISTS";
- case MEMCACHED_DATA_DOES_NOT_EXIST:
- return "CONNECTION DATA DOES NOT EXIST";
- case MEMCACHED_NOTSTORED:
- return "NOT STORED";
- case MEMCACHED_STORED:
- return "STORED";
- case MEMCACHED_NOTFOUND:
- return "NOT FOUND";
- case MEMCACHED_MEMORY_ALLOCATION_FAILURE:
- return "MEMORY ALLOCATION FAILURE";
- case MEMCACHED_PARTIAL_READ:
- return "PARTIAL READ";
- case MEMCACHED_SOME_ERRORS:
- return "SOME ERRORS WERE REPORTED";
- case MEMCACHED_NO_SERVERS:
- return "NO SERVERS DEFINED";
- case MEMCACHED_END:
- return "SERVER END";
- case MEMCACHED_DELETED:
- return "SERVER DELETE";
- case MEMCACHED_VALUE:
- return "SERVER VALUE";
- case MEMCACHED_STAT:
- return "STAT VALUE";
- case MEMCACHED_ITEM:
- return "ITEM VALUE";
- case MEMCACHED_ERRNO:
- return "SYSTEM ERROR";
- case MEMCACHED_FAIL_UNIX_SOCKET:
- return "COULD NOT OPEN UNIX SOCKET";
- case MEMCACHED_NOT_SUPPORTED:
- return "ACTION NOT SUPPORTED";
- case MEMCACHED_FETCH_NOTFINISHED:
- return "FETCH WAS NOT COMPLETED";
- case MEMCACHED_NO_KEY_PROVIDED:
- return "A KEY LENGTH OF ZERO WAS PROVIDED";
- case MEMCACHED_BUFFERED:
- return "ACTION QUEUED";
- case MEMCACHED_TIMEOUT:
- return "A TIMEOUT OCCURRED";
- case MEMCACHED_BAD_KEY_PROVIDED:
- return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE";
- case MEMCACHED_INVALID_HOST_PROTOCOL:
- return "THE HOST TRANSPORT PROTOCOL DOES NOT MATCH THAT OF THE CLIENT";
- case MEMCACHED_SERVER_MARKED_DEAD:
- return "SERVER IS MARKED DEAD";
- case MEMCACHED_UNKNOWN_STAT_KEY:
- return "ENCOUNTERED AN UNKNOWN STAT KEY";
- case MEMCACHED_E2BIG:
- return "ITEM TOO BIG";
- case MEMCACHED_INVALID_ARGUMENTS:
- return "INVALID ARGUMENTS";
- case MEMCACHED_MAXIMUM_RETURN:
- return "Gibberish returned!";
- default:
- return "Gibberish returned!";
- }
-}
+++ /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))) / string->block_size;
- adjust++;
-
- new_size= sizeof(char) * (size_t)((adjust * string->block_size) + string->current_size);
- /* Test for overflow */
- if (new_size < need)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- new_value= string->root->call_realloc(string->root, string->string, new_size);
-
- if (new_value == NULL)
- return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
- string->string= new_value;
- string->end= string->string + current_offset;
-
- string->current_size+= (string->block_size * adjust);
- }
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_string_st *memcached_string_create(memcached_st *memc, memcached_string_st *string, size_t initial_size)
-{
- memcached_return_t rc;
-
- /* Saving malloc calls :) */
- if (string)
- {
- WATCHPOINT_ASSERT(memc->options.is_safe && string->options.is_initialized == false);
-
- memset(string, 0, sizeof(memcached_string_st));
- }
- else
- {
- string= memc->call_calloc(memc, 1, sizeof(memcached_string_st));
-
- if (string == NULL)
- {
- return NULL;
- }
-
- string->options.is_allocated= true;
- }
- string->block_size= MEMCACHED_BLOCK_SIZE;
- string->root= memc;
-
- rc= _string_check(string, initial_size);
- if (rc != MEMCACHED_SUCCESS)
- {
- memc->call_free(memc, string);
- return NULL;
- }
-
- string->options.is_initialized= true;
-
- WATCHPOINT_ASSERT(string->string == string->end);
-
- return string;
-}
-
-memcached_return_t memcached_string_append_character(memcached_string_st *string,
- char character)
-{
- memcached_return_t rc;
-
- rc= _string_check(string, 1);
-
- if (rc != MEMCACHED_SUCCESS)
- return rc;
-
- *string->end= character;
- string->end++;
-
- return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_string_append(memcached_string_st *string,
- const char *value, size_t length)
-{
- memcached_return_t rc;
-
- rc= _string_check(string, length);
-
- if (rc != MEMCACHED_SUCCESS)
- return rc;
-
- WATCHPOINT_ASSERT(length <= string->current_size);
- WATCHPOINT_ASSERT(string->string);
- WATCHPOINT_ASSERT(string->end >= string->string);
-
- memcpy(string->end, value, length);
- string->end+= length;
-
- return MEMCACHED_SUCCESS;
-}
-
-char *memcached_string_c_copy(memcached_string_st *string)
-{
- char *c_ptr;
-
- if (memcached_string_length(string) == 0)
- return NULL;
-
- c_ptr= string->root->call_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char));
-
- if (c_ptr == NULL)
- return NULL;
-
- memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string));
- c_ptr[memcached_string_length(string)]= 0;
-
- return c_ptr;
-}
-
-memcached_return_t memcached_string_reset(memcached_string_st *string)
-{
- string->end= string->string;
-
- return MEMCACHED_SUCCESS;
-}
-
-void memcached_string_free(memcached_string_st *ptr)
-{
- if (ptr == NULL)
- return;
-
- if (ptr->string)
- {
- ptr->root->call_free(ptr->root, ptr->string);
- }
-
- if (memcached_is_allocated(ptr))
- {
- ptr->root->call_free(ptr->root, ptr);
- }
- else
- {
- ptr->options.is_initialized= false;
- memset(ptr, 0, sizeof(memcached_string_st));
- }
-}
-
-memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
-{
- return _string_check(string, need);
-}
-
+++ /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.
- *
- */
-
-#ifndef __MEMCACHED_STRING_H__
-#define __MEMCACHED_STRING_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct memcached_string_st {
- memcached_st *root;
- char *end;
- char *string;
- size_t current_size;
- size_t block_size;
- struct {
- bool is_allocated:1;
- bool is_initialized:1;
- } options;
-};
-
-#define memcached_string_length(A) (size_t)((A)->end - (A)->string)
-#define memcached_string_set_length(A, B) (A)->end= (A)->string + B
-#define memcached_string_size(A) (A)->current_size
-#define memcached_string_value(A) (A)->string
-
-LIBMEMCACHED_API
-memcached_string_st *memcached_string_create(memcached_st *ptr,
- memcached_string_st *string,
- size_t initial_size);
-LIBMEMCACHED_API
-memcached_return_t memcached_string_check(memcached_string_st *string, size_t need);
-
-LIBMEMCACHED_API
-char *memcached_string_c_copy(memcached_string_st *string);
-
-LIBMEMCACHED_API
-memcached_return_t memcached_string_append_character(memcached_string_st *string,
- char character);
-LIBMEMCACHED_API
-memcached_return_t memcached_string_append(memcached_string_st *string,
- const char *value, size_t length);
-LIBMEMCACHED_API
-memcached_return_t memcached_string_reset(memcached_string_st *string);
-
-LIBMEMCACHED_API
-void memcached_string_free(memcached_string_st *string);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_STRING_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: Types for libmemcached
- *
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_TYPES_H
-#define LIBMEMCACHED_MEMCACHED_TYPES_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct memcached_st memcached_st;
-typedef struct memcached_stat_st memcached_stat_st;
-typedef struct memcached_analysis_st memcached_analysis_st;
-typedef struct memcached_result_st memcached_result_st;
-typedef struct memcached_string_st memcached_string_st;
-typedef struct memcached_server_st memcached_server_st;
-typedef struct memcached_continuum_item_st memcached_continuum_item_st;
-typedef memcached_return_t (*memcached_clone_fn)(memcached_st *parent, memcached_st *clone);
-typedef memcached_return_t (*memcached_cleanup_fn)(memcached_st *ptr);
-typedef void (*memcached_free_fn)(memcached_st *ptr, void *mem);
-typedef void *(*memcached_malloc_fn)(memcached_st *ptr, const size_t size);
-typedef void *(*memcached_realloc_fn)(memcached_st *ptr, void *mem, const size_t size);
-typedef void *(*memcached_calloc_fn)(memcached_st *ptr, size_t nelem, const size_t elsize);
-typedef memcached_return_t (*memcached_execute_fn)(memcached_st *ptr, memcached_result_st *result, void *context);
-typedef memcached_return_t (*memcached_server_fn)(memcached_st *ptr, memcached_server_st *server, void *context);
-typedef memcached_return_t (*memcached_trigger_key_fn)(memcached_st *ptr,
- const char *key, size_t key_length,
- memcached_result_st *result);
-typedef memcached_return_t (*memcached_trigger_delete_key_fn)(memcached_st *ptr,
- const char *key, size_t key_length);
-
-typedef memcached_return_t (*memcached_dump_fn)(memcached_st *ptr,
- const char *key, size_t key_length, void *context);
-
-typedef struct {
- memcached_execute_fn *callback;
- void *context;
- uint32_t number_of_callback;
-} memcached_callback_st;
-
-
-/**
- @note The following definitions are just here for backwards compatibility.
-*/
-typedef memcached_return_t memcached_return;
-typedef memcached_server_distribution_t memcached_server_distribution;
-typedef memcached_behavior_t memcached_behavior;
-typedef memcached_callback_t memcached_callback;
-typedef memcached_hash_t memcached_hash;
-typedef memcached_connection_t memcached_connection;
-typedef memcached_clone_fn memcached_clone_func;
-typedef memcached_cleanup_fn memcached_cleanup_func;
-typedef memcached_free_fn memcached_free_function;
-typedef memcached_malloc_fn memcached_malloc_function;
-typedef memcached_realloc_fn memcached_realloc_function;
-typedef memcached_calloc_fn memcached_calloc_function;
-typedef memcached_execute_fn memcached_execute_function;
-typedef memcached_server_fn memcached_server_function;
-typedef memcached_trigger_key_fn memcached_trigger_key;
-typedef memcached_trigger_delete_key_fn memcached_trigger_delete_key;
-typedef memcached_dump_fn memcached_dump_func;
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBMEMCACHED_MEMCACHED_TYPES_H */
#ifndef MEMCACHED_UTIL_H
#define MEMCACHED_UTIL_H
-#include <libmemcached/memcached_pool.h>
+#include <libmemcached/pool.h>
#endif /* MEMCACHED_UTIL_H */
+++ /dev/null
-#include "common.h"
-
-memcached_return_t memcached_verbosity(memcached_st *ptr, unsigned int verbosity)
-{
- unsigned int x;
- size_t send_length;
- memcached_return_t rc;
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
- send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
- "verbosity %u\r\n", verbosity);
- unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
- return MEMCACHED_WRITE_FAILURE;
-
- rc= MEMCACHED_SUCCESS;
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- memcached_return_t rrc;
-
- rrc= memcached_do(&ptr->hosts[x], buffer, send_length, 1);
- if (rrc != MEMCACHED_SUCCESS)
- {
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
-
- unlikely (ptr->flags.use_udp)
- continue;
-
- rrc= memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
- if (rrc != MEMCACHED_SUCCESS)
- rc= MEMCACHED_SOME_ERRORS;
- }
-
- return rc;
-}
+++ /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;
-
- if (ptr->flags.binary_protocol)
- return memcached_version_binary(ptr);
- else
- return memcached_version_textual(ptr);
-}
-
-static inline memcached_return_t memcached_version_textual(memcached_st *ptr)
-{
- unsigned int x;
- size_t send_length;
- memcached_return_t rc;
- char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
- char *response_ptr;
- const char *command= "version\r\n";
-
- send_length= strlen(command);
-
- rc= MEMCACHED_SUCCESS;
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- memcached_return_t rrc;
-
- rrc= memcached_do(&ptr->hosts[x], command, send_length, 1);
- if (rrc != MEMCACHED_SUCCESS)
- {
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
-
- rrc= memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
- if (rrc != MEMCACHED_SUCCESS)
- {
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
-
- /* Find the space, and then move one past it to copy version */
- response_ptr= index(buffer, ' ');
- response_ptr++;
-
- ptr->hosts[x].major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
- response_ptr= index(response_ptr, '.');
- response_ptr++;
- ptr->hosts[x].minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
- response_ptr= index(response_ptr, '.');
- response_ptr++;
- ptr->hosts[x].micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
- }
-
- return rc;
-}
-
-static inline memcached_return_t memcached_version_binary(memcached_st *ptr)
-{
- memcached_return_t rc;
- unsigned int x;
- protocol_binary_request_version request= { .bytes= {0}};
- request.message.header.request.magic= PROTOCOL_BINARY_REQ;
- request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
- request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
- rc= MEMCACHED_SUCCESS;
- for (x= 0; x < ptr->number_of_hosts; x++)
- {
- memcached_return_t rrc;
-
- rrc= memcached_do(&ptr->hosts[x], request.bytes, sizeof(request.bytes), 1);
- if (rrc != MEMCACHED_SUCCESS)
- {
- memcached_io_reset(&ptr->hosts[x]);
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
- }
-
- for (x= 0; x < ptr->number_of_hosts; x++)
- if (memcached_server_response_count(&ptr->hosts[x]) > 0)
- {
- memcached_return_t rrc;
- char buffer[32];
- char *p;
-
- rrc= memcached_response(&ptr->hosts[x], buffer, sizeof(buffer), NULL);
- if (rrc != MEMCACHED_SUCCESS)
- {
- memcached_io_reset(&ptr->hosts[x]);
- rc= MEMCACHED_SOME_ERRORS;
- continue;
- }
-
- ptr->hosts[x].major_version= (uint8_t)strtol(buffer, &p, 10);
- ptr->hosts[x].minor_version= (uint8_t)strtol(p + 1, &p, 10);
- ptr->hosts[x].micro_version= (uint8_t)strtol(p + 1, NULL, 10);
- }
-
- return rc;
-}
+++ /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: Localized copy of WATCHPOINT debug symbols
- *
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_WATCHPOINT_H
-#define LIBMEMCACHED_MEMCACHED_WATCHPOINT_H
-
-/* Some personal debugging functions */
-#if defined(DEBUG)
-
-#include <assert.h>
-
-#define WATCHPOINT fprintf(stderr, "\nWATCHPOINT %s:%d (%s)\n", __FILE__, __LINE__,__func__);fflush(stdout);
-#define WATCHPOINT_ERROR(A) fprintf(stderr, "\nWATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout);
-#define WATCHPOINT_IFERROR(A) if(A != MEMCACHED_SUCCESS)fprintf(stderr, "\nWATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout);
-#define WATCHPOINT_STRING(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__,A);fflush(stdout);
-#define WATCHPOINT_STRING_LENGTH(A,B) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %.*s\n", __FILE__, __LINE__,__func__,(int)B,A);fflush(stdout);
-#define WATCHPOINT_NUMBER(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %zu\n", __FILE__, __LINE__,__func__,(size_t)(A));fflush(stdout);
-#define WATCHPOINT_ERRNO(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__, strerror(A));fflush(stdout);
-#define WATCHPOINT_ASSERT_PRINT(A,B,C) if(!(A)){fprintf(stderr, "\nWATCHPOINT ASSERT %s:%d (%s) ", __FILE__, __LINE__,__func__);fprintf(stderr, (B),(C));fprintf(stderr,"\n");fflush(stdout);}assert((A));
-#define WATCHPOINT_ASSERT(A) assert((A));
-#define WATCHPOINT_ASSERT_INITIALIZED(A) (memcached_is_initialized((A));
-
-#else
-
-#define WATCHPOINT
-#define WATCHPOINT_ERROR(A)
-#define WATCHPOINT_IFERROR(A)
-#define WATCHPOINT_STRING(A)
-#define WATCHPOINT_NUMBER(A)
-#define WATCHPOINT_ERRNO(A)
-#define WATCHPOINT_ASSERT_PRINT(A,B,C)
-#define WATCHPOINT_ASSERT(A)
-#define WATCHPOINT_ASSERT_INITIALIZED(A)
-
-#endif /* DEBUG */
-
-#endif /* LIBMEMCACHED_MEMCACHED_WATCHPOINT_H */
--- /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_st *memcached_servers_parse(const char *server_strings)
+{
+ char *string;
+ uint32_t port;
+ uint32_t weight;
+ const char *begin_ptr;
+ const char *end_ptr;
+ memcached_server_st *servers= NULL;
+ memcached_return_t rc;
+
+ WATCHPOINT_ASSERT(server_strings);
+
+ end_ptr= server_strings + strlen(server_strings);
+
+ for (begin_ptr= server_strings, string= index(server_strings, ',');
+ begin_ptr != end_ptr;
+ string= index(begin_ptr, ','))
+ {
+ char buffer[HUGE_STRING_LEN];
+ char *ptr, *ptr2;
+ port= 0;
+ weight= 0;
+
+ if (string)
+ {
+ memcpy(buffer, begin_ptr, (size_t) (string - begin_ptr));
+ buffer[(unsigned int)(string - begin_ptr)]= 0;
+ begin_ptr= string+1;
+ }
+ else
+ {
+ size_t length= strlen(begin_ptr);
+ memcpy(buffer, begin_ptr, length);
+ buffer[length]= 0;
+ begin_ptr= end_ptr;
+ }
+
+ ptr= index(buffer, ':');
+
+ if (ptr)
+ {
+ ptr[0]= 0;
+
+ ptr++;
+
+ port= (uint32_t) strtoul(ptr, (char **)NULL, 10);
+
+ ptr2= index(ptr, ' ');
+ if (! ptr2)
+ ptr2= index(ptr, ':');
+ if (ptr2)
+ {
+ ptr2++;
+ weight = (uint32_t) strtoul(ptr2, (char **)NULL, 10);
+ }
+ }
+
+ servers= memcached_server_list_append_with_weight(servers, buffer, port, weight, &rc);
+
+ if (isspace(*begin_ptr))
+ begin_ptr++;
+ }
+
+ return servers;
+}
--- /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: Connection pool implementation for libmemcached.
+ *
+ */
+
+
+#ifndef MEMCACHED_POOL_H
+#define MEMCACHED_POOL_H
+
+#include <libmemcached/memcached.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct memcached_pool_st;
+typedef struct memcached_pool_st memcached_pool_st;
+
+LIBMEMCACHED_API
+memcached_pool_st *memcached_pool_create(memcached_st* mmc, uint32_t initial,
+ uint32_t max);
+LIBMEMCACHED_API
+memcached_st* memcached_pool_destroy(memcached_pool_st* pool);
+LIBMEMCACHED_API
+memcached_st* memcached_pool_pop(memcached_pool_st* pool,
+ bool block,
+ memcached_return_t* rc);
+LIBMEMCACHED_API
+memcached_return_t memcached_pool_push(memcached_pool_st* pool,
+ memcached_st* mmc);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_pool_behavior_set(memcached_pool_st *ptr,
+ memcached_behavior_t flag,
+ uint64_t data);
+LIBMEMCACHED_API
+memcached_return_t memcached_pool_behavior_get(memcached_pool_st *ptr,
+ memcached_behavior_t flag,
+ uint64_t *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEMCACHED_POOL_H */
--- /dev/null
+#include "common.h"
+
+memcached_return_t memcached_purge(memcached_server_st *ptr)
+{
+ uint32_t x;
+ memcached_return_t ret= MEMCACHED_SUCCESS;
+
+ if (ptr->root->options.is_purging || /* already purging */
+ (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark &&
+ ptr->io_bytes_sent < ptr->root->io_bytes_watermark) ||
+ (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark &&
+ memcached_server_response_count(ptr) < 2))
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ /* memcached_io_write and memcached_response may call memcached_purge
+ so we need to be able stop any recursion.. */
+ ptr->root->options.is_purging= true;
+
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+ /* Force a flush of the buffer to ensure that we don't have the n-1 pending
+ requests buffered up.. */
+ if (memcached_io_write(ptr, NULL, 0, 1) == -1)
+ {
+ ptr->root->options.is_purging= true;
+ return MEMCACHED_WRITE_FAILURE;
+ }
+ WATCHPOINT_ASSERT(ptr->fd != -1);
+
+ uint32_t no_msg= memcached_server_response_count(ptr) - 1;
+ if (no_msg > 0)
+ {
+ memcached_result_st result;
+ memcached_result_st *result_ptr;
+ char buffer[SMALL_STRING_LEN];
+
+ /*
+ * We need to increase the timeout, because we might be waiting for
+ * data to be sent from the server (the commands was in the output buffer
+ * and just flushed
+ */
+ int32_t timeo= ptr->root->poll_timeout;
+ ptr->root->poll_timeout= 2000;
+
+ result_ptr= memcached_result_create(ptr->root, &result);
+ WATCHPOINT_ASSERT(result_ptr);
+
+ for (x= 0; x < no_msg; x++)
+ {
+ memcached_result_reset(result_ptr);
+ memcached_return_t rc= memcached_read_one_response(ptr, buffer,
+ sizeof (buffer),
+ result_ptr);
+ /*
+ * Purge doesn't care for what kind of command results that is received.
+ * The only kind of errors I care about if is I'm out of sync with the
+ * protocol or have problems reading data from the network..
+ */
+ if (rc== MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_UNKNOWN_READ_FAILURE)
+ {
+ WATCHPOINT_ERROR(rc);
+ ret = rc;
+ memcached_io_reset(ptr);
+ }
+ }
+
+ memcached_result_free(result_ptr);
+ ptr->root->poll_timeout= timeo;
+ }
+ ptr->root->options.is_purging= 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, uint8_t io_death)
+{
+ if (ptr->fd != -1)
+ {
+ if (io_death == 0 && ptr->type != MEMCACHED_CONNECTION_UDP)
+ {
+ memcached_return_t rc;
+ char buffer[MEMCACHED_MAX_BUFFER];
+
+ if (ptr->root->flags.binary_protocol)
+ {
+ protocol_binary_request_quit request = {.bytes= {0}};
+ request.message.header.request.magic = PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT;
+ request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
+ rc= memcached_do(ptr, request.bytes, sizeof(request.bytes), 1);
+ }
+ else
+ rc= memcached_do(ptr, "quit\r\n", 6, 1);
+
+ WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED);
+
+ /* read until socket is closed, or there is an error
+ * closing the socket before all data is read
+ * results in server throwing away all data which is
+ * not read
+ */
+ ssize_t nread;
+ while (memcached_io_read(ptr, buffer, sizeof(buffer)/sizeof(*buffer),
+ &nread) == MEMCACHED_SUCCESS);
+
+ /*
+ * memcached_io_read may call memcached_quit_server with io_death if
+ * it encounters problems, but we don't care about those occurences.
+ * The intention of that loop is to drain the data sent from the
+ * server to ensure that the server processed all of the data we
+ * sent to the server.
+ */
+ ptr->server_failure_counter= 0;
+ }
+ memcached_io_close(ptr);
+
+ ptr->fd= -1;
+ ptr->write_buffer_offset= (size_t) ((ptr->type == MEMCACHED_CONNECTION_UDP) ? UDP_DATAGRAM_HEADER_LENGTH : 0);
+ ptr->read_buffer_length= 0;
+ ptr->read_ptr= ptr->read_buffer;
+ memcached_server_response_reset(ptr);
+ }
+
+ if(io_death) ptr->server_failure_counter++;
+}
+
+void memcached_quit(memcached_st *ptr)
+{
+ unsigned int x;
+
+ if (ptr->hosts == NULL ||
+ ptr->number_of_hosts == 0)
+ return;
+
+ if (ptr->hosts && ptr->number_of_hosts)
+ {
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ memcached_quit_server(&ptr->hosts[x], 0);
+ }
+}
--- /dev/null
+/*
+ Memcached library
+
+ 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_st *ptr,
+ char *buffer, size_t buffer_length,
+ memcached_result_st *result);
+static memcached_return_t binary_read_one_response(memcached_server_st *ptr,
+ char *buffer, size_t buffer_length,
+ memcached_result_st *result);
+
+memcached_return_t memcached_read_one_response(memcached_server_st *ptr,
+ char *buffer, size_t buffer_length,
+ memcached_result_st *result)
+{
+ memcached_server_response_decrement(ptr);
+
+ if (result == NULL)
+ result = &ptr->root->result;
+
+ memcached_return_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_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)
+ (void)memcached_io_write(ptr, NULL, 0, 1);
+
+ /*
+ * The previous implementation purged all pending requests and just
+ * returned the last one. Purge all pending messages to ensure backwards
+ * compatibility.
+ */
+ if (ptr->root->flags.binary_protocol == false)
+ while (memcached_server_response_count(ptr) > 1)
+ {
+ memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result);
+
+ unlikely (rc != MEMCACHED_END &&
+ rc != MEMCACHED_STORED &&
+ rc != MEMCACHED_SUCCESS &&
+ rc != MEMCACHED_STAT &&
+ rc != MEMCACHED_DELETED &&
+ rc != MEMCACHED_NOTFOUND &&
+ rc != MEMCACHED_NOTSTORED &&
+ rc != MEMCACHED_DATA_EXISTS)
+ return rc;
+ }
+
+ return memcached_read_one_response(ptr, buffer, buffer_length, result);
+}
+
+static memcached_return_t textual_value_fetch(memcached_server_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;
+
+ if (ptr->root->flags.use_udp)
+ return MEMCACHED_NOT_SUPPORTED;
+
+ WATCHPOINT_ASSERT(ptr->root);
+ end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
+
+ memcached_result_reset(result);
+
+ string_ptr= buffer;
+ string_ptr+= 6; /* "VALUE " */
+
+
+ /* We load the key */
+ {
+ char *key;
+ size_t prefix_length;
+
+ key= result->key;
+ result->key_length= 0;
+
+ for (prefix_length= ptr->root->prefix_key_length; !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
+ {
+ if (prefix_length == 0)
+ {
+ *key= *string_ptr;
+ key++;
+ result->key_length++;
+ }
+ else
+ prefix_length--;
+ }
+ result->key[result->key_length]= 0;
+ }
+
+ if (end_ptr == string_ptr)
+ goto read_error;
+
+ /* Flags fetch move past space */
+ string_ptr++;
+ if (end_ptr == string_ptr)
+ goto read_error;
+ for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
+ result->flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10);
+
+ if (end_ptr == string_ptr)
+ goto read_error;
+
+ /* Length fetch move past space*/
+ string_ptr++;
+ if (end_ptr == string_ptr)
+ goto read_error;
+
+ for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
+ value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
+
+ if (end_ptr == string_ptr)
+ goto read_error;
+
+ /* Skip spaces */
+ if (*string_ptr == '\r')
+ {
+ /* Skip past the \r\n */
+ string_ptr+= 2;
+ }
+ else
+ {
+ string_ptr++;
+ for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
+ result->cas= strtoull(next_ptr, &string_ptr, 10);
+ }
+
+ if (end_ptr < string_ptr)
+ goto read_error;
+
+ /* We add two bytes so that we can walk the \r\n */
+ rc= memcached_string_check(&result->value, value_length+2);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ value_length= 0;
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
+
+ value_ptr= memcached_string_value(&result->value);
+ /*
+ We read the \r\n into the string since not doing so is more
+ cycles then the waster of memory to do so.
+
+ We are null terminating through, which will most likely make
+ some people lazy about using the return length.
+ */
+ to_read= (value_length) + 2;
+ ssize_t read_length= 0;
+ memcached_return_t rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length);
+ if (rrc != MEMCACHED_SUCCESS)
+ return rrc;
+
+ if (read_length != (ssize_t)(value_length + 2))
+ {
+ goto read_error;
+ }
+
+/* This next bit blows the API, but this is internal....*/
+ {
+ char *char_ptr;
+ char_ptr= memcached_string_value(&result->value);;
+ char_ptr[value_length]= 0;
+ char_ptr[value_length + 1]= 0;
+ memcached_string_set_length(&result->value, value_length);
+ }
+
+ return MEMCACHED_SUCCESS;
+
+read_error:
+ memcached_io_reset(ptr);
+
+ return MEMCACHED_PARTIAL_READ;
+}
+
+static memcached_return_t textual_read_one_response(memcached_server_st *ptr,
+ char *buffer, size_t buffer_length,
+ memcached_result_st *result)
+{
+ memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length);
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ switch(buffer[0])
+ {
+ case 'V': /* VALUE || VERSION */
+ if (buffer[1] == 'A') /* VALUE */
+ {
+ /* We add back in one because we will need to search for END */
+ memcached_server_response_increment(ptr);
+ return textual_value_fetch(ptr, buffer, result);
+ }
+ else if (buffer[1] == 'E') /* VERSION */
+ {
+ return MEMCACHED_SUCCESS;
+ }
+ else
+ {
+ WATCHPOINT_STRING(buffer);
+ WATCHPOINT_ASSERT(0);
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ case 'O': /* OK */
+ return MEMCACHED_SUCCESS;
+ case 'S': /* STORED STATS SERVER_ERROR */
+ {
+ if (buffer[2] == 'A') /* STORED STATS */
+ {
+ memcached_server_response_increment(ptr);
+ return MEMCACHED_STAT;
+ }
+ else if (buffer[1] == 'E') /* SERVER_ERROR */
+ {
+ char *rel_ptr;
+ char *startptr= buffer + 13, *endptr= startptr;
+
+ while (*endptr != '\r' && *endptr != '\n') endptr++;
+
+ /*
+ Yes, we could make this "efficent" but to do that we would need
+ to maintain more state for the size of the buffer. Why waste
+ memory in the struct, which is important, for something that
+ rarely should happen?
+ */
+ rel_ptr= (char *)ptr->root->call_realloc(ptr->root,
+ ptr->cached_server_error,
+ (size_t) (endptr - startptr + 1));
+
+ if (rel_ptr == NULL)
+ {
+ /* If we happened to have some memory, we just null it since we don't know the size */
+ if (ptr->cached_server_error)
+ ptr->cached_server_error[0]= 0;
+ return MEMCACHED_SERVER_ERROR;
+ }
+ ptr->cached_server_error= rel_ptr;
+
+ memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr));
+ ptr->cached_server_error[endptr - startptr]= 0;
+ return MEMCACHED_SERVER_ERROR;
+ }
+ else if (buffer[1] == 'T')
+ return MEMCACHED_STORED;
+ else
+ {
+ WATCHPOINT_STRING(buffer);
+ WATCHPOINT_ASSERT(0);
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ }
+ case 'D': /* DELETED */
+ return MEMCACHED_DELETED;
+ case 'N': /* NOT_FOUND */
+ {
+ if (buffer[4] == 'F')
+ return MEMCACHED_NOTFOUND;
+ else if (buffer[4] == 'S')
+ return MEMCACHED_NOTSTORED;
+ else
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ case 'E': /* PROTOCOL ERROR or END */
+ {
+ if (buffer[1] == 'N')
+ return MEMCACHED_END;
+ else if (buffer[1] == 'R')
+ return MEMCACHED_PROTOCOL_ERROR;
+ else if (buffer[1] == 'X')
+ return MEMCACHED_DATA_EXISTS;
+ else
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ case 'I': /* CLIENT ERROR */
+ /* We add back in one because we will need to search for END */
+ memcached_server_response_increment(ptr);
+ return MEMCACHED_ITEM;
+ case 'C': /* CLIENT ERROR */
+ return MEMCACHED_CLIENT_ERROR;
+ default:
+ {
+ unsigned long long auto_return_value;
+
+ if (sscanf(buffer, "%llu", &auto_return_value) == 1)
+ return MEMCACHED_SUCCESS;
+
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ }
+
+ /* NOTREACHED */
+}
+
+char *memcached_result_value(memcached_result_st *ptr)
+{
+ memcached_string_st *sptr= &ptr->value;
+ return memcached_string_value(sptr);
+}
+
+size_t memcached_result_length(memcached_result_st *ptr)
+{
+ memcached_string_st *sptr= &ptr->value;
+ return memcached_string_length(sptr);
+}
+
+static memcached_return_t binary_read_one_response(memcached_server_st *ptr,
+ char *buffer, size_t buffer_length,
+ memcached_result_st *result)
+{
+ protocol_binary_response_header header;
+
+ unlikely (memcached_safe_read(ptr, &header.bytes,
+ sizeof(header.bytes)) != MEMCACHED_SUCCESS)
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+
+ unlikely (header.response.magic != PROTOCOL_BINARY_RES)
+ return MEMCACHED_PROTOCOL_ERROR;
+
+ /*
+ ** Convert the header to host local endian!
+ */
+ header.response.keylen= ntohs(header.response.keylen);
+ header.response.status= ntohs(header.response.status);
+ header.response.bodylen= ntohl(header.response.bodylen);
+ header.response.cas= ntohll(header.response.cas);
+ uint32_t bodylen= header.response.bodylen;
+
+ if (header.response.status == 0)
+ {
+ switch (header.response.opcode)
+ {
+ case PROTOCOL_BINARY_CMD_GETKQ:
+ /*
+ * We didn't increment the response counter for the GETKQ packet
+ * (only the final NOOP), so we need to increment the counter again.
+ */
+ memcached_server_response_increment(ptr);
+ /* FALLTHROUGH */
+ case PROTOCOL_BINARY_CMD_GETK:
+ {
+ uint16_t keylen= header.response.keylen;
+ memcached_result_reset(result);
+ result->cas= header.response.cas;
+
+ if (memcached_safe_read(ptr, &result->flags,
+ sizeof (result->flags)) != MEMCACHED_SUCCESS)
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+
+ result->flags= ntohl(result->flags);
+ bodylen -= header.response.extlen;
+
+ result->key_length= keylen;
+ if (memcached_safe_read(ptr, result->key, keylen) != MEMCACHED_SUCCESS)
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+
+ bodylen -= keylen;
+ if (memcached_string_check(&result->value,
+ bodylen) != MEMCACHED_SUCCESS)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ char *vptr= memcached_string_value(&result->value);
+ if (memcached_safe_read(ptr, vptr, bodylen) != MEMCACHED_SUCCESS)
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+
+ memcached_string_set_length(&result->value, bodylen);
+ }
+ break;
+ case PROTOCOL_BINARY_CMD_INCREMENT:
+ case PROTOCOL_BINARY_CMD_DECREMENT:
+ {
+ if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t))
+ return MEMCACHED_PROTOCOL_ERROR;
+
+ WATCHPOINT_ASSERT(bodylen == buffer_length);
+ uint64_t val;
+ if (memcached_safe_read(ptr, &val, sizeof(val)) != MEMCACHED_SUCCESS)
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+
+ val= ntohll(val);
+ memcpy(buffer, &val, sizeof(val));
+ }
+ break;
+ case PROTOCOL_BINARY_CMD_VERSION:
+ {
+ memset(buffer, 0, buffer_length);
+ if (bodylen >= buffer_length)
+ /* not enough space in buffer.. should not happen... */
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ else if (memcached_safe_read(ptr, buffer, bodylen) != MEMCACHED_SUCCESS)
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ break;
+ case PROTOCOL_BINARY_CMD_FLUSH:
+ case PROTOCOL_BINARY_CMD_QUIT:
+ case PROTOCOL_BINARY_CMD_SET:
+ case PROTOCOL_BINARY_CMD_ADD:
+ case PROTOCOL_BINARY_CMD_REPLACE:
+ case PROTOCOL_BINARY_CMD_APPEND:
+ case PROTOCOL_BINARY_CMD_PREPEND:
+ case PROTOCOL_BINARY_CMD_DELETE:
+ {
+ WATCHPOINT_ASSERT(bodylen == 0);
+ return MEMCACHED_SUCCESS;
+ }
+ case PROTOCOL_BINARY_CMD_NOOP:
+ {
+ WATCHPOINT_ASSERT(bodylen == 0);
+ return MEMCACHED_END;
+ }
+ case PROTOCOL_BINARY_CMD_STAT:
+ {
+ if (bodylen == 0)
+ return MEMCACHED_END;
+ else if (bodylen + 1 > buffer_length)
+ /* not enough space in buffer.. should not happen... */
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ else
+ {
+ size_t keylen= header.response.keylen;
+ memset(buffer, 0, buffer_length);
+ if (memcached_safe_read(ptr, buffer, keylen) != MEMCACHED_SUCCESS ||
+ memcached_safe_read(ptr, buffer + keylen + 1,
+ bodylen - keylen) != MEMCACHED_SUCCESS)
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ }
+ }
+ break;
+ default:
+ {
+ /* Command not implemented yet! */
+ WATCHPOINT_ASSERT(0);
+ return MEMCACHED_PROTOCOL_ERROR;
+ }
+ }
+ }
+ else if (header.response.bodylen)
+ {
+ /* What should I do with the error message??? just discard it for now */
+ char hole[SMALL_STRING_LEN];
+ while (bodylen > 0)
+ {
+ size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
+ if (memcached_safe_read(ptr, hole, nr) != MEMCACHED_SUCCESS)
+ return MEMCACHED_UNKNOWN_READ_FAILURE;
+ bodylen-= (uint32_t) nr;
+ }
+
+ /* This might be an error from one of the quiet commands.. if
+ * so, just throw it away and get the next one. What about creating
+ * a callback to the user with the error information?
+ */
+ switch (header.response.opcode)
+ {
+ case PROTOCOL_BINARY_CMD_SETQ:
+ case PROTOCOL_BINARY_CMD_ADDQ:
+ case PROTOCOL_BINARY_CMD_REPLACEQ:
+ case PROTOCOL_BINARY_CMD_APPENDQ:
+ case PROTOCOL_BINARY_CMD_PREPENDQ:
+ return binary_read_one_response(ptr, buffer, buffer_length, result);
+ default:
+ break;
+ }
+ }
+
+ memcached_return_t rc= MEMCACHED_SUCCESS;
+ unlikely(header.response.status != 0)
+ switch (header.response.status)
+ {
+ case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
+ rc= MEMCACHED_NOTFOUND;
+ break;
+ case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
+ rc= MEMCACHED_DATA_EXISTS;
+ break;
+ case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
+ rc= MEMCACHED_NOTSTORED;
+ break;
+ case PROTOCOL_BINARY_RESPONSE_E2BIG:
+ rc= MEMCACHED_E2BIG;
+ break;
+ case PROTOCOL_BINARY_RESPONSE_ENOMEM:
+ rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ break;
+ case PROTOCOL_BINARY_RESPONSE_EINVAL:
+ case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
+ default:
+ /* @todo fix the error mappings */
+ rc= MEMCACHED_PROTOCOL_ERROR;
+ break;
+ }
+
+ return rc;
+}
--- /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"
+
+memcached_result_st *memcached_result_create(memcached_st *memc,
+ memcached_result_st *ptr)
+{
+ WATCHPOINT_ASSERT(memc && memc->options.is_initialized);
+
+ /* Saving malloc calls :) */
+ if (ptr)
+ {
+ memset(ptr, 0, sizeof(memcached_result_st));
+ }
+ else
+ {
+ ptr= memc->call_malloc(memc, sizeof(memcached_result_st));
+
+ if (ptr == NULL)
+ return NULL;
+ ptr->options.is_allocated= true;
+ }
+
+ ptr->options.is_initialized= true;
+
+ ptr->root= memc;
+ memcached_string_create(memc, &ptr->value, 0);
+ WATCHPOINT_ASSERT_INITIALIZED(&ptr->value);
+ WATCHPOINT_ASSERT(ptr->value.string == NULL);
+
+ return ptr;
+}
+
+void memcached_result_reset(memcached_result_st *ptr)
+{
+ ptr->key_length= 0;
+ memcached_string_reset(&ptr->value);
+ ptr->flags= 0;
+ ptr->cas= 0;
+ ptr->expiration= 0;
+}
+
+/*
+ NOTE turn into macro
+*/
+memcached_return_t memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length)
+{
+ return memcached_string_append(&ptr->value, value, length);
+}
+
+void memcached_result_free(memcached_result_st *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ memcached_string_free(&ptr->value);
+
+ if (memcached_is_allocated(ptr))
+ {
+ free(ptr);
+ }
+ else
+ {
+ ptr->options.is_initialized= 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: Functions to manipulate the result structure.
+ *
+ */
+
+#ifndef __MEMCACHED_RESULT_H__
+#define __MEMCACHED_RESULT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct memcached_result_st {
+ struct {
+ bool is_allocated:1;
+ bool is_initialized:1;
+ } options;
+ uint32_t flags;
+ time_t expiration;
+ memcached_st *root;
+ size_t key_length;
+ uint64_t cas;
+ memcached_string_st value;
+ char key[MEMCACHED_MAX_KEY];
+ /* Add result callback function */
+};
+
+/* Result Struct */
+LIBMEMCACHED_API
+void memcached_result_free(memcached_result_st *result);
+LIBMEMCACHED_API
+void memcached_result_reset(memcached_result_st *ptr);
+LIBMEMCACHED_API
+memcached_result_st *memcached_result_create(memcached_st *ptr,
+ memcached_result_st *result);
+#define memcached_result_key_value(A) (A)->key
+#define memcached_result_key_length(A) (A)->key_length
+#define memcached_result_string_st(A) ((A)->value)
+#ifdef FIX
+#define memcached_result_value(A) memcached_string_value((A)->value)
+#define memcached_result_length(A) memcached_string_length((A)->value)
+#else
+LIBMEMCACHED_API
+char *memcached_result_value(memcached_result_st *ptr);
+LIBMEMCACHED_API
+size_t memcached_result_length(memcached_result_st *ptr);
+#endif
+#define memcached_result_flags(A) (A)->flags
+#define memcached_result_cas(A) (A)->cas
+LIBMEMCACHED_API
+memcached_return_t memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length);
+#define memcached_result_set_flags(A,B) (A)->flags=(B)
+#define memcached_result_set_expiration(A,B) (A)->expiration=(B)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_RESULT_H__ */
--- /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 "common.h"
+
+memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr)
+{
+ if (ptr == NULL)
+ {
+ ptr= (memcached_server_st *)calloc(1, sizeof(memcached_server_st));
+
+ if (!ptr)
+ return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+
+ ptr->options.is_allocated= true;
+ }
+ else
+ {
+ memset(ptr, 0, sizeof(memcached_server_st));
+ }
+
+ ptr->root= memc;
+
+ return ptr;
+}
+
+memcached_server_st *memcached_server_create_with(memcached_st *memc, memcached_server_st *host,
+ const char *hostname, in_port_t port,
+ uint32_t weight, memcached_connection_t type)
+{
+ host= memcached_server_create(memc, host);
+
+ if (host == NULL)
+ return NULL;
+
+ strncpy(host->hostname, hostname, MEMCACHED_MAX_HOST_LENGTH - 1);
+ host->root= memc ? memc : NULL;
+ host->port= port;
+ host->weight= weight;
+ host->fd= -1;
+ host->type= type;
+ host->read_ptr= host->read_buffer;
+ if (memc)
+ host->next_retry= memc->retry_timeout;
+ if (type == MEMCACHED_CONNECTION_UDP)
+ {
+ host->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
+ memcached_io_init_udp_header(host, 0);
+ }
+
+ return host;
+}
+
+void memcached_server_free(memcached_server_st *ptr)
+{
+ memcached_quit_server(ptr, 0);
+
+ if (ptr->cached_server_error)
+ free(ptr->cached_server_error);
+
+ if (ptr->address_info)
+ freeaddrinfo(ptr->address_info);
+
+
+ if (memcached_is_allocated(ptr))
+ {
+ ptr->root->call_free(ptr->root, ptr);
+ }
+ else
+ {
+ memset(ptr, 0, sizeof(memcached_server_st));
+ }
+}
+
+/*
+ If we do not have a valid object to clone from, we toss an error.
+*/
+memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr)
+{
+ memcached_server_st *rv= NULL;
+
+ /* We just do a normal create if ptr is missing */
+ if (ptr == NULL)
+ return NULL;
+
+ rv = memcached_server_create_with(ptr->root, clone,
+ ptr->hostname, ptr->port, ptr->weight,
+ ptr->type);
+ if (rv != NULL)
+ {
+ rv->cached_errno= ptr->cached_errno;
+ if (ptr->cached_server_error)
+ rv->cached_server_error= strdup(ptr->cached_server_error);
+ }
+
+ return rv;
+
+}
+
+memcached_return_t memcached_server_cursor(memcached_st *ptr,
+ memcached_server_fn *callback,
+ void *context,
+ uint32_t number_of_callbacks)
+{
+ unsigned int y;
+
+ for (y= 0; y < ptr->number_of_hosts; y++)
+ {
+ unsigned int x;
+
+ for (x= 0; x < number_of_callbacks; x++)
+ {
+ unsigned int iferror;
+
+ iferror= (*callback[x])(ptr, &ptr->hosts[y], context);
+
+ if (iferror)
+ continue;
+ }
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_server_st *memcached_server_by_key(memcached_st *ptr, const char *key, size_t key_length, memcached_return_t *error)
+{
+ uint32_t server_key;
+
+ *error= memcached_validate_key_length(key_length,
+ ptr->flags.binary_protocol);
+ unlikely (*error != MEMCACHED_SUCCESS)
+ return NULL;
+
+ unlikely (ptr->number_of_hosts == 0)
+ {
+ *error= MEMCACHED_NO_SERVERS;
+ return NULL;
+ }
+
+ if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+ {
+ *error= MEMCACHED_BAD_KEY_PROVIDED;
+ return NULL;
+ }
+
+ server_key= memcached_generate_hash(ptr, key, key_length);
+
+ return memcached_server_clone(NULL, &ptr->hosts[server_key]);
+
+}
+
+const char *memcached_server_error(memcached_server_st *ptr)
+{
+ if (ptr)
+ return ptr->cached_server_error;
+ else
+ return NULL;
+}
+
+void memcached_server_error_reset(memcached_server_st *ptr)
+{
+ ptr->cached_server_error[0]= 0;
+}
+
+memcached_server_st *memcached_server_get_last_disconnect(memcached_st *ptr)
+{
+ return ptr->last_disconnected_server;
+}
--- /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.
+ *
+ */
+
+#ifndef __MEMCACHED_SERVER_H__
+#define __MEMCACHED_SERVER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct memcached_server_st {
+ struct {
+ bool is_allocated:1;
+ } options;
+ bool sockaddr_inited;
+ uint16_t count;
+ uint32_t cursor_active;
+ in_port_t port;
+ int cached_errno;
+ int fd;
+ uint32_t io_bytes_sent; /* # bytes sent since last read */
+ uint32_t server_failure_counter;
+ uint32_t weight;
+ uint8_t major_version;
+ uint8_t micro_version;
+ uint8_t minor_version;
+ memcached_connection_t type;
+ char *read_ptr;
+ char *cached_server_error;
+ size_t read_buffer_length;
+ size_t read_data_length;
+ size_t write_buffer_offset;
+ struct addrinfo *address_info;
+ time_t next_retry;
+ memcached_st *root;
+ uint64_t limit_maxbytes;
+ char read_buffer[MEMCACHED_MAX_BUFFER];
+ char write_buffer[MEMCACHED_MAX_BUFFER];
+ char hostname[MEMCACHED_MAX_HOST_LENGTH];
+};
+
+#define memcached_server_count(A) (A)->number_of_hosts
+#define memcached_server_name(A,B) (B).hostname
+#define memcached_server_port(A,B) (B).port
+#define memcached_server_list(A) (A)->hosts
+#define memcached_server_response_count(A) (A)->cursor_active
+
+LIBMEMCACHED_API
+memcached_return_t memcached_server_cursor(memcached_st *ptr,
+ memcached_server_fn *callback,
+ void *context,
+ uint32_t number_of_callbacks);
+
+LIBMEMCACHED_API
+memcached_server_st *memcached_server_by_key(memcached_st *ptr, const char *key,
+ size_t key_length, memcached_return_t *error);
+
+LIBMEMCACHED_API
+const char *memcached_server_error(memcached_server_st *ptr);
+
+LIBMEMCACHED_API
+void memcached_server_error_reset(memcached_server_st *ptr);
+
+/* These should not currently be used by end users */
+/* TODO: Is the above comment valid? If so, how can we unit test these if they
+ * aren't exported. If not, we should remove the comment */
+LIBMEMCACHED_API
+memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr);
+
+LIBMEMCACHED_API
+memcached_server_st *memcached_server_create_with(memcached_st *memc, memcached_server_st *host,
+ const char *hostname, in_port_t port,
+ uint32_t weight, memcached_connection_t type);
+
+LIBMEMCACHED_API
+void memcached_server_free(memcached_server_st *ptr);
+LIBMEMCACHED_API
+memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr);
+LIBMEMCACHED_API
+memcached_analysis_st *memcached_analyze(memcached_st *memc, memcached_stat_st *memc_stat,
+ memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_server_remove(memcached_server_st *st_ptr);
+
+LIBMEMCACHED_API
+memcached_server_st *memcached_server_get_last_disconnect(memcached_st *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_SERVER_H__ */
--- /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
+};
+
+
+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))
+ {
+ WATCHPOINT_STRING(key);
+ return MEMCACHED_UNKNOWN_STAT_KEY;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+char *memcached_stat_get_value(memcached_st *ptr, memcached_stat_st *memc_stat,
+ const char *key, memcached_return_t *error)
+{
+ char buffer[SMALL_STRING_LEN];
+ int length;
+ char *ret;
+
+ *error= MEMCACHED_SUCCESS;
+
+ if (!memcmp("pid", key, strlen("pid")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pid);
+ else if (!memcmp("uptime", key, strlen("uptime")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->uptime);
+ else if (!memcmp("time", key, strlen("time")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time);
+ else if (!memcmp("version", key, strlen("version")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version);
+ else if (!memcmp("pointer_size", key, strlen("pointer_size")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pointer_size);
+ else if (!memcmp("rusage_user", key, strlen("rusage_user")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds);
+ else if (!memcmp("rusage_system", key, strlen("rusage_system")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds);
+ else if (!memcmp("curr_items", key, strlen("curr_items")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_items);
+ else if (!memcmp("total_items", key, strlen("total_items")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_items);
+ else if (!memcmp("curr_connections", key, strlen("curr_connections")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_connections);
+ else if (!memcmp("total_connections", key, strlen("total_connections")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_connections);
+ else if (!memcmp("connection_structures", key, strlen("connection_structures")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->connection_structures);
+ else if (!memcmp("cmd_get", key, strlen("cmd_get")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get);
+ else if (!memcmp("cmd_set", key, strlen("cmd_set")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set);
+ else if (!memcmp("get_hits", key, strlen("get_hits")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits);
+ else if (!memcmp("get_misses", key, strlen("get_misses")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses);
+ else if (!memcmp("evictions", key, strlen("evictions")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions);
+ else if (!memcmp("bytes_read", key, strlen("bytes_read")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read);
+ else if (!memcmp("bytes_written", key, strlen("bytes_written")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written);
+ else if (!memcmp("bytes", key, strlen("bytes")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes);
+ else if (!memcmp("limit_maxbytes", key, strlen("limit_maxbytes")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes);
+ else if (!memcmp("threads", key, strlen("threads")))
+ length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->threads);
+ else
+ {
+ *error= MEMCACHED_NOTFOUND;
+ return NULL;
+ }
+
+ ret= ptr->call_malloc(ptr, (size_t) (length + 1));
+ memcpy(ret, buffer, (size_t) length);
+ ret[length]= '\0';
+
+ return ret;
+}
+
+static memcached_return_t binary_stats_fetch(memcached_st *ptr,
+ memcached_stat_st *memc_stat,
+ char *args,
+ unsigned int server_key)
+{
+ memcached_return_t rc;
+
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ protocol_binary_request_stats request= {.bytes= {0}};
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+ if (args != NULL)
+ {
+ size_t len= strlen(args);
+
+ rc= memcached_validate_key_length(len, true);
+ unlikely (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ request.message.header.request.keylen= htons((uint16_t)len);
+ request.message.header.request.bodylen= htonl((uint32_t) len);
+
+ if ((memcached_do(&ptr->hosts[server_key], request.bytes,
+ sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
+ (memcached_io_write(&ptr->hosts[server_key], args, len, 1) == -1))
+ {
+ memcached_io_reset(&ptr->hosts[server_key]);
+ return MEMCACHED_WRITE_FAILURE;
+ }
+ }
+ else
+ {
+ if (memcached_do(&ptr->hosts[server_key], request.bytes,
+ sizeof(request.bytes), 1) != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(&ptr->hosts[server_key]);
+ return MEMCACHED_WRITE_FAILURE;
+ }
+ }
+
+ memcached_server_response_decrement(&ptr->hosts[server_key]);
+ do
+ {
+ rc= memcached_response(&ptr->hosts[server_key], buffer,
+ sizeof(buffer), NULL);
+ if (rc == MEMCACHED_END)
+ break;
+
+ unlikely (rc != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(&ptr->hosts[server_key]);
+ return rc;
+ }
+
+ unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
+ {
+ WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+ WATCHPOINT_ASSERT(0);
+ }
+ } while (1);
+
+ /* shit... memcached_response will decrement the counter, so I need to
+ ** reset it.. todo: look at this and try to find a better solution.
+ */
+ ptr->hosts[server_key].cursor_active= 0;
+
+ return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t ascii_stats_fetch(memcached_st *ptr,
+ memcached_stat_st *memc_stat,
+ char *args,
+ unsigned int server_key)
+{
+ memcached_return_t rc;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ size_t send_length;
+
+ if (args)
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "stats %s\r\n", args);
+ else
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "stats\r\n");
+
+ if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+ return MEMCACHED_WRITE_FAILURE;
+
+ rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
+ if (rc != MEMCACHED_SUCCESS)
+ goto error;
+
+ while (1)
+ {
+ rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+ if (rc == MEMCACHED_STAT)
+ {
+ char *string_ptr, *end_ptr;
+ char *key, *value;
+
+ string_ptr= buffer;
+ string_ptr+= 5; /* Move past STAT */
+ for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
+ key= string_ptr;
+ key[(size_t)(end_ptr-string_ptr)]= 0;
+
+ string_ptr= end_ptr + 1;
+ for (end_ptr= string_ptr; !(isspace(*end_ptr)); end_ptr++);
+ value= string_ptr;
+ value[(size_t)(end_ptr-string_ptr)]= 0;
+ string_ptr= end_ptr + 2;
+ unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY)
+ {
+ WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+ WATCHPOINT_ASSERT(0);
+ }
+ }
+ else
+ break;
+ }
+
+error:
+ if (rc == MEMCACHED_END)
+ return MEMCACHED_SUCCESS;
+ else
+ return rc;
+}
+
+memcached_stat_st *memcached_stat(memcached_st *ptr, char *args, memcached_return_t *error)
+{
+ unsigned int x;
+ memcached_return_t rc;
+ memcached_stat_st *stats;
+
+ unlikely (ptr->flags.use_udp)
+ {
+ *error= MEMCACHED_NOT_SUPPORTED;
+ return NULL;
+ }
+
+ stats= ptr->call_calloc(ptr, ptr->number_of_hosts, sizeof(memcached_stat_st));
+
+ if (!stats)
+ {
+ *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return NULL;
+ }
+
+ rc= MEMCACHED_SUCCESS;
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ memcached_return_t temp_return;
+
+ if (ptr->flags.binary_protocol)
+ temp_return= binary_stats_fetch(ptr, stats + x, args, x);
+ else
+ temp_return= ascii_stats_fetch(ptr, stats + x, args, x);
+
+ if (temp_return != MEMCACHED_SUCCESS)
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+
+ *error= rc;
+ return stats;
+}
+
+memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args,
+ const char *hostname, in_port_t port)
+{
+ memcached_return_t rc;
+ memcached_st memc;
+ memcached_st *memc_ptr;
+
+ memc_ptr= memcached_create(&memc);
+ WATCHPOINT_ASSERT(memc_ptr);
+
+ memcached_server_add(&memc, hostname, port);
+
+ if (memc.flags.binary_protocol)
+ rc= binary_stats_fetch(&memc, memc_stat, args, 0);
+ else
+ rc= ascii_stats_fetch(&memc, memc_stat, args, 0);
+
+ memcached_free(&memc);
+
+ return rc;
+}
+
+/*
+ We make a copy of the keys since at some point in the not so distant future
+ we will add support for "found" keys.
+*/
+char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *memc_stat,
+ memcached_return_t *error)
+{
+ (void) memc_stat;
+ char **list;
+ size_t length= sizeof(memcached_stat_keys);
+
+ list= ptr->call_malloc(ptr, length);
+
+ if (!list)
+ {
+ *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ return NULL;
+ }
+
+ memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys));
+
+ *error= MEMCACHED_SUCCESS;
+
+ return list;
+}
+
+void memcached_stat_free(memcached_st *ptr, memcached_stat_st *memc_stat)
+{
+ if (memc_stat == NULL)
+ {
+ WATCHPOINT_ASSERT(0); /* Be polite, but when debugging catch this as an error */
+ return;
+ }
+
+ if (ptr)
+ ptr->call_free(ptr, memc_stat);
+ else
+ free(memc_stat);
+}
--- /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,
+ const char *master_key,
+ size_t master_key_length,
+ const char *key,
+ size_t key_length,
+ const char *value,
+ size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas,
+ memcached_storage_action_t verb);
+
+static inline memcached_return_t memcached_send(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas,
+ memcached_storage_action_t verb)
+{
+ char to_write;
+ size_t write_length;
+ ssize_t sent_length;
+ memcached_return_t rc;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ unsigned int server_key;
+
+ WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));
+
+ rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
+ unlikely (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ unlikely (ptr->number_of_hosts == 0)
+ return MEMCACHED_NO_SERVERS;
+
+ if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+ return MEMCACHED_BAD_KEY_PROVIDED;
+
+ if (ptr->flags.binary_protocol)
+ {
+ return memcached_send_binary(ptr, master_key, master_key_length,
+ key, key_length,
+ value, value_length, expiration,
+ flags, cas, verb);
+ }
+
+ server_key= memcached_generate_hash(ptr, master_key, master_key_length);
+
+ if (cas)
+ {
+ write_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "%s %s%.*s %u %llu %zu %llu%s\r\n",
+ storage_op_string(verb),
+ ptr->prefix_key,
+ (int)key_length, key, flags,
+ (unsigned long long)expiration, value_length,
+ (unsigned long long)cas,
+ (ptr->flags.no_reply) ? " noreply" : "");
+ }
+ else
+ {
+ char *buffer_ptr= buffer;
+ const char *command= storage_op_string(verb);
+
+ /* Copy in the command, no space needed, we handle that in the command function*/
+ memcpy(buffer_ptr, command, strlen(command));
+
+ /* Copy in the key prefix, switch to the buffer_ptr */
+ buffer_ptr= memcpy(buffer_ptr + strlen(command) , ptr->prefix_key, strlen(ptr->prefix_key));
+
+ /* Copy in the key, adjust point if a key prefix was used. */
+ buffer_ptr= memcpy(buffer_ptr + (ptr->prefix_key ? strlen(ptr->prefix_key) : 0),
+ key, key_length);
+ buffer_ptr+= key_length;
+ buffer_ptr[0]= ' ';
+ buffer_ptr++;
+
+ write_length= (size_t)(buffer_ptr - buffer);
+ write_length+= (size_t) snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "%u %llu %zu%s\r\n",
+ flags,
+ (unsigned long long)expiration, value_length,
+ ptr->flags.no_reply ? " noreply" : "");
+ }
+
+ if (ptr->flags.use_udp && ptr->flags.buffer_requests)
+ {
+ size_t cmd_size= write_length + value_length + 2;
+ if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+ return MEMCACHED_WRITE_FAILURE;
+ if (cmd_size + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+ memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
+ }
+
+ if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+ {
+ rc= MEMCACHED_WRITE_FAILURE;
+ goto error;
+ }
+
+ /* Send command header */
+ rc= memcached_do(&ptr->hosts[server_key], buffer, write_length, 0);
+ if (rc != MEMCACHED_SUCCESS)
+ goto error;
+
+ /* Send command body */
+ if ((sent_length= memcached_io_write(&ptr->hosts[server_key], value, value_length, 0)) == -1)
+ {
+ rc= MEMCACHED_WRITE_FAILURE;
+ goto error;
+ }
+
+ if (ptr->flags.buffer_requests && verb == SET_OP)
+ {
+ to_write= 0;
+ }
+ else
+ {
+ to_write= 1;
+ }
+
+ if ((sent_length= memcached_io_write(&ptr->hosts[server_key], "\r\n", 2, to_write)) == -1)
+ {
+ rc= MEMCACHED_WRITE_FAILURE;
+ goto error;
+ }
+
+ if (ptr->flags.no_reply)
+ return (to_write == 0) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;
+
+ if (to_write == 0)
+ return MEMCACHED_BUFFERED;
+
+ rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+ if (rc == MEMCACHED_STORED)
+ return MEMCACHED_SUCCESS;
+ else
+ return rc;
+
+error:
+ memcached_io_reset(&ptr->hosts[server_key]);
+
+ return rc;
+}
+
+
+memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_SET_START();
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, SET_OP);
+ LIBMEMCACHED_MEMCACHED_SET_END();
+ return rc;
+}
+
+memcached_return_t memcached_add(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_ADD_START();
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, ADD_OP);
+ LIBMEMCACHED_MEMCACHED_ADD_END();
+ return rc;
+}
+
+memcached_return_t memcached_replace(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_REPLACE_START();
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, REPLACE_OP);
+ LIBMEMCACHED_MEMCACHED_REPLACE_END();
+ return rc;
+}
+
+memcached_return_t memcached_prepend(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, PREPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_append(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, APPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_cas(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, key, key_length,
+ key, key_length, value, value_length,
+ expiration, flags, cas, CAS_OP);
+ return rc;
+}
+
+memcached_return_t memcached_set_by_key(memcached_st *ptr,
+ const char *master_key __attribute__((unused)),
+ size_t master_key_length __attribute__((unused)),
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_SET_START();
+ rc= memcached_send(ptr, master_key, master_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, SET_OP);
+ LIBMEMCACHED_MEMCACHED_SET_END();
+ return rc;
+}
+
+memcached_return_t memcached_add_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_ADD_START();
+ rc= memcached_send(ptr, master_key, master_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, ADD_OP);
+ LIBMEMCACHED_MEMCACHED_ADD_END();
+ return rc;
+}
+
+memcached_return_t memcached_replace_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ LIBMEMCACHED_MEMCACHED_REPLACE_START();
+ rc= memcached_send(ptr, master_key, master_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, REPLACE_OP);
+ LIBMEMCACHED_MEMCACHED_REPLACE_END();
+ return rc;
+}
+
+memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, master_key, master_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, PREPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_append_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, master_key, master_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, 0, APPEND_OP);
+ return rc;
+}
+
+memcached_return_t memcached_cas_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas)
+{
+ memcached_return_t rc;
+ rc= memcached_send(ptr, master_key, master_key_length,
+ key, key_length, value, value_length,
+ expiration, flags, cas, CAS_OP);
+ return rc;
+}
+
+static inline uint8_t get_com_code(memcached_storage_action_t verb, bool noreply)
+{
+ /* 0 isn't a value we want, but GCC 4.2 seems to think ret can otherwise
+ * be used uninitialized in this function. FAIL */
+ uint8_t ret= 0;
+
+ if (noreply)
+ switch (verb)
+ {
+ case SET_OP:
+ ret=PROTOCOL_BINARY_CMD_SETQ;
+ break;
+ case ADD_OP:
+ ret=PROTOCOL_BINARY_CMD_ADDQ;
+ break;
+ case CAS_OP: /* FALLTHROUGH */
+ case REPLACE_OP:
+ ret=PROTOCOL_BINARY_CMD_REPLACEQ;
+ break;
+ case APPEND_OP:
+ ret=PROTOCOL_BINARY_CMD_APPENDQ;
+ break;
+ case PREPEND_OP:
+ ret=PROTOCOL_BINARY_CMD_PREPENDQ;
+ break;
+ default:
+ WATCHPOINT_ASSERT(verb);
+ break;
+ }
+ else
+ switch (verb)
+ {
+ case SET_OP:
+ ret=PROTOCOL_BINARY_CMD_SET;
+ break;
+ case ADD_OP:
+ ret=PROTOCOL_BINARY_CMD_ADD;
+ break;
+ case CAS_OP: /* FALLTHROUGH */
+ case REPLACE_OP:
+ ret=PROTOCOL_BINARY_CMD_REPLACE;
+ break;
+ case APPEND_OP:
+ ret=PROTOCOL_BINARY_CMD_APPEND;
+ break;
+ case PREPEND_OP:
+ ret=PROTOCOL_BINARY_CMD_PREPEND;
+ break;
+ default:
+ WATCHPOINT_ASSERT(verb);
+ break;
+ }
+
+ return ret;
+}
+
+
+
+static memcached_return_t memcached_send_binary(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char *key,
+ size_t key_length,
+ const char *value,
+ size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas,
+ memcached_storage_action_t verb)
+{
+ uint8_t flush;
+ protocol_binary_request_set request= {.bytes= {0}};
+ size_t send_length= sizeof(request.bytes);
+ uint32_t server_key= memcached_generate_hash(ptr, master_key,
+ master_key_length);
+ memcached_server_st *server= &ptr->hosts[server_key];
+ bool noreply= server->root->flags.no_reply;
+
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= get_com_code(verb, noreply);
+ request.message.header.request.keylen= htons((uint16_t)key_length);
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+ if (verb == APPEND_OP || verb == PREPEND_OP)
+ send_length -= 8; /* append & prepend does not contain extras! */
+ else
+ {
+ request.message.header.request.extlen= 8;
+ request.message.body.flags= htonl(flags);
+ request.message.body.expiration= htonl((uint32_t)expiration);
+ }
+
+ request.message.header.request.bodylen= htonl((uint32_t) (key_length + value_length +
+ request.message.header.request.extlen));
+
+ if (cas)
+ request.message.header.request.cas= htonll(cas);
+
+ flush= (uint8_t) ((server->root->flags.buffer_requests && verb == SET_OP) ? 0 : 1);
+
+ if (server->root->flags.use_udp && !flush)
+ {
+ size_t cmd_size= send_length + key_length + value_length;
+
+ if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+ return MEMCACHED_WRITE_FAILURE;
+ if (cmd_size + server->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+ memcached_io_write(server,NULL,0, 1);
+ }
+
+ /* write the header */
+ if ((memcached_do(server, (const char*)request.bytes, send_length, 0) != MEMCACHED_SUCCESS) ||
+ (memcached_io_write(server, key, key_length, 0) == -1) ||
+ (memcached_io_write(server, value, value_length, (char) flush) == -1))
+ {
+ memcached_io_reset(server);
+ return MEMCACHED_WRITE_FAILURE;
+ }
+
+ unlikely (verb == SET_OP && ptr->number_of_replicas > 0)
+ {
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
+
+ for (uint32_t x= 0; x < ptr->number_of_replicas; x++)
+ {
+ ++server_key;
+ if (server_key == ptr->number_of_hosts)
+ server_key= 0;
+
+ memcached_server_st *srv= &ptr->hosts[server_key];
+ if ((memcached_do(srv, (const char*)request.bytes,
+ send_length, 0) != MEMCACHED_SUCCESS) ||
+ (memcached_io_write(srv, key, key_length, 0) == -1) ||
+ (memcached_io_write(srv, value, value_length, (char) flush) == -1))
+ memcached_io_reset(srv);
+ else
+ memcached_server_response_decrement(srv);
+ }
+ }
+
+ if (flush == 0)
+ return MEMCACHED_BUFFERED;
+
+ if (noreply)
+ return MEMCACHED_SUCCESS;
+
+ return memcached_response(server, NULL, 0, NULL);
+}
+
--- /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,..
+ *
+ */
+
+#ifndef __MEMCACHED_STORAGE_H__
+#define __MEMCACHED_STORAGE_H__
+
+#include "libmemcached/memcached.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* All of the functions for adding data to the server */
+LIBMEMCACHED_API
+memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+LIBMEMCACHED_API
+memcached_return_t memcached_add(memcached_st *ptr, const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+LIBMEMCACHED_API
+memcached_return_t memcached_replace(memcached_st *ptr, const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+LIBMEMCACHED_API
+memcached_return_t memcached_append(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+LIBMEMCACHED_API
+memcached_return_t memcached_prepend(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+LIBMEMCACHED_API
+memcached_return_t memcached_cas(memcached_st *ptr,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_set_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_add_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_replace_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_append_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_cas_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ const char *value, size_t value_length,
+ time_t expiration,
+ uint32_t flags,
+ uint64_t cas);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_STORAGE_H__ */
--- /dev/null
+#include "common.h"
+
+const char *memcached_strerror(memcached_st *ptr __attribute__((unused)), memcached_return_t rc)
+{
+ switch (rc)
+ {
+ case MEMCACHED_SUCCESS:
+ return "SUCCESS";
+ case MEMCACHED_FAILURE:
+ return "FAILURE";
+ case MEMCACHED_HOST_LOOKUP_FAILURE:
+ return "HOSTNAME LOOKUP FAILURE";
+ case MEMCACHED_CONNECTION_FAILURE:
+ return "CONNECTION FAILURE";
+ case MEMCACHED_CONNECTION_BIND_FAILURE:
+ return "CONNECTION BIND FAILURE";
+ case MEMCACHED_READ_FAILURE:
+ return "READ FAILURE";
+ case MEMCACHED_UNKNOWN_READ_FAILURE:
+ return "UNKNOWN READ FAILURE";
+ case MEMCACHED_PROTOCOL_ERROR:
+ return "PROTOCOL ERROR";
+ case MEMCACHED_CLIENT_ERROR:
+ return "CLIENT ERROR";
+ case MEMCACHED_SERVER_ERROR:
+ return "SERVER ERROR";
+ case MEMCACHED_WRITE_FAILURE:
+ return "WRITE FAILURE";
+ case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE:
+ return "CONNECTION SOCKET CREATE FAILURE";
+ case MEMCACHED_DATA_EXISTS:
+ return "CONNECTION DATA EXISTS";
+ case MEMCACHED_DATA_DOES_NOT_EXIST:
+ return "CONNECTION DATA DOES NOT EXIST";
+ case MEMCACHED_NOTSTORED:
+ return "NOT STORED";
+ case MEMCACHED_STORED:
+ return "STORED";
+ case MEMCACHED_NOTFOUND:
+ return "NOT FOUND";
+ case MEMCACHED_MEMORY_ALLOCATION_FAILURE:
+ return "MEMORY ALLOCATION FAILURE";
+ case MEMCACHED_PARTIAL_READ:
+ return "PARTIAL READ";
+ case MEMCACHED_SOME_ERRORS:
+ return "SOME ERRORS WERE REPORTED";
+ case MEMCACHED_NO_SERVERS:
+ return "NO SERVERS DEFINED";
+ case MEMCACHED_END:
+ return "SERVER END";
+ case MEMCACHED_DELETED:
+ return "SERVER DELETE";
+ case MEMCACHED_VALUE:
+ return "SERVER VALUE";
+ case MEMCACHED_STAT:
+ return "STAT VALUE";
+ case MEMCACHED_ITEM:
+ return "ITEM VALUE";
+ case MEMCACHED_ERRNO:
+ return "SYSTEM ERROR";
+ case MEMCACHED_FAIL_UNIX_SOCKET:
+ return "COULD NOT OPEN UNIX SOCKET";
+ case MEMCACHED_NOT_SUPPORTED:
+ return "ACTION NOT SUPPORTED";
+ case MEMCACHED_FETCH_NOTFINISHED:
+ return "FETCH WAS NOT COMPLETED";
+ case MEMCACHED_NO_KEY_PROVIDED:
+ return "A KEY LENGTH OF ZERO WAS PROVIDED";
+ case MEMCACHED_BUFFERED:
+ return "ACTION QUEUED";
+ case MEMCACHED_TIMEOUT:
+ return "A TIMEOUT OCCURRED";
+ case MEMCACHED_BAD_KEY_PROVIDED:
+ return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE";
+ case MEMCACHED_INVALID_HOST_PROTOCOL:
+ return "THE HOST TRANSPORT PROTOCOL DOES NOT MATCH THAT OF THE CLIENT";
+ case MEMCACHED_SERVER_MARKED_DEAD:
+ return "SERVER IS MARKED DEAD";
+ case MEMCACHED_UNKNOWN_STAT_KEY:
+ return "ENCOUNTERED AN UNKNOWN STAT KEY";
+ case MEMCACHED_E2BIG:
+ return "ITEM TOO BIG";
+ case MEMCACHED_INVALID_ARGUMENTS:
+ return "INVALID ARGUMENTS";
+ case MEMCACHED_MAXIMUM_RETURN:
+ return "Gibberish returned!";
+ default:
+ return "Gibberish returned!";
+ }
+}
--- /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))) / string->block_size;
+ adjust++;
+
+ new_size= sizeof(char) * (size_t)((adjust * string->block_size) + string->current_size);
+ /* Test for overflow */
+ if (new_size < need)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ new_value= string->root->call_realloc(string->root, string->string, new_size);
+
+ if (new_value == NULL)
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ string->string= new_value;
+ string->end= string->string + current_offset;
+
+ string->current_size+= (string->block_size * adjust);
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_string_st *memcached_string_create(memcached_st *memc, memcached_string_st *string, size_t initial_size)
+{
+ memcached_return_t rc;
+
+ /* Saving malloc calls :) */
+ if (string)
+ {
+ WATCHPOINT_ASSERT(memc->options.is_safe && string->options.is_initialized == false);
+
+ memset(string, 0, sizeof(memcached_string_st));
+ }
+ else
+ {
+ string= memc->call_calloc(memc, 1, sizeof(memcached_string_st));
+
+ if (string == NULL)
+ {
+ return NULL;
+ }
+
+ string->options.is_allocated= true;
+ }
+ string->block_size= MEMCACHED_BLOCK_SIZE;
+ string->root= memc;
+
+ rc= _string_check(string, initial_size);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ memc->call_free(memc, string);
+ return NULL;
+ }
+
+ string->options.is_initialized= true;
+
+ WATCHPOINT_ASSERT(string->string == string->end);
+
+ return string;
+}
+
+memcached_return_t memcached_string_append_character(memcached_string_st *string,
+ char character)
+{
+ memcached_return_t rc;
+
+ rc= _string_check(string, 1);
+
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ *string->end= character;
+ string->end++;
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_string_append(memcached_string_st *string,
+ const char *value, size_t length)
+{
+ memcached_return_t rc;
+
+ rc= _string_check(string, length);
+
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ WATCHPOINT_ASSERT(length <= string->current_size);
+ WATCHPOINT_ASSERT(string->string);
+ WATCHPOINT_ASSERT(string->end >= string->string);
+
+ memcpy(string->end, value, length);
+ string->end+= length;
+
+ return MEMCACHED_SUCCESS;
+}
+
+char *memcached_string_c_copy(memcached_string_st *string)
+{
+ char *c_ptr;
+
+ if (memcached_string_length(string) == 0)
+ return NULL;
+
+ c_ptr= string->root->call_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char));
+
+ if (c_ptr == NULL)
+ return NULL;
+
+ memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string));
+ c_ptr[memcached_string_length(string)]= 0;
+
+ return c_ptr;
+}
+
+memcached_return_t memcached_string_reset(memcached_string_st *string)
+{
+ string->end= string->string;
+
+ return MEMCACHED_SUCCESS;
+}
+
+void memcached_string_free(memcached_string_st *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ if (ptr->string)
+ {
+ ptr->root->call_free(ptr->root, ptr->string);
+ }
+
+ if (memcached_is_allocated(ptr))
+ {
+ ptr->root->call_free(ptr->root, ptr);
+ }
+ else
+ {
+ ptr->options.is_initialized= false;
+ memset(ptr, 0, sizeof(memcached_string_st));
+ }
+}
+
+memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
+{
+ return _string_check(string, need);
+}
+
--- /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.
+ *
+ */
+
+#ifndef __MEMCACHED_STRING_H__
+#define __MEMCACHED_STRING_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct memcached_string_st {
+ memcached_st *root;
+ char *end;
+ char *string;
+ size_t current_size;
+ size_t block_size;
+ struct {
+ bool is_allocated:1;
+ bool is_initialized:1;
+ } options;
+};
+
+#define memcached_string_length(A) (size_t)((A)->end - (A)->string)
+#define memcached_string_set_length(A, B) (A)->end= (A)->string + B
+#define memcached_string_size(A) (A)->current_size
+#define memcached_string_value(A) (A)->string
+
+LIBMEMCACHED_API
+memcached_string_st *memcached_string_create(memcached_st *ptr,
+ memcached_string_st *string,
+ size_t initial_size);
+LIBMEMCACHED_API
+memcached_return_t memcached_string_check(memcached_string_st *string, size_t need);
+
+LIBMEMCACHED_API
+char *memcached_string_c_copy(memcached_string_st *string);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_string_append_character(memcached_string_st *string,
+ char character);
+LIBMEMCACHED_API
+memcached_return_t memcached_string_append(memcached_string_st *string,
+ const char *value, size_t length);
+LIBMEMCACHED_API
+memcached_return_t memcached_string_reset(memcached_string_st *string);
+
+LIBMEMCACHED_API
+void memcached_string_free(memcached_string_st *string);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_STRING_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: Types for libmemcached
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_TYPES_H
+#define LIBMEMCACHED_MEMCACHED_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct memcached_st memcached_st;
+typedef struct memcached_stat_st memcached_stat_st;
+typedef struct memcached_analysis_st memcached_analysis_st;
+typedef struct memcached_result_st memcached_result_st;
+typedef struct memcached_string_st memcached_string_st;
+typedef struct memcached_server_st memcached_server_st;
+typedef struct memcached_continuum_item_st memcached_continuum_item_st;
+typedef memcached_return_t (*memcached_clone_fn)(memcached_st *parent, memcached_st *clone);
+typedef memcached_return_t (*memcached_cleanup_fn)(memcached_st *ptr);
+typedef void (*memcached_free_fn)(memcached_st *ptr, void *mem);
+typedef void *(*memcached_malloc_fn)(memcached_st *ptr, const size_t size);
+typedef void *(*memcached_realloc_fn)(memcached_st *ptr, void *mem, const size_t size);
+typedef void *(*memcached_calloc_fn)(memcached_st *ptr, size_t nelem, const size_t elsize);
+typedef memcached_return_t (*memcached_execute_fn)(memcached_st *ptr, memcached_result_st *result, void *context);
+typedef memcached_return_t (*memcached_server_fn)(memcached_st *ptr, memcached_server_st *server, void *context);
+typedef memcached_return_t (*memcached_trigger_key_fn)(memcached_st *ptr,
+ const char *key, size_t key_length,
+ memcached_result_st *result);
+typedef memcached_return_t (*memcached_trigger_delete_key_fn)(memcached_st *ptr,
+ const char *key, size_t key_length);
+
+typedef memcached_return_t (*memcached_dump_fn)(memcached_st *ptr,
+ const char *key, size_t key_length, void *context);
+
+typedef struct {
+ memcached_execute_fn *callback;
+ void *context;
+ uint32_t number_of_callback;
+} memcached_callback_st;
+
+
+/**
+ @note The following definitions are just here for backwards compatibility.
+*/
+typedef memcached_return_t memcached_return;
+typedef memcached_server_distribution_t memcached_server_distribution;
+typedef memcached_behavior_t memcached_behavior;
+typedef memcached_callback_t memcached_callback;
+typedef memcached_hash_t memcached_hash;
+typedef memcached_connection_t memcached_connection;
+typedef memcached_clone_fn memcached_clone_func;
+typedef memcached_cleanup_fn memcached_cleanup_func;
+typedef memcached_free_fn memcached_free_function;
+typedef memcached_malloc_fn memcached_malloc_function;
+typedef memcached_realloc_fn memcached_realloc_function;
+typedef memcached_calloc_fn memcached_calloc_function;
+typedef memcached_execute_fn memcached_execute_function;
+typedef memcached_server_fn memcached_server_function;
+typedef memcached_trigger_key_fn memcached_trigger_key;
+typedef memcached_trigger_delete_key_fn memcached_trigger_delete_key;
+typedef memcached_dump_fn memcached_dump_func;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBMEMCACHED_MEMCACHED_TYPES_H */
+++ /dev/null
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_pool.h"
-
-#include <errno.h>
-#include <pthread.h>
-
-struct memcached_pool_st
-{
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- memcached_st *master;
- memcached_st **mmc;
- int firstfree;
- uint32_t size;
- uint32_t current_size;
- char *version;
-};
-
-static memcached_return_t mutex_enter(pthread_mutex_t *mutex)
-{
- int ret;
- do
- ret= pthread_mutex_lock(mutex);
- while (ret == -1 && errno == EINTR);
-
- return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t mutex_exit(pthread_mutex_t *mutex) {
- int ret;
- do
- ret= pthread_mutex_unlock(mutex);
- while (ret == -1 && errno == EINTR);
-
- return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
-}
-
-/**
- * Grow the connection pool by creating a connection structure and clone the
- * original memcached handle.
- */
-static int grow_pool(memcached_pool_st* pool) {
- memcached_st *obj= calloc(1, sizeof(*obj));
- if (obj == NULL)
- return -1;
-
- if (memcached_clone(obj, pool->master) == NULL)
- {
- free(obj);
- return -1;
- }
-
- pool->mmc[++pool->firstfree] = obj;
- pool->current_size++;
-
- return 0;
-}
-
-memcached_pool_st *memcached_pool_create(memcached_st* mmc,
- uint32_t initial, uint32_t max)
-{
- memcached_pool_st* ret = NULL;
- memcached_pool_st object = { .mutex = PTHREAD_MUTEX_INITIALIZER,
- .cond = PTHREAD_COND_INITIALIZER,
- .master = mmc,
- .mmc = calloc(max, sizeof(memcached_st*)),
- .firstfree = -1,
- .size = max,
- .current_size = 0 };
-
- if (object.mmc != NULL)
- {
- ret= calloc(1, sizeof(*ret));
- if (ret == NULL)
- {
- free(object.mmc);
- return NULL;
- }
-
- *ret = object;
-
- /* Try to create the initial size of the pool. An allocation failure at
- * this time is not fatal..
- */
- for (unsigned int ii=0; ii < initial; ++ii)
- if (grow_pool(ret) == -1)
- break;
- }
-
- return ret;
-}
-
-memcached_st* memcached_pool_destroy(memcached_pool_st* pool)
-{
- memcached_st *ret = pool->master;
-
- for (int xx= 0; xx <= pool->firstfree; ++xx)
- {
- memcached_free(pool->mmc[xx]);
- free(pool->mmc[xx]);
- pool->mmc[xx] = NULL;
- }
-
- pthread_mutex_destroy(&pool->mutex);
- pthread_cond_destroy(&pool->cond);
- free(pool->mmc);
- free(pool);
-
- return ret;
-}
-
-memcached_st* memcached_pool_pop(memcached_pool_st* pool,
- bool block,
- memcached_return_t *rc)
-{
- memcached_st *ret= NULL;
- if ((*rc= mutex_enter(&pool->mutex)) != MEMCACHED_SUCCESS)
- return NULL;
-
- do
- {
- if (pool->firstfree > -1)
- ret= pool->mmc[pool->firstfree--];
- else if (pool->current_size == pool->size)
- {
- if (!block)
- {
- *rc= mutex_exit(&pool->mutex);
- return NULL;
- }
-
- if (pthread_cond_wait(&pool->cond, &pool->mutex) == -1)
- {
- int err = errno;
- mutex_exit(&pool->mutex);
- errno = err;
- *rc= MEMCACHED_ERRNO;
- return NULL;
- }
- }
- else if (grow_pool(pool) == -1)
- {
- *rc= mutex_exit(&pool->mutex);
- return NULL;
- }
- }
- while (ret == NULL);
-
- *rc= mutex_exit(&pool->mutex);
-
- return ret;
-}
-
-memcached_return_t memcached_pool_push(memcached_pool_st* pool,
- memcached_st *mmc)
-{
- memcached_return_t rc= mutex_enter(&pool->mutex);
-
- if (rc != MEMCACHED_SUCCESS)
- return rc;
-
- char* version = memcached_get_user_data(mmc);
- /* Someone updated the behavior on the object.. */
- if (version != pool->version)
- {
- memcached_free(mmc);
- memset(mmc, 0, sizeof(*mmc));
- if (memcached_clone(mmc, pool->master) == NULL)
- {
- rc= MEMCACHED_SOME_ERRORS;
- }
- }
-
- pool->mmc[++pool->firstfree]= mmc;
-
- if (pool->firstfree == 0 && pool->current_size == pool->size)
- {
- /* we might have people waiting for a connection.. wake them up :-) */
- pthread_cond_broadcast(&pool->cond);
- }
-
- memcached_return_t rval= mutex_exit(&pool->mutex);
- if (rc == MEMCACHED_SOME_ERRORS)
- return rc;
-
- return rval;
-}
-
-
-memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool,
- memcached_behavior_t flag,
- uint64_t data)
-{
-
- memcached_return_t rc= mutex_enter(&pool->mutex);
- if (rc != MEMCACHED_SUCCESS)
- return rc;
-
- /* update the master */
- rc= memcached_behavior_set(pool->master, flag, data);
- if (rc != MEMCACHED_SUCCESS)
- {
- mutex_exit(&pool->mutex);
- return rc;
- }
-
- ++pool->version;
- memcached_set_user_data(pool->master, pool->version);
- /* update the clones */
- for (int xx= 0; xx <= pool->firstfree; ++xx)
- {
- rc= memcached_behavior_set(pool->mmc[xx], flag, data);
- if (rc == MEMCACHED_SUCCESS)
- memcached_set_user_data(pool->mmc[xx], pool->version);
- else
- {
- memcached_free(pool->mmc[xx]);
- memset(pool->mmc[xx], 0, sizeof(*pool->mmc[xx]));
- if (memcached_clone(pool->mmc[xx], pool->master) == NULL)
- {
- /* I'm not sure what to do in this case.. this would happen
- if we fail to push the server list inside the client..
- I should add a testcase for this, but I believe the following
- would work, except that you would add a hole in the pool list..
- in theory you could end up with an empty pool....
- */
- free(pool->mmc[xx]);
- pool->mmc[xx]= NULL;
- }
- }
- }
-
- return mutex_exit(&pool->mutex);
-}
-
-memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool,
- memcached_behavior_t flag,
- uint64_t *value)
-{
- memcached_return_t rc= mutex_enter(&pool->mutex);
- if (rc != MEMCACHED_SUCCESS)
- return rc;
- *value= memcached_behavior_get(pool->master, flag);
- return mutex_exit(&pool->mutex);
-}
--- /dev/null
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+#include "libmemcached/common.h"
+#include "libmemcached/pool.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+struct memcached_pool_st
+{
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ memcached_st *master;
+ memcached_st **mmc;
+ int firstfree;
+ uint32_t size;
+ uint32_t current_size;
+ char *version;
+};
+
+static memcached_return_t mutex_enter(pthread_mutex_t *mutex)
+{
+ int ret;
+ do
+ ret= pthread_mutex_lock(mutex);
+ while (ret == -1 && errno == EINTR);
+
+ return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t mutex_exit(pthread_mutex_t *mutex)
+{
+ int ret;
+ do
+ ret= pthread_mutex_unlock(mutex);
+ while (ret == -1 && errno == EINTR);
+
+ return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
+}
+
+/**
+ * Grow the connection pool by creating a connection structure and clone the
+ * original memcached handle.
+ */
+static int grow_pool(memcached_pool_st* pool)
+{
+ memcached_st *obj= calloc(1, sizeof(*obj));
+
+ if (obj == NULL)
+ return -1;
+
+ if (memcached_clone(obj, pool->master) == NULL)
+ {
+ free(obj);
+ return -1;
+ }
+
+ pool->mmc[++pool->firstfree] = obj;
+ pool->current_size++;
+
+ return 0;
+}
+
+memcached_pool_st *memcached_pool_create(memcached_st* mmc,
+ uint32_t initial, uint32_t max)
+{
+ memcached_pool_st* ret = NULL;
+ memcached_pool_st object = { .mutex = PTHREAD_MUTEX_INITIALIZER,
+ .cond = PTHREAD_COND_INITIALIZER,
+ .master = mmc,
+ .mmc = calloc(max, sizeof(memcached_st*)),
+ .firstfree = -1,
+ .size = max,
+ .current_size = 0 };
+
+ if (object.mmc != NULL)
+ {
+ ret= calloc(1, sizeof(*ret));
+ if (ret == NULL)
+ {
+ free(object.mmc);
+ return NULL;
+ }
+
+ *ret = object;
+
+ /*
+ Try to create the initial size of the pool. An allocation failure at
+ this time is not fatal..
+ */
+ for (unsigned int ii= 0; ii < initial; ++ii)
+ {
+ if (grow_pool(ret) == -1)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+memcached_st* memcached_pool_destroy(memcached_pool_st* pool)
+{
+ memcached_st *ret = pool->master;
+
+ for (int xx= 0; xx <= pool->firstfree; ++xx)
+ {
+ memcached_free(pool->mmc[xx]);
+ free(pool->mmc[xx]);
+ pool->mmc[xx] = NULL;
+ }
+
+ pthread_mutex_destroy(&pool->mutex);
+ pthread_cond_destroy(&pool->cond);
+ free(pool->mmc);
+ free(pool);
+
+ return ret;
+}
+
+memcached_st* memcached_pool_pop(memcached_pool_st* pool,
+ bool block,
+ memcached_return_t *rc)
+{
+ memcached_st *ret= NULL;
+ if ((*rc= mutex_enter(&pool->mutex)) != MEMCACHED_SUCCESS)
+ return NULL;
+
+ do
+ {
+ if (pool->firstfree > -1)
+ ret= pool->mmc[pool->firstfree--];
+ else if (pool->current_size == pool->size)
+ {
+ if (!block)
+ {
+ *rc= mutex_exit(&pool->mutex);
+ return NULL;
+ }
+
+ if (pthread_cond_wait(&pool->cond, &pool->mutex) == -1)
+ {
+ int err = errno;
+ mutex_exit(&pool->mutex);
+ errno = err;
+ *rc= MEMCACHED_ERRNO;
+ return NULL;
+ }
+ }
+ else if (grow_pool(pool) == -1)
+ {
+ *rc= mutex_exit(&pool->mutex);
+ return NULL;
+ }
+ }
+ while (ret == NULL);
+
+ *rc= mutex_exit(&pool->mutex);
+
+ return ret;
+}
+
+memcached_return_t memcached_pool_push(memcached_pool_st* pool,
+ memcached_st *mmc)
+{
+ memcached_return_t rc= mutex_enter(&pool->mutex);
+
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ char* version= memcached_get_user_data(mmc);
+ /* Someone updated the behavior on the object.. */
+ if (version != pool->version)
+ {
+ memcached_free(mmc);
+ memset(mmc, 0, sizeof(*mmc));
+ if (memcached_clone(mmc, pool->master) == NULL)
+ {
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+ }
+
+ pool->mmc[++pool->firstfree]= mmc;
+
+ if (pool->firstfree == 0 && pool->current_size == pool->size)
+ {
+ /* we might have people waiting for a connection.. wake them up :-) */
+ pthread_cond_broadcast(&pool->cond);
+ }
+
+ memcached_return_t rval= mutex_exit(&pool->mutex);
+ if (rc == MEMCACHED_SOME_ERRORS)
+ return rc;
+
+ return rval;
+}
+
+
+memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool,
+ memcached_behavior_t flag,
+ uint64_t data)
+{
+
+ memcached_return_t rc= mutex_enter(&pool->mutex);
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ /* update the master */
+ rc= memcached_behavior_set(pool->master, flag, data);
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ mutex_exit(&pool->mutex);
+ return rc;
+ }
+
+ ++pool->version;
+ memcached_set_user_data(pool->master, pool->version);
+ /* update the clones */
+ for (int xx= 0; xx <= pool->firstfree; ++xx)
+ {
+ rc= memcached_behavior_set(pool->mmc[xx], flag, data);
+ if (rc == MEMCACHED_SUCCESS)
+ memcached_set_user_data(pool->mmc[xx], pool->version);
+ else
+ {
+ memcached_free(pool->mmc[xx]);
+ memset(pool->mmc[xx], 0, sizeof(*pool->mmc[xx]));
+ if (memcached_clone(pool->mmc[xx], pool->master) == NULL)
+ {
+ /* I'm not sure what to do in this case.. this would happen
+ if we fail to push the server list inside the client..
+ I should add a testcase for this, but I believe the following
+ would work, except that you would add a hole in the pool list..
+ in theory you could end up with an empty pool....
+ */
+ free(pool->mmc[xx]);
+ pool->mmc[xx]= NULL;
+ }
+ }
+ }
+
+ return mutex_exit(&pool->mutex);
+}
+
+memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool,
+ memcached_behavior_t flag,
+ uint64_t *value)
+{
+ memcached_return_t rc= mutex_enter(&pool->mutex);
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ return rc;
+ }
+
+ *value= memcached_behavior_get(pool->master, flag);
+
+ return mutex_exit(&pool->mutex);
+}
--- /dev/null
+#include "common.h"
+
+memcached_return_t memcached_verbosity(memcached_st *ptr, unsigned int verbosity)
+{
+ unsigned int x;
+ size_t send_length;
+ memcached_return_t rc;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+ send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+ "verbosity %u\r\n", verbosity);
+ unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+ return MEMCACHED_WRITE_FAILURE;
+
+ rc= MEMCACHED_SUCCESS;
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ memcached_return_t rrc;
+
+ rrc= memcached_do(&ptr->hosts[x], buffer, send_length, 1);
+ if (rrc != MEMCACHED_SUCCESS)
+ {
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+
+ unlikely (ptr->flags.use_udp)
+ continue;
+
+ rrc= memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+ if (rrc != MEMCACHED_SUCCESS)
+ rc= MEMCACHED_SOME_ERRORS;
+ }
+
+ return rc;
+}
--- /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;
+
+ if (ptr->flags.binary_protocol)
+ return memcached_version_binary(ptr);
+ else
+ return memcached_version_textual(ptr);
+}
+
+static inline memcached_return_t memcached_version_textual(memcached_st *ptr)
+{
+ unsigned int x;
+ size_t send_length;
+ memcached_return_t rc;
+ char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+ char *response_ptr;
+ const char *command= "version\r\n";
+
+ send_length= strlen(command);
+
+ rc= MEMCACHED_SUCCESS;
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ memcached_return_t rrc;
+
+ rrc= memcached_do(&ptr->hosts[x], command, send_length, 1);
+ if (rrc != MEMCACHED_SUCCESS)
+ {
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+
+ rrc= memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+ if (rrc != MEMCACHED_SUCCESS)
+ {
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+
+ /* Find the space, and then move one past it to copy version */
+ response_ptr= index(buffer, ' ');
+ response_ptr++;
+
+ ptr->hosts[x].major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+ response_ptr= index(response_ptr, '.');
+ response_ptr++;
+ ptr->hosts[x].minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+ response_ptr= index(response_ptr, '.');
+ response_ptr++;
+ ptr->hosts[x].micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+ }
+
+ return rc;
+}
+
+static inline memcached_return_t memcached_version_binary(memcached_st *ptr)
+{
+ memcached_return_t rc;
+ unsigned int x;
+ protocol_binary_request_version request= { .bytes= {0}};
+ request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+ request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
+ request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+ rc= MEMCACHED_SUCCESS;
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ {
+ memcached_return_t rrc;
+
+ rrc= memcached_do(&ptr->hosts[x], request.bytes, sizeof(request.bytes), 1);
+ if (rrc != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(&ptr->hosts[x]);
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+ }
+
+ for (x= 0; x < ptr->number_of_hosts; x++)
+ if (memcached_server_response_count(&ptr->hosts[x]) > 0)
+ {
+ memcached_return_t rrc;
+ char buffer[32];
+ char *p;
+
+ rrc= memcached_response(&ptr->hosts[x], buffer, sizeof(buffer), NULL);
+ if (rrc != MEMCACHED_SUCCESS)
+ {
+ memcached_io_reset(&ptr->hosts[x]);
+ rc= MEMCACHED_SOME_ERRORS;
+ continue;
+ }
+
+ ptr->hosts[x].major_version= (uint8_t)strtol(buffer, &p, 10);
+ ptr->hosts[x].minor_version= (uint8_t)strtol(p + 1, &p, 10);
+ ptr->hosts[x].micro_version= (uint8_t)strtol(p + 1, NULL, 10);
+ }
+
+ return rc;
+}
--- /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: Localized copy of WATCHPOINT debug symbols
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_WATCHPOINT_H
+#define LIBMEMCACHED_MEMCACHED_WATCHPOINT_H
+
+/* Some personal debugging functions */
+#if defined(DEBUG)
+
+#include <assert.h>
+
+#define WATCHPOINT fprintf(stderr, "\nWATCHPOINT %s:%d (%s)\n", __FILE__, __LINE__,__func__);fflush(stdout);
+#define WATCHPOINT_ERROR(A) fprintf(stderr, "\nWATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout);
+#define WATCHPOINT_IFERROR(A) if(A != MEMCACHED_SUCCESS)fprintf(stderr, "\nWATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout);
+#define WATCHPOINT_STRING(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__,A);fflush(stdout);
+#define WATCHPOINT_STRING_LENGTH(A,B) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %.*s\n", __FILE__, __LINE__,__func__,(int)B,A);fflush(stdout);
+#define WATCHPOINT_NUMBER(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %zu\n", __FILE__, __LINE__,__func__,(size_t)(A));fflush(stdout);
+#define WATCHPOINT_ERRNO(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__, strerror(A));fflush(stdout);
+#define WATCHPOINT_ASSERT_PRINT(A,B,C) if(!(A)){fprintf(stderr, "\nWATCHPOINT ASSERT %s:%d (%s) ", __FILE__, __LINE__,__func__);fprintf(stderr, (B),(C));fprintf(stderr,"\n");fflush(stdout);}assert((A));
+#define WATCHPOINT_ASSERT(A) assert((A));
+#define WATCHPOINT_ASSERT_INITIALIZED(A) (memcached_is_initialized((A));
+
+#else
+
+#define WATCHPOINT
+#define WATCHPOINT_ERROR(A)
+#define WATCHPOINT_IFERROR(A)
+#define WATCHPOINT_STRING(A)
+#define WATCHPOINT_NUMBER(A)
+#define WATCHPOINT_ERRNO(A)
+#define WATCHPOINT_ASSERT_PRINT(A,B,C)
+#define WATCHPOINT_ASSERT(A)
+#define WATCHPOINT_ASSERT_INITIALIZED(A)
+
+#endif /* DEBUG */
+
+#endif /* LIBMEMCACHED_MEMCACHED_WATCHPOINT_H */