Merge in touch.
authorBrian Aker <brian@tangent.org>
Wed, 5 Oct 2011 21:41:46 +0000 (14:41 -0700)
committerBrian Aker <brian@tangent.org>
Wed, 5 Oct 2011 21:41:46 +0000 (14:41 -0700)
28 files changed:
.bzrignore
clients/include.am
clients/memtouch.cc [new file with mode: 0644]
libmemcached-1.0/include.am
libmemcached-1.0/memcached.h
libmemcached-1.0/touch.h [new file with mode: 0644]
libmemcached/do.cc
libmemcached/error.cc
libmemcached/hosts.cc
libmemcached/include.am
libmemcached/initialize_query.cc
libmemcached/libmemcached_probes.d
libmemcached/libmemcached_probes.h
libmemcached/memcached.h
libmemcached/memcached/protocol_binary.h
libmemcached/response.cc
libmemcached/server.cc
libmemcached/touch.cc [new file with mode: 0644]
libmemcached/version.cc
libmemcachedutil/version.cc
m4/progtest.m4 [deleted file]
support/libmemcached.spec.in
tests/include.am
tests/libmemcached_world.h
tests/mem_functions.cc
tests/memtouch.cc [new file with mode: 0644]
tests/touch.cc [new file with mode: 0644]
tests/touch.h [new file with mode: 0644]

index 3333d5f80523fcccd9d000113a87b35b075193d8..dedeb4cbd6e90bc7fb3988d0fdd555ae28198dcf 100644 (file)
@@ -137,3 +137,5 @@ tests/memcat
 clients/memexist
 tests/memexist
 libmemcached/configure.h
+clients/memtouch
+tests/memtouch
index 31d3c0eb2df47a1259bb822d73a279d28bd3de78..bb35bdf5f27e44c1dd3d6029054f67002b4ed0b7 100644 (file)
@@ -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 (file)
index 0000000..4f3be80
--- /dev/null
@@ -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 <config.h>
+
+#include <cstdio>
+#include <cstring>
+#include <getopt.h>
+#include <iostream>
+#include <unistd.h>
+#include <libmemcached/memcached.h>
+
+#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);
+  }
+}
index e9658ad11536e8ea31815cbdcae1892fd23f9ecb..39313c2c065dea8fbd9ddde8aba34c12bc1c0ad7 100644 (file)
@@ -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 \
index d459d2c5c44150c7ff6afbb4d88e682c08b7c238..f97d333a1d4780dd9b1d7a22b71c2f71e3aeba79 100644 (file)
@@ -80,6 +80,7 @@
 #include <libmemcached-1.0/server_list.h>
 #include <libmemcached-1.0/storage.h>
 #include <libmemcached-1.0/strerror.h>
+#include <libmemcached-1.0/touch.h>
 #include <libmemcached-1.0/verbosity.h>
 #include <libmemcached-1.0/version.h>
 #include <libmemcached-1.0/sasl.h>
diff --git a/libmemcached-1.0/touch.h b/libmemcached-1.0/touch.h
new file mode 100644 (file)
index 0000000..e143c03
--- /dev/null
@@ -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
index 5e9e65f280e20b314f89e8727b9a13b46829b276..551b28ea57ce21393fcbaefbb47dc800b7f20724 100644 (file)
 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++)
index 85ce84e82081b35383675216fcdbb73eda615211..e22871cd12b91f426116f2f020b53e6c6d76d846 100644 (file)
@@ -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;
 }
index 179b7c29289c39dda38cd6a2a0932c6da1a441c2..304565597eabcb7f013424a7b962869633587a5a 100644 (file)
@@ -362,9 +362,9 @@ static memcached_return_t server_add(memcached_st *ptr,
   memcached_server_st *new_host_list= static_cast<memcached_server_st*>(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);
   }
index 03a327da327863eca093b7788fddb77e17dfe7f4..e3f5fa3fef99cc418f825a4b126f77c960cc172b 100644 (file)
@@ -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 \
index 027b156672cfe547a5b86560c37e4a51573360cf..5950158b053feb22a6205ef825719d08277d04a3 100644 (file)
@@ -38,7 +38,7 @@
 
 memcached_return_t initialize_query(memcached_st *self)
 {
-  if (not self)
+  if (self == NULL)
   {
     return MEMCACHED_INVALID_ARGUMENTS;
   }
index 1163b524f049b5f9e103eb9cb7543694a99afc9f..28d8402eb6ffc324e28c0e7e95032d334d5575d4 100644 (file)
@@ -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();
index e9a649d1ef29a7641f09f7ab6e53347ba92a4389..9dba8aa12dd7cd162ed7ccc81e85a9f5b183ee64 100644 (file)
@@ -1,5 +1,5 @@
 /*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- * 
+ *
  *  Libmemcached library
  *
  *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 #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()
index 9a1f181287810065130a89a552390d09620d8abb..a45077eeaa374666a53436be7ebd7cff1dea53a2 100644 (file)
@@ -1,5 +1,5 @@
 /*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- * 
+ *
  *  Libmemcached library
  *
  *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
index 7a253ae7d616e80309507afc0834beb092290cd9..ad6202e8d0060ce71ccb6aad586c1a0e2bafb25b 100644 (file)
@@ -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,
index adecd6e1c38475d6f2dab01a3a82dd66f9f083ca..061f7401fee84a19dbd462a0564601ebce5a7276 100644 (file)
@@ -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)
index b91512832a59568602ce34c321eff5534da4ad32..c9c5ffca6b3a9269ca3782d3f1e68fe3f4151375 100644 (file)
@@ -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 (file)
index 0000000..1107139
--- /dev/null
@@ -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 <libmemcached/common.h>
+#include <libmemcached/memcached/protocol_binary.h>
+
+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"));
+}
index abb720054545177ba929e3342c24675bafba8da0..b70cf672278c7421257ab9cacdd3269e071454bd 100644 (file)
@@ -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);
     }
   }
 
index abfd47f71cffef0f540c076c1d03776ec19f2656..15f888b875b7fd5baef93ee8db35be999b1ab990 100644 (file)
@@ -37,6 +37,7 @@
 
 
 #include <libmemcachedutil/common.h>
+#include <cassert>
 
 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 (file)
index 2d804ac..0000000
+++ /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 <drepper@cygnus.com>, 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
-])
index c6a6e727a5880c6ae62c293f40e5960e1acf18f5..449ee0b30732a1f0f571be2bd96a5606c80cff9e 100644 (file)
@@ -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
 
index a4cf4c6a18c578a7be8fa8cd1864d3d2434ccc02..b51dc2c3c74a640fef288b1bc6a11d6e83094a4f 100644 (file)
@@ -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
  
index ecbb489efbc036b1e938ae69aefd07109ba2b402..7936a524826818b009cbbe5e6ac67b7506071203 100644 (file)
@@ -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;
index 3d2869ce23bfa0f9ca6fa83e7d365d5be1a7ebf0..b9acb87ef882a7c03504765aeb4921be715bf216 100644 (file)
@@ -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 (file)
index 0000000..21378d7
--- /dev/null
@@ -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 <config.h>
+
+#include <libtest/test.hpp>
+#include <libmemcached/memcached.h>
+
+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 (file)
index 0000000..50e6a35
--- /dev/null
@@ -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 <config.h>
+#include <libtest/test.hpp>
+
+using namespace libtest;
+
+#include <libmemcached-1.0/memcached.h>
+#include <libmemcachedutil-1.0/util.h>
+
+#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 (file)
index 0000000..1cf2813
--- /dev/null
@@ -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 *);