Update all of the delete key logic (split it off for ASCII)
authorBrian Aker <brian@tangent.org>
Sun, 2 Oct 2011 23:49:04 +0000 (16:49 -0700)
committerBrian Aker <brian@tangent.org>
Sun, 2 Oct 2011 23:49:04 +0000 (16:49 -0700)
15 files changed:
docs/memcached_servers.rst
libmemcached-1.0/constants.h
libmemcached-1.0/server.h
libmemcached/allocators.cc
libmemcached/callback.cc
libmemcached/common.h
libmemcached/delete.cc
libmemcached/error.cc
libmemcached/include.am
libmemcached/key.cc
libmemcached/key.hpp [new file with mode: 0644]
libmemcached/server.cc
libmemcached/stats.cc
libtest/test.h
tests/mem_functions.cc

index 72da276496b5db9be99e7b3500d11066e27c4c95..ae5e7baeb1c868c42f76f08a4b02ce8bb23d98f1 100644 (file)
@@ -20,7 +20,7 @@ SYNOPSIS
 
 .. c:function:: memcached_return_t memcached_server_push (memcached_st *ptr, const memcached_server_st *list) 
 
-.. c:function:: memcached_server_instance_st memcached_server_by_key (const memcached_st *ptr, const char *key, size_t key_length, memcached_return_t *error)
+.. c:function:: memcached_server_instance_st memcached_server_by_key (memcached_st *ptr, const char *key, size_t key_length, memcached_return_t *error)
 
 .. c:function:: memcached_server_instance_st memcached_server_get_last_disconnect (const memcached_st *ptr)
 
index 106aec496d5050f30c2d2c2da435810611e4350e..9c8ab6432403ee0020620e23120edda6fd9a11b4 100644 (file)
@@ -122,11 +122,6 @@ enum memcached_callback_t {
   MEMCACHED_CALLBACK_USER_DATA = 1,
   MEMCACHED_CALLBACK_CLEANUP_FUNCTION = 2,
   MEMCACHED_CALLBACK_CLONE_FUNCTION = 3,
-#ifdef MEMCACHED_ENABLE_DEPRECATED
-  MEMCACHED_CALLBACK_MALLOC_FUNCTION = 4,
-  MEMCACHED_CALLBACK_REALLOC_FUNCTION = 5,
-  MEMCACHED_CALLBACK_FREE_FUNCTION = 6,
-#endif
   MEMCACHED_CALLBACK_GET_FAILURE = 7,
   MEMCACHED_CALLBACK_DELETE_TRIGGER = 8,
   MEMCACHED_CALLBACK_MAX,
index 3ca1df32eddec373f033ac71261bc78937031f29..38ab40a94f915e1497fe6fb1cad7ed873d527a15 100644 (file)
@@ -108,10 +108,10 @@ memcached_return_t memcached_server_cursor(const memcached_st *ptr,
                                            uint32_t number_of_callbacks);
 
 LIBMEMCACHED_API
-  memcached_server_instance_st memcached_server_by_key(const memcached_st *ptr,
-                                                        const char *key,
-                                                        size_t key_length,
-                                                        memcached_return_t *error);
+  memcached_server_instance_st memcached_server_by_key(memcached_st *ptr,
+                                                       const char *key,
+                                                       size_t key_length,
+                                                       memcached_return_t *error);
 
 LIBMEMCACHED_API
 void memcached_server_error_reset(memcached_server_st *ptr);
index cc41f2c37a7bb1adddad5e6c365be07e42fb9409..d18372b4ba6ca9793e1f60787487c36a80bfff7d 100644 (file)
@@ -90,11 +90,11 @@ memcached_return_t memcached_set_memory_allocators(memcached_st *self,
   }
 
   /* All should be set, or none should be set */
-  if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL) 
+  if (mem_malloc == NULL and mem_free == NULL and mem_realloc == NULL and mem_calloc == NULL) 
   {
     self->allocators= memcached_allocators_return_default();
   }
