From: Brian Aker Date: Tue, 6 Jan 2009 22:08:04 +0000 (-0800) Subject: Import new purge work from trond X-Git-Tag: 0.26~27 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=6b020861bcd821c005e218f45d9c6cea8a9d0947;p=m6w6%2Flibmemcached Import new purge work from trond --- diff --git a/ChangeLog b/ChangeLog index 8ff99b09..ba1964db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 0.26 * Fix for decrement on hash key * Fixed assert that was catching bad memset() call in host_reset() + * Fix purge issue for blocked IO which has been stacked. 0.25 Fri Nov 28 09:59:35 PST 2008 * Jenkins HASH added. diff --git a/libmemcached/memcached_io.c b/libmemcached/memcached_io.c index 6f852893..9a11556b 100644 --- a/libmemcached/memcached_io.c +++ b/libmemcached/memcached_io.c @@ -30,7 +30,6 @@ static memcached_return io_wait(memcached_server_st *ptr, fds[0].fd= ptr->fd; fds[0].events= flags; -#ifdef NOT_DONE /* ** 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.. @@ -41,10 +40,10 @@ static memcached_return io_wait(memcached_server_st *ptr, */ if (read_or_write == MEM_WRITE) { - if (memcached_purge(ptr) != MEMCACHED_SUCCESS || memcached_purge(ptr) != MEMCACHED_STORED) - return MEMCACHED_FAILURE; + memcached_return rc=memcached_purge(ptr); + if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED) + return MEMCACHED_FAILURE; } -#endif error= poll(fds, 1, ptr->root->poll_timeout); @@ -216,7 +215,9 @@ ssize_t memcached_io_write(memcached_server_st *ptr, if (sent_length == -1) return -1; - WATCHPOINT_ASSERT(sent_length == MEMCACHED_MAX_BUFFER); + /* If io_flush calls memcached_purge, sent_length may be 0 */ + if (sent_length != 0) + WATCHPOINT_ASSERT(sent_length == MEMCACHED_MAX_BUFFER); } } @@ -265,6 +266,19 @@ memcached_return memcached_io_close(memcached_server_st *ptr) static ssize_t io_flush(memcached_server_st *ptr, memcached_return *error) { + /* + ** We might want to purge the input buffer if we haven't consumed + ** any output yet... The test for the limits is the purge is inline + ** in the purge function to avoid duplicating the logic.. + */ + { + memcached_return rc; + WATCHPOINT_ASSERT(ptr->fd != -1); + rc= memcached_purge(ptr); + + if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED) + return -1; + } ssize_t sent_length; size_t return_length; char *local_write_ptr= ptr->write_buffer; @@ -320,22 +334,6 @@ static ssize_t io_flush(memcached_server_st *ptr, } else { -#ifdef NOT_DONE - /* - ** We might want to purge the input buffer if we haven't consumed - ** any output yet... The test for the limits is the purge is inline - ** in the purge function to avoid duplicating the logic.. - */ - { - memcached_return rc; - WATCHPOINT_ASSERT(ptr->fd != -1); - rc= memcached_purge(ptr); - - if (rc != MEMCACHED_SUCCESS || rc != MEMCACHED_STORED) - return -1; - } -#endif - WATCHPOINT_ASSERT(ptr->fd != -1); if ((sent_length= write(ptr->fd, local_write_ptr, write_length)) == -1) @@ -349,7 +347,7 @@ static ssize_t io_flush(memcached_server_st *ptr, memcached_return rc; rc= io_wait(ptr, MEM_WRITE); - if (rc == MEMCACHED_SUCCESS) + if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_TIMEOUT) continue; memcached_quit_server(ptr, 1); @@ -386,3 +384,28 @@ void memcached_io_reset(memcached_server_st *ptr) { memcached_quit_server(ptr, 1); } + +/** + * Read a given number of bytes from the server and place it into a specific + * buffer. Reset the IO channel on this server if an error occurs. + */ +memcached_return memcached_safe_read(memcached_server_st *ptr, + void *dta, + size_t size) +{ + size_t offset= 0; + char *data= dta; + + while (offset < size) + { + ssize_t nread= memcached_io_read(ptr, data + offset, size - offset); + if (nread <= 0) + { + memcached_io_reset(ptr); + return MEMCACHED_UNKNOWN_READ_FAILURE; + } + offset+= nread; + } + + return MEMCACHED_SUCCESS; +} diff --git a/libmemcached/memcached_io.h b/libmemcached/memcached_io.h index 8361a577..3da8af75 100644 --- a/libmemcached/memcached_io.h +++ b/libmemcached/memcached_io.h @@ -10,4 +10,12 @@ void memcached_io_reset(memcached_server_st *ptr); ssize_t memcached_io_read(memcached_server_st *ptr, void *buffer, size_t length); memcached_return memcached_io_close(memcached_server_st *ptr); +/* Read n bytes of data from the server and store them in dta */ +memcached_return memcached_safe_read(memcached_server_st *ptr, + void *dta, + size_t size); +/* Read a single response from the server */ +memcached_return memcached_read_one_response(memcached_server_st *ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result); #endif /* __MEMCACHED_IO_H__ */ diff --git a/libmemcached/memcached_purge.c b/libmemcached/memcached_purge.c index c73e97ff..96bf1d27 100644 --- a/libmemcached/memcached_purge.c +++ b/libmemcached/memcached_purge.c @@ -1,21 +1,17 @@ -#include - #include "common.h" #include "memcached_io.h" +#include "memcached_constants.h" -memcached_return memcached_purge(memcached_server_st *ptr) +memcached_return memcached_purge(memcached_server_st *ptr) { - memcached_return rc; - int32_t timeout; - char buffer[2048]; - memcached_result_st result; - memcached_result_st *result_ptr; + uint32_t x; + memcached_return ret= MEMCACHED_SUCCESS; if (ptr->root->purging || /* already purging */ - (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark && - ptr->io_bytes_sent < ptr->root->io_bytes_watermark) || - (ptr->io_bytes_sent > ptr->root->io_bytes_watermark && - memcached_server_response_count(ptr) < 10)) + (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark && + ptr->io_bytes_sent < ptr->root->io_bytes_watermark) || + (ptr->io_bytes_sent > ptr->root->io_bytes_watermark && + memcached_server_response_count(ptr) < 2)) { return MEMCACHED_SUCCESS; } @@ -28,33 +24,53 @@ memcached_return memcached_purge(memcached_server_st *ptr) /* Force a flush of the buffer to ensure that we don't have the n-1 pending requests buffered up.. */ if (memcached_io_write(ptr, NULL, 0, 1) == -1) - return MEMCACHED_FAILURE; + { + ptr->root->purging= 0; + return MEMCACHED_WRITE_FAILURE; + } WATCHPOINT_ASSERT(ptr->fd != -1); - /* we have already incremented the response counter, and memcached_response - will read out all messages.. To avoid memcached_response to wait forever - for a response to a command I have in my buffer, let's decrement the - response counter :) */ - memcached_server_response_decrement(ptr); - - /* memcached_response may call memcached_io_read, but let's use a short - timeout if there is no data yet */ - timeout= ptr->root->poll_timeout; - ptr->root->poll_timeout= 1; - result_ptr= memcached_result_create(ptr->root, &result); - - if (result_ptr == NULL) - return MEMCACHED_FAILURE; + int no_msg= memcached_server_response_count(ptr) - 1; + if (no_msg > 0) + { + memcached_result_st result; + memcached_result_st *result_ptr; + char buffer[SMALL_STRING_LEN]; - WATCHPOINT_ASSERT(ptr->fd != -1); - rc= memcached_response(ptr, buffer, sizeof(buffer), &result); - WATCHPOINT_ERROR(rc); - WATCHPOINT_ASSERT(ptr->fd != -1); - ptr->root->poll_timeout= timeout; - memcached_server_response_increment(ptr); - ptr->root->purging = 0; + /* + * We need to increase the timeout, because we might be waiting for + * data to be sent from the server (the commands was in the output buffer + * and just flushed + */ + long timeo= ptr->root->poll_timeout; + ptr->root->poll_timeout= 2000; + + result_ptr= memcached_result_create(ptr->root, &result); + WATCHPOINT_ASSERT(result_ptr); - memcached_result_free(&result); + for (x= 0; x < no_msg; x++) + { + memcached_result_reset(result_ptr); + memcached_return rc= memcached_read_one_response(ptr, buffer, + sizeof (buffer), + result_ptr); + /* + * Purge doesn't care for what kind of command results that is received. + * The only kind of errors I care about if is I'm out of sync with the + * protocol or have problems reading data from the network.. + */ + if (rc== MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_UNKNOWN_READ_FAILURE) + { + WATCHPOINT_ERROR(rc); + ret = rc; + memcached_io_reset(ptr); + } + } + + memcached_result_free(result_ptr); + ptr->root->poll_timeout=timeo; + } + ptr->root->purging= 0; - return rc; + return ret; } diff --git a/libmemcached/memcached_response.c b/libmemcached/memcached_response.c index 3a071c14..5c44e5f2 100644 --- a/libmemcached/memcached_response.c +++ b/libmemcached/memcached_response.c @@ -8,79 +8,102 @@ #include "common.h" #include "memcached_io.h" -static memcached_return binary_response(memcached_server_st *ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result); - -memcached_return memcached_response(memcached_server_st *ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result) +static memcached_return textual_read_one_response(memcached_server_st *ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result); +static memcached_return binary_read_one_response(memcached_server_st *ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result); + +memcached_return memcached_read_one_response(memcached_server_st *ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result) { - unsigned int x; - size_t send_length; - char *buffer_ptr; - unsigned int max_messages; - + memcached_server_response_decrement(ptr); - send_length= 0; - /* UDP at the moment is odd...*/ - if (ptr->type == MEMCACHED_CONNECTION_UDP) - { - char buffer[8]; - ssize_t read_length; + memcached_return rc; + if (ptr->root->flags & MEM_BINARY_PROTOCOL) + rc= binary_read_one_response(ptr, buffer, buffer_length, result); + else + rc= textual_read_one_response(ptr, buffer, buffer_length, result); - return MEMCACHED_SUCCESS; + unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE || + rc == MEMCACHED_PROTOCOL_ERROR || + rc == MEMCACHED_CLIENT_ERROR || + rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) + memcached_io_reset(ptr); - read_length= memcached_io_read(ptr, buffer, 8); - } + return rc; +} +memcached_return memcached_response(memcached_server_st *ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result) +{ /* We may have old commands in the buffer not set, first purge */ if (ptr->root->flags & MEM_NO_BLOCK) (void)memcached_io_write(ptr, NULL, 0, 1); - if (ptr->root->flags & MEM_BINARY_PROTOCOL) - return binary_response(ptr, buffer, buffer_length, result); - - max_messages= memcached_server_response_count(ptr); - for (x= 0; x < max_messages; x++) - { - size_t total_length= 0; - buffer_ptr= buffer; - - - while (1) - { - ssize_t read_length; - - read_length= memcached_io_read(ptr, buffer_ptr, 1); - WATCHPOINT_ASSERT(*buffer_ptr != '\0'); + /* + * The previous implementation purged all pending requests and just + * returned the last one. Purge all pending messages to ensure backwards + * compatibility. + */ + if ((ptr->root->flags & MEM_BINARY_PROTOCOL) == 0) + while (memcached_server_response_count(ptr) > 1) { + memcached_return rc= memcached_read_one_response(ptr, buffer, buffer_length, result); + + unlikely (rc != MEMCACHED_END && + rc != MEMCACHED_STORED && + rc != MEMCACHED_SUCCESS && + rc != MEMCACHED_STAT && + rc != MEMCACHED_DELETED && + rc != MEMCACHED_NOTFOUND && + rc != MEMCACHED_NOTSTORED && + rc != MEMCACHED_DATA_EXISTS) + return rc; + } - if (read_length != 1) - { - memcached_io_reset(ptr); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } + return memcached_read_one_response(ptr, buffer, buffer_length, result); +} - if (*buffer_ptr == '\n') - break; - else - buffer_ptr++; +static memcached_return memcached_readline(memcached_server_st *ptr, + char *buffer, + size_t size) +{ + bool line_complete= false; + char *buffer_ptr= buffer; + int total_nr=0; - total_length++; - WATCHPOINT_ASSERT(total_length <= buffer_length); + while (!line_complete) + { + if (memcached_io_read(ptr, buffer_ptr, 1) != 1) + return MEMCACHED_UNKNOWN_READ_FAILURE; - if (total_length >= buffer_length) - { - memcached_io_reset(ptr); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } + WATCHPOINT_ASSERT(*buffer_ptr != '\0'); + if (*buffer_ptr == '\n') + line_complete=true; + else + { + ++buffer_ptr; + ++total_nr; } - buffer_ptr++; - *buffer_ptr= 0; - memcached_server_response_decrement(ptr); + if (total_nr == size) + return MEMCACHED_PROTOCOL_ERROR; } + return MEMCACHED_SUCCESS; +} + +static memcached_return textual_read_one_response(memcached_server_st *ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result) +{ + memcached_return rc=memcached_readline(ptr, buffer, buffer_length); + if (rc != MEMCACHED_SUCCESS) + return rc; + switch(buffer[0]) { case 'V': /* VALUE || VERSION */ @@ -105,7 +128,6 @@ memcached_return memcached_response(memcached_server_st *ptr, { WATCHPOINT_STRING(buffer); WATCHPOINT_ASSERT(0); - memcached_io_reset(ptr); return MEMCACHED_UNKNOWN_READ_FAILURE; } case 'O': /* OK */ @@ -125,7 +147,6 @@ memcached_return memcached_response(memcached_server_st *ptr, { WATCHPOINT_STRING(buffer); WATCHPOINT_ASSERT(0); - memcached_io_reset(ptr); return MEMCACHED_UNKNOWN_READ_FAILURE; } } @@ -138,45 +159,30 @@ memcached_return memcached_response(memcached_server_st *ptr, else if (buffer[4] == 'S') return MEMCACHED_NOTSTORED; else - { - memcached_io_reset(ptr); return MEMCACHED_UNKNOWN_READ_FAILURE; - } } case 'E': /* PROTOCOL ERROR or END */ { if (buffer[1] == 'N') return MEMCACHED_END; else if (buffer[1] == 'R') - { - memcached_io_reset(ptr); return MEMCACHED_PROTOCOL_ERROR; - } else if (buffer[1] == 'X') - { return MEMCACHED_DATA_EXISTS; - } else - { - memcached_io_reset(ptr); return MEMCACHED_UNKNOWN_READ_FAILURE; - } } case 'C': /* CLIENT ERROR */ - memcached_io_reset(ptr); return MEMCACHED_CLIENT_ERROR; default: { unsigned long long auto_return_value; - if (sscanf(buffer, "%llu", &auto_return_value) == 1) + if (sscanf(buffer, "%llu", &auto_return_value) == 1) return MEMCACHED_SUCCESS; - memcached_io_reset(ptr); - return MEMCACHED_UNKNOWN_READ_FAILURE; } - } return MEMCACHED_SUCCESS; @@ -194,47 +200,18 @@ size_t memcached_result_length(memcached_result_st *ptr) return memcached_string_length(sptr); } -/** - * Read a given number of bytes from the server and place it into a specific - * buffer. Reset the IO channel or this server if an error occurs. - */ -static memcached_return safe_read(memcached_server_st *ptr, void *dta, - size_t size) -{ - size_t offset= 0; - char *data= dta; - - while (offset < size) - { - ssize_t nread= memcached_io_read(ptr, data + offset, size - offset); - if (nread <= 0) - { - memcached_io_reset(ptr); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - offset += nread; - } - - return MEMCACHED_SUCCESS; -} - -static memcached_return binary_response(memcached_server_st *ptr, - char *buffer, - size_t buffer_length, - memcached_result_st *result) +static memcached_return binary_read_one_response(memcached_server_st *ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result) { protocol_binary_response_header header; - memcached_server_response_decrement(ptr); - unlikely (safe_read(ptr, &header.bytes, - sizeof(header.bytes)) != MEMCACHED_SUCCESS) + unlikely (memcached_safe_read(ptr, &header.bytes, + sizeof(header.bytes)) != MEMCACHED_SUCCESS) return MEMCACHED_UNKNOWN_READ_FAILURE; unlikely (header.response.magic != PROTOCOL_BINARY_RES) - { - memcached_io_reset(ptr); return MEMCACHED_PROTOCOL_ERROR; - } /* ** Convert the header to host local endian! @@ -256,33 +233,25 @@ static memcached_return binary_response(memcached_server_st *ptr, memcached_result_reset(result); result->cas= header.response.cas; - if (safe_read(ptr, &result->flags, - sizeof(result->flags)) != MEMCACHED_SUCCESS) - { + if (memcached_safe_read(ptr, &result->flags, + sizeof (result->flags)) != MEMCACHED_SUCCESS) return MEMCACHED_UNKNOWN_READ_FAILURE; - } + result->flags= ntohl(result->flags); bodylen -= header.response.extlen; result->key_length= keylen; - if (safe_read(ptr, result->key, keylen) != MEMCACHED_SUCCESS) - { + if (memcached_safe_read(ptr, result->key, keylen) != MEMCACHED_SUCCESS) return MEMCACHED_UNKNOWN_READ_FAILURE; - } bodylen -= keylen; if (memcached_string_check(&result->value, bodylen) != MEMCACHED_SUCCESS) - { - memcached_io_reset(ptr); return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - } char *vptr= memcached_string_value(&result->value); - if (safe_read(ptr, vptr, bodylen) != MEMCACHED_SUCCESS) - { + if (memcached_safe_read(ptr, vptr, bodylen) != MEMCACHED_SUCCESS) return MEMCACHED_UNKNOWN_READ_FAILURE; - } memcached_string_set_length(&result->value, bodylen); } @@ -291,16 +260,12 @@ static memcached_return binary_response(memcached_server_st *ptr, case PROTOCOL_BINARY_CMD_DECREMENT: { if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t)) - { return MEMCACHED_PROTOCOL_ERROR; - } WATCHPOINT_ASSERT(bodylen == buffer_length); uint64_t val; - if (safe_read(ptr, &val, sizeof(val)) != MEMCACHED_SUCCESS) - { + if (memcached_safe_read(ptr, &val, sizeof(val)) != MEMCACHED_SUCCESS) return MEMCACHED_UNKNOWN_READ_FAILURE; - } val= ntohll(val); memcpy(buffer, &val, sizeof(val)); @@ -312,8 +277,8 @@ static memcached_return binary_response(memcached_server_st *ptr, if (bodylen >= buffer_length) /* not enough space in buffer.. should not happen... */ return MEMCACHED_UNKNOWN_READ_FAILURE; - else - safe_read(ptr, buffer, bodylen); + else if (memcached_safe_read(ptr, buffer, bodylen) != MEMCACHED_SUCCESS) + return MEMCACHED_UNKNOWN_READ_FAILURE; } break; case PROTOCOL_BINARY_CMD_FLUSH: @@ -346,8 +311,10 @@ static memcached_return binary_response(memcached_server_st *ptr, { size_t keylen= header.response.keylen; memset(buffer, 0, buffer_length); - safe_read(ptr, buffer, keylen); - safe_read(ptr, buffer + keylen + 1, bodylen - keylen); + if (memcached_safe_read(ptr, buffer, keylen) != MEMCACHED_SUCCESS || + memcached_safe_read(ptr, buffer + keylen + 1, + bodylen - keylen) != MEMCACHED_SUCCESS) + return MEMCACHED_UNKNOWN_READ_FAILURE; } } break; @@ -355,7 +322,6 @@ static memcached_return binary_response(memcached_server_st *ptr, { /* Command not implemented yet! */ WATCHPOINT_ASSERT(0); - memcached_io_reset(ptr); return MEMCACHED_PROTOCOL_ERROR; } } @@ -367,7 +333,8 @@ static memcached_return binary_response(memcached_server_st *ptr, while (bodylen > 0) { size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen; - safe_read(ptr, buffer, nr); + if (memcached_safe_read(ptr, buffer, nr) != MEMCACHED_SUCCESS) + return MEMCACHED_UNKNOWN_READ_FAILURE; bodylen -= nr; } } diff --git a/tests/function.c b/tests/function.c index ab6d4567..7ec22d4c 100644 --- a/tests/function.c +++ b/tests/function.c @@ -395,10 +395,13 @@ static test_return cas2_test(memcached_st *memc) static test_return cas_test(memcached_st *memc) { memcached_return rc; - char *key= "fun"; - size_t key_length= strlen("fun"); - char *value= "we the people"; - size_t value_length= strlen("we the people"); + const char *key= "fun"; + size_t key_length= strlen(key); + const char *value= "we the people"; + size_t value_length= strlen(value); + const char *value2= "change the value"; + size_t value2_length= strlen(value2); + memcached_result_st results_obj; memcached_result_st *results; unsigned int set= 1; @@ -421,24 +424,27 @@ static test_return cas_test(memcached_st *memc) assert(results); assert(rc == MEMCACHED_SUCCESS); WATCHPOINT_ASSERT(memcached_result_cas(results)); - - assert(!memcmp(value, "we the people", strlen("we the people"))); - assert(strlen("we the people") == value_length); + assert(!memcmp(value, memcached_result_value(results), value_length)); + assert(strlen(memcached_result_value(results)) == value_length); assert(rc == MEMCACHED_SUCCESS); + uint64_t cas = memcached_result_cas(results); - rc= memcached_cas(memc, key, key_length, - "change the value", strlen("change the value"), - 0, 0, memcached_result_cas(results)); - + #if 0 + results= memcached_fetch_result(memc, &results_obj, &rc); + assert(rc == MEMCACHED_END); + assert(results == NULL); +#endif + + rc= memcached_cas(memc, key, key_length, value2, value2_length, 0, 0, cas); assert(rc == MEMCACHED_SUCCESS); - rc= memcached_cas(memc, key, key_length, - "change the value", strlen("change the value"), - 0, 0, 23); - + /* + * The item will have a new cas value, so try to set it again with the old + * value. This should fail! + */ + rc= memcached_cas(memc, key, key_length, value2, value2_length, 0, 0, cas); assert(rc == MEMCACHED_DATA_EXISTS); - memcached_result_free(&results_obj); return 0; @@ -1397,13 +1403,11 @@ static test_return user_supplied_bug1(memcached_st *memc) sprintf(key, "%d", x); rc = memcached_set(memc, key, strlen(key), randomstuff, strlen(randomstuff), 10, 0); - WATCHPOINT_ERROR(rc); assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); /* If we fail, lets try again */ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) rc = memcached_set(memc, key, strlen(key), randomstuff, strlen(randomstuff), 10, 0); - WATCHPOINT_ERROR(rc); assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); } @@ -1931,7 +1935,11 @@ static test_return user_supplied_bug12(memcached_st *memc) 1, &number_value); assert(value == NULL); - assert(rc == MEMCACHED_NOTFOUND); + /* The binary protocol will set the key if it doesn't exist */ + if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1) + assert(rc == MEMCACHED_SUCCESS); + else + assert(rc == MEMCACHED_NOTFOUND); rc= memcached_set(memc, "autoincrement", strlen("autoincrement"), "1", 1, 0, 0); @@ -2150,6 +2158,33 @@ test_return user_supplied_bug19(memcached_st *memc) return 0; } +/* CAS test from Andei */ +test_return user_supplied_bug20(memcached_st *memc) +{ + memcached_return status; + memcached_result_st *result, result_obj; + char *key = "abc"; + size_t key_len = strlen("abc"); + char *value = "foobar"; + size_t value_len = strlen(value); + + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); + + status = memcached_set(memc, key, key_len, value, value_len, (time_t)0, (uint32_t)0); + assert(status == MEMCACHED_SUCCESS); + + status = memcached_mget(memc, &key, &key_len, 1); + assert(status == MEMCACHED_SUCCESS); + + memcached_result_create(memc, &result_obj); + result= memcached_fetch_result(memc, &result_obj, &status); + + assert(result); + assert(status == MEMCACHED_SUCCESS); + + return 0; +} + #include "ketama_test_cases.h" test_return user_supplied_bug18(memcached_st *trash) { @@ -3022,7 +3057,7 @@ test_st user_tests[] ={ {"user_supplied_bug8", 1, user_supplied_bug8 }, {"user_supplied_bug9", 1, user_supplied_bug9 }, {"user_supplied_bug10", 1, user_supplied_bug10 }, -// {"user_supplied_bug11", 1, user_supplied_bug11 }, + {"user_supplied_bug11", 1, user_supplied_bug11 }, {"user_supplied_bug12", 1, user_supplied_bug12 }, {"user_supplied_bug13", 1, user_supplied_bug13 }, {"user_supplied_bug14", 1, user_supplied_bug14 }, @@ -3031,6 +3066,7 @@ test_st user_tests[] ={ {"user_supplied_bug17", 1, user_supplied_bug17 }, {"user_supplied_bug18", 1, user_supplied_bug18 }, {"user_supplied_bug19", 1, user_supplied_bug19 }, + {"user_supplied_bug20", 1, user_supplied_bug20 }, {0, 0, 0} };