X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=clients%2Fmemcapable.cc;h=fc956fe07d891911041c80b9e04095fb14173535;hb=8c84f5e265f1fc68681f0856a7d96fa8aa034e80;hp=9c9feb52d5d46ffa7356ed4a55b9490f17602bc9;hpb=28adf7b936c6f5c25b7526ff56ec1256da1246d4;p=awesomized%2Flibmemcached diff --git a/clients/memcapable.cc b/clients/memcapable.cc index 9c9feb52..fc956fe0 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,25 +13,35 @@ /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */ #undef NDEBUG -#include "config.h" -#include -#include +#include + +#ifdef HAVE_POLL_H +#include +#else +#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 "utilities.h" +#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 @@ -99,9 +110,13 @@ static struct addrinfo *lookuphost(const char *hostname, const char *port) if (error != 0) { if (error != EAI_SYSTEM) + { fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error)); + } else + { perror("getaddrinfo()"); + } } return ai; @@ -113,7 +128,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) { @@ -126,7 +141,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; } @@ -135,7 +150,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; } } @@ -171,8 +186,9 @@ static memcached_socket_t connect_server(const char *hostname, const char *port) } } else - fprintf(stderr, "Failed to create socket: %s\n", - strerror(get_socket_errno())); + { + fprintf(stderr, "Failed to create socket: %s\n", strerror(get_socket_errno())); + } freeaddrinfo(ai); } @@ -237,10 +253,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); + { + fprintf(stdout, "\n%s:%d: %s", file, line, expression); + } if (do_core) + { abort(); + } return TEST_FAIL; } @@ -264,9 +284,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; @@ -279,7 +304,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; @@ -314,11 +339,13 @@ static enum test_return retry_read(void *buf, size_t len) ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset); switch (nr) { case -1 : - fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno)); + 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; } @@ -655,16 +682,20 @@ static enum test_return test_binary_set_impl(const char* key, uint8_t cc) command cmd; response rsp; - uint64_t value= 0xdeadbeefdeadcafe; + uint64_t value= 0xdeadbeefdeadcafeULL; storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0); /* set should always work */ 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) { @@ -725,7 +756,7 @@ static enum test_return test_binary_add_impl(const char* key, uint8_t cc) { command cmd; response rsp; - uint64_t value= 0xdeadbeefdeadcafe; + uint64_t value= 0xdeadbeefdeadcafeULL; storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0); /* first add should work, rest of them should fail (even with cas @@ -784,7 +815,7 @@ static enum test_return test_binary_replace_impl(const char* key, uint8_t cc) { command cmd; response rsp; - uint64_t value= 0xdeadbeefdeadcafe; + uint64_t value= 0xdeadbeefdeadcafeULL; storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0); /* first replace should fail, successive should succeed (when the @@ -792,17 +823,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)); @@ -813,7 +852,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! */ @@ -1087,16 +1128,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)); @@ -1106,7 +1155,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)); @@ -1251,7 +1302,7 @@ static enum test_return test_ascii_verbosity(void) execute(receive_error_response()); execute(send_string("verbosity noreply\r\n")); - execute(receive_error_response()); + execute(test_ascii_version()); execute(send_string("verbosity 0 noreply\r\n")); execute(test_ascii_version()); @@ -1278,7 +1329,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(); } @@ -1301,12 +1354,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(); } @@ -1329,21 +1386,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); @@ -1369,17 +1433,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); @@ -1396,14 +1467,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); @@ -1425,22 +1500,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); @@ -1457,7 +1542,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); @@ -1491,9 +1578,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)); @@ -1531,17 +1622,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(); } @@ -1633,14 +1732,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) { @@ -1672,7 +1774,9 @@ static enum test_return test_ascii_mget(void) } for (uint32_t x= 0; x < nkeys; ++x) + { free(returned[x]); + } return TEST_PASS; } @@ -1724,7 +1828,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]; @@ -1739,7 +1845,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]; @@ -1813,9 +1921,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", @@ -1825,9 +1937,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)); @@ -1838,9 +1954,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; } @@ -1959,25 +2079,27 @@ int main(int argc, char **argv) struct test_type_st tests= { true, true }; int total= 0; int failed= 0; - const char *hostname= "localhost"; - const char *port= "11211"; + const char *hostname= NULL; + const char *port= MEMCACHED_DEFAULT_PORT_STRING; int cmd; bool prompt= false; const char *testname= NULL; - 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) @@ -1986,18 +2108,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" @@ -2011,23 +2144,31 @@ 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; } } + if (hostname) + { + fprintf(stderr, "No hostname was provided.\n"); + return EXIT_FAILURE; + } + initialize_sockets(); sock= connect_server(hostname, port); if (sock == INVALID_SOCKET) { fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", - hostname, port, strerror(get_socket_errno())); + hostname?:"(null)", port?:"(null)", strerror(get_socket_errno())); return EXIT_FAILURE; } 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)) @@ -2051,7 +2192,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); @@ -2065,19 +2208,30 @@ int main(int argc, char **argv) reconnect= true; ++failed; if (verbose) + { fprintf(stderr, "\n"); + } } else if (ret == TEST_PASS_RECONNECT) + { reconnect= true; + } + + if (ret == TEST_FAIL) + { + fprintf(stderr, "%s\n", status_msg[ret]); + } + else + { + fprintf(stdout, "%s\n", status_msg[ret]); + } - fprintf(stderr, "%s\n", status_msg[ret]); if (reconnect) { 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?:"(null)", port?:"(null)", strerror(get_socket_errno())); fprintf(stderr, "%d of %d tests failed\n", failed, total); return EXIT_FAILURE; } @@ -2086,9 +2240,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; }