-  else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL)
+  else if (mem_malloc == NULL or mem_free == NULL or mem_realloc == NULL or mem_calloc == NULL)
   {
     return memcached_set_error(*self, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("NULL parameter provided for one or more allocators"));
   }
index 84f99359d78d138e697ca80f8b84f1107fc82c4d..32d85dcd93842343312eb46796d8d50cd298e21e 100644 (file)
@@ -30,51 +30,46 @@ memcached_return_t memcached_callback_set(memcached_st *ptr,
     {
       return memcached_set_namespace(ptr, (char*)data, data ? strlen((char*)data) : 0);
     }
+
   case MEMCACHED_CALLBACK_USER_DATA:
     {
       ptr->user_data= const_cast<void *>(data);
       break;
     }
+
   case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
     {
       memcached_cleanup_fn func= *(memcached_cleanup_fn *)&data;
       ptr->on_cleanup= func;
       break;
     }
+
   case MEMCACHED_CALLBACK_CLONE_FUNCTION:
     {
       memcached_clone_fn func= *(memcached_clone_fn *)&data;
       ptr->on_clone= func;
       break;
     }
-#ifdef MEMCACHED_ENABLE_DEPRECATED
-  case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
-    {
-      memcached_malloc_function func= *(memcached_malloc_fn *)&data;
-      ptr->call_malloc= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
-    {
-      memcached_realloc_function func= *(memcached_realloc_fn *)&data;
-      ptr->call_realloc= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_FREE_FUNCTION:
-    {
-      memcached_free_function func= *(memcached_free_fn *)&data;
-      ptr->call_free= func;
-      break;
-    }
-#endif
+
   case MEMCACHED_CALLBACK_GET_FAILURE:
     {
       memcached_trigger_key_fn func= *(memcached_trigger_key_fn *)&data;
       ptr->get_key_failure= func;
       break;
     }
+
   case MEMCACHED_CALLBACK_DELETE_TRIGGER:
     {
+      if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS)) 
+      {
+        return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Delete triggers cannot be used if buffering is enabled"));
+      }
+
+      if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_NOREPLY)) 
+      {
+        return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Delete triggers cannot be used if MEMCACHED_BEHAVIOR_NOREPLY is set"));
+      }
+
       memcached_trigger_delete_key_fn func= *(memcached_trigger_delete_key_fn *)&data;
       ptr->delete_trigger= func;
       break;
@@ -97,67 +92,59 @@ void *memcached_callback_get(memcached_st *ptr,
     error = &local_error;
   }
 
+  if (ptr == NULL)
+  {
+    *error= MEMCACHED_INVALID_ARGUMENTS;
+    return NULL;
+  }
+
   switch (flag)
   {
   case MEMCACHED_CALLBACK_PREFIX_KEY:
     {
+      *error= MEMCACHED_SUCCESS;
       if (ptr->_namespace)
       {
-        *error= MEMCACHED_SUCCESS;
         return (void *)memcached_array_string(ptr->_namespace);
       }
-      else
-      {
-        *error= MEMCACHED_FAILURE;
-        return NULL;
-      }
+      return NULL;
     }
+
   case MEMCACHED_CALLBACK_USER_DATA:
     {
       *error= ptr->user_data ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
       return (void *)ptr->user_data;
     }
+
   case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
     {
       *error= ptr->on_cleanup ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
       return *(void **)&ptr->on_cleanup;
     }
+
   case MEMCACHED_CALLBACK_CLONE_FUNCTION:
     {
       *error= ptr->on_clone ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
       return *(void **)&ptr->on_clone;
     }
-#ifdef MEMCACHED_ENABLE_DEPRECATED
-  case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
-    {
-      *error= ptr->call_malloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->call_malloc;
-    }
-  case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
-    {
-      *error= ptr->call_realloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->call_realloc;
-    }
-  case MEMCACHED_CALLBACK_FREE_FUNCTION:
-    {
-      *error= ptr->call_free ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->call_free;
-    }
-#endif
+
   case MEMCACHED_CALLBACK_GET_FAILURE:
     {
       *error= ptr->get_key_failure ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
       return *(void **)&ptr->get_key_failure;
     }
+
   case MEMCACHED_CALLBACK_DELETE_TRIGGER:
     {
       *error= ptr->delete_trigger ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
       return *(void **)&ptr->delete_trigger;
     }
+
   case MEMCACHED_CALLBACK_MAX:
-  default:
-    assert_msg(0, "Invalid behavior passed to memcached_behavior_set()");
-    *error= MEMCACHED_FAILURE;
-    return NULL;
+    break;
   }
