static memcached_return io_wait(memcached_server_st *ptr, memc_read_or_write read_or_write) { struct pollfd fds[1]; short flags= 0; int error; if (read_or_write == MEM_WRITE) /* write */ flags= POLLOUT | POLLERR; else flags= POLLIN | POLLERR; memset(&fds, 0, sizeof(struct pollfd)); fds[0].fd= ptr->fd; fds[0].events= flags; error= poll(fds, 1, ptr->root->poll_timeout); if (error == 1) return MEMCACHED_SUCCESS; else if (error == 0) { return MEMCACHED_TIMEOUT; } /* Imposssible for anything other then -1 */ WATCHPOINT_ASSERT(error == -1); memcached_quit_server(ptr, 1); return MEMCACHED_FAILURE; }
void memcached_quit(memcached_st *ptr) { uint32_t x; if (memcached_server_count(ptr) == 0) return; if (memcached_server_count(ptr)) { for (x= 0; x < memcached_server_count(ptr); x++) { memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); memcached_quit_server(instance, false); } } }
memcached_return_t memcached_behavior_set(memcached_st *ptr, const memcached_behavior_t flag, uint64_t data) { switch (flag) { case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: ptr->number_of_replicas= (uint32_t)data; break; case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: ptr->io_msg_watermark= (uint32_t) data; break; case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: ptr->io_bytes_watermark= (uint32_t)data; break; case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: ptr->io_key_prefetch = (uint32_t)data; break; case MEMCACHED_BEHAVIOR_SND_TIMEOUT: ptr->snd_timeout= (int32_t)data; break; case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: ptr->rcv_timeout= (int32_t)data; break; case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: ptr->server_failure_limit= (uint32_t)data; break; case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: memcached_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol if (data) { ptr->flags.verify_key= false; } ptr->flags.binary_protocol= set_flag(data); break; case MEMCACHED_BEHAVIOR_SUPPORT_CAS: ptr->flags.support_cas= set_flag(data); break; case MEMCACHED_BEHAVIOR_NO_BLOCK: ptr->flags.no_block= set_flag(data); memcached_quit(ptr); break; case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: ptr->flags.buffer_requests= set_flag(data); memcached_quit(ptr); break; case MEMCACHED_BEHAVIOR_USE_UDP: if (memcached_server_count(ptr)) { return MEMCACHED_FAILURE; } ptr->flags.use_udp= set_flag(data); if (data) { ptr->flags.no_reply= set_flag(data); } break; case MEMCACHED_BEHAVIOR_TCP_NODELAY: ptr->flags.tcp_nodelay= set_flag(data); memcached_quit(ptr); break; case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: ptr->flags.tcp_keepalive= set_flag(data); memcached_quit(ptr); break; case MEMCACHED_BEHAVIOR_DISTRIBUTION: return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data); case MEMCACHED_BEHAVIOR_KETAMA: { if (data) { (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5); (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5); (void)memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA); } else { (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_DEFAULT); (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_DEFAULT); (void)memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA); } break; } case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: { (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5); (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5); ptr->flags.ketama_weighted= set_flag(data); /** @note We try to keep the same distribution going. This should be deprecated and rewritten. */ return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA); } case MEMCACHED_BEHAVIOR_HASH: return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data)); case MEMCACHED_BEHAVIOR_KETAMA_HASH: return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data)); case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: ptr->flags.use_cache_lookups= set_flag(data); memcached_quit(ptr); break; case MEMCACHED_BEHAVIOR_VERIFY_KEY: if (ptr->flags.binary_protocol) return MEMCACHED_FAILURE; ptr->flags.verify_key= set_flag(data); break; case MEMCACHED_BEHAVIOR_SORT_HOSTS: { ptr->flags.use_sort_hosts= set_flag(data); run_distribution(ptr); break; } case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: ptr->poll_timeout= (int32_t)data; break; case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: ptr->connect_timeout= (int32_t)data; break; case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: ptr->retry_timeout= (int32_t)data; break; case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: ptr->send_size= (int32_t)data; memcached_quit(ptr); break; case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: ptr->recv_size= (int32_t)data; memcached_quit(ptr); break; case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: ptr->tcp_keepidle= (uint32_t)data; memcached_quit(ptr); break; case MEMCACHED_BEHAVIOR_USER_DATA: return MEMCACHED_FAILURE; case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: ptr->flags.hash_with_prefix_key= set_flag(data); break; case MEMCACHED_BEHAVIOR_NOREPLY: ptr->flags.no_reply= set_flag(data); break; case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: ptr->flags.auto_eject_hosts= set_flag(data); break; case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: srandom((uint32_t) time(NULL)); ptr->flags.randomize_replica_read= set_flag(data); break; case MEMCACHED_BEHAVIOR_CORK: { memcached_server_write_instance_st instance; bool action= set_flag(data); if (action == false) { ptr->flags.cork= set_flag(false); return MEMCACHED_SUCCESS; } instance= memcached_server_instance_fetch(ptr, 0); if (! instance) return MEMCACHED_NO_SERVERS; /* We just try the first host, and if it is down we return zero */ memcached_return_t rc; rc= memcached_connect(instance); if (rc != MEMCACHED_SUCCESS) { return rc; } /* Now we test! */ memcached_ternary_t enabled; enabled= test_cork(instance, true); switch (enabled) { case MEM_FALSE: return ptr->cached_errno ? MEMCACHED_ERRNO : MEMCACHED_FAILURE ; case MEM_TRUE: { enabled= test_cork(instance, false); if (enabled == false) // Possible bug in OS? { memcached_quit_server(instance, false); // We should reset everything on this error. return MEMCACHED_ERRNO; // Errno will be true because we will have already set it. } ptr->flags.cork= true; ptr->flags.tcp_nodelay= true; memcached_quit(ptr); // We go on and reset the connections. } break; case MEM_NOT: default: return MEMCACHED_NOT_SUPPORTED; } } break; case MEMCACHED_BEHAVIOR_MAX: default: /* Shouldn't get here */ WATCHPOINT_ASSERT(0); return MEMCACHED_FAILURE; } return MEMCACHED_SUCCESS; }
ssize_t memcached_io_read(memcached_server_st *ptr, void *buffer, size_t length) { char *buffer_ptr; buffer_ptr= buffer; while (length) { uint8_t found_eof= 0; if (!ptr->read_buffer_length) { ssize_t data_read; while (1) { data_read= read(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER); if (data_read > 0) break; else if (data_read == -1) { ptr->cached_errno= errno; switch (errno) { case EAGAIN: { memcached_return rc; rc= io_wait(ptr, MEM_READ); if (rc == MEMCACHED_SUCCESS) continue; } /* fall trough */ default: { memcached_quit_server(ptr, 1); return -1; } } } else { found_eof= 1; break; } } ptr->read_data_length= data_read; ptr->read_buffer_length= data_read; ptr->read_ptr= ptr->read_buffer; } if (length > 1) { size_t difference; difference= (length > ptr->read_buffer_length) ? ptr->read_buffer_length : length; memcpy(buffer_ptr, ptr->read_ptr, difference); length -= difference; ptr->read_ptr+= difference; ptr->read_buffer_length-= difference; buffer_ptr+= difference; } else { *buffer_ptr= *ptr->read_ptr; ptr->read_ptr++; ptr->read_buffer_length--; buffer_ptr++; break; } if (found_eof) break; } return (size_t)(buffer_ptr - (char*)buffer); }
/* Eventually we will just kill off the server with the problem. */ void memcached_io_reset(memcached_server_st *ptr) { memcached_quit_server(ptr, 0); }
static ssize_t io_flush(memcached_server_st *ptr, memcached_return *error) { size_t sent_length; size_t return_length; char *local_write_ptr= ptr->write_buffer; size_t write_length= ptr->write_buffer_offset; *error= MEMCACHED_SUCCESS; if (ptr->write_buffer_offset == 0) return 0; /* Looking for memory overflows */ if (write_length == MEMCACHED_MAX_BUFFER) WATCHPOINT_ASSERT(ptr->write_buffer == local_write_ptr); WATCHPOINT_ASSERT((ptr->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length)); return_length= 0; while (write_length) { WATCHPOINT_ASSERT(write_length > 0); sent_length= 0; if (ptr->type == MEMCACHED_CONNECTION_UDP) { struct addrinfo *ai; ai= ptr->address_info; /* Crappy test code */ char buffer[HUGE_STRING_LEN + 8]; memset(buffer, 0, HUGE_STRING_LEN + 8); memcpy (buffer+8, local_write_ptr, write_length); buffer[0]= 0; buffer[1]= 0; buffer[2]= 0; buffer[3]= 0; buffer[4]= 0; buffer[5]= 1; buffer[6]= 0; buffer[7]= 0; sent_length= sendto(ptr->fd, buffer, write_length + 8, 0, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen); if (sent_length == -1) { WATCHPOINT_ERRNO(errno); WATCHPOINT_ASSERT(0); } sent_length-= 8; /* We remove the header */ } else { if ((ssize_t)(sent_length= write(ptr->fd, local_write_ptr, write_length)) == -1) { switch (errno) { case ENOBUFS: continue; case EAGAIN: { memcached_return rc; rc= io_wait(ptr, MEM_WRITE); if (rc == MEMCACHED_SUCCESS) continue; memcached_quit_server(ptr, 1); return -1; } default: memcached_quit_server(ptr, 1); ptr->cached_errno= errno; *error= MEMCACHED_ERRNO; return -1; } } } local_write_ptr+= sent_length; write_length-= sent_length; return_length+= sent_length; } WATCHPOINT_ASSERT(write_length == 0); WATCHPOINT_ASSERT(return_length == ptr->write_buffer_offset); ptr->write_buffer_offset= 0; return return_length; }