From 96c84d98b1b2db8419072eea960e8800c189586b Mon Sep 17 00:00:00 2001 From: Brian Aker Date: Tue, 20 Apr 2010 20:14:19 -0700 Subject: [PATCH] Fix for bad name servers. --- libmemcached/common.h | 2 + libmemcached/connect.c | 92 +++++++++++++++++++++++++++++++-------- libmemcached/constants.h | 1 + libmemcached/do.c | 2 + libmemcached/io.c | 22 ++++++---- libmemcached/memcached.c | 11 ++++- libmemcached/memcached.h | 3 ++ libmemcached/quit.c | 1 + tests/mem_functions.c | 93 ++++++++++++++++++++++++---------------- 9 files changed, 162 insertions(+), 65 deletions(-) diff --git a/libmemcached/common.h b/libmemcached/common.h index f8f236ed..bfbc9220 100644 --- a/libmemcached/common.h +++ b/libmemcached/common.h @@ -123,6 +123,8 @@ memcached_return_t run_distribution(memcached_st *ptr); #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); LIBMEMCACHED_LOCAL memcached_return_t memcached_key_test(const char * const *keys, diff --git a/libmemcached/connect.c b/libmemcached/connect.c index 99238d8d..cb093d12 100644 --- a/libmemcached/connect.c +++ b/libmemcached/connect.c @@ -2,13 +2,14 @@ #include #include #include +#include static memcached_return_t set_hostinfo(memcached_server_st *server) { struct addrinfo *ai; struct addrinfo hints; - int e; char str_port[NI_MAXSERV]; + uint32_t counter= 5; snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port); @@ -26,12 +27,31 @@ static memcached_return_t set_hostinfo(memcached_server_st *server) hints.ai_protocol= IPPROTO_TCP; } - e= getaddrinfo(server->hostname, str_port, &hints, &ai); - if (e != 0) + while (--counter) { - WATCHPOINT_STRING(server->hostname); - WATCHPOINT_STRING(gai_strerror(e)); - return MEMCACHED_HOST_LOOKUP_FAILURE; + int e= getaddrinfo(server->hostname, str_port, &hints, &ai); + + if (e == 0) + { + break; + } + else if (e == EAI_AGAIN) + { + struct timespec dream, rem; + + dream.tv_nsec= 1000; + dream.tv_sec= 0; + + nanosleep(&dream, &rem); + + continue; + } + else + { + WATCHPOINT_STRING(server->hostname); + WATCHPOINT_STRING(gai_strerror(e)); + return MEMCACHED_HOST_LOOKUP_FAILURE; + } } if (server->address_info) @@ -269,8 +289,7 @@ static memcached_return_t network_connect(memcached_server_st *ptr) (void)set_socket_options(ptr); /* connect to server */ - while (ptr->fd != -1 && - connect(ptr->fd, use->ai_addr, use->ai_addrlen) < 0) + if ((connect(ptr->fd, use->ai_addr, use->ai_addrlen) == -1)) { ptr->cached_errno= errno; if (errno == EINPROGRESS || /* nonblocking mode - first return, */ @@ -279,20 +298,48 @@ static memcached_return_t network_connect(memcached_server_st *ptr) struct pollfd fds[1]; fds[0].fd = ptr->fd; fds[0].events = POLLOUT; - int error= poll(fds, 1, ptr->root->connect_timeout); - if (error != 1 || fds[0].revents & POLLERR) + int timeout= ptr->root->connect_timeout; + if (ptr->root->flags.no_block == false) + timeout= -1; + + size_t loop_max= 5; + while (--loop_max) { - if (fds[0].revents & POLLERR) + int error= poll(fds, 1, timeout); + + switch (error) { - int err; - socklen_t len = sizeof (err); - (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len); - ptr->cached_errno= (err == 0) ? errno : err; + case 1: + loop_max= 1; + break; + case 0: + continue; + // A real error occurred and we need to completely bail + default: + WATCHPOINT_ERRNO(errno); + switch (errno) + { +#ifdef TARGET_OS_LINUX + case ERESTART: +#endif + case EINTR: + continue; + default: + if (fds[0].revents & POLLERR) + { + int err; + socklen_t len= sizeof (err); + (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len); + ptr->cached_errno= (err == 0) ? errno : err; + } + + (void)close(ptr->fd); + ptr->fd= -1; + + break; + } } - - (void)close(ptr->fd); - ptr->fd= -1; } } else if (errno == EISCONN) /* we are connected :-) */ @@ -332,6 +379,8 @@ static memcached_return_t network_connect(memcached_server_st *ptr) if (ptr->fd == -1) { + WATCHPOINT_STRING("Never got a good file descriptor"); + /* Failed to connect. schedule next retry */ if (ptr->root->retry_timeout) { @@ -350,11 +399,16 @@ static memcached_return_t network_connect(memcached_server_st *ptr) return MEMCACHED_SUCCESS; /* The last error should be from connect() */ } -static inline void set_last_disconnected_host(memcached_server_write_instance_st ptr) +void set_last_disconnected_host(memcached_server_write_instance_st ptr) { // const_cast memcached_st *root= (memcached_st *)ptr->root; +#if 0 + WATCHPOINT_STRING(ptr->hostname); + WATCHPOINT_NUMBER(ptr->port); + WATCHPOINT_ERRNO(ptr->cached_errno); +#endif if (root->last_disconnected_server) memcached_server_free(root->last_disconnected_server); root->last_disconnected_server= memcached_server_clone(NULL, ptr); diff --git a/libmemcached/constants.h b/libmemcached/constants.h index 4a7b0cdb..d6798d0d 100644 --- a/libmemcached/constants.h +++ b/libmemcached/constants.h @@ -22,6 +22,7 @@ #define MEMCACHED_CONTINUUM_SIZE MEMCACHED_POINTS_PER_SERVER*100 /* This would then set max hosts to 100 */ #define MEMCACHED_STRIDE 4 #define MEMCACHED_DEFAULT_TIMEOUT 1000 +#define MEMCACHED_DEFAULT_CONNECT_TIMEOUT 4000 #define MEMCACHED_CONTINUUM_ADDITION 10 /* How many extra slots we should build for in the continuum */ #define MEMCACHED_PREFIX_KEY_MAX_SIZE 128 #define MEMCACHED_EXPIRATION_NOT_ADD 0xffffffffU diff --git a/libmemcached/do.c b/libmemcached/do.c index 794303a8..1a274cd3 100644 --- a/libmemcached/do.c +++ b/libmemcached/do.c @@ -87,6 +87,8 @@ memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr, if (sent_length == -1 || (size_t)sent_length != command_length) { rc= MEMCACHED_WRITE_FAILURE; + WATCHPOINT_ERROR(rc); + WATCHPOINT_ERRNO(errno); } else if ((ptr->root->flags.no_reply) == 0) { diff --git a/libmemcached/io.c b/libmemcached/io.c index 616ad497..070af6b1 100644 --- a/libmemcached/io.c +++ b/libmemcached/io.c @@ -64,20 +64,25 @@ static memcached_return_t io_wait(memcached_server_write_instance_st ptr, case 1: return MEMCACHED_SUCCESS; case 0: - return MEMCACHED_TIMEOUT; -#ifdef TARGET_OS_LINUX - case ERESTART: -#endif - case EINTR: continue; default: - ptr->cached_errno= error; - memcached_quit_server(ptr, true); + WATCHPOINT_ERRNO(errno); + { + switch (errno) + { + default: + ptr->cached_errno= error; + memcached_quit_server(ptr, true); - return MEMCACHED_FAILURE; + return MEMCACHED_FAILURE; + } + } } } + if (loop_max == 0 && error == 0) + return MEMCACHED_TIMEOUT; + /* Imposssible for anything other then -1 */ WATCHPOINT_ASSERT(error == -1); ptr->cached_errno= error; @@ -583,6 +588,7 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr, if (sent_length == -1) { ptr->cached_errno= errno; + WATCHPOINT_ERRNO(errno); switch (errno) { case ENOBUFS: diff --git a/libmemcached/memcached.c b/libmemcached/memcached.c index e6124493..d5411e86 100644 --- a/libmemcached/memcached.c +++ b/libmemcached/memcached.c @@ -69,7 +69,7 @@ static inline bool _memcached_init(memcached_st *self) self->io_key_prefetch= 0; self->cached_errno= 0; self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT; - self->connect_timeout= MEMCACHED_DEFAULT_TIMEOUT; + self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT; self->retry_timeout= 0; self->continuum_count= 0; @@ -151,6 +151,15 @@ void memcached_servers_reset(memcached_st *ptr) ptr->server_failure_limit= 0; } +void memcached_reset_last_disconnected_server(memcached_st *ptr) +{ + if (ptr->last_disconnected_server) + { + memcached_server_free(ptr->last_disconnected_server); + ptr->last_disconnected_server= NULL; + } +} + void memcached_free(memcached_st *ptr) { /* If we have anything open, lets close it now */ diff --git a/libmemcached/memcached.h b/libmemcached/memcached.h index 69b469dc..26f101f2 100644 --- a/libmemcached/memcached.h +++ b/libmemcached/memcached.h @@ -146,6 +146,9 @@ memcached_st *memcached_create(memcached_st *ptr); LIBMEMCACHED_API void memcached_free(memcached_st *ptr); +LIBMEMCACHED_API +void memcached_reset_last_disconnected_server(memcached_st *ptr); + LIBMEMCACHED_API memcached_st *memcached_clone(memcached_st *clone, const memcached_st *ptr); diff --git a/libmemcached/quit.c b/libmemcached/quit.c index 592373f6..49af9963 100644 --- a/libmemcached/quit.c +++ b/libmemcached/quit.c @@ -67,6 +67,7 @@ void memcached_quit_server(memcached_server_st *ptr, bool io_death) if (io_death) { ptr->server_failure_counter++; + set_last_disconnected_host(ptr); } } diff --git a/tests/mem_functions.c b/tests/mem_functions.c index 57b1c7b4..701de442 100644 --- a/tests/mem_functions.c +++ b/tests/mem_functions.c @@ -5417,6 +5417,7 @@ static test_return_t test_get_last_disconnect(memcached_st *memc) const char *key= "marmotte"; const char *value= "milka"; + memcached_reset_last_disconnected_server(memc); rc= memcached_set(memc, key, strlen(key), value, strlen(value), (time_t)0, (uint32_t)0); @@ -5444,7 +5445,12 @@ static test_return_t test_get_last_disconnect(memcached_st *memc) (time_t)0, (uint32_t)0); test_true(rc != MEMCACHED_SUCCESS); - disconnected_server = memcached_server_get_last_disconnect(mine); + disconnected_server= memcached_server_get_last_disconnect(mine); + if (disconnected_server == NULL) + { + fprintf(stderr, "RC %s\n", memcached_strerror(mine, rc)); + abort(); + } test_true(disconnected_server != NULL); test_true(memcached_server_port(disconnected_server)== 9); test_true(strncmp(memcached_server_name(disconnected_server),"localhost",9) == 0); @@ -5647,9 +5653,9 @@ static test_return_t regression_bug_490486(memcached_st *memc) return TEST_SUCCESS; } -static void memcached_die(memcached_st* mc, memcached_return error, const char* what, int it) +static void memcached_die(memcached_st* mc, memcached_return error, const char* what, uint32_t it) { - fprintf(stderr, "Iteration #%i: ", it); + fprintf(stderr, "Iteration #%u: ", it); if(error == MEMCACHED_ERRNO) { @@ -5661,17 +5667,19 @@ static void memcached_die(memcached_st* mc, memcached_return error, const char* fprintf(stderr, "error %d from %s: %s\n", error, what, memcached_strerror(mc, error)); } - - abort(); } -#define TEST_CONSTANT_CREATION 400 +#define TEST_CONSTANT_CREATION 200 static test_return_t regression_bug_(memcached_st *memc) { - memcached_server_instance_st instance= memcached_server_instance_by_position(memc, 0); - const char *servername= memcached_server_name(instance); - in_port_t port= memcached_server_port(instance); + const char *remote_server; + (void)memc; + + if (! (remote_server= getenv("LIBMEMCACHED_REMOTE_SERVER"))) + { + return TEST_SKIPPED; + } for (uint32_t x= 0; x < TEST_CONSTANT_CREATION; x++) { @@ -5690,8 +5698,8 @@ static test_return_t regression_bug_(memcached_st *memc) memcached_die(mc, rc, "memcached_behavior_set", x); } - rc= memcached_server_add(mc, servername, port); - if(rc != MEMCACHED_SUCCESS) + rc= memcached_server_add(mc, remote_server, 0); + if (rc != MEMCACHED_SUCCESS) { memcached_die(mc, rc, "memcached_server_add", x); } @@ -5701,42 +5709,53 @@ static test_return_t regression_bug_(memcached_st *memc) const char *set_value= "a value"; const size_t set_value_len= strlen(set_value); - char *get_value=NULL; - size_t get_value_len=0; - uint32_t get_value_flags=0; - if (x > 0) + if (rc == MEMCACHED_SUCCESS) { - get_value= memcached_get(mc, set_key, set_key_len, &get_value_len, - &get_value_flags, &rc); - if (rc != MEMCACHED_SUCCESS) + if (x > 0) { - memcached_die(mc, rc, "memcached_get", x); + size_t get_value_len; + char *get_value; + uint32_t get_value_flags; + + get_value= memcached_get(mc, set_key, set_key_len, &get_value_len, + &get_value_flags, &rc); + if (rc != MEMCACHED_SUCCESS) + { + memcached_die(mc, rc, "memcached_get", x); + } + else + { + + if (x != 0 && + (get_value_len != set_value_len + || 0!=strncmp(get_value, set_value, get_value_len))) + { + fprintf(stderr, "Values don't match?\n"); + rc= MEMCACHED_FAILURE; + } + free(get_value); + } } - if (x != 0 && - (get_value_len != set_value_len - || 0!=strncmp(get_value, set_value, get_value_len))) + rc= memcached_set(mc, + set_key, set_key_len, + set_value, set_value_len, + 0, /* time */ + 0 /* flags */ + ); + if (rc != MEMCACHED_SUCCESS) { - fprintf(stderr, "Values don't match?\n"); + memcached_die(mc, rc, "memcached_set", x); } - free(get_value); - get_value= NULL; - get_value_len= 0; } - rc= memcached_set(mc, - set_key, set_key_len, - set_value, set_value_len, - 0, /* time */ - 0 /* flags */ - ); + memcached_quit(mc); + memcached_free(mc); + if (rc != MEMCACHED_SUCCESS) { - memcached_die(mc, rc, "memcached_set", x); + break; } - - memcached_quit(mc); - memcached_free(mc); } return MEMCACHED_SUCCESS; @@ -5933,7 +5952,7 @@ test_st replication_tests[]= { test_st regression_tests[]= { {"lp:434484", 1, (test_callback_fn)regression_bug_434484 }, {"lp:434843", 1, (test_callback_fn)regression_bug_434843 }, - {"lp:434843 buffered", 1, (test_callback_fn)regression_bug_434843_buffered }, + {"lp:434843-buffered", 1, (test_callback_fn)regression_bug_434843_buffered }, {"lp:421108", 1, (test_callback_fn)regression_bug_421108 }, {"lp:442914", 1, (test_callback_fn)regression_bug_442914 }, {"lp:447342", 1, (test_callback_fn)regression_bug_447342 }, -- 2.30.2