+
+  assert_msg(0, "Invalid behavior passed to memcached_behavior_set()");
+  *error= MEMCACHED_FAILURE;
+  return NULL;
 }
index f4956e872e55c8f2a623bdca215a8747a255165f..6867490c8da8c56793853f6a0828e7c95499e7ea 100644 (file)
@@ -120,6 +120,7 @@ memcached_return_t memcached_server_execute(memcached_st *ptr,
 #include <libmemcached/backtrace.hpp>
 #include <libmemcached/assert.hpp>
 #include <libmemcached/server.hpp>
+#include <libmemcached/key.hpp>
 #endif
 
 #include <libmemcached/continuum.hpp>
@@ -154,43 +155,9 @@ memcached_return_t run_distribution(memcached_st *ptr);
 #define memcached_server_response_decrement(A) (A)->cursor_active--
 #define memcached_server_response_reset(A) (A)->cursor_active=0
 
-#ifdef __cplusplus
-LIBMEMCACHED_LOCAL
-memcached_return_t memcached_key_test(const memcached_st& memc,
-                                      const char * const *keys,
-                                      const size_t *key_length,
-                                      size_t number_of_keys);
-#endif
-
 LIBMEMCACHED_LOCAL
 memcached_return_t memcached_purge(memcached_server_write_instance_st ptr);
 
-
-static inline memcached_return_t memcached_validate_key_length(size_t key_length, bool binary)
-{
-  if (key_length == 0)
-  {
-    return MEMCACHED_BAD_KEY_PROVIDED;
-  }
-
-  if (binary)
-  {
-    if (key_length > 0xffff)
-    {
-      return MEMCACHED_BAD_KEY_PROVIDED;
-    }
-  }
-  else
-  {
-    if (key_length >= MEMCACHED_MAX_KEY)
-    {
-      return MEMCACHED_BAD_KEY_PROVIDED;
-    }
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
 #ifdef __cplusplus
 }
 #endif
index 5244f0db4862555070f4cc36f886d28b80921793..6be7e224ec70e52ee1502098b7779ac1fda02f4d 100644 (file)
@@ -45,188 +45,135 @@ memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t k
                                  key, key_length, expiration);
 }
 
