From e097b6cf87ee49c74404642a0862171ecc605d67 Mon Sep 17 00:00:00 2001 From: Brian Aker Date: Sun, 18 Sep 2011 17:59:56 -0700 Subject: [PATCH] Add memcached_exist() --- .bzrignore | 2 + clients/include.am | 4 + clients/memexist.cc | 236 ++++++++++++++++++++++++++ docs/conf.py.in | 2 + docs/include.am | 3 +- docs/index.rst | 1 + docs/libmemcached/memcached_exist.rst | 53 ++++++ libmemcached/delete.cc | 7 +- libmemcached/exist.cc | 149 ++++++++++++++++ libmemcached/exist.h | 43 +++++ libmemcached/include.am | 2 + libmemcached/memcached.h | 1 + libmemcached/response.cc | 7 +- libmemcached/storage.cc | 4 + tests/exist.cc | 74 ++++++++ tests/exist.h | 42 +++++ tests/include.am | 9 + tests/mem_functions.cc | 5 + tests/memexist.cc | 159 +++++++++++++++++ 19 files changed, 796 insertions(+), 7 deletions(-) create mode 100644 clients/memexist.cc create mode 100644 docs/libmemcached/memcached_exist.rst create mode 100644 libmemcached/exist.cc create mode 100644 libmemcached/exist.h create mode 100644 tests/exist.cc create mode 100644 tests/exist.h create mode 100644 tests/memexist.cc diff --git a/.bzrignore b/.bzrignore index da5a7c17..763623e5 100644 --- a/.bzrignore +++ b/.bzrignore @@ -134,3 +134,5 @@ tests/memflush tests/memrm tests/memstat tests/memcat +clients/memexist +tests/memexist diff --git a/clients/include.am b/clients/include.am index 8fc8c00b..31d3c0eb 100644 --- a/clients/include.am +++ b/clients/include.am @@ -16,6 +16,7 @@ bin_PROGRAMS+= \ clients/memcp \ clients/memdump \ clients/memerror \ + clients/memexist \ clients/memflush \ clients/memparse \ clients/memping \ @@ -66,6 +67,9 @@ clients_memstat_LDADD= $(CLIENTS_LDADDS) clients_memrm_SOURCES= clients/memrm.cc clients_memrm_LDADD= $(CLIENTS_LDADDS) +clients_memexist_SOURCES= clients/memexist.cc +clients_memexist_LDADD= $(CLIENTS_LDADDS) + clients_memflush_SOURCES= clients/memflush.cc clients_memflush_LDADD= $(CLIENTS_LDADDS) diff --git a/clients/memexist.cc b/clients/memexist.cc new file mode 100644 index 00000000..20ad4850 --- /dev/null +++ b/clients/memexist.cc @@ -0,0 +1,236 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + */ +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include "client_options.h" +#include "utilities.h" + +static int opt_binary= 0; +static int opt_verbose= 0; +static char *opt_servers= NULL; +static char *opt_hash= NULL; +static char *opt_username; +static char *opt_passwd; + +#define PROGRAM_NAME "memexist" +#define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster." + +/* Prototypes */ +static void options_parse(int argc, char *argv[]); + +int main(int argc, char *argv[]) +{ + memcached_st *memc; + memcached_server_st *servers; + + options_parse(argc, argv); + initialize_sockets(); + + if (opt_servers == 0) + { + char *temp; + + if ((temp= getenv("MEMCACHED_SERVERS"))) + { + opt_servers= strdup(temp); + } + else + { + std::cerr << "No Servers provided" << std::endl; + return EXIT_FAILURE; + } + } + + memc= memcached_create(NULL); + process_hash_option(memc, opt_hash); + + servers= memcached_servers_parse(opt_servers); + memcached_server_push(memc, servers); + memcached_server_list_free(servers); + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, + (uint64_t) opt_binary); + + if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0) + { + memcached_free(memc); + std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl; + return EXIT_FAILURE; + } + + if (opt_username) + { + memcached_return_t ret; + if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd))) + { + std::cerr << memcached_last_error_message(memc) << std::endl; + memcached_free(memc); + return EXIT_FAILURE; + } + } + + int return_code= EXIT_SUCCESS; + + while (optind < argc) + { + memcached_return_t rc= memcached_exist(memc, argv[optind], strlen(argv[optind])); + + if (rc == MEMCACHED_NOTFOUND) + { + if (opt_verbose) + { + std::cout << "Could not find key \"" << argv[optind] << "\"" << std::endl; + } + + return_code= EXIT_FAILURE; + } + else if (memcached_failed(rc)) + { + if (opt_verbose) + { + std::cerr << "Fatal error for key \"" << argv[optind] << "\" :" << memcached_last_error_message(memc) << std::endl; + } + + return_code= EXIT_FAILURE; + } + else // success + { + if (opt_verbose) + { + std::cout << "Found key " << argv[optind] << std::endl; + } + } + + optind++; + } + + memcached_free(memc); + + if (opt_servers) + { + free(opt_servers); + } + + if (opt_hash) + { + free(opt_hash); + } + + return return_code; +} + + +static void options_parse(int argc, char *argv[]) +{ + memcached_programs_help_st help_options[]= + { + {0}, + }; + + static struct option long_options[]= + { + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, + {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH}, + {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY}, + {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME}, + {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD}, + {0, 0, 0, 0}, + }; + + bool opt_version= false; + bool opt_help= false; + int option_index= 0; + + while (1) + { + int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + if (option_rv == -1) + { + break; + } + + switch (option_rv) + { + case 0: + break; + + case OPT_BINARY: + opt_binary = 1; + break; + + case OPT_VERBOSE: /* --verbose or -v */ + opt_verbose = OPT_VERBOSE; + break; + + case OPT_DEBUG: /* --debug or -d */ + opt_verbose = OPT_DEBUG; + break; + + case OPT_VERSION: /* --version or -V */ + opt_version= true; + break; + + case OPT_HELP: /* --help or -h */ + opt_help= true; + break; + + case OPT_SERVERS: /* --servers or -s */ + opt_servers= strdup(optarg); + break; + + case OPT_HASH: + opt_hash= strdup(optarg); + break; + + case OPT_USERNAME: + opt_username= optarg; + break; + + case OPT_PASSWD: + opt_passwd= optarg; + break; + + case OPT_QUIET: + close_stdio(); + break; + + case '?': + /* getopt_long already printed an error message. */ + exit(EXIT_SUCCESS); + + default: + abort(); + } + } + + if (opt_version) + { + version_command(PROGRAM_NAME); + exit(EXIT_SUCCESS); + } + + if (opt_help) + { + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options); + exit(EXIT_SUCCESS); + } +} diff --git a/docs/conf.py.in b/docs/conf.py.in index 4f5a4c27..c485d77c 100644 --- a/docs/conf.py.in +++ b/docs/conf.py.in @@ -263,6 +263,8 @@ man_pages = [ ('memcached_create', 'memcached_servers_reset', u'libmemcached Documentation', [u'Brian Aker'], 3), ('memcached_delete', 'memcached_delete', u'libmemcached Documentation', [u'Brian Aker'], 3), ('memcached_delete', 'memcached_delete_by_key', u'libmemcached Documentation', [u'Brian Aker'], 3), + ('libmemcached/memcached_exist', 'memcached_exist', u'libmemcached Documentation', [u'Brian Aker'], 3), + ('libmemcached/memcached_exist', 'memcached_exist_by_key', u'libmemcached Documentation', [u'Brian Aker'], 3), ('memcached_dump', 'memcached_dump', u'libmemcached Documentation', [u'Brian Aker'], 3), ('memcached_flush', 'memcached_flush', u'libmemcached Documentation', [u'Brian Aker'], 3), ('memcached_flush_buffers', 'memcached_flush_buffers', u'libmemcached Documentation', [u'Brian Aker'], 3), diff --git a/docs/include.am b/docs/include.am index 346bfe7c..1a1feac0 100644 --- a/docs/include.am +++ b/docs/include.am @@ -54,6 +54,8 @@ man_MANS+= \ docs/man/memcached_decrement_with_initial.3 \ docs/man/memcached_delete.3 \ docs/man/memcached_delete_by_key.3 \ + docs/man/memcached_exist.3 \ + docs/man/memcached_exist_by_key.3 \ docs/man/memcached_destroy_sasl_auth_data.3 \ docs/man/memcached_dump.3 \ docs/man/memcached_fetch.3 \ @@ -124,7 +126,6 @@ man_MANS+= \ docs/man/memslap.1 \ docs/man/memstat.1 - if HAVE_SPHINX sphinx-help: @echo "Please use \`make ' where is one of" diff --git a/docs/index.rst b/docs/index.rst index 64124709..4f4ccfa3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -30,6 +30,7 @@ Working with data memcached_auto memcached_delete + libmemcached/memcached_exist memcached_flush_buffers memcached_flush memcached_get diff --git a/docs/libmemcached/memcached_exist.rst b/docs/libmemcached/memcached_exist.rst new file mode 100644 index 00000000..806efe6e --- /dev/null +++ b/docs/libmemcached/memcached_exist.rst @@ -0,0 +1,53 @@ +=========================== +Determine if a keys exists. +=========================== + +.. index:: object: memcached_st + +-------- +SYNOPSIS +-------- + + +#include + +.. c:function:: memcached_return_t memcached_exist(memcached_st *ptr, char *key, size_t *key_length) + +.. c:function:: memcached_return_t memcached_exist_by_key(memcached_st *ptr, char *group_key, size_t *group_key_length, char *key, size_t *key_length) + + .. versionadded:: 0.53 + +Compile and link with -lmemcached + + +----------- +DESCRIPTION +----------- + +:c:func:`memcached_exist()` can be used to check to see if a key exists. No value is returned if the key exists, or does not exist, on the server. + + +------ +RETURN +------ + +:c:func:`memcached_exist()` sets error to +to :c:type:`MEMCACHED_SUCCESS` upon finding that the key exists. +:c:type:`MEMCACHED_NOTFOUND` will be return if the key is not found. + + +---- +HOME +---- + +To find out more information please check: +`http://libmemcached.org/ `_ + + +-------- +SEE ALSO +-------- + +:manpage:`memcached(1)` :manpage:`libmemcached(3)` :manpage:`memcached_strerror(3)` + + diff --git a/libmemcached/delete.cc b/libmemcached/delete.cc index 7348dabe..3f1cde8a 100644 --- a/libmemcached/delete.cc +++ b/libmemcached/delete.cc @@ -70,11 +70,10 @@ memcached_return_t memcached_delete_by_key(memcached_st *ptr, rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol); - unlikely (memcached_failed(rc)) + if (memcached_failed(rc)) + { return rc; - - unlikely (memcached_server_count(ptr) == 0) - return MEMCACHED_NO_SERVERS; + } uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length); instance= memcached_server_instance_fetch(ptr, server_key); diff --git a/libmemcached/exist.cc b/libmemcached/exist.cc new file mode 100644 index 00000000..b8d4b0d8 --- /dev/null +++ b/libmemcached/exist.cc @@ -0,0 +1,149 @@ +/* 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 + +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[]= + { + { sizeof("add ") -1, "add " }, + { memcached_array_size(memc->_namespace), memcached_array_string(memc->_namespace) }, + { key_length, key }, + { sizeof(" 0") -1, " 0" }, + { sizeof(" 2678400") -1, " 2678400" }, + { sizeof(" 0") -1, " 0" }, + { 2, "\r\n" }, + { 2, "\r\n" } + }; + + /* Send command header */ + memcached_return_t rc= memcached_vdo(instance, vector, 8, 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; +} + +static memcached_return_t binary_exist(memcached_st *memc, memcached_server_write_instance_st instance, const char *key, size_t key_length) +{ + protocol_binary_request_set request= {}; + size_t send_length= sizeof(request.bytes); + + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_ADD; + request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(memc->_namespace))); + request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; + request.message.header.request.extlen= 8; + request.message.body.flags= 0; + request.message.body.expiration= htonl(2678400); + + request.message.header.request.bodylen= htonl((uint32_t) (key_length + +memcached_array_size(memc->_namespace) + +request.message.header.request.extlen)); + + struct libmemcached_io_vector_st vector[]= + { + { send_length, request.bytes }, + { memcached_array_size(memc->_namespace), memcached_array_string(memc->_namespace) }, + { key_length, key } + }; + + /* write the header */ + memcached_return_t rc; + if ((rc= memcached_vdo(instance, vector, 3, true)) != MEMCACHED_SUCCESS) + { + memcached_io_reset(instance); + return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc; + } + + rc= memcached_response(instance, NULL, 0, NULL); + + if (rc == MEMCACHED_SUCCESS) + rc= MEMCACHED_NOTFOUND; + + if (rc == MEMCACHED_DATA_EXISTS) + rc= MEMCACHED_SUCCESS; + + return rc; +} + +memcached_return_t memcached_exist(memcached_st *memc, const char *key, size_t key_length) +{ + return memcached_exist_by_key(memc, key, key_length, key, key_length); +} + +memcached_return_t memcached_exist_by_key(memcached_st *memc, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length) +{ + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(memc))) + { + return rc; + } + + if (memc->flags.use_udp) + { + 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); + + if (memc->flags.binary_protocol) + { + return binary_exist(memc, instance, key, key_length); + } + else + { + return ascii_exist(memc, instance, key, key_length); + } +} diff --git a/libmemcached/exist.h b/libmemcached/exist.h new file mode 100644 index 00000000..816fe2f8 --- /dev/null +++ b/libmemcached/exist.h @@ -0,0 +1,43 @@ +/* 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. + * + */ + +#pragma once + +memcached_return_t memcached_exist(memcached_st *memc, const char *key, size_t key_length); + +memcached_return_t memcached_exist_by_key(memcached_st *memc, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length); diff --git a/libmemcached/include.am b/libmemcached/include.am index 28456b59..5e8b32ae 100644 --- a/libmemcached/include.am +++ b/libmemcached/include.am @@ -49,6 +49,7 @@ nobase_include_HEADERS+= \ libmemcached/delete.h \ libmemcached/dump.h \ libmemcached/error.h \ + libmemcached/exist.h \ libmemcached/exception.hpp \ libmemcached/fetch.h \ libmemcached/flush.h \ @@ -102,6 +103,7 @@ libmemcached_libmemcached_la_SOURCES+= \ libmemcached/do.cc \ libmemcached/dump.cc \ libmemcached/error.cc \ + libmemcached/exist.cc \ libmemcached/fetch.cc \ libmemcached/flush.cc \ libmemcached/flush_buffers.cc \ diff --git a/libmemcached/memcached.h b/libmemcached/memcached.h index 3c29a5e1..9309d8b9 100644 --- a/libmemcached/memcached.h +++ b/libmemcached/memcached.h @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include diff --git a/libmemcached/response.cc b/libmemcached/response.cc index 74d10a96..669c633a 100644 --- a/libmemcached/response.cc +++ b/libmemcached/response.cc @@ -401,7 +401,7 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan header.response.cas= memcached_ntohll(header.response.cas); uint32_t bodylen= header.response.bodylen; - if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS || + if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS or header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) { switch (header.response.opcode) @@ -601,13 +601,15 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan case PROTOCOL_BINARY_CMD_APPENDQ: case PROTOCOL_BINARY_CMD_PREPENDQ: return binary_read_one_response(ptr, buffer, buffer_length, result); + default: break; } } rc= MEMCACHED_SUCCESS; - unlikely(header.response.status != 0) + if (header.response.status != 0) + { switch (header.response.status) { case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT: @@ -645,6 +647,7 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan rc= MEMCACHED_PROTOCOL_ERROR; break; } + } return rc; } diff --git a/libmemcached/storage.cc b/libmemcached/storage.cc index d9b5986d..703b0e30 100644 --- a/libmemcached/storage.cc +++ b/libmemcached/storage.cc @@ -126,7 +126,9 @@ static memcached_return_t memcached_send_binary(memcached_st *ptr, 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 || verb == PREPEND_OP) + { send_length -= 8; /* append & prepend does not contain extras! */ + } else { request.message.header.request.extlen= 8; @@ -138,7 +140,9 @@ static memcached_return_t memcached_send_binary(memcached_st *ptr, request.message.header.request.extlen)); if (cas) + { request.message.header.request.cas= memcached_htonll(cas); + } flush= (bool) ((server->root->flags.buffer_requests && verb == SET_OP) ? 0 : 1); diff --git a/tests/exist.cc b/tests/exist.cc new file mode 100644 index 00000000..7d1178ff --- /dev/null +++ b/tests/exist.cc @@ -0,0 +1,74 @@ +/* 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 +#include + +#include + +using namespace libtest; + +test_return_t memcached_exist_NOTFOUND(memcached_st *memc) +{ + test_compare(MEMCACHED_NOTFOUND, memcached_exist(memc, test_literal_param("frog"))); + return TEST_SUCCESS; +} + +test_return_t memcached_exist_SUCCESS(memcached_st *memc) +{ + test_compare(MEMCACHED_SUCCESS, memcached_set(memc, test_literal_param("frog"), 0, 0, 0, 0)); + test_compare(MEMCACHED_SUCCESS, memcached_exist(memc, test_literal_param("frog"))); + test_compare(MEMCACHED_SUCCESS, memcached_delete(memc, test_literal_param("frog"), 0)); + test_compare(MEMCACHED_NOTFOUND, memcached_exist(memc, test_literal_param("frog"))); + + return TEST_SUCCESS; +} + +test_return_t memcached_exist_by_key_NOTFOUND(memcached_st *memc) +{ + test_compare(MEMCACHED_NOTFOUND, memcached_exist_by_key(memc, test_literal_param("master"), test_literal_param("frog"))); + return TEST_SUCCESS; +} + +test_return_t memcached_exist_by_key_SUCCESS(memcached_st *memc) +{ + test_compare(MEMCACHED_SUCCESS, memcached_set_by_key(memc, test_literal_param("master"), test_literal_param("frog"), 0, 0, 0, 0)); + test_compare(MEMCACHED_SUCCESS, memcached_exist_by_key(memc, test_literal_param("master"), test_literal_param("frog"))); + test_compare(MEMCACHED_SUCCESS, memcached_delete_by_key(memc, test_literal_param("master"), test_literal_param("frog"), 0)); + test_compare(MEMCACHED_NOTFOUND, memcached_exist_by_key(memc, test_literal_param("master"), test_literal_param("frog"))); + + return TEST_SUCCESS; +} diff --git a/tests/exist.h b/tests/exist.h new file mode 100644 index 00000000..581932a2 --- /dev/null +++ b/tests/exist.h @@ -0,0 +1,42 @@ +/* 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. + * + */ + +#pragma once + +test_return_t memcached_exist_NOTFOUND(memcached_st *); +test_return_t memcached_exist_SUCCESS(memcached_st *); +test_return_t memcached_exist_by_key_NOTFOUND(memcached_st *); +test_return_t memcached_exist_by_key_SUCCESS(memcached_st *); diff --git a/tests/include.am b/tests/include.am index 2bbe5802..9ea0994d 100644 --- a/tests/include.am +++ b/tests/include.am @@ -25,6 +25,7 @@ noinst_HEADERS+= \ tests/basic.h \ tests/debug.h \ tests/error_conditions.h \ + tests/exist.h \ tests/hash_results.h \ tests/ketama.h \ tests/ketama_test_cases.h \ @@ -71,6 +72,7 @@ tests_testapp_SOURCES= \ tests/debug.cc \ tests/deprecated.cc \ tests/error_conditions.cc \ + tests/exist.cc \ tests/ketama.cc \ tests/mem_functions.cc \ tests/namespace.cc \ @@ -202,6 +204,13 @@ tests_memrm_LDADD= $(tests_memrm_DEPENDENCIES) check_PROGRAMS+= tests/memrm noinst_PROGRAMS+= tests/memrm +tests_memexist_SOURCES= tests/memexist.cc +tests_memexist_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) +tests_memexist_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) +tests_memexist_LDADD= $(tests_memexist_DEPENDENCIES) +check_PROGRAMS+= tests/memexist +noinst_PROGRAMS+= tests/memexist + tests_memcat_SOURCES= tests/memcat.cc tests_memcat_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) tests_memcat_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) diff --git a/tests/mem_functions.cc b/tests/mem_functions.cc index b56c47bc..965b5ec2 100644 --- a/tests/mem_functions.cc +++ b/tests/mem_functions.cc @@ -73,6 +73,7 @@ #include "tests/debug.h" #include "tests/deprecated.h" #include "tests/error_conditions.h" +#include "tests/exist.h" #include "tests/ketama.h" #include "tests/namespace.h" #include "tests/parser.h" @@ -5827,6 +5828,10 @@ test_st tests[] ={ {"test_get_last_disconnect", true, (test_callback_fn*)test_get_last_disconnect}, {"verbosity", true, (test_callback_fn*)test_verbosity}, {"memcached_stat_execute", true, (test_callback_fn*)memcached_stat_execute_test}, + {"memcached_exist(MEMCACHED_NOTFOUND)", true, (test_callback_fn*)memcached_exist_NOTFOUND }, + {"memcached_exist(MEMCACHED_SUCCESS)", true, (test_callback_fn*)memcached_exist_SUCCESS }, + {"memcached_exist_by_key(MEMCACHED_NOTFOUND)", true, (test_callback_fn*)memcached_exist_by_key_NOTFOUND }, + {"memcached_exist_by_key(MEMCACHED_SUCCESS)", true, (test_callback_fn*)memcached_exist_by_key_SUCCESS }, {0, 0, 0} }; diff --git a/tests/memexist.cc b/tests/memexist.cc new file mode 100644 index 00000000..00fc3abf --- /dev/null +++ b/tests/memexist.cc @@ -0,0 +1,159 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Test memexist + * + * 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. + * + */ + + +/* + Test that we are cycling the servers we are creating during testing. +*/ + +#include + +#include +#include + +using namespace libtest; + +#ifndef __INTEL_COMPILER +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + +static std::string executable; + +static test_return_t quiet_test(void *) +{ + const char *args[]= { "--quiet", 0 }; + + test_true(exec_cmdline(executable, args)); + return TEST_SUCCESS; +} + +static test_return_t help_test(void *) +{ + const char *args[]= { "--quiet", "--help", 0 }; + + test_true(exec_cmdline(executable, args)); + return TEST_SUCCESS; +} + +static test_return_t exist_test(void *) +{ + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port())); + const char *args[]= { "--quiet", buffer, "foo", 0 }; + + memcached_st *memc= memcached(buffer, strlen(buffer)); + test_true(memc); + + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, test_literal_param("foo"), 0, 0, 0, 0)); + + memcached_return_t rc; + test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); + test_compare(MEMCACHED_SUCCESS, rc); + + test_true(exec_cmdline(executable, args)); + + test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); + test_compare(MEMCACHED_SUCCESS, rc); + + memcached_free(memc); + + return TEST_SUCCESS; +} + +static test_return_t NOT_FOUND_test(void *) +{ + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port())); + const char *args[]= { "--quiet", buffer, "foo", 0 }; + + memcached_st *memc= memcached(buffer, strlen(buffer)); + test_true(memc); + + test_compare(MEMCACHED_SUCCESS, memcached_flush(memc, 0)); + + memcached_return_t rc; + test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); + test_compare(MEMCACHED_NOTFOUND, rc); + + test_true(exec_cmdline(executable, args)); + + test_null(memcached_get(memc, test_literal_param("foo"), 0, 0, &rc)); + test_compare(MEMCACHED_NOTFOUND, rc); + + memcached_free(memc); + + return TEST_SUCCESS; +} + +test_st memexist_tests[] ={ + {"--quiet", true, quiet_test }, + {"--help", true, help_test }, + {"exist(FOUND)", true, exist_test }, + {"exist(NOT_FOUND)", true, NOT_FOUND_test }, + {0, 0, 0} +}; + +collection_st collection[] ={ + {"memexist", 0, 0, memexist_tests }, + {0, 0, 0, 0} +}; + +static void *world_create(server_startup_st& servers, test_return_t& error) +{ + if (HAVE_MEMCACHED_BINARY == 0) + { + error= TEST_FATAL; + return NULL; + } + + const char *argv[1]= { "memexist" }; + if (not server_startup(servers, "memcached", MEMCACHED_DEFAULT_PORT +10, 1, argv)) + { + error= TEST_FAILURE; + } + + return &servers; +} + + +void get_world(Framework *world) +{ + executable= "./clients/memexist"; + world->collections= collection; + world->_create= world_create; +} + -- 2.30.2