tests/c_sasl_test
tests/c_test
tests/cycle
+tests/failure
tests/hash_plus
tests/hashplus
tests/internals
.. c:type:: MEMCACHED_BEHAVIOR_RETRY_TIMEOUT
-When enabled a host which is problematic will only be checked for usage based on the amount of time set by this behavior.
+When enabled a host which is problematic will only be checked for usage based on the amount of time set by this behavior. The value is in seconds.
.. c:type:: MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY
case HASHKIT_HASH_CUSTOM:
case HASHKIT_HASH_MAX:
default:
-#ifdef HAVE_DEBUG
- fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n");
- fflush(stderr);
- assert(0);
-#endif
+ if (DEBUG)
+ {
+ fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n");
+ fflush(stderr);
+ assert(0);
+ }
break;
}
uint64_t data)
{
if (not ptr)
+ {
return MEMCACHED_INVALID_ARGUMENTS;
+ }
switch (flag)
{
ptr->flags.auto_eject_hosts= bool(data);
case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
- ptr->server_failure_limit= (uint32_t)data;
+ if (data == 0)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT requires a value greater then zero."));
+ }
+ ptr->server_failure_limit= uint32_t(data);
break;
case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
break;
case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
- ptr->retry_timeout= (int32_t)data;
+ if (data == 0)
+ {
+ return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("MEMCACHED_BEHAVIOR_RETRY_TIMEOUT requires a value greater then zero."));
+ }
+ ptr->retry_timeout= int32_t(data);
break;
case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
{
ptr->ketama.weighted= false;
}
+
ptr->distribution= type;
run_distribution(ptr);
+
return MEMCACHED_SUCCESS;
}
#define memcached_server_response_decrement(A) (A)->cursor_active--
#define memcached_server_response_reset(A) (A)->cursor_active=0
-LIBMEMCACHED_LOCAL
-void set_last_disconnected_host(memcached_server_write_instance_st ptr);
-
#ifdef __cplusplus
LIBMEMCACHED_LOCAL
memcached_return_t memcached_key_test(const memcached_st& memc,
#include <libmemcached/common.h>
+
+#include <cassert>
#include <ctime>
#include <sys/time.h>
static memcached_return_t unix_socket_connect(memcached_server_st *server)
{
#ifndef WIN32
- WATCHPOINT_ASSERT(server->fd == -1);
+ WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
if ((server->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
WATCHPOINT_ASSERT(server->cursor_active == 0);
- if (not server->address_info)
+ if (server->address_info == NULL or server->address_info_next == NULL)
{
WATCHPOINT_ASSERT(server->state == MEMCACHED_SERVER_STATE_NEW);
memcached_return_t rc;
}
if (memcached_failed(rc))
+ {
return rc;
+ }
}
/* Create the socket */
- while (server->address_info_next && server->fd == INVALID_SOCKET)
+ while (server->address_info_next and server->fd == INVALID_SOCKET)
{
/* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
if (server->type == MEMCACHED_CONNECTION_UDP && server->address_info_next->ai_family != AF_INET)
}
WATCHPOINT_STRING("Never got a good file descriptor");
- /* Failed to connect. schedule next retry */
- if (server->root->retry_timeout)
- {
- struct timeval next_time;
-
- if (gettimeofday(&next_time, NULL) == 0)
- {
- server->next_retry= next_time.tv_sec + server->root->retry_timeout;
- }
- }
if (memcached_has_current_error(*server))
{
return memcached_set_error(*server, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT); /* The last error should be from connect() */
}
-void set_last_disconnected_host(memcached_server_write_instance_st self)
-{
- // const_cast
- memcached_st *root= (memcached_st *)self->root;
- memcached_server_free(root->last_disconnected_server);
- root->last_disconnected_server= memcached_server_clone(NULL, self);
-}
+/*
+ backoff_handling()
-memcached_return_t memcached_connect(memcached_server_write_instance_st server)
+ Based on time/failure count fail the connect without trying. This prevents waiting in a state where
+ we get caught spending cycles just waiting.
+*/
+static memcached_return_t backoff_handling(memcached_server_write_instance_st server, bool& in_timeout)
{
- memcached_return_t rc= MEMCACHED_NO_SERVERS;
+ /*
+ If we hit server_failure_limit then something is completely wrong about the server.
- if (server->fd != INVALID_SOCKET)
+ 1) If autoeject is enabled we do that.
+ 2) If not? We go into timeout again, there is much else to do :(
+ */
+ if (server->server_failure_counter >= server->root->server_failure_limit)
{
- return MEMCACHED_SUCCESS;
- }
-
- LIBMEMCACHED_MEMCACHED_CONNECT_START();
-
- /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */
- WATCHPOINT_ASSERT(server->root);
- if (server->root->retry_timeout and server->next_retry)
- {
- struct timeval curr_time;
-
- gettimeofday(&curr_time, NULL);
-
- // We should optimize this to remove the allocation if the server was
- // the last server to die
- if (server->next_retry > curr_time.tv_sec)
+ /*
+ We just auto_eject if we hit this point
+ */
+ if (_is_auto_eject_host(server->root))
{
set_last_disconnected_host(server);
+ run_distribution((memcached_st *)server->root);
return memcached_set_error(*server, MEMCACHED_SERVER_MARKED_DEAD, MEMCACHED_AT);
}
+
+ server->state= MEMCACHED_SERVER_STATE_IN_TIMEOUT;
+
+ // Sanity check/setting
+ if (server->next_retry == 0)
+ {
+ server->next_retry= 1;
+ }
}
- // If we are over the counter failure, we just fail. Reject host only
- // works if you have a set number of failures.
- if (server->root->server_failure_limit and server->server_failure_counter >= server->root->server_failure_limit)
+ if (server->state == MEMCACHED_SERVER_STATE_IN_TIMEOUT)
{
- set_last_disconnected_host(server);
+ struct timeval curr_time;
+ bool _gettime_success= (gettimeofday(&curr_time, NULL) == 0);
- // @todo fix this by fixing behavior to no longer make use of
- // memcached_st
- if (_is_auto_eject_host(server->root))
+ /*
+ If next_retry is less then our current time, then we reset and try everything again.
+ */
+ if (_gettime_success and server->next_retry < curr_time.tv_sec)
{
- run_distribution((memcached_st *)server->root);
+ server->state= MEMCACHED_SERVER_STATE_NEW;
+ }
+ else
+ {
+ return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT);
}
- return memcached_set_error(*server, MEMCACHED_SERVER_MARKED_DEAD, MEMCACHED_AT);
+ in_timeout= true;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_connect(memcached_server_write_instance_st server)
+{
+ if (server->fd != INVALID_SOCKET)
+ {
+ return MEMCACHED_SUCCESS;
+ }
+
+ LIBMEMCACHED_MEMCACHED_CONNECT_START();
+
+ bool in_timeout= false;
+ memcached_return_t rc;
+ if (memcached_failed(rc= backoff_handling(server, in_timeout)))
+ {
+ set_last_disconnected_host(server);
+ return rc;
}
/* We need to clean up the multi startup piece */
case MEMCACHED_CONNECTION_UDP:
case MEMCACHED_CONNECTION_TCP:
rc= network_connect(server);
+
if (LIBMEMCACHED_WITH_SASL_SUPPORT)
{
if (server->fd != INVALID_SOCKET and server->root->sasl.callbacks)
if (memcached_success(rc))
{
- server->server_failure_counter= 0;
- server->next_retry= 0;
+ memcached_mark_server_as_clean(server);
+ return rc;
}
- else if (memcached_has_current_error(*server))
+
+ set_last_disconnected_host(server);
+ if (memcached_has_current_error(*server))
{
- server->server_failure_counter++;
- set_last_disconnected_host(server);
+ memcached_mark_server_for_timeout(server);
+ assert(memcached_failed(memcached_server_error_return(server)));
}
else
{
memcached_set_error(*server, rc, MEMCACHED_AT);
- server->server_failure_counter++;
- set_last_disconnected_host(server);
+ memcached_mark_server_for_timeout(server);
}
LIBMEMCACHED_MEMCACHED_CONNECT_END();
+ if (in_timeout)
+ {
+ return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT);
+ }
+
return rc;
}
#define MEMCACHED_EXPIRATION_NOT_ADD 0xffffffffU
#define MEMCACHED_VERSION_STRING_LENGTH 24
#define MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH 20
+#define MEMCACHED_SERVER_FAILURE_LIMIT 2
+#define MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT 2
enum memcached_server_distribution_t {
{
rc= memcached_connect(instance);
if (memcached_failed(rc))
+ {
continue;
+ }
}
protocol_binary_request_getk request= { }; //= {.bytes= {0}};
server += start;
while (server >= memcached_server_count(ptr))
+ {
server -= memcached_server_count(ptr);
+ }
if (dead_servers[server])
+ {
continue;
+ }
memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server);
if (memcached_server_response_count(instance) == 0)
{
rc= memcached_connect(instance);
+
if (memcached_failed(rc))
{
memcached_io_reset(instance);
{
struct timeval now;
- if (gettimeofday(&now, NULL) == 0 &&
+ if (gettimeofday(&now, NULL) == 0 and
now.tv_sec > ptr->ketama.next_distribution_rebuild)
{
run_distribution(ptr);
}
else
{
- if (ptr->ketama.next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->ketama.next_distribution_rebuild)
+ if (ptr->ketama.next_distribution_rebuild == 0 or list[host_index].next_retry < ptr->ketama.next_distribution_rebuild)
{
ptr->ketama.next_distribution_rebuild= list[host_index].next_retry;
}
sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server));
if (new_ptr == 0)
+ {
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+ }
ptr->ketama.continuum= new_ptr;
ptr->ketama.continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
{
for (uint32_t host_index = 0; host_index < memcached_server_count(ptr); ++host_index)
{
- if (! is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
+ if (is_auto_ejecting == false or list[host_index].next_retry <= now.tv_sec)
{
total_weight += list[host_index].weight;
}
for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
{
- if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec)
+ if (is_auto_ejecting and list[host_index].next_retry > now.tv_sec)
+ {
continue;
+ }
if (is_ketama_weighted)
{
- float pct = (float)list[host_index].weight / (float)total_weight;
+ float pct= (float)list[host_index].weight / (float)total_weight;
pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
pointer_per_hash= 4;
-#ifdef DEBUG
- printf("ketama_weighted:%s|%d|%llu|%u\n",
- list[host_index].hostname,
- list[host_index].port,
- (unsigned long long)list[host_index].weight,
- pointer_per_server);
-#endif
+ if (DEBUG)
+ {
+ printf("ketama_weighted:%s|%d|%llu|%u\n",
+ list[host_index].hostname,
+ list[host_index].port,
+ (unsigned long long)list[host_index].weight,
+ pointer_per_server);
+ }
}
return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
}
-#ifdef DEBUG
- printf("update_continuum: key is %s\n", sort_host);
-#endif
+
+ if (DEBUG)
+ {
+ fprintf(stdout, "update_continuum: key is %s\n", sort_host);
+ }
+
if (is_ketama_weighted)
{
for (uint32_t x= 0; x < pointer_per_hash; x++)
ptr->ketama.continuum_points_counter= pointer_counter;
qsort(ptr->ketama.continuum, ptr->ketama.continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
-#ifdef DEBUG
- for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
+ if (DEBUG)
{
- WATCHPOINT_ASSERT(ptr->ketama.continuum[pointer_index].value <= ptr->ketama.continuum[pointer_index + 1].value);
+ for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
+ {
+ WATCHPOINT_ASSERT(ptr->ketama.continuum[pointer_index].value <= ptr->ketama.continuum[pointer_index + 1].value);
+ }
}
-#endif
return MEMCACHED_SUCCESS;
}
}
}
- ptr->server_failure_counter= 0;
*nread = (ssize_t)(buffer_ptr - (char*)buffer);
+
return MEMCACHED_SUCCESS;
}
self->distribution= MEMCACHED_DISTRIBUTION_MODULA;
if (not hashkit_create(&self->hashkit))
+ {
return false;
+ }
+
+ self->server_info.version= 0;
self->ketama.continuum= NULL;
self->ketama.continuum_count= 0;
self->snd_timeout= 0;
self->rcv_timeout= 0;
- self->server_failure_limit= 0;
+ self->server_failure_limit= MEMCACHED_SERVER_FAILURE_LIMIT;
self->query_id= 1; // 0 is considered invalid
/* TODO, Document why we picked these defaults */
self->io_key_prefetch= 0;
self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
- self->retry_timeout= 0;
+ self->retry_timeout= MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT;
self->send_size= -1;
self->recv_size= -1;
memcached_server_free(ptr->last_disconnected_server);
if (ptr->on_cleanup)
+ {
ptr->on_cleanup(ptr);
+ }
libmemcached_free(ptr, ptr->ketama.continuum);
memcached_set_processing_input(ptr, false);
#endif
- if (! _memcached_init(ptr))
+ if (_memcached_init(ptr) == false)
{
memcached_free(ptr);
return NULL;
}
- if (! memcached_result_create(ptr, &ptr->result))
+ if (memcached_result_create(ptr, &ptr->result) == NULL)
{
memcached_free(ptr);
return NULL;
}
if (not length)
+ {
return self;
+ }
memcached_return_t rc= memcached_parse_configuration(self, string, length);
{
WATCHPOINT_ASSERT(ptr);
if (not ptr)
+ {
return MEMCACHED_INVALID_ARGUMENTS;
+ }
bool stored_is_allocated= memcached_is_allocated(ptr);
uint64_t query_id= ptr->query_id;
void memcached_servers_reset(memcached_st *self)
{
- if (not self)
- return;
-
- memcached_server_list_free(memcached_server_list(self));
+ if (self)
+ {
+ memcached_server_list_free(memcached_server_list(self));
- memcached_server_list_set(self, NULL);
- self->number_of_hosts= 0;
- memcached_server_free(self->last_disconnected_server);
- self->last_disconnected_server= NULL;
- self->server_failure_limit= 0;
+ memcached_server_list_set(self, NULL);
+ self->number_of_hosts= 0;
+ memcached_server_free(self->last_disconnected_server);
+ self->last_disconnected_server= NULL;
+ }
}
void memcached_reset_last_disconnected_server(memcached_st *self)
{
- if (not self)
- return;
-
- memcached_server_free(self->last_disconnected_server);
- self->last_disconnected_server= NULL;
+ if (self)
+ {
+ memcached_server_free(self->last_disconnected_server);
+ self->last_disconnected_server= NULL;
+ }
}
void memcached_free(memcached_st *ptr)
{
- if (not ptr)
- return;
-
- _free(ptr, true);
+ if (ptr)
+ {
+ _free(ptr, true);
+ }
}
/*
new_clone->tcp_keepidle= source->tcp_keepidle;
if (memcached_server_count(source))
+ {
rc= memcached_push(new_clone, source);
+ }
- if (rc != MEMCACHED_SUCCESS)
+ if (memcached_failed(rc))
{
memcached_free(new_clone);
if (LIBMEMCACHED_WITH_SASL_SUPPORT and source->sasl.callbacks)
{
- if (memcached_clone_sasl(new_clone, source) != MEMCACHED_SUCCESS)
+ if (memcached_failed(memcached_clone_sasl(new_clone, source)))
{
memcached_free(new_clone);
return NULL;
}
}
- rc= run_distribution(new_clone);
-
- if (rc != MEMCACHED_SUCCESS)
+ if (memcached_failed(run_distribution(new_clone)))
{
memcached_free(new_clone);
}
if (source->on_clone)
+ {
source->on_clone(new_clone, source);
+ }
return new_clone;
}
memcached_server_distribution_t distribution;
hashkit_st hashkit;
+ struct {
+ unsigned int version;
+ } server_info;
uint32_t number_of_hosts;
memcached_server_st *servers;
memcached_server_st *last_disconnected_server;
if (io_death)
{
- ptr->server_failure_counter++;
- set_last_disconnected_host(ptr);
+ memcached_mark_server_for_timeout(ptr);
}
}
MEMCACHED_PARSE_USER_ERROR,
MEMCACHED_DEPRECATED,
MEMCACHED_IN_PROGRESS,
+ MEMCACHED_SERVER_TEMPORARILY_DISABLED,
MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */
};
self->address_info_next= NULL;
self->state= MEMCACHED_SERVER_STATE_NEW;
+ self->next_retry= 0;
+ self->root= root;
if (root)
{
- self->next_retry= root->retry_timeout;
+ self->version= ++root->server_info.version;
}
else
{
- self->next_retry= 0;
+ self->version= UINT_MAX;
}
-
- self->root= root;
self->limit_maxbytes= 0;
memcpy(self->hostname, hostname.c_str, hostname.size);
self->hostname[hostname.size]= 0;
MEMCACHED_SERVER_STATE_NEW, // fd == -1, no address lookup has been done
MEMCACHED_SERVER_STATE_ADDRINFO, // ADDRRESS information has been gathered
MEMCACHED_SERVER_STATE_IN_PROGRESS,
- MEMCACHED_SERVER_STATE_CONNECTED
+ MEMCACHED_SERVER_STATE_CONNECTED,
+ MEMCACHED_SERVER_STATE_IN_TIMEOUT
};
struct memcached_server_st {
uint32_t io_bytes_sent; /* # bytes sent since last read */
uint32_t server_failure_counter;
uint32_t weight;
+ uint32_t version;
enum memcached_server_state_t state;
struct {
uint32_t read;
#include <libmemcached/basic_string.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <cassert>
+
static inline bool memcached_is_valid_servername(const memcached_string_t& arg)
{
return arg.size > 0 or arg.size < NI_MAXHOST;
}
+static inline void memcached_mark_server_as_clean(memcached_server_write_instance_st server)
+{
+ server->server_failure_counter= 0;
+ server->next_retry= 0;
+}
+
+
+static inline void set_last_disconnected_host(memcached_server_write_instance_st self)
+{
+ assert(self->root);
+ if (self->root == NULL)
+ {
+ return;
+ }
+
+ if (self->root->last_disconnected_server and self->root->last_disconnected_server->version == self->version)
+ {
+ return;
+ }
+
+ // const_cast
+ memcached_st *root= (memcached_st *)self->root;
+
+ memcached_server_free(root->last_disconnected_server);
+ root->last_disconnected_server= memcached_server_clone(NULL, self);
+ root->last_disconnected_server->version= self->version;
+}
+
+static inline void memcached_mark_server_for_timeout(memcached_server_write_instance_st server)
+{
+ if (server->state != MEMCACHED_SERVER_STATE_IN_TIMEOUT)
+ {
+ struct timeval next_time;
+ if (gettimeofday(&next_time, NULL) == 0)
+ {
+ server->next_retry= next_time.tv_sec +server->root->retry_timeout;
+ }
+ else
+ {
+ server->next_retry= 1; // Setting the value to 1 causes the timeout to occur immediatly
+ }
+
+ server->state= MEMCACHED_SERVER_STATE_IN_TIMEOUT;
+ server->server_failure_counter++;
+ set_last_disconnected_host(server);
+ }
+}
+
LIBMEMCACHED_LOCAL
memcached_server_st *__server_create_with(memcached_st *memc,
memcached_server_write_instance_st host,
memcached_server_st *memcached_server_list(const memcached_st *self)
{
- return self->servers;
+ if (self)
+ {
+ return self->servers;
+ }
+
+ return NULL;
}
void memcached_server_list_set(memcached_st *self, memcached_server_st *list)
case MEMCACHED_IN_PROGRESS:
return "OPERATION IN PROCESS";
+ case MEMCACHED_SERVER_TEMPORARILY_DISABLED:
+ return "SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY";
+
default:
case MEMCACHED_MAXIMUM_RETURN:
return "INVALID memcached_return_t";
<< got_str
<< "\"";
}
-#if (defined(HAVE_LIBMEMCACHED) && HAVE_LIBMEMCACHED)
+#if defined(HAVE_LIBMEMCACHED) && HAVE_LIBMEMCACHED
else if (typeid(__expected) == typeid(memcached_return_t))
{
libtest::stream::make_cerr(file, line, func) << "Expected \""
{
if (__expected != __actual)
{
- libtest::stream::make_cerr(file, line, func) << "Expected \"" << __expected << "\" got \"" << __actual << "\" Additionally: \"" << __hint << "\"";
+ if (typeid(__expected) == typeid(test_return_t))
+ {
+ const char *expected_str= test_strerror(test_return_t(__expected));
+ const char *got_str= test_strerror(test_return_t(__actual));
+ libtest::stream::make_cerr(file, line, func) << "Expected \""
+ << expected_str
+ << "\" got \""
+ << got_str
+ << "\""
+ << " Additionally: \"" << __hint << "\"";
+ }
+#if defined(HAVE_LIBMEMCACHED) && HAVE_LIBMEMCACHED
+ else if (typeid(__expected) == typeid(memcached_return_t))
+ {
+ libtest::stream::make_cerr(file, line, func) << "Expected \""
+ << memcached_strerror(NULL, memcached_return_t(__expected))
+ << "\" got \""
+ << memcached_strerror(NULL, memcached_return_t(__actual)) << "\""
+ << " Additionally: \"" << __hint << "\"";
+ }
+#endif
+#if defined(HAVE_LIBGEARMAN) && HAVE_LIBGEARMAN
+ else if (typeid(__expected) == typeid(gearman_return_t))
+ {
+ libtest::stream::make_cerr(file, line, func) << "Expected \""
+ << gearman_strerror(gearman_return_t(__expected))
+ << "\" got \""
+ << gearman_strerror(gearman_return_t(__actual)) << "\""
+ << " Additionally: \"" << __hint << "\"";
+ }
+#endif
+ else
+ {
+ libtest::stream::make_cerr(file, line, func) << "Expected \"" << __expected << "\" got \"" << __actual << "\""
+ << " Additionally: \"" << __hint << "\"";
+ }
return false;
}
{
_servers.set_sasl(username_arg, password_arg);
}
+
+ libtest::server_startup_st& servers()
+ {
+ return _servers;
+ }
/**
Runner represents the callers for the tests. If not implemented we will use
return tmp;
}
-void server_startup_st::shutdown(bool remove)
+bool server_startup_st::shutdown(uint32_t number_of_host)
{
- if (remove)
+ assert(servers.size() > number_of_host);
+ if (servers.size() > number_of_host)
{
- for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
+ Server* tmp= servers[number_of_host];
+
+ if (tmp and tmp->has_pid() and not tmp->kill(tmp->pid()))
+ { }
+ else
{
- delete *iter;
+ return true;
}
- servers.clear();
}
- else
+
+ return false;
+}
+
+void server_startup_st::shutdown_and_remove()
+{
+ for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
{
- for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
+ delete *iter;
+ }
+ servers.clear();
+}
+
+void server_startup_st::shutdown()
+{
+ for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
+ {
+ if ((*iter)->has_pid() and not (*iter)->kill((*iter)->pid()))
{
- if ((*iter)->has_pid() and not (*iter)->kill((*iter)->pid()))
- {
- Error << "Unable to kill:" << *(*iter);
- }
+ Error << "Unable to kill:" << *(*iter);
}
}
}
+void server_startup_st::restart()
+{
+ for (std::vector<Server *>::iterator iter= servers.begin(); iter != servers.end(); iter++)
+ {
+ (*iter)->start();
+ }
+}
+
server_startup_st::~server_startup_st()
{
- shutdown(true);
+ shutdown_and_remove();
}
bool server_startup_st::is_debug() const
std::string server_list;
bool _socket;
bool _sasl;
+ uint32_t _count;
std::string _username;
std::string _password;
server_startup_st() :
_socket(false),
_sasl(false),
+ _count(5),
udp(0)
{ }
bool start_socket_server(const std::string& server_type, const in_port_t try_port, int argc, const char *argv[]);
- std::string option_string() const;
+ uint32_t count() const
+ {
+ return _count;
+ }
- size_t count() const
+ void set_count(uint32_t arg)
{
- return servers.size();
+ _count= arg;
}
+ void restart();
+
+ std::string option_string() const;
+
const std::string& password() const
{
return _password;
}
- void shutdown(bool remove= false);
+ void shutdown_and_remove();
+ void shutdown();
+ bool shutdown(uint32_t number_of_host);
+
void push_server(Server *);
Server *pop_server();
# Debugging. No optimization.
AM_CFLAGS="${AM_CFLAGS} ${DEBUG_CFLAGS} -DDEBUG"
AM_CXXFLAGS="${AM_CXXFLAGS} ${DEBUG_CXXFLAGS} -DDEBUG"
+ AC_DEFINE(DEBUG, [ 1 ], [Define to 1 to enable debugging code.])
],[
# Optimized version. No debug
AM_CFLAGS="${AM_CFLAGS} ${OPTIMIZE_CFLAGS}"
AM_CXXFLAGS="${AM_CXXFLAGS} ${OPTIMIZE_CXXFLAGS}"
+ AC_DEFINE(DEBUG, [ 0 ], [Define to 1 to enable debugging code.])
])
])
#define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT +10
-#define SERVERS_TO_CREATE 5
#include "libmemcached_world.h"
--- /dev/null
+/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ *
+ * Libmemcached library
+ *
+ * Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * The names of its contributors may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+
+/*
+ C++ interface test
+*/
+#include <libmemcached/memcached.hpp>
+#include <libmemcached/server_instance.h>
+#include <libtest/test.hpp>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctime>
+
+#include <string>
+#include <iostream>
+
+using namespace std;
+using namespace memcache;
+using namespace libtest;
+
+Framework *global_framework= NULL;
+
+static test_return_t shutdown_servers(memcached_st *memc)
+{
+ test_compare(memcached_server_count(memc), 1U);
+
+ // Disable a single server, just the first
+ global_framework->servers().shutdown(0);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t restart_servers(memcached_st *)
+{
+ // Restart the servers
+ global_framework->servers().restart();
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t cull_TEST(memcached_st *memc)
+{
+ uint32_t count= memcached_server_count(memc);
+
+ // Do not do this in your code, it is not supported.
+ memc->servers[0].options.is_dead= true;
+ memc->state.is_time_for_rebuild= true;
+
+ uint32_t new_count= memcached_server_count(memc);
+ test_compare(count, new_count);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t MEMCACHED_SERVER_TEMPORARILY_DISABLED_TEST(memcached_st *memc)
+{
+ test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 30));
+ test_compare_got(MEMCACHED_CONNECTION_FAILURE,
+ memcached_set(memc,
+ test_literal_param("foo"),
+ NULL, 0, time_t(0), uint32_t(0)),
+ memcached_last_error_message(memc));
+
+ /*
+ Setting server_failure_counter==0 should not influence the timeout that we set above,
+ since we check the timeout that is created by the failure before we check how many times
+ a server has failed.
+ */
+ test_compare(MEMCACHED_SERVER_TEMPORARILY_DISABLED,
+ memcached_set(memc, test_literal_param("foo"), NULL, 0, time_t(0), uint32_t(0)));
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t MEMCACHED_SERVER_TEMPORARILY_DISABLED_to_success_TEST(memcached_st *memc)
+{
+ test_compare_got(MEMCACHED_CONNECTION_FAILURE,
+ memcached_set(memc,
+ test_literal_param("foo"),
+ NULL, 0, time_t(0), uint32_t(0)),
+ memcached_last_error_message(memc));
+
+ /*
+ Setting server_failure_counter==0 should not influence the timeout that we set above,
+ since we check the timeout that is created by the failure before we check how many times
+ a server has failed.
+ */
+ test_compare(MEMCACHED_SERVER_TEMPORARILY_DISABLED,
+ memcached_set(memc, test_literal_param("foo"), NULL, 0, time_t(0), uint32_t(0)));
+
+ global_framework->servers().restart();
+
+ memcached_return_t ret;
+ do {
+ sleep(3);
+ ret= memcached_set(memc, test_literal_param("foo"), NULL, 0, time_t(0), uint32_t(0));
+ } while (ret == MEMCACHED_SERVER_TEMPORARILY_DISABLED);
+
+ test_compare_got(MEMCACHED_SUCCESS, ret, memcached_last_error_message(memc));
+
+ return TEST_SUCCESS;
+}
+
+test_st cull_TESTS[] ={
+ { "cull servers", true, (test_callback_fn*)cull_TEST },
+ { 0, 0, 0 }
+};
+
+test_st server_temporarily_disabled_TESTS[] ={
+ { "memcached_set(MEMCACHED_SERVER_TEMPORARILY_DISABLED)", true, (test_callback_fn*)MEMCACHED_SERVER_TEMPORARILY_DISABLED_TEST },
+ { "memcached_set(MEMCACHED_SERVER_TEMPORARILY_DISABLED -> MEMCACHED_SUCCESS)", true, (test_callback_fn*)MEMCACHED_SERVER_TEMPORARILY_DISABLED_to_success_TEST },
+ { 0, 0, 0 }
+};
+
+collection_st collection[] ={
+ { "cull", (test_callback_fn*)shutdown_servers, (test_callback_fn*)restart_servers, cull_TESTS },
+ { "server failed", (test_callback_fn*)shutdown_servers, (test_callback_fn*)restart_servers, server_temporarily_disabled_TESTS },
+ { 0, 0, 0, 0 }
+};
+
+#define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT +10
+#include "libmemcached_world.h"
+
+void get_world(Framework *world)
+{
+ world->servers().set_count(1);
+
+ world->collections= collection;
+
+ world->_create= (test_callback_create_fn*)world_create;
+ world->_destroy= (test_callback_destroy_fn*)world_destroy;
+
+ world->item._startup= (test_callback_fn*)world_test_startup;
+ world->item.set_pre((test_callback_fn*)world_pre_run);
+ world->item.set_flush((test_callback_fn*)world_flush);
+ world->item.set_post((test_callback_fn*)world_post_run);
+ world->_on_error= (test_callback_error_fn*)world_on_error;
+
+ world->collection_startup= (test_callback_fn*)world_container_startup;
+ world->collection_shutdown= (test_callback_fn*)world_container_shutdown;
+
+ world->set_runner(&defualt_libmemcached_runner);
+
+ global_framework= world;
+}
check_PROGRAMS+= tests/testplus
noinst_PROGRAMS+= tests/testplus
+tests_failure_SOURCES= tests/failure.cc
+tests_failure_CXXFLAGS = $(AM_CXXFLAGS)
+tests_failure_DEPENDENCIES= $(TESTS_LDADDS)
+tests_failure_LDADD= $(tests_failure_DEPENDENCIES)
+check_PROGRAMS+= tests/failure
+noinst_PROGRAMS+= tests/failure
+
tests_atomsmasher_SOURCES= \
tests/atomsmasher.cc \
tests/debug.cc \
gdb-cycle: tests/cycle
@$(DEBUG_COMMAND) tests/cycle
+gdb-failure: tests/failure
+ @$(DEBUG_COMMAND) tests/failure
+
valgrind-cycle: tests/cycle
$(VALGRIND_COMMAND) tests/cycle
valgrind-mem: tests/testapp
@$(VALGRIND_COMMAND) tests/testapp
+valgrind-failure: tests/failure
+ @$(VALGRIND_COMMAND) tests/failure
+
valgrind-atom: tests/atomsmasher
$(VALGRIND_COMMAND) tests/atomsmasher
{ }
};
-#define SERVERS_TO_CREATE 5
-
static void *world_create(server_startup_st& servers, test_return_t& error)
{
if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
}
- in_port_t max_port;
- for (uint32_t x= 0; x < SERVERS_TO_CREATE; x++)
+ in_port_t max_port= TEST_PORT_BASE;
+ for (uint32_t x= 0; x < servers.count(); x++)
{
in_port_t port;
return TEST_SUCCESS;
}
-static test_return_t error_test(memcached_st *memc)
+static test_return_t memcached_return_t_TEST(memcached_st *memc)
{
uint32_t values[] = { 851992627U, 2337886783U, 4109241422U, 4001849190U,
982370485U, 1263635348U, 4242906218U, 3829656100U,
54481931U, 4186304426U, 1741088401U, 2979625118U,
4159057246U, 3425930182U, 2593724503U, 1868899624U,
1769812374U, 2302537950U, 1110330676U, 3365377466U,
- 1336171666U, 3021258493U, 2334992265U, 3365377466U };
+ 1336171666U, 3021258493U, 2334992265U, 3861994737U,
+ 3365377466U };
// You have updated the memcache_error messages but not updated docs/tests.
for (int rc= int(MEMCACHED_SUCCESS); rc < int(MEMCACHED_MAXIMUM_RETURN); ++rc)
MEMCACHED_HASH_JENKINS);
if (values[rc] != hash_val)
{
- fprintf(stderr, "\n\nYou have updated memcached_return_t without updating the error_test\n");
+ fprintf(stderr, "\n\nYou have updated memcached_return_t without updating the memcached_return_t_TEST\n");
fprintf(stderr, "%u, %s, (%u)\n\n", (uint32_t)rc, memcached_strerror(memc, memcached_return_t(rc)), hash_val);
}
test_compare(values[rc], hash_val);
}
- test_compare(47, int(MEMCACHED_MAXIMUM_RETURN));
+ test_compare(48, int(MEMCACHED_MAXIMUM_RETURN));
return TEST_SUCCESS;
}
test_literal_param("number"),
1, &new_number));
test_compare(uint64_t(2), new_number);
+ memcached_free(memc);
return TEST_SUCCESS;
}
/* We are testing with aggressive timeout to get failures */
static test_return_t user_supplied_bug10(memcached_st *memc)
{
- const char *key= "foo";
size_t value_length= 512;
- size_t key_len= 3;
unsigned int set= 1;
memcached_st *mclone= memcached_clone(NULL, memc);
for (unsigned int x= 1; x <= 100000; ++x)
{
- memcached_return_t rc= memcached_set(mclone, key, key_len,value, value_length, 0, 0);
+ memcached_return_t rc= memcached_set(mclone,
+ test_literal_param("foo"),
+ value, value_length, 0, 0);
- test_true_got(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_WRITE_FAILURE or rc == MEMCACHED_BUFFERED or rc == MEMCACHED_TIMEOUT or rc == MEMCACHED_CONNECTION_FAILURE,
+ test_true_got((rc == MEMCACHED_SUCCESS or rc == MEMCACHED_WRITE_FAILURE or rc == MEMCACHED_BUFFERED or rc == MEMCACHED_TIMEOUT or rc == MEMCACHED_CONNECTION_FAILURE
+ or rc == MEMCACHED_SERVER_TEMPORARILY_DISABLED),
memcached_strerror(NULL, rc));
if (rc == MEMCACHED_WRITE_FAILURE or rc == MEMCACHED_TIMEOUT)
for (host_index= 0; host_index < SERVERS_TO_CREATE; host_index++)
{
/* This test was changes so that "make test" would work properlly */
-#ifdef DEBUG
- memcached_server_instance_st instance=
- memcached_server_instance_by_position(memc, host_index);
+ if (DEBUG)
+ {
+ memcached_server_instance_st instance=
+ memcached_server_instance_by_position(memc, host_index);
- printf("\nserver %u|%s|%u bytes: %llu\n", host_index, instance->hostname, instance->port, (unsigned long long)(stat_p + host_index)->bytes);
-#endif
+ printf("\nserver %u|%s|%u bytes: %llu\n", host_index, instance->hostname, instance->port, (unsigned long long)(stat_p + host_index)->bytes);
+ }
test_true((unsigned long long)(stat_p + host_index)->bytes);
}
{
const char *msg= memcached_strerror(memc, memcached_return_t(x));
memcached_return_t ret= memcached_set(memc, msg, strlen(msg), NULL, 0, (time_t)0, (uint32_t)0);
- test_compare_got(MEMCACHED_CONNECTION_FAILURE, ret, memcached_last_error_message(memc));
+ test_true_got((ret == MEMCACHED_CONNECTION_FAILURE or ret == MEMCACHED_SERVER_TEMPORARILY_DISABLED), memcached_last_error_message(memc));
memcached_server_instance_st disconnected_server= memcached_server_get_last_disconnect(memc);
test_true(disconnected_server);
return TEST_SUCCESS;
}
-static test_return_t test_server_failure(memcached_st *memc)
-{
- if (memcached_server_count(memc) < 2)
- return TEST_SKIPPED;
-
- memcached_server_instance_st instance= memcached_server_instance_by_position(memc, 0);
-
- memcached_st *local_memc= memcached_create(NULL);
-
- memcached_server_add(local_memc, memcached_server_name(instance), memcached_server_port(instance));
- memcached_behavior_set(local_memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, 2);
-
- uint32_t server_count= memcached_server_count(local_memc);
- test_compare(1U, server_count);
-
- // Disable the server
- instance= memcached_server_instance_by_position(local_memc, 0);
- ((memcached_server_write_instance_st)instance)->server_failure_counter= 2;
-
- memcached_return_t rc;
- test_compare_got(MEMCACHED_SERVER_MARKED_DEAD,
- rc= memcached_set(local_memc, "foo", strlen("foo"), NULL, 0, (time_t)0, (uint32_t)0),
- memcached_last_error_message(local_memc));
-
- ((memcached_server_write_instance_st)instance)->server_failure_counter= 0;
- test_compare(MEMCACHED_SUCCESS,
- memcached_set(local_memc, "foo", strlen("foo"), NULL, 0, (time_t)0, (uint32_t)0));
-#if 0
- memcached_last_error_message(local_memc));
-#endif
-
-
- memcached_free(local_memc);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t test_cull_servers(memcached_st *memc)
-{
- uint32_t count= memcached_server_count(memc);
-
- if (count < 2)
- {
- return TEST_SKIPPED;
- }
-
- // Do not do this in your code, it is not supported.
- memc->servers[1].options.is_dead= true;
- memc->state.is_time_for_rebuild= true;
-
- uint32_t new_count= memcached_server_count(memc);
- test_compare(count, new_count);
-
-#if 0
- test_true(count == new_count + 1 );
-#endif
-
- return TEST_SUCCESS;
-}
-
static memcached_return_t stat_printer(memcached_server_instance_st server,
const char *key, size_t key_length,
{"connection_test", false, (test_callback_fn*)connection_test},
{"callback_test", false, (test_callback_fn*)callback_test},
{"userdata_test", false, (test_callback_fn*)userdata_test},
- {"error", false, (test_callback_fn*)error_test },
{"set", false, (test_callback_fn*)set_test },
{"set2", false, (test_callback_fn*)set_test2 },
{"set3", false, (test_callback_fn*)set_test3 },
{"memcached_pool_test", true, (test_callback_fn*)memcached_pool_test },
{"test_get_last_disconnect", true, (test_callback_fn*)test_get_last_disconnect},
{"verbosity", true, (test_callback_fn*)test_verbosity},
- {"test_server_failure", true, (test_callback_fn*)test_server_failure},
- {"cull_servers", true, (test_callback_fn*)test_cull_servers},
{"memcached_stat_execute", true, (test_callback_fn*)memcached_stat_execute_test},
{0, 0, 0}
};
{"reset heap", true, (test_callback_fn*)basic_reset_heap_test},
{"reset stack clone", true, (test_callback_fn*)basic_reset_stack_clone_test},
{"reset heap clone", true, (test_callback_fn*)basic_reset_heap_clone_test},
+ {"memcached_return_t", false, (test_callback_fn*)memcached_return_t_TEST },
{0, 0, 0}
};
{"async", (test_callback_fn*)pre_nonblock, 0, async_tests},
{"async(BINARY)", (test_callback_fn*)pre_nonblock_binary, 0, async_tests},
{"Cal Haldenbrand's tests", 0, 0, haldenbrand_tests},
- {"user", 0, 0, user_tests},
+ {"user written tests", 0, 0, user_tests},
{"generate", 0, 0, generate_tests},
{"generate_hsieh", (test_callback_fn*)pre_hsieh, 0, generate_tests},
{"generate_ketama", (test_callback_fn*)pre_behavior_ketama, 0, generate_tests},
#include <libtest/server.h>
-#define SERVERS_TO_CREATE 5
-
#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
{0, 0, 0, 0}
};
-#define SERVERS_TO_CREATE 5
-
#define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT +10
#include "libmemcached_world.h"