-static inline memcached_return_t binary_delete(memcached_st *ptr,
-                                               uint32_t server_key,
-                                               const char *key,
-                                               size_t key_length,
-                                               bool flush);
-
-memcached_return_t memcached_delete_by_key(memcached_st *ptr,
-                                           const char *group_key, size_t group_key_length,
-                                           const char *key, size_t key_length,
-                                           time_t expiration)
+static inline memcached_return_t ascii_delete(memcached_st *ptr,
+                                              memcached_server_write_instance_st instance,
+                                              uint32_t ,
+                                              const char *key,
+                                              size_t key_length,
+                                              uint64_t expiration,
+                                              bool& reply,
+                                              bool& flush)
 {
   char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  memcached_server_write_instance_st instance;
+  int send_length;
 
-  LIBMEMCACHED_MEMCACHED_DELETE_START();
-
-  memcached_return_t rc;
-  if (memcached_failed(rc= initialize_query(ptr)))
+  if (expiration)
   {
-    return rc;
-  }
-
-  rc= memcached_validate_key_length(key_length,
-                                    ptr->flags.binary_protocol);
-
-  if (memcached_failed(rc))
-  {
-    return rc;
-  }
-
-  uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
-  instance= memcached_server_instance_fetch(ptr, server_key);
-
-  bool to_write= (ptr->flags.buffer_requests) ? false : true;
-
-  bool no_reply= (ptr->flags.no_reply);
-
-  if (ptr->flags.binary_protocol)
-  {
-    if (expiration == 0)
+    if ((instance->major_version == 1 and
+         instance->minor_version > 2) or
+        instance->major_version > 1)
     {
-      rc= binary_delete(ptr, server_key, key, key_length, to_write);
+      return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, 
+                                 memcached_literal_param("Memcached server version does not allow expiration of deleted items"));
     }
     else
     {
-      rc= MEMCACHED_INVALID_ARGUMENTS;
-    }
-  }
-  else
-  {
-    int send_length;
+      /* ensure that we are connected, otherwise we might bump the
+       * command counter before connection */
+      memcached_return_t rc;
+      if ((rc= memcached_connect(instance)) != MEMCACHED_SUCCESS)
+      {
+        WATCHPOINT_ERROR(rc);
+        return rc;
+      }
 
-    if (expiration)
-    {
-       if ((instance->major_version == 1 &&
-            instance->minor_version > 2) ||
-           instance->major_version > 1)
-       {
-         rc= MEMCACHED_INVALID_ARGUMENTS;
-         goto error;
-       }
-       else
-       {
-          /* ensure that we are connected, otherwise we might bump the
-           * command counter before connection */
-          if ((rc= memcached_connect(instance)) != MEMCACHED_SUCCESS)
+      if (instance->minor_version == 0)
+      {
+        if (reply == false or flush == false)
+        {
+          /* We might get out of sync with the server if we send this command
+           * to a server newer than 1.2.x..  enable reply and buffered mode.
+         */
+          flush= true;
+          if (reply == false)
           {
-            WATCHPOINT_ERROR(rc);
-            return rc;
+            memcached_server_response_increment(instance);
           }
+          reply= true;
+        }
+      }
 
-          if (instance->minor_version == 0)
-          {
-             if (no_reply or to_write == false)
-             {
-                /* We might get out of sync with the server if we
-                 * send this command to a server newer than 1.2.x..
-                 * disable no_reply and buffered mode.
-                 */
-                to_write= true;
-                if (no_reply)
-                   memcached_server_response_increment(instance);
-                no_reply= false;
-             }
-          }
-          send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                                "delete %.*s%.*s %u%s\r\n",
-                                memcached_print_array(ptr->_namespace),
-                                (int) key_length, key,
-                                (uint32_t)expiration,
-                                no_reply ? " noreply" :"" );
-       }
-    }
-    else
-    {
       send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                            "delete %.*s%.*s%s\r\n",
+                            "delete %.*s%.*s %u%s\r\n",
                             memcached_print_array(ptr->_namespace),
-                            (int)key_length, key, no_reply ? " noreply" :"");
-    }
-
-    if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
-    {
-      rc=  memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, 
-                               memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
-      goto error;
-    }
-
-    if (ptr->flags.use_udp and to_write == false)
-    {
-      if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
-        return MEMCACHED_WRITE_FAILURE;
-
-      if (send_length + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
-      {
-        memcached_io_write(instance, NULL, 0, true);
-      }
+                            (int) key_length, key,
+                            (uint32_t)expiration,
+                            reply ? "" :  " noreply");
     }
-
-    rc= memcached_do(instance, buffer, (size_t)send_length, to_write);
   }
-
-  if (rc != MEMCACHED_SUCCESS)
+  else
   {
-    goto error;
+    send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                          "delete %.*s%.*s%s\r\n",
+                          memcached_print_array(ptr->_namespace),
+                          (int)key_length, key, 
+                          reply ? "" :  " noreply");
   }
 
-  if (to_write == false)
+  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
   {
-    rc= MEMCACHED_BUFFERED;
+    return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, 
+                               memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
   }
