X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;ds=sidebyside;f=libmemcached%2Fconnect.c;h=125d7b0ab1b4adc842492284a3d11b67d755a1f3;hb=32ed62f678c9ec668aff20a546b016f650d71e29;hp=f3832faed079d8b771ee18e61b1237b7a8283c5e;hpb=475f477dab6dfc5e4f018d1ecfb128c37e2c44a0;p=m6w6%2Flibmemcached diff --git a/libmemcached/connect.c b/libmemcached/connect.c index f3832fae..125d7b0a 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) @@ -85,6 +105,19 @@ static memcached_return_t set_socket_options(memcached_server_st *ptr) } #endif + + { + int set = 1; + int error= setsockopt(ptr->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); + + // This is not considered a fatal error + if (error == -1) + { + WATCHPOINT_ERRNO(errno); + perror("setsockopt(SO_NOSIGPIPE)"); + } + } + if (ptr->root->flags.no_block) { int error; @@ -111,6 +144,31 @@ static memcached_return_t set_socket_options(memcached_server_st *ptr) return MEMCACHED_FAILURE; } + if (ptr->root->flags.tcp_keepalive) + { + int flag= 1; + int error; + + error= setsockopt(ptr->fd, SOL_SOCKET, SO_KEEPALIVE, + &flag, (socklen_t)sizeof(int)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } + +#ifdef TCP_KEEPIDLE + if (ptr->root->tcp_keepidle > 0) + { + int error; + + error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_KEEPIDLE, + &ptr->root->tcp_keepidle, (socklen_t)sizeof(int)); + WATCHPOINT_ASSERT(error == 0); + if (error) + return MEMCACHED_FAILURE; + } +#endif + if (ptr->root->send_size > 0) { int error; @@ -199,6 +257,7 @@ test_connect: } WATCHPOINT_ASSERT(ptr->fd != -1); + return MEMCACHED_SUCCESS; } @@ -244,8 +303,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, */ @@ -254,20 +312,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 :-) */ @@ -290,6 +376,7 @@ static memcached_return_t network_connect(memcached_server_st *ptr) { (void)close(ptr->fd); ptr->fd= -1; + return rc; } } @@ -298,7 +385,6 @@ static memcached_return_t network_connect(memcached_server_st *ptr) if (ptr->fd != -1) { - ptr->server_failure_counter= 0; return MEMCACHED_SUCCESS; } use = use->ai_next; @@ -307,6 +393,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) { @@ -315,17 +403,30 @@ static memcached_return_t network_connect(memcached_server_st *ptr) if (gettimeofday(&next_time, NULL) == 0) ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout; } - ptr->server_failure_counter++; + if (ptr->cached_errno == 0) return MEMCACHED_TIMEOUT; return MEMCACHED_ERRNO; /* The last error should be from connect() */ } - ptr->server_failure_counter= 0; return MEMCACHED_SUCCESS; /* The last error should be from connect() */ } +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); +} memcached_return_t memcached_connect(memcached_server_write_instance_st ptr) { @@ -334,33 +435,36 @@ memcached_return_t memcached_connect(memcached_server_write_instance_st ptr) /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */ WATCHPOINT_ASSERT(ptr->root); - if (ptr->root->retry_timeout && ptr->root->server_failure_limit) + if (ptr->root->retry_timeout && ptr->next_retry) { struct timeval curr_time; gettimeofday(&curr_time, NULL); - /* if we've had too many consecutive errors on this server, mark it dead. */ - if (ptr->server_failure_counter >= ptr->root->server_failure_limit) + // We should optimize this to remove the allocation if the server was + // the last server to die + if (ptr->next_retry > curr_time.tv_sec) { - ptr->next_retry= curr_time.tv_sec + ptr->root->retry_timeout; - ptr->server_failure_counter= 0; - } + set_last_disconnected_host(ptr); - if (curr_time.tv_sec < ptr->next_retry) - { - memcached_st *root= (memcached_st *)ptr->root; - // @todo fix this by fixing behavior to no longer make use of - // memcached_st - if (memcached_behavior_get(root, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS)) - { - run_distribution(root); - } + return MEMCACHED_SERVER_MARKED_DEAD; + } + } - root->last_disconnected_server = ptr; + // If we are over the counter failure, we just fail. Reject host only + // works if you have a set number of failures. + if (ptr->root->server_failure_limit && ptr->server_failure_counter >= ptr->root->server_failure_limit) + { + set_last_disconnected_host(ptr); - return MEMCACHED_SERVER_MARKED_DEAD; + // @todo fix this by fixing behavior to no longer make use of + // memcached_st + if (_is_auto_eject_host(ptr->root)) + { + run_distribution((memcached_st *)ptr->root); } + + return MEMCACHED_SERVER_MARKED_DEAD; } /* We need to clean up the multi startup piece */ @@ -382,11 +486,16 @@ memcached_return_t memcached_connect(memcached_server_write_instance_st ptr) WATCHPOINT_ASSERT(0); } - unlikely ( rc != MEMCACHED_SUCCESS) + if (rc == MEMCACHED_SUCCESS) + { + ptr->server_failure_counter= 0; + ptr->next_retry= 0; + } + else { - //@todo create interface around last_discontected_server - memcached_st *root= (memcached_st *)ptr->root; - root->last_disconnected_server = ptr; + ptr->server_failure_counter++; + + set_last_disconnected_host(ptr); } LIBMEMCACHED_MEMCACHED_CONNECT_END();