From: Brian Aker Date: Wed, 4 Jan 2012 05:59:51 +0000 (-0800) Subject: Merge from build trunk. X-Git-Tag: 1.0.3~3^2~1 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=920b0f21e75bb5b145a7de7383f5ae8c4a2c358a;hp=256805451de4f0dc6fe3b976894483b43313f46e;p=awesomized%2Flibmemcached Merge from build trunk. --- diff --git a/clients/client_options.h b/clients/client_options.h index 57aefd2b..c3420b49 100644 --- a/clients/client_options.h +++ b/clients/client_options.h @@ -35,6 +35,7 @@ enum memcached_options { OPT_HASH, OPT_BINARY, OPT_UDP, + OPT_BUFFER, OPT_USERNAME, OPT_PASSWD, OPT_STAT_ARGS, diff --git a/clients/execute.cc b/clients/execute.cc index 1ada836f..b2769545 100644 --- a/clients/execute.cc +++ b/clients/execute.cc @@ -15,7 +15,7 @@ */ #include -#include "execute.h" +#include "clients/execute.h" unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of) { @@ -27,10 +27,15 @@ unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int numbe memcached_return_t rc= memcached_set(memc, pairs[x].key, pairs[x].key_length, pairs[x].value, pairs[x].value_length, 0, 0); - if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) + if (rc != MEMCACHED_SUCCESS and rc != MEMCACHED_BUFFERED) { - fprintf(stderr, "Failured on insert of %.*s\n", + fprintf(stderr, "%s:%d Failure on insert (%s) of %.*s\n", + __FILE__, __LINE__, + memcached_last_error_message(memc), (unsigned int)pairs[x].key_length, pairs[x].key); + + // We will try to reconnect and see if that fixes the issue + memcached_quit(memc); } else { @@ -54,23 +59,27 @@ unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int numbe for (retrieved= 0,x= 0; x < number_of; x++) { - char *value; size_t value_length; uint32_t flags; - unsigned int fetch_key; - fetch_key= (unsigned int)((unsigned int)random() % number_of); + unsigned int fetch_key= (unsigned int)((unsigned int)random() % number_of); - value= memcached_get(memc, pairs[fetch_key].key, pairs[fetch_key].key_length, - &value_length, &flags, &rc); + char *value= memcached_get(memc, pairs[fetch_key].key, pairs[fetch_key].key_length, + &value_length, &flags, &rc); if (rc != MEMCACHED_SUCCESS) - fprintf(stderr, "Failured on read of %.*s\n", + { + fprintf(stderr, "%s:%d Failure on read(%s) of %.*s\n", + __FILE__, __LINE__, + memcached_last_error_message(memc), (unsigned int)pairs[fetch_key].key_length, pairs[fetch_key].key); + } else + { retrieved++; + } - free(value); + ::free(value); } return retrieved; @@ -116,7 +125,8 @@ unsigned int execute_mget(memcached_st *memc, rc= memcached_fetch_execute(memc, callbacks, (void *)&retrieved, 1); if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_END) { - fprintf(stderr, "Failed to execute mget: %s\n", + fprintf(stderr, "%s:%d Failed to execute mget: %s\n", + __FILE__, __LINE__, memcached_strerror(memc, rc)); memcached_quit(memc); return 0; @@ -124,7 +134,8 @@ unsigned int execute_mget(memcached_st *memc, } else { - fprintf(stderr, "Failed to execute mget: %s\n", + fprintf(stderr, "%s:%d Failed to execute mget: %s\n", + __FILE__, __LINE__, memcached_strerror(memc, rc)); memcached_quit(memc); return 0; diff --git a/clients/memcp.cc b/clients/memcp.cc index 4f4f8e10..5422aa73 100644 --- a/clients/memcp.cc +++ b/clients/memcp.cc @@ -42,6 +42,8 @@ static void options_parse(int argc, char *argv[]); static bool opt_binary= false; +static bool opt_udp= false; +static bool opt_buffer= false; static int opt_verbose= 0; static char *opt_servers= NULL; static char *opt_hash= NULL; @@ -61,8 +63,8 @@ static long strtol_wrapper(const char *nptr, int base, bool *error) /* Check for various possible errors */ - if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) - || (errno != 0 && val == 0)) + if ((errno == ERANGE and (val == LONG_MAX or val == LONG_MIN)) + or (errno != 0 && val == 0)) { *error= true; return EXIT_SUCCESS; @@ -85,6 +87,37 @@ int main(int argc, char *argv[]) initialize_sockets(); memcached_st *memc= memcached_create(NULL); + + if (opt_udp) + { + if (opt_verbose) + { + std::cout << "Enabling UDP" << std::endl; + } + + if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, opt_udp))) + { + memcached_free(memc); + std::cerr << "Could not enable UDP protocol." << std::endl; + return EXIT_FAILURE; + } + } + + if (opt_buffer) + { + if (opt_verbose) + { + std::cout << "Enabling MEMCACHED_BEHAVIOR_BUFFER_REQUESTS" << std::endl; + } + + if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, opt_buffer))) + { + memcached_free(memc); + std::cerr << "Could not enable MEMCACHED_BEHAVIOR_BUFFER_REQUESTS." << std::endl; + return EXIT_FAILURE; + } + } + process_hash_option(memc, opt_hash); if (opt_servers == NULL) @@ -114,9 +147,7 @@ int main(int argc, char *argv[]) memcached_server_push(memc, servers); memcached_server_list_free(servers); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, - (uint64_t)opt_binary); - + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, opt_binary); if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0) { memcached_free(memc); @@ -143,7 +174,7 @@ int main(int argc, char *argv[]) { if (opt_verbose) { - fprintf(stderr, "memcp: %s: %s\n", argv[optind], strerror(errno)); + std::cerr << "memcp " << argv[optind] << " " << strerror(errno) << std::endl; optind++; } exit_code= EXIT_FAILURE; @@ -175,59 +206,65 @@ int main(int argc, char *argv[]) char *file_buffer_ptr; if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL) { - fprintf(stderr, "malloc: %s\n", strerror(errno)); + std::cerr << "Error allocating file buffer(" << strerror(errno) << ")" << std::endl; exit(EXIT_FAILURE); } ssize_t read_length; - if ((read_length= read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1) + if ((read_length= ::read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1) { - fprintf(stderr, "read: %s\n", strerror(errno)); + std::cerr << "Error while reading file " << file_buffer_ptr << " (" << strerror(errno) << ")" << std::endl; exit(EXIT_FAILURE); } if (read_length != sbuf.st_size) { - fprintf(stderr, "Failure reading from file\n"); - exit(1); + std::cerr << "Failure while reading file. Read length was not equal to stat() length" << std::endl; + exit(EXIT_FAILURE); } memcached_return_t rc; if (opt_method == OPT_ADD) + { rc= memcached_add(memc, ptr, strlen(ptr), file_buffer_ptr, (size_t)sbuf.st_size, opt_expires, opt_flags); + } else if (opt_method == OPT_REPLACE) + { rc= memcached_replace(memc, ptr, strlen(ptr), file_buffer_ptr, (size_t)sbuf.st_size, opt_expires, opt_flags); + } else + { rc= memcached_set(memc, ptr, strlen(ptr), file_buffer_ptr, (size_t)sbuf.st_size, opt_expires, opt_flags); + } - if (rc != MEMCACHED_SUCCESS) + if (memcached_failed(rc)) { - fprintf(stderr, "memcp: %s: memcache error %s", - ptr, memcached_strerror(memc, rc)); - if (memcached_last_error_errno(memc)) - fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc))); - fprintf(stderr, "\n"); - + std::cerr << "Error occrrured during operation: " << memcached_last_error_message(memc) << std::endl; exit_code= EXIT_FAILURE; } - free(file_buffer_ptr); - close(fd); + ::free(file_buffer_ptr); + ::close(fd); optind++; } memcached_free(memc); if (opt_servers) + { free(opt_servers); + } + if (opt_hash) + { free(opt_hash); + } return exit_code; } @@ -244,6 +281,8 @@ static void options_parse(int argc, char *argv[]) {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET}, + {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP}, + {(OPTIONSTRING)"buffer", no_argument, NULL, OPT_BUFFER}, {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, @@ -274,6 +313,7 @@ static void options_parse(int argc, char *argv[]) { case 0: break; + case OPT_BINARY: opt_binary= true; break; @@ -350,6 +390,14 @@ static void options_parse(int argc, char *argv[]) close_stdio(); break; + case OPT_UDP: + opt_udp= true; + break; + + case OPT_BUFFER: + opt_buffer= true; + break; + case '?': /* getopt_long already printed an error message. */ exit(1); diff --git a/clients/memslap.cc b/clients/memslap.cc index f00ba457..a8c0da1e 100644 --- a/clients/memslap.cc +++ b/clients/memslap.cc @@ -53,6 +53,8 @@ #include #include +#include + #include #include "client_options.h" @@ -152,7 +154,7 @@ static unsigned int opt_createial_load= 0; static unsigned int opt_concurrency= 0; static int opt_displayflag= 0; static char *opt_servers= NULL; -static int opt_udp_io= 0; +static bool opt_udp_io= false; test_t opt_test= SET_TEST; extern "C" { @@ -243,26 +245,31 @@ void scheduler(memcached_server_st *servers, conclusions_st *conclusion) memcached_st *memc= memcached_create(NULL); + memcached_server_push(memc, servers); + /* We need to set udp behavior before adding servers to the client */ if (opt_udp_io) { - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, - (uint64_t)opt_udp_io); - for (uint32_t x= 0; x < memcached_server_list_count(servers); x++ ) + if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, opt_udp_io))) { - servers[x].type= MEMCACHED_CONNECTION_UDP; + std::cerr << "Failed to enable UDP." << std::endl; + memcached_free(memc); + exit(EXIT_FAILURE); } } - memcached_server_push(memc, servers); memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, (uint64_t)opt_binary); if (opt_flush) + { flush_all(memc); + } if (opt_createial_load) + { pairs= load_create_data(memc, opt_createial_load, &actual_loaded); + } char **keys= static_cast(calloc(actual_loaded, sizeof(char*))); size_t *key_lengths= static_cast(calloc(actual_loaded, sizeof(size_t))); @@ -399,7 +406,7 @@ void options_parse(int argc, char *argv[]) "does not currently support get ops.\n"); exit(1); } - opt_udp_io= 1; + opt_udp_io= true; break; case OPT_BINARY: diff --git a/clients/utilities.cc b/clients/utilities.cc index 79f2f2ae..d0b3dba8 100644 --- a/clients/utilities.cc +++ b/clients/utilities.cc @@ -98,6 +98,7 @@ static const char *lookup_help(memcached_options option) case OPT_BINARY: return("Switch to binary protocol."); case OPT_ANALYZE: return("Analyze the provided servers."); case OPT_UDP: return("Use UDP protocol when communicating with server."); + case OPT_BUFFER: return("Enable request buffering."); case OPT_USERNAME: return "Username to use for SASL authentication"; case OPT_PASSWD: return "Password to use for SASL authentication"; case OPT_FILE: return "Path to file in which to save result"; diff --git a/configure.ac b/configure.ac index 883fa3c4..602b4520 100644 --- a/configure.ac +++ b/configure.ac @@ -127,6 +127,10 @@ AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([stddef.h]) AC_CHECK_HEADERS([sys/time.h]) AC_CHECK_HEADERS([sasl/sasl.h]) +AC_CHECK_HEADERS([execinfo.h]) +AC_CHECK_HEADERS([cxxabi.h], + AC_DEFINE([HAVE_CXXABI_H], [1], [Have cxxabi.h]), + AC_DEFINE([HAVE_CXXABI_H], [0], [Have cxxabi.h])) AC_CXX_HEADER_STDCXX_98 AC_FUNC_ALLOCA @@ -154,6 +158,8 @@ AC_C_INLINE AC_C_VOLATILE AC_C_RESTRICT +AX_CXX_GCC_ABI_DEMANGLE + dnl The sasl functions should only be visible if we build with sasl support AS_IF([test "x$ac_cv_sasl" = "xyes"], [ diff --git a/libmemcached-1.0/struct/memcached.h b/libmemcached-1.0/struct/memcached.h index 152f3103..564eb74e 100644 --- a/libmemcached-1.0/struct/memcached.h +++ b/libmemcached-1.0/struct/memcached.h @@ -54,7 +54,7 @@ struct memcached_st { bool buffer_requests:1; bool hash_with_namespace:1; bool no_block:1; // Don't block - bool no_reply:1; + bool reply:1; bool randomize_replica_read:1; bool support_cas:1; bool tcp_nodelay:1; diff --git a/libmemcached/assert.hpp b/libmemcached/assert.hpp index 787d844a..6858879c 100644 --- a/libmemcached/assert.hpp +++ b/libmemcached/assert.hpp @@ -49,7 +49,7 @@ do \ { \ if (not (__expr)) \ { \ - fprintf(stderr, "\nAssertion \"%s\" failed for function \"%s\" likely for %s, at %s:%d\n", #__expr, __func__, (#__mesg), __FILE__, __LINE__);\ + fprintf(stderr, "\n%s:%d Assertion \"%s\" failed for function \"%s\" likely for %s\n", __FILE__, __LINE__, #__expr, __func__, (#__mesg));\ custom_backtrace(); \ abort(); \ } \ diff --git a/libmemcached/auto.cc b/libmemcached/auto.cc index b2e4f534..28550a18 100644 --- a/libmemcached/auto.cc +++ b/libmemcached/auto.cc @@ -37,127 +37,105 @@ #include -static memcached_return_t text_incr_decr(memcached_st *ptr, - const char *verb, - const char *group_key, size_t group_key_length, +static memcached_return_t text_incr_decr(memcached_server_write_instance_st instance, + const bool is_incr, const char *key, size_t key_length, - uint64_t offset, - uint64_t *value) + const uint64_t offset, + const bool reply, + uint64_t& numeric_value) { char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - uint32_t server_key; - memcached_server_write_instance_st instance; - bool no_reply= ptr->flags.no_reply; - if (memcached_failed(memcached_key_test(*ptr, (const char **)&key, &key_length, 1))) + int send_length= snprintf(buffer, sizeof(buffer), " %" PRIu64, offset); + if (size_t(send_length) >= sizeof(buffer) or send_length < 0) { - return memcached_set_error(*ptr, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT); + return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, + memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); } - server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); - instance= memcached_server_instance_fetch(ptr, server_key); + libmemcached_io_vector_st vector[]= + { + { NULL, 0 }, + { memcached_literal_param("incr ") }, + { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) }, + { key, key_length }, + { buffer, send_length }, + { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") }, + { memcached_literal_param("\r\n") } + }; - int send_length; - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "%s %.*s%.*s %" PRIu64 "%s\r\n", verb, - memcached_print_array(ptr->_namespace), - (int)key_length, key, - offset, no_reply ? " noreply" : ""); - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + if (is_incr == false) { - return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, - memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); + vector[1].buffer= "decr "; } - memcached_return_t rc= memcached_do(instance, buffer, (size_t)send_length, true); - if (no_reply or memcached_failed(rc)) - return rc; - - rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + memcached_return_t rc= memcached_vdo(instance, vector, 7, true); - if (rc != MEMCACHED_SUCCESS) + if (reply == false) { - return memcached_set_error(*instance, rc, MEMCACHED_AT); + return MEMCACHED_SUCCESS; } - /* - So why recheck responce? Because the protocol is brain dead :) - The number returned might end up equaling one of the string - values. Less chance of a mistake with strncmp() so we will - use it. We still called memcached_response() though since it - worked its magic for non-blocking IO. - */ - if (not strncmp(buffer, memcached_literal_param("ERROR\r\n"))) + if (memcached_failed(rc)) { - *value= 0; - rc= MEMCACHED_PROTOCOL_ERROR; - } - else if (not strncmp(buffer, memcached_literal_param("CLIENT_ERROR\r\n"))) - { - *value= 0; - rc= MEMCACHED_PROTOCOL_ERROR; - } - else if (not strncmp(buffer, memcached_literal_param("NOT_FOUND\r\n"))) - { - *value= 0; - rc= MEMCACHED_NOTFOUND; - } - else - { - *value= strtoull(buffer, (char **)NULL, 10); - rc= MEMCACHED_SUCCESS; + numeric_value= UINT64_MAX; + return rc; } + rc= memcached_response(instance, buffer, sizeof(buffer), NULL, numeric_value); + return memcached_set_error(*instance, rc, MEMCACHED_AT); } -static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd, - const char *group_key, size_t group_key_length, - const char *key, size_t key_length, - uint64_t offset, uint64_t initial, - uint32_t expiration, +static memcached_return_t binary_incr_decr(memcached_server_write_instance_st instance, + protocol_binary_command cmd, + const char *key, const size_t key_length, + const uint64_t offset, + const uint64_t initial, + const uint32_t expiration, + const bool reply, uint64_t *value) { - bool no_reply= ptr->flags.no_reply; - - uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); - memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key); - - if (no_reply) + if (reply == false) { if(cmd == PROTOCOL_BINARY_CMD_DECREMENT) + { cmd= PROTOCOL_BINARY_CMD_DECREMENTQ; + } if(cmd == PROTOCOL_BINARY_CMD_INCREMENT) + { cmd= PROTOCOL_BINARY_CMD_INCREMENTQ; + } } protocol_binary_request_incr request= {}; // = {.bytes= {0}}; request.message.header.request.magic= PROTOCOL_BINARY_REQ; request.message.header.request.opcode= cmd; - request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace))); + request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(instance->root->_namespace))); request.message.header.request.extlen= 20; request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->_namespace) +request.message.header.request.extlen)); + request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(instance->root->_namespace) +request.message.header.request.extlen)); request.message.body.delta= memcached_htonll(offset); request.message.body.initial= memcached_htonll(initial); request.message.body.expiration= htonl((uint32_t) expiration); - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { + { NULL, 0 }, { request.bytes, sizeof(request.bytes) }, - { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) }, + { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) }, { key, key_length } }; memcached_return_t rc; - if (memcached_failed(rc= memcached_vdo(instance, vector, 3, true))) + if (memcached_failed(rc= memcached_vdo(instance, vector, 4, true))) { memcached_io_reset(instance); - return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc; + return MEMCACHED_WRITE_FAILURE; } - if (no_reply) + if (reply == false) { return MEMCACHED_SUCCESS; } @@ -194,7 +172,7 @@ memcached_return_t memcached_increment_by_key(memcached_st *ptr, value= &local_value; } - if (memcached_failed(rc= initialize_query(ptr))) + if (memcached_failed(rc= initialize_query(ptr, true))) { return rc; } @@ -204,17 +182,28 @@ memcached_return_t memcached_increment_by_key(memcached_st *ptr, return rc; } + if (memcached_failed(rc= memcached_key_test(*ptr, (const char **)&key, &key_length, 1))) + { + return memcached_set_error(*ptr, rc, MEMCACHED_AT); + } + + uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key); + + bool reply= memcached_is_replying(instance->root); + LIBMEMCACHED_MEMCACHED_INCREMENT_START(); - if (ptr->flags.binary_protocol) + if (memcached_is_binary(ptr)) { - rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT, - group_key, group_key_length, key, key_length, - (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD, + rc= binary_incr_decr(instance, PROTOCOL_BINARY_CMD_INCREMENT, + key, key_length, + uint64_t(offset), 0, MEMCACHED_EXPIRATION_NOT_ADD, + reply, value); } else { - rc= text_incr_decr(ptr, "incr", group_key, group_key_length, key, key_length, offset, value); + rc= text_incr_decr(instance, true, key, key_length, offset, reply, *value); } LIBMEMCACHED_MEMCACHED_INCREMENT_END(); @@ -235,28 +224,34 @@ memcached_return_t memcached_decrement_by_key(memcached_st *ptr, } memcached_return_t rc; - if (memcached_failed(rc= initialize_query(ptr))) + if (memcached_failed(rc= initialize_query(ptr, true))) { return rc; } - if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + if (memcached_failed(rc= memcached_key_test(*ptr, (const char **)&key, &key_length, 1))) { - return rc; + return memcached_set_error(*ptr, rc, MEMCACHED_AT); } + uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key); + + bool reply= memcached_is_replying(instance->root); + LIBMEMCACHED_MEMCACHED_DECREMENT_START(); - if (ptr->flags.binary_protocol) + if (memcached_is_binary(ptr)) { - rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT, - group_key, group_key_length, key, key_length, - (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD, + rc= binary_incr_decr(instance, PROTOCOL_BINARY_CMD_DECREMENT, + key, key_length, + offset, 0, MEMCACHED_EXPIRATION_NOT_ADD, + reply, value); } else { - rc= text_incr_decr(ptr, "decr", group_key, group_key_length, key, key_length, offset, value); + rc= text_incr_decr(instance, false, key, key_length, offset, reply, *value); } LIBMEMCACHED_MEMCACHED_DECREMENT_END(); @@ -272,12 +267,6 @@ memcached_return_t memcached_increment_with_initial(memcached_st *ptr, time_t expiration, uint64_t *value) { - uint64_t local_value; - if (value == NULL) - { - value= &local_value; - } - return memcached_increment_with_initial_by_key(ptr, key, key_length, key, key_length, offset, initial, expiration, value); @@ -300,27 +289,34 @@ memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr, } memcached_return_t rc; - if (memcached_failed(rc= initialize_query(ptr))) + if (memcached_failed(rc= initialize_query(ptr, true))) { return rc; } - if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + if (memcached_failed(rc= memcached_key_test(*ptr, (const char **)&key, &key_length, 1))) { - return rc; + return memcached_set_error(*ptr, rc, MEMCACHED_AT); } + uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key); + + bool reply= memcached_is_replying(instance->root); + LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START(); - if (ptr->flags.binary_protocol) + if (memcached_is_binary(ptr)) { - rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT, - group_key, group_key_length, key, key_length, - offset, initial, (uint32_t)expiration, + rc= binary_incr_decr(instance, PROTOCOL_BINARY_CMD_INCREMENT, + key, key_length, + offset, initial, uint32_t(expiration), + reply, value); } else { - rc= MEMCACHED_PROTOCOL_ERROR; + rc= memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, + memcached_literal_param("memcached_increment_with_initial_by_key() is not supported via the ASCII protocol")); } LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END(); @@ -336,12 +332,6 @@ memcached_return_t memcached_decrement_with_initial(memcached_st *ptr, time_t expiration, uint64_t *value) { - uint64_t local_value; - if (value == NULL) - { - value= &local_value; - } - return memcached_decrement_with_initial_by_key(ptr, key, key_length, key, key_length, offset, initial, expiration, value); @@ -364,32 +354,38 @@ memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr, } memcached_return_t rc; - if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + if (memcached_failed(rc= initialize_query(ptr, true))) { return rc; } - if (memcached_failed(rc= initialize_query(ptr))) + if (memcached_failed(rc= memcached_key_test(*ptr, (const char **)&key, &key_length, 1))) { - return rc; + return memcached_set_error(*ptr, rc, MEMCACHED_AT); } + uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key); + + bool reply= memcached_is_replying(instance->root); + LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START(); - if (ptr->flags.binary_protocol) + if (memcached_is_binary(ptr)) { - rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT, - group_key, group_key_length, key, key_length, - offset, initial, (uint32_t)expiration, + rc= binary_incr_decr(instance, PROTOCOL_BINARY_CMD_DECREMENT, + key, key_length, + offset, initial, uint32_t(expiration), + reply, value); } else { - rc= MEMCACHED_PROTOCOL_ERROR; + rc= memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, + memcached_literal_param("memcached_decrement_with_initial_by_key() is not supported via the ASCII protocol")); } LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END(); return rc; } - diff --git a/libmemcached/backtrace.cc b/libmemcached/backtrace.cc index bc8846ba..8fb8acc7 100644 --- a/libmemcached/backtrace.cc +++ b/libmemcached/backtrace.cc @@ -40,69 +40,106 @@ #include #include -#ifdef __GNUC__ -#ifdef HAVE_BACKTRACE +#ifdef HAVE_EXECINFO_H #include +#endif + +#ifdef HAVE_CXXABI_H #include -#endif // HAVE_BACKTRACE -#endif // __GNUC__ +#endif +#ifdef HAVE_GCC_ABI_DEMANGLE +#define USE_DEMANGLE 1 +#else +#define USE_DEMANGLE 0 +#endif void custom_backtrace(void) { -#ifdef __GNUC__ -#ifdef HAVE_BACKTRACE +#ifdef HAVE_EXECINFO_H void *array[50]; size_t size= backtrace(array, 50); char **strings= backtrace_symbols(array, size); + if (strings == NULL) + { + return; + } + fprintf(stderr, "Number of stack frames obtained: %lu\n", (unsigned long)size); - for (size_t x= 1; x < size; x++) + char *named_function= (char *)::realloc(NULL, 1024); + + if (named_function == NULL) { - size_t sz= 200; - char *function= (char *)malloc(sz); - char *begin= 0; - char *end= 0; + ::free(strings); + return; + } - for (char *j = strings[x]; *j; ++j) + for (size_t x= 1; x < size; x++) + { + if (USE_DEMANGLE) { - if (*j == '(') { - begin = j; + size_t sz= 200; + char *named_function_ptr= (char *)::realloc(named_function, sz); + if (named_function_ptr == NULL) + { + continue; } - else if (*j == '+') { - end = j; + named_function= named_function_ptr; + + char *begin_name= 0; + char *begin_offset= 0; + char *end_offset= 0; + + for (char *j= strings[x]; *j; ++j) + { + if (*j == '(') + { + begin_name= j; + } + else if (*j == '+') + { + begin_offset= j; + } + else if (*j == ')' and begin_offset) + { + end_offset= j; + break; + } } - } - if (begin && end) - { - begin++; - *end= '\0'; - int status; - char *ret = abi::__cxa_demangle(begin, function, &sz, &status); - if (ret) + if (begin_name and begin_offset and end_offset and begin_name < begin_offset) { - function= ret; + *begin_name++= '\0'; + *begin_offset++= '\0'; + *end_offset= '\0'; + + int status; + char *ret= abi::__cxa_demangle(begin_name, named_function, &sz, &status); + if (ret) // realloc()'ed string + { + named_function= ret; + fprintf(stderr, " %s : %s()+%s\n", strings[x], begin_name, begin_offset); + } + else + { + fprintf(stderr, " %s : %s()+%s\n", strings[x], begin_name, begin_offset); + } } else { - strncpy(function, begin, sz); - strncat(function, "()", sz); - function[sz-1] = '\0'; + fprintf(stderr, " %s\n", strings[x]); } - fprintf(stderr, "%s\n", function); } else { - fprintf(stderr, "%s\n", strings[x]); + fprintf(stderr, " unmangled: %s\n", strings[x]); } - free(function); } - - free (strings); -#endif // HAVE_BACKTRACE -#endif // __GNUC__ + ::free(named_function); + ::free(strings); +#endif // HAVE_EXECINFO_H } diff --git a/libmemcached/backtrace.hpp b/libmemcached/backtrace.hpp index 98db320c..330d02c4 100644 --- a/libmemcached/backtrace.hpp +++ b/libmemcached/backtrace.hpp @@ -37,5 +37,4 @@ #pragma once -LIBMEMCACHED_LOCAL void custom_backtrace(void); diff --git a/libmemcached/behavior.cc b/libmemcached/behavior.cc index bb17f2bd..9769759b 100644 --- a/libmemcached/behavior.cc +++ b/libmemcached/behavior.cc @@ -114,7 +114,7 @@ memcached_return_t memcached_behavior_set(memcached_st *ptr, break; case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: - if (ptr->flags.use_udp) + if (memcached_is_udp(ptr)) { return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("MEMCACHED_BEHAVIOR_BUFFER_REQUESTS cannot be set while MEMCACHED_BEHAVIOR_USE_UDP is enabled.")); @@ -128,9 +128,13 @@ memcached_return_t memcached_behavior_set(memcached_st *ptr, ptr->flags.use_udp= bool(data); if (bool(data)) { - ptr->flags.no_reply= true; + ptr->flags.reply= false; ptr->flags.buffer_requests= false; } + else + { + ptr->flags.reply= true; + } break; case MEMCACHED_BEHAVIOR_TCP_NODELAY: @@ -231,12 +235,14 @@ memcached_return_t memcached_behavior_set(memcached_st *ptr, break; case MEMCACHED_BEHAVIOR_NOREPLY: - if (ptr->flags.use_udp and bool(data) == false) + if (memcached_is_udp(ptr) and bool(data) == false) { return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("MEMCACHED_BEHAVIOR_NOREPLY cannot be disabled while MEMCACHED_BEHAVIOR_USE_UDP is enabled.")); } - ptr->flags.no_reply= bool(data); + // We reverse the logic here to make it easier to understand throughout the + // code. + ptr->flags.reply= bool(data) ? false : true; break; case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: @@ -310,7 +316,7 @@ uint64_t memcached_behavior_get(memcached_st *ptr, return ptr->flags.buffer_requests; case MEMCACHED_BEHAVIOR_USE_UDP: - return ptr->flags.use_udp; + return memcached_is_udp(ptr); case MEMCACHED_BEHAVIOR_TCP_NODELAY: return ptr->flags.tcp_nodelay; @@ -364,7 +370,9 @@ uint64_t memcached_behavior_get(memcached_st *ptr, socklen_t sock_length= sizeof(int); if (ptr->send_size != -1) // If value is -1 then we are using the default + { return (uint64_t) ptr->send_size; + } memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, 0); @@ -437,7 +445,7 @@ uint64_t memcached_behavior_get(memcached_st *ptr, return ptr->flags.hash_with_namespace; case MEMCACHED_BEHAVIOR_NOREPLY: - return ptr->flags.no_reply; + return ptr->flags.reply ? false : true; case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return ptr->flags.auto_eject_hosts; diff --git a/libmemcached/common.h b/libmemcached/common.h index 5aaf797b..0f33a784 100644 --- a/libmemcached/common.h +++ b/libmemcached/common.h @@ -105,6 +105,7 @@ memcached_return_t memcached_server_execute(memcached_st *ptr, #ifdef __cplusplus #include #include +#include #include #include #include @@ -122,7 +123,9 @@ memcached_return_t memcached_server_execute(memcached_st *ptr, #include #include #include +#ifdef __cplusplus #include +#endif #include #include diff --git a/libmemcached/connect.cc b/libmemcached/connect.cc index e04098c4..b81b25b9 100644 --- a/libmemcached/connect.cc +++ b/libmemcached/connect.cc @@ -231,7 +231,7 @@ static inline void set_socket_nonblocking(memcached_server_st *server) static void set_socket_options(memcached_server_st *server) { - assert_msg(server->fd != -1, "invalid socket was passed to set_socket_options()"); + assert_msg(server->fd != INVALID_SOCKET, "invalid socket was passed to set_socket_options()"); if (memcached_is_udp(server->root)) { diff --git a/libmemcached/delete.cc b/libmemcached/delete.cc index ed7510a6..121ec91b 100644 --- a/libmemcached/delete.cc +++ b/libmemcached/delete.cc @@ -44,50 +44,33 @@ memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t k return memcached_delete_by_key(ptr, key, key_length, key, key_length, expiration); } -static inline memcached_return_t ascii_delete(memcached_st *ptr, - memcached_server_write_instance_st instance, +static inline memcached_return_t ascii_delete(memcached_server_write_instance_st instance, uint32_t , const char *key, - size_t key_length, - bool& reply, - bool& flush) + const size_t key_length, + const bool reply, + const bool flush) { - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - int send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "delete %.*s%.*s%s\r\n", - memcached_print_array(ptr->_namespace), - (int)key_length, key, - reply ? "" : " noreply"); - - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + libmemcached_io_vector_st vector[]= { - return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, - memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); - } - - if (ptr->flags.use_udp and flush == false) - { - if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) - { - return MEMCACHED_WRITE_FAILURE; - } - - if (send_length +instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) - { - memcached_io_write(instance, NULL, 0, true); - } - } + { NULL, 0 }, + { memcached_literal_param("delete ") }, + { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) }, + { key, key_length }, + { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") }, + { memcached_literal_param("\r\n") } + }; - return memcached_do(instance, buffer, (size_t)send_length, flush); + /* Send command header */ + return memcached_vdo(instance, vector, 6, flush); } -static inline memcached_return_t binary_delete(memcached_st *ptr, - memcached_server_write_instance_st instance, +static inline memcached_return_t binary_delete(memcached_server_write_instance_st instance, uint32_t server_key, const char *key, - size_t key_length, - bool& reply, - bool& flush) + const size_t key_length, + const bool reply, + const bool flush) { protocol_binary_request_delete request= {}; @@ -100,53 +83,41 @@ static inline memcached_return_t binary_delete(memcached_st *ptr, { request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ; } - request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace))); + request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(instance->root->_namespace))); request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->_namespace))); - - if (ptr->flags.use_udp and flush == false) - { - size_t cmd_size= sizeof(request.bytes) + key_length; - if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) - { - return MEMCACHED_WRITE_FAILURE; - } - - if (cmd_size +instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) - { - memcached_io_write(instance, NULL, 0, true); - } - } + request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(instance->root->_namespace))); - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { + { NULL, 0 }, { request.bytes, sizeof(request.bytes) }, - { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) }, + { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) }, { key, key_length } }; memcached_return_t rc= MEMCACHED_SUCCESS; - if ((rc= memcached_vdo(instance, vector, 3, flush)) != MEMCACHED_SUCCESS) + if ((rc= memcached_vdo(instance, vector, 4, flush)) != MEMCACHED_SUCCESS) { memcached_io_reset(instance); } - if (ptr->number_of_replicas > 0) + if (instance->root->number_of_replicas > 0) { request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ; - for (uint32_t x= 0; x < ptr->number_of_replicas; ++x) + for (uint32_t x= 0; x < instance->root->number_of_replicas; ++x) { - memcached_server_write_instance_st replica; ++server_key; - if (server_key == memcached_server_count(ptr)) + if (server_key == memcached_server_count(instance->root)) + { server_key= 0; + } - replica= memcached_server_instance_fetch(ptr, server_key); + memcached_server_write_instance_st replica= memcached_server_instance_fetch(instance->root, server_key); - if (memcached_vdo(replica, vector, 3, flush) != MEMCACHED_SUCCESS) + if (memcached_vdo(replica, vector, 4, flush) != MEMCACHED_SUCCESS) { memcached_io_reset(replica); } @@ -168,7 +139,7 @@ memcached_return_t memcached_delete_by_key(memcached_st *ptr, LIBMEMCACHED_MEMCACHED_DELETE_START(); memcached_return_t rc; - if (memcached_failed(rc= initialize_query(ptr))) + if (memcached_failed(rc= initialize_query(ptr, true))) { return rc; } @@ -184,63 +155,63 @@ memcached_return_t memcached_delete_by_key(memcached_st *ptr, return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Memcached server version does not allow expiration of deleted items")); } + + uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key); + bool buffering= memcached_is_buffering(instance->root); + bool reply= memcached_is_replying(instance->root); + // If a delete trigger exists, we need a response, so no buffering/noreply if (ptr->delete_trigger) { - if (ptr->flags.buffer_requests) + if (buffering) { return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Delete triggers cannot be used if buffering is enabled")); } - if (ptr->flags.no_reply) + if (reply == false) { return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Delete triggers cannot be used if MEMCACHED_BEHAVIOR_NOREPLY is set")); } } - - uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); - memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key); - - bool to_write= (ptr->flags.buffer_requests) ? false : true; - - // Invert the logic to make it simpler to read the code - bool reply= (ptr->flags.no_reply) ? false : true; - - if (ptr->flags.binary_protocol) + if (memcached_is_binary(ptr)) { - rc= binary_delete(ptr, instance, server_key, key, key_length, reply, to_write); + rc= binary_delete(instance, server_key, key, key_length, reply, buffering ? false : true); } else { - rc= ascii_delete(ptr, instance, server_key, key, key_length, reply, to_write); + rc= ascii_delete(instance, server_key, key, key_length, reply, buffering ? false : true); } if (rc == MEMCACHED_SUCCESS) { - if (to_write == false) + if (buffering == true) { rc= MEMCACHED_BUFFERED; } - else if (reply) + else if (reply == false) + { + rc= MEMCACHED_SUCCESS; + } + else { char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); if (rc == MEMCACHED_DELETED) { rc= MEMCACHED_SUCCESS; + if (ptr->delete_trigger) + { + ptr->delete_trigger(ptr, key, key_length); + } } } - - if (rc == MEMCACHED_SUCCESS and ptr->delete_trigger) - { - ptr->delete_trigger(ptr, key, key_length); - } } LIBMEMCACHED_MEMCACHED_DELETE_END(); - return rc; + return memcached_set_error(*ptr, rc, MEMCACHED_AT ); } diff --git a/libmemcached/do.cc b/libmemcached/do.cc index c3cfab93..3c3519c2 100644 --- a/libmemcached/do.cc +++ b/libmemcached/do.cc @@ -11,17 +11,19 @@ #include -memcached_return_t memcached_do(memcached_server_write_instance_st ptr, const void *command, - size_t command_length, bool with_flush) +memcached_return_t memcached_vdo(memcached_server_write_instance_st instance, + libmemcached_io_vector_st vector[], + const size_t count, + const bool with_flush) { - assert_msg(command_length, "Programming error, somehow a command had a length of zero"); - assert_msg(command, "Programming error, somehow a command was NULL"); - memcached_return_t rc; - if (memcached_failed(rc= memcached_connect(ptr))) + + assert_msg(vector, "Invalid vector passed"); + + if (memcached_failed(rc= memcached_connect(instance))) { - WATCHPOINT_ASSERT(rc == memcached_last_error(ptr->root)); WATCHPOINT_ERROR(rc); + assert_msg(instance->error_messages, "memcached_connect() returned an error but the memcached_server_write_instance_st showed none."); return rc; } @@ -30,57 +32,33 @@ memcached_return_t memcached_do(memcached_server_write_instance_st ptr, const vo ** before they start writing, if there is any data in buffer, clear it out, ** otherwise we might get a partial write. **/ - if (memcached_is_udp(ptr->root) and with_flush and ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH) - { - memcached_io_write(ptr, NULL, 0, true); - } - - ssize_t sent_length= memcached_io_write(ptr, command, command_length, with_flush); - - if (sent_length == -1 or size_t(sent_length) != command_length) + if (memcached_is_udp(instance->root)) { - rc= MEMCACHED_WRITE_FAILURE; - } - else if ((ptr->root->flags.no_reply) == 0) - { - memcached_server_response_increment(ptr); - } - - return rc; -} + if (vector[0].buffer or vector[0].length) + { + return memcached_set_error(*instance->root, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT, + memcached_literal_param("UDP messages was attempted, but vector was not setup for it")); + } -memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr, - const struct libmemcached_io_vector_st *vector, size_t count, - bool with_flush) -{ - memcached_return_t rc; + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); - WATCHPOINT_ASSERT(count); - WATCHPOINT_ASSERT(vector); + increment_udp_message_id(instance); + vector[0].buffer= instance->write_buffer; + vector[0].length= UDP_DATAGRAM_HEADER_LENGTH; - if (memcached_failed(rc= memcached_connect(ptr))) - { - WATCHPOINT_ERROR(rc); - assert_msg(ptr->error_messages, "memcached_connect() returned an error but the memcached_server_write_instance_st showed none."); - return rc; - } + msg.msg_iov= (struct iovec*)vector; + msg.msg_iovlen= count; - /* - ** Since non buffering ops in UDP mode dont check to make sure they will fit - ** before they start writing, if there is any data in buffer, clear it out, - ** otherwise we might get a partial write. - **/ - if (memcached_is_udp(ptr->root) and with_flush and ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH) - { - if (memcached_io_write(ptr, NULL, 0, true) == -1) + if (::sendmsg(instance->fd, &msg, 0) < 1) { - memcached_io_reset(ptr); - return memcached_set_error(*ptr, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); + return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); } - } - ssize_t sent_length= memcached_io_writev(ptr, vector, count, with_flush); + return MEMCACHED_SUCCESS; + } + ssize_t sent_length= memcached_io_writev(instance, vector, count, with_flush); size_t command_length= 0; for (uint32_t x= 0; x < count; ++x, vector++) { @@ -93,9 +71,9 @@ memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr, WATCHPOINT_ERROR(rc); WATCHPOINT_ERRNO(errno); } - else if ((ptr->root->flags.no_reply) == 0) + else if (memcached_is_replying(instance->root)) { - memcached_server_response_increment(ptr); + memcached_server_response_increment(instance); } return rc; diff --git a/libmemcached/do.hpp b/libmemcached/do.hpp index f1232662..560c1318 100644 --- a/libmemcached/do.hpp +++ b/libmemcached/do.hpp @@ -37,13 +37,7 @@ #pragma once -LIBMEMCACHED_LOCAL -memcached_return_t memcached_do(memcached_server_write_instance_st ptr, - const void *commmand, - size_t command_length, - bool with_flush); - -LIBMEMCACHED_LOCAL memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr, - const struct libmemcached_io_vector_st *vector, size_t count, - bool with_flush); + libmemcached_io_vector_st vector[], + const size_t count, + const bool with_flush); diff --git a/libmemcached/dump.cc b/libmemcached/dump.cc index dcbe15b8..830c3ff4 100644 --- a/libmemcached/dump.cc +++ b/libmemcached/dump.cc @@ -1,3 +1,39 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + /* We use this to dump all keys. @@ -21,17 +57,21 @@ static memcached_return_t ascii_dump(memcached_st *ptr, memcached_dump_fn *callb for (uint32_t x= 0; x < 256; x++) { char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - int send_length; - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "stats cachedump %u 0 0\r\n", x); - - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + int buffer_length= snprintf(buffer, sizeof(buffer), "%u", x); + if (buffer_length >= MEMCACHED_DEFAULT_COMMAND_SIZE or buffer_length < 0) { return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); } - rc= memcached_do(instance, buffer, (size_t)send_length, true); + libmemcached_io_vector_st vector[]= + { + { memcached_literal_param("stats cachedump ") }, + { buffer, buffer_length }, + { memcached_literal_param(" 0 0\r\n") } + }; + + rc= memcached_vdo(instance, vector, 3, true); if (rc != MEMCACHED_SUCCESS) { @@ -76,7 +116,7 @@ static memcached_return_t ascii_dump(memcached_st *ptr, memcached_dump_fn *callb * This isn't really a fatal error, so let's just skip it. I want to * fix the return value from the memcached server to a CLIENT_ERROR, * so let's add support for that as well right now. - */ + */ rc= MEMCACHED_END; break; } @@ -102,7 +142,7 @@ error: memcached_return_t memcached_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks) { memcached_return_t rc; - if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS) + if (memcached_failed(rc= initialize_query(ptr, true))) { return rc; } diff --git a/libmemcached/error.cc b/libmemcached/error.cc index f7764d0f..becffd23 100644 --- a/libmemcached/error.cc +++ b/libmemcached/error.cc @@ -395,11 +395,11 @@ static void _error_print(const memcached_error_t *error) if (error->size == 0) { - fprintf(stderr, "%s\n", memcached_strerror(NULL, error->rc) ); + fprintf(stderr, "\t%s\n", memcached_strerror(NULL, error->rc) ); } else { - fprintf(stderr, "%s %s\n", memcached_strerror(NULL, error->rc), error->message); + fprintf(stderr, "\t%s %s\n", memcached_strerror(NULL, error->rc), error->message); } _error_print(error->next); @@ -407,10 +407,19 @@ static void _error_print(const memcached_error_t *error) void memcached_error_print(const memcached_st *self) { - if (not self) + if (self == NULL) + { return; + } _error_print(self->error_messages); + + for (uint32_t x= 0; x < memcached_server_count(self); x++) + { + memcached_server_instance_st instance= memcached_server_instance_by_position(self, x); + + _error_print(instance->error_messages); + } } static void _error_free(memcached_error_t *error) diff --git a/libmemcached/exist.cc b/libmemcached/exist.cc index b68ba466..d2dc34dd 100644 --- a/libmemcached/exist.cc +++ b/libmemcached/exist.cc @@ -38,8 +38,9 @@ static memcached_return_t ascii_exist(memcached_st *memc, memcached_server_write_instance_st instance, const char *key, size_t key_length) { - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { + { NULL, 0 }, { memcached_literal_param("add ") }, { memcached_array_string(memc->_namespace), memcached_array_size(memc->_namespace) }, { key, key_length }, @@ -51,21 +52,27 @@ static memcached_return_t ascii_exist(memcached_st *memc, memcached_server_write }; /* Send command header */ - memcached_return_t rc= memcached_vdo(instance, vector, 8, true); + memcached_return_t rc= memcached_vdo(instance, vector, 9, true); if (rc == MEMCACHED_SUCCESS) { char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); if (rc == MEMCACHED_NOTSTORED) + { rc= MEMCACHED_SUCCESS; + } if (rc == MEMCACHED_STORED) + { rc= MEMCACHED_NOTFOUND; + } } if (rc == MEMCACHED_WRITE_FAILURE) + { memcached_io_reset(instance); + } return rc; } @@ -87,8 +94,9 @@ static memcached_return_t binary_exist(memcached_st *memc, memcached_server_writ +memcached_array_size(memc->_namespace) +request.message.header.request.extlen)); - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { + { NULL, 0 }, { request.bytes, send_length }, { memcached_array_string(memc->_namespace), memcached_array_size(memc->_namespace) }, { key, key_length } @@ -96,7 +104,7 @@ static memcached_return_t binary_exist(memcached_st *memc, memcached_server_writ /* write the header */ memcached_return_t rc; - if ((rc= memcached_vdo(instance, vector, 3, true)) != MEMCACHED_SUCCESS) + if ((rc= memcached_vdo(instance, vector, 4, true)) != MEMCACHED_SUCCESS) { memcached_io_reset(instance); return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc; @@ -123,17 +131,16 @@ memcached_return_t memcached_exist_by_key(memcached_st *memc, const char *key, size_t key_length) { memcached_return_t rc; - if (memcached_failed(rc= initialize_query(memc))) + if (memcached_failed(rc= initialize_query(memc, true))) { return rc; } - if (memc->flags.use_udp) + if (memcached_is_udp(memc)) { return MEMCACHED_NOT_SUPPORTED; } - uint32_t server_key= memcached_generate_hash_with_redistribution(memc, group_key, group_key_length); memcached_server_write_instance_st instance; instance= memcached_server_instance_fetch(memc, server_key); diff --git a/libmemcached/fetch.cc b/libmemcached/fetch.cc index 8867d53d..2b5b8006 100644 --- a/libmemcached/fetch.cc +++ b/libmemcached/fetch.cc @@ -44,23 +44,32 @@ char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length, { memcached_result_st *result_buffer= &ptr->result; memcached_return_t unused; - if (not error) + if (error == NULL) + { error= &unused; + } - - unlikely (ptr->flags.use_udp) + if (memcached_is_udp(ptr)) { if (value_length) + { *value_length= 0; + } if (key_length) + { *key_length= 0; + } if (flags) + { *flags= 0; + } if (key) + { *key= 0; + } *error= MEMCACHED_NOT_SUPPORTED; return NULL; @@ -71,16 +80,24 @@ char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length, { WATCHPOINT_ASSERT(result_buffer == NULL); if (value_length) + { *value_length= 0; + } if (key_length) + { *key_length= 0; + } if (flags) + { *flags= 0; + } if (key) + { *key= 0; + } return NULL; } @@ -96,26 +113,39 @@ char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length, { *error= MEMCACHED_KEY_TOO_BIG; if (value_length) + { *value_length= 0; + } - if (key_length) - *key_length= 0; + if (key_length) + { + *key_length= 0; + } - if (flags) - *flags= 0; + if (flags) + { + *flags= 0; + } - if (key) - *key= 0; + if (key) + { + *key= 0; + } return NULL; } + strncpy(key, result_buffer->item_key, result_buffer->key_length); // For the binary protocol we will cut off the key :( if (key_length) + { *key_length= result_buffer->key_length; + } } if (flags) + { *flags= result_buffer->item_flags; + } return memcached_string_take_value(&result_buffer->value); } @@ -134,13 +164,13 @@ memcached_result_st *memcached_fetch_result(memcached_st *ptr, return NULL; } - if (ptr->flags.use_udp) + if (memcached_is_udp(ptr)) { *error= MEMCACHED_NOT_SUPPORTED; return NULL; } - if (not result) + if (result == NULL) { // If we have already initialized (ie it is in use) our internal, we // create one. diff --git a/libmemcached/flush.cc b/libmemcached/flush.cc index f2c490ba..6b8ea4b0 100644 --- a/libmemcached/flush.cc +++ b/libmemcached/flush.cc @@ -37,65 +37,97 @@ #include static memcached_return_t memcached_flush_binary(memcached_st *ptr, - time_t expiration); -static memcached_return_t memcached_flush_textual(memcached_st *ptr, - time_t expiration); - -memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration) + time_t expiration, + const bool reply) { - memcached_return_t rc; - if (memcached_failed(rc= initialize_query(ptr))) - { - return rc; - } + protocol_binary_request_flush request= {}; - LIBMEMCACHED_MEMCACHED_FLUSH_START(); - if (ptr->flags.binary_protocol) + request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH; + request.message.header.request.extlen= 4; + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + request.message.header.request.bodylen= htonl(request.message.header.request.extlen); + request.message.body.expiration= htonl((uint32_t) expiration); + + memcached_return_t rc= MEMCACHED_SUCCESS; + + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) { - rc= memcached_flush_binary(ptr, expiration); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); + + if (reply) + { + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH; + } + else + { + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ; + } + + libmemcached_io_vector_st vector[]= + { + { NULL, 0 }, + { request.bytes, sizeof(request.bytes) } + }; + + memcached_return_t rrc; + if (memcached_failed(rrc= memcached_vdo(instance, vector, 2, true))) + { + if (instance->error_messages == NULL or instance->root->error_messages == NULL) + { + memcached_set_error(*instance, rrc, MEMCACHED_AT); + } + memcached_io_reset(instance); + rc= MEMCACHED_SOME_ERRORS; + } } - else + + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) { - rc= memcached_flush_textual(ptr, expiration); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); + + if (memcached_server_response_count(instance) > 0) + { + (void)memcached_response(instance, NULL, 0, NULL); + } } - LIBMEMCACHED_MEMCACHED_FLUSH_END(); return rc; } static memcached_return_t memcached_flush_textual(memcached_st *ptr, - time_t expiration) + time_t expiration, + const bool reply) { - bool reply= ptr->flags.no_reply ? false : true; - - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - int send_length; + char buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1]; + int send_length= 0; if (expiration) { - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "flush_all %llu%s\r\n", - (unsigned long long)expiration, reply ? "" : " noreply"); - } - else - { - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "flush_all%s\r\n", reply ? "" : " noreply"); + send_length= snprintf(buffer, sizeof(buffer), "%llu", (unsigned long long)expiration); } - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE or send_length < 0) + if (size_t(send_length) >= sizeof(buffer) or send_length < 0) { return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); } - memcached_return_t rc= MEMCACHED_SUCCESS; - for (unsigned int x= 0; x < memcached_server_count(ptr); x++) + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) { memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); - memcached_return_t rrc= memcached_do(instance, buffer, (size_t)send_length, true); - if (rrc == MEMCACHED_SUCCESS and reply == true) + libmemcached_io_vector_st vector[]= + { + { NULL, 0 }, + { memcached_literal_param("flush_all ") }, + { buffer, send_length }, + { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") }, + { memcached_literal_param("\r\n") } + }; + + memcached_return_t rrc= memcached_vdo(instance, vector, 5, true); + if (memcached_success(rrc) and reply == true) { char response_buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; rrc= memcached_response(instance, response_buffer, sizeof(response_buffer), NULL); @@ -104,7 +136,7 @@ static memcached_return_t memcached_flush_textual(memcached_st *ptr, if (memcached_failed(rrc)) { // If an error has already been reported, then don't add to it - if (instance->error_messages == NULL) + if (instance->error_messages == NULL or instance->root->error_messages == NULL) { memcached_set_error(*instance, rrc, MEMCACHED_AT); } @@ -115,51 +147,26 @@ static memcached_return_t memcached_flush_textual(memcached_st *ptr, return rc; } -static memcached_return_t memcached_flush_binary(memcached_st *ptr, - time_t expiration) +memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration) { - protocol_binary_request_flush request= {}; - - request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ; - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH; - request.message.header.request.extlen= 4; - request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - request.message.header.request.bodylen= htonl(request.message.header.request.extlen); - request.message.body.expiration= htonl((uint32_t) expiration); - - memcached_return_t rc= MEMCACHED_SUCCESS; - - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr, true))) { - memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); + return rc; + } - if (ptr->flags.no_reply) - { - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ; - } - else - { - request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH; - } + bool reply= memcached_is_replying(ptr); - memcached_return_t rrc; - if ((rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true))) - { - memcached_set_error(*instance, rrc, MEMCACHED_AT); - memcached_io_reset(instance); - rc= MEMCACHED_SOME_ERRORS; - } + LIBMEMCACHED_MEMCACHED_FLUSH_START(); + if (memcached_is_binary(ptr)) + { + rc= memcached_flush_binary(ptr, expiration, reply); } - - for (uint32_t x= 0; x < memcached_server_count(ptr); x++) + else { - memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); - - if (memcached_server_response_count(instance) > 0) - { - (void)memcached_response(instance, NULL, 0, NULL); - } + rc= memcached_flush_textual(ptr, expiration, reply); } + LIBMEMCACHED_MEMCACHED_FLUSH_END(); return rc; } diff --git a/libmemcached/flush_buffers.cc b/libmemcached/flush_buffers.cc index bb3c4dec..58260fc1 100644 --- a/libmemcached/flush_buffers.cc +++ b/libmemcached/flush_buffers.cc @@ -48,14 +48,14 @@ memcached_return_t memcached_flush_buffers(memcached_st *memc) if (instance->write_buffer_offset != 0) { - if (instance->fd == -1 && + if (instance->fd == INVALID_SOCKET and (ret= memcached_connect(instance)) != MEMCACHED_SUCCESS) { WATCHPOINT_ERROR(ret); return ret; } - if (memcached_io_write(instance, NULL, 0, true) == -1) + if (memcached_io_write(instance) == false) { ret= MEMCACHED_SOME_ERRORS; } diff --git a/libmemcached/get.cc b/libmemcached/get.cc index c10f2341..b2428386 100644 --- a/libmemcached/get.cc +++ b/libmemcached/get.cc @@ -72,36 +72,35 @@ char *memcached_get_by_key(memcached_st *ptr, error= &unused; } - if (ptr->flags.use_udp) + uint64_t query_id= 0; + if (ptr) { - if (value_length) - { - *value_length= 0; - } - - *error= memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT); - return NULL; + query_id= ptr->query_id; } - uint64_t query_id= ptr->query_id; - (void)query_id; - /* Request the key */ *error= memcached_mget_by_key_real(ptr, group_key, group_key_length, (const char * const *)&key, &key_length, 1, false); - assert_msg(ptr->query_id == query_id +1, "Programmer error, the query_id was not incremented."); - + if (ptr) + { + assert_msg(ptr->query_id == query_id +1, "Programmer error, the query_id was not incremented."); + } if (memcached_failed(*error)) { - if (memcached_has_current_error(*ptr)) // Find the most accurate error + if (ptr) { - *error= memcached_last_error(ptr); + if (memcached_has_current_error(*ptr)) // Find the most accurate error + { + *error= memcached_last_error(ptr); + } } if (value_length) + { *value_length= 0; + } return NULL; } @@ -209,12 +208,12 @@ static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr, unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */ memcached_return_t rc; - if (memcached_failed(rc= initialize_query(ptr))) + if (memcached_failed(rc= initialize_query(ptr, true))) { return rc; } - if (ptr->flags.use_udp) + if (memcached_is_udp(ptr)) { return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT); } @@ -259,10 +258,14 @@ static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr, char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; if (ptr->flags.no_block) - (void)memcached_io_write(instance, NULL, 0, true); + { + memcached_io_write(instance); + } while(memcached_server_response_count(instance)) + { (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result); + } } } @@ -300,7 +303,7 @@ static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr, instance= memcached_server_instance_fetch(ptr, server_key); - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { { get_command, get_command_length }, { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) }, @@ -345,7 +348,9 @@ static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr, LIBMEMCACHED_MEMCACHED_MGET_END(); if (memcached_failed(rc)) + { return rc; + } return memcached_set_error(*ptr, MEMCACHED_NO_SERVERS, MEMCACHED_AT); } @@ -421,12 +426,22 @@ memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr, void *context, unsigned int number_of_callbacks) { - if ((ptr->flags.binary_protocol) == 0) + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr, false))) + { + return rc; + } + + if (memcached_is_udp(ptr)) + { + return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT); + } + + if (memcached_is_binary(ptr) == false) { return MEMCACHED_NOT_SUPPORTED; } - memcached_return_t rc; memcached_callback_st *original_callbacks= ptr->callbacks; memcached_callback_st cb= { callback, @@ -504,7 +519,7 @@ static memcached_return_t simple_binary_mget(memcached_st *ptr, request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->_namespace))); - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { { request.bytes, sizeof(request.bytes) }, { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) }, @@ -539,12 +554,11 @@ static memcached_return_t simple_binary_mget(memcached_st *ptr, for (uint32_t x= 0; x < memcached_server_count(ptr); ++x) { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); if (memcached_server_response_count(instance)) { - if (memcached_io_write(instance, NULL, 0, true) == -1) + if (memcached_io_write(instance) == false) { memcached_server_response_reset(instance); memcached_io_reset(instance); @@ -638,7 +652,7 @@ static memcached_return_t replication_binary_mget(memcached_st *ptr, * that we might have processed some of the responses etc. For now, * just make sure we work _correctly_ */ - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { { request.bytes, sizeof(request.bytes) }, { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) }, diff --git a/libmemcached/include.am b/libmemcached/include.am index af49d2d5..a1e47ab9 100644 --- a/libmemcached/include.am +++ b/libmemcached/include.am @@ -42,6 +42,7 @@ noinst_HEADERS+= \ libmemcached/server.hpp \ libmemcached/server_instance.h \ libmemcached/string.hpp \ + libmemcached/udp.hpp \ libmemcached/virtual_bucket.h \ libmemcached/watchpoint.h @@ -98,6 +99,7 @@ libmemcached_libmemcached_la_SOURCES+= \ libmemcached/touch.cc \ libmemcached/verbosity.cc \ libmemcached/version.cc \ + libmemcached/udp.cc \ libmemcached/virtual_bucket.c libmemcached/options.cc: libmemcached/csl/parser.h diff --git a/libmemcached/initialize_query.cc b/libmemcached/initialize_query.cc index 84fc2290..dca3c4d8 100644 --- a/libmemcached/initialize_query.cc +++ b/libmemcached/initialize_query.cc @@ -36,14 +36,17 @@ #include -memcached_return_t initialize_query(memcached_st *self) +memcached_return_t initialize_query(memcached_st *self, bool increment_query_id) { if (self == NULL) { return MEMCACHED_INVALID_ARGUMENTS; } - self->query_id++; + if (increment_query_id) + { + self->query_id++; + } if (self->state.is_time_for_rebuild) { diff --git a/libmemcached/initialize_query.h b/libmemcached/initialize_query.h index 86c8e2d8..943a37a3 100644 --- a/libmemcached/initialize_query.h +++ b/libmemcached/initialize_query.h @@ -36,16 +36,6 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif +memcached_return_t initialize_query(memcached_st *self, bool increment_query_id); -LIBMEMCACHED_LOCAL - memcached_return_t initialize_query(memcached_st *self); - -LIBMEMCACHED_LOCAL memcached_return_t initialize_const_query(const memcached_st *self); - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/libmemcached/io.cc b/libmemcached/io.cc index 85e5ed42..7a321ade 100644 --- a/libmemcached/io.cc +++ b/libmemcached/io.cc @@ -44,30 +44,6 @@ enum memc_read_or_write { MEM_WRITE }; -/* - * The udp request id consists of two seperate sections - * 1) The thread id - * 2) The message number - * The thread id should only be set when the memcached_st struct is created - * and should not be changed. - * - * The message num is incremented for each new message we send, this function - * extracts the message number from message_id, increments it and then - * writes the new value back into the header - */ -static void increment_udp_message_id(memcached_server_write_instance_st ptr) -{ - struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer; - uint16_t cur_req= get_udp_datagram_request_id(header); - int msg_num= get_msg_num_from_request_id(cur_req); - int thread_id= get_thread_id_from_request_id(cur_req); - - if (((++msg_num) & UDP_REQUEST_ID_THREAD_MASK) != 0) - msg_num= 0; - - header->request_id= htons((uint16_t) (thread_id | msg_num)); -} - /** * Try to fill the input buffer for a server with as much * data as possible. @@ -192,7 +168,7 @@ static bool process_input_buffer(memcached_server_write_instance_st ptr) } static memcached_return_t io_wait(memcached_server_write_instance_st ptr, - memc_read_or_write read_or_write) + const memc_read_or_write read_or_write) { struct pollfd fds; fds.fd= ptr->fd; @@ -294,9 +270,9 @@ static memcached_return_t io_wait(memcached_server_write_instance_st ptr, return memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT); } -static ssize_t io_flush(memcached_server_write_instance_st ptr, - const bool with_flush, - memcached_return_t *error) +static bool io_flush(memcached_server_write_instance_st ptr, + const bool with_flush, + memcached_return_t& error) { /* ** We might want to purge the input buffer if we haven't consumed @@ -310,27 +286,26 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr, if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED) { - return -1; + return false; } } - size_t return_length; char *local_write_ptr= ptr->write_buffer; size_t write_length= ptr->write_buffer_offset; - *error= MEMCACHED_SUCCESS; + error= MEMCACHED_SUCCESS; WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); // UDP Sanity check, make sure that we are not sending somthing too big if (memcached_is_udp(ptr->root) and write_length > MAX_UDP_DATAGRAM_LENGTH) { - *error= MEMCACHED_WRITE_FAILURE; - return -1; + error= memcached_set_error(*ptr, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); + return false; } if (ptr->write_buffer_offset == 0 or (memcached_is_udp(ptr->root) and ptr->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH)) { - return 0; + return true; } /* Looking for memory overflows */ @@ -340,7 +315,6 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr, WATCHPOINT_ASSERT((ptr->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length)); #endif - return_length= 0; while (write_length) { WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); @@ -354,11 +328,11 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr, WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); if (with_flush) { - sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT); + 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); + sent_length= ::send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT|MSG_MORE); } if (sent_length == SOCKET_ERROR) @@ -395,44 +369,38 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr, } else if (rc == MEMCACHED_TIMEOUT) { - *error= memcached_set_error(*ptr, MEMCACHED_TIMEOUT, MEMCACHED_AT); - return -1; + error= memcached_set_error(*ptr, MEMCACHED_TIMEOUT, MEMCACHED_AT); + return false; } memcached_quit_server(ptr, true); - *error= memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT); - return -1; + error= memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT); + return false; } case ENOTCONN: case EPIPE: default: memcached_quit_server(ptr, true); - *error= memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT); - WATCHPOINT_ASSERT(ptr->fd == -1); - return -1; + error= memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT); + WATCHPOINT_ASSERT(ptr->fd == INVALID_SOCKET); + return false; } } if (memcached_is_udp(ptr->root) and size_t(sent_length) != write_length) { memcached_quit_server(ptr, true); - *error= memcached_set_error(*ptr, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); - return -1; + error= memcached_set_error(*ptr, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); + return false; } ptr->io_bytes_sent+= uint32_t(sent_length); local_write_ptr+= sent_length; write_length-= uint32_t(sent_length); - return_length+= uint32_t(sent_length); } WATCHPOINT_ASSERT(write_length == 0); - // Need to study this assert() WATCHPOINT_ASSERT(return_length == - // ptr->write_buffer_offset); - - // if we are a udp server, the begining of the buffer is reserverd for - // the upd frame header if (memcached_is_udp(ptr->root)) { ptr->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH; @@ -442,7 +410,7 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr, ptr->write_buffer_offset= 0; } - return (ssize_t) return_length; + return true; } memcached_return_t memcached_io_wait_for_write(memcached_server_write_instance_st ptr) @@ -451,14 +419,16 @@ memcached_return_t memcached_io_wait_for_write(memcached_server_write_instance_s } memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, - void *buffer, size_t length, ssize_t *nread) + void *buffer, size_t length, ssize_t& nread) { assert_msg(ptr, "Programmer error, memcached_io_read() recieved an invalid memcached_server_write_instance_st"); // Programmer error char *buffer_ptr= static_cast(buffer); if (ptr->fd == INVALID_SOCKET) { +#if 0 assert_msg(int(ptr->state) <= int(MEMCACHED_SERVER_STATE_ADDRINFO), "Programmer error, invalid socket state"); +#endif return MEMCACHED_CONNECTION_FAILURE; } @@ -469,7 +439,7 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, ssize_t data_read; do { - data_read= recv(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER, MSG_DONTWAIT); + data_read= ::recv(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER, MSG_DONTWAIT); if (data_read == SOCKET_ERROR) { switch (get_socket_errno()) @@ -505,7 +475,7 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, default: { memcached_quit_server(ptr, true); - *nread= -1; + nread= -1; return memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT); } } @@ -523,8 +493,9 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, */ WATCHPOINT_STRING("We had a zero length recv()"); memcached_quit_server(ptr, true); - *nread= -1; - return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT); + nread= -1; + return memcached_set_error(*ptr, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT, + memcached_literal_param("::rec() returned zero, server has disconnected")); } } while (data_read <= 0); @@ -556,7 +527,7 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, } } - *nread = (ssize_t)(buffer_ptr - (char*)buffer); + nread= ssize_t(buffer_ptr - (char*)buffer); return MEMCACHED_SUCCESS; } @@ -659,17 +630,10 @@ static ssize_t _io_write(memcached_server_write_instance_st ptr, WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); memcached_return_t rc; - ssize_t sent_length= io_flush(ptr, with_flush, &rc); - if (sent_length == -1) + if (io_flush(ptr, with_flush, rc) == false) { return -1; } - - /* If io_flush calls memcached_purge, sent_length may be 0 */ - unlikely (sent_length != 0) - { - WATCHPOINT_ASSERT(sent_length == (ssize_t)buffer_end); - } } } @@ -677,7 +641,7 @@ static ssize_t _io_write(memcached_server_write_instance_st ptr, { memcached_return_t rc; WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); - if (io_flush(ptr, with_flush, &rc) == -1) + if (io_flush(ptr, with_flush, rc) == false) { return -1; } @@ -686,15 +650,20 @@ static ssize_t _io_write(memcached_server_write_instance_st ptr, return (ssize_t) original_length; } +bool memcached_io_write(memcached_server_write_instance_st ptr) +{ + return (_io_write(ptr, NULL, 0, true) >= 0); +} + ssize_t memcached_io_write(memcached_server_write_instance_st ptr, - const void *buffer, size_t length, bool with_flush) + const void *buffer, const size_t length, const bool with_flush) { return _io_write(ptr, buffer, length, with_flush); } ssize_t memcached_io_writev(memcached_server_write_instance_st ptr, - const struct libmemcached_io_vector_st *vector, - size_t number_of, bool with_flush) + libmemcached_io_vector_st vector[], + const size_t number_of, const bool with_flush) { ssize_t total= 0; @@ -702,16 +671,19 @@ ssize_t memcached_io_writev(memcached_server_write_instance_st ptr, { ssize_t returnable; - if ((returnable= _io_write(ptr, vector->buffer, vector->length, false)) == -1) + if (vector->length) { - return -1; + if ((returnable= _io_write(ptr, vector->buffer, vector->length, false)) == -1) + { + return -1; + } + total+= returnable; } - total+= returnable; } if (with_flush) { - if (memcached_io_write(ptr, NULL, 0, true) == -1) + if (memcached_io_write(ptr) == false) { return -1; } @@ -752,11 +724,12 @@ memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st for (uint32_t x= 0; x < memcached_server_count(memc) && host_index < MAX_SERVERS_TO_POLL; ++x) { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(memc, x); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(memc, x); if (instance->read_buffer_length > 0) /* I have data in the buffer */ + { return instance; + } if (memcached_server_response_count(instance) > 0) { @@ -827,7 +800,7 @@ void memcached_io_reset(memcached_server_write_instance_st ptr) */ memcached_return_t memcached_safe_read(memcached_server_write_instance_st ptr, void *dta, - size_t size) + const size_t size) { size_t offset= 0; char *data= static_cast(dta); @@ -837,14 +810,14 @@ memcached_return_t memcached_safe_read(memcached_server_write_instance_st ptr, ssize_t nread; memcached_return_t rc; - while (memcached_continue(rc= memcached_io_read(ptr, data + offset, size - offset, &nread))) { }; + while (memcached_continue(rc= memcached_io_read(ptr, data + offset, size - offset, nread))) { }; if (memcached_failed(rc)) { return rc; } - offset+= (size_t) nread; + offset+= size_t(nread); } return MEMCACHED_SUCCESS; @@ -858,7 +831,7 @@ memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr, total_nr= 0; bool line_complete= false; - while (not line_complete) + while (line_complete == false) { if (ptr->read_buffer_length == 0) { @@ -868,7 +841,7 @@ memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr, * the logic. */ ssize_t nread; - memcached_return_t rc= memcached_io_read(ptr, buffer_ptr, 1, &nread); + memcached_return_t rc= memcached_io_read(ptr, buffer_ptr, 1, nread); if (memcached_failed(rc) and rc == MEMCACHED_IN_PROGRESS) { memcached_quit_server(ptr, true); @@ -880,7 +853,9 @@ memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr, } if (*buffer_ptr == '\n') + { line_complete= true; + } ++buffer_ptr; ++total_nr; @@ -891,7 +866,9 @@ memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr, { *buffer_ptr = *ptr->read_ptr; if (*buffer_ptr == '\n') + { line_complete = true; + } --ptr->read_buffer_length; ++ptr->read_ptr; ++total_nr; @@ -899,21 +876,10 @@ memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr, } if (total_nr == size) + { return MEMCACHED_PROTOCOL_ERROR; + } } return MEMCACHED_SUCCESS; } - -memcached_return_t memcached_io_init_udp_header(memcached_server_write_instance_st ptr, uint16_t thread_id) -{ - if (thread_id > UDP_REQUEST_ID_MAX_THREAD_ID) - return MEMCACHED_FAILURE; - - struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer; - header->request_id= htons((uint16_t) (generate_udp_request_thread_id(thread_id))); - header->num_datagrams= htons(1); - header->sequence_number= htons(0); - - return MEMCACHED_SUCCESS; -} diff --git a/libmemcached/io.h b/libmemcached/io.h index 6d3e2fa2..c2711e28 100644 --- a/libmemcached/io.h +++ b/libmemcached/io.h @@ -38,45 +38,8 @@ #pragma once -#define MAX_UDP_DATAGRAM_LENGTH 1400 -#define UDP_DATAGRAM_HEADER_LENGTH 8 -#define UDP_REQUEST_ID_MSG_SIG_DIGITS 10 -#define UDP_REQUEST_ID_THREAD_MASK 0xFFFF << UDP_REQUEST_ID_MSG_SIG_DIGITS -#define get_udp_datagram_request_id(A) ntohs((A)->request_id) -#define get_udp_datagram_seq_num(A) ntohs((A)->sequence_number) -#define get_udp_datagram_num_datagrams(A) ntohs((A)->num_datagrams) -#define get_msg_num_from_request_id(A) ( (A) & (~(UDP_REQUEST_ID_THREAD_MASK)) ) -#define get_thread_id_from_request_id(A) ( (A) & (UDP_REQUEST_ID_THREAD_MASK) ) >> UDP_REQUEST_ID_MSG_SIG_DIGITS -#define generate_udp_request_thread_id(A) (A) << UDP_REQUEST_ID_MSG_SIG_DIGITS -#define UDP_REQUEST_ID_MAX_THREAD_ID get_thread_id_from_request_id(0xFFFF) - -struct udp_datagram_header_st -{ - uint16_t request_id; - uint16_t sequence_number; - uint16_t num_datagrams; - uint16_t reserved; -}; - struct libmemcached_io_vector_st { const void *buffer; size_t length; }; - -#ifdef __cplusplus -extern "C" { -#endif - -LIBMEMCACHED_LOCAL -ssize_t memcached_io_write(memcached_server_write_instance_st ptr, - const void *buffer, size_t length, bool with_flush); - -LIBMEMCACHED_LOCAL -ssize_t memcached_io_writev(memcached_server_write_instance_st ptr, - const struct libmemcached_io_vector_st *vector, - size_t number_of, bool with_flush); - -#ifdef __cplusplus -} -#endif diff --git a/libmemcached/io.hpp b/libmemcached/io.hpp index 23a4a6b4..549f86a0 100644 --- a/libmemcached/io.hpp +++ b/libmemcached/io.hpp @@ -38,38 +38,35 @@ #pragma once -LIBMEMCACHED_LOCAL +bool memcached_io_write(memcached_server_write_instance_st ptr); + +ssize_t memcached_io_write(memcached_server_write_instance_st ptr, + const void *buffer, size_t length, bool with_flush); + +ssize_t memcached_io_writev(memcached_server_write_instance_st ptr, + libmemcached_io_vector_st vector[], + const size_t number_of, const bool with_flush); + memcached_return_t memcached_io_wait_for_write(memcached_server_write_instance_st ptr); -LIBMEMCACHED_LOCAL void memcached_io_reset(memcached_server_write_instance_st ptr); -LIBMEMCACHED_LOCAL memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr, - void *buffer, size_t length, ssize_t *nread); + void *buffer, size_t length, ssize_t& nread); /* Read a line (terminated by '\n') into the buffer */ -LIBMEMCACHED_LOCAL memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr, char *buffer_ptr, size_t size, size_t& total); -LIBMEMCACHED_LOCAL void memcached_io_close(memcached_server_write_instance_st ptr); /* Read n bytes of data from the server and store them in dta */ -LIBMEMCACHED_LOCAL memcached_return_t memcached_safe_read(memcached_server_write_instance_st ptr, void *dta, - size_t size); - -LIBMEMCACHED_LOCAL -memcached_return_t memcached_io_init_udp_header(memcached_server_write_instance_st ptr, - uint16_t thread_id); + const size_t size); -LIBMEMCACHED_LOCAL memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st *memc); -LIBMEMCACHED_LOCAL memcached_return_t memcached_io_slurp(memcached_server_write_instance_st ptr); diff --git a/libmemcached/is.h b/libmemcached/is.h index 9f8783d8..6f8241d9 100644 --- a/libmemcached/is.h +++ b/libmemcached/is.h @@ -40,9 +40,17 @@ /* These are private */ #define memcached_is_allocated(__object) ((__object)->options.is_allocated) #define memcached_is_udp(__object) ((__object)->flags.use_udp) +#define memcached_is_verify_key(__object) ((__object)->flags.verify_key) +#define memcached_is_binary(__object) ((__object)->flags.binary_protocol) #define memcached_is_initialized(__object) ((__object)->options.is_initialized) #define memcached_is_purging(__object) ((__object)->state.is_purging) #define memcached_is_processing_input(__object) ((__object)->state.is_processing_input) + +#define memcached_is_buffering(__object) ((__object)->flags.buffer_requests) +#define memcached_is_replying(__object) ((__object)->flags.reply) + +#define memcached_has_error(__object) ((__object)->error_messages) + #define memcached_set_purging(__object, __value) ((__object)->state.is_purging= (__value)) #define memcached_set_processing_input(__object, __value) ((__object)->state.is_processing_input= (__value)) #define memcached_set_initialized(__object, __value) ((__object)->options.is_initialized(= (__value)) diff --git a/libmemcached/key.cc b/libmemcached/key.cc index ea98c729..e9246881 100644 --- a/libmemcached/key.cc +++ b/libmemcached/key.cc @@ -47,25 +47,15 @@ memcached_return_t memcached_key_test(memcached_st &memc, return memcached_set_error(memc, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT); } - if (not memc.flags.verify_key) + // If we don't need to verify the key, or we are using the binary protoocol, + // we just check the size of the key + if (memc.flags.verify_key == false or memc.flags.binary_protocol == true) { for (uint32_t x= 0; x < number_of_keys; x++) { - memcached_return_t rc= memcached_validate_key_length(*(key_length +x), false); - if (memcached_failed(rc)) - { - return rc; - } - } - - return MEMCACHED_SUCCESS; - } - - if (memc.flags.binary_protocol) - { - for (uint32_t x= 0; x < number_of_keys; x++) - { - memcached_return_t rc= memcached_validate_key_length(*(key_length +x), false); + // We should set binary key, but the memcached server is broken for + // longer keys at the moment. + memcached_return_t rc= memcached_validate_key_length(*(key_length +x), false /* memc.flags.binary_protocol */); if (memcached_failed(rc)) { return rc; diff --git a/libmemcached/memcached.cc b/libmemcached/memcached.cc index 8c1e3acb..62052ada 100644 --- a/libmemcached/memcached.cc +++ b/libmemcached/memcached.cc @@ -40,31 +40,6 @@ #include #include -#if 0 -static const memcached_st global_copy= { - .state= { - .is_purging= false, // .is_purging - .is_processing_input= false, // is_processing_input - .is_time_for_rebuild= false, - }, - .flags= { - .auto_eject_hosts= false, - .binary_protocol= false, - .buffer_requests= false, - .hash_with_namespace= false, - .no_block= false, - .no_reply= false, - .randomize_replica_read= false, - .support_cas= false, - .tcp_nodelay= false, - .use_sort_hosts= false, - .use_udp= false, - .verify_key= false, - .tcp_keepalive= false, - }, -}; -#endif - static inline bool _memcached_init(memcached_st *self) { self->state.is_purging= false; @@ -76,7 +51,7 @@ static inline bool _memcached_init(memcached_st *self) self->flags.buffer_requests= false; self->flags.hash_with_namespace= false; self->flags.no_block= false; - self->flags.no_reply= false; + self->flags.reply= true; self->flags.randomize_replica_read= false; self->flags.support_cas= false; self->flags.tcp_nodelay= false; diff --git a/libmemcached/purge.cc b/libmemcached/purge.cc index 36a33ae9..4dd65419 100644 --- a/libmemcached/purge.cc +++ b/libmemcached/purge.cc @@ -1,4 +1,44 @@ -#include "common.h" +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * LibMemcached + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include + memcached_return_t memcached_purge(memcached_server_write_instance_st ptr) { @@ -14,27 +54,30 @@ memcached_return_t memcached_purge(memcached_server_write_instance_st ptr) return MEMCACHED_SUCCESS; } - /* memcached_io_write and memcached_response may call memcached_purge - so we need to be able stop any recursion.. */ + /* + memcached_io_write and memcached_response may call memcached_purge + so we need to be able stop any recursion.. + */ memcached_set_purging(root, true); - WATCHPOINT_ASSERT(ptr->fd != -1); - /* 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, true) == -1) + WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); + /* + 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) == false) { memcached_set_purging(root, true); return memcached_set_error(*ptr, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); } - WATCHPOINT_ASSERT(ptr->fd != -1); + WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET); uint32_t 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]; /* * We need to increase the timeout, because we might be waiting for @@ -50,32 +93,34 @@ memcached_return_t memcached_purge(memcached_server_write_instance_st ptr) for (uint32_t x= 0; x < no_msg; x++) { memcached_result_reset(result_ptr); - memcached_return_t rc= memcached_read_one_response(ptr, buffer, - sizeof (buffer), - result_ptr); + memcached_return_t rc= memcached_read_one_response(ptr, 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) + if (rc== MEMCACHED_PROTOCOL_ERROR or rc == MEMCACHED_UNKNOWN_READ_FAILURE or rc == MEMCACHED_READ_FAILURE) { WATCHPOINT_ERROR(rc); - ret= rc; memcached_io_reset(ptr); - memcached_set_error(*ptr, rc, MEMCACHED_AT); + ret= rc; +#if 0 + ret= memcached_set_error(*ptr, rc, MEMCACHED_AT); +#endif } if (ptr->root->callbacks != NULL) { memcached_callback_st cb = *ptr->root->callbacks; - if (rc == MEMCACHED_SUCCESS) + if (memcached_success(rc)) { for (uint32_t y= 0; y < cb.number_of_callback; y++) { rc = (*cb.callback[y])(ptr->root, result_ptr, cb.context); if (rc != MEMCACHED_SUCCESS) + { break; + } } } } diff --git a/libmemcached/quit.cc b/libmemcached/quit.cc index ffd4cd45..9aadd605 100644 --- a/libmemcached/quit.cc +++ b/libmemcached/quit.cc @@ -61,11 +61,22 @@ void memcached_quit_server(memcached_server_st *ptr, bool io_death) request.message.header.request.magic = PROTOCOL_BINARY_REQ; request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT; request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; - rc= memcached_do(ptr, request.bytes, sizeof(request.bytes), true); + + libmemcached_io_vector_st vector[]= + { + { request.bytes, sizeof(request.bytes) } + }; + + rc= memcached_vdo(ptr, vector, 1, true); } else { - rc= memcached_do(ptr, memcached_literal_param("quit\r\n"), true); + libmemcached_io_vector_st vector[]= + { + { memcached_literal_param("quit\r\n") } + }; + + rc= memcached_vdo(ptr, vector, 1, true); } WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_FETCH_NOTFINISHED); @@ -129,7 +140,8 @@ void send_quit(memcached_st *ptr) void memcached_quit(memcached_st *ptr) { - if (memcached_failed(initialize_query(ptr))) + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr, true))) { return; } diff --git a/libmemcached/response.cc b/libmemcached/response.cc index 061f7401..e876123d 100644 --- a/libmemcached/response.cc +++ b/libmemcached/response.cc @@ -38,104 +38,20 @@ #include #include -static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result); -static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result); - -memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result) -{ - memcached_server_response_decrement(ptr); - - if (result == NULL) - { - memcached_st *root= (memcached_st *)ptr->root; - result = &root->result; - } - - memcached_return_t rc; - if (ptr->root->flags.binary_protocol) - { - rc= binary_read_one_response(ptr, buffer, buffer_length, result); - } - else - { - rc= textual_read_one_response(ptr, buffer, buffer_length, result); - } - - unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE or - rc == MEMCACHED_PROTOCOL_ERROR or - rc == MEMCACHED_CLIENT_ERROR or - rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) - { - memcached_io_reset(ptr); - } - - return rc; -} - -memcached_return_t memcached_response(memcached_server_write_instance_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.no_block) && (memcached_is_processing_input(ptr->root) == false)) - { - (void)memcached_io_write(ptr, NULL, 0, true); - } - - /* - * 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.binary_protocol == false) - { - while (memcached_server_response_count(ptr) > 1) - { - memcached_return_t 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; - } - } - - return memcached_read_one_response(ptr, buffer, buffer_length, result); -} - static memcached_return_t textual_value_fetch(memcached_server_write_instance_st ptr, char *buffer, memcached_result_st *result) { - char *string_ptr; - char *end_ptr; char *next_ptr; - size_t value_length; - size_t to_read; ssize_t read_length= 0; - - if (ptr->root->flags.use_udp) - { - return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT); - } + size_t value_length; WATCHPOINT_ASSERT(ptr->root); - end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE; + char *end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE; memcached_result_reset(result); - string_ptr= buffer; + char *string_ptr= buffer; string_ptr+= 6; /* "VALUE " */ @@ -162,29 +78,39 @@ static memcached_return_t textual_value_fetch(memcached_server_write_instance_st } if (end_ptr == string_ptr) + { goto read_error; + } /* Flags fetch move past space */ string_ptr++; if (end_ptr == string_ptr) + { goto read_error; + } for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++) {}; result->item_flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10); if (end_ptr == string_ptr) + { goto read_error; + } /* Length fetch move past space*/ string_ptr++; if (end_ptr == string_ptr) + { goto read_error; + } for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++) {}; value_length= (size_t)strtoull(next_ptr, &string_ptr, 10); if (end_ptr == string_ptr) + { goto read_error; + } /* Skip spaces */ if (*string_ptr == '\r') @@ -200,7 +126,9 @@ static memcached_return_t textual_value_fetch(memcached_server_write_instance_st } if (end_ptr < string_ptr) + { goto read_error; + } /* We add two bytes so that we can walk the \r\n */ if (memcached_failed(memcached_string_check(&result->value, value_length +2))) @@ -217,8 +145,8 @@ static memcached_return_t textual_value_fetch(memcached_server_write_instance_st We are null terminating through, which will most likely make some people lazy about using the return length. */ - to_read= (value_length) + 2; - memcached_return_t rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length); + size_t to_read= (value_length) + 2; + memcached_return_t rrc= memcached_io_read(ptr, value_ptr, to_read, read_length); if (memcached_failed(rrc) and rrc == MEMCACHED_IN_PROGRESS) { memcached_quit_server(ptr, true); @@ -253,9 +181,11 @@ read_error: } static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, - memcached_result_st *result) + char *buffer, const size_t buffer_length, + memcached_result_st *result, + uint64_t& numeric_value) { + numeric_value= UINT64_MAX; size_t total_read; memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length, total_read); @@ -263,36 +193,49 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta { return rc; } + assert(total_read); switch(buffer[0]) { - case 'V': /* VALUE || VERSION */ - if (buffer[1] == 'A') /* VALUE */ - { - /* We add back in one because we will need to search for END */ - memcached_server_response_increment(ptr); - return textual_value_fetch(ptr, buffer, result); - } - else if (buffer[1] == 'E') /* VERSION */ + case 'V': { - return MEMCACHED_SUCCESS; + // VALUE + if (buffer[1] == 'A' and buffer[2] == 'L' and buffer[3] == 'U' and buffer[4] == 'E') /* VALUE */ + { + /* We add back in one because we will need to search for END */ + memcached_server_response_increment(ptr); + return textual_value_fetch(ptr, buffer, result); + } + // VERSION + else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'S' and buffer[4] == 'I' and buffer[5] == 'O' and buffer[6] == 'N') /* VERSION */ + { + return MEMCACHED_SUCCESS; + } } - else + break; + + case 'O': { - WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; + // OK + if (buffer[1] == 'K') + { + return MEMCACHED_SUCCESS; + } } - case 'O': /* OK */ - return MEMCACHED_SUCCESS; + break; - case 'S': /* STORED STATS SERVER_ERROR */ + case 'S': { - if (buffer[2] == 'A') /* STORED STATS */ + // STAT + if (buffer[1] == 'T' and buffer[2] == 'A' and buffer[3] == 'T') /* STORED STATS */ { memcached_server_response_increment(ptr); return MEMCACHED_STAT; } - else if (buffer[1] == 'E') /* SERVER_ERROR */ + // SERVER_ERROR + else if (buffer[1] == 'E' and buffer[2] == 'R' and buffer[3] == 'V' and buffer[4] == 'E' and buffer[5] == 'R' + and buffer[6] == '_' + and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R' ) { if (total_read == memcached_literal_param_size("SERVER_ERROR")) { @@ -317,92 +260,150 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta return memcached_set_error(*ptr, MEMCACHED_SERVER_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr)); } - else if (buffer[1] == 'T') + // STORED + else if (buffer[1] == 'T' and buffer[2] == 'O' and buffer[3] == 'R') // and buffer[4] == 'E' and buffer[5] == 'D') { return MEMCACHED_STORED; } - else + } + break; + + case 'D': + { + // DELETED + if (buffer[1] == 'E' and buffer[2] == 'L' and buffer[3] == 'E' and buffer[4] == 'T' and buffer[5] == 'E' and buffer[6] == 'D') { - WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; + return MEMCACHED_DELETED; } } - case 'D': /* DELETED */ - return MEMCACHED_DELETED; + break; - case 'N': /* NOT_FOUND */ + case 'N': { - if (buffer[4] == 'F') + // NOT_FOUND + if (buffer[1] == 'O' and buffer[2] == 'T' + and buffer[3] == '_' + and buffer[4] == 'F' and buffer[5] == 'O' and buffer[6] == 'U' and buffer[7] == 'N' and buffer[8] == 'D') { return MEMCACHED_NOTFOUND; } - else if (buffer[4] == 'S') + // NOT_STORED + else if (buffer[1] == 'O' and buffer[2] == 'T' + and buffer[3] == '_' + and buffer[4] == 'S' and buffer[5] == 'T' and buffer[6] == 'O' and buffer[7] == 'R' and buffer[8] == 'E' and buffer[9] == 'D') { return MEMCACHED_NOTSTORED; } - else - { - WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } } + break; + case 'E': /* PROTOCOL ERROR or END */ { - if (buffer[1] == 'N') + // END + if (buffer[1] == 'N' and buffer[2] == 'D') { return MEMCACHED_END; } - else if (buffer[1] == 'R') +#if 0 + // PROTOCOL_ERROR + else if (buffer[1] == 'R' and buffer[2] == 'O' and buffer[3] == 'T' and buffer[4] == 'O' and buffer[5] == 'C' and buffer[6] == 'O' and buffer[7] == 'L' + and buffer[8] == '_' + and buffer[9] == 'E' and buffer[10] == 'R' and buffer[11] == 'R' and buffer[12] == 'O' and buffer[13] == 'R') { return MEMCACHED_PROTOCOL_ERROR; } - else if (buffer[1] == 'X') +#endif + // EXISTS + else if (buffer[1] == 'X' and buffer[2] == 'I' and buffer[3] == 'S' and buffer[4] == 'T' and buffer[5] == 'S') { return MEMCACHED_DATA_EXISTS; } - else - { - WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; - } - } + break; + case 'T': /* TOUCHED */ { - if (buffer[1] == 'O' and buffer[2] == 'U' - and buffer[3] == 'C' and buffer[4] == 'H' - and buffer[5] == 'E' and buffer[6] == 'D') + // TOUCHED + if (buffer[1] == 'O' and buffer[2] == 'U' and buffer[3] == 'C' and buffer[4] == 'H' and buffer[5] == 'E' and buffer[6] == 'D') { return MEMCACHED_SUCCESS; } } - return MEMCACHED_UNKNOWN_READ_FAILURE; + break; - case 'I': /* CLIENT ERROR */ - /* We add back in one because we will need to search for END */ - memcached_server_response_increment(ptr); - return MEMCACHED_ITEM; + case 'I': /* ITEM */ + { + // ITEM + if (buffer[1] == 'T' and buffer[2] == 'E' and buffer[3] == 'M') + { + /* We add back in one because we will need to search for END */ + memcached_server_response_increment(ptr); + return MEMCACHED_ITEM; + } + } + break; case 'C': /* CLIENT ERROR */ - return MEMCACHED_CLIENT_ERROR; - - default: { - unsigned long long auto_return_value; + // CLIENT_ERROR + if (buffer[1] == 'L' and buffer[2] == 'I' and buffer[3] == 'E' and buffer[4] == 'N' and buffer[5] == 'T' + and buffer[6] == '_' + and buffer[7] == 'E' and buffer[8] == 'R' and buffer[9] == 'R' and buffer[10] == 'O' and buffer[11] == 'R') + { + return MEMCACHED_CLIENT_ERROR; + } + } + break; + + case '0': /* INCR/DECR response */ + case '1': /* INCR/DECR response */ + case '2': /* INCR/DECR response */ + case '3': /* INCR/DECR response */ + case '4': /* INCR/DECR response */ + case '5': /* INCR/DECR response */ + case '6': /* INCR/DECR response */ + case '7': /* INCR/DECR response */ + case '8': /* INCR/DECR response */ + case '9': /* INCR/DECR response */ + { + unsigned long long int auto_return_value= strtoull(buffer, (char **)NULL, 10); - if (sscanf(buffer, "%llu", &auto_return_value) == 1) - return MEMCACHED_SUCCESS; + if (auto_return_value == ULLONG_MAX and errno == ERANGE) + { + return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, + memcached_literal_param("Numeric response was out of range")); + } + else if (errno == EINVAL) + { + return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, + memcached_literal_param("Numeric response was out of range")); + } + + numeric_value= uint64_t(auto_return_value); WATCHPOINT_STRING(buffer); - return MEMCACHED_UNKNOWN_READ_FAILURE; + return MEMCACHED_SUCCESS; } + + default: + break; } - /* NOTREACHED */ + buffer[total_read]= 0; +#if 0 + if (total_read >= sizeof("STORSTORED") -1) + { + fprintf(stderr, "%s:%d '%s', %.*s\n", __FILE__, __LINE__, + buffer, MEMCACHED_MAX_BUFFER, ptr->read_buffer); + assert(memcmp(buffer,"STORSTORED", sizeof("STORSTORED") -1)); + } +#endif + return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT, + buffer, total_read); } static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, + char *buffer, const size_t buffer_length, memcached_result_st *result) { memcached_return_t rc; @@ -416,7 +417,7 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan if (header.response.magic != PROTOCOL_BINARY_RES) { - return MEMCACHED_PROTOCOL_ERROR; + return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT); } /* @@ -497,9 +498,9 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan case PROTOCOL_BINARY_CMD_INCREMENT: case PROTOCOL_BINARY_CMD_DECREMENT: { - if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t)) + if (bodylen != sizeof(uint64_t) or buffer_length != sizeof(uint64_t)) { - return MEMCACHED_PROTOCOL_ERROR; + return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT); } WATCHPOINT_ASSERT(bodylen == buffer_length); @@ -599,8 +600,7 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan default: { /* Command not implemented yet! */ - WATCHPOINT_ASSERT(0); - return MEMCACHED_PROTOCOL_ERROR; + return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT); } } } @@ -673,11 +673,122 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan case PROTOCOL_BINARY_RESPONSE_EINVAL: case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND: default: - /* @todo fix the error mappings */ - rc= MEMCACHED_PROTOCOL_ERROR; + return memcached_set_error(*ptr, MEMCACHED_UNKNOWN_READ_FAILURE, MEMCACHED_AT); break; } } return rc; } + +static memcached_return_t _read_one_response(memcached_server_write_instance_st ptr, + char *buffer, const size_t buffer_length, + memcached_result_st *result, + uint64_t& numeric_value) +{ + memcached_server_response_decrement(ptr); + + if (result == NULL) + { + memcached_st *root= (memcached_st *)ptr->root; + result = &root->result; + } + + memcached_return_t rc; + if (memcached_is_binary(ptr->root)) + { + rc= binary_read_one_response(ptr, buffer, buffer_length, result); + } + else + { + rc= textual_read_one_response(ptr, buffer, buffer_length, result, numeric_value); + assert(rc != MEMCACHED_PROTOCOL_ERROR); + } + + if (rc == MEMCACHED_UNKNOWN_READ_FAILURE or + rc == MEMCACHED_READ_FAILURE or + rc == MEMCACHED_PROTOCOL_ERROR or + rc == MEMCACHED_CLIENT_ERROR or + rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) + { + memcached_io_reset(ptr); + } + + return rc; +} + +memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr, + memcached_result_st *result) +{ + uint64_t numeric_value; + char buffer[SMALL_STRING_LEN]; + + if (memcached_is_udp(ptr->root)) + { + return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT); + } + + + return _read_one_response(ptr, buffer, sizeof(buffer), result, numeric_value); +} + +memcached_return_t memcached_response(memcached_server_write_instance_st ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result) +{ + uint64_t numeric_value; + + return memcached_response(ptr, buffer, buffer_length, result, numeric_value); +} + +memcached_return_t memcached_response(memcached_server_write_instance_st ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result, + uint64_t& numeric_value) +{ + if (memcached_is_udp(ptr->root)) + { + return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT); + } + + /* We may have old commands in the buffer not set, first purge */ + if ((ptr->root->flags.no_block) and (memcached_is_processing_input(ptr->root) == false)) + { + (void)memcached_io_write(ptr); + } + + /* + * The previous implementation purged all pending requests and just + * returned the last one. Purge all pending messages to ensure backwards + * compatibility. + */ + if (memcached_is_binary(ptr->root) == false and memcached_server_response_count(ptr) > 1) + { + memcached_result_st junked_result; + memcached_result_st *junked_result_ptr= memcached_result_create(ptr->root, &junked_result); + + assert(junked_result_ptr); + + while (memcached_server_response_count(ptr) > 1) + { + memcached_return_t rc= _read_one_response(ptr, buffer, buffer_length, junked_result_ptr, numeric_value); + + // @TODO should we return an error on another but a bad read case? + if (rc != MEMCACHED_END and + rc != MEMCACHED_STORED and + rc != MEMCACHED_SUCCESS and + rc != MEMCACHED_STAT and + rc != MEMCACHED_DELETED and + rc != MEMCACHED_NOTFOUND and + rc != MEMCACHED_NOTSTORED and + rc != MEMCACHED_DATA_EXISTS) + { + memcached_result_free(junked_result_ptr); + return rc; + } + } + memcached_result_free(junked_result_ptr); + } + + return _read_one_response(ptr, buffer, buffer_length, result, numeric_value); +} diff --git a/libmemcached/response.h b/libmemcached/response.h index 51f09998..d9abdb8a 100644 --- a/libmemcached/response.h +++ b/libmemcached/response.h @@ -37,21 +37,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - /* Read a single response from the server */ -LIBMEMCACHED_LOCAL memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr, - char *buffer, size_t buffer_length, memcached_result_st *result); -LIBMEMCACHED_LOCAL memcached_return_t memcached_response(memcached_server_write_instance_st ptr, char *buffer, size_t buffer_length, memcached_result_st *result); -#ifdef __cplusplus -} -#endif +memcached_return_t memcached_response(memcached_server_write_instance_st ptr, + char *buffer, size_t buffer_length, + memcached_result_st *result, + uint64_t& numeric_value); diff --git a/libmemcached/sasl.cc b/libmemcached/sasl.cc index 2e9bdc63..902ccd87 100644 --- a/libmemcached/sasl.cc +++ b/libmemcached/sasl.cc @@ -133,9 +133,10 @@ memcached_return_t memcached_sasl_authenticate_connection(memcached_server_st *s } /* SANITY CHECK: SASL can only be used with the binary protocol */ - if (server->root->flags.binary_protocol == false) + if (memcached_is_binary(server->root) == false) { - return MEMCACHED_PROTOCOL_ERROR; + return memcached_set_error(*server, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, + memcached_literal_param("memcached_sasl_authenticate_connection() is not supported via the ASCII protocol")); } /* Try to get the supported mech from the server. Servers without SASL @@ -229,7 +230,7 @@ memcached_return_t memcached_sasl_authenticate_connection(memcached_server_st *s do { /* send the packet */ - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { { request.bytes, sizeof(request.bytes) }, { chosenmech, keylen }, diff --git a/libmemcached/server.cc b/libmemcached/server.cc index 7011fd24..f08f8bf0 100644 --- a/libmemcached/server.cc +++ b/libmemcached/server.cc @@ -50,7 +50,7 @@ static inline void _server_init(memcached_server_st *self, memcached_st *root, self->number_of_hosts= 0; self->cursor_active= 0; self->port= port; - self->fd= -1; + self->fd= INVALID_SOCKET; self->io_bytes_sent= 0; self->server_failure_counter= 0; self->server_failure_counter_query_id= 0; @@ -88,11 +88,11 @@ static inline void _server_init(memcached_server_st *self, memcached_st *root, static memcached_server_st *_server_create(memcached_server_st *self, const memcached_st *memc) { - if (not self) + if (self == NULL) { self= libmemcached_xmalloc(memc, struct memcached_server_st); - if (not self) + if (self == NULL) { return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */ } @@ -131,9 +131,8 @@ memcached_server_st *__server_create_with(memcached_st *memc, _server_init(self, const_cast(memc), hostname, port, weight, type); - if (memc and memcached_is_udp(memc)) - { + { self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH; memcached_io_init_udp_header(self, 0); } diff --git a/libmemcached/server_list.cc b/libmemcached/server_list.cc index d5994e85..f03dc356 100644 --- a/libmemcached/server_list.cc +++ b/libmemcached/server_list.cc @@ -83,7 +83,7 @@ memcached_server_list_append_with_weight(memcached_server_list_st ptr, memcached_string_t _hostname= { memcached_string_make_from_cstr(hostname) }; /* @todo Check return type */ - if (not __server_create_with(NULL, &new_host_list[count-1], _hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET)) + if (__server_create_with(NULL, &new_host_list[count-1], _hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET) == NULL) { *error= memcached_set_errno(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT); return NULL; diff --git a/libmemcached/stats.cc b/libmemcached/stats.cc index 239c789d..d5d1c234 100644 --- a/libmemcached/stats.cc +++ b/libmemcached/stats.cc @@ -1,7 +1,40 @@ -/* -*/ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ -#include "common.h" +#include static const char *memcached_stat_keys[] = { "pid", @@ -34,13 +67,16 @@ struct local_context memcached_stat_fn func; void *context; const char *args; + const size_t args_length; local_context(memcached_stat_fn func_arg, - void *context_arg, - const char *args_arg) : + void *context_arg, + const char *args_arg, + const size_t args_length_arg) : func(func_arg), context(context_arg), - args(args_arg) + args(args_arg), + args_length(args_length_arg) { } }; @@ -53,7 +89,7 @@ static memcached_return_t set_data(memcached_stat_st *memc_stat, char *key, char WATCHPOINT_STRING(key); return MEMCACHED_UNKNOWN_STAT_KEY; } - else if (not strcmp("pid", key)) + else if (strcmp("pid", key) == 0) { int64_t temp= strtoll(value, (char **)NULL, 10); @@ -200,7 +236,7 @@ char *memcached_stat_get_value(const memcached_st *ptr, memcached_stat_st *memc_ *error= MEMCACHED_SUCCESS; - if (not memcmp("pid", key, sizeof("pid") -1)) + if (memcmp("pid", key, sizeof("pid") -1) == 0) { length= snprintf(buffer, SMALL_STRING_LEN,"%lld", (signed long long)memc_stat->pid); } @@ -309,6 +345,7 @@ char *memcached_stat_get_value(const memcached_st *ptr, memcached_stat_st *memc_ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, const char *args, + const size_t args_length, memcached_server_write_instance_st instance, struct local_context *check) { @@ -318,23 +355,15 @@ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT; request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - if (args) + if (args_length) { - size_t len= strlen(args); + request.message.header.request.keylen= htons(uint16_t(args_length)); + request.message.header.request.bodylen= htonl(uint32_t( args_length)); - memcached_return_t rc= memcached_validate_key_length(len, true); - if (rc != MEMCACHED_SUCCESS) - { - return rc; - } - - request.message.header.request.keylen= htons((uint16_t)len); - request.message.header.request.bodylen= htonl((uint32_t) len); - - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { { request.bytes, sizeof(request.bytes) }, - { args, len } + { args, args_length } }; if (memcached_vdo(instance, vector, 2, true) != MEMCACHED_SUCCESS) @@ -345,8 +374,12 @@ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, } else { - if (memcached_do(instance, request.bytes, - sizeof(request.bytes), true) != MEMCACHED_SUCCESS) + libmemcached_io_vector_st vector[]= + { + { request.bytes, sizeof(request.bytes) } + }; + + if (memcached_vdo(instance, vector, 1, true) != MEMCACHED_SUCCESS) { memcached_io_reset(instance); return MEMCACHED_WRITE_FAILURE; @@ -359,9 +392,11 @@ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, memcached_return_t rc= memcached_response(instance, buffer, sizeof(buffer), NULL); if (rc == MEMCACHED_END) + { break; + } - unlikely (rc != MEMCACHED_SUCCESS) + if (rc != MEMCACHED_SUCCESS) { memcached_io_reset(instance); return rc; @@ -369,7 +404,7 @@ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, if (memc_stat) { - unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY) + if ((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY) { WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); WATCHPOINT_ASSERT(0); @@ -387,9 +422,10 @@ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, } } while (1); - /* shit... memcached_response will decrement the counter, so I need to - ** reset it.. todo: look at this and try to find a better solution. - */ + /* + * memcached_response will decrement the counter, so I need to reset it.. + * todo: look at this and try to find a better solution. + * */ instance->cursor_active= 0; return MEMCACHED_SUCCESS; @@ -397,30 +433,21 @@ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat, const char *args, + const size_t args_length, memcached_server_write_instance_st instance, struct local_context *check) { - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - int send_length; - - if (args) + libmemcached_io_vector_st vector[]= { - send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, "stats %s\r\n", args); - } - else - { - send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, "stats\r\n"); - } + { memcached_literal_param("stats ") }, + { args, args_length }, + { memcached_literal_param("\r\n") } + }; - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) - { - return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, - memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); - } - - memcached_return_t rc= memcached_do(instance, buffer, (size_t)send_length, true); + memcached_return_t rc= memcached_vdo(instance, vector, 3, true); if (memcached_success(rc)) { + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; while ((rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL)) == MEMCACHED_STAT) { char *string_ptr, *end_ptr; @@ -456,9 +483,11 @@ static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat, } if (rc == MEMCACHED_END) + { return MEMCACHED_SUCCESS; - else - return rc; + } + + return rc; } memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_return_t *error) @@ -469,29 +498,36 @@ memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_retu error= &unused; } - memcached_return_t rc; - if (memcached_failed(rc= initialize_query(self))) + if (memcached_failed(*error= initialize_query(self, true))) { - *error= rc; - return NULL; } - WATCHPOINT_ASSERT(error); - - if (self->flags.use_udp) + if (memcached_is_udp(self)) { *error= memcached_set_error(*self, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT); - return NULL; } - memcached_stat_st *stats= libmemcached_xcalloc(self, memcached_server_count(self), memcached_stat_st); - - if (not stats) + memcached_return_t rc; + size_t args_length= 0; + if (args) { - *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE; + args_length= strlen(args); + rc= memcached_validate_key_length(args_length, self->flags.binary_protocol); + if (memcached_failed(rc)) + { + *error= memcached_set_error(*self, rc, MEMCACHED_AT); + return NULL; + } + } + + WATCHPOINT_ASSERT(error); + memcached_stat_st *stats= libmemcached_xcalloc(self, memcached_server_count(self), memcached_stat_st); + if (stats == NULL) + { + *error= memcached_set_error(*self, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT); return NULL; } @@ -499,24 +535,21 @@ memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_retu rc= MEMCACHED_SUCCESS; for (uint32_t x= 0; x < memcached_server_count(self); x++) { - memcached_return_t temp_return; - memcached_server_write_instance_st instance; - memcached_stat_st *stat_instance; - - stat_instance= stats +x; + memcached_stat_st* stat_instance= stats +x; stat_instance->pid= -1; stat_instance->root= self; - instance= memcached_server_instance_fetch(self, x); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(self, x); - if (self->flags.binary_protocol) + memcached_return_t temp_return; + if (memcached_is_binary(self)) { - temp_return= binary_stats_fetch(stat_instance, args, instance, NULL); + temp_return= binary_stats_fetch(stat_instance, args, args_length, instance, NULL); } else { - temp_return= ascii_stats_fetch(stat_instance, args, instance, NULL); + temp_return= ascii_stats_fetch(stat_instance, args, args_length, instance, NULL); } if (memcached_failed(temp_return)) @@ -534,31 +567,43 @@ memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char const char *hostname, in_port_t port) { memcached_st memc; - memcached_server_write_instance_st instance; memset(memc_stat, 0, sizeof(memcached_stat_st)); memcached_st *memc_ptr= memcached_create(&memc); - if (not memc_ptr) + if (memc_ptr == NULL) + { return MEMCACHED_MEMORY_ALLOCATION_FAILURE; - - memcached_server_add(&memc, hostname, port); + } memcached_return_t rc; - if ((rc= initialize_query(memc_ptr)) != MEMCACHED_SUCCESS) + if (memcached_failed(rc= memcached_server_add(&memc, hostname, port))) { + memcached_free(&memc); return rc; } - instance= memcached_server_instance_fetch(memc_ptr, 0); - - if (memc.flags.binary_protocol) + if (memcached_success(rc= initialize_query(memc_ptr, true))) { - rc= binary_stats_fetch(memc_stat, args, instance, NULL); - } - else - { - rc= ascii_stats_fetch(memc_stat, args, instance, NULL); + size_t args_length= 0; + if (args) + { + args_length= strlen(args); + rc= memcached_validate_key_length(args_length, memc.flags.binary_protocol); + } + + if (memcached_success(rc)) + { + memcached_server_write_instance_st instance= memcached_server_instance_fetch(memc_ptr, 0); + if (memc.flags.binary_protocol) + { + rc= binary_stats_fetch(memc_stat, args, args_length, instance, NULL); + } + else + { + rc= ascii_stats_fetch(memc_stat, args, args_length, instance, NULL); + } + } } memcached_free(&memc); @@ -617,11 +662,11 @@ static memcached_return_t call_stat_fn(memcached_st *ptr, if (ptr->flags.binary_protocol) { - rc= binary_stats_fetch(NULL, check->args, instance, check); + rc= binary_stats_fetch(NULL, check->args, check->args_length, instance, check); } else { - rc= ascii_stats_fetch(NULL, check->args, instance, check); + rc= ascii_stats_fetch(NULL, check->args, check->args_length, instance, check); } return rc; @@ -631,7 +676,7 @@ memcached_return_t memcached_stat_execute(memcached_st *memc, const char *args, { memcached_version(memc); - struct local_context check(func, context, args); + struct local_context check(func, context, args, args ? strlen(args) : 0); return memcached_server_execute(memc, call_stat_fn, (void *)&check); } diff --git a/libmemcached/storage.cc b/libmemcached/storage.cc index 89bc8e87..2d0ae8fc 100644 --- a/libmemcached/storage.cc +++ b/libmemcached/storage.cc @@ -1,14 +1,41 @@ -/* LibMemcached - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. * - * Summary: Storage related functions, aka set, replace,.. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + #include enum memcached_storage_action_t { @@ -47,9 +74,9 @@ static inline const char *storage_op_string(memcached_storage_action_t verb) return "set "; } -static inline uint8_t get_com_code(memcached_storage_action_t verb, bool noreply) +static inline uint8_t get_com_code(const memcached_storage_action_t verb, const bool reply) { - if (noreply) + if (reply == false) { switch (verb) { @@ -97,22 +124,21 @@ static memcached_return_t memcached_send_binary(memcached_st *ptr, memcached_server_write_instance_st server, uint32_t server_key, const char *key, - size_t key_length, + const size_t key_length, const char *value, - size_t value_length, - time_t expiration, - uint32_t flags, - uint64_t cas, - bool flush, + const size_t value_length, + const time_t expiration, + const uint32_t flags, + const uint64_t cas, + const bool flush, + const bool reply, memcached_storage_action_t verb) { protocol_binary_request_set request= {}; size_t send_length= sizeof(request.bytes); - bool noreply= server->root->flags.no_reply; - request.message.header.request.magic= PROTOCOL_BINARY_REQ; - request.message.header.request.opcode= get_com_code(verb, noreply); + request.message.header.request.opcode= get_com_code(verb, reply); request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace))); request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; if (verb == APPEND_OP or verb == PREPEND_OP) @@ -134,22 +160,9 @@ static memcached_return_t memcached_send_binary(memcached_st *ptr, request.message.header.request.cas= memcached_htonll(cas); } - if (server->root->flags.use_udp and flush == false) - { - size_t cmd_size= send_length + key_length + value_length; - - if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) - { - return MEMCACHED_WRITE_FAILURE; - } - if (cmd_size + server->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) - { - memcached_io_write(server, NULL, 0, true); - } - } - - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { + { NULL, 0 }, { request.bytes, send_length }, { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) }, { key, key_length }, @@ -158,11 +171,11 @@ static memcached_return_t memcached_send_binary(memcached_st *ptr, /* write the header */ memcached_return_t rc; - if ((rc= memcached_vdo(server, vector, 4, flush)) != MEMCACHED_SUCCESS) + if ((rc= memcached_vdo(server, vector, 5, flush)) != MEMCACHED_SUCCESS) { memcached_io_reset(server); - if (ptr->error_messages == NULL) + if (memcached_has_error(ptr)) { memcached_set_error(*server, rc, MEMCACHED_AT); } @@ -170,7 +183,7 @@ static memcached_return_t memcached_send_binary(memcached_st *ptr, return MEMCACHED_WRITE_FAILURE; } - if (verb == SET_OP && ptr->number_of_replicas > 0) + if (verb == SET_OP and ptr->number_of_replicas > 0) { request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ; WATCHPOINT_STRING("replicating"); @@ -185,7 +198,7 @@ static memcached_return_t memcached_send_binary(memcached_st *ptr, memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key); - if (memcached_vdo(instance, vector, 4, false) != MEMCACHED_SUCCESS) + if (memcached_vdo(instance, vector, 5, false) != MEMCACHED_SUCCESS) { memcached_io_reset(instance); } @@ -201,7 +214,8 @@ static memcached_return_t memcached_send_binary(memcached_st *ptr, return MEMCACHED_BUFFERED; } - if (noreply) + // No reply always assumes success + if (reply == false) { return MEMCACHED_SUCCESS; } @@ -212,121 +226,90 @@ static memcached_return_t memcached_send_binary(memcached_st *ptr, static memcached_return_t memcached_send_ascii(memcached_st *ptr, memcached_server_write_instance_st instance, const char *key, - size_t key_length, + const size_t key_length, const char *value, - size_t value_length, - time_t expiration, - uint32_t flags, - uint64_t cas, - bool flush, - memcached_storage_action_t verb) + const size_t value_length, + const time_t expiration, + const uint32_t flags, + const uint64_t cas, + const bool flush, + const bool reply, + const memcached_storage_action_t verb) { - size_t write_length; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - - if (cas) + char flags_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1]; + int flags_buffer_length= snprintf(flags_buffer, sizeof(flags_buffer), " %u", flags); + if (size_t(flags_buffer_length) >= sizeof(flags_buffer) or flags_buffer_length < 0) { - int check_length; - check_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "%s %.*s%.*s %u %llu %lu %llu%s\r\n", - storage_op_string(verb), - memcached_print_array(ptr->_namespace), - (int)key_length, key, flags, - (unsigned long long)expiration, (unsigned long)value_length, - (unsigned long long)cas, - (ptr->flags.no_reply) ? " noreply" : ""); - if (check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE or check_length < 0) - { - return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, - memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); - } - write_length= check_length; + return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, + memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)")); } - else - { - char *buffer_ptr= buffer; - const char *command= storage_op_string(verb); - - /* Copy in the command, no space needed, we handle that in the command function*/ - memcpy(buffer_ptr, command, strlen(command)); - - /* Copy in the key prefix, switch to the buffer_ptr */ - buffer_ptr= (char *)memcpy((char *)(buffer_ptr + strlen(command)), (char *)memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace)); - - /* Copy in the key, adjust point if a key prefix was used. */ - buffer_ptr= (char *)memcpy(buffer_ptr + memcached_array_size(ptr->_namespace), - key, key_length); - buffer_ptr+= key_length; - buffer_ptr[0]= ' '; - buffer_ptr++; - - write_length= (size_t)(buffer_ptr - buffer); - int check_length= snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer), - "%u %llu %lu%s\r\n", - flags, - (unsigned long long)expiration, (unsigned long)value_length, - ptr->flags.no_reply ? " noreply" : ""); - if ((size_t)check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE -size_t(buffer_ptr - buffer) or check_length < 0) - { - return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, - memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); - } - write_length+= (size_t)check_length; - WATCHPOINT_ASSERT(write_length < MEMCACHED_DEFAULT_COMMAND_SIZE); + char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1]; + int expiration_buffer_length= snprintf(expiration_buffer, sizeof(expiration_buffer), " %llu", (unsigned long long)expiration); + if (size_t(expiration_buffer_length) >= sizeof(expiration_buffer) or expiration_buffer_length < 0) + { + return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, + memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)")); } - if (ptr->flags.use_udp) + char value_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1]; + int value_buffer_length= snprintf(value_buffer, sizeof(value_buffer), " %llu", (unsigned long long)value_length); + if (size_t(value_buffer_length) >= sizeof(value_buffer) or value_buffer_length < 0) { - size_t cmd_size= write_length + value_length +2; - if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH) - { - return memcached_set_error(*ptr, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); - } - - if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH) - { - memcached_io_write(instance, NULL, 0, true); - } + return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, + memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)")); } - if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE) + char cas_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1]; + int cas_buffer_length= 0; + if (cas) { - return memcached_set_error(*ptr, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); + cas_buffer_length= snprintf(cas_buffer, sizeof(cas_buffer), " %llu", (unsigned long long)cas); + if (size_t(cas_buffer_length) >= sizeof(cas_buffer) or cas_buffer_length < 0) + { + return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, + memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)")); + } } - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { - { buffer, write_length }, + { NULL, 0 }, + { storage_op_string(verb), strlen(storage_op_string(verb))}, + { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) }, + { key, key_length }, + { flags_buffer, flags_buffer_length }, + { expiration_buffer, expiration_buffer_length }, + { value_buffer, value_buffer_length }, + { cas_buffer, cas_buffer_length }, + { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") }, + { memcached_literal_param("\r\n") }, { value, value_length }, { memcached_literal_param("\r\n") } }; - if (memcached_is_udp(instance->root) and (write_length +value_length +memcached_literal_param_size("\r\n") +UDP_DATAGRAM_HEADER_LENGTH > MAX_UDP_DATAGRAM_LENGTH)) + /* Send command header */ + memcached_return_t rc= memcached_vdo(instance, vector, 12, flush); + + // If we should not reply, return with MEMCACHED_SUCCESS, unless error + if (reply == false) { - return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT, memcached_literal_param("UDP packet is too large")); + return memcached_success(rc) ? MEMCACHED_SUCCESS : rc; + } + + if (flush == false) + { + return memcached_success(rc) ? MEMCACHED_BUFFERED : rc; } - /* Send command header */ - memcached_return_t rc= memcached_vdo(instance, vector, 3, flush); if (rc == MEMCACHED_SUCCESS) { - if (ptr->flags.no_reply and flush) - { - rc= MEMCACHED_SUCCESS; - } - else if (flush == false) - { - rc= MEMCACHED_BUFFERED; - } - else - { - rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + rc= memcached_response(instance, buffer, sizeof(buffer), NULL); - if (rc == MEMCACHED_STORED) - { - rc= MEMCACHED_SUCCESS; - } + if (rc == MEMCACHED_STORED) + { + return MEMCACHED_SUCCESS; } } @@ -335,9 +318,10 @@ static memcached_return_t memcached_send_ascii(memcached_st *ptr, memcached_io_reset(instance); } - if (memcached_failed(rc) and ptr->error_messages == NULL) + assert(memcached_failed(rc)); + if (memcached_has_error(ptr) == false) { - memcached_set_error(*ptr, rc, MEMCACHED_AT); + return memcached_set_error(*ptr, rc, MEMCACHED_AT); } return rc; @@ -347,18 +331,18 @@ static inline memcached_return_t memcached_send(memcached_st *ptr, const char *group_key, size_t group_key_length, const char *key, size_t key_length, const char *value, size_t value_length, - time_t expiration, - uint32_t flags, - uint64_t cas, + const time_t expiration, + const uint32_t flags, + const uint64_t cas, memcached_storage_action_t verb) { memcached_return_t rc; - if (memcached_failed(rc= initialize_query(ptr))) + if (memcached_failed(rc= initialize_query(ptr, true))) { return rc; } - if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + if (memcached_failed(rc= memcached_validate_key_length(key_length, memcached_is_binary(ptr)))) { return rc; } @@ -374,23 +358,27 @@ static inline memcached_return_t memcached_send(memcached_st *ptr, WATCHPOINT_SET(instance->io_wait_count.read= 0); WATCHPOINT_SET(instance->io_wait_count.write= 0); - bool flush= (bool) ((instance->root->flags.buffer_requests && verb == SET_OP) ? 0 : 1); - if (ptr->flags.binary_protocol) + + bool flush= true; + if (memcached_is_buffering(instance->root) and verb == SET_OP) { - rc= memcached_send_binary(ptr, instance, server_key, - key, key_length, - value, value_length, expiration, - flags, cas, flush, verb); + flush= false; } - else + + bool reply= memcached_is_replying(ptr); + + if (memcached_is_binary(ptr)) { - rc= memcached_send_ascii(ptr, instance, - key, key_length, - value, value_length, expiration, - flags, cas, flush, verb); + return memcached_send_binary(ptr, instance, server_key, + key, key_length, + value, value_length, expiration, + flags, cas, flush, reply, verb); } - return rc; + return memcached_send_ascii(ptr, instance, + key, key_length, + value, value_length, expiration, + flags, cas, flush, reply, verb); } @@ -419,6 +407,11 @@ memcached_return_t memcached_add(memcached_st *ptr, rc= memcached_send(ptr, key, key_length, key, key_length, value, value_length, expiration, flags, 0, ADD_OP); + + if (rc == MEMCACHED_NOTSTORED or rc == MEMCACHED_DATA_EXISTS) + { + memcached_set_error(*ptr, rc, MEMCACHED_AT); + } LIBMEMCACHED_MEMCACHED_ADD_END(); return rc; } @@ -534,11 +527,9 @@ memcached_return_t memcached_prepend_by_key(memcached_st *ptr, time_t expiration, uint32_t flags) { - memcached_return_t rc; - rc= memcached_send(ptr, group_key, group_key_length, - key, key_length, value, value_length, - expiration, flags, 0, PREPEND_OP); - return rc; + return memcached_send(ptr, group_key, group_key_length, + key, key_length, value, value_length, + expiration, flags, 0, PREPEND_OP); } memcached_return_t memcached_append_by_key(memcached_st *ptr, @@ -548,11 +539,9 @@ memcached_return_t memcached_append_by_key(memcached_st *ptr, time_t expiration, uint32_t flags) { - memcached_return_t rc; - rc= memcached_send(ptr, group_key, group_key_length, - key, key_length, value, value_length, - expiration, flags, 0, APPEND_OP); - return rc; + return memcached_send(ptr, group_key, group_key_length, + key, key_length, value, value_length, + expiration, flags, 0, APPEND_OP); } memcached_return_t memcached_cas_by_key(memcached_st *ptr, @@ -563,10 +552,8 @@ memcached_return_t memcached_cas_by_key(memcached_st *ptr, uint32_t flags, uint64_t cas) { - memcached_return_t rc; - rc= memcached_send(ptr, group_key, group_key_length, - key, key_length, value, value_length, - expiration, flags, cas, CAS_OP); - return rc; + return memcached_send(ptr, group_key, group_key_length, + key, key_length, value, value_length, + expiration, flags, cas, CAS_OP); } diff --git a/libmemcached/touch.cc b/libmemcached/touch.cc index 1107139d..8505d7e6 100644 --- a/libmemcached/touch.cc +++ b/libmemcached/touch.cc @@ -42,20 +42,26 @@ static memcached_return_t ascii_touch(memcached_server_write_instance_st instanc const char *key, size_t key_length, time_t expiration) { - char buffer[21]; + char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1]; + int expiration_buffer_length= snprintf(expiration_buffer, sizeof(expiration_buffer), " %llu", (unsigned long long)expiration); + if (size_t(expiration_buffer_length) >= sizeof(expiration_buffer) or expiration_buffer_length < 0) + { + return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, + memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)")); + } - int buffer_length= snprintf(buffer, sizeof(buffer), " %u", uint32_t(expiration)); - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { + { NULL, 0 }, { memcached_literal_param("touch ") }, { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) }, { key, key_length }, - { buffer, buffer_length }, + { expiration_buffer, expiration_buffer_length }, { memcached_literal_param("\r\n") } }; memcached_return_t rc; - if (memcached_failed(rc= memcached_vdo(instance, vector, 5, true))) + if (memcached_failed(rc= memcached_vdo(instance, vector, 6, true))) { memcached_io_reset(instance); return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); @@ -77,15 +83,16 @@ static memcached_return_t binary_touch(memcached_server_write_instance_st instan request.message.header.request.bodylen= htonl((uint32_t)(key_length +memcached_array_size(instance->root->_namespace) +request.message.header.request.extlen)); request.message.body.expiration= htonl((uint32_t) expiration); - struct libmemcached_io_vector_st vector[]= + libmemcached_io_vector_st vector[]= { + { NULL, 0 }, { request.bytes, sizeof(request.bytes) }, { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) }, { key, key_length } }; memcached_return_t rc; - if (memcached_failed(rc= memcached_vdo(instance, vector, 3, true))) + if (memcached_failed(rc= memcached_vdo(instance, vector, 4, true))) { memcached_io_reset(instance); return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); @@ -109,7 +116,7 @@ memcached_return_t memcached_touch_by_key(memcached_st *ptr, LIBMEMCACHED_MEMCACHED_TOUCH_START(); memcached_return_t rc; - if (memcached_failed(rc= initialize_query(ptr))) + if (memcached_failed(rc= initialize_query(ptr, true))) { return rc; } @@ -137,7 +144,7 @@ memcached_return_t memcached_touch_by_key(memcached_st *ptr, } char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - rc= memcached_read_one_response(instance, buffer, sizeof(buffer), NULL); + rc= memcached_response(instance, buffer, sizeof(buffer), NULL); if (rc == MEMCACHED_SUCCESS or rc == MEMCACHED_NOTFOUND) { diff --git a/libmemcached/udp.cc b/libmemcached/udp.cc new file mode 100644 index 00000000..905eedd7 --- /dev/null +++ b/libmemcached/udp.cc @@ -0,0 +1,77 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * LibMemcached + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +/* + * The udp request id consists of two seperate sections + * 1) The thread id + * 2) The message number + * The thread id should only be set when the memcached_st struct is created + * and should not be changed. + * + * The message num is incremented for each new message we send, this function + * extracts the message number from message_id, increments it and then + * writes the new value back into the header + */ +void increment_udp_message_id(memcached_server_write_instance_st ptr) +{ + struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer; + uint16_t cur_req= get_udp_datagram_request_id(header); + int msg_num= get_msg_num_from_request_id(cur_req); + int thread_id= get_thread_id_from_request_id(cur_req); + + if (((++msg_num) & UDP_REQUEST_ID_THREAD_MASK) != 0) + msg_num= 0; + + header->request_id= htons((uint16_t) (thread_id | msg_num)); +} + +bool memcached_io_init_udp_header(memcached_server_write_instance_st ptr, const uint16_t thread_id) +{ + if (thread_id > UDP_REQUEST_ID_MAX_THREAD_ID) + { + return MEMCACHED_FAILURE; + } + + struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer; + header->request_id= htons(uint16_t((generate_udp_request_thread_id(thread_id)))); + header->num_datagrams= htons(1); + header->sequence_number= htons(0); + + return MEMCACHED_SUCCESS; +} diff --git a/libmemcached/udp.hpp b/libmemcached/udp.hpp new file mode 100644 index 00000000..9cc53889 --- /dev/null +++ b/libmemcached/udp.hpp @@ -0,0 +1,59 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * LibMemcached + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define MAX_UDP_DATAGRAM_LENGTH 1400 +#define UDP_DATAGRAM_HEADER_LENGTH 8 +#define UDP_REQUEST_ID_MSG_SIG_DIGITS 10 +#define UDP_REQUEST_ID_THREAD_MASK 0xFFFF << UDP_REQUEST_ID_MSG_SIG_DIGITS +#define get_udp_datagram_request_id(A) ntohs((A)->request_id) +#define get_udp_datagram_seq_num(A) ntohs((A)->sequence_number) +#define get_udp_datagram_num_datagrams(A) ntohs((A)->num_datagrams) +#define get_msg_num_from_request_id(A) ( (A) & (~(UDP_REQUEST_ID_THREAD_MASK)) ) +#define get_thread_id_from_request_id(A) ( (A) & (UDP_REQUEST_ID_THREAD_MASK) ) >> UDP_REQUEST_ID_MSG_SIG_DIGITS +#define generate_udp_request_thread_id(A) (A) << UDP_REQUEST_ID_MSG_SIG_DIGITS +#define UDP_REQUEST_ID_MAX_THREAD_ID get_thread_id_from_request_id(0xFFFF) + +struct udp_datagram_header_st +{ + uint16_t request_id; + uint16_t sequence_number; + uint16_t num_datagrams; + uint16_t reserved; +}; + +bool memcached_io_init_udp_header(memcached_server_write_instance_st ptr, const uint16_t thread_id); +void increment_udp_message_id(memcached_server_write_instance_st ptr); diff --git a/libmemcached/verbosity.cc b/libmemcached/verbosity.cc index 5564c7a9..334a3316 100644 --- a/libmemcached/verbosity.cc +++ b/libmemcached/verbosity.cc @@ -47,7 +47,7 @@ static memcached_return_t _set_verbosity(const memcached_st *, const memcached_server_st *server, void *context) { - struct context_st *execute= (struct context_st *)context; + libmemcached_io_vector_st *vector= (libmemcached_io_vector_st *)context; memcached_st local_memc; memcached_st *memc_ptr= memcached_create(&local_memc); @@ -56,16 +56,15 @@ static memcached_return_t _set_verbosity(const memcached_st *, if (rc == MEMCACHED_SUCCESS) { - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - memcached_server_write_instance_st instance= memcached_server_instance_fetch(memc_ptr, 0); - rc= memcached_do(instance, execute->buffer, execute->length, true); + rc= memcached_vdo(instance, vector, 4, true); if (rc == MEMCACHED_SUCCESS) { - rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + rc= memcached_response(instance, buffer, sizeof(buffer), NULL); } } @@ -76,22 +75,32 @@ static memcached_return_t _set_verbosity(const memcached_st *, memcached_return_t memcached_verbosity(memcached_st *ptr, uint32_t verbosity) { - int send_length; + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr, false))) + { + return rc; + } + memcached_server_fn callbacks[1]; char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, - "verbosity %u\r\n", verbosity); - if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0) + int send_length= snprintf(buffer, sizeof(buffer), "%u", verbosity); + if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE or send_length < 0) { return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)")); } - struct context_st context = { (size_t)send_length, buffer }; + libmemcached_io_vector_st vector[]= + { + { NULL, 0 }, + { memcached_literal_param("verbosity ") }, + { buffer, send_length }, + { memcached_literal_param("\r\n") } + }; callbacks[0]= _set_verbosity; - return memcached_server_cursor(ptr, callbacks, &context, 1); + return memcached_server_cursor(ptr, callbacks, vector, 1); } diff --git a/libmemcached/version.cc b/libmemcached/version.cc index b70cf672..b889bf4f 100644 --- a/libmemcached/version.cc +++ b/libmemcached/version.cc @@ -41,37 +41,14 @@ const char * memcached_lib_version(void) return LIBMEMCACHED_VERSION_STRING; } -static inline memcached_return_t memcached_version_binary(memcached_st *ptr); -static inline memcached_return_t memcached_version_textual(memcached_st *ptr); - -memcached_return_t memcached_version(memcached_st *ptr) -{ - memcached_return_t rc; - if (memcached_failed(rc= initialize_query(ptr))) - { - return rc; - } - - if (ptr->flags.use_udp) - { - return MEMCACHED_NOT_SUPPORTED; - } - - if (ptr->flags.binary_protocol) - { - rc= memcached_version_binary(ptr); - } - else - { - rc= memcached_version_textual(ptr); - } - - return rc; -} - static inline memcached_return_t memcached_version_textual(memcached_st *ptr) { + libmemcached_io_vector_st vector[]= + { + { memcached_literal_param("version\r\n") }, + }; memcached_return_t rc= MEMCACHED_SUCCESS; + for (uint32_t x= 0; x < memcached_server_count(ptr); x++) { memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); @@ -82,7 +59,7 @@ static inline memcached_return_t memcached_version_textual(memcached_st *ptr) continue; } - memcached_return_t rrc= memcached_do(instance, memcached_literal_param("version\r\n"), true); + memcached_return_t rrc= memcached_vdo(instance, vector, 1, true); if (memcached_failed(rrc)) { (void)memcached_set_error(*instance, rrc, MEMCACHED_AT); @@ -92,7 +69,7 @@ static inline memcached_return_t memcached_version_textual(memcached_st *ptr) } char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); + rrc= memcached_response(instance, buffer, sizeof(buffer), NULL); if (memcached_failed(rrc)) { memcached_set_error(*instance, rrc, MEMCACHED_AT); @@ -152,6 +129,11 @@ static inline memcached_return_t memcached_version_binary(memcached_st *ptr) request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION; request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + libmemcached_io_vector_st vector[]= + { + { request.bytes, sizeof(request.bytes) } + }; + memcached_return_t rc= MEMCACHED_SUCCESS; for (uint32_t x= 0; x < memcached_server_count(ptr); x++) { @@ -162,7 +144,7 @@ static inline memcached_return_t memcached_version_binary(memcached_st *ptr) continue; } - memcached_return_t rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true); + memcached_return_t rrc= memcached_vdo(instance, vector, 1, true); if (memcached_failed(rrc)) { memcached_io_reset(instance); @@ -173,8 +155,7 @@ static inline memcached_return_t memcached_version_binary(memcached_st *ptr) for (uint32_t x= 0; x < memcached_server_count(ptr); x++) { - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); if (instance->major_version != UINT8_MAX) { @@ -228,3 +209,28 @@ static inline memcached_return_t memcached_version_binary(memcached_st *ptr) return rc; } + +memcached_return_t memcached_version(memcached_st *ptr) +{ + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr, true))) + { + return rc; + } + + if (memcached_is_udp(ptr)) + { + return MEMCACHED_NOT_SUPPORTED; + } + + if (memcached_is_binary(ptr)) + { + rc= memcached_version_binary(ptr); + } + else + { + rc= memcached_version_textual(ptr); + } + + return rc; +} diff --git a/libmemcachedutil/pid.cc b/libmemcachedutil/pid.cc index 7ff665b6..99f378d1 100644 --- a/libmemcachedutil/pid.cc +++ b/libmemcachedutil/pid.cc @@ -48,11 +48,13 @@ pid_t libmemcached_util_getpid(const char *hostname, in_port_t port, memcached_r pid_t pid= -1; memcached_return_t unused; - if (not ret) + if (ret == NULL) + { ret= &unused; + } memcached_st *memc_ptr= memcached_create(NULL); - if (not memc_ptr) + if (memc_ptr == NULL) { *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE; return -1; @@ -72,8 +74,7 @@ pid_t libmemcached_util_getpid(const char *hostname, in_port_t port, memcached_r } else if (rc == MEMCACHED_SOME_ERRORS) // Generic answer, we will now find the specific reason (if one exists) { - memcached_server_instance_st instance= - memcached_server_instance_by_position(memc_ptr, 0); + memcached_server_instance_st instance= memcached_server_instance_by_position(memc_ptr, 0); assert_msg(instance and instance->error_messages, " "); if (instance and instance->error_messages) diff --git a/libtest/run.gdb b/libtest/run.gdb index a520ae87..320407a2 100644 --- a/libtest/run.gdb +++ b/libtest/run.gdb @@ -1,3 +1,2 @@ set environment LIBTEST_IN_GDB=1 run -quit diff --git a/m4/ax_cxx_gcc_abi_demangle.m4 b/m4/ax_cxx_gcc_abi_demangle.m4 new file mode 100644 index 00000000..11e8728c --- /dev/null +++ b/m4/ax_cxx_gcc_abi_demangle.m4 @@ -0,0 +1,58 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cxx_gcc_abi_demangle.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_GCC_ABI_DEMANGLE +# +# DESCRIPTION +# +# If the compiler supports GCC C++ ABI name demangling (has header +# cxxabi.h and abi::__cxa_demangle() function), define +# HAVE_GCC_ABI_DEMANGLE +# +# Adapted from AX_CXX_RTTI by Luc Maisonobe +# +# LICENSE +# +# Copyright (c) 2008 Neil Ferguson +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 9 + +AC_DEFUN([AX_CXX_GCC_ABI_DEMANGLE], +[AC_CACHE_CHECK(whether the compiler supports GCC C++ ABI name demangling, +ax_cv_cxx_gcc_abi_demangle, +[AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([#include +#include +#include +#include + +template +class A {}; +],[A instance; +int status = 0; +char* c_name = 0; + +c_name = abi::__cxa_demangle(typeid(instance).name(), 0, 0, &status); + +std::string name(c_name); +::free(c_name); + +return name == "A"; +], + ax_cv_cxx_gcc_abi_demangle=yes, ax_cv_cxx_gcc_abi_demangle=no) + AC_LANG_RESTORE +]) +if test "$ax_cv_cxx_gcc_abi_demangle" = yes; then + AC_DEFINE(HAVE_GCC_ABI_DEMANGLE,1, + [define if the compiler supports GCC C++ ABI name demangling]) +fi +]) diff --git a/tests/include.am b/tests/include.am index 35b0a913..23f0f899 100644 --- a/tests/include.am +++ b/tests/include.am @@ -202,8 +202,8 @@ valgrind-memstat: clients/memstat @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server" @rm tests/Xumemc.pid -test-mem: tests/var tests/testapp - @tests/testapp +test-mem: tests/var tests/libmemcached-1.0/testapp + @tests/libmemcached-1.0/testapp test-sasl: tests/sasl @tests/sasl @@ -229,8 +229,8 @@ test-memcapable: tests/var tests/memcapable pahole-mem: tests/testapp @$(PAHOLE_COMMAND) tests/testapp -gdb-mem: tests/testapp - @$(DEBUG_COMMAND) tests/testapp +gdb-mem: tests/var tests/libmemcached-1.0/testapp + @$(DEBUG_COMMAND) tests/libmemcached-1.0/testapp gdb-sasl: tests/sasl @$(DEBUG_COMMAND) tests/sasl @@ -238,9 +238,6 @@ gdb-sasl: tests/sasl gdb-atom: tests/atomsmasher @$(DEBUG_COMMAND) tests/atomsmasher -gdb-udp: tests/testudp - @$(DEBUG_COMMAND) tests/testudp - gdb-plus: tests/testplus $(DEBUG_COMMAND) tests/testplus @@ -268,9 +265,6 @@ valgrind-failure: tests/failure valgrind-atom: tests/atomsmasher $(VALGRIND_COMMAND) tests/atomsmasher -valgrind-udp: tests/testudp - $(VALGRIND_COMMAND) tests/testudp - valgrind-plus: tests/testplus @$(VALGRIND_COMMAND) tests/testplus @@ -292,9 +286,6 @@ helgrind-mem: tests/testapp helgrind-atom: tests/atomsmasher @$(HELGRIND_COMMAND) tests/atomsmasher -helgrind-udp: tests/testudp - @$(HELGRIND_COMMAND) tests/testudp - helgrind-plus: tests/testplus @$(HELGRIND_COMMAND) tests/testplus diff --git a/tests/libmemcached-1.0/include.am b/tests/libmemcached-1.0/include.am index 29c02b32..81653a1c 100644 --- a/tests/libmemcached-1.0/include.am +++ b/tests/libmemcached-1.0/include.am @@ -123,6 +123,9 @@ tests_testudp_LDADD= $(tests_testudp_DEPENDENCIES) check_PROGRAMS+= tests/testudp noinst_PROGRAMS+= tests/testudp +test-udp: tests/testudp + @tests/testudp + tests_testplus_SOURCES= tests/libmemcached-1.0/plus.cpp tests_testplus_CXXFLAGS = $(AM_CXXFLAGS) $(NO_EFF_CXX) tests_testplus_DEPENDENCIES= $(TESTS_LDADDS) diff --git a/tests/libmemcached-1.0/mem_functions.cc b/tests/libmemcached-1.0/mem_functions.cc index 29009ce3..dd2abef2 100644 --- a/tests/libmemcached-1.0/mem_functions.cc +++ b/tests/libmemcached-1.0/mem_functions.cc @@ -95,7 +95,7 @@ using namespace libtest; #define GLOBAL_COUNT 10000 #define GLOBAL2_COUNT 100 #define SERVERS_TO_CREATE 5 -static uint32_t global_count; +static uint32_t global_count= GLOBAL2_COUNT; static pairs_st *global_pairs; static const char *global_keys[GLOBAL_COUNT]; @@ -112,6 +112,16 @@ static test_return_t pre_binary(memcached_st *memc) return TEST_SUCCESS; } +static memcached_return_t return_value_based_on_buffering(memcached_st *memc) +{ + if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS)) + { + return MEMCACHED_BUFFERED; + } + + return MEMCACHED_SUCCESS; +} + static memcached_st * create_single_instance_memcached(const memcached_st *original_memc, const char *options) { /* @@ -384,7 +394,7 @@ static test_return_t clone_test(memcached_st *memc) test_true(memc_clone->ketama.weighted == memc->ketama.weighted); test_true(memc_clone->flags.binary_protocol == memc->flags.binary_protocol); test_true(memc_clone->flags.hash_with_namespace == memc->flags.hash_with_namespace); - test_true(memc_clone->flags.no_reply == memc->flags.no_reply); + test_true(memc_clone->flags.reply == memc->flags.reply); test_true(memc_clone->flags.use_udp == memc->flags.use_udp); test_true(memc_clone->flags.auto_eject_hosts == memc->flags.auto_eject_hosts); test_true(memc_clone->flags.randomize_replica_read == memc->flags.randomize_replica_read); @@ -512,7 +522,7 @@ static test_return_t set_test(memcached_st *memc) test_literal_param("foo"), test_literal_param("when we sanitize"), time_t(0), (uint32_t)0); - test_true_got(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED, memcached_strerror(NULL, rc)); + test_true_got(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED, memcached_strerror(NULL, rc)); return TEST_SUCCESS; } @@ -520,32 +530,34 @@ static test_return_t set_test(memcached_st *memc) static test_return_t append_test(memcached_st *memc) { memcached_return_t rc; - const char *key= "fig"; const char *in_value= "we"; - char *out_value= NULL; size_t value_length; uint32_t flags; - rc= memcached_flush(memc, 0); - test_compare(MEMCACHED_SUCCESS, rc); - - rc= memcached_set(memc, key, strlen(key), - in_value, strlen(in_value), - (time_t)0, (uint32_t)0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_flush(memc, 0)); - rc= memcached_append(memc, key, strlen(key), - " the", strlen(" the"), - (time_t)0, (uint32_t)0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, + test_literal_param(__func__), + in_value, strlen(in_value), + time_t(0), uint32_t(0))); - rc= memcached_append(memc, key, strlen(key), - " people", strlen(" people"), - (time_t)0, (uint32_t)0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_append(memc, + test_literal_param(__func__), + " the", strlen(" the"), + time_t(0), uint32_t(0))); - out_value= memcached_get(memc, key, strlen(key), - &value_length, &flags, &rc); + test_compare(MEMCACHED_SUCCESS, + memcached_append(memc, + test_literal_param(__func__), + " people", strlen(" people"), + time_t(0), uint32_t(0))); + + char *out_value= memcached_get(memc, + test_literal_param(__func__), + &value_length, &flags, &rc); test_memcmp(out_value, "we the people", strlen("we the people")); test_compare(strlen("we the people"), value_length); test_compare(MEMCACHED_SUCCESS, rc); @@ -556,40 +568,40 @@ static test_return_t append_test(memcached_st *memc) static test_return_t append_binary_test(memcached_st *memc) { - memcached_return_t rc; - const char *key= "numbers"; uint32_t store_list[] = { 23, 56, 499, 98, 32847, 0 }; - uint32_t *value; - size_t value_length; - uint32_t flags; - uint32_t x; - rc= memcached_flush(memc, 0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_flush(memc, 0)); - rc= memcached_set(memc, - key, strlen(key), - NULL, 0, - (time_t)0, (uint32_t)0); - test_compare_got(MEMCACHED_SUCCESS, rc, memcached_strerror(NULL, rc)); + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, + test_literal_param(__func__), + NULL, 0, + time_t(0), uint32_t(0))); - for (x= 0; store_list[x] ; x++) + size_t count= 0; + for (uint32_t x= 0; store_list[x] ; x++) { - rc= memcached_append(memc, - key, strlen(key), + test_compare(MEMCACHED_SUCCESS, + memcached_append(memc, + test_literal_param(__func__), (char *)&store_list[x], sizeof(uint32_t), - (time_t)0, (uint32_t)0); - test_compare(MEMCACHED_SUCCESS, rc); + time_t(0), uint32_t(0))); + count++; } - value= (uint32_t *)memcached_get(memc, key, strlen(key), - &value_length, &flags, &rc); - test_compare(value_length, sizeof(uint32_t) * x); + size_t value_length; + uint32_t flags; + memcached_return_t rc; + uint32_t *value= (uint32_t *)memcached_get(memc, + test_literal_param(__func__), + &value_length, &flags, &rc); + test_compare(value_length, sizeof(uint32_t) * count); test_compare(MEMCACHED_SUCCESS, rc); - for (uint32_t counter= x, *ptr= value; counter; counter--) + for (uint32_t counter= count, *ptr= value; counter; counter--) { - test_compare(*ptr, store_list[x - counter]); + test_compare(*ptr, store_list[count - counter]); ptr++; } free(value); @@ -599,34 +611,31 @@ static test_return_t append_binary_test(memcached_st *memc) static test_return_t cas2_test(memcached_st *memc) { - memcached_return_t rc; const char *keys[]= {"fudge", "son", "food"}; size_t key_length[]= {5, 3, 4}; const char *value= "we the people"; size_t value_length= strlen("we the people"); - memcached_result_st results_obj; - memcached_result_st *results; - unsigned int set= 1; test_compare(MEMCACHED_SUCCESS, memcached_flush(memc, 0)); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, set); + test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, true)); for (uint32_t x= 0; x < 3; x++) { - rc= memcached_set(memc, keys[x], key_length[x], - keys[x], key_length[x], - (time_t)50, (uint32_t)9); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, keys[x], key_length[x], + keys[x], key_length[x], + time_t(50), uint32_t(9))); } test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, key_length, 3)); - results= memcached_result_create(memc, &results_obj); + memcached_result_st *results= memcached_result_create(memc, NULL); test_true(results); - results= memcached_fetch_result(memc, &results_obj, &rc); + memcached_return_t rc; + results= memcached_fetch_result(memc, results, &rc); test_true(results); test_true(results->item_cas); test_compare(MEMCACHED_SUCCESS, rc); @@ -636,51 +645,44 @@ static test_return_t cas2_test(memcached_st *memc) test_compare(strlen("we the people"), value_length); test_compare(MEMCACHED_SUCCESS, rc); - memcached_result_free(&results_obj); + memcached_result_free(results); return TEST_SUCCESS; } static test_return_t cas_test(memcached_st *memc) { - memcached_return_t rc; - const char *key= "fun"; - size_t key_length= strlen(key); - const char *value= "we the people"; - const char* keys[2] = { key, NULL }; - size_t keylengths[2] = { strlen(key), 0 }; - size_t value_length= strlen(value); - const char *value2= "change the value"; - size_t value2_length= strlen(value2); + const char* keys[2] = { __func__, NULL }; + size_t keylengths[2] = { strlen(__func__), 0 }; memcached_result_st results_obj; - memcached_result_st *results; - unsigned int set= 1; - rc= memcached_flush(memc, 0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, memcached_flush(memc, 0)); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, set); + test_skip(true, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, true)); - rc= memcached_set(memc, key, strlen(key), - value, strlen(value), - (time_t)0, (uint32_t)0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, + test_literal_param(__func__), + test_literal_param("we the people"), + (time_t)0, (uint32_t)0)); test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, keylengths, 1)); - results= memcached_result_create(memc, &results_obj); + memcached_result_st *results= memcached_result_create(memc, &results_obj); test_true(results); + memcached_return_t rc; results= memcached_fetch_result(memc, &results_obj, &rc); test_true(results); test_compare(MEMCACHED_SUCCESS, rc); test_true(memcached_result_cas(results)); - test_memcmp(value, memcached_result_value(results), value_length); - test_compare(strlen(memcached_result_value(results)), value_length); - test_compare(MEMCACHED_SUCCESS, rc); - uint64_t cas = memcached_result_cas(results); + test_memcmp("we the people", memcached_result_value(results), test_literal_param_size("we the people")); + test_compare(test_literal_param_size("we the people"), + strlen(memcached_result_value(results))); + + uint64_t cas= memcached_result_cas(results); #if 0 results= memcached_fetch_result(memc, &results_obj, &rc); @@ -688,15 +690,21 @@ static test_return_t cas_test(memcached_st *memc) test_true(results == NULL); #endif - rc= memcached_cas(memc, key, key_length, value2, value2_length, 0, 0, cas); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_cas(memc, + test_literal_param(__func__), + test_literal_param("change the value"), + 0, 0, cas)); /* * 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); - test_compare(MEMCACHED_DATA_EXISTS, rc); + test_compare(MEMCACHED_DATA_EXISTS, + memcached_cas(memc, + test_literal_param(__func__), + test_literal_param("change the value"), + 0, 0, cas)); memcached_result_free(&results_obj); @@ -705,32 +713,31 @@ static test_return_t cas_test(memcached_st *memc) static test_return_t prepend_test(memcached_st *memc) { - memcached_return_t rc; const char *key= "fig"; const char *value= "people"; - char *out_value= NULL; - size_t value_length; - uint32_t flags; - rc= memcached_flush(memc, 0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_flush(memc, 0)); - rc= memcached_set(memc, key, strlen(key), - value, strlen(value), - (time_t)0, (uint32_t)0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, key, strlen(key), + value, strlen(value), + time_t(0), uint32_t(0))); - rc= memcached_prepend(memc, key, strlen(key), - "the ", strlen("the "), - (time_t)0, (uint32_t)0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_prepend(memc, key, strlen(key), + "the ", strlen("the "), + time_t(0), uint32_t(0))); - rc= memcached_prepend(memc, key, strlen(key), - "we ", strlen("we "), - (time_t)0, (uint32_t)0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_prepend(memc, key, strlen(key), + "we ", strlen("we "), + time_t(0), uint32_t(0))); - out_value= memcached_get(memc, key, strlen(key), + size_t value_length; + uint32_t flags; + memcached_return_t rc; + char *out_value= memcached_get(memc, key, strlen(key), &value_length, &flags, &rc); test_memcmp(out_value, "we the people", strlen("we the people")); test_compare(strlen("we the people"), value_length); @@ -746,31 +753,21 @@ static test_return_t prepend_test(memcached_st *memc) */ static test_return_t add_test(memcached_st *memc) { - memcached_return_t rc; - const char *key= "foo"; - const char *value= "when we sanitize"; - unsigned long long setting_value; - - setting_value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK); + test_compare_hint(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param(__func__), + test_literal_param("when we sanitize"), + time_t(0), uint32_t(0)), + memcached_last_error_message(memc)); - rc= memcached_set(memc, key, strlen(key), - value, strlen(value), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); memcached_quit(memc); - rc= memcached_add(memc, key, strlen(key), - value, strlen(value), - (time_t)0, (uint32_t)0); - /* Too many broken OS'es have broken loopback in async, so we can't be sure of the result */ - if (setting_value) - { - test_true(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_STORED); - } - else - { - test_true(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_DATA_EXISTS); - } + test_compare_hint(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) ? MEMCACHED_DATA_EXISTS : MEMCACHED_NOTSTORED, + memcached_add(memc, + test_literal_param(__func__), + test_literal_param("try something else"), + time_t(0), uint32_t(0)), + memcached_last_error_message(memc)); return TEST_SUCCESS; } @@ -800,37 +797,34 @@ static test_return_t add_wrapper(memcached_st *memc) static test_return_t replace_test(memcached_st *memc) { - memcached_return_t rc; - const char *key= "foo"; - const char *value= "when we sanitize"; - const char *original= "first we insert some data"; - - rc= memcached_set(memc, key, strlen(key), - original, strlen(original), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param(__func__), + test_literal_param("when we sanitize"), + time_t(0), uint32_t(0))); test_compare(MEMCACHED_SUCCESS, - memcached_replace(memc, key, strlen(key), - value, strlen(value), - (time_t)0, (uint32_t)0)); + memcached_replace(memc, + test_literal_param(__func__), + test_literal_param("first we insert some data"), + time_t(0), uint32_t(0))); return TEST_SUCCESS; } static test_return_t delete_test(memcached_st *memc) { - memcached_return_t rc; - const char *key= "foo"; - const char *value= "when we sanitize"; - - rc= memcached_set(memc, key, strlen(key), - value, strlen(value), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param(__func__), + test_literal_param("when we sanitize"), + time_t(0), uint32_t(0))); - rc= memcached_delete(memc, key, strlen(key), (time_t)0); - test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + test_compare_hint(return_value_based_on_buffering(memc), + memcached_delete(memc, + test_literal_param(__func__), + time_t(0)), + memcached_last_error_message(memc)); return TEST_SUCCESS; } @@ -845,13 +839,11 @@ static test_return_t flush_test(memcached_st *memc) return TEST_SUCCESS; } -static memcached_return_t server_function(const memcached_st *ptr, - const memcached_server_st *server, - void *context) +static memcached_return_t server_function(const memcached_st *, + const memcached_server_st *, + void *) { - (void)ptr; (void)server; (void)context; /* Do Nothing */ - return MEMCACHED_SUCCESS; } @@ -871,7 +863,6 @@ static test_return_t bad_key_test(memcached_st *memc) memcached_return_t rc; const char *key= "foo bad"; uint32_t flags; - memcached_st *memc_clone; uint64_t query_id= memcached_query_id(memc); @@ -880,7 +871,7 @@ static test_return_t bad_key_test(memcached_st *memc) test_compare(query_id, memcached_query_id(memc)); // We should not increase the query_id for memcached_behavior_get() - memc_clone= memcached_clone(NULL, memc); + memcached_st *memc_clone= memcached_clone(NULL, memc); test_true(memc_clone); query_id= memcached_query_id(memc_clone); @@ -993,24 +984,24 @@ static memcached_return_t read_through_trigger(memcached_st *memc, static test_return_t read_through(memcached_st *memc) { - memcached_return_t rc; - const char *key= "foo"; - char *string; - size_t string_length; - uint32_t flags; memcached_trigger_key_fn cb= (memcached_trigger_key_fn)read_through_trigger; - string= memcached_get(memc, key, strlen(key), - &string_length, &flags, &rc); + size_t string_length; + uint32_t flags; + memcached_return_t rc; + char *string= memcached_get(memc, + test_literal_param(__func__), + &string_length, &flags, &rc); test_compare(MEMCACHED_NOTFOUND, rc); test_false(string_length); test_false(string); - rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_GET_FAILURE, *(void **)&cb); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_callback_set(memc, MEMCACHED_CALLBACK_GET_FAILURE, *(void **)&cb)); - string= memcached_get(memc, key, strlen(key), + string= memcached_get(memc, + test_literal_param(__func__), &string_length, &flags, &rc); test_compare(MEMCACHED_SUCCESS, rc); @@ -1019,7 +1010,8 @@ static test_return_t read_through(memcached_st *memc) test_strcmp(READ_THROUGH_VALUE, string); free(string); - string= memcached_get(memc, key, strlen(key), + string= memcached_get(memc, + test_literal_param(__func__), &string_length, &flags, &rc); test_compare(MEMCACHED_SUCCESS, rc); @@ -1035,17 +1027,19 @@ static test_return_t read_through(memcached_st *memc) static test_return_t get_test(memcached_st *memc) { memcached_return_t rc; - const char *key= "foo"; char *string; size_t string_length; uint32_t flags; uint64_t query_id= memcached_query_id(memc); - rc= memcached_delete(memc, key, strlen(key), (time_t)0); - test_true(rc == MEMCACHED_BUFFERED || rc == MEMCACHED_NOTFOUND); + rc= memcached_delete(memc, + test_literal_param(__func__), + time_t(0)); + test_true_got(rc == MEMCACHED_BUFFERED or rc == MEMCACHED_NOTFOUND, memcached_last_error_message(memc)); test_compare(query_id +1, memcached_query_id(memc)); - string= memcached_get(memc, key, strlen(key), + string= memcached_get(memc, + test_literal_param(__func__), &string_length, &flags, &rc); test_compare_got(MEMCACHED_NOTFOUND, rc, memcached_strerror(NULL, rc)); @@ -1057,14 +1051,14 @@ static test_return_t get_test(memcached_st *memc) static test_return_t get_test2(memcached_st *memc) { - const char *key= "foo"; const char *value= "when we sanitize"; uint64_t query_id= memcached_query_id(memc); - memcached_return_t rc= memcached_set(memc, key, strlen(key), - value, strlen(value), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param(__func__), + value, strlen(value), + time_t(0), uint32_t(0))); test_compare(query_id +1, memcached_query_id(memc)); query_id= memcached_query_id(memc); @@ -1072,7 +1066,9 @@ static test_return_t get_test2(memcached_st *memc) uint32_t flags; size_t string_length; - char *string= memcached_get(memc, key, strlen(key), + memcached_return_t rc; + char *string= memcached_get(memc, + test_literal_param(__func__), &string_length, &flags, &rc); test_compare(query_id +1, memcached_query_id(memc)); @@ -1091,11 +1087,11 @@ static test_return_t set_test2(memcached_st *memc) { for (uint32_t x= 0; x < 10; x++) { - memcached_return_t rc= memcached_set(memc, - test_literal_param("foo"), - test_literal_param("train in the brain"), - time_t(0), uint32_t(0)); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param("foo"), + test_literal_param("train in the brain"), + time_t(0), uint32_t(0))); } return TEST_SUCCESS; @@ -1120,10 +1116,11 @@ static test_return_t set_test3(memcached_st *memc) snprintf(key, sizeof(key), "foo%u", x); uint64_t query_id= memcached_query_id(memc); - memcached_return_t rc= memcached_set(memc, key, strlen(key), - &value[0], value.size(), - (time_t)0, (uint32_t)0); - test_true_got(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED, memcached_strerror(NULL, rc)); + test_compare_hint(return_value_based_on_buffering(memc), + memcached_set(memc, key, strlen(key), + &value[0], value.size(), + time_t(0), uint32_t(0)), + memcached_last_error_message(memc)); test_compare(query_id +1, memcached_query_id(memc)); } @@ -1132,7 +1129,6 @@ static test_return_t set_test3(memcached_st *memc) static test_return_t get_test3(memcached_st *memc) { - const char *key= "foo"; size_t value_length= 8191; std::vector value; @@ -1142,20 +1138,23 @@ static test_return_t get_test3(memcached_st *memc) value.push_back(char(x % 127)); } - memcached_return_t rc; - rc= memcached_set(memc, key, strlen(key), - &value[0], value.size(), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + test_compare_hint(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param(__func__), + &value[0], value.size(), + time_t(0), uint32_t(0)), + memcached_last_error_message(memc)); size_t string_length; uint32_t flags; - char *string= memcached_get(memc, key, strlen(key), + memcached_return_t rc; + char *string= memcached_get(memc, + test_literal_param(__func__), &string_length, &flags, &rc); test_compare(MEMCACHED_SUCCESS, rc); test_true(string); - test_compare(string_length, value_length); + test_compare(value.size(), string_length); test_memcmp(string, &value[0], string_length); free(string); @@ -1165,7 +1164,6 @@ static test_return_t get_test3(memcached_st *memc) static test_return_t get_test4(memcached_st *memc) { - const char *key= "foo"; size_t value_length= 8191; std::vector value; @@ -1175,21 +1173,25 @@ static test_return_t get_test4(memcached_st *memc) value.push_back(char(x % 127)); } - memcached_return_t rc= memcached_set(memc, key, strlen(key), - &value[0], value.size(), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + test_compare_hint(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param(__func__), + &value[0], value.size(), + time_t(0), uint32_t(0)), + memcached_last_error_message(memc)); for (uint32_t x= 0; x < 10; x++) { uint32_t flags; size_t string_length; - char *string= memcached_get(memc, key, strlen(key), + memcached_return_t rc; + char *string= memcached_get(memc, + test_literal_param(__func__), &string_length, &flags, &rc); test_compare(MEMCACHED_SUCCESS, rc); test_true(string); - test_compare(string_length, value_length); + test_compare(value.size(), string_length); test_memcmp(string, &value[0], string_length); free(string); } @@ -1213,14 +1215,18 @@ static test_return_t get_test5(memcached_st *memc) uint32_t flags; size_t rlen; - memcached_return_t rc= memcached_set(memc, keys[0], lengths[0], - keys[0], lengths[0], 0, 0); + test_compare_hint(return_value_based_on_buffering(memc), + memcached_set(memc, keys[0], lengths[0], + keys[0], lengths[0], + time_t(0), uint32_t(0)), + memcached_last_error_message(memc)); test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, lengths, test_array_length(keys))); memcached_result_st results_obj; memcached_result_st *results= memcached_result_create(memc, &results_obj); test_true(results); + memcached_return_t rc; results= memcached_fetch_result(memc, &results_obj, &rc); test_true(results); @@ -1247,12 +1253,14 @@ static test_return_t mget_end(memcached_st *memc) size_t lengths[]= { 3, 4 }; const char *values[]= { "fjord", "41" }; - memcached_return_t rc; - // Set foo and foo2 for (size_t x= 0; x < test_array_length(keys); x++) { - test_compare(MEMCACHED_SUCCESS, memcached_set(memc, keys[x], lengths[x], values[x], strlen(values[x]), (time_t)0, (uint32_t)0)); + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, + keys[x], lengths[x], + values[x], strlen(values[x]), + time_t(0), uint32_t(0))); } char *string; @@ -1260,10 +1268,14 @@ static test_return_t mget_end(memcached_st *memc) uint32_t flags; // retrieve both via mget - test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, lengths, test_array_length(keys))); + test_compare(MEMCACHED_SUCCESS, + memcached_mget(memc, + keys, lengths, + test_array_length(keys))); char key[MEMCACHED_MAX_KEY]; size_t key_length; + memcached_return_t rc; // this should get both for (size_t x= 0; x < test_array_length(keys); x++) @@ -1288,8 +1300,8 @@ static test_return_t mget_end(memcached_st *memc) test_null(string); // now get just one - rc= memcached_mget(memc, keys, lengths, 1); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_mget(memc, keys, lengths, 1)); string= memcached_fetch(memc, key, &key_length, &string_length, &flags, &rc); test_compare(key_length, lengths[0]); @@ -1369,25 +1381,24 @@ static test_return_t increment_with_initial_test(memcached_st *memc) static test_return_t decrement_test(memcached_st *memc) { - uint64_t new_number; - memcached_return_t rc; - const char *value= "3"; - - rc= memcached_set(memc, - test_literal_param("number"), - value, strlen(value), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param(__func__), + test_literal_param("3"), + time_t(0), uint32_t(0))); + // Make sure we flush the value we just set + test_compare(MEMCACHED_SUCCESS, memcached_flush_buffers(memc)); + uint64_t new_number; test_compare(MEMCACHED_SUCCESS, memcached_decrement(memc, - test_literal_param("number"), + test_literal_param(__func__), 1, &new_number)); test_compare(uint64_t(2), new_number); test_compare(MEMCACHED_SUCCESS, memcached_decrement(memc, - test_literal_param("number"), + test_literal_param(__func__), 1, &new_number)); test_compare(uint64_t(1), new_number); @@ -1398,21 +1409,23 @@ static test_return_t decrement_with_initial_test(memcached_st *memc) { test_skip(true, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)); - uint64_t new_number; uint64_t initial= 3; test_compare(MEMCACHED_SUCCESS, memcached_flush_buffers(memc)); + uint64_t new_number; test_compare(MEMCACHED_SUCCESS, memcached_decrement_with_initial(memc, - test_literal_param("number"), - 1, initial, 0, &new_number)); + test_literal_param(__func__), + 1, initial, + 0, &new_number)); test_compare(new_number, initial); test_compare(MEMCACHED_SUCCESS, memcached_decrement_with_initial(memc, - test_literal_param("number"), - 1, initial, 0, &new_number)); + test_literal_param(__func__), + 1, initial, + 0, &new_number)); test_compare(new_number, (initial - 1)); return TEST_SUCCESS; @@ -1420,24 +1433,28 @@ static test_return_t decrement_with_initial_test(memcached_st *memc) static test_return_t increment_by_key_test(memcached_st *memc) { - uint64_t new_number; - memcached_return_t rc; const char *master_key= "foo"; const char *key= "number"; const char *value= "0"; - rc= memcached_set_by_key(memc, master_key, strlen(master_key), - key, strlen(key), - value, strlen(value), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set_by_key(memc, master_key, strlen(master_key), + key, strlen(key), + value, strlen(value), + time_t(0), uint32_t(0))); + + // Make sure we flush the value we just set + test_compare(MEMCACHED_SUCCESS, memcached_flush_buffers(memc)); + uint64_t new_number; test_compare(MEMCACHED_SUCCESS, - memcached_increment_by_key(memc, master_key, strlen(master_key), key, strlen(key), 1, &new_number)); + memcached_increment_by_key(memc, master_key, strlen(master_key), + key, strlen(key), 1, &new_number)); test_compare(uint64_t(1), new_number); test_compare(MEMCACHED_SUCCESS, - memcached_increment_by_key(memc, master_key, strlen(master_key), key, strlen(key), 1, &new_number)); + memcached_increment_by_key(memc, master_key, strlen(master_key), + key, strlen(key), 1, &new_number)); test_compare(uint64_t(2), new_number); return TEST_SUCCESS; @@ -1448,21 +1465,20 @@ static test_return_t increment_with_initial_by_key_test(memcached_st *memc) test_skip(true, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)); uint64_t new_number; - memcached_return_t rc; const char *master_key= "foo"; const char *key= "number"; uint64_t initial= 0; - rc= memcached_increment_with_initial_by_key(memc, master_key, strlen(master_key), - key, strlen(key), - 1, initial, 0, &new_number); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_increment_with_initial_by_key(memc, master_key, strlen(master_key), + key, strlen(key), + 1, initial, 0, &new_number)); test_compare(new_number, initial); - rc= memcached_increment_with_initial_by_key(memc, master_key, strlen(master_key), - key, strlen(key), - 1, initial, 0, &new_number); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_increment_with_initial_by_key(memc, master_key, strlen(master_key), + key, strlen(key), + 1, initial, 0, &new_number)); test_compare(new_number, (initial +1)); return TEST_SUCCESS; @@ -1471,15 +1487,14 @@ static test_return_t increment_with_initial_by_key_test(memcached_st *memc) static test_return_t decrement_by_key_test(memcached_st *memc) { uint64_t new_number; - memcached_return_t rc; const char *value= "3"; - rc= memcached_set_by_key(memc, - test_literal_param("foo"), - test_literal_param("number"), - value, strlen(value), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set_by_key(memc, + test_literal_param("foo"), + test_literal_param("number"), + value, strlen(value), + (time_t)0, (uint32_t)0)); test_compare(MEMCACHED_SUCCESS, memcached_decrement_by_key(memc, @@ -1529,12 +1544,11 @@ static test_return_t binary_increment_with_prefix_test(memcached_st *orig_memc) test_compare(MEMCACHED_SUCCESS, memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, (void *)"namespace:")); - memcached_return_t rc; - rc= memcached_set(memc, - test_literal_param("number"), - test_literal_param("0"), - (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param("number"), + test_literal_param("0"), + (time_t)0, (uint32_t)0)); uint64_t new_number; test_compare(MEMCACHED_SUCCESS, memcached_increment(memc, @@ -1553,20 +1567,20 @@ static test_return_t binary_increment_with_prefix_test(memcached_st *orig_memc) static test_return_t quit_test(memcached_st *memc) { - memcached_return_t rc; - const char *key= "fudge"; const char *value= "sanford and sun"; - rc= memcached_set(memc, key, strlen(key), - value, strlen(value), - (time_t)10, (uint32_t)3); - test_true_got(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED, memcached_strerror(NULL, rc)); + test_compare(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param(__func__), + value, strlen(value), + (time_t)10, (uint32_t)3)); memcached_quit(memc); - rc= memcached_set(memc, key, strlen(key), - value, strlen(value), - (time_t)50, (uint32_t)9); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set(memc, + test_literal_param(__func__), + value, strlen(value), + (time_t)50, (uint32_t)9)); return TEST_SUCCESS; } @@ -1693,16 +1707,15 @@ static test_return_t mget_result_function(memcached_st *memc) size_t counter; memcached_execute_fn callbacks[1]; - /* We need to empty the server before continueing test */ - test_compare(MEMCACHED_SUCCESS, - memcached_flush(memc, 0)); for (uint32_t x= 0; x < 3; x++) { - memcached_return_t rc= memcached_set(memc, keys[x], key_length[x], - keys[x], key_length[x], - (time_t)50, (uint32_t)9); - test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + test_compare(return_value_based_on_buffering(memc), + memcached_set(memc, keys[x], key_length[x], + keys[x], key_length[x], + time_t(50), uint32_t(9))); } + test_compare(MEMCACHED_SUCCESS, memcached_flush_buffers(memc)); + memcached_quit(memc); test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, key_length, 3)); @@ -1728,10 +1741,6 @@ static test_return_t mget_test(memcached_st *memc) char *return_value; size_t return_value_length; - /* We need to empty the server before continueing test */ - test_compare(MEMCACHED_SUCCESS, - memcached_flush(memc, 0)); - test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, key_length, 3)); @@ -2106,36 +2115,25 @@ static test_return_t MEMCACHED_BEHAVIOR_TCP_KEEPIDLE_test(memcached_st *memc) return TEST_SUCCESS; } -static test_return_t fetch_all_results(memcached_st *memc, unsigned int &keys_returned, const memcached_return_t expect) +static test_return_t fetch_all_results(memcached_st *memc, unsigned int &keys_returned, memcached_return_t& rc) { - memcached_return_t rc; - char return_key[MEMCACHED_MAX_KEY]; - size_t return_key_length; - char *return_value; - size_t return_value_length; - uint32_t flags; - keys_returned= 0; - while ((return_value= memcached_fetch(memc, return_key, &return_key_length, - &return_value_length, &flags, &rc))) + + memcached_result_st* result= NULL; + while ((result= memcached_fetch_result(memc, result, &rc))) { - test_true(return_value); - test_compare_got(MEMCACHED_SUCCESS, rc, memcached_strerror(NULL, rc)); - free(return_value); + test_compare(MEMCACHED_SUCCESS, rc); keys_returned+= 1; } + memcached_result_free(result); - if (memcached_success(expect) and memcached_success(rc)) - { - return TEST_SUCCESS; - } - else if (expect == rc) - { - return TEST_SUCCESS; - } - fprintf(stderr, "\n%s:%u %s(#%u)\n", __FILE__, __LINE__, memcached_strerror(NULL, rc), keys_returned); + return TEST_SUCCESS; +} - return TEST_FAILURE; +static test_return_t fetch_all_results(memcached_st *memc, unsigned int &keys_returned) +{ + memcached_return_t rc; + return fetch_all_results(memc, keys_returned, rc); } /* Test case provided by Cal Haldenbrand */ @@ -2167,10 +2165,12 @@ static test_return_t user_supplied_bug1(memcached_st *memc) } total+= size; - char key[22]; + char key[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1]; int key_length= snprintf(key, sizeof(key), "%u", x); test_compare(MEMCACHED_SUCCESS, - memcached_set(memc, key, key_length, randomstuff, strlen(randomstuff), time_t(0), HALDENBRAND_FLAG_KEY)); + memcached_set(memc, key, key_length, + randomstuff, strlen(randomstuff), + time_t(0), HALDENBRAND_FLAG_KEY)); } test_true(total > HALDENBRAND_KEY_COUNT); @@ -2220,10 +2220,11 @@ static test_return_t user_supplied_bug2(memcached_st *memc) continue; } test_compare(uint32_t(HALDENBRAND_FLAG_KEY), flags); + test_true(getval); total_value_length+= val_len; errors= 0; - free(getval); + ::free(getval); } return TEST_SUCCESS; @@ -2232,8 +2233,8 @@ static test_return_t user_supplied_bug2(memcached_st *memc) /* Do a large mget() over all the keys we think exist */ static test_return_t user_supplied_bug3(memcached_st *memc) { - test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1)); - test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1)); + test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, true)); + test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, true)); #ifdef NOT_YET memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE, 20 * 1024576); @@ -2259,14 +2260,14 @@ static test_return_t user_supplied_bug3(memcached_st *memc) memcached_mget(memc, &keys[0], &key_lengths[0], key_lengths.size())); unsigned int keys_returned; - test_compare(TEST_SUCCESS, fetch_all_results(memc, keys_returned, MEMCACHED_SUCCESS)); + test_compare(TEST_SUCCESS, fetch_all_results(memc, keys_returned)); test_compare(HALDENBRAND_KEY_COUNT, keys_returned); for (std::vector::iterator iter= keys.begin(); iter != keys.end(); iter++) { - free(*iter); + ::free(*iter); } return TEST_SUCCESS; @@ -2289,9 +2290,13 @@ static test_return_t user_supplied_bug4(memcached_st *memc) test_compare(MEMCACHED_NO_SERVERS, memcached_mget(memc, keys, key_length, 3)); - unsigned int keys_returned; - test_compare(TEST_SUCCESS, fetch_all_results(memc, keys_returned, MEMCACHED_NOTFOUND)); - test_zero(keys_returned); + { + unsigned int keys_returned; + memcached_return_t rc; + test_compare(TEST_SUCCESS, fetch_all_results(memc, keys_returned, rc)); + test_compare(MEMCACHED_NOTFOUND, rc); + test_zero(keys_returned); + } for (uint32_t x= 0; x < 3; x++) { @@ -2351,7 +2356,8 @@ static test_return_t user_supplied_bug5(memcached_st *memc) memcached_mget(memc, keys, key_length, 4)); unsigned int count; - test_compare(TEST_SUCCESS, fetch_all_results(memc, count, MEMCACHED_NOTFOUND)); + test_compare(TEST_SUCCESS, fetch_all_results(memc, count, rc)); + test_compare(MEMCACHED_NOTFOUND, rc); test_zero(count); for (uint32_t x= 0; x < 4; x++) @@ -2368,12 +2374,12 @@ static test_return_t user_supplied_bug5(memcached_st *memc) &value_length, &flags, &rc); test_compare(rc, MEMCACHED_SUCCESS); test_true(value); - free(value); + ::free(value); test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, key_length, 4)); - test_compare(TEST_SUCCESS, fetch_all_results(memc, count, MEMCACHED_SUCCESS)); + test_compare(TEST_SUCCESS, fetch_all_results(memc, count)); test_compare(4U, count); } delete [] insert_data; @@ -2483,37 +2489,36 @@ static test_return_t user_supplied_bug8(memcached_st *) /* Test flag store/retrieve */ static test_return_t user_supplied_bug7(memcached_st *memc) { - const char *keys= "036790384900"; - size_t key_length= strlen(keys); - char return_key[MEMCACHED_MAX_KEY]; - size_t return_key_length; - char *value; - size_t value_length; - uint32_t flags; char *insert_data= new (std::nothrow) char[VALUE_SIZE_BUG5]; + test_true(insert_data); - for (unsigned int x= 0; x < VALUE_SIZE_BUG5; x++) + for (size_t x= 0; x < VALUE_SIZE_BUG5; x++) { insert_data[x]= (signed char)rand(); } memcached_flush(memc, 0); - flags= 245; - test_compare(MEMCACHED_SUCCESS, memcached_set(memc, keys, key_length, - insert_data, VALUE_SIZE_BUG5, - (time_t)0, flags)); + const char *keys= "036790384900"; + size_t key_length= strlen(keys); + test_compare_hint(MEMCACHED_SUCCESS, memcached_set(memc, keys, key_length, + insert_data, VALUE_SIZE_BUG5, + time_t(0), 245U), + memcached_last_error_message(memc)); memcached_return_t rc; - flags= 0; - value= memcached_get(memc, keys, key_length, - &value_length, &flags, &rc); + size_t value_length; + uint32_t flags= 0; + char *value= memcached_get(memc, keys, key_length, + &value_length, &flags, &rc); test_compare(245U, flags); test_true(value); free(value); test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, &keys, &key_length, 1)); + char return_key[MEMCACHED_MAX_KEY]; + size_t return_key_length; flags= 0; value= memcached_fetch(memc, return_key, &return_key_length, &value_length, &flags, &rc); @@ -2795,19 +2800,20 @@ static test_return_t user_supplied_bug15(memcached_st *memc) /* Check the return sizes on FLAGS to make sure it stores 32bit unsigned values correctly */ static test_return_t user_supplied_bug16(memcached_st *memc) { - memcached_return_t rc= memcached_set(memc, test_literal_param("mykey"), - NULL, 0, - (time_t)0, UINT32_MAX); + test_compare_hint(MEMCACHED_SUCCESS, memcached_set(memc, test_literal_param("mykey"), + NULL, 0, + (time_t)0, UINT32_MAX), + memcached_last_error_message(memc)); - test_compare(MEMCACHED_SUCCESS, rc); size_t length; uint32_t flags; + memcached_return_t rc; char *value= memcached_get(memc, test_literal_param("mykey"), &length, &flags, &rc); test_compare(MEMCACHED_SUCCESS, rc); - test_true(value == NULL); + test_null(value); test_zero(length); test_compare(flags, UINT32_MAX); @@ -3115,7 +3121,7 @@ static test_return_t generate_data(memcached_st *memc) { unsigned int check_execute= execute_set(memc, global_pairs, global_count); - test_compare(check_execute, global_count); + test_compare_warn_hint(global_count, check_execute, "Possible false, positive, memcached may have ejected key/value based on memory needs"); return TEST_SUCCESS; } @@ -3192,6 +3198,7 @@ static test_return_t get_read_count(memcached_st *memc) static test_return_t get_read(memcached_st *memc) { + size_t keys_returned= 0; for (size_t x= 0; x < global_count; x++) { size_t return_value_length; @@ -3205,9 +3212,11 @@ static test_return_t get_read(memcached_st *memc) */ if (rc == MEMCACHED_SUCCESS && return_value) { + keys_returned++; free(return_value); } } + test_compare_warn_hint(global_count, keys_returned, "Possible false, positive, memcached may have ejected key/value based on memory needs"); return TEST_SUCCESS; } @@ -3223,7 +3232,7 @@ static test_return_t mget_read(memcached_st *memc) // Go fetch the keys and test to see if all of them were returned { unsigned int keys_returned; - test_compare(TEST_SUCCESS, fetch_all_results(memc, keys_returned, MEMCACHED_SUCCESS)); + test_compare(TEST_SUCCESS, fetch_all_results(memc, keys_returned)); test_true(keys_returned > 0); test_compare_warn_hint(global_count, keys_returned, "Possible false, positive, memcached may have ejected key/value based on memory needs"); } @@ -3348,10 +3357,15 @@ static test_return_t mget_read_function(memcached_st *memc) static test_return_t delete_generate(memcached_st *memc) { + size_t total= 0; for (size_t x= 0; x < global_count; x++) { - (void)memcached_delete(memc, global_keys[x], global_keys_length[x], (time_t)0); + if (memcached_success(memcached_delete(memc, global_keys[x], global_keys_length[x], (time_t)0))) + { + total++; + } } + test_compare_warn_hint(global_count, total, "Possible false, positive, memcached may have ejected key/value based on memory needs"); return TEST_SUCCESS; } @@ -3360,10 +3374,15 @@ static test_return_t delete_buffer_generate(memcached_st *memc) { memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, true); + size_t total= 0; for (size_t x= 0; x < global_count; x++) { - (void)memcached_delete(memc, global_keys[x], global_keys_length[x], (time_t)0); + if (memcached_success(memcached_delete(memc, global_keys[x], global_keys_length[x], (time_t)0))) + { + total++; + } } + test_compare_warn_hint(global_count, total, "Possible false, positive, memcached may have ejected key/value based on memory needs"); return TEST_SUCCESS; } @@ -3934,11 +3953,11 @@ static test_return_t MEMCACHED_BEHAVIOR_POLL_TIMEOUT_test(memcached_st *memc) static test_return_t noreply_test(memcached_st *memc) { test_compare(MEMCACHED_SUCCESS, - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 1)); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, true)); test_compare(MEMCACHED_SUCCESS, - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1)); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, true)); test_compare(MEMCACHED_SUCCESS, - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1)); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, true)); test_compare(1LLU, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NOREPLY)); test_compare(1LLU, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS)); test_compare(1LLU, memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS)); @@ -5088,14 +5107,14 @@ static test_return_t memcached_stat_execute_test(memcached_st *memc) memcached_return_t rc= memcached_stat_execute(memc, NULL, stat_printer, NULL); test_compare(MEMCACHED_SUCCESS, rc); - rc= memcached_stat_execute(memc, "slabs", stat_printer, NULL); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_stat_execute(memc, "slabs", stat_printer, NULL)); - rc= memcached_stat_execute(memc, "items", stat_printer, NULL); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_stat_execute(memc, "items", stat_printer, NULL)); - rc= memcached_stat_execute(memc, "sizes", stat_printer, NULL); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, + memcached_stat_execute(memc, "sizes", stat_printer, NULL)); return TEST_SUCCESS; } @@ -5125,7 +5144,7 @@ static test_return_t wrong_failure_counter_test(memcached_st *memc) rc= memcached_set(memc, key, strlen(key), value, strlen(value), (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); instance= memcached_server_instance_by_position(memc, 0); @@ -5155,53 +5174,45 @@ static test_return_t wrong_failure_counter_test(memcached_st *memc) */ static test_return_t wrong_failure_counter_two_test(memcached_st *memc) { - memcached_return rc; - - memcached_st *memc_clone; - memc_clone= memcached_clone(NULL, memc); - test_true(memc_clone); - /* Set value to force connection to the server */ const char *key= "marmotte"; const char *value= "milka"; - char *string = NULL; - size_t string_length; - uint32_t flags; - rc= memcached_set(memc_clone, key, strlen(key), - value, strlen(value), - (time_t)0, (uint32_t)0); - test_true_got(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED, memcached_strerror(NULL, rc)); + test_compare_hint(MEMCACHED_SUCCESS, + memcached_set(memc, key, strlen(key), + value, strlen(value), + (time_t)0, (uint32_t)0), + memcached_last_error_message(memc)); /* put failure limit to 1 */ test_compare(MEMCACHED_SUCCESS, - memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, 1)); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, true)); /* Put a retry timeout to effectively activate failure_limit effect */ test_compare(MEMCACHED_SUCCESS, - memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 1)); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, true)); /* change behavior that triggers memcached_quit()*/ test_compare(MEMCACHED_SUCCESS, - memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1)); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, true)); /* Check if we still are connected */ - string= memcached_get(memc_clone, key, strlen(key), - &string_length, &flags, &rc); + uint32_t flags; + size_t string_length; + memcached_return rc; + char *string= memcached_get(memc, key, strlen(key), + &string_length, &flags, &rc); test_compare_got(MEMCACHED_SUCCESS, rc, memcached_strerror(NULL, rc)); test_true(string); free(string); - memcached_free(memc_clone); return TEST_SUCCESS; } - - /* * Test that ensures mget_execute does not end into recursive calls that finally fails */ diff --git a/tests/libmemcached-1.0/parser.cc b/tests/libmemcached-1.0/parser.cc index 32b0d9d8..03da195a 100644 --- a/tests/libmemcached-1.0/parser.cc +++ b/tests/libmemcached-1.0/parser.cc @@ -762,7 +762,11 @@ test_return_t regression_bug_71231153_poll(memcached_st *) char *value= memcached_get(memc, test_literal_param("test"), &value_len, NULL, &rc); test_false(value); test_zero(value_len); +#ifdef __APPLE__ + test_compare_got(MEMCACHED_CONNECTION_FAILURE, rc, memcached_last_error_message(memc)); +#else test_compare_got(MEMCACHED_TIMEOUT, rc, memcached_last_error_message(memc)); +#endif memcached_free(memc); } diff --git a/tests/mem_udp.cc b/tests/mem_udp.cc index 16fc1c73..1591bdcf 100644 --- a/tests/mem_udp.cc +++ b/tests/mem_udp.cc @@ -1,11 +1,41 @@ -/* libMemcached Functions Test - * Copyright (C) 2006-2009 Brian Aker - * All rights reserved. +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2006-2009 Brian Aker All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Use and distribution licensed under the BSD license. See - * the COPYING file in the parent directory for full text. */ + /* Sample test application. */ @@ -18,6 +48,7 @@ using namespace libtest; #include #include #include +#include #include #include @@ -111,8 +142,25 @@ static test_return_t init_udp(memcached_st *memc) return TEST_SUCCESS; } +static test_return_t init_udp_valgrind(memcached_st *memc) +{ + if (getenv("TESTS_ENVIRONMENT")) + { + return TEST_SKIPPED; + } + + test_skip(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, true)); + + return TEST_SUCCESS; +} + static test_return_t binary_init_udp(memcached_st *memc) { + if (getenv("TESTS_ENVIRONMENT")) + { + return TEST_SKIPPED; + } + test_skip(TEST_SUCCESS, pre_binary(memc)); return init_udp(memc); @@ -152,26 +200,80 @@ static test_return_t add_udp_server_tcp_client_test(memcached_st *memc) return TEST_SUCCESS; } +static test_return_t version_TEST(memcached_st *memc) +{ + test_compare(MEMCACHED_NOT_SUPPORTED, memcached_version(memc)); + return TEST_SUCCESS; +} + +static test_return_t verbosity_TEST(memcached_st *memc) +{ + test_compare(MEMCACHED_SUCCESS, memcached_verbosity(memc, 0)); + return TEST_SUCCESS; +} + +static test_return_t memcached_get_TEST(memcached_st *memc) +{ + memcached_return_t rc; + test_null(memcached_get(memc, + test_literal_param(__func__), + 0, 0, &rc)); + test_compare(MEMCACHED_NOT_SUPPORTED, rc); + + return TEST_SUCCESS; +} + +static test_return_t memcached_mget_execute_by_key_TEST(memcached_st *memc) +{ + char **keys= NULL; + size_t *key_length= NULL; + test_compare(MEMCACHED_NOT_SUPPORTED, + memcached_mget_execute_by_key(memc, + test_literal_param(__func__), // Group key + keys, key_length, // Actual key + 0, // Number of keys + 0, // callbacks + 0, // context + 0)); // Number of callbacks + + return TEST_SUCCESS; +} + +static test_return_t memcached_stat_TEST(memcached_st *memc) +{ + memcached_return_t rc; + test_null(memcached_stat(memc, 0, &rc)); + test_compare(MEMCACHED_NOT_SUPPORTED, rc); + + return TEST_SUCCESS; +} + static test_return_t set_udp_behavior_test(memcached_st *memc) { memcached_quit(memc); test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, memc->distribution)); test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, true)); - test_true(memc->flags.use_udp); - test_true(memc->flags.no_reply); + test_compare(true, memc->flags.use_udp); + test_compare(false, memc->flags.reply); test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, false)); - test_false(memc->flags.use_udp); + test_compare(false, memc->flags.use_udp); test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, false)); - test_false(memc->flags.no_reply); + test_compare(true, memc->flags.reply); return TEST_SUCCESS; } static test_return_t udp_set_test(memcached_st *memc) { - unsigned int num_iters= 1025; //request id rolls over at 1024 + // Assume we are running under valgrind, and bail + if (getenv("TESTS_ENVIRONMENT")) + { + return TEST_SUCCESS; + } + + const unsigned int num_iters= 1025; //request id rolls over at 1024 test_true(memc); @@ -184,29 +286,23 @@ static test_return_t udp_set_test(memcached_st *memc) memcached_server_instance_st instance= memcached_server_instance_by_position(memc, server_key); size_t init_offset= instance->write_buffer_offset; - memcached_return_t rc= memcached_set(memc, test_literal_param("foo"), - test_literal_param("when we sanitize"), - time_t(0), uint32_t(0)); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); - /** NB, the check below assumes that if new write_ptr is less than - * the original write_ptr that we have flushed. For large payloads, this - * maybe an invalid assumption, but for the small payload we have it is OK - */ - if (rc == MEMCACHED_SUCCESS or instance->write_buffer_offset < init_offset) + test_compare_hint(MEMCACHED_SUCCESS, + memcached_set(memc, + test_literal_param("foo"), + test_literal_param("when we sanitize"), + time_t(0), uint32_t(0)), + memcached_last_error_message(memc)); + + /* + NB, the check below assumes that if new write_ptr is less than + the original write_ptr that we have flushed. For large payloads, this + maybe an invalid assumption, but for the small payload we have it is OK + */ + if (instance->write_buffer_offset < init_offset) { increment_request_id(&expected_ids[server_key]); } - if (rc == MEMCACHED_SUCCESS) - { - test_true(instance->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH); - } - else - { - test_true(instance->write_buffer_offset != UDP_DATAGRAM_HEADER_LENGTH); - test_true(instance->write_buffer_offset <= MAX_UDP_DATAGRAM_LENGTH); - } - test_compare(TEST_SUCCESS, post_udp_op_check(memc, expected_ids)); } @@ -216,21 +312,27 @@ static test_return_t udp_set_test(memcached_st *memc) static test_return_t udp_buffered_set_test(memcached_st *memc) { test_true(memc); - test_compare(MEMCACHED_INVALID_ARGUMENTS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, true)); + test_compare(MEMCACHED_INVALID_ARGUMENTS, + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, true)); return TEST_SUCCESS; } static test_return_t udp_set_too_big_test(memcached_st *memc) { test_true(memc); - char value[MAX_UDP_DATAGRAM_LENGTH]; Expected expected_ids; get_udp_request_ids(memc, expected_ids); - memset(value, int('f'), sizeof(value)); + std::vector value; + value.resize(1024 * 1024 * 10); - test_compare_hint(MEMCACHED_WRITE_FAILURE, memcached_set(memc, test_literal_param("bar"), value, sizeof(value), time_t(0), uint32_t(0)), + test_compare_hint(MEMCACHED_WRITE_FAILURE, + memcached_set(memc, + test_literal_param(__func__), + &value[0], value.size(), + time_t(0), uint32_t(0)), memcached_last_error_message(memc)); + memcached_quit(memc); return post_udp_op_check(memc, expected_ids); } @@ -249,23 +351,14 @@ static test_return_t udp_delete_test(memcached_st *memc) memcached_server_instance_st instance= memcached_server_instance_by_position(memc, server_key); size_t init_offset= instance->write_buffer_offset; - memcached_return_t rc= memcached_delete(memc, test_literal_param("foo"), 0); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + test_compare(MEMCACHED_SUCCESS, + memcached_delete(memc, test_literal_param("foo"), 0)); - if (rc == MEMCACHED_SUCCESS or instance->write_buffer_offset < init_offset) + if (instance->write_buffer_offset < init_offset) { increment_request_id(&expected_ids[server_key]); } - if (rc == MEMCACHED_SUCCESS) - { - test_true(instance->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH); - } - else - { - test_true(instance->write_buffer_offset != UDP_DATAGRAM_HEADER_LENGTH); - test_true(instance->write_buffer_offset <= MAX_UDP_DATAGRAM_LENGTH); - } test_compare(TEST_SUCCESS, post_udp_op_check(memc, expected_ids)); } @@ -310,6 +403,7 @@ static test_return_t udp_flush_test(memcached_st *memc) { increment_request_id(&expected_ids[x]); } + memcached_error_print(memc); test_compare_hint(MEMCACHED_SUCCESS, memcached_flush(memc, 0), memcached_last_error_message(memc)); return post_udp_op_check(memc, expected_ids); @@ -317,9 +411,10 @@ static test_return_t udp_flush_test(memcached_st *memc) static test_return_t udp_incr_test(memcached_st *memc) { - test_compare(MEMCACHED_SUCCESS, memcached_set(memc, test_literal_param("incr"), - test_literal_param("1"), - (time_t)0, (uint32_t)0)); + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, test_literal_param("incr"), + test_literal_param("1"), + (time_t)0, (uint32_t)0)); Expected expected_ids; get_udp_request_ids(memc, expected_ids); @@ -335,19 +430,23 @@ static test_return_t udp_incr_test(memcached_st *memc) static test_return_t udp_decr_test(memcached_st *memc) { - test_compare(MEMCACHED_SUCCESS, memcached_set(memc, - test_literal_param("decr"), - test_literal_param("1"), - (time_t)0, (uint32_t)0)); + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, + test_literal_param(__func__), + test_literal_param("1"), + (time_t)0, (uint32_t)0)); Expected expected_ids; get_udp_request_ids(memc, expected_ids); - unsigned int server_key= memcached_generate_hash(memc, test_literal_param("decr")); + unsigned int server_key= memcached_generate_hash(memc, + test_literal_param(__func__)); increment_request_id(&expected_ids[server_key]); uint64_t newvalue; - test_compare(MEMCACHED_SUCCESS, memcached_decrement(memc, test_literal_param("decr"), 1, &newvalue)); + test_compare(MEMCACHED_SUCCESS, memcached_decrement(memc, + test_literal_param(__func__), + 1, &newvalue)); return post_udp_op_check(memc, expected_ids); } @@ -371,7 +470,8 @@ static test_return_t udp_version_test(memcached_st *memc) Expected expected_ids; get_udp_request_ids(memc, expected_ids); - test_compare(MEMCACHED_NOT_SUPPORTED, memcached_version(memc)); + test_compare(MEMCACHED_NOT_SUPPORTED, + memcached_version(memc)); return post_udp_op_check(memc, expected_ids); } @@ -421,6 +521,15 @@ static test_return_t udp_mixed_io_test(memcached_st *memc) return TEST_SUCCESS; } +test_st compatibility_TESTS[] ={ + {"version", 0, (test_callback_fn*)version_TEST }, + {"version", 0, (test_callback_fn*)verbosity_TEST }, + {"memcached_get()", 0, (test_callback_fn*)memcached_get_TEST }, + {"memcached_mget_execute_by_key()", 0, (test_callback_fn*)memcached_mget_execute_by_key_TEST }, + {"memcached_stat()", 0, (test_callback_fn*)memcached_stat_TEST }, + {0, 0, 0} +}; + test_st udp_setup_server_tests[] ={ {"set_udp_behavior_test", 0, (test_callback_fn*)set_udp_behavior_test}, {"add_tcp_server_udp_client_test", 0, (test_callback_fn*)add_tcp_server_udp_client_test}, @@ -448,7 +557,8 @@ test_st upd_io_tests[] ={ collection_st collection[] ={ {"udp_setup", (test_callback_fn*)init_udp, 0, udp_setup_server_tests}, - {"udp_io", (test_callback_fn*)init_udp, 0, upd_io_tests}, + {"compatibility", (test_callback_fn*)init_udp, 0, compatibility_TESTS}, + {"udp_io", (test_callback_fn*)init_udp_valgrind, 0, upd_io_tests}, {"udp_binary_io", (test_callback_fn*)binary_init_udp, 0, upd_io_tests}, {0, 0, 0, 0} }; diff --git a/util/instance.cc b/util/instance.cc index 23c8aec4..19d01fcf 100644 --- a/util/instance.cc +++ b/util/instance.cc @@ -192,7 +192,7 @@ bool Instance::run() switch(errno) { default: - std::cerr << "Failed during send(" << strerror(errno) << ")" << std::endl; + std::cerr << "Failed dureng send(" << strerror(errno) << ")" << std::endl; break; } }