-  else if (no_reply == false)
+
+  if (ptr->flags.use_udp and flush == false)
   {
-    rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-    if (rc == MEMCACHED_DELETED)
+    if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
     {
-      rc= MEMCACHED_SUCCESS;
+      return MEMCACHED_WRITE_FAILURE;
     }
-  }
 
-  if (rc == MEMCACHED_SUCCESS and ptr->delete_trigger)
-  {
-    ptr->delete_trigger(ptr, key, key_length);
+    if (send_length +instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+    {
+      memcached_io_write(instance, NULL, 0, true);
+    }
   }
 
-error:
-  LIBMEMCACHED_MEMCACHED_DELETE_END();
-  return rc;
+  return memcached_do(instance, buffer, (size_t)send_length, flush);
 }
 
 static inline memcached_return_t binary_delete(memcached_st *ptr,
+                                               memcached_server_write_instance_st instance,
                                                uint32_t server_key,
                                                const char *key,
                                                size_t key_length,
-                                               bool flush)
+                                               time_t expiration,
+                                               bool& reply,
+                                               bool& flush)
 {
-  memcached_server_write_instance_st instance;
   protocol_binary_request_delete request= {};
 
-  instance= memcached_server_instance_fetch(ptr, server_key);
+  // No expiration is supported in the binary protocol
+  if (expiration)
+  {
+    return MEMCACHED_INVALID_ARGUMENTS;
+  }
 
   request.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  if (ptr->flags.no_reply)
+  if (reply)
   {
-    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
+    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
   }
   else
   {
-    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
+    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
   }
   request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace)));
   request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
   request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->_namespace)));
 
-  if (ptr->flags.use_udp && ! flush)
+  if (ptr->flags.use_udp and flush == false)
   {
     size_t cmd_size= sizeof(request.bytes) + key_length;
     if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+    {
       return MEMCACHED_WRITE_FAILURE;
+    }
 
-    if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+    if (cmd_size +instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+    {
       memcached_io_write(instance, NULL, 0, true);
+    }
   }
 
   struct libmemcached_io_vector_st vector[]=
@@ -243,7 +190,7 @@ static inline memcached_return_t binary_delete(memcached_st *ptr,
     memcached_io_reset(instance);
   }
 
-  unlikely (ptr->number_of_replicas > 0)
+  if (ptr->number_of_replicas > 0)
   {
     request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
 
@@ -270,3 +217,82 @@ static inline memcached_return_t binary_delete(memcached_st *ptr,
 
   return rc;
 }
+
+memcached_return_t memcached_delete_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_DELETE_START();
+
+  memcached_return_t rc;
+  if (memcached_failed(rc= initialize_query(ptr)))
+  {
+    return rc;
+  }
+
+  rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
+  if (memcached_failed(rc))
+  {
+    return rc;
+  }
+  
+  // If a delete trigger exists, we need a response, so no buffering/noreply
+  if (ptr->delete_trigger)
+  {
+    if (ptr->flags.buffer_requests)
+    {
+      return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, 
+                                 memcached_literal_param("Delete triggers cannot be used if buffering is enabled"));
+    }
+
+    if (ptr->flags.no_reply)
+    {
+      return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, 
+                                 memcached_literal_param("Delete triggers cannot be used if MEMCACHED_BEHAVIOR_NOREPLY is set"));
+    }
+  }
+
+
+  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);
+
+  bool to_write= (ptr->flags.buffer_requests) ? false : true;
+
+  // Invert the logic to make it simpler to read the code
+  bool reply= (ptr->flags.no_reply) ? false : true;
+
+  if (ptr->flags.binary_protocol)
+  {
+    rc= binary_delete(ptr, instance, server_key, key, key_length, expiration, reply, to_write);
+  }
+  else
+  {
+    rc= ascii_delete(ptr, instance, server_key, key, key_length, expiration, reply, to_write);
+  }
+
+  if (rc == MEMCACHED_SUCCESS)
+  {
+    if (to_write == false)
+    {
+      rc= MEMCACHED_BUFFERED;
+    }
+    else if (reply)
+    {
+      char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+      rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+      if (rc == MEMCACHED_DELETED)
+      {
+        rc= MEMCACHED_SUCCESS;
+      }
+    }
+
+    if (rc == MEMCACHED_SUCCESS and ptr->delete_trigger)
+    {
+      ptr->delete_trigger(ptr, key, key_length);
+    }
+  }
+
+  LIBMEMCACHED_MEMCACHED_DELETE_END();
+  return rc;
+}
index d6b7f16613734bdea1e86c59a0339a8247eb8c2e..85ce84e82081b35383675216fcdbb73eda615211 100644 (file)
@@ -62,7 +62,9 @@ static void _set(memcached_server_st& server, memcached_st& memc)
 
   memcached_error_t *error= (struct memcached_error_t *)libmemcached_malloc(&memc, sizeof(struct memcached_error_t));
   if (not error) // Bad business if this happens
