From 969fea8e7bed82c109685ec3976cf7b0ec514ae9 Mon Sep 17 00:00:00 2001 From: Brian Aker Date: Fri, 19 Aug 2011 15:33:44 -0700 Subject: [PATCH] Merge in updates for server failure testing. --- .bzrignore | 1 + docs/memcached_behavior.rst | 2 +- libhashkit/digest.cc | 11 ++- libmemcached/behavior.cc | 18 +++- libmemcached/common.h | 3 - libmemcached/connect.cc | 134 +++++++++++++++----------- libmemcached/constants.h | 2 + libmemcached/get.cc | 7 ++ libmemcached/hash.cc | 2 +- libmemcached/hosts.cc | 45 +++++---- libmemcached/io.cc | 2 +- libmemcached/memcached.cc | 65 +++++++------ libmemcached/memcached.h | 3 + libmemcached/quit.cc | 3 +- libmemcached/return.h | 1 + libmemcached/server.cc | 8 +- libmemcached/server.h | 4 +- libmemcached/server.hpp | 54 +++++++++++ libmemcached/server_list.cc | 7 +- libmemcached/strerror.cc | 3 + libtest/comparison.hpp | 39 +++++++- libtest/framework.h | 5 + libtest/server_container.cc | 48 +++++++--- libtest/server_container.h | 20 +++- m4/pandora_optimize.m4 | 2 + tests/atomsmasher.cc | 1 - tests/failure.cc | 186 ++++++++++++++++++++++++++++++++++++ tests/include.am | 13 +++ tests/libmemcached_world.h | 6 +- tests/mem_functions.cc | 98 ++++--------------- tests/mem_udp.cc | 4 - 31 files changed, 571 insertions(+), 226 deletions(-) create mode 100644 tests/failure.cc diff --git a/.bzrignore b/.bzrignore index c28f4fd1..3a6e517a 100644 --- a/.bzrignore +++ b/.bzrignore @@ -110,6 +110,7 @@ tests/atomsmasher tests/c_sasl_test tests/c_test tests/cycle +tests/failure tests/hash_plus tests/hashplus tests/internals diff --git a/docs/memcached_behavior.rst b/docs/memcached_behavior.rst index baa2eacd..3480d251 100644 --- a/docs/memcached_behavior.rst +++ b/docs/memcached_behavior.rst @@ -252,7 +252,7 @@ Find the current size of SO_RCVBUF. A value of 0 means either an error occured o .. 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 diff --git a/libhashkit/digest.cc b/libhashkit/digest.cc index e1559819..ce94cc76 100644 --- a/libhashkit/digest.cc +++ b/libhashkit/digest.cc @@ -48,11 +48,12 @@ uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algo 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; } diff --git a/libmemcached/behavior.cc b/libmemcached/behavior.cc index a6988a22..2a1e7537 100644 --- a/libmemcached/behavior.cc +++ b/libmemcached/behavior.cc @@ -53,7 +53,9 @@ memcached_return_t memcached_behavior_set(memcached_st *ptr, uint64_t data) { if (not ptr) + { return MEMCACHED_INVALID_ARGUMENTS; + } switch (flag) { @@ -85,7 +87,12 @@ memcached_return_t memcached_behavior_set(memcached_st *ptr, 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: @@ -189,7 +196,12 @@ memcached_return_t memcached_behavior_set(memcached_st *ptr, 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: @@ -461,8 +473,10 @@ memcached_return_t memcached_behavior_set_distribution(memcached_st *ptr, memcac { ptr->ketama.weighted= false; } + ptr->distribution= type; run_distribution(ptr); + return MEMCACHED_SUCCESS; } diff --git a/libmemcached/common.h b/libmemcached/common.h index f45eaffd..6de9bbd1 100644 --- a/libmemcached/common.h +++ b/libmemcached/common.h @@ -155,9 +155,6 @@ memcached_return_t run_distribution(memcached_st *ptr); #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, diff --git a/libmemcached/connect.cc b/libmemcached/connect.cc index f90cb6b0..589c40c5 100644 --- a/libmemcached/connect.cc +++ b/libmemcached/connect.cc @@ -37,6 +37,8 @@ #include + +#include #include #include @@ -343,7 +345,7 @@ static void set_socket_options(memcached_server_st *server) 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) { @@ -398,7 +400,7 @@ static memcached_return_t network_connect(memcached_server_st *server) 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; @@ -421,11 +423,13 @@ static memcached_return_t network_connect(memcached_server_st *server) } 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) @@ -510,16 +514,6 @@ static memcached_return_t network_connect(memcached_server_st *server) } 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)) { @@ -534,58 +528,81 @@ static memcached_return_t network_connect(memcached_server_st *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 */ @@ -594,6 +611,7 @@ memcached_return_t memcached_connect(memcached_server_write_instance_st server) 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) @@ -616,22 +634,28 @@ memcached_return_t memcached_connect(memcached_server_write_instance_st server) 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; } diff --git a/libmemcached/constants.h b/libmemcached/constants.h index e17e676e..7a84b9a8 100644 --- a/libmemcached/constants.h +++ b/libmemcached/constants.h @@ -54,6 +54,8 @@ #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 { diff --git a/libmemcached/get.cc b/libmemcached/get.cc index 8c98d4ca..21170102 100644 --- a/libmemcached/get.cc +++ b/libmemcached/get.cc @@ -469,7 +469,9 @@ static memcached_return_t simple_binary_mget(memcached_st *ptr, { rc= memcached_connect(instance); if (memcached_failed(rc)) + { continue; + } } protocol_binary_request_getk request= { }; //= {.bytes= {0}}; @@ -589,16 +591,21 @@ static memcached_return_t replication_binary_mget(memcached_st *ptr, 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); diff --git a/libmemcached/hash.cc b/libmemcached/hash.cc index ae07dfd0..8edd839d 100644 --- a/libmemcached/hash.cc +++ b/libmemcached/hash.cc @@ -132,7 +132,7 @@ static inline void _regen_for_auto_eject(memcached_st *ptr) { 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); diff --git a/libmemcached/hosts.cc b/libmemcached/hosts.cc index 4a9a1033..5c4cf175 100644 --- a/libmemcached/hosts.cc +++ b/libmemcached/hosts.cc @@ -161,7 +161,7 @@ static memcached_return_t update_continuum(memcached_st *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; } @@ -189,7 +189,9 @@ static memcached_return_t update_continuum(memcached_st *ptr) 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; @@ -200,7 +202,7 @@ static memcached_return_t update_continuum(memcached_st *ptr) { 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; } @@ -209,21 +211,24 @@ static memcached_return_t update_continuum(memcached_st *ptr) 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); + } } @@ -249,9 +254,12 @@ static memcached_return_t update_continuum(memcached_st *ptr) 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++) @@ -327,12 +335,13 @@ static memcached_return_t update_continuum(memcached_st *ptr) 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; } diff --git a/libmemcached/io.cc b/libmemcached/io.cc index 0ed565d7..d7268940 100644 --- a/libmemcached/io.cc +++ b/libmemcached/io.cc @@ -547,8 +547,8 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, } } - ptr->server_failure_counter= 0; *nread = (ssize_t)(buffer_ptr - (char*)buffer); + return MEMCACHED_SUCCESS; } diff --git a/libmemcached/memcached.cc b/libmemcached/memcached.cc index ce3fb8e3..e81f19ee 100644 --- a/libmemcached/memcached.cc +++ b/libmemcached/memcached.cc @@ -90,7 +90,11 @@ static inline bool _memcached_init(memcached_st *self) 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; @@ -104,7 +108,7 @@ static inline bool _memcached_init(memcached_st *self) 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 */ @@ -116,7 +120,7 @@ static inline bool _memcached_init(memcached_st *self) 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; @@ -156,7 +160,9 @@ static void _free(memcached_st *ptr, bool release_st) memcached_server_free(ptr->last_disconnected_server); if (ptr->on_cleanup) + { ptr->on_cleanup(ptr); + } libmemcached_free(ptr, ptr->ketama.continuum); @@ -205,13 +211,13 @@ memcached_st *memcached_create(memcached_st *ptr) 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; @@ -232,7 +238,9 @@ memcached_st *memcached(const char *string, size_t length) } if (not length) + { return self; + } memcached_return_t rc= memcached_parse_configuration(self, string, length); @@ -255,7 +263,9 @@ memcached_return_t memcached_reset(memcached_st *ptr) { WATCHPOINT_ASSERT(ptr); if (not ptr) + { return MEMCACHED_INVALID_ARGUMENTS; + } bool stored_is_allocated= memcached_is_allocated(ptr); uint64_t query_id= ptr->query_id; @@ -274,33 +284,32 @@ memcached_return_t memcached_reset(memcached_st *ptr) 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); + } } /* @@ -359,9 +368,11 @@ memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source) 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); @@ -374,16 +385,14 @@ memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source) 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); @@ -391,7 +400,9 @@ memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source) } if (source->on_clone) + { source->on_clone(new_clone, source); + } return new_clone; } diff --git a/libmemcached/memcached.h b/libmemcached/memcached.h index 0bf8c619..3c29a5e1 100644 --- a/libmemcached/memcached.h +++ b/libmemcached/memcached.h @@ -113,6 +113,9 @@ struct memcached_st { 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; diff --git a/libmemcached/quit.cc b/libmemcached/quit.cc index fa7599ed..0162700d 100644 --- a/libmemcached/quit.cc +++ b/libmemcached/quit.cc @@ -112,8 +112,7 @@ void memcached_quit_server(memcached_server_st *ptr, bool io_death) if (io_death) { - ptr->server_failure_counter++; - set_last_disconnected_host(ptr); + memcached_mark_server_for_timeout(ptr); } } diff --git a/libmemcached/return.h b/libmemcached/return.h index d45d2e85..378194fd 100644 --- a/libmemcached/return.h +++ b/libmemcached/return.h @@ -84,6 +84,7 @@ enum memcached_return_t { MEMCACHED_PARSE_USER_ERROR, MEMCACHED_DEPRECATED, MEMCACHED_IN_PROGRESS, + MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */ }; diff --git a/libmemcached/server.cc b/libmemcached/server.cc index 073972dd..022dda4f 100644 --- a/libmemcached/server.cc +++ b/libmemcached/server.cc @@ -69,17 +69,17 @@ static inline void _server_init(memcached_server_st *self, memcached_st *root, 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; diff --git a/libmemcached/server.h b/libmemcached/server.h index 40328ab6..e6f3a30a 100644 --- a/libmemcached/server.h +++ b/libmemcached/server.h @@ -46,7 +46,8 @@ enum memcached_server_state_t { 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 { @@ -63,6 +64,7 @@ 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; diff --git a/libmemcached/server.hpp b/libmemcached/server.hpp index 05b51f4f..320da115 100644 --- a/libmemcached/server.hpp +++ b/libmemcached/server.hpp @@ -39,11 +39,65 @@ #include +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include + 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, diff --git a/libmemcached/server_list.cc b/libmemcached/server_list.cc index a4a617c0..d5994e85 100644 --- a/libmemcached/server_list.cc +++ b/libmemcached/server_list.cc @@ -118,7 +118,12 @@ uint32_t memcached_server_list_count(const memcached_server_list_st self) 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) diff --git a/libmemcached/strerror.cc b/libmemcached/strerror.cc index 3688a66b..ebb90056 100644 --- a/libmemcached/strerror.cc +++ b/libmemcached/strerror.cc @@ -182,6 +182,9 @@ const char *memcached_strerror(memcached_st *, memcached_return_t rc) 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"; diff --git a/libtest/comparison.hpp b/libtest/comparison.hpp index 5c687fc3..09106d9f 100644 --- a/libtest/comparison.hpp +++ b/libtest/comparison.hpp @@ -62,7 +62,7 @@ bool _compare(const char *file, int line, const char *func, const T_comparable _ << 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 \"" @@ -107,8 +107,43 @@ bool _compare_hint(const char *file, int line, const char *func, T_comparable __ { 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; } diff --git a/libtest/framework.h b/libtest/framework.h index 90908244..c5ca7a1b 100644 --- a/libtest/framework.h +++ b/libtest/framework.h @@ -148,6 +148,11 @@ public: { _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 diff --git a/libtest/server_container.cc b/libtest/server_container.cc index f747dc22..bba1240c 100644 --- a/libtest/server_container.cc +++ b/libtest/server_container.cc @@ -75,31 +75,55 @@ Server* server_startup_st::pop_server() 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::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::iterator iter= servers.begin(); iter != servers.end(); iter++) { - for (std::vector::iterator iter= servers.begin(); iter != servers.end(); iter++) + delete *iter; + } + servers.clear(); +} + +void server_startup_st::shutdown() +{ + for (std::vector::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::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 diff --git a/libtest/server_container.h b/libtest/server_container.h index 9c9922ed..4e81dafd 100644 --- a/libtest/server_container.h +++ b/libtest/server_container.h @@ -38,6 +38,7 @@ private: std::string server_list; bool _socket; bool _sasl; + uint32_t _count; std::string _username; std::string _password; @@ -49,18 +50,26 @@ public: 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; @@ -99,7 +108,10 @@ public: } - 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(); diff --git a/m4/pandora_optimize.m4 b/m4/pandora_optimize.m4 index fb2cd776..b0fd5ad0 100644 --- a/m4/pandora_optimize.m4 +++ b/m4/pandora_optimize.m4 @@ -67,9 +67,11 @@ AC_DEFUN([PANDORA_OPTIMIZE],[ # 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.]) ]) ]) diff --git a/tests/atomsmasher.cc b/tests/atomsmasher.cc index 6949bcd6..eebe0f38 100644 --- a/tests/atomsmasher.cc +++ b/tests/atomsmasher.cc @@ -282,7 +282,6 @@ collection_st collection[] ={ #define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT +10 -#define SERVERS_TO_CREATE 5 #include "libmemcached_world.h" diff --git a/tests/failure.cc b/tests/failure.cc new file mode 100644 index 00000000..185f9c71 --- /dev/null +++ b/tests/failure.cc @@ -0,0 +1,186 @@ +/* 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 + +/* + C++ interface test +*/ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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; +} diff --git a/tests/include.am b/tests/include.am index ed345c92..38a07f99 100644 --- a/tests/include.am +++ b/tests/include.am @@ -130,6 +130,13 @@ tests_testplus_LDADD= $(tests_testplus_DEPENDENCIES) 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 \ @@ -355,12 +362,18 @@ gdb-hashplus: tests/hash_plus 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 diff --git a/tests/libmemcached_world.h b/tests/libmemcached_world.h index e2f0c27d..9f38c024 100644 --- a/tests/libmemcached_world.h +++ b/tests/libmemcached_world.h @@ -27,8 +27,6 @@ struct libmemcached_test_container_st { } }; -#define SERVERS_TO_CREATE 5 - static void *world_create(server_startup_st& servers, test_return_t& error) { if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0) @@ -45,8 +43,8 @@ static void *world_create(server_startup_st& servers, test_return_t& error) } - 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; diff --git a/tests/mem_functions.cc b/tests/mem_functions.cc index 492467ca..2c29c048 100644 --- a/tests/mem_functions.cc +++ b/tests/mem_functions.cc @@ -422,7 +422,7 @@ static test_return_t libmemcached_string_distribution_test(memcached_st *) 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, @@ -435,7 +435,8 @@ static test_return_t error_test(memcached_st *memc) 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) @@ -446,12 +447,12 @@ static test_return_t error_test(memcached_st *memc) 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; } @@ -1522,6 +1523,7 @@ static test_return_t binary_increment_with_prefix_test(memcached_st *orig_memc) test_literal_param("number"), 1, &new_number)); test_compare(uint64_t(2), new_number); + memcached_free(memc); return TEST_SUCCESS; } @@ -2614,9 +2616,7 @@ static test_return_t user_supplied_bug9(memcached_st *memc) /* 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); @@ -2633,9 +2633,12 @@ static test_return_t user_supplied_bug10(memcached_st *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) @@ -3219,12 +3222,13 @@ static test_return_t generate_data_with_stats(memcached_st *memc) 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); } @@ -5259,7 +5263,7 @@ static test_return_t test_multiple_get_last_disconnect(memcached_st *) { 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); @@ -5285,66 +5289,6 @@ static test_return_t test_verbosity(memcached_st *memc) 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, @@ -5857,7 +5801,6 @@ test_st tests[] ={ {"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 }, @@ -5903,8 +5846,6 @@ test_st tests[] ={ {"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} }; @@ -5933,6 +5874,7 @@ test_st basic_tests[] ={ {"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} }; @@ -6216,7 +6158,7 @@ collection_st collection[] ={ {"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}, diff --git a/tests/mem_udp.cc b/tests/mem_udp.cc index 4c81cadf..077f8c99 100644 --- a/tests/mem_udp.cc +++ b/tests/mem_udp.cc @@ -33,8 +33,6 @@ using namespace libtest; #include -#define SERVERS_TO_CREATE 5 - #ifndef __INTEL_COMPILER #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif @@ -491,8 +489,6 @@ collection_st collection[] ={ {0, 0, 0, 0} }; -#define SERVERS_TO_CREATE 5 - #define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT +10 #include "libmemcached_world.h" -- 2.30.2