From: Jean-Charles Redoutey Date: Mon, 30 Nov 2009 19:57:41 +0000 (+0100) Subject: Fixed mget_execute possibly failing into some non ending recursive call X-Git-Tag: 0.40~122^2 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=24020ff57ce7b83038650c42952d3fe6d49fd417;p=m6w6%2Flibmemcached Fixed mget_execute possibly failing into some non ending recursive call --- diff --git a/libmemcached/memcached.h b/libmemcached/memcached.h index 722da814..f7729490 100644 --- a/libmemcached/memcached.h +++ b/libmemcached/memcached.h @@ -75,6 +75,7 @@ struct memcached_stat_st { struct memcached_st { uint8_t purging; + uint8_t processing_input; bool is_allocated; uint8_t distribution; uint8_t hash; diff --git a/libmemcached/memcached_io.c b/libmemcached/memcached_io.c index 693ce95c..f7469ead 100644 --- a/libmemcached/memcached_io.c +++ b/libmemcached/memcached_io.c @@ -120,10 +120,15 @@ static bool process_input_buffer(memcached_server_st *ptr) */ memcached_callback_st cb= *ptr->root->callbacks; + ptr->root->processing_input = 1; + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; memcached_return error; error= memcached_response(ptr, buffer, sizeof(buffer), &ptr->root->result); + + ptr->root->processing_input = 0; + if (error == MEMCACHED_SUCCESS) { for (unsigned int x= 0; x < cb.number_of_callback; x++) diff --git a/libmemcached/memcached_response.c b/libmemcached/memcached_response.c index fe13ddd5..01db4169 100644 --- a/libmemcached/memcached_response.c +++ b/libmemcached/memcached_response.c @@ -44,7 +44,7 @@ memcached_return memcached_response(memcached_server_st *ptr, memcached_result_st *result) { /* We may have old commands in the buffer not set, first purge */ - if (ptr->root->flags & MEM_NO_BLOCK) + if ((ptr->root->flags & MEM_NO_BLOCK) && (!ptr->root->processing_input)) (void)memcached_io_write(ptr, NULL, 0, 1); /* diff --git a/tests/function.c b/tests/function.c index 84a053a4..8df6b4cc 100644 --- a/tests/function.c +++ b/tests/function.c @@ -3922,7 +3922,7 @@ static test_return_t dump_test(memcached_st *memc) } #ifdef HAVE_LIBMEMCACHEDUTIL -static void* connection_release(void *arg) +static void* connection_release(void *arg) { struct { memcached_pool_st* pool; @@ -4169,7 +4169,7 @@ static test_return_t replication_randomize_mget_test(memcached_st *memc) rc= memcached_set(memc, keys[x], len[x], "1", 1, 0, 0); test_truth(rc == MEMCACHED_SUCCESS); } - + memcached_quit(memc); for (int x=0; x< 7; ++x) { @@ -5391,6 +5391,88 @@ static test_return_t wrong_failure_counter_test(memcached_st *memc) return TEST_SUCCESS; } + + + +/* + * Test that ensures mget_execute does not end into recursive calls that finally fails + */ +static test_return_t regression_bug_490486(memcached_st *memc) +{ + + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,1); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK,1); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT,1000); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT,1); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT,3600); + + /* + * I only want to hit _one_ server so I know the number of requests I'm + * sending in the pipeline. + */ + uint32_t number_of_hosts= memc->number_of_hosts; + memc->number_of_hosts= 1; + int max_keys= 20480; + + + char **keys= calloc((size_t)max_keys, sizeof(char*)); + size_t *key_length=calloc((size_t)max_keys, sizeof(size_t)); + + /* First add all of the items.. */ + char blob[1024] = {0}; + memcached_return rc; + for (int x= 0; x < max_keys; ++x) + { + char k[251]; + key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%u", x); + keys[x]= strdup(k); + assert(keys[x] != NULL); + rc= memcached_set(memc, keys[x], key_length[x], blob, sizeof(blob), 0, 0); + assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + } + + /* Try to get all of them with a large multiget */ + unsigned int counter= 0; + memcached_execute_function callbacks[1]= { [0]= &callback_counter }; + rc= memcached_mget_execute(memc, (const char**)keys, key_length, + (size_t)max_keys, callbacks, &counter, 1); + + assert(rc == MEMCACHED_SUCCESS); + char* the_value = NULL; + char the_key[MEMCACHED_MAX_KEY]; + size_t the_key_length; + size_t the_value_length; + uint32_t the_flags; + + do { + the_value = memcached_fetch(memc, the_key, &the_key_length, &the_value_length, &the_flags, &rc); + if((the_value!= NULL) && (rc == MEMCACHED_SUCCESS)) + { + ++counter; + free(the_value); + } + + }while( (the_value!= NULL) && (rc == MEMCACHED_SUCCESS)); + + + assert(rc == MEMCACHED_END); + + /* Verify that we got all of the items */ + assert(counter == (unsigned int)max_keys); + + /* Release all allocated resources */ + for (int x= 0; x < max_keys; ++x) + free(keys[x]); + free(keys); + free(key_length); + + memc->number_of_hosts= number_of_hosts; + return TEST_SUCCESS; +} + + + + test_st udp_setup_server_tests[] ={ {"set_udp_behavior_test", 0, set_udp_behavior_test}, {"add_tcp_server_udp_client_test", 0, add_tcp_server_udp_client_test}, @@ -5567,6 +5649,7 @@ test_st regression_tests[]= { {"lp:442914", 1, regression_bug_442914 }, {"lp:447342", 1, regression_bug_447342 }, {"lp:463297", 1, regression_bug_463297 }, + {"lp:490486", 1, regression_bug_490486 }, {0, 0, 0} };