From: Brian Aker Date: Wed, 5 Oct 2011 21:41:46 +0000 (-0700) Subject: Merge in touch. X-Git-Tag: 1.0.2~9^2~2^2 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=afddcf83538afc8300886702fcddf2333eb94c1f;p=m6w6%2Flibmemcached Merge in touch. --- diff --git a/.bzrignore b/.bzrignore index 3333d5f8..dedeb4cb 100644 --- a/.bzrignore +++ b/.bzrignore @@ -137,3 +137,5 @@ tests/memcat clients/memexist tests/memexist libmemcached/configure.h +clients/memtouch +tests/memtouch diff --git a/clients/include.am b/clients/include.am index 31d3c0eb..bb35bdf5 100644 --- a/clients/include.am +++ b/clients/include.am @@ -17,6 +17,7 @@ bin_PROGRAMS+= \ clients/memdump \ clients/memerror \ clients/memexist \ + clients/memtouch \ clients/memflush \ clients/memparse \ clients/memping \ @@ -70,6 +71,9 @@ clients_memrm_LDADD= $(CLIENTS_LDADDS) clients_memexist_SOURCES= clients/memexist.cc clients_memexist_LDADD= $(CLIENTS_LDADDS) +clients_memtouch_SOURCES= clients/memtouch.cc +clients_memtouch_LDADD= $(CLIENTS_LDADDS) + clients_memflush_SOURCES= clients/memflush.cc clients_memflush_LDADD= $(CLIENTS_LDADDS) diff --git a/clients/memtouch.cc b/clients/memtouch.cc new file mode 100644 index 00000000..4f3be80e --- /dev/null +++ b/clients/memtouch.cc @@ -0,0 +1,241 @@ +/* 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 + +#include +#include +#include +#include +#include +#include + +#include "utilities.h" + +#define PROGRAM_NAME "memtouch" +#define PROGRAM_DESCRIPTION "Update the expiration value of an alreasy existing value in the sever" + + +/* Prototypes */ +void options_parse(int argc, char *argv[]); + +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; + +time_t expiration= 0; + +int main(int argc, char *argv[]) +{ + int return_code= EXIT_SUCCESS; + + options_parse(argc, argv); + initialize_sockets(); + + if (opt_servers == NULL) + { + char *temp; + + if ((temp= getenv("MEMCACHED_SERVERS"))) + { + opt_servers= strdup(temp); + } + else + { + std::cerr << "No Servers provided" << std::endl; + return EXIT_FAILURE; + } + } + + memcached_st *memc= memcached_create(NULL); + process_hash_option(memc, opt_hash); + + memcached_server_st *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; + } + } + + while (optind < argc) + { + memcached_return_t rc= memcached_touch(memc, argv[optind], strlen(argv[optind]), expiration); + 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; +} + + +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}, + {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE}, + {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 = true; + 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_EXPIRE: + expiration= time_t(strtoul(optarg, (char **)NULL, 10)); + break; + + case OPT_QUIET: + close_stdio(); + break; + + case '?': + /* getopt_long already printed an error message. */ + exit(EXIT_FAILURE); + + 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/libmemcached-1.0/include.am b/libmemcached-1.0/include.am index e9658ad1..39313c2c 100644 --- a/libmemcached-1.0/include.am +++ b/libmemcached-1.0/include.am @@ -39,6 +39,7 @@ nobase_include_HEADERS+= \ libmemcached-1.0/storage.h \ libmemcached-1.0/strerror.h \ libmemcached-1.0/string.h \ + libmemcached-1.0/touch.h \ libmemcached-1.0/types.h \ libmemcached-1.0/verbosity.h \ libmemcached-1.0/version.h \ diff --git a/libmemcached-1.0/memcached.h b/libmemcached-1.0/memcached.h index d459d2c5..f97d333a 100644 --- a/libmemcached-1.0/memcached.h +++ b/libmemcached-1.0/memcached.h @@ -80,6 +80,7 @@ #include #include #include +#include #include #include #include diff --git a/libmemcached-1.0/touch.h b/libmemcached-1.0/touch.h new file mode 100644 index 00000000..e143c037 --- /dev/null +++ b/libmemcached-1.0/touch.h @@ -0,0 +1,59 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached library + * + * Copyright (C) 2011 Data Differential, http://datadifferential.com/ + * Copyright (C) 2010 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. + * + */ + + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + +LIBMEMCACHED_API +memcached_return_t memcached_touch(memcached_st *ptr, + const char *key, size_t key_length, + time_t expiration); + +LIBMEMCACHED_API +memcached_return_t memcached_touch_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + time_t expiration); + +#ifdef __cplusplus +} +#endif diff --git a/libmemcached/do.cc b/libmemcached/do.cc index 5e9e65f2..551b28ea 100644 --- a/libmemcached/do.cc +++ b/libmemcached/do.cc @@ -14,12 +14,10 @@ memcached_return_t memcached_do(memcached_server_write_instance_st ptr, const void *command, size_t command_length, bool with_flush) { - memcached_return_t rc; - ssize_t sent_length; - - WATCHPOINT_ASSERT(command_length); - WATCHPOINT_ASSERT(command); + 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))) { WATCHPOINT_ASSERT(rc == memcached_last_error(ptr->root)); @@ -37,9 +35,9 @@ memcached_return_t memcached_do(memcached_server_write_instance_st ptr, const vo memcached_io_write(ptr, NULL, 0, true); } - sent_length= memcached_io_write(ptr, command, command_length, with_flush); + ssize_t sent_length= memcached_io_write(ptr, command, command_length, with_flush); - if (sent_length == -1 || (size_t)sent_length != command_length) + if (sent_length == -1 or size_t(sent_length) != command_length) { rc= MEMCACHED_WRITE_FAILURE; } @@ -56,7 +54,6 @@ memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr, bool with_flush) { memcached_return_t rc; - ssize_t sent_length; WATCHPOINT_ASSERT(count); WATCHPOINT_ASSERT(vector); @@ -78,7 +75,7 @@ memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr, memcached_io_write(ptr, NULL, 0, true); } - sent_length= memcached_io_writev(ptr, vector, count, with_flush); + ssize_t sent_length= memcached_io_writev(ptr, vector, count, with_flush); size_t command_length= 0; for (uint32_t x= 0; x < count; ++x, vector++) diff --git a/libmemcached/error.cc b/libmemcached/error.cc index 85ce84e8..e22871cd 100644 --- a/libmemcached/error.cc +++ b/libmemcached/error.cc @@ -58,10 +58,12 @@ static void _set(memcached_server_st& server, memcached_st& memc) } if (memc.error_messages == NULL) + { return; + } memcached_error_t *error= (struct memcached_error_t *)libmemcached_malloc(&memc, sizeof(struct memcached_error_t)); - if (not error) // Bad business if this happens + if (error == NULL) // Bad business if this happens { return; } @@ -73,7 +75,6 @@ static void _set(memcached_server_st& server, memcached_st& memc) static void _set(memcached_st& memc, memcached_string_t *str, memcached_return_t &rc, const char *at, int local_errno= 0) { - (void)at; if (memc.error_messages && memc.error_messages->query_id != memc.query_id) { memcached_error_free(memc); @@ -112,8 +113,10 @@ static void _set(memcached_st& memc, memcached_string_t *str, memcached_return_t } memcached_error_t *error= (struct memcached_error_t *)libmemcached_malloc(&memc, sizeof(struct memcached_error_t)); - if (not error) // Bad business if this happens + if (error == NULL) // Bad business if this happens + { return; + } error->root= &memc; error->query_id= memc.query_id; @@ -190,7 +193,9 @@ memcached_return_t memcached_set_error(memcached_st& memc, memcached_return_t rc { assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client"); if (memcached_success(rc)) - return MEMCACHED_SUCCESS; + { + return rc; + } _set(memc, &str, rc, at); @@ -216,7 +221,9 @@ memcached_return_t memcached_set_error(memcached_server_st& self, memcached_retu assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client"); assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_server_st"); if (memcached_success(rc)) - return MEMCACHED_SUCCESS; + { + return rc; + } char hostname_port_message[MAX_ERROR_LENGTH]; int size; @@ -234,29 +241,37 @@ memcached_return_t memcached_set_error(memcached_server_st& self, memcached_retu memcached_string_t error_host= { hostname_port_message, size }; - if (not self.root) + assert(self.root); + if (self.root == NULL) + { return rc; + } _set(*self.root, &error_host, rc, at); _set(self, (*self.root)); + assert(self.root->error_messages); + assert(self.error_messages); return rc; } memcached_return_t memcached_set_error(memcached_server_st& self, memcached_return_t rc, const char *at) { - assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client"); assert_msg(rc != MEMCACHED_SOME_ERRORS, "Programmer error, MEMCACHED_SOME_ERRORS was about to be set on a memcached_server_st"); if (memcached_success(rc)) - return MEMCACHED_SUCCESS; + { + return rc; + } char hostname_port[NI_MAXHOST +NI_MAXSERV + sizeof("host : ")]; int size= snprintf(hostname_port, sizeof(hostname_port), "host: %s:%d", self.hostname, int(self.port)); memcached_string_t error_host= { hostname_port, size}; - if (not self.root) + if (self.root == NULL) + { return rc; + } _set(*self.root, &error_host, rc, at); _set(self, *self.root); @@ -268,7 +283,9 @@ memcached_return_t memcached_set_error(memcached_st& self, memcached_return_t rc { assert_msg(rc != MEMCACHED_ERRNO, "Programmer error, MEMCACHED_ERRNO was set to be returned to client"); if (memcached_success(rc)) - return MEMCACHED_SUCCESS; + { + return rc; + } _set(self, NULL, rc, at); @@ -289,8 +306,10 @@ memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errn memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, const char *at) { - if (not local_errno) + if (local_errno == 0) + { return MEMCACHED_SUCCESS; + } memcached_return_t rc= MEMCACHED_ERRNO; _set(self, NULL, rc, at, local_errno); @@ -300,8 +319,10 @@ memcached_return_t memcached_set_errno(memcached_st& self, int local_errno, cons memcached_return_t memcached_set_errno(memcached_st& memc, int local_errno, const char *at, memcached_string_t& str) { - if (not local_errno) + if (local_errno == 0) + { return MEMCACHED_SUCCESS; + } memcached_return_t rc= MEMCACHED_ERRNO; _set(memc, &str, rc, at, local_errno); @@ -311,8 +332,10 @@ memcached_return_t memcached_set_errno(memcached_st& memc, int local_errno, cons memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at, memcached_string_t& str) { - if (not local_errno) + if (local_errno == 0) + { return MEMCACHED_SUCCESS; + } char hostname_port_message[MAX_ERROR_LENGTH]; int size; @@ -342,8 +365,10 @@ memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errn memcached_return_t memcached_set_errno(memcached_server_st& self, int local_errno, const char *at) { - if (not local_errno) + if (local_errno == 0) + { return MEMCACHED_SUCCESS; + } char hostname_port_message[MAX_ERROR_LENGTH]; int size = snprintf(hostname_port_message, sizeof(hostname_port_message), "host: %s:%d", @@ -391,7 +416,9 @@ void memcached_error_print(const memcached_st *self) static void _error_free(memcached_error_t *error) { if (not error) + { return; + } _error_free(error->next); @@ -424,11 +451,15 @@ const char *memcached_last_error_message(memcached_st *memc) return memcached_strerror(memc, MEMCACHED_INVALID_ARGUMENTS); } - if (not memc->error_messages) + if (memc->error_messages == NULL) + { return memcached_strerror(memc, MEMCACHED_SUCCESS); + } - if (not memc->error_messages->size) + if (memc->error_messages->size == 0) + { return memcached_strerror(memc, memc->error_messages->rc); + } return memc->error_messages->message; } diff --git a/libmemcached/hosts.cc b/libmemcached/hosts.cc index 179b7c29..30456559 100644 --- a/libmemcached/hosts.cc +++ b/libmemcached/hosts.cc @@ -362,9 +362,9 @@ static memcached_return_t server_add(memcached_st *ptr, memcached_server_st *new_host_list= static_cast(libmemcached_realloc(ptr, memcached_server_list(ptr), sizeof(memcached_server_st) * (ptr->number_of_hosts + 1))); - if (not new_host_list) + if (new_host_list == NULL) { - return MEMCACHED_MEMORY_ALLOCATION_FAILURE; + return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT); } memcached_server_list_set(ptr, new_host_list); @@ -372,7 +372,7 @@ static memcached_return_t server_add(memcached_st *ptr, /* TODO: Check return type */ memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr)); - if (not __server_create_with(ptr, instance, hostname, port, weight, type)) + if (__server_create_with(ptr, instance, hostname, port, weight, type) == NULL) { return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT); } diff --git a/libmemcached/include.am b/libmemcached/include.am index 03a327da..e3f5fa3f 100644 --- a/libmemcached/include.am +++ b/libmemcached/include.am @@ -68,6 +68,7 @@ libmemcached_libmemcached_la_SOURCES+= \ libmemcached/flush.cc \ libmemcached/flush_buffers.cc \ libmemcached/get.cc \ + libmemcached/touch.cc \ libmemcached/hash.cc \ libmemcached/hosts.cc \ libmemcached/initialize_query.cc \ diff --git a/libmemcached/initialize_query.cc b/libmemcached/initialize_query.cc index 027b1566..5950158b 100644 --- a/libmemcached/initialize_query.cc +++ b/libmemcached/initialize_query.cc @@ -38,7 +38,7 @@ memcached_return_t initialize_query(memcached_st *self) { - if (not self) + if (self == NULL) { return MEMCACHED_INVALID_ARGUMENTS; } diff --git a/libmemcached/libmemcached_probes.d b/libmemcached/libmemcached_probes.d index 1163b524..28d8402e 100644 --- a/libmemcached/libmemcached_probes.d +++ b/libmemcached/libmemcached_probes.d @@ -19,6 +19,8 @@ provider libmemcached { probe memcached_replace_end(); probe memcached_get_start(); probe memcached_get_end(); + probe memcached_touch_start(); + probe memcached_touch_end(); probe memcached_mget_start(); probe memcached_mget_end(); probe memcached_connect_start(); diff --git a/libmemcached/libmemcached_probes.h b/libmemcached/libmemcached_probes.h index e9a649d1..9dba8aa1 100644 --- a/libmemcached/libmemcached_probes.h +++ b/libmemcached/libmemcached_probes.h @@ -1,5 +1,5 @@ /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: - * + * * Libmemcached library * * Copyright (C) 2011 Data Differential, http://datadifferential.com/ @@ -86,6 +86,10 @@ #define LIBMEMCACHED_MEMCACHED_GET_END_ENABLED() (0) #define LIBMEMCACHED_MEMCACHED_GET_START() #define LIBMEMCACHED_MEMCACHED_GET_START_ENABLED() (0) +#define LIBMEMCACHED_MEMCACHED_TOUCH_END() +#define LIBMEMCACHED_MEMCACHED_TOUCH_END_ENABLED() (0) +#define LIBMEMCACHED_MEMCACHED_TOUCH_START() +#define LIBMEMCACHED_MEMCACHED_TOUCH_START_ENABLED() (0) #define LIBMEMCACHED_MEMCACHED_INCREMENT_END() #define LIBMEMCACHED_MEMCACHED_INCREMENT_END_ENABLED() (0) #define LIBMEMCACHED_MEMCACHED_INCREMENT_START() diff --git a/libmemcached/memcached.h b/libmemcached/memcached.h index 9a1f1812..a45077ee 100644 --- a/libmemcached/memcached.h +++ b/libmemcached/memcached.h @@ -1,5 +1,5 @@ /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: - * + * * Libmemcached library * * Copyright (C) 2011 Data Differential, http://datadifferential.com/ diff --git a/libmemcached/memcached/protocol_binary.h b/libmemcached/memcached/protocol_binary.h index 7a253ae7..ad6202e8 100644 --- a/libmemcached/memcached/protocol_binary.h +++ b/libmemcached/memcached/protocol_binary.h @@ -122,6 +122,8 @@ extern "C" PROTOCOL_BINARY_CMD_TOUCH = 0x1c, PROTOCOL_BINARY_CMD_GAT = 0x1d, PROTOCOL_BINARY_CMD_GATQ = 0x1e, + PROTOCOL_BINARY_CMD_GATK = 0x23, + PROTOCOL_BINARY_CMD_GATKQ = 0x24, PROTOCOL_BINARY_CMD_SASL_LIST_MECHS = 0x20, PROTOCOL_BINARY_CMD_SASL_AUTH = 0x21, diff --git a/libmemcached/response.cc b/libmemcached/response.cc index adecd6e1..061f7401 100644 --- a/libmemcached/response.cc +++ b/libmemcached/response.cc @@ -1,5 +1,5 @@ /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: - * + * * Libmemcached library * * Copyright (C) 2011 Data Differential, http://datadifferential.com/ @@ -71,7 +71,9 @@ memcached_return_t memcached_read_one_response(memcached_server_write_instance_s rc == MEMCACHED_PROTOCOL_ERROR or rc == MEMCACHED_CLIENT_ERROR or rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE) + { memcached_io_reset(ptr); + } return rc; } @@ -124,7 +126,9 @@ static memcached_return_t textual_value_fetch(memcached_server_write_instance_st ssize_t read_length= 0; if (ptr->root->flags.use_udp) + { return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT); + } WATCHPOINT_ASSERT(ptr->root); end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE; @@ -280,6 +284,7 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta } case 'O': /* OK */ return MEMCACHED_SUCCESS; + case 'S': /* STORED STATS SERVER_ERROR */ { if (buffer[2] == 'A') /* STORED STATS */ @@ -328,9 +333,13 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta case 'N': /* NOT_FOUND */ { if (buffer[4] == 'F') + { return MEMCACHED_NOTFOUND; + } else if (buffer[4] == 'S') + { return MEMCACHED_NOTSTORED; + } else { WATCHPOINT_STRING(buffer); @@ -340,11 +349,17 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta case 'E': /* PROTOCOL ERROR or END */ { if (buffer[1] == 'N') + { return MEMCACHED_END; + } else if (buffer[1] == 'R') + { return MEMCACHED_PROTOCOL_ERROR; + } else if (buffer[1] == 'X') + { return MEMCACHED_DATA_EXISTS; + } else { WATCHPOINT_STRING(buffer); @@ -352,12 +367,25 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta } } + 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') + { + return MEMCACHED_SUCCESS; + } + } + return MEMCACHED_UNKNOWN_READ_FAILURE; + 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 'C': /* CLIENT ERROR */ return MEMCACHED_CLIENT_ERROR; + default: { unsigned long long auto_return_value; @@ -511,15 +539,18 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan case PROTOCOL_BINARY_CMD_APPEND: case PROTOCOL_BINARY_CMD_PREPEND: case PROTOCOL_BINARY_CMD_DELETE: + case PROTOCOL_BINARY_CMD_TOUCH: { WATCHPOINT_ASSERT(bodylen == 0); return MEMCACHED_SUCCESS; } + case PROTOCOL_BINARY_CMD_NOOP: { WATCHPOINT_ASSERT(bodylen == 0); return MEMCACHED_END; } + case PROTOCOL_BINARY_CMD_STAT: { if (bodylen == 0) diff --git a/libmemcached/server.cc b/libmemcached/server.cc index b9151283..c9c5ffca 100644 --- a/libmemcached/server.cc +++ b/libmemcached/server.cc @@ -124,7 +124,7 @@ memcached_server_st *__server_create_with(memcached_st *memc, self= _server_create(self, memc); - if (not self) + if (self == NULL) { return NULL; } @@ -166,8 +166,10 @@ void __server_free(memcached_server_st *self) void memcached_server_free(memcached_server_st *self) { - if (not self) + if (self == NULL) + { return; + } if (memcached_server_list_count(self)) { @@ -185,7 +187,7 @@ memcached_server_st *memcached_server_clone(memcached_server_st *destination, memcached_server_st *source) { /* We just do a normal create if source is missing */ - if (not source) + if (source == NULL) { return NULL; } @@ -263,12 +265,14 @@ memcached_server_instance_st memcached_server_by_key(memcached_st *ptr, size_t key_length, memcached_return_t *error) { - memcached_return_t rc; memcached_return_t unused; - if (not error) + { error= &unused; + } + + memcached_return_t rc; if (memcached_failed(rc= initialize_const_query(ptr))) { *error= rc; diff --git a/libmemcached/touch.cc b/libmemcached/touch.cc new file mode 100644 index 00000000..1107139d --- /dev/null +++ b/libmemcached/touch.cc @@ -0,0 +1,148 @@ +/* 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. + * + */ + +#include +#include + +static memcached_return_t ascii_touch(memcached_server_write_instance_st instance, + const char *key, size_t key_length, + time_t expiration) +{ + char buffer[21]; + + int buffer_length= snprintf(buffer, sizeof(buffer), " %u", uint32_t(expiration)); + struct libmemcached_io_vector_st vector[]= + { + { memcached_literal_param("touch ") }, + { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) }, + { key, key_length }, + { buffer, buffer_length }, + { memcached_literal_param("\r\n") } + }; + + memcached_return_t rc; + if (memcached_failed(rc= memcached_vdo(instance, vector, 5, true))) + { + memcached_io_reset(instance); + return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); + } + + return rc; +} + +static memcached_return_t binary_touch(memcached_server_write_instance_st instance, + const char *key, size_t key_length, + time_t expiration) +{ + protocol_binary_request_touch request= {}; //{.bytes= {0}}; + request.message.header.request.magic= PROTOCOL_BINARY_REQ; + request.message.header.request.opcode= PROTOCOL_BINARY_CMD_TOUCH; + request.message.header.request.extlen= 4; + 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(instance->root->_namespace) +request.message.header.request.extlen)); + request.message.body.expiration= htonl((uint32_t) expiration); + + struct libmemcached_io_vector_st vector[]= + { + { 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))) + { + memcached_io_reset(instance); + return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT); + } + + return rc; +} + +memcached_return_t memcached_touch(memcached_st *ptr, + const char *key, size_t key_length, + time_t expiration) +{ + return memcached_touch_by_key(ptr, key, key_length, key, key_length, expiration); +} + +memcached_return_t memcached_touch_by_key(memcached_st *ptr, + const char *group_key, size_t group_key_length, + const char *key, size_t key_length, + time_t expiration) +{ + LIBMEMCACHED_MEMCACHED_TOUCH_START(); + + memcached_return_t rc; + if (memcached_failed(rc= initialize_query(ptr))) + { + return rc; + } + + if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol))) + { + 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); + + if (ptr->flags.binary_protocol) + { + rc= binary_touch(instance, key, key_length, expiration); + } + else + { + rc= ascii_touch(instance, key, key_length, expiration); + } + + if (memcached_failed(rc)) + { + return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while writing touch command to server")); + } + + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; + rc= memcached_read_one_response(instance, buffer, sizeof(buffer), NULL); + + if (rc == MEMCACHED_SUCCESS or rc == MEMCACHED_NOTFOUND) + { + return rc; + } + + return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while reading response")); +} diff --git a/libmemcached/version.cc b/libmemcached/version.cc index abb72005..b70cf672 100644 --- a/libmemcached/version.cc +++ b/libmemcached/version.cc @@ -46,88 +46,100 @@ 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; - - memcached_return_t rc; + } 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) { - size_t send_length; - memcached_return_t rc; - char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; - char *response_ptr; - const char *command= "version\r\n"; - - send_length= sizeof("version\r\n") -1; - - rc= MEMCACHED_SUCCESS; + memcached_return_t rc= MEMCACHED_SUCCESS; for (uint32_t x= 0; x < memcached_server_count(ptr); x++) { - memcached_return_t rrc; - memcached_server_write_instance_st instance= - memcached_server_instance_fetch(ptr, x); + memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x); // Optimization, we only fetch version once. if (instance->major_version != UINT8_MAX) + { continue; + } - rrc= memcached_do(instance, command, send_length, true); - if (rrc != MEMCACHED_SUCCESS) + memcached_return_t rrc= memcached_do(instance, memcached_literal_param("version\r\n"), true); + if (memcached_failed(rrc)) { + (void)memcached_set_error(*instance, rrc, MEMCACHED_AT); instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; rc= MEMCACHED_SOME_ERRORS; continue; } + char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL); - if (rrc != MEMCACHED_SUCCESS) + if (memcached_failed(rrc)) { + memcached_set_error(*instance, rrc, MEMCACHED_AT); instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; rc= MEMCACHED_SOME_ERRORS; continue; } /* Find the space, and then move one past it to copy version */ - response_ptr= index(buffer, ' '); + char *response_ptr= index(buffer, ' '); response_ptr++; - instance->major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10); - if (errno == ERANGE) + long int version= strtol(response_ptr, (char **)NULL, 10); + if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX or version == 0) { + memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version")); instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; rc= MEMCACHED_SOME_ERRORS; continue; } + instance->major_version= uint8_t(version); response_ptr= index(response_ptr, '.'); response_ptr++; - instance->minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10); - if (errno == ERANGE) + version= strtol(response_ptr, (char **)NULL, 10); + if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX) { + memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse minor version")); instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; rc= MEMCACHED_SOME_ERRORS; continue; } + instance->minor_version= uint8_t(version); response_ptr= index(response_ptr, '.'); response_ptr++; - instance->micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10); - if (errno == ERANGE) + + version= strtol(response_ptr, (char **)NULL, 10); + if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX) { + memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version")); instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; rc= MEMCACHED_SOME_ERRORS; continue; } + instance->micro_version= uint8_t(version); } return rc; @@ -135,25 +147,23 @@ static inline memcached_return_t memcached_version_textual(memcached_st *ptr) static inline memcached_return_t memcached_version_binary(memcached_st *ptr) { - memcached_return_t rc; protocol_binary_request_version request= {}; request.message.header.request.magic= PROTOCOL_BINARY_REQ; request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION; request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; - rc= MEMCACHED_SUCCESS; + memcached_return_t rc= MEMCACHED_SUCCESS; for (uint32_t x= 0; x < memcached_server_count(ptr); x++) { - memcached_return_t rrc; - - 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) + { continue; + } - rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true); - if (rrc != MEMCACHED_SUCCESS) + memcached_return_t rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true); + if (memcached_failed(rrc)) { memcached_io_reset(instance); rc= MEMCACHED_SOME_ERRORS; @@ -167,46 +177,52 @@ static inline memcached_return_t memcached_version_binary(memcached_st *ptr) memcached_server_instance_fetch(ptr, x); if (instance->major_version != UINT8_MAX) + { continue; + } if (memcached_server_response_count(instance) > 0) { - memcached_return_t rrc; char buffer[32]; char *p; - rrc= memcached_response(instance, buffer, sizeof(buffer), NULL); - if (rrc != MEMCACHED_SUCCESS) + memcached_return_t rrc= memcached_response(instance, buffer, sizeof(buffer), NULL); + if (memcached_failed(rrc)) { memcached_io_reset(instance); rc= MEMCACHED_SOME_ERRORS; continue; } - instance->major_version= (uint8_t)strtol(buffer, &p, 10); - if (errno == ERANGE) + long int version= strtol(buffer, &p, 10); + if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX or version == 0) { + memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse major version")); instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; rc= MEMCACHED_SOME_ERRORS; continue; } + instance->major_version= uint8_t(version); - instance->minor_version= (uint8_t)strtol(p + 1, &p, 10); - if (errno == ERANGE) + version= strtol(p +1, &p, 10); + if (version == LONG_MIN or version == LONG_MAX or errno == EINVAL or version > UINT8_MAX) { + memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version")); instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; rc= MEMCACHED_SOME_ERRORS; continue; } + instance->minor_version= uint8_t(version); - instance->micro_version= (uint8_t)strtol(p + 1, NULL, 10); + version= strtol(p + 1, NULL, 10); if (errno == ERANGE) { + memcached_set_error(*instance, MEMCACHED_PROTOCOL_ERROR, MEMCACHED_AT, memcached_literal_param("strtol() failed to parse micro version")); instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX; rc= MEMCACHED_SOME_ERRORS; continue; } - + instance->micro_version= uint8_t(version); } } diff --git a/libmemcachedutil/version.cc b/libmemcachedutil/version.cc index abfd47f7..15f888b8 100644 --- a/libmemcachedutil/version.cc +++ b/libmemcachedutil/version.cc @@ -37,6 +37,7 @@ #include +#include struct local_context { @@ -55,8 +56,8 @@ static memcached_return_t check_server_version(const memcached_st *, struct local_context *check= (struct local_context *)context; if (instance->major_version != UINT8_MAX && - instance->major_version >= check->major_version && - instance->minor_version >= check->minor_version && + instance->major_version >= check->major_version and + instance->minor_version >= check->minor_version and instance->micro_version >= check->micro_version ) { return MEMCACHED_SUCCESS; @@ -72,8 +73,10 @@ bool libmemcached_util_version_check(memcached_st *memc, uint8_t minor_version, uint8_t micro_version) { - if (memcached_version(memc) != MEMCACHED_SUCCESS) + if (memcached_failed(memcached_version(memc))) + { return false; + } struct local_context check= { major_version, minor_version, micro_version, true }; diff --git a/m4/progtest.m4 b/m4/progtest.m4 deleted file mode 100644 index 2d804ac9..00000000 --- a/m4/progtest.m4 +++ /dev/null @@ -1,92 +0,0 @@ -# progtest.m4 serial 6 (gettext-0.18) -dnl Copyright (C) 1996-2003, 2005, 2008-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. -dnl -dnl This file can can be used in projects which are not available under -dnl the GNU General Public License or the GNU Library General Public -dnl License but which still want to provide support for the GNU gettext -dnl functionality. -dnl Please note that the actual code of the GNU gettext library is covered -dnl by the GNU Library General Public License, and the rest of the GNU -dnl gettext package package is covered by the GNU General Public License. -dnl They are *not* in the public domain. - -dnl Authors: -dnl Ulrich Drepper , 1996. - -AC_PREREQ([2.50]) - -# Search path for a program which passes the given test. - -dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, -dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) -AC_DEFUN([AM_PATH_PROG_WITH_TEST], -[ -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi - -# Find out how to test for executable files. Don't use a zero-byte file, -# as systems may use methods other than mode bits to determine executability. -cat >conf$$.file <<_ASEOF -#! /bin/sh -exit 0 -_ASEOF -chmod +x conf$$.file -if test -x conf$$.file >/dev/null 2>&1; then - ac_executable_p="test -x" -else - ac_executable_p="test -f" -fi -rm -f conf$$.file - -# Extract the first word of "$2", so it can be a program name with args. -set dummy $2; ac_word=[$]2 -AC_MSG_CHECKING([for $ac_word]) -AC_CACHE_VAL([ac_cv_path_$1], -[case "[$]$1" in - [[\\/]]* | ?:[[\\/]]*) - ac_cv_path_$1="[$]$1" # Let the user override the test with a path. - ;; - *) - ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in ifelse([$5], , $PATH, [$5]); do - IFS="$ac_save_IFS" - test -z "$ac_dir" && ac_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then - echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD - if [$3]; then - ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" - break 2 - fi - fi - done - done - IFS="$ac_save_IFS" -dnl If no 4th arg is given, leave the cache variable unset, -dnl so AC_PATH_PROGS will keep looking. -ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" -])dnl - ;; -esac])dnl -$1="$ac_cv_path_$1" -if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then - AC_MSG_RESULT([$][$1]) -else - AC_MSG_RESULT([no]) -fi -AC_SUBST([$1])dnl -]) diff --git a/support/libmemcached.spec.in b/support/libmemcached.spec.in index c6a6e727..449ee0b3 100644 --- a/support/libmemcached.spec.in +++ b/support/libmemcached.spec.in @@ -28,6 +28,8 @@ memslap - Generate testing loads on a memcached cluster. memcp - Copy files to memcached servers. memerror - Creates human readable messages from libmemecached error codes. memcapable - Verify a memcached server for protocol behavior. +memexist - Check for the existance of a key. +memtouch - Update the expiration value of a key. %package devel @@ -151,6 +153,7 @@ you will need to install %{name}-devel. %{_includedir}/libmemcached-1.0/dump.h %{_includedir}/libmemcached-1.0/error.h %{_includedir}/libmemcached-1.0/exist.h +%{_includedir}/libmemcached-1.0/touch.h %{_includedir}/libmemcached-1.0/exception.hpp %{_includedir}/libmemcached-1.0/fetch.h %{_includedir}/libmemcached-1.0/flush.h @@ -281,6 +284,8 @@ you will need to install %{name}-devel. %{_mandir}/man3/memcached_strerror.3.gz %{_mandir}/man3/memcached_exist.3.gz %{_mandir}/man3/memcached_exist_by_key.3.gz +%{_mandir}/man3/memcached_touch.3.gz +%{_mandir}/man3/memcached_touch_by_key.3.gz %{_mandir}/man3/memcached_verbosity.3.gz %{_mandir}/man3/memcached_version.3.gz diff --git a/tests/include.am b/tests/include.am index a4cf4c6a..b51dc2c3 100644 --- a/tests/include.am +++ b/tests/include.am @@ -34,6 +34,7 @@ noinst_HEADERS+= \ tests/libmemcached_world.h \ tests/namespace.h \ tests/parser.h \ + tests/touch.h \ tests/deprecated.h \ tests/pool.h \ tests/print.h \ @@ -78,6 +79,7 @@ tests_testapp_SOURCES= \ tests/mem_functions.cc \ tests/namespace.cc \ tests/parser.cc \ + tests/touch.cc \ tests/callbacks.cc \ tests/pool.cc \ tests/print.cc \ @@ -173,71 +175,78 @@ noinst_PROGRAMS+= tests/hash_plus tests_memcapable_SOURCES= tests/memcapable.cc tests_memcapable_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_memcapable_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) -tests_memcapable_LDADD= $(tests_memcapable_DEPENDENCIES) +tests_memcapable_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memcapable +tests_memcapable_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memcapable noinst_PROGRAMS+= tests/memcapable tests_memstat_SOURCES= tests/memstat.cc tests_memstat_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_memstat_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) -tests_memstat_LDADD= $(tests_memstat_DEPENDENCIES) +tests_memstat_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memstat +tests_memstat_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memstat noinst_PROGRAMS+= tests/memstat tests_memcp_SOURCES= tests/memcp.cc tests_memcp_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_memcp_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) -tests_memcp_LDADD= $(tests_memcp_DEPENDENCIES) +tests_memcp_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memcp +tests_memcp_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memcp noinst_PROGRAMS+= tests/memcp tests_memflush_SOURCES= tests/memflush.cc tests_memflush_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_memflush_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) -tests_memflush_LDADD= $(tests_memflush_DEPENDENCIES) +tests_memflush_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memflush +tests_memflush_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memflush noinst_PROGRAMS+= tests/memflush tests_memrm_SOURCES= tests/memrm.cc tests_memrm_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_memrm_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) -tests_memrm_LDADD= $(tests_memrm_DEPENDENCIES) +tests_memrm_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memrm +tests_memrm_LDADD= libtest/libtest.la $(TESTS_LDADDS) 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) +tests_memexist_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memexist +tests_memexist_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memexist noinst_PROGRAMS+= tests/memexist +tests_memtouch_SOURCES= tests/memtouch.cc +tests_memtouch_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) +tests_memtouch_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memtouch +tests_memtouch_LDADD= libtest/libtest.la $(TESTS_LDADDS) +check_PROGRAMS+= tests/memtouch +noinst_PROGRAMS+= tests/memtouch + tests_memcat_SOURCES= tests/memcat.cc tests_memcat_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_memcat_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) -tests_memcat_LDADD= $(tests_memcat_DEPENDENCIES) +tests_memcat_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memcat +tests_memcat_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memcat noinst_PROGRAMS+= tests/memcat tests_memerror_SOURCES= tests/memerror.cc tests_memerror_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_memerror_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) -tests_memerror_LDADD= $(tests_memerror_DEPENDENCIES) +tests_memerror_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memerror +tests_memerror_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memerror noinst_PROGRAMS+= tests/memerror tests_memslap_SOURCES= tests/memslap.cc tests_memslap_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_memslap_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) -tests_memslap_LDADD= $(tests_memslap_DEPENDENCIES) +tests_memslap_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memslap +tests_memslap_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memslap noinst_PROGRAMS+= tests/memslap tests_memdump_SOURCES= tests/memdump.cc tests_memdump_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX) -tests_memdump_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) -tests_memdump_LDADD= $(tests_memdump_DEPENDENCIES) +tests_memdump_DEPENDENCIES= libtest/libtest.la $(TESTS_LDADDS) clients/memdump +tests_memdump_LDADD= libtest/libtest.la $(TESTS_LDADDS) check_PROGRAMS+= tests/memdump noinst_PROGRAMS+= tests/memdump diff --git a/tests/libmemcached_world.h b/tests/libmemcached_world.h index ecbb489e..7936a524 100644 --- a/tests/libmemcached_world.h +++ b/tests/libmemcached_world.h @@ -131,9 +131,10 @@ static test_return_t world_container_startup(libmemcached_test_container_st *con buffer, sizeof(buffer)), container->construct.option_string().c_str()); - test_true(not container->parent); + test_null(container->parent); container->parent= memcached(container->construct.option_string().c_str(), container->construct.option_string().size()); test_true(container->parent); + test_compare(MEMCACHED_SUCCESS, memcached_version(container->parent)); if (container->construct.sasl()) { @@ -175,7 +176,7 @@ static test_return_t world_container_shutdown(libmemcached_test_container_st *co static test_return_t world_test_startup(libmemcached_test_container_st *container) { test_true(container); - test_true(not container->memc); + test_null(container->memc); test_true(container->parent); container->memc= memcached_clone(NULL, container->parent); test_true(container->memc); @@ -216,9 +217,8 @@ static test_return_t world_post_run(libmemcached_test_container_st *container) return TEST_SUCCESS; } -static test_return_t world_on_error(test_return_t test_state, libmemcached_test_container_st *container) +static test_return_t world_on_error(test_return_t , libmemcached_test_container_st *container) { - (void)test_state; test_true(container->memc); memcached_free(container->memc); container->memc= NULL; diff --git a/tests/mem_functions.cc b/tests/mem_functions.cc index 3d2869ce..b9acb87e 100644 --- a/tests/mem_functions.cc +++ b/tests/mem_functions.cc @@ -78,6 +78,7 @@ #include "tests/ketama.h" #include "tests/namespace.h" #include "tests/parser.h" +#include "tests/touch.h" #include "tests/callbacks.h" #include "tests/pool.h" #include "tests/print.h" @@ -100,8 +101,22 @@ static pairs_st *global_pairs; static const char *global_keys[GLOBAL_COUNT]; static size_t global_keys_length[GLOBAL_COUNT]; -// Prototype -static test_return_t pre_binary(memcached_st *memc); +/** + @note This should be testing to see if the server really supports the binary protocol. +*/ +static test_return_t pre_binary(memcached_st *memc) +{ + memcached_return_t rc= MEMCACHED_FAILURE; + + if (libmemcached_util_version_check(memc, 1, 4, 4)) + { + rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); + test_compare(MEMCACHED_SUCCESS, rc); + test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1); + } + + return rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_SKIPPED; +} static test_return_t init_test(memcached_st *not_used) @@ -2260,9 +2275,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) { - unsigned int setter= 1; - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, setter); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, setter); + test_compare(true, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1)); + test_compare(true, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1)); #ifdef NOT_YET setter = 20 * 1024576; memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE, setter); @@ -2279,6 +2293,7 @@ static test_return_t user_supplied_bug3(memcached_st *memc) { char key[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1]; int key_length= snprintf(key, sizeof(key), "%u", x); + test_true(key_length); keys[x]= strdup(key); test_true(keys[x]); key_lengths[x]= key_length; @@ -2376,7 +2391,7 @@ static test_return_t user_supplied_bug5(memcached_st *memc) memcached_return_t rc; value= memcached_get(memc, keys[0], key_length[0], - &value_length, &flags, &rc); + &value_length, &flags, &rc); test_false(value); test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, keys, key_length, 4)); @@ -2440,7 +2455,7 @@ static test_return_t user_supplied_bug6(memcached_st *memc) memcached_return_t rc; uint32_t count= 0; while ((value= memcached_fetch(memc, return_key, &return_key_length, - &value_length, &flags, &rc))) + &value_length, &flags, &rc))) { count++; } @@ -2536,7 +2551,7 @@ static test_return_t user_supplied_bug7(memcached_st *memc) flags= 0; value= memcached_get(memc, keys, key_length, - &value_length, &flags, &rc); + &value_length, &flags, &rc); test_true(flags == 245); test_true(value); free(value); @@ -2622,7 +2637,7 @@ static test_return_t user_supplied_bug10(memcached_st *memc) value, value_length, 0, 0); test_true_got((rc == MEMCACHED_SUCCESS or rc == MEMCACHED_WRITE_FAILURE or rc == MEMCACHED_BUFFERED or rc == MEMCACHED_TIMEOUT or rc == MEMCACHED_CONNECTION_FAILURE - or rc == MEMCACHED_SERVER_TEMPORARILY_DISABLED), + or rc == MEMCACHED_SERVER_TEMPORARILY_DISABLED), memcached_strerror(NULL, rc)); if (rc == MEMCACHED_WRITE_FAILURE or rc == MEMCACHED_TIMEOUT) @@ -2688,7 +2703,7 @@ static test_return_t user_supplied_bug12(memcached_st *memc) uint64_t number_value; value= memcached_get(memc, "autoincrement", strlen("autoincrement"), - &value_length, &flags, &rc); + &value_length, &flags, &rc); test_true(value == NULL); test_compare(MEMCACHED_NOTFOUND, rc); @@ -2709,7 +2724,7 @@ static test_return_t user_supplied_bug12(memcached_st *memc) rc= memcached_set(memc, "autoincrement", strlen("autoincrement"), "1", 1, 0, 0); value= memcached_get(memc, "autoincrement", strlen("autoincrement"), - &value_length, &flags, &rc); + &value_length, &flags, &rc); test_true(value); test_compare(MEMCACHED_SUCCESS, rc); free(value); @@ -2725,7 +2740,7 @@ static test_return_t user_supplied_bug12(memcached_st *memc) /* Bug found where command total one more than MEMCACHED_MAX_BUFFER set key34567890 0 0 8169 \r\n is sent followed by buffer of size 8169, followed by 8169 - */ +*/ static test_return_t user_supplied_bug13(memcached_st *memc) { char key[] = "key34567890"; @@ -2762,7 +2777,7 @@ static test_return_t user_supplied_bug13(memcached_st *memc) Bug found where command total one more than MEMCACHED_MAX_BUFFER set key34567890 0 0 8169 \r\n is sent followed by buffer of size 8169, followed by 8169 - */ +*/ static test_return_t user_supplied_bug14(memcached_st *memc) { memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, true); @@ -2797,7 +2812,7 @@ static test_return_t user_supplied_bug14(memcached_st *memc) /* Look for zero length value problems - */ +*/ static test_return_t user_supplied_bug15(memcached_st *memc) { for (uint32_t x= 0; x < 2; x++) @@ -2842,7 +2857,7 @@ static test_return_t user_supplied_bug16(memcached_st *memc) size_t length; uint32_t flags; char *value= memcached_get(memc, test_literal_param("mykey"), - &length, &flags, &rc); + &length, &flags, &rc); test_compare(MEMCACHED_SUCCESS, rc); test_true(value == NULL); @@ -2856,25 +2871,25 @@ static test_return_t user_supplied_bug16(memcached_st *memc) /* Check the validity of chinese key*/ static test_return_t user_supplied_bug17(memcached_st *memc) { - const char *key= "豆瓣"; - const char *value="我们在炎热抑郁的夏天无法停止豆瓣"; - memcached_return_t rc= memcached_set(memc, key, strlen(key), - value, strlen(value), - (time_t)0, 0); + const char *key= "豆瓣"; + const char *value="我们在炎热抑郁的夏天无法停止豆瓣"; + memcached_return_t rc= memcached_set(memc, key, strlen(key), + value, strlen(value), + (time_t)0, 0); - test_compare(MEMCACHED_SUCCESS, rc); + test_compare(MEMCACHED_SUCCESS, rc); - size_t length; - uint32_t flags; - char *value2= memcached_get(memc, key, strlen(key), - &length, &flags, &rc); + size_t length; + uint32_t flags; + char *value2= memcached_get(memc, key, strlen(key), + &length, &flags, &rc); - test_true(length==strlen(value)); - test_compare(MEMCACHED_SUCCESS, rc); - test_memcmp(value, value2, length); - free(value2); + test_true(length==strlen(value)); + test_compare(MEMCACHED_SUCCESS, rc); + test_memcmp(value, value2, length); + free(value2); - return TEST_SUCCESS; + return TEST_SUCCESS; } #endif @@ -3016,13 +3031,7 @@ static test_return_t _user_supplied_bug21(memcached_st* memc, size_t key_count) static test_return_t user_supplied_bug21(memcached_st *memc) { - test_return_t test_rc; - test_rc= pre_binary(memc); - - if (test_rc != TEST_SUCCESS) - { - return test_rc; - } + test_skip(TEST_SUCCESS, pre_binary(memc)); /* should work as of r580 */ test_compare(TEST_SUCCESS, @@ -3429,7 +3438,7 @@ static test_return_t add_host_test1(memcached_st *memc) snprintf(buffer, SMALL_STRING_LEN, "%lu.example.com", (unsigned long)(400 +x)); servers= memcached_server_list_append_with_weight(servers, buffer, 401, 0, - &rc); + &rc); test_compare(MEMCACHED_SUCCESS, rc); test_compare(x, memcached_server_list_count(servers)); } @@ -3591,23 +3600,6 @@ static test_return_t pre_behavior_ketama_weighted(memcached_st *memc) return TEST_SUCCESS; } -/** - @note This should be testing to see if the server really supports the binary protocol. -*/ -static test_return_t pre_binary(memcached_st *memc) -{ - memcached_return_t rc= MEMCACHED_FAILURE; - - if (libmemcached_util_version_check(memc, 1, 4, 4)) - { - rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); - test_compare(MEMCACHED_SUCCESS, rc); - test_true(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1); - } - - return rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_SKIPPED; -} - static test_return_t pre_replication(memcached_st *memc) { test_skip(TEST_SUCCESS, pre_binary(memc)); @@ -3615,7 +3607,7 @@ static test_return_t pre_replication(memcached_st *memc) /* * Make sure that we store the item on all servers * (master + replicas == number of servers) - */ + */ test_compare(MEMCACHED_SUCCESS, memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, memcached_server_count(memc) - 1)); test_compare(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS), uint64_t(memcached_server_count(memc) - 1)); @@ -4042,10 +4034,10 @@ static test_return_t noreply_test(memcached_st *memc) } /* - ** NOTE: Don't ever do this in your code! this is not a supported use of the - ** API and is _ONLY_ done this way to verify that the library works the - ** way it is supposed to do!!!! - */ + ** NOTE: Don't ever do this in your code! this is not a supported use of the + ** API and is _ONLY_ done this way to verify that the library works the + ** way it is supposed to do!!!! + */ int no_msg=0; for (uint32_t x= 0; x < memcached_server_count(memc); ++x) { @@ -4059,7 +4051,7 @@ static test_return_t noreply_test(memcached_st *memc) /* ** Now validate that all items was set properly! - */ + */ for (size_t x= 0; x < 100; ++x) { char key[10]; @@ -4098,7 +4090,7 @@ static test_return_t noreply_test(memcached_st *memc) /* Try setting an illegal cas value (should not return an error to * the caller (because we don't expect a return message from the server) - */ + */ const char* keys[]= {"0"}; size_t lengths[]= {1}; size_t length; @@ -4122,7 +4114,7 @@ static test_return_t noreply_test(memcached_st *memc) /* * The item will have a new cas value, so try to set it again with the old * value. This should fail! - */ + */ test_compare(MEMCACHED_SUCCESS, memcached_cas(memc, keys[0], lengths[0], keys[0], lengths[0], 0, 0, cas)); test_true(memcached_flush_buffers(memc) == MEMCACHED_SUCCESS); @@ -4255,7 +4247,7 @@ static test_return_t connection_pool2_test(memcached_st *memc) /* verify that I can set behaviors on the pool when I don't have all * of the connections in the pool. It should however be enabled * when I push the item into the pool - */ + */ mmc[0]= memcached_pool_fetch(pool, NULL, NULL); test_true(mmc[0]); @@ -4406,10 +4398,10 @@ static test_return_t connection_pool3_test(memcached_st *memc) static test_return_t util_version_test(memcached_st *memc) { - bool if_successful= libmemcached_util_version_check(memc, 0, 0, 0); - test_true(if_successful); + test_compare_hint(MEMCACHED_SUCCESS, memcached_version(memc), memcached_last_error_message(memc)); + test_true(libmemcached_util_version_check(memc, 0, 0, 0)); - if_successful= libmemcached_util_version_check(memc, 9, 9, 9); + bool if_successful= libmemcached_util_version_check(memc, 9, 9, 9); // We expect failure if (if_successful) @@ -4903,11 +4895,7 @@ static test_return_t memcached_get_by_key_MEMCACHED_NOTFOUND(memcached_st *memc) static test_return_t regression_bug_434484(memcached_st *memc) { - test_return_t test_rc; - test_rc= pre_binary(memc); - - if (test_rc != TEST_SUCCESS) - return test_rc; + test_skip(TEST_SUCCESS, pre_binary(memc)); const char *key= "regression_bug_434484"; size_t keylen= strlen(key); @@ -4927,11 +4915,7 @@ static test_return_t regression_bug_434484(memcached_st *memc) static test_return_t regression_bug_434843(memcached_st *memc) { - test_return_t test_rc; - test_rc= pre_binary(memc); - - if (test_rc != TEST_SUCCESS) - return test_rc; + test_skip(TEST_SUCCESS, pre_binary(memc)); memcached_return_t rc; size_t counter= 0; @@ -4942,7 +4926,7 @@ static test_return_t regression_bug_434843(memcached_st *memc) * sending in the pipleine to the server. Let's try to do a multiget of * 1024 (that should satisfy most users don't you think?). Future versions * will include a mget_execute function call if you need a higher number. - */ + */ uint32_t number_of_hosts= memcached_server_count(memc); memc->number_of_hosts= 1; const size_t max_keys= 1024; @@ -4951,17 +4935,17 @@ static test_return_t regression_bug_434843(memcached_st *memc) for (size_t x= 0; x < max_keys; ++x) { - char k[251]; + char k[251]; - key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%lu", (unsigned long)x); - keys[x]= strdup(k); - test_true(keys[x]); + key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%lu", (unsigned long)x); + keys[x]= strdup(k); + test_true(keys[x]); } /* * Run two times.. the first time we should have 100% cache miss, * and the second time we should have 100% cache hits - */ + */ for (size_t y= 0; y < 2; y++) { test_compare(MEMCACHED_SUCCESS, @@ -4987,7 +4971,7 @@ static test_return_t regression_bug_434843(memcached_st *memc) else { /* Verify that we received all of the key/value pairs */ - test_compare(counter, max_keys); + test_compare(counter, max_keys); } } @@ -5072,9 +5056,9 @@ static test_return_t regression_bug_442914(memcached_st *memc) for (uint32_t x= 0; x < 250; ++x) { - len= (size_t)snprintf(k, sizeof(k), "%0250u", x); - memcached_return_t rc= memcached_delete(memc, k, len, 0); - test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); + len= (size_t)snprintf(k, sizeof(k), "%0250u", x); + memcached_return_t rc= memcached_delete(memc, k, len, 0); + test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED); } (void)snprintf(k, sizeof(k), "%037u", 251U); @@ -5118,23 +5102,23 @@ static test_return_t regression_bug_447342(memcached_st *memc) } /* - ** We are using the quiet commands to store the replicas, so we need - ** to ensure that all of them are processed before we can continue. - ** In the test we go directly from storing the object to trying to - ** receive the object from all of the different servers, so we - ** could end up in a race condition (the memcached server hasn't yet - ** processed the quiet command from the replication set when it process - ** the request from the other client (created by the clone)). As a - ** workaround for that we call memcached_quit to send the quit command - ** to the server and wait for the response ;-) If you use the test code - ** as an example for your own code, please note that you shouldn't need - ** to do this ;-) - */ + ** We are using the quiet commands to store the replicas, so we need + ** to ensure that all of them are processed before we can continue. + ** In the test we go directly from storing the object to trying to + ** receive the object from all of the different servers, so we + ** could end up in a race condition (the memcached server hasn't yet + ** processed the quiet command from the replication set when it process + ** the request from the other client (created by the clone)). As a + ** workaround for that we call memcached_quit to send the quit command + ** to the server and wait for the response ;-) If you use the test code + ** as an example for your own code, please note that you shouldn't need + ** to do this ;-) + */ memcached_quit(memc); /* Verify that all messages are stored, and we didn't stuff too much * into the servers - */ + */ test_compare(MEMCACHED_SUCCESS, memcached_mget(memc, (const char* const *)keys, key_length, max_keys)); @@ -5152,7 +5136,7 @@ static test_return_t regression_bug_447342(memcached_st *memc) * within the library, and this is not a supported interface. * This is to verify correct behavior in the library. Fake that two servers * are dead.. - */ + */ instance_one= memcached_server_instance_by_position(memc, 0); instance_two= memcached_server_instance_by_position(memc, 2); in_port_t port0= instance_one->port; @@ -5244,7 +5228,7 @@ static test_return_t regression_bug_463297(memcached_st *memc) /* but there is a bug in some of the memcached servers (1.4) that treats * the counter as noreply so it doesn't send the proper error message - */ + */ test_true_got(rc == MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_NOTFOUND || rc == MEMCACHED_CLIENT_ERROR || rc == MEMCACHED_INVALID_ARGUMENTS, memcached_strerror(NULL, rc)); /* And buffered mode should be disabled and we should get protocol error */ @@ -5422,7 +5406,7 @@ static test_return_t wrong_failure_counter_test(memcached_st *memc) * Please note that I'm abusing the internal structures in libmemcached * in a non-portable way and you shouldn't be doing this. I'm only * doing this in order to verify that the library works the way it should - */ + */ uint32_t number_of_hosts= memcached_server_count(memc); memc->number_of_hosts= 1; @@ -5437,7 +5421,7 @@ static test_return_t wrong_failure_counter_test(memcached_st *memc) /* The test is to see that the memcached_quit doesn't increase the * the server failure conter, so let's ensure that it is zero * before sending quit - */ + */ ((memcached_server_write_instance_st)instance)->server_failure_counter= 0; memcached_quit(memc); @@ -5445,7 +5429,7 @@ static test_return_t wrong_failure_counter_test(memcached_st *memc) /* Verify that it memcached_quit didn't increment the failure counter * Please note that this isn't bullet proof, because an error could * occur... - */ + */ test_zero(instance->server_failure_counter); /* restore the instance */ @@ -5525,7 +5509,7 @@ static test_return_t regression_bug_490486(memcached_st *memc) /* * I only want to hit _one_ server so I know the number of requests I'm * sending in the pipeline. - */ + */ uint32_t number_of_hosts= memc->number_of_hosts; memc->number_of_hosts= 1; size_t max_keys= 20480; @@ -5769,16 +5753,16 @@ static test_return_t regression_bug_854604(memcached_st *) test_compare(MEMCACHED_INVALID_ARGUMENTS, libmemcached_check_configuration(0, 0, buffer, 0)); test_compare(MEMCACHED_PARSE_ERROR, libmemcached_check_configuration(test_literal_param("syntax error"), buffer, 0)); - + test_compare(MEMCACHED_PARSE_ERROR, libmemcached_check_configuration(test_literal_param("syntax error"), buffer, 1)); test_compare(buffer[0], 0); - + test_compare(MEMCACHED_PARSE_ERROR, libmemcached_check_configuration(test_literal_param("syntax error"), buffer, 10)); test_true(strlen(buffer)); test_compare(MEMCACHED_PARSE_ERROR, libmemcached_check_configuration(test_literal_param("syntax error"), buffer, sizeof(buffer))); test_true(strlen(buffer)); - + return TEST_SUCCESS; } @@ -5957,6 +5941,14 @@ test_st tests[] ={ {"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 }, + {"memcached_touch", 0, (test_callback_fn*)test_memcached_touch}, + {"memcached_touch_with_prefix", 0, (test_callback_fn*)test_memcached_touch_by_key}, + {0, 0, 0} +}; + +test_st touch_tests[] ={ + {"memcached_touch", 0, (test_callback_fn*)test_memcached_touch}, + {"memcached_touch_with_prefix", 0, (test_callback_fn*)test_memcached_touch_by_key}, {0, 0, 0} }; @@ -6045,12 +6037,12 @@ test_st user_tests[] ={ {"user_supplied_bug16", true, (test_callback_fn*)user_supplied_bug16 }, #if !defined(__sun) && !defined(__OpenBSD__) /* - ** It seems to be something weird with the character sets.. - ** value_fetch is unable to parse the value line (iscntrl "fails"), so I - ** guess I need to find out how this is supposed to work.. Perhaps I need - ** to run the test in a specific locale (I tried zh_CN.UTF-8 without success, - ** so just disable the code for now...). - */ + ** It seems to be something weird with the character sets.. + ** value_fetch is unable to parse the value line (iscntrl "fails"), so I + ** guess I need to find out how this is supposed to work.. Perhaps I need + ** to run the test in a specific locale (I tried zh_CN.UTF-8 without success, + ** so just disable the code for now...). + */ {"user_supplied_bug17", true, (test_callback_fn*)user_supplied_bug17 }, #endif {"user_supplied_bug18", true, (test_callback_fn*)user_supplied_bug18 }, @@ -6190,7 +6182,6 @@ test_st error_conditions[] ={ {0, 0, (test_callback_fn*)0} }; - test_st parser_tests[] ={ {"behavior", false, (test_callback_fn*)behavior_parser_test }, {"boolean_options", false, (test_callback_fn*)parser_boolean_options_test }, @@ -6296,6 +6287,7 @@ collection_st collection[] ={ {"parser", 0, 0, parser_tests}, {"virtual buckets", 0, 0, virtual_bucket_tests}, {"memcached_server_get_last_disconnect", 0, 0, memcached_server_get_last_disconnect_tests}, + {"touch", 0, 0, touch_tests}, {0, 0, 0, 0} }; diff --git a/tests/memtouch.cc b/tests/memtouch.cc new file mode 100644 index 00000000..21378d73 --- /dev/null +++ b/tests/memtouch.cc @@ -0,0 +1,153 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Test memtouch + * + * 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 touch_test(void *) +{ + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "--server=localhost:%d", int(default_port())); + const char *args[]= { "--quiet", "--expire=30", 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)); + + test_compare(MEMCACHED_SUCCESS, memcached_exist(memc, test_literal_param("foo"))); + + test_true(exec_cmdline(executable, args)); + + test_compare(MEMCACHED_SUCCESS, memcached_exist(memc, test_literal_param("foo"))); + + 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", "--expire=30", buffer, "foo", 0 }; + + memcached_st *memc= memcached(buffer, strlen(buffer)); + test_true(memc); + + test_compare(MEMCACHED_SUCCESS, memcached_flush(memc, 0)); + + test_compare(MEMCACHED_NOTFOUND, memcached_exist(memc, test_literal_param("foo"))); + + test_true(exec_cmdline(executable, args)); + + test_compare(MEMCACHED_NOTFOUND, memcached_exist(memc, test_literal_param("foo"))); + + memcached_free(memc); + + return TEST_SUCCESS; +} + +test_st memtouch_tests[] ={ + {"--quiet", true, quiet_test }, + {"--help", true, help_test }, + {"touch(FOUND)", true, touch_test }, + {"touch(NOT_FOUND)", true, NOT_FOUND_test }, + {0, 0, 0} +}; + +collection_st collection[] ={ + {"memtouch", 0, 0, memtouch_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]= { "memtouch" }; + if (not server_startup(servers, "memcached", MEMCACHED_DEFAULT_PORT +10, 1, argv)) + { + error= TEST_FAILURE; + } + + return &servers; +} + + +void get_world(Framework *world) +{ + executable= "./clients/memtouch"; + world->collections= collection; + world->_create= world_create; +} + diff --git a/tests/touch.cc b/tests/touch.cc new file mode 100644 index 00000000..50e6a359 --- /dev/null +++ b/tests/touch.cc @@ -0,0 +1,156 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Libmemcached Client and Server + * + * 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 +#include + +using namespace libtest; + +#include +#include + +#include "tests/touch.h" + +static test_return_t pre_touch(memcached_st *memc) +{ + test_compare(MEMCACHED_SUCCESS, memcached_version(memc)); + test_skip(true, libmemcached_util_version_check(memc, 1, 4, 8)); + + return TEST_SUCCESS; +} + +test_return_t test_memcached_touch(memcached_st *memc) +{ + + test_skip(TEST_SUCCESS, pre_touch(memc)); + + size_t len; + uint32_t flags; + memcached_return rc; + + test_null(memcached_get(memc, + test_literal_param("touchkey"), + &len, &flags, &rc)); + test_zero(len); + test_compare(MEMCACHED_NOTFOUND, rc); + + test_compare(MEMCACHED_SUCCESS, + memcached_set(memc, + test_literal_param("touchkey"), + test_literal_param("touchval"), + 2, 0)); + + { + char *value= memcached_get(memc, + test_literal_param("touchkey"), + &len, &flags, &rc); + test_compare(8U, test_literal_param_size("touchval")); + test_true(value); + test_strcmp(value, "touchval"); + test_compare(MEMCACHED_SUCCESS, rc); + free(value); + } + + test_compare(MEMCACHED_SUCCESS, + memcached_touch(memc, test_literal_param("touchkey"), 60 *60)); + + test_skip(false ,memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)); + + rc= memcached_touch(memc, test_literal_param("touchkey"), 60 *60 *24 *60); + test_compare_hint(MEMCACHED_SUCCESS, rc, memcached_last_error_message(memc)); + + test_compare(MEMCACHED_NOTFOUND, + memcached_exist(memc, test_literal_param("touchkey"))); + + return TEST_SUCCESS; +} + +test_return_t test_memcached_touch_by_key(memcached_st *memc) +{ + + test_skip(TEST_SUCCESS, pre_touch(memc)); + + size_t len; + uint32_t flags; + memcached_return rc; + + test_null(memcached_get_by_key(memc, + test_literal_param("grouping_key"), + test_literal_param("touchkey"), + &len, &flags, &rc)); + test_zero(len); + test_compare(MEMCACHED_NOTFOUND, rc); + + test_compare(MEMCACHED_SUCCESS, + memcached_set_by_key(memc, + test_literal_param("grouping_key"), + test_literal_param("touchkey"), + test_literal_param("touchval"), + 2, 0)); + + { + char *value= memcached_get_by_key(memc, + test_literal_param("grouping_key"), + test_literal_param("touchkey"), + &len, &flags, &rc); + test_compare(8U, test_literal_param_size("touchval")); + test_true(value); + test_strcmp(value, "touchval"); + test_compare(MEMCACHED_SUCCESS, rc); + free(value); + } + + test_compare(MEMCACHED_SUCCESS, + memcached_touch_by_key(memc, + test_literal_param("grouping_key"), + test_literal_param("touchkey"), + 60 *60)); + + test_skip(false ,memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)); + test_compare(MEMCACHED_SUCCESS, + memcached_touch_by_key(memc, + test_literal_param("grouping_key"), + test_literal_param("touchkey"), + 60 *60 *24 *60)); + test_compare(MEMCACHED_NOTFOUND, + memcached_exist_by_key(memc, test_literal_param("grouping_key"),test_literal_param("touchkey"))); + + return TEST_SUCCESS; +} + + + diff --git a/tests/touch.h b/tests/touch.h new file mode 100644 index 00000000..1cf28134 --- /dev/null +++ b/tests/touch.h @@ -0,0 +1,41 @@ +/* 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. + * + */ + +#pragma once + +test_return_t test_memcached_touch(memcached_st *); +test_return_t test_memcached_touch_by_key(memcached_st *);