X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=libmemcached%2Fio.cc;h=77db241e80262ea58604cf263bae01990ddb8dac;hb=5c09a7ed2edbb9876493f30d59433331b63f6bfc;hp=d7c13199c46cb62c62ea0df8a9cb001d07523acb;hpb=7ba11a92a63df071ee3f848c980c8459dc184ebc;p=m6w6%2Flibmemcached diff --git a/libmemcached/io.cc b/libmemcached/io.cc index d7c13199..77db241e 100644 --- a/libmemcached/io.cc +++ b/libmemcached/io.cc @@ -67,14 +67,17 @@ static bool repack_input_buffer(memcached_server_write_instance_st ptr) { do { /* Just try a single read to grab what's available */ - ssize_t nr= recv(ptr->fd, - ptr->read_ptr + ptr->read_data_length, - MEMCACHED_MAX_BUFFER - ptr->read_data_length, - MSG_DONTWAIT); - - switch (nr) + ssize_t nr; + if ((nr= recv(ptr->fd, + ptr->read_ptr + ptr->read_data_length, + MEMCACHED_MAX_BUFFER - ptr->read_data_length, + MSG_DONTWAIT)) <= 0) { - case SOCKET_ERROR: + if (nr == 0) + { + memcached_set_error(*ptr, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT); + } + else { switch (get_socket_errno()) { @@ -94,24 +97,19 @@ static bool repack_input_buffer(memcached_server_write_instance_st ptr) memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT); } } - break; - case 0: // Shutdown on the socket has occurred - { - memcached_set_error(*ptr, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT); - } break; + } + else // We read data, append to our read buffer + { + ptr->read_data_length+= size_t(nr); + ptr->read_buffer_length+= size_t(nr); - default: - { - ptr->read_data_length+= size_t(nr); - ptr->read_buffer_length+= size_t(nr); - return true; - } - break; + return true; } - } while (0); + } while (false); } + return false; } @@ -153,7 +151,9 @@ static bool process_input_buffer(memcached_server_write_instance_st ptr) { error= (*cb.callback[x])(ptr->root, &root->result, cb.context); if (error != MEMCACHED_SUCCESS) + { break; + } } /* @todo what should I do with the error message??? */ @@ -168,20 +168,6 @@ static bool process_input_buffer(memcached_server_write_instance_st ptr) static memcached_return_t io_wait(memcached_server_write_instance_st ptr, const memc_read_or_write read_or_write) { - struct pollfd fds; - fds.fd= ptr->fd; - fds.events= POLLIN; - - if (read_or_write == MEM_WRITE) /* write */ - { - fds.events= POLLOUT; - WATCHPOINT_SET(ptr->io_wait_count.write++); - } - else - { - WATCHPOINT_SET(ptr->io_wait_count.read++); - } - /* ** We are going to block on write, but at least on Solaris we might block ** on write if we haven't read anything from our input buffer.. @@ -192,78 +178,91 @@ static memcached_return_t io_wait(memcached_server_write_instance_st ptr, */ if (read_or_write == MEM_WRITE) { - if (memcached_fatal(memcached_purge(ptr))) + if (memcached_purge(ptr) == false) { return MEMCACHED_FAILURE; } } + struct pollfd fds; + fds.fd= ptr->fd; + fds.events= POLLIN; + fds.revents= 0; + + if (read_or_write == MEM_WRITE) /* write */ + { + fds.events= POLLOUT; + ptr->io_wait_count.write++; + } + else + { + ptr->io_wait_count.read++; + } + if (ptr->root->poll_timeout == 0) // Mimic 0 causes timeout behavior (not all platforms do this) { + ptr->io_wait_count.timeouts++; return memcached_set_error(*ptr, MEMCACHED_TIMEOUT, MEMCACHED_AT); } + int local_errno; size_t loop_max= 5; while (--loop_max) // While loop is for ERESTART or EINTR { - int error= poll(&fds, 1, ptr->root->poll_timeout); - switch (error) - { - case 1: // Success! - WATCHPOINT_IF_LABELED_NUMBER(read_or_write && loop_max < 4, "read() times we had to loop, decremented down from 5", loop_max); - WATCHPOINT_IF_LABELED_NUMBER(!read_or_write && loop_max < 4, "write() times we had to loop, decremented down from 5", loop_max); + int active_fd= poll(&fds, 1, ptr->root->poll_timeout); + if (active_fd >= 1) + { + assert_msg(active_fd == 1 , "poll() returned an unexpected value"); return MEMCACHED_SUCCESS; - - case 0: // Timeout occured, we let the while() loop do its thing. + } + else if (active_fd == 0) + { + ptr->io_wait_count.timeouts++; return memcached_set_error(*ptr, MEMCACHED_TIMEOUT, MEMCACHED_AT); + } - default: - WATCHPOINT_ERRNO(get_socket_errno()); - switch (get_socket_errno()) - { + // Only an error should result in this code being called. + local_errno= get_socket_errno(); // We cache in case memcached_quit_server() modifies errno + assert_msg(active_fd == -1 , "poll() returned an unexpected value"); + switch (local_errno) + { #ifdef TARGET_OS_LINUX - case ERESTART: + case ERESTART: #endif - case EINTR: - break; + case EINTR: + continue; - case EFAULT: - case ENOMEM: - return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT); + case EFAULT: + case ENOMEM: + return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT); - case EINVAL: - return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid")); + case EINVAL: + return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid")); - default: - if (fds.revents & POLLERR) + default: + if (fds.revents & POLLERR) + { + int err; + socklen_t len= sizeof (err); + if (getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0) { - int err; - socklen_t len= sizeof (err); - if (getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0) + if (err == 0) // treat this as EINTR { - if (err == 0) - { - continue; - } - errno= err; + continue; } + local_errno= err; } - else - { - memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT); - } - int local_errno= get_socket_errno(); // We cache in case memcached_quit_server() modifies errno - memcached_quit_server(ptr, true); - - return memcached_set_errno(*ptr, local_errno, MEMCACHED_AT); } + break; } + + break; // should only occur from poll error } memcached_quit_server(ptr, true); - return memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT); + return memcached_set_errno(*ptr, local_errno, MEMCACHED_AT); } static bool io_flush(memcached_server_write_instance_st ptr, @@ -277,9 +276,8 @@ static bool io_flush(memcached_server_write_instance_st ptr, */ { WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - memcached_return_t rc= memcached_purge(ptr); - if (rc != MEMCACHED_SUCCESS and rc != MEMCACHED_STORED) + if (memcached_purge(ptr) == false) { return false; } @@ -303,16 +301,8 @@ static bool io_flush(memcached_server_write_instance_st ptr, WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); WATCHPOINT_ASSERT(write_length > 0); - ssize_t sent_length= 0; - WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - if (with_flush) - { - sent_length= ::send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT); - } - else - { - sent_length= ::send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT|MSG_MORE); - } + int flags= with_flush ? MSG_NOSIGNAL|MSG_DONTWAIT : MSG_NOSIGNAL|MSG_DONTWAIT|MSG_MORE; + ssize_t sent_length= ::send(ptr->fd, local_write_ptr, write_length, flags); if (sent_length == SOCKET_ERROR) { @@ -348,7 +338,6 @@ static bool io_flush(memcached_server_write_instance_st ptr, } else if (rc == MEMCACHED_TIMEOUT) { - error= memcached_set_error(*ptr, MEMCACHED_TIMEOUT, MEMCACHED_AT); return false; } @@ -400,7 +389,7 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, while (length) { - if (not ptr->read_buffer_length) + if (ptr->read_buffer_length == 0) { ssize_t data_read; do @@ -421,11 +410,15 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, #ifdef TARGET_OS_LINUX case ERESTART: #endif - if (memcached_success(io_wait(ptr, MEM_READ))) { - continue; + memcached_return_t io_wait_ret; + if (memcached_success(io_wait_ret= io_wait(ptr, MEM_READ))) + { + continue; + } + + return io_wait_ret; } - return MEMCACHED_IN_PROGRESS; /* fall through */ @@ -457,15 +450,15 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, for blocking I/O we do not return 0 and for non-blocking case it will return EGAIN if data is not immediatly available. */ - WATCHPOINT_STRING("We had a zero length recv()"); memcached_quit_server(ptr, true); nread= -1; return memcached_set_error(*ptr, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT, memcached_literal_param("::rec() returned zero, server has disconnected")); } + ptr->io_wait_count._bytes_read+= data_read; } while (data_read <= 0); - ptr->io_bytes_sent = 0; + ptr->io_bytes_sent= 0; ptr->read_data_length= (size_t) data_read; ptr->read_buffer_length= (size_t) data_read; ptr->read_ptr= ptr->read_buffer; @@ -538,9 +531,9 @@ memcached_return_t memcached_io_slurp(memcached_server_write_instance_st ptr) /* fall through */ case ENOTCONN: // Programmer Error - WATCHPOINT_ASSERT(0); + assert(0); case ENOTSOCK: - WATCHPOINT_ASSERT(0); + assert(0); case EBADF: assert_msg(ptr->fd != INVALID_SOCKET, "Invalid socket state"); case EINVAL: @@ -555,15 +548,17 @@ memcached_return_t memcached_io_slurp(memcached_server_write_instance_st ptr) return MEMCACHED_CONNECTION_FAILURE; } -static ssize_t _io_write(memcached_server_write_instance_st ptr, - const void *buffer, size_t length, bool with_flush) +static bool _io_write(memcached_server_write_instance_st ptr, + const void *buffer, size_t length, bool with_flush, + size_t& written) { - WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); + assert(ptr->fd != INVALID_SOCKET); assert(memcached_is_udp(ptr->root) == false); - size_t original_length= length; const char *buffer_ptr= static_cast(buffer); + const size_t original_length= length; + while (length) { char *write_ptr; @@ -584,7 +579,8 @@ static ssize_t _io_write(memcached_server_write_instance_st ptr, memcached_return_t rc; if (io_flush(ptr, with_flush, rc) == false) { - return -1; + written= original_length -length; + return false; } } } @@ -595,41 +591,53 @@ static ssize_t _io_write(memcached_server_write_instance_st ptr, WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); if (io_flush(ptr, with_flush, rc) == false) { - return -1; + written= original_length -length; + return false; } } - return (ssize_t) original_length; + written= original_length -length; + + return true; } bool memcached_io_write(memcached_server_write_instance_st ptr) { - return (_io_write(ptr, NULL, 0, true) >= 0); + size_t written; + return _io_write(ptr, NULL, 0, true, written); } ssize_t memcached_io_write(memcached_server_write_instance_st ptr, const void *buffer, const size_t length, const bool with_flush) { - return _io_write(ptr, buffer, length, with_flush); + size_t written; + + if (_io_write(ptr, buffer, length, with_flush, written) == false) + { + return -1; + } + + return ssize_t(written); } -ssize_t memcached_io_writev(memcached_server_write_instance_st ptr, +bool memcached_io_writev(memcached_server_write_instance_st ptr, libmemcached_io_vector_st vector[], const size_t number_of, const bool with_flush) { + ssize_t complete_total= 0; ssize_t total= 0; for (size_t x= 0; x < number_of; x++, vector++) { - ssize_t returnable; - + complete_total+= vector->length; if (vector->length) { - if ((returnable= _io_write(ptr, vector->buffer, vector->length, false)) == -1) + size_t written; + if ((_io_write(ptr, vector->buffer, vector->length, false, written)) == false) { - return -1; + return false; } - total+= returnable; + total+= written; } } @@ -637,11 +645,11 @@ ssize_t memcached_io_writev(memcached_server_write_instance_st ptr, { if (memcached_io_write(ptr) == false) { - return -1; + return false; } } - return total; + return (complete_total == total); } @@ -815,7 +823,7 @@ memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr, } /* Now let's look in the buffer and copy as we go! */ - while (ptr->read_buffer_length && total_nr < size && !line_complete) + while (ptr->read_buffer_length and total_nr < size and line_complete == false) { *buffer_ptr = *ptr->read_ptr; if (*buffer_ptr == '\n')