#define MEMCACHED_MAX_HOST_LENGTH 64
#define MEMCACHED_WHEEL_SIZE 1024
#define MEMCACHED_STRIDE 4
+#define MEMCACHED_DEFAILT_TIMEOUT 100
typedef enum {
MEMCACHED_SUCCESS,
char *buffer, size_t buffer_length,
unsigned int server_key);
unsigned int memcached_generate_hash(memcached_st *ptr, char *key, size_t key_length);
-void memcached_quit_server(memcached_st *ptr, unsigned int server_key);
+void memcached_quit_server(memcached_st *ptr, unsigned int server_key, uint8_t io_death);
#define memcached_server_response_increment(A,B) A->hosts[B].stack_responses++
#define memcached_server_response_decrement(A,B) A->hosts[B].stack_responses--
}
string_ptr= memcached_string_create(ptr, &ptr->result_buffer, 0);
WATCHPOINT_ASSERT(string_ptr);
- ptr->poll_timeout= -1;
+ ptr->poll_timeout= MEMCACHED_DEFAILT_TIMEOUT;
ptr->distribution= MEMCACHED_DISTRIBUTION_MODULO;
return ptr;
sent_length= memcached_io_write(ptr, server_key, command, command_length, with_flush);
if (sent_length == -1 || sent_length != command_length)
- {
- memcached_quit_server(ptr, server_key);
rc= MEMCACHED_WRITE_FAILURE;
- }
return rc;
}
memcached_finish(ptr);
+ /*
+ If a server fails we warn about errors and start all over with sending keys
+ to the server.
+ */
for (x= 0; x < number_of_keys; x++)
{
unsigned int server_key;
if ((memcached_io_write(ptr, server_key, get_command, get_command_length, 0)) == -1)
{
- memcached_quit_server(ptr, server_key);
rc= MEMCACHED_SOME_ERRORS;
continue;
}
if ((memcached_io_write(ptr, server_key, keys[x], key_length[x], 0)) == -1)
{
ptr->hosts[server_key].cursor_active= 0;
- memcached_quit_server(ptr, server_key);
rc= MEMCACHED_SOME_ERRORS;
continue;
}
if ((memcached_io_write(ptr, server_key, " ", 1, 0)) == -1)
{
ptr->hosts[server_key].cursor_active= 0;
- memcached_quit_server(ptr, server_key);
rc= MEMCACHED_SOME_ERRORS;
continue;
}
/* We need to doo something about non-connnected hosts in the future */
if ((memcached_io_write(ptr, x, "\r\n", 2, 1)) == -1)
{
- memcached_quit_server(ptr, x);
rc= MEMCACHED_SOME_ERRORS;
}
}
{
struct pollfd fds[1];
short flags= 0;
+ int error;
+ int latch= 0;
if (read_or_write)
flags= POLLOUT | POLLERR;
fds[0].fd= ptr->hosts[server_key].fd;
fds[0].events= flags;
- if (poll(fds, 1, ptr->poll_timeout) < 0)
- return MEMCACHED_FAILURE;
+ while (latch == 0)
+ {
+ error= poll(fds, 1, ptr->poll_timeout);
- return MEMCACHED_SUCCESS;
+ if (error == 1)
+ return MEMCACHED_SUCCESS;
+ else if (error == -1)
+ {
+ memcached_quit_server(ptr, server_key, 1);
+ return MEMCACHED_FAILURE;
+ }
+ else if (error)
+ {
+ /* This is impossible */
+ WATCHPOINT_ASSERT(0);
+ return MEMCACHED_FAILURE;
+ }
+ else
+ latch++;
+ }
+
+ memcached_quit_server(ptr, server_key, 1);
+
+ return MEMCACHED_FAILURE; /* Timeout occurred */
}
ssize_t memcached_io_read(memcached_st *ptr, unsigned int server_key,
break;
default:
{
+ memcached_quit_server(ptr, server_key, 1);
ptr->cached_errno= errno;
return -1;
}
size_t sent_length;
sent_length= memcached_io_flush(ptr, server_key);
+ if (sent_length == -1)
+ return -1;
WATCHPOINT_ASSERT(sent_length == MEMCACHED_MAX_BUFFER);
ptr->hosts[server_key].write_ptr= ptr->hosts[server_key].write_buffer;
rc= MEMCACHED_SUCCESS;
if (ptr->flags & MEM_NO_BLOCK)
{
+ int error;
struct pollfd fds[1];
short flags= 0;
fds[0].events= flags;
fds[0].revents= 0;
- if (poll(fds, 1, ptr->poll_timeout == -1 ? 100 : ptr->poll_timeout) < 0)
- rc= MEMCACHED_FAILURE;
+ error= poll(fds, 1, ptr->poll_timeout == -1 ? 100 : ptr->poll_timeout);
+
+ if (error == -1)
+ {
+ memcached_quit_server(ptr, server_key, 1);
+ return MEMCACHED_FAILURE;
+ }
+ else if (error == 0)
+ return MEMCACHED_FAILURE; /* Timeout occurred */
}
close(ptr->hosts[server_key].fd);
}
/* Yes, we want to fall through */
default:
+ memcached_quit_server(ptr, server_key, 1);
ptr->cached_errno= errno;
return -1;
}
will force data to be completed.
*/
-void memcached_quit_server(memcached_st *ptr, unsigned int server_key)
+void memcached_quit_server(memcached_st *ptr, unsigned int server_key, uint8_t io_death)
{
- if (ptr->hosts == NULL ||
- ptr->number_of_hosts == 0 ||
- server_key > ptr->number_of_hosts)
+ if (server_key > ptr->number_of_hosts)
+ {
+ WATCHPOINT_ASSERT(0);
return;
+ }
if (ptr->hosts[server_key].fd != -1)
{
- memcached_return rc;
- rc= memcached_do(ptr, server_key, "quit\r\n", 6, 1);
- WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED);
-
- memcached_io_close(ptr, server_key);
+ if (io_death == 0)
+ {
+ memcached_return rc;
+ rc= memcached_do(ptr, server_key, "quit\r\n", 6, 1);
+ WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED);
+
+ memcached_io_close(ptr, server_key);
+ }
ptr->hosts[server_key].fd= -1;
ptr->hosts[server_key].stack_responses= 0;
ptr->hosts[server_key].cursor_active= 0;
void memcached_quit(memcached_st *ptr)
{
unsigned int x;
+ if (ptr->hosts == NULL ||
+ ptr->number_of_hosts == 0)
+ return;
if (ptr->hosts && ptr->number_of_hosts)
{
for (x= 0; x < ptr->number_of_hosts; x++)
- memcached_quit_server(ptr, x);
+ memcached_quit_server(ptr, x, 0);
}
ptr->connected= 0;
if ((sent_length= memcached_io_write(ptr, server_key, "\r\n", 2, to_write)) == -1)
{
- memcached_quit_server(ptr, server_key);
rc= MEMCACHED_WRITE_FAILURE;
goto error;
}
return 0;
}
+uint8_t user_supplied_bug10(memcached_st *memc)
+{
+ char *key= "foo";
+ char *value;
+ size_t value_length= 512;
+ unsigned int x;
+ int key_len= 3;
+ memcached_return rc;
+ unsigned int set= 1;
+ memcached_st *mclone= memcached_clone(NULL, memc);
+
+ memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_NO_BLOCK, &set);
+ memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_TCP_NODELAY, &set);
+
+ value = (char*)malloc(value_length * sizeof(char));
+
+ for (x= 0; x < value_length; x++)
+ value[x]= (char) (x % 127);
+
+ for (x= 1; x <= 100000; ++x)
+ {
+ rc= memcached_set(mclone, key, key_len,value, value_length, 0, 0);
+
+ assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_WRITE_FAILURE);
+
+ if (rc == MEMCACHED_WRITE_FAILURE)
+ x--;
+ }
+
+ free(value);
+ memcached_free(mclone);
+
+ return 0;
+}
+
uint8_t result_static(memcached_st *memc)
{
memcached_result_st result;
{"user_supplied_bug7", 1, user_supplied_bug7 },
{"user_supplied_bug8", 1, user_supplied_bug8 },
{"user_supplied_bug9", 1, user_supplied_bug9 },
+ {"user_supplied_bug10", 1, user_supplied_bug10 },
{0, 0, 0}
};