X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=clients%2Fmemcapable.cc;h=b38cf311001cbae26ebe2f12a272fe507828181f;hb=9763b8e9b681d1d6713b95e4d7ce6ffeafeafca5;hp=9dff427eb3c2c9c88e8c5463569aa895ca8d65d6;hpb=562eadf651a079c347ff2797069adbbf938fea96;p=awesomized%2Flibmemcached diff --git a/clients/memcapable.cc b/clients/memcapable.cc index 9dff427e..b38cf311 100644 --- a/clients/memcapable.cc +++ b/clients/memcapable.cc @@ -1,4 +1,5 @@ /* LibMemcached + * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/ * Copyright (C) 2006-2009 Brian Aker * All rights reserved. * @@ -12,7 +13,7 @@ /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ #undef NDEBUG -#include +#include #ifdef HAVE_POLL_H #include @@ -20,24 +21,27 @@ #include "poll/poll.h" #endif -#include +#include +#include +#include +#include +#include #include -#include #include #include #include #include -#include -#include -#include -#include #include #include -#include -#include -#include -#include +#include + +#include "libmemcached/socket.hpp" +#include "libmemcached/memcached/protocol_binary.h" +#include "libmemcached/byteorder.h" +#include "clients/utilities.h" + +#include #ifdef linux /* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to @@ -120,7 +124,7 @@ static struct addrinfo *lookuphost(const char *hostname, const char *port) */ static memcached_socket_t set_noblock(void) { -#ifdef WIN32 +#if defined(_WIN32) u_long arg = 1; if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR) { @@ -133,7 +137,7 @@ static memcached_socket_t set_noblock(void) if (flags == -1) { perror("Failed to get socket flags"); - closesocket(sock); + memcached_close_socket(sock); return INVALID_SOCKET; } @@ -142,7 +146,7 @@ static memcached_socket_t set_noblock(void) if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) { perror("Failed to set socket to nonblocking mode"); - closesocket(sock); + memcached_close_socket(sock); return INVALID_SOCKET; } } @@ -244,10 +248,14 @@ static enum test_return ensure(bool val, const char *expression, const char *fil if (!val) { if (verbose) + { fprintf(stderr, "\n%s:%d: %s", file, line, expression); + } if (do_core) + { abort(); + } return TEST_FAIL; } @@ -271,9 +279,14 @@ static enum test_return retry_write(const void* buf, size_t len) size_t num_bytes= len - offset; ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes); if (nw == -1) + { verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN); + } else + { offset+= (size_t)nw; + } + } while (offset < len); return TEST_PASS; @@ -286,7 +299,7 @@ static enum test_return retry_write(const void* buf, size_t len) static enum test_return resend_packet(command *cmd) { size_t length= sizeof (protocol_binary_request_no_extras) + - ntohl(cmd->plain.message.header.request.bodylen); + ntohl(cmd->plain.message.header.request.bodylen); execute(retry_write(cmd, length)); return TEST_PASS; @@ -324,8 +337,10 @@ static enum test_return retry_read(void *buf, size_t len) fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno)); verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN); break; + case 0: return TEST_FAIL; + default: offset+= (size_t)nr; } @@ -669,9 +684,13 @@ static enum test_return test_binary_set_impl(const char* key, uint8_t cc) for (int ii= 0; ii < 10; ii++) { if (ii == 0) + { execute(send_packet(&cmd)); + } else + { execute(resend_packet(&cmd)); + } if (cc == PROTOCOL_BINARY_CMD_SET) { @@ -799,17 +818,25 @@ static enum test_return test_binary_replace_impl(const char* key, uint8_t cc) for (int ii= 0; ii < 10; ii++) { if (ii == 0) + { execute(send_packet(&cmd)); + } else + { execute(resend_packet(&cmd)); + } if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0) { uint16_t expected_result; if (ii == 0) + { expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT; + } else + { expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS; + } execute(send_binary_noop()); execute(recv_packet(&rsp)); @@ -820,7 +847,9 @@ static enum test_return test_binary_replace_impl(const char* key, uint8_t cc) execute(binary_set_item(key, key)); } else + { execute(test_binary_noop()); + } } /* verify that replace with CAS value works! */ @@ -1094,16 +1123,24 @@ static enum test_return test_binary_concat_impl(const char *key, uint8_t cc) const char *value; if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ) + { value="hello"; + } else + { value=" world"; + } execute(binary_set_item(key, value)); if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ) + { value=" world"; + } else + { value="hello"; + } raw_command(&cmd, cc, key, strlen(key), value, strlen(value)); execute(send_packet(&cmd)); @@ -1113,7 +1150,9 @@ static enum test_return test_binary_concat_impl(const char *key, uint8_t cc) verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS)); } else + { execute(test_binary_noop()); + } raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0); execute(send_packet(&cmd)); @@ -1285,7 +1324,9 @@ static enum test_return test_ascii_set_impl(const char* key, bool noreply) execute(send_string(buffer)); if (!noreply) + { execute(receive_response("STORED\r\n")); + } return test_ascii_version(); } @@ -1308,12 +1349,16 @@ static enum test_return test_ascii_add_impl(const char* key, bool noreply) execute(send_string(buffer)); if (!noreply) + { execute(receive_response("STORED\r\n")); + } execute(send_string(buffer)); if (!noreply) + { execute(receive_response("NOT_STORED\r\n")); + } return test_ascii_version(); } @@ -1336,21 +1381,28 @@ static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_ verify(strncmp(buffer, "VALUE ", 6) == 0); char *end= strchr(buffer + 6, ' '); verify(end != NULL); - *end= '\0'; + if (end) + { + *end= '\0'; + } *key= strdup(buffer + 6); verify(*key != NULL); char *ptr= end + 1; + errno= 0; unsigned long val= strtoul(ptr, &end, 10); /* flags */ + verify(errno == 0); verify(ptr != end); verify(val == 0); verify(end != NULL); + errno= 0; *ndata = (ssize_t)strtoul(end, &end, 10); /* size */ + verify(errno == 0); verify(ptr != end); verify(end != NULL); - while (*end != '\n' && isspace(*end)) + while (end and *end != '\n' and isspace(*end)) ++end; - verify(*end == '\n'); + verify(end and *end == '\n'); *value= static_cast(malloc((size_t)*ndata)); verify(*value != NULL); @@ -1376,17 +1428,24 @@ static enum test_return ascii_get_value(const char *key, const char *value) char *ptr= buffer + 6 + strlen(key) + 1; char *end; + errno= 0; unsigned long val= strtoul(ptr, &end, 10); /* flags */ + verify(errno == 0); verify(ptr != end); verify(val == 0); verify(end != NULL); + + errno= 0; val= strtoul(end, &end, 10); /* size */ + verify(errno == 0); verify(ptr != end); verify(val == datasize); verify(end != NULL); - while (*end != '\n' && isspace(*end)) + while (end and *end != '\n' and isspace(*end)) + { ++end; - verify(*end == '\n'); + } + verify(end and *end == '\n'); execute(retry_read(buffer, datasize)); verify(memcmp(buffer, value, datasize) == 0); @@ -1403,14 +1462,18 @@ static enum test_return ascii_get_item(const char *key, const char *value, char buffer[1024]; size_t datasize= 0; if (value != NULL) + { datasize= strlen(value); + } verify(datasize < sizeof(buffer)); snprintf(buffer, sizeof(buffer), "get %s\r\n", key); execute(send_string(buffer)); if (exist) + { execute(ascii_get_value(key, value)); + } execute(retry_read(buffer, 5)); verify(memcmp(buffer, "END\r\n", 5) == 0); @@ -1432,22 +1495,32 @@ static enum test_return ascii_gets_value(const char *key, const char *value, char *ptr= buffer + 6 + strlen(key) + 1; char *end; + errno= 0; unsigned long val= strtoul(ptr, &end, 10); /* flags */ + verify(errno == 0); verify(ptr != end); verify(val == 0); verify(end != NULL); + + errno= 0; val= strtoul(end, &end, 10); /* size */ + verify(errno == 0); verify(ptr != end); verify(val == datasize); verify(end != NULL); + + errno= 0; *cas= strtoul(end, &end, 10); /* cas */ + verify(errno == 0); verify(ptr != end); verify(val == datasize); verify(end != NULL); - while (*end != '\n' && isspace(*end)) + while (end and *end != '\n' and isspace(*end)) + { ++end; - verify(*end == '\n'); + } + verify(end and *end == '\n'); execute(retry_read(buffer, datasize)); verify(memcmp(buffer, value, datasize) == 0); @@ -1464,7 +1537,9 @@ static enum test_return ascii_gets_item(const char *key, const char *value, char buffer[1024]; size_t datasize= 0; if (value != NULL) + { datasize= strlen(value); + } verify(datasize < sizeof(buffer)); snprintf(buffer, sizeof(buffer), "gets %s\r\n", key); @@ -1498,9 +1573,13 @@ static enum test_return test_ascii_replace_impl(const char* key, bool noreply) execute(send_string(buffer)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("NOT_STORED\r\n")); + } execute(ascii_set_item(key, "value")); execute(ascii_get_item(key, "value", true)); @@ -1538,17 +1617,25 @@ static enum test_return test_ascii_cas_impl(const char* key, bool noreply) execute(send_string(buffer)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("STORED\r\n")); + } /* reexecute the same command should fail due to illegal cas */ execute(send_string(buffer)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("EXISTS\r\n")); + } return test_ascii_version(); } @@ -1640,14 +1727,17 @@ static enum test_return test_ascii_mget(void) }; for (uint32_t x= 0; x < nkeys; ++x) + { execute(ascii_set_item(keys[x], "value")); + } /* Ask for a key that doesn't exist as well */ execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 " "test_ascii_mget4 test_ascii_mget5 " "test_ascii_mget6\r\n")); - char *returned[nkeys]; + std::vector returned; + returned.resize(nkeys); for (uint32_t x= 0; x < nkeys; ++x) { @@ -1679,7 +1769,9 @@ static enum test_return test_ascii_mget(void) } for (uint32_t x= 0; x < nkeys; ++x) + { free(returned[x]); + } return TEST_PASS; } @@ -1731,7 +1823,9 @@ static enum test_return test_ascii_decr_impl(const char* key, bool noreply) execute(send_string(cmd)); if (noreply) + { execute(test_ascii_version()); + } else { char buffer[80]; @@ -1746,7 +1840,9 @@ static enum test_return test_ascii_decr_impl(const char* key, bool noreply) /* verify that it doesn't wrap */ execute(send_string(cmd)); if (noreply) + { execute(test_ascii_version()); + } else { char buffer[80]; @@ -1820,9 +1916,13 @@ static enum test_return test_ascii_concat_impl(const char *key, execute(ascii_set_item(key, value)); if (append) + { value=" world"; + } else + { value="hello"; + } char cmd[400]; snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n", @@ -1832,9 +1932,13 @@ static enum test_return test_ascii_concat_impl(const char *key, execute(send_string(cmd)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("STORED\r\n")); + } execute(ascii_get_item(key, "hello world", true)); @@ -1845,9 +1949,13 @@ static enum test_return test_ascii_concat_impl(const char *key, execute(send_string(cmd)); if (noreply) + { execute(test_ascii_version()); + } else + { execute(receive_response("NOT_STORED\r\n")); + } return TEST_PASS; } @@ -1974,17 +2082,19 @@ int main(int argc, char **argv) - while ((cmd= getopt(argc, argv, "t:vch:p:PT:?ab")) != EOF) + while ((cmd= getopt(argc, argv, "qt:vch:p:PT:?ab")) != EOF) { switch (cmd) { case 'a': tests.ascii= true; tests.binary= false; break; + case 'b': tests.ascii= false; tests.binary= true; break; + case 't': timeout= atoi(optarg); if (timeout == 0) @@ -1993,18 +2103,29 @@ int main(int argc, char **argv) return EXIT_FAILURE; } break; + case 'v': verbose= true; break; + case 'c': do_core= true; break; + case 'h': hostname= optarg; break; + case 'p': port= optarg; break; + + case 'q': + close_stdio(); + break; + case 'P': prompt= true; break; + case 'T': testname= optarg; break; + default: fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n" "\t-c\tGenerate coredump if a test fails\n" @@ -2018,7 +2139,7 @@ int main(int argc, char **argv) "\t-a\tOnly test the ascii protocol\n" "\t-b\tOnly test the binary protocol\n", argv[0]); - return EXIT_FAILURE; + return EXIT_SUCCESS; } } @@ -2034,7 +2155,9 @@ int main(int argc, char **argv) for (int ii= 0; testcases[ii].description != NULL; ++ii) { if (testname != NULL && strcmp(testcases[ii].description, testname) != 0) - continue; + { + continue; + } if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) || (testcases[ii].description[0] == 'b' && (tests.binary) == 0)) @@ -2058,7 +2181,9 @@ int main(int argc, char **argv) continue; } if (strncmp(buffer, "quit", 4) == 0) - exit(0); + { + exit(EXIT_SUCCESS); + } } fprintf(stdout, "%-40s", testcases[ii].description); @@ -2083,8 +2208,7 @@ int main(int argc, char **argv) closesocket(sock); if ((sock= connect_server(hostname, port)) == INVALID_SOCKET) { - fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", - hostname, port, strerror(get_socket_errno())); + fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", hostname, port, strerror(get_socket_errno())); fprintf(stderr, "%d of %d tests failed\n", failed, total); return EXIT_FAILURE; } @@ -2093,9 +2217,13 @@ int main(int argc, char **argv) closesocket(sock); if (failed == 0) + { fprintf(stdout, "All tests passed\n"); + } else + { fprintf(stderr, "%d of %d tests failed\n", failed, total); + } - return (failed == 0) ? 0 : 1; + return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }