X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=libmemcached%2Fmemcached_connect.c;h=cee75e4c7c24412752155464c4f5e263f2810d26;hb=a572add17935f282abfb31e0aac9706e4a57cdd1;hp=c2e03ac38e7a4279512f84c0c096e63545769f1c;hpb=95084fee7261488e27be38d9c50957f82a75f416;p=m6w6%2Flibmemcached diff --git a/libmemcached/memcached_connect.c b/libmemcached/memcached_connect.c index c2e03ac3..cee75e4c 100644 --- a/libmemcached/memcached_connect.c +++ b/libmemcached/memcached_connect.c @@ -60,7 +60,7 @@ static memcached_return set_socket_options(memcached_server_st *ptr) waittime.tv_sec= 0; waittime.tv_usec= ptr->root->snd_timeout; - error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO, + error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO, &waittime, (socklen_t)sizeof(struct timeval)); WATCHPOINT_ASSERT(error == 0); } @@ -75,19 +75,20 @@ static memcached_return set_socket_options(memcached_server_st *ptr) waittime.tv_sec= 0; waittime.tv_usec= ptr->root->rcv_timeout; - error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO, + error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO, &waittime, (socklen_t)sizeof(struct timeval)); WATCHPOINT_ASSERT(error == 0); } #endif + if (ptr->root->flags & MEM_NO_BLOCK) { int error; struct linger linger; - linger.l_onoff= 1; - linger.l_linger= MEMCACHED_DEFAULT_TIMEOUT; - error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER, + linger.l_onoff= 1; + linger.l_linger= 0; /* By default on close() just drop the socket */ + error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER, &linger, (socklen_t)sizeof(struct linger)); WATCHPOINT_ASSERT(error == 0); } @@ -97,7 +98,7 @@ static memcached_return set_socket_options(memcached_server_st *ptr) int flag= 1; int error; - error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY, + error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY, &flag, (socklen_t)sizeof(int)); WATCHPOINT_ASSERT(error == 0); } @@ -106,7 +107,7 @@ static memcached_return set_socket_options(memcached_server_st *ptr) { int error; - error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF, + error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF, &ptr->root->send_size, (socklen_t)sizeof(int)); WATCHPOINT_ASSERT(error == 0); } @@ -115,13 +116,13 @@ static memcached_return set_socket_options(memcached_server_st *ptr) { int error; - error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF, + error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF, &ptr->root->recv_size, (socklen_t)sizeof(int)); WATCHPOINT_ASSERT(error == 0); } /* For the moment, not getting a nonblocking mode will not be fatal */ - if (ptr->root->flags & MEM_NO_BLOCK) + if ((ptr->root->flags & MEM_NO_BLOCK) || ptr->root->connect_timeout) { int flags; @@ -152,14 +153,15 @@ static memcached_return unix_socket_connect(memcached_server_st *ptr) servAddr.sun_family= AF_UNIX; strcpy(servAddr.sun_path, ptr->hostname); /* Copy filename */ - addrlen= strlen(servAddr.sun_path) + sizeof(servAddr.sun_family); + addrlen= (socklen_t) (strlen(servAddr.sun_path) + sizeof(servAddr.sun_family)); test_connect: - if (connect(ptr->fd, + if (connect(ptr->fd, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) { - switch (errno) { + switch (errno) + { case EINPROGRESS: case EALREADY: case EINTR: @@ -184,16 +186,7 @@ static memcached_return network_connect(memcached_server_st *ptr) { struct addrinfo *use; - if (ptr->root->server_failure_limit != 0) - { - if (ptr->server_failure_counter >= ptr->root->server_failure_limit) - { - memcached_server_remove(ptr); - return MEMCACHED_FAILURE; - } - } - - if (ptr->sockaddr_inited || + if (!ptr->sockaddr_inited || (!(ptr->root->flags & MEM_USE_CACHE_LOOKUPS))) { memcached_return rc; @@ -208,8 +201,15 @@ static memcached_return network_connect(memcached_server_st *ptr) /* Create the socket */ while (use != NULL) { - if ((ptr->fd= socket(use->ai_family, - use->ai_socktype, + /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */ + if (ptr->type == MEMCACHED_CONNECTION_UDP && use->ai_family != AF_INET) + { + use= use->ai_next; + continue; + } + + if ((ptr->fd= socket(use->ai_family, + use->ai_socktype, use->ai_protocol)) < 0) { ptr->cached_errno= errno; @@ -219,7 +219,7 @@ static memcached_return network_connect(memcached_server_st *ptr) (void)set_socket_options(ptr); - int flags; + int flags= 0; if (ptr->root->connect_timeout) { flags= fcntl(ptr->fd, F_GETFL, 0); @@ -228,14 +228,16 @@ static memcached_return network_connect(memcached_server_st *ptr) } /* connect to server */ - while (ptr->fd != -1 && + while (ptr->fd != -1 && connect(ptr->fd, use->ai_addr, use->ai_addrlen) < 0) { ptr->cached_errno= errno; if (errno == EINPROGRESS || /* nonblocking mode - first return, */ errno == EALREADY) /* nonblocking mode - subsequent returns */ { - struct pollfd fds[1] = { [0].fd = ptr->fd, [0].events = POLLOUT }; + 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) @@ -243,31 +245,31 @@ static memcached_return network_connect(memcached_server_st *ptr) if (fds[0].revents & POLLERR) { int err; - int len = sizeof (err); + socklen_t len = sizeof (err); (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len); - ptr->cached_errno= errno; + ptr->cached_errno= (err == 0) ? errno : err; } (void)close(ptr->fd); ptr->fd= -1; } - } + } else if (errno == EISCONN) /* we are connected :-) */ { break; - } + } else if (errno != EINTR) { (void)close(ptr->fd); ptr->fd= -1; break; - } + } } if (ptr->fd != -1) { - /* restore flags */ - if (ptr->root->connect_timeout && (flags & O_NONBLOCK) == 0) + /* restore flags */ + if (ptr->root->connect_timeout && (ptr->root->flags & MEM_NO_BLOCK) == 0) (void)fcntl(ptr->fd, F_SETFL, flags & ~O_NONBLOCK); WATCHPOINT_ASSERT(ptr->cursor_active == 0); @@ -289,6 +291,8 @@ static memcached_return network_connect(memcached_server_st *ptr) ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout; } ptr->server_failure_counter+= 1; + if (ptr->cached_errno == 0) + return MEMCACHED_TIMEOUT; return MEMCACHED_ERRNO; /* The last error should be from connect() */ } @@ -302,14 +306,31 @@ memcached_return memcached_connect(memcached_server_st *ptr) memcached_return rc= MEMCACHED_NO_SERVERS; LIBMEMCACHED_MEMCACHED_CONNECT_START(); - if (ptr->root->retry_timeout) + /* 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) { - struct timeval next_time; + struct timeval curr_time; - gettimeofday(&next_time, NULL); - if (next_time.tv_sec < ptr->next_retry) - return MEMCACHED_TIMEOUT; + 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) + { + ptr->next_retry= curr_time.tv_sec + ptr->root->retry_timeout; + ptr->server_failure_counter= 0; + } + + if (curr_time.tv_sec < ptr->next_retry) + { + if (memcached_behavior_get(ptr->root, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS)) + run_distribution(ptr->root); + + ptr->root->last_disconnected_server = ptr; + return MEMCACHED_SERVER_MARKED_DEAD; + } } + /* We need to clean up the multi startup piece */ switch (ptr->type) { @@ -328,6 +349,8 @@ memcached_return memcached_connect(memcached_server_st *ptr) WATCHPOINT_ASSERT(0); } + unlikely ( rc != MEMCACHED_SUCCESS) ptr->root->last_disconnected_server = ptr; + LIBMEMCACHED_MEMCACHED_CONNECT_END(); return rc;