*.exe
*.lo
*.pop
+*.rpm
*/*.l[oa]
*/*/*.l[oa]
*/*/.deps
config/missing
config/pandora_vc_revinfo
config/plugin.ac
+config/top.h
configure
docs/*.[13]
docs/*.html
libmemcached.pop
libmemcached/configure.h
libmemcached/dtrace_probes.h
+libmemcached/generated_probes.h
libmemcached/memcached_configure.h
+libmemcached/options/parser.cc
+libmemcached/options/parser.h
+libmemcached/options/parser.output
+libmemcached/options/parsers.cc
+libmemcached/options/parsers.h
+libmemcached/options/parsers.output
+libmemcached/options/scanner.cc
+libmemcached/options/scanner.h
libmemcached_examples.pop
libmemcachedutil.pop
libtool
tests/testplus
tests/testudp
unittests/unittests
-config/top.h
-libmemcached/generated_probes.h
+clients/memparse
+0.49
+ * Fix calls to auto methods so that if value is not passed in nothing bad happens.
+ * New parser calls for generating memcached_st objects.
+ * New error system.
+
0.48 Tue Mar 15 23:05:18 PDT 2011
* Fix memory leak in server parse.
* Move test framework out to be its own library (easier to work with Gearman).
check_PROGRAMS =
EXTRA_HEADERS =
BUILT_SOURCES=
+DISTCLEANFILES=
EXTRA_DIST= \
${srcdir}/m4/pandora_*.m4 \
.quickly \
clients/memdump \
clients/memerror \
clients/memflush \
+ clients/memparse \
clients/memrm \
clients/memstat
clients_memcat_SOURCES= clients/memcat.c
clients_memcat_LDADD= $(CLIENTS_LDADDS)
+clients_memparse_SOURCES= clients/memparse.cc
+clients_memparse_LDADD= $(CLIENTS_LDADDS)
+
clients_memcp_SOURCES= clients/memcp.c
clients_memcp_LDADD= $(CLIENTS_LDADDS)
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <iostream>
+
+#include <libmemcached/memcached.h>
+
+int main(int argc, char *argv[])
+{
+
+ if (argc < 2)
+ {
+ std::cerr << "No arguments provided." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ for (int x= 1; x < argc; x++)
+ {
+ char buffer[BUFSIZ];
+ memcached_return_t rc;
+ rc= libmemcached_check_configuration(argv[x], strlen(argv[x]), buffer, sizeof(buffer));
+
+ if (rc != MEMCACHED_SUCCESS)
+ {
+ std::cerr << "Failed to parse argument #" << x << " " << argv[x] << std::endl;
+ std::cerr << "Error message from parser was:\t" << buffer << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
#!/usr/bin/env bash
-# libmemcached
+# LibmemcacheD
+# Copyright (C) 2011 Data Differential, http://datadifferential.com/
# Copyright (C) 2006-2010 Brian Aker, Monty Taylor, Trond Norbye
# All rights reserved.
#
AC_CONFIG_AUX_DIR(config)
PANDORA_CANONICAL_TARGET(no-vc-changelog)
+AC_CHECK_PROGS([YACC], ['bison'], [:])
+AC_CHECK_PROGS([LEX], ['flex'], [:])
#shared library versioning
MEMCACHED_UTIL_LIBRARY_VERSION=1:0:0
AC_SUBST(MEMCACHED_LIBRARY_VERSION)
-HASHKIT_LIBRARY_VERSION=0:0:0
+HASHKIT_LIBRARY_VERSION=1:0:0
AC_SUBST(HASHKIT_LIBRARY_VERSION)
AH_TOP([
LIBS=
PANDORA_REQUIRE_PTHREAD
LIBS="$my_saved_libs"
-PANDORA_CXX_DEMANGLE
dnl Specialty checks
DETECT_BYTEORDER
self->function= hashkit_jenkins;
break;
case HASHKIT_HASH_CUSTOM:
+ return HASHKIT_INVALID_ARGUMENT;
case HASHKIT_HASH_MAX:
default:
- return HASHKIT_FAILURE;
+ return HASHKIT_INVALID_HASH;
}
self->context= NULL;
(void)ptr;
switch (rc)
{
- case HASHKIT_SUCCESS:
- return "SUCCESS";
- case HASHKIT_FAILURE:
- return "FAILURE";
- case HASHKIT_MEMORY_ALLOCATION_FAILURE:
- return "MEMORY ALLOCATION FAILURE";
+ case HASHKIT_SUCCESS: return "SUCCESS";
+ case HASHKIT_FAILURE: return "FAILURE";
+ case HASHKIT_MEMORY_ALLOCATION_FAILURE: return "MEMORY ALLOCATION FAILURE";
+ case HASHKIT_INVALID_ARGUMENT: return "INVALID ARGUMENT";
+ case HASHKIT_INVALID_HASH: return "INVALID hashkit_hash_algorithm_t";
case HASHKIT_MAXIMUM_RETURN:
- return "Gibberish returned!";
default:
- return "Gibberish returned!";
+ return "INVALID hashkit_return_t";
}
}
HASHKIT_SUCCESS,
HASHKIT_FAILURE,
HASHKIT_MEMORY_ALLOCATION_FAILURE,
+ HASHKIT_INVALID_HASH,
+ HASHKIT_INVALID_ARGUMENT,
HASHKIT_MAXIMUM_RETURN /* Always add new error code before */
} hashkit_return_t;
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libmemcached/common.h"
+
+struct memcached_array_st
+{
+ memcached_st *root;
+ size_t size;
+ char c_str[];
+};
+
+memcached_array_st *memcached_array_clone(memcached_st *memc, const memcached_array_st *original)
+{
+ if (! original)
+ return NULL;
+
+ return memcached_strcpy(memc, original->c_str, original->size);
+}
+
+memcached_array_st *memcached_strcpy(memcached_st *memc, const char *str, size_t str_length)
+{
+ memcached_array_st *array= (struct memcached_array_st *)libmemcached_malloc(memc, sizeof(struct memcached_array_st) +str_length +1);
+
+ if (! array)
+ return NULL;
+
+ array->root= memc;
+ array->size= str_length -1; // We don't count the NULL ending
+ memcpy(array->c_str, str, str_length);
+ array->c_str[str_length]= 0;
+
+ return array;
+}
+
+memcached_string_t memcached_array_to_string(memcached_array_st *array)
+{
+ memcached_string_t tmp;
+ tmp.c_str= array->c_str;
+ tmp.size= array->size;
+
+ return tmp;
+}
+
+void memcached_array_free(memcached_array_st *array)
+{
+ if (! array)
+ return;
+
+ WATCHPOINT_ASSERT(array->root);
+ if (array && array->root)
+ {
+ libmemcached_free(array->root, array);
+ }
+ else if (array)
+ {
+ free(array);
+ }
+}
+
+size_t memcached_array_size(memcached_array_st *array)
+{
+ if (! array)
+ return 0;
+
+ return array->size;
+}
+
+const char *memcached_array_string(memcached_array_st *array)
+{
+ if (! array)
+ return NULL;
+
+ return array->c_str;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_LOCAL
+memcached_array_st *memcached_array_clone(memcached_st *memc, const memcached_array_st *original);
+
+LIBMEMCACHED_LOCAL
+memcached_array_st *memcached_strcpy(memcached_st *memc, const char *str, size_t str_length);
+
+LIBMEMCACHED_LOCAL
+void memcached_array_free(memcached_array_st *array);
+
+LIBMEMCACHED_LOCAL
+size_t memcached_array_size(memcached_array_st *array);
+
+LIBMEMCACHED_LOCAL
+const char *memcached_array_string(memcached_array_st *array);
+
+LIBMEMCACHED_LOCAL
+memcached_string_t memcached_array_to_string(memcached_array_st *array);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#ifdef __cplusplus
+#define memcached_print_array(X) static_cast<int>(memcached_array_size(X)), memcached_array_string(X)
+#define memcached_param_array(X) memcached_array_string(X), memcached_array_size(X)
+#else
+#define memcached_print_array(X) (int)memcached_array_size((X)), memcached_array_string((X))
+#define memcached_param_array(X) memcached_array_string(X), memcached_array_size(X)
+#endif
*
*/
-#include "common.h"
+#include "libmemcached/common.h"
static memcached_return_t text_incr_decr(memcached_st *ptr,
const char *verb,
memcached_server_write_instance_st instance;
bool no_reply= ptr->flags.no_reply;
- unlikely (memcached_server_count(ptr) == 0)
- return MEMCACHED_NO_SERVERS;
+ if (memcached_server_count(ptr) == 0)
+ return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL);
if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
return MEMCACHED_BAD_KEY_PROVIDED;
int send_length;
send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
"%s %.*s%.*s %" PRIu64 "%s\r\n", verb,
- (int)ptr->prefix_key_length,
- ptr->prefix_key,
+ memcached_print_array(ptr->prefix_key),
(int)key_length, key,
offset, no_reply ? " noreply" : "");
if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
memcached_server_write_instance_st instance;
bool no_reply= ptr->flags.no_reply;
- unlikely (memcached_server_count(ptr) == 0)
- return MEMCACHED_NO_SERVERS;
+ if (memcached_server_count(ptr) == 0)
+ return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL);
server_key= memcached_generate_hash_with_redistribution(ptr, master_key, master_key_length);
instance= memcached_server_instance_fetch(ptr, server_key);
request.message.header.request.magic= PROTOCOL_BINARY_REQ;
request.message.header.request.opcode= cmd;
- request.message.header.request.keylen= htons((uint16_t)(key_length + ptr->prefix_key_length));
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
request.message.header.request.extlen= 20;
request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)(key_length + ptr->prefix_key_length + request.message.header.request.extlen));
+ request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key) +request.message.header.request.extlen));
request.message.body.delta= htonll(offset);
request.message.body.initial= htonll(initial);
request.message.body.expiration= htonl((uint32_t) expiration);
struct libmemcached_io_vector_st vector[]=
{
{ .length= sizeof(request.bytes), .buffer= request.bytes },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= ptr->prefix_key },
{ .length= key_length, .buffer= key }
};
uint32_t offset,
uint64_t *value)
{
+ uint64_t local_value;
+ if (! value)
+ value= &local_value;
+
return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
}
uint32_t offset,
uint64_t *value)
{
+ uint64_t local_value;
+ if (! value)
+ value= &local_value;
+
return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
}
unlikely (rc != MEMCACHED_SUCCESS)
return rc;
+ uint64_t local_value;
+ if (! value)
+ value= &local_value;
+
LIBMEMCACHED_MEMCACHED_INCREMENT_START();
if (ptr->flags.binary_protocol)
{
unlikely (rc != MEMCACHED_SUCCESS)
return rc;
+ uint64_t local_value;
+ if (! value)
+ value= &local_value;
+
LIBMEMCACHED_MEMCACHED_DECREMENT_START();
if (ptr->flags.binary_protocol)
{
time_t expiration,
uint64_t *value)
{
+ uint64_t local_value;
+ if (! value)
+ value= &local_value;
+
return memcached_increment_with_initial_by_key(ptr, key, key_length,
key, key_length,
offset, initial, expiration, value);
unlikely (rc != MEMCACHED_SUCCESS)
return rc;
+ uint64_t local_value;
+ if (! value)
+ value= &local_value;
+
LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
if (ptr->flags.binary_protocol)
rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
time_t expiration,
uint64_t *value)
{
+ uint64_t local_value;
+ if (! value)
+ value= &local_value;
+
return memcached_decrement_with_initial_by_key(ptr, key, key_length,
key, key_length,
offset, initial, expiration, value);
unlikely (rc != MEMCACHED_SUCCESS)
return rc;
+ uint64_t local_value;
+ if (! value)
+ value= &local_value;
+
LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
if (ptr->flags.binary_protocol)
{
#endif
LIBMEMCACHED_API
-memcached_return_t memcached_increment(memcached_st *ptr,
- const char *key, size_t key_length,
- uint32_t offset,
- uint64_t *value);
+ memcached_return_t memcached_increment(memcached_st *ptr,
+ const char *key, size_t key_length,
+ uint32_t offset,
+ uint64_t *value);
LIBMEMCACHED_API
-memcached_return_t memcached_decrement(memcached_st *ptr,
- const char *key, size_t key_length,
- uint32_t offset,
- uint64_t *value);
+ memcached_return_t memcached_decrement(memcached_st *ptr,
+ const char *key, size_t key_length,
+ uint32_t offset,
+ uint64_t *value);
LIBMEMCACHED_API
-memcached_return_t memcached_increment_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- uint64_t offset,
- uint64_t *value);
+ memcached_return_t memcached_increment_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ uint64_t offset,
+ uint64_t *value);
LIBMEMCACHED_API
-memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
- const char *master_key, size_t master_key_length,
- const char *key, size_t key_length,
- uint64_t offset,
- uint64_t *value);
+ memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
+ const char *master_key, size_t master_key_length,
+ const char *key, size_t key_length,
+ uint64_t offset,
+ uint64_t *value);
LIBMEMCACHED_API
-memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value);
+ memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value);
+
LIBMEMCACHED_API
-memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value);
+ memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value);
+
LIBMEMCACHED_API
-memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value);
+ memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value);
+
LIBMEMCACHED_API
-memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
- const char *master_key,
- size_t master_key_length,
- const char *key,
- size_t key_length,
- uint64_t offset,
- uint64_t initial,
- time_t expiration,
- uint64_t *value);
+ memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
+ const char *master_key,
+ size_t master_key_length,
+ const char *key,
+ size_t key_length,
+ uint64_t offset,
+ uint64_t initial,
+ time_t expiration,
+ uint64_t *value);
#ifdef __cplusplus
}
break;
case MEMCACHED_BEHAVIOR_VERIFY_KEY:
if (ptr->flags.binary_protocol)
- return MEMCACHED_FAILURE;
+ return memcached_set_error_string(ptr, MEMCACHED_FAILURE,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled."));
ptr->flags.verify_key= set_flag(data);
break;
case MEMCACHED_BEHAVIOR_SORT_HOSTS:
memcached_quit(ptr);
break;
case MEMCACHED_BEHAVIOR_USER_DATA:
- return MEMCACHED_FAILURE;
+ return memcached_set_error_string(ptr, MEMCACHED_FAILURE,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
ptr->flags.hash_with_prefix_key= set_flag(data);
break;
break;
case MEM_NOT:
default:
- return MEMCACHED_NOT_SUPPORTED;
+ return memcached_set_error_string(ptr, MEMCACHED_NOT_SUPPORTED,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_CORK is not supported on this platform."));
}
}
break;
+ case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()"));
case MEMCACHED_BEHAVIOR_MAX:
default:
/* Shouldn't get here */
WATCHPOINT_ASSERT(0);
- return MEMCACHED_FAILURE;
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("Invalid behavior passed to memcached_behavior_set()"));
}
return MEMCACHED_SUCCESS;
return (uint64_t) sock_size;
}
case MEMCACHED_BEHAVIOR_USER_DATA:
- return MEMCACHED_FAILURE;
+ return memcached_set_error_string(ptr, MEMCACHED_FAILURE,
+ memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
return ptr->flags.hash_with_prefix_key;
case MEMCACHED_BEHAVIOR_NOREPLY:
return ptr->flags.cork;
case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
return ptr->flags.tcp_keepalive;
+ case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
+ return ptr->configure.filename ? true : false;
case MEMCACHED_BEHAVIOR_MAX:
default:
WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */
{
ptr->distribution= type;
run_distribution(ptr);
- }
- else
- {
- return MEMCACHED_FAILURE;
+ return MEMCACHED_SUCCESS;
}
- return MEMCACHED_SUCCESS;
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("Invalid memcached_server_distribution_t"));
}
memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type)
{
- hashkit_return_t rc;
- rc= hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type);
+ if (hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
+ return MEMCACHED_SUCCESS;
- return rc == HASHKIT_SUCCESS ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("Invalid memcached_hash_t()"));
}
memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr)
memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type)
{
- hashkit_return_t rc;
- rc= hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type);
+ if (hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
+ return MEMCACHED_SUCCESS;
- return rc == HASHKIT_SUCCESS ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+ return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+ memcached_string_with_size("Invalid memcached_hash_t()"));
}
memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr)
{
return (memcached_hash_t)hashkit_get_function(&ptr->distribution_hashkit);
}
+
+const char *libmemcached_string_behavior(const memcached_behavior_t flag)
+{
+ switch (flag)
+ {
+ case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK";
+ case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY";
+ case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH";
+ case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA";
+ case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE";
+ case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE";
+ case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS";
+ case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS";
+ case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION";
+ case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS";
+ case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA";
+ case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS";
+ case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY";
+ case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED";
+ case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH";
+ case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL";
+ case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT";
+ case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT";
+ case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK";
+ case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK";
+ case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH";
+ case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY";
+ case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY";
+ case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP";
+ case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS";
+ case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS";
+ case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ";
+ case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK";
+ case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE";
+ case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE";
+ case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE";
+ default:
+ case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t";
+ }
+}
+
+const char *libmemcached_string_distribution(const memcached_server_distribution_t flag)
+{
+ switch (flag)
+ {
+ case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA";
+ case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM";
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY";
+ default:
+ case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t";
+ }
+}
LIBMEMCACHED_LOCAL
bool _is_auto_eject_host(const memcached_st *ptr);
+LIBMEMCACHED_LOCAL
+ const char *libmemcached_string_behavior(const memcached_behavior_t flag);
+
+LIBMEMCACHED_LOCAL
+ const char *libmemcached_string_distribution(const memcached_server_distribution_t flag);
#ifdef __cplusplus
}
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;
- }
+ return memcached_set_error(ptr, MEMCACHED_BAD_KEY_PROVIDED, NULL);
- if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1)
- || (strncpy(ptr->prefix_key, key, MEMCACHED_PREFIX_KEY_MAX_SIZE) == NULL))
- {
- ptr->prefix_key_length= 0;
- return MEMCACHED_BAD_KEY_PROVIDED;
- }
- else
- {
- ptr->prefix_key_length= key_length;
- }
+ if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1))
+ return memcached_set_error(ptr, MEMCACHED_KEY_TOO_BIG, NULL);
+
+ memcached_array_free(ptr->prefix_key);
+ ptr->prefix_key= memcached_strcpy(ptr, (const char *)data, strlen((const char*)data));
+
+ if (! ptr->prefix_key)
+ return memcached_set_error(ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, NULL);
}
else
{
- ptr->prefix_key[0]= 0;
- ptr->prefix_key_length= 0;
+ memcached_array_free(ptr->prefix_key);
+ ptr->prefix_key= NULL;
}
break;
{
case MEMCACHED_CALLBACK_PREFIX_KEY:
{
- if (ptr->prefix_key_length)
+ if (ptr->prefix_key)
{
*error= MEMCACHED_SUCCESS;
- return (void *)ptr->prefix_key;
+ return (void *)memcached_array_string(ptr->prefix_key);
}
else
{
#ifndef __LIBMEMCACHED_COMMON_H__
#define __LIBMEMCACHED_COMMON_H__
-#include "config.h"
+#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include "libmemcached/memcached.h"
#include "libmemcached/watchpoint.h"
+#include "libmemcached/is.h"
typedef struct memcached_server_st * memcached_server_write_instance_st;
#include "libmemcached/io.h"
#include "libmemcached/do.h"
#include "libmemcached/internal.h"
+#include "libmemcached/array.h"
#include "libmemcached/libmemcached_probes.h"
#include "libmemcached/memcached/protocol_binary.h"
#include "libmemcached/byteorder.h"
#define memcached_server_response_decrement(A) (A)->cursor_active--
#define memcached_server_response_reset(A) (A)->cursor_active=0
-// These are private
-#define memcached_is_allocated(__object) ((__object)->options.is_allocated)
-#define memcached_is_initialized(__object) ((__object)->options.is_initialized)
-#define memcached_is_purging(__object) ((__object)->state.is_purging)
-#define memcached_is_processing_input(__object) ((__object)->state.is_processing_input)
-#define memcached_set_purging(__object, __value) ((__object)->state.is_purging= (__value))
-#define memcached_set_processing_input(__object, __value) ((__object)->state.is_processing_input= (__value))
-#define memcached_set_initialized(__object, __value) ((__object)->options.is_initialized(= (__value))
-#define memcached_set_allocated(__object, __value) ((__object)->options.is_allocated(= (__value))
-
LIBMEMCACHED_LOCAL
void set_last_disconnected_host(memcached_server_write_instance_st ptr);
*
*/
+#pragma once
#ifndef __LIBMEMCACHED_CONSTANTS_H__
#define __LIBMEMCACHED_CONSTANTS_H__
MEMCACHED_AUTH_PROBLEM,
MEMCACHED_AUTH_FAILURE,
MEMCACHED_AUTH_CONTINUE,
+ MEMCACHED_PARSE_ERROR,
+ MEMCACHED_PARSE_USER_ERROR,
MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */
} memcached_return_t;
MEMCACHED_BEHAVIOR_CORK,
MEMCACHED_BEHAVIOR_TCP_KEEPALIVE,
MEMCACHED_BEHAVIOR_TCP_KEEPIDLE,
+ MEMCACHED_BEHAVIOR_LOAD_FROM_FILE,
MEMCACHED_BEHAVIOR_MAX
} memcached_behavior_t;
}
send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
"delete %.*s%.*s %u%s\r\n",
- (int)ptr->prefix_key_length,
- ptr->prefix_key,
+ memcached_print_array(ptr->prefix_key),
(int) key_length, key,
(uint32_t)expiration,
no_reply ? " noreply" :"" );
{
send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
"delete %.*s%.*s%s\r\n",
- (int)ptr->prefix_key_length,
- ptr->prefix_key,
+ memcached_print_array(ptr->prefix_key),
(int)key_length, key, no_reply ? " noreply" :"");
}
request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
else
request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
- request.message.header.request.keylen= htons((uint16_t)(key_length + ptr->prefix_key_length));
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)(key_length + ptr->prefix_key_length));
+ request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key)));
if (ptr->flags.use_udp && ! flush)
{
struct libmemcached_io_vector_st vector[]=
{
{ .length= sizeof(request.bytes), .buffer= request.bytes},
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length, .buffer= key },
};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "libmemcached/common.h"
+
+struct memcached_error_st
+{
+ memcached_st *root;
+ struct memcached_error_st *next;
+ memcached_return_t rc;
+ int local_errno;
+ size_t size;
+ char c_str[];
+};
+
+static memcached_error_st *_set(memcached_st *memc, memcached_string_t *str)
+{
+ if (! memc)
+ return NULL;
+
+ memcached_error_st *error;
+ error= (struct memcached_error_st *)libmemcached_malloc(memc, sizeof(struct memcached_error_st) +(str ? str->size :0) +1);
+
+ if (! error)
+ return NULL;
+
+ error->root= memc;
+
+ if (str)
+ {
+ error->size= str->size;
+ memcpy(error->c_str, str->c_str, str->size);
+ error->c_str[str->size]= 0;
+ }
+ else
+ {
+ error->size= 0;
+ }
+
+ error->next= memc->error_messages;
+ memc->error_messages= error;
+
+ return error;
+}
+
+memcached_return_t memcached_set_error_string(memcached_st *memc, memcached_return_t rc, const char *str, size_t length)
+{
+ memcached_string_t tmp;
+ tmp.c_str= str;
+ tmp.size= length;
+ return memcached_set_error(memc, rc, &tmp);
+}
+
+memcached_return_t memcached_set_error(memcached_st *memc, memcached_return_t rc, memcached_string_t *str)
+{
+ if (rc == MEMCACHED_SUCCESS)
+ return MEMCACHED_SUCCESS;
+
+ memcached_error_st *error= _set(memc, str);
+
+ if (error)
+ {
+ error->local_errno= 0;
+ error->rc= rc;
+ }
+
+ return rc;
+}
+
+memcached_return_t memcached_set_errno(memcached_st *memc, int local_errno, memcached_string_t *str)
+{
+ memcached_error_st *error= _set(memc, str);
+
+ if (error)
+ {
+ error->local_errno= local_errno;
+ error->rc= MEMCACHED_ERRNO;
+ }
+
+ return error->rc;
+}
+
+static void _error_print(const memcached_error_st *error)
+{
+ if (! error)
+ return;
+
+ if (! error->size)
+ {
+ fprintf(stderr, "%s\n", memcached_strerror(NULL, error->rc) );
+ }
+ else
+ {
+ fprintf(stderr, "%s %s\n", memcached_strerror(NULL, error->rc), error->c_str);
+ }
+
+ _error_print(error->next);
+}
+
+void memcached_error_print(const memcached_st *self)
+{
+ if (! self)
+ return;
+
+ _error_print(self->error_messages);
+}
+
+static void _error_free(memcached_error_st *error)
+{
+ if (! error)
+ return;
+
+ _error_free(error->next);
+
+ if (error && error->root)
+ {
+ libmemcached_free(error->root, error);
+ }
+ else if (error)
+ {
+ free(error);
+ }
+}
+
+void memcached_error_free(memcached_st *self)
+{
+ if (! self)
+ return;
+
+ _error_free(self->error_messages);
+}
+
+const char *memcached_last_error_message(memcached_st *memc)
+{
+ if (! memc)
+ return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS);
+
+ if (! memc->error_messages)
+ return memcached_strerror(memc, MEMCACHED_SUCCESS);
+
+ if (! memc->error_messages->size)
+ {
+ return memcached_strerror(memc, memc->error_messages->rc);
+ }
+
+ return memc->error_messages->c_str;
+}
+
+memcached_return_t memcached_last_error(memcached_st *memc)
+{
+ if (! memc)
+ return MEMCACHED_INVALID_ARGUMENTS;
+
+ if (! memc->error_messages)
+ return MEMCACHED_SUCCESS;
+
+ return memc->error_messages->rc;
+}
+
+memcached_return_t memcached_last_error_errno(memcached_st *memc)
+{
+ if (! memc)
+ return MEMCACHED_INVALID_ARGUMENTS;
+
+ if (! memc->error_messages)
+ return MEMCACHED_SUCCESS;
+
+ return memc->error_messages->local_errno;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_LOCAL
+ memcached_return_t memcached_set_error(memcached_st *memc, memcached_return_t rc, memcached_string_t *str);
+
+LIBMEMCACHED_LOCAL
+ memcached_return_t memcached_set_error_string(memcached_st *memc, memcached_return_t rc, const char *str, size_t length);
+
+LIBMEMCACHED_LOCAL
+ memcached_return_t memcached_set_errno(memcached_st *memc, int local_errno, memcached_string_t *str);
+
+LIBMEMCACHED_LOCAL
+ void memcached_error_free(memcached_st *error);
+
+LIBMEMCACHED_API
+ const char *memcached_last_error_message(memcached_st *memc);
+
+LIBMEMCACHED_API
+ void memcached_error_print(const memcached_st *self);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_last_error(memcached_st *memc);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_last_error_errno(memcached_st *memc);
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
struct libmemcached_io_vector_st vector[]=
{
{ .length= get_command_length, .buffer= get_command },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length[x], .buffer= keys[x] },
{ .length= 1, .buffer= " " }
};
return vk;
}
- request.message.header.request.keylen= htons((uint16_t)(key_length[x] + ptr->prefix_key_length));
+ request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key)));
request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
- request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + ptr->prefix_key_length));
+ request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->prefix_key)));
struct libmemcached_io_vector_st vector[]=
{
{ .length= sizeof(request.bytes), .buffer= request.bytes },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length[x], .buffer= keys[x] }
};
.message.header.request= {
.magic= PROTOCOL_BINARY_REQ,
.opcode= PROTOCOL_BINARY_CMD_GETK,
- .keylen= htons((uint16_t)(key_length[x] + ptr->prefix_key_length)),
+ .keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key))),
.datatype= PROTOCOL_BINARY_RAW_BYTES,
- .bodylen= htonl((uint32_t)(key_length[x] + ptr->prefix_key_length))
+ .bodylen= htonl((uint32_t)(key_length[x] + memcached_array_size(ptr->prefix_key)))
}
};
struct libmemcached_io_vector_st vector[]=
{
{ .length= sizeof(request.bytes), .buffer= request.bytes },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length[x], .buffer= keys[x] }
};
if (ptr->flags.hash_with_prefix_key)
{
- size_t temp_length= ptr->prefix_key_length + key_length;
+ size_t temp_length= memcached_array_size(ptr->prefix_key) + key_length;
char temp[temp_length];
if (temp_length > MEMCACHED_MAX_KEY -1)
return 0;
- strncpy(temp, ptr->prefix_key, ptr->prefix_key_length);
- strncpy(temp + ptr->prefix_key_length, key, key_length);
+ strncpy(temp, memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
+ strncpy(temp + memcached_array_size(ptr->prefix_key), key, key_length);
return generate_hash(ptr, temp, temp_length);
}
return MEMCACHED_SUCCESS;
}
+
+const char * libmemcached_string_hash(memcached_hash_t type)
+{
+ switch (type)
+ {
+ case MEMCACHED_HASH_DEFAULT: return "MEMCACHED_HASH_DEFAULT";
+ case MEMCACHED_HASH_MD5: return "MEMCACHED_HASH_MD5";
+ case MEMCACHED_HASH_CRC: return "MEMCACHED_HASH_CRC";
+ case MEMCACHED_HASH_FNV1_64: return "MEMCACHED_HASH_FNV1_64";
+ case MEMCACHED_HASH_FNV1A_64: return "MEMCACHED_HASH_FNV1A_64";
+ case MEMCACHED_HASH_FNV1_32: return "MEMCACHED_HASH_FNV1_32";
+ case MEMCACHED_HASH_FNV1A_32: return "MEMCACHED_HASH_FNV1A_32";
+ case MEMCACHED_HASH_HSIEH: return "MEMCACHED_HASH_HSIEH";
+ case MEMCACHED_HASH_MURMUR: return "MEMCACHED_HASH_MURMUR";
+ case MEMCACHED_HASH_JENKINS: return "MEMCACHED_HASH_JENKINS";
+ case MEMCACHED_HASH_CUSTOM: return "MEMCACHED_HASH_CUSTOM";
+ default:
+ case MEMCACHED_HASH_MAX: return "INVALID memcached_hash_t";
+ }
+}
LIBMEMCACHED_API
void memcached_autoeject(memcached_st *ptr);
+LIBMEMCACHED_API
+ const char * libmemcached_string_hash(memcached_hash_t type);
+
#ifdef __cplusplus
}
#endif
in_port_t port,
uint32_t weight,
memcached_connection_t type);
+
static memcached_return_t update_continuum(memcached_st *ptr);
static int compare_servers(const void *p1, const void *p2)
return run_distribution(ptr);
}
+
+memcached_return_t memcached_server_add_parsed(memcached_st *ptr,
+ const char *hostname,
+ size_t hostname_length,
+ in_port_t port,
+ uint32_t weight)
+{
+ char buffer[NI_MAXHOST];
+
+ memcpy(buffer, hostname, hostname_length);
+ buffer[hostname_length]= 0;
+
+ return server_add(ptr, buffer,
+ port,
+ weight,
+ MEMCACHED_CONNECTION_TCP);
+}
# included from Top Level Makefile.am
# All paths should be given relative to the root
+libmemcached_libmemcached_la_SOURCES =
+
+include libmemcached/options/include.am
+
EXTRA_DIST+= \
libmemcached/configure.h.in \
libmemcached/libmemcached_probes.d \
libmemcached/do.h \
libmemcached/internal.h \
libmemcached/io.h \
+ libmemcached/is.h \
libmemcached/libmemcached_probes.h \
libmemcached/protocol/ascii_handler.h \
libmemcached/protocol/binary_handler.h \
nobase_include_HEADERS+= \
libmemcached/allocators.h \
libmemcached/analyze.h \
+ libmemcached/array.h \
libmemcached/auto.h \
libmemcached/behavior.h \
libmemcached/callback.h \
libmemcached/constants.h \
libmemcached/delete.h \
libmemcached/dump.h \
+ libmemcached/error.h \
libmemcached/exception.hpp \
libmemcached/fetch.h \
libmemcached/flush.h \
libmemcached/memcached.h \
libmemcached/memcached.hpp \
libmemcached/memcached/protocol_binary.h \
+ libmemcached/options.h \
libmemcached/parse.h \
libmemcached/platform.h \
libmemcached/protocol/cache.h \
lib_LTLIBRARIES+= libmemcached/libmemcached.la
libmemcached_libmemcached_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION}
-libmemcached_libmemcached_la_SOURCES = \
+libmemcached_libmemcached_la_SOURCES+= \
libmemcached/allocators.c \
libmemcached/analyze.c \
+ libmemcached/array.c \
libmemcached/auto.c \
libmemcached/behavior.c \
libmemcached/connect.c \
libmemcached/delete.c \
libmemcached/do.c \
libmemcached/dump.c \
+ libmemcached/error.c \
libmemcached/fetch.c \
libmemcached/flush.c \
libmemcached/flush_buffers.c \
libmemcached/io.c \
libmemcached/key.c \
libmemcached/memcached.c \
+ libmemcached/options.cc \
libmemcached/parse.c \
libmemcached/purge.c \
libmemcached/quit.c \
libmemcached/verbosity.c \
libmemcached/version.c
+libmemcached/options.cc: libmemcached/options/parser.h
+
libmemcached_libmemcached_la_DEPENDENCIES= libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la libhashkit/libhashkitinc.la
libmemcached_libmemcached_la_LIBADD= $(LIBM) libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la libhashkit/libhashkitinc.la
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * LibMemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+/* These are private */
+#define memcached_is_allocated(__object) ((__object)->options.is_allocated)
+#define memcached_is_initialized(__object) ((__object)->options.is_initialized)
+#define memcached_is_purging(__object) ((__object)->state.is_purging)
+#define memcached_is_processing_input(__object) ((__object)->state.is_processing_input)
+#define memcached_set_purging(__object, __value) ((__object)->state.is_purging= (__value))
+#define memcached_set_processing_input(__object, __value) ((__object)->state.is_processing_input= (__value))
+#define memcached_set_initialized(__object, __value) ((__object)->options.is_initialized(= (__value))
+#define memcached_set_allocated(__object, __value) ((__object)->options.is_allocated= (__value))
.use_sort_hosts= false,
.use_udp= false,
.verify_key= false,
- .tcp_keepalive= false
+ .tcp_keepalive= false,
+ .ping_service= false
}
};
self->user_data= NULL;
self->next_distribution_rebuild= 0;
- self->prefix_key_length= 0;
self->number_of_replicas= 0;
hash_ptr= hashkit_create(&self->distribution_hashkit);
if (! hash_ptr)
self->sasl.callbacks= NULL;
self->sasl.is_allocated= false;
+ self->error_messages= NULL;
+ self->prefix_key= NULL;
+ self->configure.filename= NULL;
+
return true;
}
+static void _free(memcached_st *ptr, bool release_st)
+{
+ /* If we have anything open, lets close it now */
+ memcached_quit(ptr);
+ memcached_server_list_free(memcached_server_list(ptr));
+ memcached_result_free(&ptr->result);
+
+ if (ptr->last_disconnected_server)
+ memcached_server_free(ptr->last_disconnected_server);
+
+ if (ptr->on_cleanup)
+ ptr->on_cleanup(ptr);
+
+ if (ptr->continuum)
+ libmemcached_free(ptr, ptr->continuum);
+
+ memcached_array_free(ptr->prefix_key);
+ ptr->prefix_key= NULL;
+
+ memcached_error_free(ptr);
+
+ if (ptr->sasl.callbacks)
+ {
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+ memcached_destroy_sasl_auth_data(ptr);
+#endif
+ }
+
+ if (release_st)
+ {
+ memcached_array_free(ptr->configure.filename);
+ ptr->configure.filename= NULL;
+ }
+
+ if (memcached_is_allocated(ptr) && release_st)
+ {
+ libmemcached_free(ptr, ptr);
+ }
+}
+
memcached_st *memcached_create(memcached_st *ptr)
{
if (ptr == NULL)
return ptr;
}
+memcached_st *memcached_create_with_options(const char *string, size_t length)
+{
+ memcached_st *self= memcached_create(NULL);
+
+ if (! self)
+ return NULL;
+
+ memcached_return_t rc;
+ if ((rc= memcached_parse_configuration(self, string, length)) != MEMCACHED_SUCCESS)
+ {
+ return self;
+ }
+
+ if (memcached_parse_filename(self))
+ {
+ rc= memcached_parse_configure_file(self, memcached_parse_filename(self), memcached_parse_filename_length(self));
+ }
+
+ return self;
+}
+
+memcached_return_t memcached_reset(memcached_st *ptr)
+{
+ WATCHPOINT_ASSERT(ptr);
+ if (! ptr)
+ return MEMCACHED_INVALID_ARGUMENTS;
+
+ bool stored_is_allocated= memcached_is_allocated(ptr);
+ _free(ptr, false);
+ memcached_create(ptr);
+ memcached_set_allocated(ptr, stored_is_allocated);
+
+ if (ptr->configure.filename)
+ {
+ return memcached_parse_configure_file(ptr, memcached_param_array(ptr->configure.filename));
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
void memcached_servers_reset(memcached_st *ptr)
{
memcached_server_list_free(memcached_server_list(ptr));
void memcached_free(memcached_st *ptr)
{
- /* If we have anything open, lets close it now */
- memcached_quit(ptr);
- memcached_server_list_free(memcached_server_list(ptr));
- memcached_result_free(&ptr->result);
-
- if (ptr->last_disconnected_server)
- memcached_server_free(ptr->last_disconnected_server);
-
- if (ptr->on_cleanup)
- ptr->on_cleanup(ptr);
-
- if (ptr->continuum)
- libmemcached_free(ptr, ptr->continuum);
-
- if (ptr->sasl.callbacks)
- {
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
- memcached_destroy_sasl_auth_data(ptr);
-#endif
- }
-
- if (memcached_is_allocated(ptr))
- {
- libmemcached_free(ptr, ptr);
- }
+ _free(ptr, true);
}
/*
}
- if (source->prefix_key_length)
- {
- strcpy(new_clone->prefix_key, source->prefix_key);
- new_clone->prefix_key_length= source->prefix_key_length;
- }
+ new_clone->prefix_key= memcached_array_clone(new_clone, source->prefix_key);
#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
if (source->sasl.callbacks)
#include <libmemcached/constants.h>
#include <libmemcached/types.h>
#include <libmemcached/string.h>
+#include <libmemcached/array.h>
+#include <libmemcached/error.h>
#include <libmemcached/stats.h>
#include <libhashkit/hashkit.h>
// Everything above this line must be in the order specified.
#include <libmemcached/flush_buffers.h>
#include <libmemcached/get.h>
#include <libmemcached/hash.h>
+#include <libmemcached/options.h>
#include <libmemcached/parse.h>
#include <libmemcached/quit.h>
#include <libmemcached/result.h>
bool use_udp:1;
bool verify_key:1;
bool tcp_keepalive:1;
+ bool ping_service:1;
} flags;
memcached_server_distribution_t distribution;
hashkit_st hashkit;
int recv_size;
void *user_data;
time_t next_distribution_rebuild; // Ketama
- size_t prefix_key_length;
uint32_t number_of_replicas;
hashkit_st distribution_hashkit;
memcached_result_st result;
memcached_trigger_delete_key_fn delete_trigger;
memcached_callback_st *callbacks;
struct memcached_sasl_st sasl;
- char prefix_key[MEMCACHED_PREFIX_KEY_MAX_SIZE];
+ struct memcached_error_st *error_messages;
+ struct memcached_array_st *prefix_key;
+ struct {
+ struct memcached_array_st *filename;
+ } configure;
struct {
bool is_allocated:1;
} options;
LIBMEMCACHED_API
memcached_st *memcached_create(memcached_st *ptr);
+LIBMEMCACHED_API
+memcached_st *memcached_create_with_options(const char *string, size_t length);
+
LIBMEMCACHED_API
void memcached_free(memcached_st *ptr);
+LIBMEMCACHED_API
+memcached_return_t memcached_reset(memcached_st *ptr);
+
LIBMEMCACHED_API
void memcached_reset_last_disconnected_server(memcached_st *ptr);
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "common.h"
+
+#include <iostream>
+
+#include <libmemcached/options/context.h>
+
+const char *memcached_parse_filename(memcached_st *memc)
+{
+ return memcached_array_string(memc->configure.filename);
+}
+
+size_t memcached_parse_filename_length(memcached_st *memc)
+{
+ return memcached_array_size(memc->configure.filename);
+}
+
+static memcached_return_t _parse_file_options(memcached_st *self, memcached_string_t *filename)
+{
+ std::string real_name(filename->c_str, filename->size);
+ FILE *fp= fopen(real_name.c_str(), "r");
+ if (! fp)
+ {
+ memcached_string_t tmp;
+ tmp.c_str= real_name.c_str();
+ tmp.size= real_name.size();
+ return memcached_set_errno(self, errno, &tmp);
+ }
+
+ char buffer[BUFSIZ];
+ memcached_return_t rc= MEMCACHED_INVALID_ARGUMENTS;
+ while (fgets(buffer, sizeof(buffer), fp))
+ {
+ size_t length= strlen(buffer);
+
+ if (length == 1 and buffer[0] == '\n')
+ continue;
+
+ rc= memcached_parse_configuration(self, buffer, length);
+ if (rc != MEMCACHED_SUCCESS)
+ break;
+ }
+ fclose(fp);
+
+ return rc;
+}
+
+memcached_return_t libmemcached_check_configuration(const char *option_string, size_t length, char *error_buffer, size_t error_buffer_size)
+{
+ memcached_st memc, *memc_ptr;
+
+ if (! (memc_ptr= memcached_create(&memc)))
+ return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+ memcached_return_t rc= memcached_parse_configuration(memc_ptr, option_string, length);
+ if (rc != MEMCACHED_SUCCESS && error_buffer && error_buffer_size)
+ {
+ strncpy(error_buffer, memcached_last_error_message(memc_ptr), error_buffer_size);
+ }
+
+ if (rc== MEMCACHED_SUCCESS && memcached_behavior_get(memc_ptr, MEMCACHED_BEHAVIOR_LOAD_FROM_FILE))
+ {
+ memcached_string_t filename= memcached_array_to_string(memc_ptr->configure.filename);
+ rc= _parse_file_options(memc_ptr, &filename);
+
+ if (rc != MEMCACHED_SUCCESS && error_buffer && error_buffer_size)
+ {
+ strncpy(error_buffer, memcached_last_error_message(memc_ptr), error_buffer_size);
+ }
+ }
+
+ memcached_free(memc_ptr);
+
+ return rc;
+}
+
+memcached_return_t memcached_parse_configuration(memcached_st *self, char const *option_string, size_t length)
+{
+ WATCHPOINT_ASSERT(self);
+ if (! self)
+ return memcached_set_error(self, MEMCACHED_INVALID_ARGUMENTS, NULL);
+
+ memcached_return_t rc;
+ Context context(option_string, length, self, rc);
+
+ context.start();
+
+ return rc;
+}
+
+void memcached_set_configuration_file(memcached_st *self, const char *filename, size_t filename_length)
+{
+ memcached_array_free(self->configure.filename);
+ self->configure.filename= memcached_strcpy(self, filename, filename_length);
+}
+
+memcached_return_t memcached_parse_configure_file(memcached_st *self, const char *filename, size_t filename_length)
+{
+ if (! self)
+ return memcached_set_error(self, MEMCACHED_INVALID_ARGUMENTS, NULL);
+
+ if (! filename || filename_length == 0)
+ return memcached_set_error(self, MEMCACHED_INVALID_ARGUMENTS, NULL);
+
+ memcached_string_t tmp;
+ tmp.c_str= filename;
+ tmp.size= filename_length;
+
+ return _parse_file_options(self, &tmp);
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+ memcached_return_t libmemcached_check_configuration(const char *option_string, size_t length, char *error_buffer, size_t error_buffer_size);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_parse_configuration(memcached_st *ptr, const char *option_string, size_t length);
+
+LIBMEMCACHED_API
+ memcached_return_t memcached_parse_configure_file(memcached_st *ptr, const char *filename, size_t filename_length);
+
+LIBMEMCACHED_API
+ void memcached_set_configuration_file(memcached_st *self, const char *filename, size_t filename_length);
+
+LIBMEMCACHED_API
+ const char *memcached_parse_filename(memcached_st *memc);
+
+LIBMEMCACHED_LOCAL
+ size_t memcached_parse_filename_length(memcached_st *memc);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libmemcached/memcached.h>
+
+class Context
+{
+public:
+ Context(const char *option_string, size_t option_string_length, memcached_st *memc_arg,
+ memcached_return_t &rc_arg) :
+ scanner(NULL),
+ begin(NULL),
+ pos(0),
+ memc(NULL),
+ rc(rc_arg),
+ _end(false)
+ {
+ buf= option_string;
+ length= option_string_length;
+ memc= memc_arg;
+ init_scanner();
+ rc= MEMCACHED_SUCCESS;
+ }
+
+ bool end()
+ {
+ return _end;
+ }
+
+ void start();
+
+ void set_end()
+ {
+ rc= MEMCACHED_SUCCESS;
+ _end= true;
+ }
+
+ ~Context()
+ {
+ destroy_scanner();
+ }
+
+ void *scanner;
+ const char *buf;
+ const char *begin;
+ size_t pos;
+ size_t length;
+ memcached_st *memc;
+ memcached_return_t &rc;
+
+protected:
+ void init_scanner();
+ void destroy_scanner();
+
+private:
+ bool _end;
+};
--- /dev/null
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+
+DISTCLEANFILES+= \
+ libmemcached/options/parser.output \
+ libmemcached/options/parser.cc \
+ libmemcached/options/parser.h \
+ libmemcached/options/scanner.cc \
+ libmemcached/options/scanner.h
+
+EXTRA_DIST+= \
+ libmemcached/options/scanner.l \
+ libmemcached/options/parser.yy
+
+noinst_HEADERS+= \
+ libmemcached/options/context.h \
+ libmemcached/options/parser.h \
+ libmemcached/options/scanner.h \
+ libmemcached/options/server.h \
+ libmemcached/options/string.h \
+ libmemcached/options/symbol.h
+
+libmemcached_libmemcached_la_SOURCES+= \
+ libmemcached/options/parser.cc \
+ libmemcached/options/scanner.cc
+
+libmemcached/options/parser.h: libmemcached/options/parser.cc
+
+libmemcached/options/parser.cc: libmemcached/options/parser.yy libmemcached/options/scanner.l libmemcached/options/scanner.h
+ $(AM_V_YACC)$(am__skipyacc) $(YACC) $(YLFLAGS) $(AM_YFLAGS) -o $@ $<
+
+libmemcached/options/scanner.h: libmemcached/options/scanner.cc
+
+libmemcached/options/scanner.cc: libmemcached/options/scanner.l libmemcached/options/parser.yy
+ $(AM_V_GEN)$(LEX) $<
+
--- /dev/null
+#pragma once
+
+#include <stdlib.h>
+#include <iostream>
+
+struct string_t
+{
+ const char *c_str;
+ size_t length;
+};
+
+inline std::ostream& operator<<(std::ostream& output, const string_t& arg)
+{
+ output << arg.c_str;
+ return output;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached Scanner and Parser
+ *
+ * Copyright (C) 2011 DataDifferental, http://datadifferential.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+%error-verbose
+%debug
+%defines
+%expect 0
+%output "libmemcached/options/parser.cc"
+%defines "libmemcached/options/parser.h"
+%lex-param { yyscan_t *scanner }
+%name-prefix="libmemcached_"
+%parse-param { Context *context }
+%parse-param { yyscan_t *scanner }
+%locations
+%pure-parser
+%require "2.2"
+%start begin
+%verbose
+
+%{
+
+#include <config.h>
+
+#include <stdint.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <libmemcached/options/context.h>
+#include <libmemcached/options/string.h>
+#include <libmemcached/options/symbol.h>
+
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#include <libmemcached/options/scanner.h>
+
+int libmemcached_lex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner);
+
+#define parser_abort(A, B) do { parser_abort_func((A), (B)); YYABORT; } while (0)
+
+inline void parser_abort_func(Context *context, const char *error)
+{
+ (void)error;
+ if (context->rc == MEMCACHED_SUCCESS)
+ context->rc= MEMCACHED_PARSE_ERROR;
+
+ std::string error_message;
+ error_message+= "Error occured while parsing: ";
+ error_message+= context->begin;
+ error_message+= " (";
+ if (context->rc == MEMCACHED_PARSE_ERROR and error)
+ {
+ error_message+= error;
+ }
+ else
+ {
+ error_message+= memcached_strerror(NULL, context->rc);
+ }
+ error_message+= ")";
+
+ memcached_set_error_string(context->memc, context->rc, error_message.c_str(), error_message.size());
+}
+
+inline void libmemcached_error(YYLTYPE *locp, Context *context, yyscan_t *scanner, const char *error)
+{
+ if (not context->end())
+ parser_abort_func(context, error);
+}
+
+int libmemcached_parse(Context*, yyscan_t *);
+void Context::start()
+{
+ libmemcached_parse(this, scanner);
+}
+
+%}
+
+%token COMMENT
+%token END
+%token ERROR
+%token RESET
+%token PARSER_DEBUG
+%token INCLUDE
+%token CONFIGURE_FILE
+%token EMPTY_LINE
+%token SERVER
+%token SERVERS
+%token SERVERS_OPTION
+%token UNKNOWN_OPTION
+%token UNKNOWN
+
+/* All behavior options */
+%token AUTO_EJECT_HOSTS
+%token BINARY_PROTOCOL
+%token BUFFER_REQUESTS
+%token CACHE_LOOKUPS
+%token CONNECT_TIMEOUT
+%token _CORK
+%token DISTRIBUTION
+%token HASH
+%token HASH_WITH_PREFIX_KEY
+%token IO_BYTES_WATERMARK
+%token IO_KEY_PREFETCH
+%token IO_MSG_WATERMARK
+%token KETAMA
+%token KETAMA_HASH
+%token KETAMA_WEIGHTED
+%token NOREPLY
+%token NUMBER_OF_REPLICAS
+%token POLL_TIMEOUT
+%token RANDOMIZE_REPLICA_READ
+%token RCV_TIMEOUT
+%token RETRY_TIMEOUT
+%token SERVER_FAILURE_LIMIT
+%token SND_TIMEOUT
+%token SOCKET_RECV_SIZE
+%token SOCKET_SEND_SIZE
+%token SORT_HOSTS
+%token SUPPORT_CAS
+%token _TCP_NODELAY
+%token _TCP_KEEPALIVE
+%token _TCP_KEEPIDLE
+%token USER_DATA
+%token USE_UDP
+%token VERIFY_KEY
+
+/* Callbacks */
+%token PREFIX_KEY
+
+/* Hash types */
+%token MD5
+%token CRC
+%token FNV1_64
+%token FNV1A_64
+%token FNV1_32
+%token FNV1A_32
+%token HSIEH
+%token MURMUR
+%token JENKINS
+
+/* Distributions */
+%token CONSISTENT
+%token MODULA
+%token RANDOM
+
+/* Boolean values */
+%token <boolean> TRUE
+%token <boolean> FALSE
+
+%nonassoc ','
+%nonassoc '='
+
+%token <number> NUMBER
+%token <number> FLOAT
+%token <string> HOSTNAME
+%token <string> HOSTNAME_WITH_PORT
+%token <string> IPADDRESS
+%token <string> IPADDRESS_WITH_PORT
+%token <string> STRING
+%token <string> QUOTED_STRING
+%token <string> FILE_PATH
+
+%type <server> server
+%type <string> string
+%type <distribution> distribution
+%type <hash> hash
+%type <behavior> behavior_boolean
+%type <behavior> behavior_number
+
+%%
+
+begin:
+ statement
+ | begin ' ' statement
+ ;
+
+statement:
+ expression
+ { }
+ | COMMENT
+ { }
+ | EMPTY_LINE
+ { }
+ | END
+ {
+ context->set_end();
+ YYACCEPT;
+ }
+ | ERROR
+ {
+ context->rc= MEMCACHED_PARSE_USER_ERROR;
+ parser_abort(context, NULL);
+ }
+ | RESET
+ {
+ memcached_reset(context->memc);
+ }
+ | PARSER_DEBUG
+ {
+ yydebug= 1;
+ }
+ | INCLUDE ' ' string
+ {
+ if ((context->rc= memcached_parse_configure_file(context->memc, $3.c_str, $3.length)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);
+ }
+ }
+ ;
+
+
+expression:
+ SERVER '=' server
+ {
+ if ((context->rc= memcached_server_add_parsed(context->memc, $3.c_str, $3.length, $3.port, 0)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);
+ }
+ }
+ | SERVERS_OPTION '=' server_list
+ {
+ }
+ | CONFIGURE_FILE '=' string
+ {
+ memcached_set_configuration_file(context->memc, $3.c_str, $3.length);
+ }
+ | behaviors
+ ;
+
+behaviors:
+ PREFIX_KEY '=' string
+ {
+ if ((context->rc= memcached_callback_set(context->memc, MEMCACHED_CALLBACK_PREFIX_KEY, std::string($3.c_str, $3.length).c_str())) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);;
+ }
+ }
+ | DISTRIBUTION '=' distribution
+ {
+ if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $3)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);;
+ }
+ }
+ | HASH '=' hash
+ {
+ if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_HASH, $3)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);;
+ }
+ }
+ | KETAMA_HASH '=' hash
+ {
+ if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, $3)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);;
+ }
+ }
+ | behavior_number '=' NUMBER
+ {
+ if ((context->rc= memcached_behavior_set(context->memc, $1, $3)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);;
+ }
+ }
+ | behavior_boolean
+ {
+ if ((context->rc= memcached_behavior_set(context->memc, $1, true)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);;
+ }
+ }
+ | USER_DATA
+ {
+ }
+ ;
+
+behavior_number:
+ CONNECT_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT;
+ }
+ | IO_MSG_WATERMARK
+ {
+ $$= MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK;
+ }
+ | IO_BYTES_WATERMARK
+ {
+ $$= MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK;
+ }
+ | IO_KEY_PREFETCH
+ {
+ $$= MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH;
+ }
+ | NUMBER_OF_REPLICAS
+ {
+ $$= MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS;
+ }
+ | POLL_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_POLL_TIMEOUT;
+ }
+ | RCV_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_RCV_TIMEOUT;
+ }
+ | RETRY_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_RETRY_TIMEOUT;
+ }
+ | SERVER_FAILURE_LIMIT
+ {
+ $$= MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT;
+ }
+ | SND_TIMEOUT
+ {
+ $$= MEMCACHED_BEHAVIOR_SND_TIMEOUT;
+ }
+ | SOCKET_RECV_SIZE
+ {
+ $$= MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE;
+ }
+ | SOCKET_SEND_SIZE
+ {
+ $$= MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE;
+ }
+ ;
+
+behavior_boolean:
+ AUTO_EJECT_HOSTS
+ {
+ $$= MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS;
+ }
+ | BINARY_PROTOCOL
+ {
+ $$= MEMCACHED_BEHAVIOR_BINARY_PROTOCOL;
+ }
+ | BUFFER_REQUESTS
+ {
+ $$= MEMCACHED_BEHAVIOR_BUFFER_REQUESTS;
+ }
+ | CACHE_LOOKUPS
+ {
+ $$= MEMCACHED_BEHAVIOR_CACHE_LOOKUPS;
+ }
+ | _CORK
+ {
+ $$= MEMCACHED_BEHAVIOR_CORK;
+ }
+ | HASH_WITH_PREFIX_KEY
+ {
+ $$= MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY;
+ }
+ | KETAMA
+ {
+ $$= MEMCACHED_BEHAVIOR_KETAMA;
+ }
+ | KETAMA_WEIGHTED
+ {
+ $$= MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED;
+ }
+ | NOREPLY
+ {
+ $$= MEMCACHED_BEHAVIOR_NOREPLY;
+ }
+ | RANDOMIZE_REPLICA_READ
+ {
+ $$= MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ;
+ }
+ | SORT_HOSTS
+ {
+ $$= MEMCACHED_BEHAVIOR_SORT_HOSTS;
+ }
+ | SUPPORT_CAS
+ {
+ $$= MEMCACHED_BEHAVIOR_SUPPORT_CAS;
+ }
+ | _TCP_NODELAY
+ {
+ $$= MEMCACHED_BEHAVIOR_TCP_NODELAY;
+ }
+ | _TCP_KEEPALIVE
+ {
+ $$= MEMCACHED_BEHAVIOR_TCP_KEEPALIVE;
+ }
+ | _TCP_KEEPIDLE
+ {
+ $$= MEMCACHED_BEHAVIOR_TCP_KEEPIDLE;
+ }
+ | USE_UDP
+ {
+ $$= MEMCACHED_BEHAVIOR_USE_UDP;
+ }
+ | VERIFY_KEY
+ {
+ $$= MEMCACHED_BEHAVIOR_VERIFY_KEY;
+ }
+
+
+server_list:
+ server
+ {
+ if ((context->rc= memcached_server_add_parsed(context->memc, $1.c_str, $1.length, $1.port, 0)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);;
+ }
+ }
+ | server_list ',' server
+ {
+ if ((context->rc= memcached_server_add_parsed(context->memc, $3.c_str, $3.length, $3.port, 0)) != MEMCACHED_SUCCESS)
+ {
+ parser_abort(context, NULL);;
+ }
+ }
+ ;
+
+server:
+ HOSTNAME_WITH_PORT NUMBER
+ {
+ $$.c_str= $1.c_str;
+ $$.length= $1.length -1; // -1 to remove :
+ $$.port= $2;
+ }
+ | HOSTNAME
+ {
+ $$.c_str= $1.c_str;
+ $$.length= $1.length;
+ $$.port= MEMCACHED_DEFAULT_PORT;
+ }
+ | STRING /* a match can be against "localhost" which is just a string */
+ {
+ $$.c_str= $1.c_str;
+ $$.length= $1.length;
+ $$.port= MEMCACHED_DEFAULT_PORT;
+ }
+ | IPADDRESS_WITH_PORT NUMBER
+ {
+ $$.c_str= $1.c_str;
+ $$.length= $1.length -1; // -1 to remove :
+ $$.port= $2;
+ }
+ | IPADDRESS
+ {
+ $$.c_str= $1.c_str;
+ $$.length= $1.length;
+ $$.port= MEMCACHED_DEFAULT_PORT;
+ }
+ ;
+
+hash:
+ MD5
+ {
+ $$= MEMCACHED_HASH_MD5;
+ }
+ | CRC
+ {
+ $$= MEMCACHED_HASH_CRC;
+ }
+ | FNV1_64
+ {
+ $$= MEMCACHED_HASH_FNV1_64;
+ }
+ | FNV1A_64
+ {
+ $$= MEMCACHED_HASH_FNV1A_64;
+ }
+ | FNV1_32
+ {
+ $$= MEMCACHED_HASH_FNV1_32;
+ }
+ | FNV1A_32
+ {
+ $$= MEMCACHED_HASH_FNV1A_32;
+ }
+ | HSIEH
+ {
+ $$= MEMCACHED_HASH_HSIEH;
+ }
+ | MURMUR
+ {
+ $$= MEMCACHED_HASH_MURMUR;
+ }
+ | JENKINS
+ {
+ $$= MEMCACHED_HASH_JENKINS;
+ }
+ ;
+
+string:
+ STRING
+ {
+ $$= $1;
+ }
+ | QUOTED_STRING
+ {
+ $$.c_str= $1.c_str +1; // +1 to move use passed the initial quote
+ $$.length= $1.length -1; // -1 removes the end quote
+ }
+ ;
+
+distribution:
+ CONSISTENT
+ {
+ $$= MEMCACHED_DISTRIBUTION_CONSISTENT;
+ }
+ | MODULA
+ {
+ $$= MEMCACHED_DISTRIBUTION_MODULA;
+ }
+ | RANDOM
+ {
+ $$= MEMCACHED_DISTRIBUTION_RANDOM;
+ }
+ ;
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached Scanner and Parser
+ *
+ * Copyright (C) 2011 DataDifferental, http://datadifferential.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+%top{
+
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-fpermissive"
+
+#include <iostream>
+
+#include <libmemcached/options/context.h>
+#include <libmemcached/options/parser.h>
+#include <libmemcached/options/string.h>
+#include <libmemcached/options/symbol.h>
+
+#define YY_EXTRA_TYPE Context*
+#define YY_USER_ACTION yylloc->first_line = yylineno;
+
+}
+
+
+%{
+#include <cstdlib>
+#include <cstring>
+
+#define PARAM yyget_extra(yyscanner)
+
+static void get_lex_chars(char* buffer, int& result, int max_size, Context *context)
+{
+ if (context->pos >= context->length)
+ {
+ result= YY_NULL;
+ }
+ else
+ {
+ result= context->length - context->pos;
+ result > (int)max_size ? result = max_size : 0;
+ memcpy(buffer, context->buf + context->pos, result);
+ context->pos += result;
+ }
+}
+
+
+#define YY_INPUT(buffer, result, max_size) get_lex_chars(buffer, result, max_size, PARAM)
+
+%}
+
+%option bison-bridge
+%option bison-locations
+%option case-insensitive
+%option debug
+%option nounput
+%option noyywrap
+%option yylineno
+%option outfile="libmemcached/options/scanner.cc" header-file="libmemcached/options/scanner.h"
+%option perf-report
+%option prefix="libmemcached_"
+%option reentrant
+
+%%
+
+
+=|,|[ ] { return yytext[0];}
+
+
+[[:digit:]]+ { yylval->number = atoi(yytext); return (NUMBER); }
+
+[\t\r\n] ; /* skip whitespace */
+
+^#.*$ {
+ return COMMENT;
+ }
+
+"--SERVER" { yyextra->begin= yytext; return SERVER; }
+"--SERVERS" { yyextra->begin= yytext; return SERVERS_OPTION; }
+
+"--VERIFY_KEY" { yyextra->begin= yytext; return VERIFY_KEY; }
+"--VERIFY-KEY" { yyextra->begin= yytext; return VERIFY_KEY; }
+"--AUTO_EJECT_HOSTS" { yyextra->begin= yytext; return AUTO_EJECT_HOSTS; }
+"--AUTO-EJECT_HOSTS" { yyextra->begin= yytext; return AUTO_EJECT_HOSTS; }
+"--BINARY_PROTOCOL" { yyextra->begin= yytext; return BINARY_PROTOCOL; }
+"--BINARY-PROTOCOL" { yyextra->begin= yytext; return BINARY_PROTOCOL; }
+"--BUFFER_REQUESTS" { yyextra->begin= yytext; return BUFFER_REQUESTS; }
+"--BUFFER-REQUESTS" { yyextra->begin= yytext; return BUFFER_REQUESTS; }
+"--CACHE_LOOKUPS" { yyextra->begin= yytext; return CACHE_LOOKUPS; }
+"--CACHE-LOOKUPS" { yyextra->begin= yytext; return CACHE_LOOKUPS; }
+"--CONFIGURE_FILE" { yyextra->begin= yytext; return CONFIGURE_FILE; }
+"--CONFIGURE-FILE" { yyextra->begin= yytext; return CONFIGURE_FILE; }
+"--CONNECT_TIMEOUT" { yyextra->begin= yytext; return CONNECT_TIMEOUT; }
+"--CONNECT-TIMEOUT" { yyextra->begin= yytext; return CONNECT_TIMEOUT; }
+"--CORK" { yyextra->begin= yytext; return _CORK; }
+"--DISTRIBUTION" { yyextra->begin= yytext; return DISTRIBUTION; }
+"--HASH" { yyextra->begin= yytext; return HASH; }
+"--HASH_WITH_PREFIX_KEY" { yyextra->begin= yytext; return HASH_WITH_PREFIX_KEY; }
+"--HASH-WITH-PREFIX_KEY" { yyextra->begin= yytext; return HASH_WITH_PREFIX_KEY; }
+"--IO_BYTES_WATERMARK" { yyextra->begin= yytext; return IO_BYTES_WATERMARK; }
+"--IO-BYTES-WATERMARK" { yyextra->begin= yytext; return IO_BYTES_WATERMARK; }
+"--IO_KEY_PREFETCH" { yyextra->begin= yytext; return IO_KEY_PREFETCH; }
+"--IO-KEY-PREFETCH" { yyextra->begin= yytext; return IO_KEY_PREFETCH; }
+"--IO_MSG_WATERMARK" { yyextra->begin= yytext; return IO_MSG_WATERMARK; }
+"--IO-MSG-WATERMARK" { yyextra->begin= yytext; return IO_MSG_WATERMARK; }
+"--KETAMA" { yyextra->begin= yytext; return KETAMA; }
+"--KETAMA_HASH" { yyextra->begin= yytext; return KETAMA_HASH; }
+"--KETAMA-HASH" { yyextra->begin= yytext; return KETAMA_HASH; }
+"--KETAMA_WEIGHTED" { yyextra->begin= yytext; return KETAMA_WEIGHTED; }
+"--KETAMA-WEIGHTED" { yyextra->begin= yytext; return KETAMA_WEIGHTED; }
+"--NOREPLY" { yyextra->begin= yytext; return NOREPLY; }
+"--NUMBER_OF_REPLICAS" { yyextra->begin= yytext; return NUMBER_OF_REPLICAS; }
+"--NUMBER-OF-REPLICAS" { yyextra->begin= yytext; return NUMBER_OF_REPLICAS; }
+"--POLL_TIMEOUT" { yyextra->begin= yytext; return POLL_TIMEOUT; }
+"--POLL-TIMEOUT" { yyextra->begin= yytext; return POLL_TIMEOUT; }
+"--RANDOMIZE_REPLICA_READ" { yyextra->begin= yytext; return RANDOMIZE_REPLICA_READ; }
+"--RANDOMIZE-REPLICA-READ" { yyextra->begin= yytext; return RANDOMIZE_REPLICA_READ; }
+"--RCV_TIMEOUT" { yyextra->begin= yytext; return RCV_TIMEOUT; }
+"--RCV-TIMEOUT" { yyextra->begin= yytext; return RCV_TIMEOUT; }
+"--RETRY_TIMEOUT" { yyextra->begin= yytext; return RETRY_TIMEOUT; }
+"--RETRY-TIMEOUT" { yyextra->begin= yytext; return RETRY_TIMEOUT; }
+"--SERVER_FAILURE_LIMIT" { yyextra->begin= yytext; return SERVER_FAILURE_LIMIT; }
+"--SERVER-FAILURE-LIMIT" { yyextra->begin= yytext; return SERVER_FAILURE_LIMIT; }
+"--SND_TIMEOUT" { yyextra->begin= yytext; return SND_TIMEOUT; }
+"--SND-TIMEOUT" { yyextra->begin= yytext; return SND_TIMEOUT; }
+"--SOCKET_RECV_SIZE" { yyextra->begin= yytext; return SOCKET_RECV_SIZE; }
+"--SOCKET-RECV-SIZE" { yyextra->begin= yytext; return SOCKET_RECV_SIZE; }
+"--SOCKET_SEND_SIZE" { yyextra->begin= yytext; return SOCKET_SEND_SIZE; }
+"--SOCKET-SEND-SIZE" { yyextra->begin= yytext; return SOCKET_SEND_SIZE; }
+"--SORT_HOSTS" { yyextra->begin= yytext; return SORT_HOSTS; }
+"--SORT-HOSTS" { yyextra->begin= yytext; return SORT_HOSTS; }
+"--SUPPORT_CAS" { yyextra->begin= yytext; return SUPPORT_CAS; }
+"--SUPPORT-CAS" { yyextra->begin= yytext; return SUPPORT_CAS; }
+"--TCP_NODELAY" { yyextra->begin= yytext; return _TCP_NODELAY; }
+"--TCP-NODELAY" { yyextra->begin= yytext; return _TCP_NODELAY; }
+"--TCP_KEEPALIVE" { yyextra->begin= yytext; return _TCP_KEEPALIVE; }
+"--TCP-KEEPALIVE" { yyextra->begin= yytext; return _TCP_KEEPALIVE; }
+"--TCP_KEEPIDLE" { yyextra->begin= yytext; return _TCP_KEEPIDLE; }
+"--TCP-KEEPIDLE" { yyextra->begin= yytext; return _TCP_KEEPIDLE; }
+"--USER_DATA" { yyextra->begin= yytext; return USER_DATA; }
+"--USER-DATA" { yyextra->begin= yytext; return USER_DATA; }
+"--USE_UDP" { yyextra->begin= yytext; return USE_UDP; }
+"--USE-UDP" { yyextra->begin= yytext; return USE_UDP; }
+
+"--PREFIX-KEY" { yyextra->begin= yytext; return PREFIX_KEY; }
+"--PREFIX_KEY" { yyextra->begin= yytext; return PREFIX_KEY; }
+
+INCLUDE { yyextra->begin= yytext; return INCLUDE; }
+RESET { yyextra->begin= yytext; return RESET; }
+DEBUG { yyextra->begin= yytext; return PARSER_DEBUG; }
+SERVERS { yyextra->begin= yytext; return SERVERS; }
+END { yyextra->begin= yytext; return END; }
+ERROR { yyextra->begin= yytext; return ERROR; }
+
+TRUE { return TRUE; }
+FALSE { return FALSE; }
+
+
+"--"[[:alnum:]]* {
+ yyextra->begin= yytext;
+ return UNKNOWN_OPTION;
+ }
+
+CONSISTENT { return CONSISTENT; }
+MODULA { return MODULA; }
+RANDOM { return RANDOM; }
+
+MD5 { return MD5; }
+CRC { return CRC; }
+FNV1_64 { return FNV1_64; }
+FNV1A_64 { return FNV1A_64; }
+FNV1_32 { return FNV1_32; }
+FNV1A_32 { return FNV1A_32; }
+HSIEH { return HSIEH; }
+MURMUR { return MURMUR; }
+JENKINS { return JENKINS; }
+
+[[:alnum:]][[:alnum:].]*[[:alpha:]]: {
+ yylval->string.c_str = yytext;
+ yylval->string.length = yyleng;
+ return HOSTNAME_WITH_PORT;
+ }
+
+[[:alnum:]]+"."[[:alpha:].]+[[:alnum:]] {
+ yylval->string.c_str = yytext;
+ yylval->string.length = yyleng;
+ return HOSTNAME;
+ }
+
+(([[:digit:]]{1,3}"."){3}([[:digit:]]{1,3})): {
+ yylval->string.c_str = yytext;
+ yylval->string.length = yyleng;
+ return IPADDRESS_WITH_PORT;
+ }
+
+(([[:digit:]]{1,3}"."){3}([[:digit:]]{1,3})) {
+ yylval->string.c_str = yytext;
+ yylval->string.length = yyleng;
+ return IPADDRESS;
+ }
+
+[[:alnum:]]+ {
+ yylval->string.c_str = yytext;
+ yylval->string.length = yyleng;
+ return STRING;
+ }
+
+(\".*\") {
+ yylval->string.c_str = yytext;
+ yylval->string.length = yyleng;
+ return QUOTED_STRING;
+ }
+
+. {
+ yyextra->begin= yytext;
+ return UNKNOWN;
+ }
+
+%%
+
+void Context::init_scanner()
+{
+ yylex_init(&scanner);
+ yyset_extra(this, scanner);
+}
+
+void Context::destroy_scanner()
+{
+ yylex_destroy(scanner);
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <cstdlib>
+#include <iostream>
+#include <arpa/inet.h>
+
+struct server_t
+{
+ const char *c_str;
+ size_t length;
+ in_port_t port;
+};
+
+inline std::ostream& operator<<(std::ostream& output, const server_t& arg)
+{
+ output.write(arg.c_str, arg.length);
+ output << ':' << arg.port;
+ return output;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <cstdlib>
+#include <iostream>
+
+struct string_t
+{
+ const char *c_str;
+ size_t length;
+};
+
+inline std::ostream& operator<<(std::ostream& output, const string_t& arg)
+{
+ output.write(arg.c_str, arg.length);
+ return output;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libmemcached/constants.h>
+#include <libmemcached/options/string.h>
+#include <libmemcached/options/server.h>
+
+union YYSTYPE
+{
+ long long number;
+ string_t string;
+ string_t option;
+ server_t server;
+ double double_number;
+ memcached_server_distribution_t distribution;
+ memcached_hash_t hash;
+ memcached_behavior_t behavior;
+ bool boolean;
+};
+
+typedef union YYSTYPE YYSTYPE;
*
*/
-#ifndef __LIBMEMCACHED_PARSE_H__
-#define __LIBMEMCACHED_PARSE_H__
+#pragma once
#ifdef __cplusplus
extern "C" {
#ifdef __cplusplus
}
#endif
-
-#endif /* __LIBMEMCACHED_PARSE_H__ */
key= result->item_key;
result->key_length= 0;
- for (prefix_length= ptr->root->prefix_key_length; !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
+ for (prefix_length= memcached_array_size(ptr->root->prefix_key); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
{
if (prefix_length == 0)
{
memcached_return_t memcached_server_add(memcached_st *ptr,
const char *hostname, in_port_t port);
+LIBMEMCACHED_LOCAL
+ memcached_return_t memcached_server_add_parsed(memcached_st *ptr,
+ const char *hostname,
+ size_t hostname_length,
+ in_port_t port,
+ uint32_t weight);
+
LIBMEMCACHED_API
memcached_return_t memcached_server_add_udp_with_weight(memcached_st *ptr,
const char *hostname,
return rc;
}
-memcached_stat_st *memcached_stat(memcached_st *ptr, char *args, memcached_return_t *error)
+memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_return_t *error)
{
memcached_return_t rc;
memcached_stat_st *stats;
- if (! ptr)
+ if (! self)
{
- WATCHPOINT_ASSERT(memc_ptr);
+ WATCHPOINT_ASSERT(self);
return NULL;
}
WATCHPOINT_ASSERT(error);
- unlikely (ptr->flags.use_udp)
+ unlikely (self->flags.use_udp)
{
if (error)
*error= MEMCACHED_NOT_SUPPORTED;
return NULL;
}
- stats= libmemcached_calloc(ptr, memcached_server_count(ptr), sizeof(memcached_stat_st));
+ stats= libmemcached_calloc(self, memcached_server_count(self), sizeof(memcached_stat_st));
if (! stats)
{
}
rc= MEMCACHED_SUCCESS;
- for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+ for (uint32_t x= 0; x < memcached_server_count(self); x++)
{
memcached_return_t temp_return;
memcached_server_write_instance_st instance;
stat_instance= stats + x;
- stat_instance->root= ptr;
+ stat_instance->root= self;
- instance= memcached_server_instance_fetch(ptr, x);
+ instance= memcached_server_instance_fetch(self, x);
- if (ptr->flags.binary_protocol)
+ if (self->flags.binary_protocol)
{
temp_return= binary_stats_fetch(stat_instance, args, instance, NULL);
}
check_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
"%s %.*s%.*s %u %llu %lu %llu%s\r\n",
storage_op_string(verb),
- (int)ptr->prefix_key_length,
- ptr->prefix_key,
+ memcached_print_array(ptr->prefix_key),
(int)key_length, key, flags,
(unsigned long long)expiration, (unsigned long)value_length,
(unsigned long long)cas,
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, ptr->prefix_key_length);
+ buffer_ptr= memcpy((buffer_ptr + strlen(command)), memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
/* Copy in the key, adjust point if a key prefix was used. */
- buffer_ptr= memcpy(buffer_ptr + (ptr->prefix_key_length ? ptr->prefix_key_length : 0),
+ buffer_ptr= memcpy(buffer_ptr + memcached_array_size(ptr->prefix_key),
key, key_length);
buffer_ptr+= key_length;
buffer_ptr[0]= ' ';
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 + ptr->prefix_key_length));
+ request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
if (verb == APPEND_OP || verb == PREPEND_OP)
send_length -= 8; /* append & prepend does not contain extras! */
request.message.body.expiration= htonl((uint32_t)expiration);
}
- request.message.header.request.bodylen= htonl((uint32_t) (key_length + ptr->prefix_key_length + value_length +
+ request.message.header.request.bodylen= htonl((uint32_t) (key_length + memcached_array_size(ptr->prefix_key) + value_length +
request.message.header.request.extlen));
if (cas)
struct libmemcached_io_vector_st vector[]=
{
{ .length= send_length, .buffer= request.bytes },
- { .length= ptr->prefix_key_length, .buffer= ptr->prefix_key },
+ { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
{ .length= key_length, .buffer= key },
{ .length= value_length, .buffer= value }
};
return "AUTHENTICATION FAILURE";
case MEMCACHED_AUTH_CONTINUE:
return "CONTINUE AUTHENTICATION";
+ case MEMCACHED_PARSE_ERROR:
+ return "ERROR OCCURED WHILE PARSING";
+ case MEMCACHED_PARSE_USER_ERROR:
+ return "USER INITIATED ERROR OCCURED WHILE PARSING";
case MEMCACHED_MAXIMUM_RETURN:
return "Gibberish returned!";
default:
{
self->end= self->string + length;
}
+
+memcached_string_t memcached_string_make(const char *str, size_t length)
+{
+ memcached_string_t tmp;
+ tmp.c_str= str;
+ tmp.size= length;
+
+ return tmp;
+}
*
*/
+#pragma once
#ifndef __LIBMEMCACHED_STRING_H__
#define __LIBMEMCACHED_STRING_H__
} options;
};
+struct memcached_string_t {
+ size_t size;
+ const char *c_str;
+};
+
#ifdef __cplusplus
extern "C" {
#endif
LIBMEMCACHED_LOCAL
void memcached_string_set_length(memcached_string_st *self, size_t length);
+LIBMEMCACHED_LOCAL
+memcached_string_t memcached_string_make(const char *str, size_t length);
+
#ifdef __cplusplus
}
#endif
+#ifdef __cplusplus
+#define memcached_string_with_size(X) (X), (static_cast<size_t>((sizeof(X) - 1)))
+#else
+#define memcached_string_with_size(X) (X), ((size_t)((sizeof(X) - 1)))
+#endif
+
#endif /* __LIBMEMCACHED_STRING_H__ */
typedef struct memcached_stat_st memcached_stat_st;
typedef struct memcached_analysis_st memcached_analysis_st;
typedef struct memcached_result_st memcached_result_st;
+typedef struct memcached_array_st memcached_array_st;
+typedef struct memcached_error_st memcached_error_st;
// All of the flavors of memcache_server_st
typedef struct memcached_server_st memcached_server_st;
// The following two structures are internal, and never exposed to users.
typedef struct memcached_string_st memcached_string_st;
+typedef struct memcached_string_t memcached_string_t;
typedef struct memcached_continuum_item_st memcached_continuum_item_st;
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * uTest Framework
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <libtest/failed.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+struct failed_test_names_st
+{
+ failed_test_names_st(const char *collection_arg, const char *test_arg) :
+ collection(collection_arg),
+ test(test_arg)
+ {
+ }
+
+ std::string collection;
+ std::string test;
+};
+
+typedef std::vector<failed_test_names_st> Failures;
+
+static Failures failures;
+
+void push_failed_test(const char *collection, const char *test)
+{
+ failures.push_back(failed_test_names_st(collection, test));
+}
+
+void print_failed_test(void)
+{
+ for (Failures::iterator iter= failures.begin(); iter != failures.end(); iter++)
+ {
+ std::cerr << "\t" << (*iter).collection << " " << (*iter).test << std::endl;
+ }
+ std::cerr << std::endl;
+}
+
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * uTest Framework
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+#include <libtest/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBTEST_INTERNAL_API
+ void push_failed_test(const char *collection, const char *test);
+
+LIBTEST_INTERNAL_API
+ void print_failed_test(void);
+
+#ifdef __cplusplus
+}
+#endif
# All paths should be given relative to the root
noinst_HEADERS+= \
+ libtest/failed.h \
libtest/server.h \
- libtest/test.h
+ libtest/test.h \
+ libtest/visibility.h
noinst_LTLIBRARIES+= libtest/libserver.la
libtest_libserver_la_SOURCES= libtest/server.c
noinst_LTLIBRARIES+= libtest/libtest.la
-libtest_libtest_la_SOURCES= libtest/test.c
+libtest_libtest_la_SOURCES=\
+ libtest/test.c
+libtest_libtest_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION}
+libtest_libtest_la_CPPFLAGS= ${AM_CPPFLAGS}
static void kill_file(const char *file_buffer)
{
- FILE *fp= fopen(file_buffer, "r");
+ FILE *fp;
while ((fp= fopen(file_buffer, "r")))
{
#include <libmemcached/memcached.h>
#include <libtest/test.h>
+#include <libtest/failed.h>
static void world_stats_print(world_stats_st *stats)
{
stats.success++;
break;
case TEST_FAILURE:
+#if 0
+ push_failed_test(next->name, run->name);
+#endif
stats.failed++;
failed= true;
break;
if (stats.collection_failed || stats.collection_skipped)
{
fprintf(stderr, "Some test failures and/or skipped test occurred.\n\n");
+#if 0
+ print_failed_test();
+#endif
}
else
{
-/* uTest
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Gearmand client and server library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * Copyright (C) 2006-2010 Brian Aker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Use and distribution licensed under the BSD license. See
- * the COPYING file in the parent directory for full text.
*/
+#pragma once
+
+#include <libtest/visibility.h>
+
/*
Structures for generic tests.
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef test_return_t (*test_callback_runner_fn)(test_callback_fn, void *);
typedef test_return_t (*test_callback_error_fn)(test_return_t, void *);
-/* Help function for use with gettimeofday() */
-long int timedif(struct timeval a, struct timeval b);
-
/**
A structure describing the test case.
*/
uint32_t total;
} world_stats_st;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Help function for use with gettimeofday() */
+LIBTEST_API
+long int timedif(struct timeval a, struct timeval b);
+
/* How we make all of this work :) */
+LIBTEST_API
void get_world(world_st *world);
+LIBTEST_INTERNAL_API
void create_core(void);
/**
@note Friendly print function for errors.
*/
+LIBTEST_API
const char *test_strerror(test_return_t code);
#define test_fail(A) \
} \
} while (0)
+#define test_false_with(A,B) \
+do \
+{ \
+ if ((A)) { \
+ fprintf(stderr, "\nAssertion failed at %s:%d: %s with %s\n", __FILE__, __LINE__, #A, (B));\
+ create_core(); \
+ return TEST_FAILURE; \
+ } \
+} while (0)
+
#define test_strcmp(A,B) \
do \
{ \
} \
} while (0)
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define AT __FILE__ ":" TOSTRING(__LINE__)
+
+#ifdef __cplusplus
+#define STRING_WITH_LEN(X) (X), (static_cast<size_t>((sizeof(X) - 1)))
+#else
+#define STRING_WITH_LEN(X) (X), ((size_t)((sizeof(X) - 1)))
+#endif
+
+#ifdef __cplusplus
+#define STRING_PARAM_WITH_LEN(X) X, static_cast<size_t>(sizeof(X) - 1)
+#else
+#define STRING_PARAM_WITH_LEN(X) X, (size_t)((sizeof(X) - 1))
+#endif
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Gearmand client and server library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#if defined(BUILDING_LIBTEST)
+# if defined(HAVE_VISIBILITY)
+# define LIBTEST_API __attribute__ ((visibility("default")))
+# define LIBTEST_INTERNAL_API __attribute__ ((visibility("hidden")))
+# define LIBTEST_API_DEPRECATED __attribute__ ((deprecated,visibility("default")))
+# define LIBTEST_LOCAL __attribute__ ((visibility("hidden")))
+# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+# define LIBTEST_API __global
+# define LIBTEST_INTERNAL_API __hidden
+# define LIBTEST_API_DEPRECATED __global
+# define LIBTEST_LOCAL __hidden
+# elif defined(_MSC_VER)
+# define LIBTEST_API extern __declspec(dllexport)
+# define LIBTEST_INTERNAL_API extern __declspec(dllexport)
+# define LIBTEST_DEPRECATED_API extern __declspec(dllexport)
+# define LIBTEST_LOCAL
+# endif /* defined(HAVE_VISIBILITY) */
+#else /* defined(BUILDING_LIBTEST) */
+# if defined(_MSC_VER)
+# define LIBTEST_API extern __declspec(dllimport)
+# define LIBTEST_INTERNAL_API extern __declspec(dllimport)
+# define LIBTEST_API_DEPRECATED extern __declspec(dllimport)
+# define LIBTEST_LOCAL
+# else
+# define LIBTEST_API
+# define LIBTEST_INTERNAL_API
+# define LIBTEST_API_DEPRECATED
+# define LIBTEST_LOCAL
+# endif /* defined(_MSC_VER) */
+#endif /* defined(BUILDING_LIBTEST) */
m4_if(PW_LESS_WARNINGS,[no],[
BASE_WARNINGS_FULL="${W_CONVERSION} -Wstrict-aliasing"
CC_WARNINGS_FULL="-Wswitch-default -Wswitch-enum -Wwrite-strings"
- CXX_WARNINGS_FULL="-Weffc++ -Wold-style-cast"
+ CXX_WARNINGS_FULL=""
NO_OLD_STYLE_CAST="-Wno-old-style-cast"
NO_EFF_CXX="-Wno-effc++"
],[
--- /dev/null
+# http://en.wikipedia.org/wiki/Consistent_hashing
+--distribution=consistent
+
+# Store one additional copy on each node.
+--number-of-replicas=2
+--prefix-key="my_foo"
+--prefix-key="my_prefix"
+--server=localhost:11211
+--server=localhost:11212
+--server=localhost:11213
+--verify-key
%exclude %{_libdir}/libhashkit.la
%exclude %{_libdir}/libmemcachedutil.la
%exclude %{_libdir}/libmemcachedprotocol.la
-%{_libdir}/libhashkit.so.0.0.0
+%{_libdir}/libhashkit.so.1.0.0
%{_libdir}/libmemcached.so.6.0.0
%{_libdir}/libmemcachedutil.so.1.0.0
%{_libdir}/libmemcachedprotocol.so.0.0.0
-%{_libdir}/libhashkit.so.0
+%{_libdir}/libhashkit.so.1
%{_libdir}/libmemcached.so.6
%{_libdir}/libmemcachedprotocol.so.0
%{_libdir}/libmemcachedutil.so.1
%files devel
%defattr (-,root,root,-)
%doc examples
-%{_includedir}/libmemcached/allocators.h
-%{_includedir}/libmemcached/delete.h
-%{_includedir}/libmemcached/fetch.h
-%{_includedir}/libmemcached/flush.h
%{_includedir}/libhashkit/algorithm.h
%{_includedir}/libhashkit/behavior.h
%{_includedir}/libhashkit/configure.h
%{_includedir}/libhashkit/strerror.h
%{_includedir}/libhashkit/types.h
%{_includedir}/libhashkit/visibility.h
+%{_includedir}/libmemcached/allocators.h
%{_includedir}/libmemcached/analyze.h
+%{_includedir}/libmemcached/array.h
%{_includedir}/libmemcached/auto.h
%{_includedir}/libmemcached/behavior.h
%{_includedir}/libmemcached/callback.h
%{_includedir}/libmemcached/configure.h
%{_includedir}/libmemcached/constants.h
+%{_includedir}/libmemcached/delete.h
%{_includedir}/libmemcached/dump.h
+%{_includedir}/libmemcached/error.h
%{_includedir}/libmemcached/exception.hpp
+%{_includedir}/libmemcached/fetch.h
+%{_includedir}/libmemcached/flush.h
%{_includedir}/libmemcached/flush_buffers.h
%{_includedir}/libmemcached/get.h
%{_includedir}/libmemcached/hash.h
%{_includedir}/libmemcached/memcached.h
%{_includedir}/libmemcached/memcached.hpp
+%{_includedir}/libmemcached/memcached/protocol_binary.h
%{_includedir}/libmemcached/memcached_util.h
+%{_includedir}/libmemcached/options.h
%{_includedir}/libmemcached/parse.h
%{_includedir}/libmemcached/platform.h
%{_includedir}/libmemcached/protocol/cache.h
%{_includedir}/libmemcached/version.h
%{_includedir}/libmemcached/visibility.h
%{_includedir}/libmemcached/watchpoint.h
-%{_includedir}/libmemcached/memcached/protocol_binary.h
%{_libdir}/libhashkit.so
%{_libdir}/libmemcached.so
%{_libdir}/libmemcachedprotocol.so
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <libmemcached/memcached.h>
+#include <libmemcached/is.h>
+#include <libtest/test.h>
+#include "tests/basic.h"
+
+test_return_t basic_init_test(memcached_st *junk)
+{
+ (void)junk;
+
+ memcached_st memc;
+ memcached_st *memc_ptr;
+
+ memc_ptr= memcached_create(&memc);
+ test_true(memc_ptr);
+ test_false(memcached_is_allocated(&memc));
+ memcached_free(memc_ptr);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t basic_clone_test(memcached_st *memc)
+{
+ memcached_st *memc_ptr;
+
+ memc_ptr= memcached_clone(NULL, memc);
+ test_true(memc_ptr);
+ test_true(memcached_is_allocated(memc_ptr));
+ memcached_free(memc_ptr);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t basic_reset_stack_test(memcached_st *junk)
+{
+ (void)junk;
+ memcached_st memc;
+
+ memcached_create(&memc);
+
+ memcached_reset(&memc);
+ test_false(memcached_is_allocated(&memc));
+
+ memcached_free(&memc);
+ test_false(memcached_is_allocated(&memc));
+
+ return TEST_SUCCESS;
+}
+
+test_return_t basic_reset_heap_test(memcached_st *junk)
+{
+ (void)junk;
+ memcached_st *memc_ptr;
+
+ memc_ptr= memcached_create(NULL);
+ test_true(memcached_is_allocated(memc_ptr));
+
+ memcached_reset(memc_ptr);
+ test_true(memcached_is_allocated(memc_ptr));
+
+ memcached_free(memc_ptr);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t basic_reset_stack_clone_test(memcached_st *memc)
+{
+ memcached_st clone;
+ memcached_st *memc_ptr;
+
+ memset(&clone, 0, sizeof(clone));
+ memc_ptr= memcached_clone(&clone, memc);
+ test_true(memc_ptr);
+
+ memcached_reset(memc_ptr);
+
+ memcached_free(memc_ptr);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t basic_reset_heap_clone_test(memcached_st *memc)
+{
+ memcached_st *memc_ptr;
+
+ memc_ptr= memcached_clone(NULL, memc);
+ test_true(memc_ptr);
+
+ memcached_reset(memc_ptr);
+
+ memcached_free(memc_ptr);
+
+ return TEST_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libtest/visibility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBTEST_INTERNAL_API
+test_return_t basic_init_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t basic_clone_test(memcached_st *memc);
+
+LIBTEST_INTERNAL_API
+test_return_t basic_reset_stack_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t basic_reset_heap_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t basic_reset_stack_clone_test(memcached_st *memc);
+
+LIBTEST_INTERNAL_API
+test_return_t basic_reset_heap_clone_test(memcached_st *memc);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <libmemcached/memcached.h>
+#include <libmemcached/is.h>
+#include <libtest/test.h>
+#include <tests/error_conditions.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+test_return_t memcached_increment_MEMCACHED_NO_SERVERS(memcached_st *junk)
+{
+ (void)junk;
+ memcached_st *memc_ptr;
+
+ memc_ptr= memcached_create(NULL);
+ test_true(memc_ptr);
+
+ memcached_increment(memc_ptr, memcached_string_with_size("dead key"), 1, NULL);
+ test_true(memcached_last_error(memc_ptr) == MEMCACHED_NO_SERVERS);
+
+ memcached_increment(memc_ptr, memcached_string_with_size("dead key"), 1, NULL);
+ test_true(memcached_last_error(memc_ptr) == MEMCACHED_NO_SERVERS);
+
+ memcached_free(memc_ptr);
+
+ return TEST_SUCCESS;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libtest/test.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+test_return_t memcached_increment_MEMCACHED_NO_SERVERS(memcached_st *junk);
+
+#ifdef __cplusplus
+}
+#endif
continue;
#endif
- if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_CUSTOM)
+ if (rc == HASHKIT_INVALID_ARGUMENT && algo == HASHKIT_HASH_CUSTOM)
continue;
- test_true(rc == HASHKIT_SUCCESS);
+ test_true_got(rc == HASHKIT_SUCCESS, hashkit_strerror(NULL, rc));
switch (algo)
{
if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_HSIEH)
continue;
- if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_CUSTOM)
+ if (rc == HASHKIT_INVALID_ARGUMENT && algo == HASHKIT_HASH_CUSTOM)
continue;
test_true(rc == HASHKIT_SUCCESS);
tests/output_plus.res
noinst_HEADERS+= \
+ tests/basic.h \
+ tests/error_conditions.h \
tests/hash_results.h \
tests/ketama_test_cases.h \
tests/ketama_test_cases_spy.h \
- tests/libmemcached_world.h
+ tests/libmemcached_world.h \
+ tests/parser.h \
+ tests/print.h \
+ tests/replication.h
noinst_PROGRAMS+= \
tests/atomsmasher \
tests/testudp
tests_testapp_CFLAGS= $(AM_CFLAGS) $(NO_CONVERSION) $(NO_STRICT_ALIASING)
-tests_testapp_SOURCES= tests/mem_functions.c
+tests_testapp_SOURCES= \
+ tests/basic.cc \
+ tests/error_conditions.cc \
+ tests/mem_functions.c \
+ tests/parser.cc \
+ tests/print.cc \
+ tests/replication.cc
+
tests_testapp_DEPENDENCIES= \
$(BUILT_SOURCES) \
clients/libgenexec.la \
#define SMALL_STRING_LEN 1024
#include <libtest/test.h>
+#include "tests/parser.h"
+#include "tests/replication.h"
+#include "tests/basic.h"
+#include "tests/error_conditions.h"
+#include "tests/print.h"
#ifdef HAVE_LIBMEMCACHEDUTIL
return TEST_SUCCESS;
}
-static memcached_return_t server_print_callback(const memcached_st *ptr,
- const memcached_server_st *server,
- void *context)
-{
- (void)server; // Just in case we aren't printing.
- (void)ptr;
- (void)context;
-
-#if 0
- fprintf(stderr, "%s(%d)", memcached_server_name(server), memcached_server_port(server));
-#endif
-
- return MEMCACHED_SUCCESS;
-}
-
static test_return_t memcached_server_remove_test(memcached_st *ptr)
{
memcached_return_t rc;
2300930706U, 2943759320U, 674306647U, 2400528935U,
54481931U, 4186304426U, 1741088401U, 2979625118U,
4159057246U, 3425930182U, 2593724503U, 1868899624U,
- 1769812374U, 2302537950U, 1110330676U };
+ 1769812374U, 2302537950U, 1110330676U, 3365377466U,
+ 1336171666U, 3365377466U };
// You have updated the memcache_error messages but not updated docs/tests.
- test_true(MEMCACHED_MAXIMUM_RETURN == 43);
for (rc= MEMCACHED_SUCCESS; rc < MEMCACHED_MAXIMUM_RETURN; rc++)
{
uint32_t hash_val;
}
test_true(values[rc] == hash_val);
}
+ test_true(MEMCACHED_MAXIMUM_RETURN == 45);
return TEST_SUCCESS;
}
/* Test a clean set */
rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, (void *)key);
- test_true(rc == MEMCACHED_SUCCESS);
+ test_true_got(rc == MEMCACHED_SUCCESS, memcached_last_error_message(memc));
value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+ test_true(value);
test_true(memcmp(value, key, 4) == 0);
test_true(rc == MEMCACHED_SUCCESS);
test_true(rc == MEMCACHED_SUCCESS);
value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+ test_false(value);
test_true(rc == MEMCACHED_FAILURE);
/* Now setup for main test */
test_true(rc == MEMCACHED_SUCCESS);
value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+ test_true(value);
test_true(rc == MEMCACHED_SUCCESS);
test_true(memcmp(value, key, 4) == 0);
test_true(rc == MEMCACHED_SUCCESS);
value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+ test_false(value);
test_true(rc == MEMCACHED_FAILURE);
test_true(value == NULL);
}
#endif
-static test_return_t replication_set_test(memcached_st *memc)
-{
- memcached_return_t rc;
- memcached_st *memc_clone= memcached_clone(NULL, memc);
- memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
-
- rc= memcached_set(memc, "bubba", 5, "0", 1, 0, 0);
- test_true(rc == MEMCACHED_SUCCESS);
-
- /*
- ** We are using the quiet commands to store the replicas, so we need
- ** to ensure that all of them are processed before we can continue.
- ** In the test we go directly from storing the object to trying to
- ** receive the object from all of the different servers, so we
- ** could end up in a race condition (the memcached server hasn't yet
- ** processed the quiet command from the replication set when it process
- ** the request from the other client (created by the clone)). As a
- ** workaround for that we call memcached_quit to send the quit command
- ** to the server and wait for the response ;-) If you use the test code
- ** as an example for your own code, please note that you shouldn't need
- ** to do this ;-)
- */
- memcached_quit(memc);
-
- /*
- ** "bubba" should now be stored on all of our servers. We don't have an
- ** easy to use API to address each individual server, so I'll just iterate
- ** through a bunch of "master keys" and I should most likely hit all of the
- ** servers...
- */
- for (int x= 'a'; x <= 'z'; ++x)
- {
- char key[2]= { [0]= (char)x };
- size_t len;
- uint32_t flags;
- char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
- &len, &flags, &rc);
- test_true(rc == MEMCACHED_SUCCESS);
- test_true(val != NULL);
- free(val);
- }
-
- memcached_free(memc_clone);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t replication_get_test(memcached_st *memc)
-{
- memcached_return_t rc;
-
- /*
- * Don't do the following in your code. I am abusing the internal details
- * within the library, and this is not a supported interface.
- * This is to verify correct behavior in the library
- */
- for (uint32_t host= 0; host < memcached_server_count(memc); ++host)
- {
- memcached_st *memc_clone= memcached_clone(NULL, memc);
- memcached_server_instance_st instance=
- memcached_server_instance_by_position(memc_clone, host);
-
- ((memcached_server_write_instance_st)instance)->port= 0;
-
- for (int x= 'a'; x <= 'z'; ++x)
- {
- char key[2]= { [0]= (char)x };
- size_t len;
- uint32_t flags;
- char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
- &len, &flags, &rc);
- test_true(rc == MEMCACHED_SUCCESS);
- test_true(val != NULL);
- free(val);
- }
-
- memcached_free(memc_clone);
- }
-
- return TEST_SUCCESS;
-}
-
-static test_return_t replication_mget_test(memcached_st *memc)
-{
- memcached_return_t rc;
- memcached_st *memc_clone= memcached_clone(NULL, memc);
- memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
-
- const char *keys[]= { "bubba", "key1", "key2", "key3" };
- size_t len[]= { 5, 4, 4, 4 };
-
- for (size_t x= 0; x< 4; ++x)
- {
- rc= memcached_set(memc, keys[x], len[x], "0", 1, 0, 0);
- test_true(rc == MEMCACHED_SUCCESS);
- }
-
- /*
- ** We are using the quiet commands to store the replicas, so we need
- ** to ensure that all of them are processed before we can continue.
- ** In the test we go directly from storing the object to trying to
- ** receive the object from all of the different servers, so we
- ** could end up in a race condition (the memcached server hasn't yet
- ** processed the quiet command from the replication set when it process
- ** the request from the other client (created by the clone)). As a
- ** workaround for that we call memcached_quit to send the quit command
- ** to the server and wait for the response ;-) If you use the test code
- ** as an example for your own code, please note that you shouldn't need
- ** to do this ;-)
- */
- memcached_quit(memc);
-
- /*
- * Don't do the following in your code. I am abusing the internal details
- * within the library, and this is not a supported interface.
- * This is to verify correct behavior in the library
- */
- memcached_result_st result_obj;
- for (uint32_t host= 0; host < memc_clone->number_of_hosts; host++)
- {
- memcached_st *new_clone= memcached_clone(NULL, memc);
- memcached_server_instance_st instance=
- memcached_server_instance_by_position(new_clone, host);
- ((memcached_server_write_instance_st)instance)->port= 0;
-
- for (int x= 'a'; x <= 'z'; ++x)
- {
- char key[2]= { [0]= (char)x, [1]= 0 };
-
- rc= memcached_mget_by_key(new_clone, key, 1, keys, len, 4);
- test_true(rc == MEMCACHED_SUCCESS);
-
- memcached_result_st *results= memcached_result_create(new_clone, &result_obj);
- test_true(results);
-
- int hits= 0;
- while ((results= memcached_fetch_result(new_clone, &result_obj, &rc)) != NULL)
- {
- hits++;
- }
- test_true(hits == 4);
- memcached_result_free(&result_obj);
- }
-
- memcached_free(new_clone);
- }
-
- memcached_free(memc_clone);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t replication_randomize_mget_test(memcached_st *memc)
-{
- memcached_result_st result_obj;
- memcached_return_t rc;
- memcached_st *memc_clone= memcached_clone(NULL, memc);
- memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 3);
- memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, 1);
-
- const char *keys[]= { "key1", "key2", "key3", "key4", "key5", "key6", "key7" };
- size_t len[]= { 4, 4, 4, 4, 4, 4, 4 };
-
- for (size_t x= 0; x< 7; ++x)
- {
- rc= memcached_set(memc, keys[x], len[x], "1", 1, 0, 0);
- test_true(rc == MEMCACHED_SUCCESS);
- }
-
- memcached_quit(memc);
-
- for (size_t x= 0; x< 7; ++x)
- {
- const char key[2]= { [0]= (const char)x };
-
- rc= memcached_mget_by_key(memc_clone, key, 1, keys, len, 7);
- test_true(rc == MEMCACHED_SUCCESS);
-
- memcached_result_st *results= memcached_result_create(memc_clone, &result_obj);
- test_true(results);
-
- int hits= 0;
- while ((results= memcached_fetch_result(memc_clone, &result_obj, &rc)) != NULL)
- {
- ++hits;
- }
- test_true(hits == 7);
- memcached_result_free(&result_obj);
- }
- memcached_free(memc_clone);
- return TEST_SUCCESS;
-}
-
-static test_return_t replication_delete_test(memcached_st *memc)
-{
- memcached_return_t rc;
- memcached_st *memc_clone= memcached_clone(NULL, memc);
- /* Delete the items from all of the servers except 1 */
- uint64_t repl= memcached_behavior_get(memc,
- MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
- memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, --repl);
-
- const char *keys[]= { "bubba", "key1", "key2", "key3" };
- size_t len[]= { 5, 4, 4, 4 };
-
- for (size_t x= 0; x< 4; ++x)
- {
- rc= memcached_delete_by_key(memc, keys[0], len[0], keys[x], len[x], 0);
- test_true(rc == MEMCACHED_SUCCESS);
- }
-
- /*
- * Don't do the following in your code. I am abusing the internal details
- * within the library, and this is not a supported interface.
- * This is to verify correct behavior in the library
- */
- uint32_t hash= memcached_generate_hash(memc, keys[0], len[0]);
- for (uint32_t x= 0; x < (repl + 1); ++x)
- {
- memcached_server_instance_st instance=
- memcached_server_instance_by_position(memc_clone, x);
-
- ((memcached_server_write_instance_st)instance)->port= 0;
- if (++hash == memc_clone->number_of_hosts)
- hash= 0;
- }
-
- memcached_result_st result_obj;
- for (uint32_t host= 0; host < memc_clone->number_of_hosts; ++host)
- {
- for (size_t x= 'a'; x <= 'z'; ++x)
- {
- const char key[2]= { [0]= (const char)x };
-
- rc= memcached_mget_by_key(memc_clone, key, 1, keys, len, 4);
- test_true(rc == MEMCACHED_SUCCESS);
-
- memcached_result_st *results= memcached_result_create(memc_clone, &result_obj);
- test_true(results);
-
- int hits= 0;
- while ((results= memcached_fetch_result(memc_clone, &result_obj, &rc)) != NULL)
- {
- ++hits;
- }
- test_true(hits == 4);
- memcached_result_free(&result_obj);
- }
- }
- memcached_free(memc_clone);
-
- return TEST_SUCCESS;
-}
#if 0
static test_return_t hash_sanity_test (memcached_st *memc)
static test_return_t hsieh_avaibility_test (memcached_st *memc)
{
- memcached_return_t expected_rc= MEMCACHED_FAILURE;
+ memcached_return_t expected_rc= MEMCACHED_INVALID_ARGUMENTS;
#ifdef HAVE_HSIEH_HASH
expected_rc= MEMCACHED_SUCCESS;
#endif
static test_return_t murmur_avaibility_test (memcached_st *memc)
{
- memcached_return_t expected_rc= MEMCACHED_FAILURE;
+ memcached_return_t expected_rc= MEMCACHED_INVALID_ARGUMENTS;
#ifdef HAVE_MURMUR_HASH
expected_rc= MEMCACHED_SUCCESS;
#endif
{0, 0, 0}
};
+test_st basic_tests[] ={
+ {"init", 1, (test_callback_fn)basic_init_test},
+ {"clone", 1, (test_callback_fn)basic_clone_test},
+ {"reset", 1, (test_callback_fn)basic_reset_stack_test},
+ {"reset heap", 1, (test_callback_fn)basic_reset_heap_test},
+ {"reset stack clone", 1, (test_callback_fn)basic_reset_stack_clone_test},
+ {"reset heap clone", 1, (test_callback_fn)basic_reset_heap_clone_test},
+ {0, 0, 0}
+};
+
test_st regression_binary_vs_block[] ={
{"block add", 1, (test_callback_fn)block_add_regression},
{"binary add", 1, (test_callback_fn)binary_add_regression},
};
test_st error_conditions[] ={
- {"memcached_get_MEMCACHED_ERRNO", 0, (test_callback_fn)memcached_get_MEMCACHED_ERRNO },
- {"memcached_get_MEMCACHED_NOTFOUND", 0, (test_callback_fn)memcached_get_MEMCACHED_NOTFOUND },
- {"memcached_get_by_key_MEMCACHED_ERRNO", 0, (test_callback_fn)memcached_get_by_key_MEMCACHED_ERRNO },
- {"memcached_get_by_key_MEMCACHED_NOTFOUND", 0, (test_callback_fn)memcached_get_by_key_MEMCACHED_NOTFOUND },
+ {"memcached_get(MEMCACHED_ERRNO)", 0, (test_callback_fn)memcached_get_MEMCACHED_ERRNO },
+ {"memcached_get(MEMCACHED_NOTFOUND)", 0, (test_callback_fn)memcached_get_MEMCACHED_NOTFOUND },
+ {"memcached_get_by_key(MEMCACHED_ERRNO)", 0, (test_callback_fn)memcached_get_by_key_MEMCACHED_ERRNO },
+ {"memcached_get_by_key(MEMCACHED_NOTFOUND)", 0, (test_callback_fn)memcached_get_by_key_MEMCACHED_NOTFOUND },
+ {"memcached_get_by_key(MEMCACHED_NOTFOUND)", 0, (test_callback_fn)memcached_get_by_key_MEMCACHED_NOTFOUND },
+ {"memcached_increment(MEMCACHED_NO_SERVERS)", 0, (test_callback_fn)memcached_increment_MEMCACHED_NO_SERVERS },
+ {0, 0, (test_callback_fn)0}
+};
+
+
+test_st parser_tests[] ={
+ {"behavior", 0, (test_callback_fn)behavior_parser_test },
+ {"boolean_options", 0, (test_callback_fn)parser_boolean_options_test },
+ {"configure_file", 0, (test_callback_fn)memcached_create_with_options_with_filename },
+ {"distribtions", 0, (test_callback_fn)parser_distribution_test },
+ {"hash", 0, (test_callback_fn)parser_hash_test },
+ {"libmemcached_check_configuration", 0, (test_callback_fn)libmemcached_check_configuration_test },
+ {"libmemcached_check_configuration_with_filename", 0, (test_callback_fn)libmemcached_check_configuration_with_filename_test },
+ {"memcached_parse_configure_file", 0, (test_callback_fn)memcached_parse_configure_file_test },
+ {"number_options", 0, (test_callback_fn)parser_number_options_test },
+ {"randomly generated options", 0, (test_callback_fn)random_statement_build_test },
+ {"prefix_key", 0, (test_callback_fn)parser_key_prefix_test },
+ {"server", 0, (test_callback_fn)server_test },
+ {"servers", 0, (test_callback_fn)servers_test },
{0, 0, (test_callback_fn)0}
};
#if 0
{"hash_sanity", 0, 0, hash_sanity},
#endif
+ {"basic", 0, 0, basic_tests},
{"hsieh_availability", 0, 0, hsieh_availability},
{"murmur_availability", 0, 0, murmur_availability},
{"block", 0, 0, tests},
{"behaviors", 0, 0, behavior_tests},
{"regression_binary_vs_block", (test_callback_fn)key_setup, (test_callback_fn)key_teardown, regression_binary_vs_block},
{"error_conditions", 0, 0, error_conditions},
+ {"parser", 0, 0, parser_tests},
{0, 0, 0, 0}
};
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Gearmand client and server library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <vector>
+#include <iostream>
+#include <string>
+
+#include <libmemcached/memcached.h>
+
+#include "tests/parser.h"
+#include "tests/print.h"
+
+enum scanner_type_t
+{
+ NIL,
+ UNSIGNED,
+ SIGNED,
+ ARRAY
+};
+
+
+struct scanner_string_st {
+ const char *c_str;
+ size_t size;
+};
+
+static inline scanner_string_st scanner_string(const char *arg, size_t arg_size)
+{
+ scanner_string_st local= { arg, arg_size };
+ return local;
+}
+
+#define make_scanner_string(X) scanner_string((X), static_cast<size_t>(sizeof(X) - 1))
+
+static struct scanner_string_st scanner_string_null= { 0, 0};
+
+struct scanner_variable_t {
+ enum scanner_type_t type;
+ struct scanner_string_st option;
+ struct scanner_string_st result;
+ test_return_t (*check_func)(memcached_st *memc, const scanner_string_st &hostname);
+};
+
+// Check and make sure the first host is what we expect it to be
+static test_return_t __check_host(memcached_st *memc, const scanner_string_st &hostname)
+{
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(memc, 0);
+
+ test_true(instance);
+
+ const char *first_hostname = memcached_server_name(instance);
+ test_true(first_hostname);
+ test_strcmp(first_hostname, hostname.c_str);
+
+ return TEST_SUCCESS;
+}
+
+// Check and make sure the prefix_key is what we expect it to be
+static test_return_t __check_prefix_key(memcached_st *memc, const scanner_string_st &hostname)
+{
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(memc, 0);
+
+ test_true(instance);
+
+ const char *first_hostname = memcached_server_name(instance);
+ test_true(first_hostname);
+ test_strcmp(first_hostname, hostname.c_str);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t __check_IO_MSG_WATERMARK(memcached_st *memc, const scanner_string_st &value)
+{
+ uint64_t value_number;
+
+ value_number= atoll(value.c_str);
+
+ test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK) == value_number);
+ return TEST_SUCCESS;
+}
+
+static test_return_t __check_AUTO_EJECT_HOSTS(memcached_st *memc, const scanner_string_st &value)
+{
+ (void)value;
+ test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS));
+ return TEST_SUCCESS;
+}
+
+static test_return_t __check_CACHE_LOOKUPS(memcached_st *memc, const scanner_string_st &value)
+{
+ (void)value;
+ test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_CACHE_LOOKUPS));
+ return TEST_SUCCESS;
+}
+
+static test_return_t __check_NOREPLY(memcached_st *memc, const scanner_string_st &value)
+{
+ (void)value;
+ test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NOREPLY));
+ return TEST_SUCCESS;
+}
+
+static test_return_t __check_VERIFY_KEY(memcached_st *memc, const scanner_string_st &value)
+{
+ (void)value;
+ test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_VERIFY_KEY));
+ return TEST_SUCCESS;
+}
+
+static test_return_t __check_distribution_RANDOM(memcached_st *memc, const scanner_string_st &value)
+{
+ (void)value;
+ test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION) == MEMCACHED_DISTRIBUTION_RANDOM);
+ return TEST_SUCCESS;
+}
+
+scanner_variable_t test_server_strings[]= {
+ { ARRAY, make_scanner_string("--server=localhost"), make_scanner_string("localhost"), __check_host },
+ { ARRAY, make_scanner_string("--server=10.0.2.1"), make_scanner_string("10.0.2.1"), __check_host },
+ { ARRAY, make_scanner_string("--server=example.com"), make_scanner_string("example.com"), __check_host },
+ { ARRAY, make_scanner_string("--server=localhost:30"), make_scanner_string("localhost"), __check_host },
+ { ARRAY, make_scanner_string("--server=10.0.2.1:20"), make_scanner_string("10.0.2.1"), __check_host },
+ { ARRAY, make_scanner_string("--server=example.com:1024"), make_scanner_string("example.com"), __check_host },
+ { NIL, scanner_string_null, scanner_string_null, NULL }
+};
+
+scanner_variable_t test_servers_strings[]= {
+ { ARRAY, make_scanner_string("--servers=localhost:11221,localhost:11222,localhost:11223,localhost:11224,localhost:11225"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--servers=a.example.com:81,localhost:82,b.example.com"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--servers=localhost,localhost:80"), scanner_string_null, NULL },
+ { NIL, scanner_string_null, scanner_string_null, NULL}
+};
+
+
+scanner_variable_t bad_test_strings[]= {
+ { ARRAY, make_scanner_string("-servers=localhost:11221,localhost:11222,localhost:11223,localhost:11224,localhost:11225"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("-- servers=a.example.com:81,localhost:82,b.example.com"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--servers=localhost+80"), scanner_string_null, NULL},
+ { ARRAY, make_scanner_string("--servers=localhost.com."), scanner_string_null, NULL},
+ { ARRAY, make_scanner_string("--server=localhost.com."), scanner_string_null, NULL},
+ { ARRAY, make_scanner_string("--server=localhost.com.:80"), scanner_string_null, NULL},
+ { NIL, scanner_string_null, scanner_string_null, NULL}
+};
+
+scanner_variable_t test_number_options[]= {
+ { ARRAY, make_scanner_string("--CONNECT_TIMEOUT=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--IO_MSG_WATERMARK=456"), make_scanner_string("456"), __check_IO_MSG_WATERMARK },
+ { ARRAY, make_scanner_string("--IO_BYTES_WATERMARK=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--IO_KEY_PREFETCH=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--NUMBER_OF_REPLICAS=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--POLL_TIMEOUT=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--RCV_TIMEOUT=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--RETRY_TIMEOUT=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--SERVER_FAILURE_LIMIT=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--SND_TIMEOUT=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--SOCKET_RECV_SIZE=456"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--SOCKET_SEND_SIZE=456"), scanner_string_null, NULL },
+ { NIL, scanner_string_null, scanner_string_null, NULL}
+};
+
+scanner_variable_t test_boolean_options[]= {
+ { ARRAY, make_scanner_string("--AUTO_EJECT_HOSTS"), scanner_string_null, __check_AUTO_EJECT_HOSTS },
+ { ARRAY, make_scanner_string("--BINARY_PROTOCOL"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--BUFFER_REQUESTS"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--CACHE_LOOKUPS"), scanner_string_null, __check_CACHE_LOOKUPS },
+#if 0 // Not all platforms support
+ { ARRAY, make_scanner_string("--CORK"), scanner_string_null, NULL },
+#endif
+ { ARRAY, make_scanner_string("--HASH_WITH_PREFIX_KEY"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--KETAMA"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--KETAMA_WEIGHTED"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--NOREPLY"), scanner_string_null, __check_NOREPLY },
+ { ARRAY, make_scanner_string("--RANDOMIZE_REPLICA_READ"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--SORT_HOSTS"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--SUPPORT_CAS"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--TCP_NODELAY"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--TCP_KEEPALIVE"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--TCP_KEEPIDLE"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--USE_UDP"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--VERIFY_KEY"), scanner_string_null, __check_VERIFY_KEY },
+ { NIL, scanner_string_null, scanner_string_null, NULL}
+};
+
+scanner_variable_t prefix_key_strings[]= {
+ { ARRAY, make_scanner_string("--PREFIX_KEY=foo"), make_scanner_string("foo"), __check_prefix_key },
+ { ARRAY, make_scanner_string("--PREFIX-KEY=\"foo\""), make_scanner_string("foo"), __check_prefix_key },
+ { ARRAY, make_scanner_string("--PREFIX-KEY=\"This is a very long key\""), make_scanner_string("This is a very long key"), __check_prefix_key },
+ { NIL, scanner_string_null, scanner_string_null, NULL}
+};
+
+scanner_variable_t distribution_strings[]= {
+ { ARRAY, make_scanner_string("--DISTRIBUTION=consistent"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--DISTRIBUTION=random"), scanner_string_null, __check_distribution_RANDOM },
+ { ARRAY, make_scanner_string("--DISTRIBUTION=modula"), scanner_string_null, NULL },
+ { NIL, scanner_string_null, scanner_string_null, NULL}
+};
+
+scanner_variable_t hash_strings[]= {
+ { ARRAY, make_scanner_string("--HASH=CRC"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--HASH=FNV1A_32"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--HASH=FNV1A_64"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--HASH=FNV1_32"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--HASH=FNV1_64"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--HASH=JENKINS"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--HASH=MD5"), scanner_string_null, NULL },
+ { ARRAY, make_scanner_string("--HASH=MURMUR"), scanner_string_null, NULL },
+ { NIL, scanner_string_null, scanner_string_null, NULL}
+};
+
+
+static test_return_t _test_option(scanner_variable_t *scanner, bool test_true= true)
+{
+ (void)test_true;
+ memcached_st *memc;
+ memc= memcached_create(NULL);
+
+ for (scanner_variable_t *ptr= scanner; ptr->type != NIL; ptr++)
+ {
+ memcached_return_t rc;
+ rc= memcached_parse_configuration(memc, ptr->option.c_str, ptr->option.size);
+ if (test_true)
+ {
+ if (rc != MEMCACHED_SUCCESS)
+ memcached_error_print(memc);
+
+ test_true(rc == MEMCACHED_SUCCESS);
+
+ if (ptr->check_func)
+ {
+ (*ptr->check_func)(memc, ptr->result);
+ }
+ }
+ else
+ {
+ test_false_with(rc == MEMCACHED_SUCCESS, ptr->option.c_str);
+ }
+ memcached_reset(memc);
+ }
+ memcached_free(memc);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t server_test(memcached_st *junk)
+{
+ (void)junk;
+ return _test_option(test_server_strings);
+}
+
+test_return_t servers_test(memcached_st *junk)
+{
+ (void)junk;
+
+ test_return_t rc;
+ if ((rc= _test_option(test_server_strings)) != TEST_SUCCESS)
+ {
+ return rc;
+ }
+
+#if 0
+ memcached_server_fn callbacks[1];
+ callbacks[0]= server_print_callback;
+ memcached_server_cursor(memc, callbacks, NULL, 1);
+#endif
+
+ if ((rc= _test_option(bad_test_strings, false)) != TEST_SUCCESS)
+ {
+ return rc;
+ }
+
+ return TEST_SUCCESS;
+}
+
+test_return_t parser_number_options_test(memcached_st *junk)
+{
+ (void)junk;
+ return _test_option(test_number_options);
+}
+
+test_return_t parser_boolean_options_test(memcached_st *junk)
+{
+ (void)junk;
+ return _test_option(test_boolean_options);
+}
+
+test_return_t behavior_parser_test(memcached_st *junk)
+{
+ (void)junk;
+ return TEST_SUCCESS;
+}
+
+test_return_t parser_hash_test(memcached_st *junk)
+{
+ (void)junk;
+ return _test_option(hash_strings);
+}
+
+test_return_t parser_distribution_test(memcached_st *junk)
+{
+ (void)junk;
+ return _test_option(distribution_strings);
+}
+
+test_return_t parser_key_prefix_test(memcached_st *junk)
+{
+ (void)junk;
+ return _test_option(distribution_strings);
+}
+
+test_return_t memcached_parse_configure_file_test(memcached_st *junk)
+{
+ (void)junk;
+ memcached_st memc;
+ memcached_st *memc_ptr= memcached_create(&memc);
+
+ test_true(memc_ptr);
+
+ memcached_return_t rc= memcached_parse_configure_file(memc_ptr, memcached_string_with_size("support/example.cnf"));
+ test_true_got(rc == MEMCACHED_SUCCESS, memcached_last_error_message(memc_ptr) ? memcached_last_error_message(memc_ptr) : memcached_strerror(NULL, rc));
+ memcached_free(memc_ptr);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t memcached_create_with_options_with_filename(memcached_st *junk)
+{
+ (void)junk;
+
+ memcached_st *memc_ptr;
+ memc_ptr= memcached_create_with_options(STRING_WITH_LEN("--CONFIGURE-FILE=\"support/example.cnf\""));
+ test_true_got(memc_ptr, memcached_last_error_message(memc_ptr));
+ memcached_free(memc_ptr);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t libmemcached_check_configuration_with_filename_test(memcached_st *junk)
+{
+ (void)junk;
+ memcached_return_t rc;
+ char buffer[BUFSIZ];
+
+ rc= libmemcached_check_configuration(STRING_WITH_LEN("--CONFIGURE-FILE=\"support/example.cnf\""), buffer, sizeof(buffer));
+ test_true_got(rc == MEMCACHED_SUCCESS, buffer);
+
+ rc= libmemcached_check_configuration(STRING_WITH_LEN("--CONFIGURE-FILE=support/example.cnf"), buffer, sizeof(buffer));
+ test_false_with(rc == MEMCACHED_SUCCESS, buffer);
+
+ rc= libmemcached_check_configuration(STRING_WITH_LEN("--CONFIGURE-FILE=\"bad-path/example.cnf\""), buffer, sizeof(buffer));
+ test_true_got(rc == MEMCACHED_ERRNO, buffer);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t libmemcached_check_configuration_test(memcached_st *junk)
+{
+ (void)junk;
+
+ memcached_return_t rc;
+ char buffer[BUFSIZ];
+
+ rc= libmemcached_check_configuration(STRING_WITH_LEN("--server=localhost"), buffer, sizeof(buffer));
+ test_true_got(rc == MEMCACHED_SUCCESS, buffer);
+
+ rc= libmemcached_check_configuration(STRING_WITH_LEN("--dude=localhost"), buffer, sizeof(buffer));
+ test_false_with(rc == MEMCACHED_SUCCESS, buffer);
+ test_true(rc == MEMCACHED_PARSE_ERROR);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t memcached_create_with_options_test(memcached_st *junk)
+{
+ (void)junk;
+
+ memcached_st *memc_ptr;
+ memc_ptr= memcached_create_with_options(STRING_WITH_LEN("--server=localhost"));
+ test_true_got(memc_ptr, memcached_last_error_message(memc_ptr));
+ memcached_free(memc_ptr);
+
+ memc_ptr= memcached_create_with_options(STRING_WITH_LEN("--dude=localhost"));
+ test_false_with(memc_ptr, memcached_last_error_message(memc_ptr));
+
+ return TEST_SUCCESS;
+}
+
+test_return_t test_include_keyword(memcached_st *junk)
+{
+ (void)junk;
+ char buffer[BUFSIZ];
+ memcached_return_t rc;
+ rc= libmemcached_check_configuration(STRING_WITH_LEN("INCLUDE \"support/example.cnf\""), buffer, sizeof(buffer));
+ test_true_got(rc == MEMCACHED_SUCCESS, buffer);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t test_end_keyword(memcached_st *junk)
+{
+ (void)junk;
+ char buffer[BUFSIZ];
+ memcached_return_t rc;
+ rc= libmemcached_check_configuration(STRING_WITH_LEN("--server=localhost END bad keywords"), buffer, sizeof(buffer));
+ test_true_got(rc == MEMCACHED_SUCCESS, buffer);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t test_reset_keyword(memcached_st *junk)
+{
+ (void)junk;
+ char buffer[BUFSIZ];
+ memcached_return_t rc;
+ rc= libmemcached_check_configuration(STRING_WITH_LEN("--server=localhost reset --server=bad.com"), buffer, sizeof(buffer));
+ test_true_got(rc == MEMCACHED_SUCCESS, buffer);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t test_error_keyword(memcached_st *junk)
+{
+ (void)junk;
+ char buffer[BUFSIZ];
+ memcached_return_t rc;
+ rc= libmemcached_check_configuration(STRING_WITH_LEN("--server=localhost ERROR --server=bad.com"), buffer, sizeof(buffer));
+ test_true_got(rc != MEMCACHED_SUCCESS, buffer);
+
+ return TEST_SUCCESS;
+}
+
+#define RANDOM_STRINGS 50
+test_return_t random_statement_build_test(memcached_st *junk)
+{
+ (void)junk;
+ std::vector<scanner_string_st *> option_list;
+
+ for (scanner_variable_t *ptr= test_server_strings; ptr->type != NIL; ptr++)
+ option_list.push_back(&ptr->option);
+
+#if 0
+ for (scanner_variable_t *ptr= test_servers_strings; ptr->type != NIL; ptr++)
+ option_list.push_back(&ptr->option);
+#endif
+
+ for (scanner_variable_t *ptr= test_number_options; ptr->type != NIL; ptr++)
+ option_list.push_back(&ptr->option);
+
+ for (scanner_variable_t *ptr= test_boolean_options; ptr->type != NIL; ptr++)
+ option_list.push_back(&ptr->option);
+
+ for (scanner_variable_t *ptr= prefix_key_strings; ptr->type != NIL; ptr++)
+ option_list.push_back(&ptr->option);
+
+ for (scanner_variable_t *ptr= distribution_strings; ptr->type != NIL; ptr++)
+ option_list.push_back(&ptr->option);
+
+ for (scanner_variable_t *ptr= hash_strings; ptr->type != NIL; ptr++)
+ option_list.push_back(&ptr->option);
+
+ for (uint32_t x= 0; x < RANDOM_STRINGS; x++)
+ {
+ std::string random_options;
+
+ uint32_t number_of= random() % option_list.size();
+ for (uint32_t options= 0; options < number_of; options++)
+ {
+ random_options+= option_list[random() % option_list.size()]->c_str;
+ random_options+= " ";
+ }
+ random_options.resize(random_options.size() -1);
+
+ memcached_return_t rc;
+ memcached_st *memc_ptr= memcached_create(NULL);
+ rc= memcached_parse_configuration(memc_ptr, random_options.c_str(), random_options.size());
+ if (rc == MEMCACHED_PARSE_ERROR)
+ {
+ std::cerr << std::endl << "Failed to parse(" << memcached_strerror(NULL, rc) << "): " << random_options << std::endl;
+ memcached_error_print(memc_ptr);
+ }
+ memcached_free(memc_ptr);
+ }
+
+ return TEST_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Gearmand client and server library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <libtest/test.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBTEST_INTERNAL_API
+test_return_t server_test(memcached_st *memc);
+
+LIBTEST_INTERNAL_API
+test_return_t servers_test(memcached_st *memc);
+
+LIBTEST_INTERNAL_API
+test_return_t behavior_parser_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t parser_number_options_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t parser_distribution_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t parser_hash_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t parser_boolean_options_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t parser_key_prefix_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t memcached_parse_configure_file_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+ test_return_t libmemcached_check_configuration_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+ test_return_t memcached_create_with_options_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+ test_return_t memcached_create_with_options_with_filename(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+ test_return_t libmemcached_check_configuration_with_filename_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+ test_return_t random_statement_build_test(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t test_include_keyword(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t test_end_keyword(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t test_reset_keyword(memcached_st *junk);
+
+LIBTEST_INTERNAL_API
+test_return_t test_error_keyword(memcached_st *junk);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Gearmand client and server library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <iostream>
+
+#include <libmemcached/memcached.h>
+#include <libtest/test.h>
+
+#include "tests/print.h"
+
+memcached_return_t server_print_callback(const memcached_st *ptr,
+ const memcached_server_st *server,
+ void *context)
+{
+ (void)ptr;
+
+ if (context)
+ {
+ std::cerr << memcached_server_name(server) << ":" << memcached_server_port(server) << std::endl;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Gearmand client and server library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBTEST_INTERNAL_API
+memcached_return_t server_print_callback(const memcached_st *ptr,
+ const memcached_server_st *server,
+ void *context);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Gearmand client and server library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+#include <libtest/test.h>
+#include "libmemcached/common.h"
+#include <tests/replication.h>
+
+test_return_t replication_set_test(memcached_st *memc)
+{
+ memcached_return_t rc;
+ memcached_st *memc_clone= memcached_clone(NULL, memc);
+ memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
+
+ rc= memcached_set(memc, "bubba", 5, "0", 1, 0, 0);
+ test_true(rc == MEMCACHED_SUCCESS);
+
+ /*
+ ** We are using the quiet commands to store the replicas, so we need
+ ** to ensure that all of them are processed before we can continue.
+ ** In the test we go directly from storing the object to trying to
+ ** receive the object from all of the different servers, so we
+ ** could end up in a race condition (the memcached server hasn't yet
+ ** processed the quiet command from the replication set when it process
+ ** the request from the other client (created by the clone)). As a
+ ** workaround for that we call memcached_quit to send the quit command
+ ** to the server and wait for the response ;-) If you use the test code
+ ** as an example for your own code, please note that you shouldn't need
+ ** to do this ;-)
+ */
+ memcached_quit(memc);
+
+ /*
+ ** "bubba" should now be stored on all of our servers. We don't have an
+ ** easy to use API to address each individual server, so I'll just iterate
+ ** through a bunch of "master keys" and I should most likely hit all of the
+ ** servers...
+ */
+ for (int x= 'a'; x <= 'z'; ++x)
+ {
+ const char key[2]= { (char)x, 0 };
+ size_t len;
+ uint32_t flags;
+ char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
+ &len, &flags, &rc);
+ test_true(rc == MEMCACHED_SUCCESS);
+ test_true(val != NULL);
+ free(val);
+ }
+
+ memcached_free(memc_clone);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t replication_get_test(memcached_st *memc)
+{
+ memcached_return_t rc;
+
+ /*
+ * Don't do the following in your code. I am abusing the internal details
+ * within the library, and this is not a supported interface.
+ * This is to verify correct behavior in the library
+ */
+ for (uint32_t host= 0; host < memcached_server_count(memc); ++host)
+ {
+ memcached_st *memc_clone= memcached_clone(NULL, memc);
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(memc_clone, host);
+
+ ((memcached_server_write_instance_st)instance)->port= 0;
+
+ for (int x= 'a'; x <= 'z'; ++x)
+ {
+ const char key[2]= { (char)x, 0 };
+ size_t len;
+ uint32_t flags;
+ char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
+ &len, &flags, &rc);
+ test_true(rc == MEMCACHED_SUCCESS);
+ test_true(val != NULL);
+ free(val);
+ }
+
+ memcached_free(memc_clone);
+ }
+
+ return TEST_SUCCESS;
+}
+
+test_return_t replication_mget_test(memcached_st *memc)
+{
+ memcached_return_t rc;
+ memcached_st *memc_clone= memcached_clone(NULL, memc);
+ memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
+
+ const char *keys[]= { "bubba", "key1", "key2", "key3" };
+ size_t len[]= { 5, 4, 4, 4 };
+
+ for (size_t x= 0; x< 4; ++x)
+ {
+ rc= memcached_set(memc, keys[x], len[x], "0", 1, 0, 0);
+ test_true(rc == MEMCACHED_SUCCESS);
+ }
+
+ /*
+ ** We are using the quiet commands to store the replicas, so we need
+ ** to ensure that all of them are processed before we can continue.
+ ** In the test we go directly from storing the object to trying to
+ ** receive the object from all of the different servers, so we
+ ** could end up in a race condition (the memcached server hasn't yet
+ ** processed the quiet command from the replication set when it process
+ ** the request from the other client (created by the clone)). As a
+ ** workaround for that we call memcached_quit to send the quit command
+ ** to the server and wait for the response ;-) If you use the test code
+ ** as an example for your own code, please note that you shouldn't need
+ ** to do this ;-)
+ */
+ memcached_quit(memc);
+
+ /*
+ * Don't do the following in your code. I am abusing the internal details
+ * within the library, and this is not a supported interface.
+ * This is to verify correct behavior in the library
+ */
+ memcached_result_st result_obj;
+ for (uint32_t host= 0; host < memc_clone->number_of_hosts; host++)
+ {
+ memcached_st *new_clone= memcached_clone(NULL, memc);
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(new_clone, host);
+ ((memcached_server_write_instance_st)instance)->port= 0;
+
+ for (int x= 'a'; x <= 'z'; ++x)
+ {
+ char key[2]= { (char)x, 0 };
+
+ rc= memcached_mget_by_key(new_clone, key, 1, keys, len, 4);
+ test_true(rc == MEMCACHED_SUCCESS);
+
+ memcached_result_st *results= memcached_result_create(new_clone, &result_obj);
+ test_true(results);
+
+ int hits= 0;
+ while ((results= memcached_fetch_result(new_clone, &result_obj, &rc)) != NULL)
+ {
+ hits++;
+ }
+ test_true(hits == 4);
+ memcached_result_free(&result_obj);
+ }
+
+ memcached_free(new_clone);
+ }
+
+ memcached_free(memc_clone);
+
+ return TEST_SUCCESS;
+}
+
+test_return_t replication_randomize_mget_test(memcached_st *memc)
+{
+ memcached_result_st result_obj;
+ memcached_return_t rc;
+ memcached_st *memc_clone= memcached_clone(NULL, memc);
+ memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 3);
+ memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, 1);
+
+ const char *keys[]= { "key1", "key2", "key3", "key4", "key5", "key6", "key7" };
+ size_t len[]= { 4, 4, 4, 4, 4, 4, 4 };
+
+ for (size_t x= 0; x< 7; ++x)
+ {
+ rc= memcached_set(memc, keys[x], len[x], "1", 1, 0, 0);
+ test_true(rc == MEMCACHED_SUCCESS);
+ }
+
+ memcached_quit(memc);
+
+ for (size_t x= 0; x< 7; ++x)
+ {
+ const char key[2]= { (char)x, 0 };
+
+ rc= memcached_mget_by_key(memc_clone, key, 1, keys, len, 7);
+ test_true(rc == MEMCACHED_SUCCESS);
+
+ memcached_result_st *results= memcached_result_create(memc_clone, &result_obj);
+ test_true(results);
+
+ int hits= 0;
+ while ((results= memcached_fetch_result(memc_clone, &result_obj, &rc)) != NULL)
+ {
+ ++hits;
+ }
+ test_true(hits == 7);
+ memcached_result_free(&result_obj);
+ }
+ memcached_free(memc_clone);
+ return TEST_SUCCESS;
+}
+
+test_return_t replication_delete_test(memcached_st *memc)
+{
+ memcached_return_t rc;
+ memcached_st *memc_clone= memcached_clone(NULL, memc);
+ /* Delete the items from all of the servers except 1 */
+ uint64_t repl= memcached_behavior_get(memc,
+ MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
+ memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, --repl);
+
+ const char *keys[]= { "bubba", "key1", "key2", "key3" };
+ size_t len[]= { 5, 4, 4, 4 };
+
+ for (size_t x= 0; x< 4; ++x)
+ {
+ rc= memcached_delete_by_key(memc, keys[0], len[0], keys[x], len[x], 0);
+ test_true(rc == MEMCACHED_SUCCESS);
+ }
+
+ /*
+ * Don't do the following in your code. I am abusing the internal details
+ * within the library, and this is not a supported interface.
+ * This is to verify correct behavior in the library
+ */
+ uint32_t hash= memcached_generate_hash(memc, keys[0], len[0]);
+ for (uint32_t x= 0; x < (repl + 1); ++x)
+ {
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(memc_clone, x);
+
+ ((memcached_server_write_instance_st)instance)->port= 0;
+ if (++hash == memc_clone->number_of_hosts)
+ hash= 0;
+ }
+
+ memcached_result_st result_obj;
+ for (uint32_t host= 0; host < memc_clone->number_of_hosts; ++host)
+ {
+ for (size_t x= 'a'; x <= 'z'; ++x)
+ {
+ const char key[2]= { (char)x, 0 };
+
+ rc= memcached_mget_by_key(memc_clone, key, 1, keys, len, 4);
+ test_true(rc == MEMCACHED_SUCCESS);
+
+ memcached_result_st *results= memcached_result_create(memc_clone, &result_obj);
+ test_true(results);
+
+ int hits= 0;
+ while ((results= memcached_fetch_result(memc_clone, &result_obj, &rc)) != NULL)
+ {
+ ++hits;
+ }
+ test_true(hits == 4);
+ memcached_result_free(&result_obj);
+ }
+ }
+ memcached_free(memc_clone);
+
+ return TEST_SUCCESS;
+}
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Gearmand client and server library.
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBTEST_INTERNAL_API
+test_return_t replication_set_test(memcached_st *memc);
+
+LIBTEST_INTERNAL_API
+test_return_t replication_get_test(memcached_st *memc);
+
+LIBTEST_INTERNAL_API
+test_return_t replication_mget_test(memcached_st *memc);
+
+LIBTEST_INTERNAL_API
+test_return_t replication_delete_test(memcached_st *memc);
+
+LIBTEST_INTERNAL_API
+test_return_t replication_randomize_mget_test(memcached_st *memc);
+
+#ifdef __cplusplus
+}
+#endif