+  {
     return;
+  }
 
   memcpy(error, memc.error_messages, sizeof(memcached_error_t));
   error->next= server.error_messages;
index 5ae5850714dd93b01d6b1c19646404e8f40406b1..3097fdd0c0b5ca538fa572a812bc6bf4f1824aaf 100644 (file)
@@ -25,12 +25,13 @@ noinst_HEADERS+= \
                 libmemcached/io.h \
                 libmemcached/io.hpp \
                 libmemcached/is.h \
+                libmemcached/key.hpp \
                 libmemcached/libmemcached_probes.h \
+                libmemcached/memcached/protocol_binary.h \
+                libmemcached/memcached/vbucket.h \
                 libmemcached/memory.h \
                 libmemcached/namespace.h \
                 libmemcached/options.hpp \
-                libmemcached/memcached/protocol_binary.h \
-                libmemcached/memcached/vbucket.h \
                 libmemcached/protocol/ascii_handler.h \
                 libmemcached/protocol/binary_handler.h \
                 libmemcached/protocol/cache.h \
index 02e0c2b326dbfcb51400c04e8c2c17c3a36dd58e..ea98c729f02b92f5fdf187623dba9ec4a37b0ad0 100644 (file)
 
 #include <libmemcached/common.h>
 
-memcached_return_t memcached_key_test(const memcached_st &memc,
+memcached_return_t memcached_key_test(memcached_st &memc,
                                       const char * const *keys,
                                       const size_t *key_length,
                                       size_t number_of_keys)
 {
+  if (keys == NULL or key_length == NULL)
+  {
+    return memcached_set_error(memc, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT);
+  }
+
   if (not memc.flags.verify_key)
+  {
+    for (uint32_t x= 0; x < number_of_keys; x++)
+    {
+      memcached_return_t rc= memcached_validate_key_length(*(key_length +x), false);
+      if (memcached_failed(rc))
+      {
+        return rc;
+      }
+    }
+
     return MEMCACHED_SUCCESS;
+  }
 
   if (memc.flags.binary_protocol)
+  {
+    for (uint32_t x= 0; x < number_of_keys; x++)
+    {
+      memcached_return_t rc= memcached_validate_key_length(*(key_length +x), false);
+      if (memcached_failed(rc))
+      {
+        return rc;
+      }
+    }
+
     return MEMCACHED_SUCCESS;
+  }
 
   for (uint32_t x= 0; x < number_of_keys; x++)
   {
diff --git a/libmemcached/key.hpp b/libmemcached/key.hpp
new file mode 100644 (file)
index 0000000..ddd557d
--- /dev/null
@@ -0,0 +1,67 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ *
+ *      * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ *      * Redistributions in binary form must reproduce the above
+ *  copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ *      * The names of its contributors may not be used to endorse or
+ *  promote products derived from this software without specific prior
+ *  written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+memcached_return_t memcached_key_test(memcached_st& memc,
+                                      const char * const *keys,
+                                      const size_t *key_length,
+                                      size_t number_of_keys);
+
+static inline memcached_return_t memcached_validate_key_length(size_t key_length, bool binary)
+{
+  if (key_length == 0)
+  {
+    return MEMCACHED_BAD_KEY_PROVIDED;
+  }
+
+  if (binary)
+  {
+    if (key_length > 0xffff)
+    {
+      return MEMCACHED_BAD_KEY_PROVIDED;
+    }
+  }
+  else
+  {
+    if (key_length >= MEMCACHED_MAX_KEY)
+    {
+      return MEMCACHED_BAD_KEY_PROVIDED;
+    }
+  }
+
+  return MEMCACHED_SUCCESS;
+}
index 669979ef1cd154cec31587ccececd6bf94b34634..b91512832a59568602ce34c321eff5534da4ad32 100644 (file)
@@ -258,7 +258,7 @@ memcached_return_t memcached_server_execute(memcached_st *ptr,
   return MEMCACHED_SUCCESS;
 }
 
-memcached_server_instance_st memcached_server_by_key(const memcached_st *ptr,
+memcached_server_instance_st memcached_server_by_key(memcached_st *ptr,
                                                      const char *key,
                                                      size_t key_length,
                                                      memcached_return_t *error)
index 515adeeb8daeb735c30d0d1b31a63b3e187a1fee..88e2d101675fc61c55abbb39d7a8c44752263341 100644 (file)
@@ -323,8 +323,10 @@ static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat,
     size_t len= strlen(args);
 
     memcached_return_t rc= memcached_validate_key_length(len, true);
-    unlikely (rc != MEMCACHED_SUCCESS)
+    if (rc != MEMCACHED_SUCCESS)
+    {
       return rc;
+    }
 
     request.message.header.request.keylen= htons((uint16_t)len);
     request.message.header.request.bodylen= htonl((uint32_t) len);
index 0f1e1e0ad7044846d0f1a60b99077e407850ade7..74a20e05e8d3df44ebdd70584c155ad9a63d7c28 100644 (file)
@@ -160,6 +160,8 @@ do \
   } \
 } while (0)
 
+#define test_compare_hint test_compare_got
+
 #define test_compare_warn(__expected, __actual) \
 do \
 { \
index cca23464e01ac16d9b63aa21e2c5cdef6ca3395d..c0e76be96c45b006c431681c46e37240bfee1c1e 100644 (file)
@@ -3802,10 +3802,10 @@ static test_return_t set_namespace(memcached_st *memc)
   const char *key= "mine";
   char *value;
 
-  /* Make sure be default none exists */
+  // Make sure we default to a null namespace
   value= (char*)memcached_callback_get(memc, MEMCACHED_CALLBACK_NAMESPACE, &rc);
   test_null(value);
-  test_compare_got(MEMCACHED_FAILURE, rc, memcached_strerror(NULL, rc));
+  test_compare_got(MEMCACHED_SUCCESS, rc, memcached_strerror(NULL, rc));
 
   /* Test a clean set */
   test_compare(MEMCACHED_SUCCESS,
@@ -4358,6 +4358,10 @@ static void* connection_release(void *arg)
 
 static test_return_t connection_pool3_test(memcached_st *memc)
 {
+#ifdef __APPLE__
+  return TEST_SKIPPED;
+#endif
+
   memcached_pool_st* pool= memcached_pool_create(memc, 1, 1);
   test_true(pool);
 
@@ -4385,6 +4389,7 @@ static test_return_t connection_pool3_test(memcached_st *memc)
 
   memcached_return_t rc;
   memcached_st *pop_memc;
+  // We do a hard loop, and try N times
   int counter= 5;
   do
   {
@@ -4394,8 +4399,9 @@ static test_return_t connection_pool3_test(memcached_st *memc)
     if (memcached_failed(rc))
     {
       test_null(pop_memc);
+      test_true(rc != MEMCACHED_TIMEOUT); // As long as relative_time is zero, MEMCACHED_TIMEOUT is invalid
     }
-  } while (rc == MEMCACHED_TIMEOUT and --counter);
+  } while (--counter);
 
   if (memcached_failed(rc)) // Cleanup thread since we will exit once we test.
   {