Merge
author <brian@gir-2.local> <>
Wed, 13 Feb 2008 11:54:25 +0000 (17:24 +0530)
committer <brian@gir-2.local> <>
Wed, 13 Feb 2008 11:54:25 +0000 (17:24 +0530)
15 files changed:
ChangeLog
THANKS
docs/memcached_behavior.pod
include/memcached.h
lib/Makefile.am
lib/common.h
lib/memcached_auto.c
lib/memcached_behavior.c
lib/memcached_get.c
lib/memcached_hosts.c
lib/memcached_storage.c
lib/memcached_strerror.c
src/memslap.c
tests/atomsmasher.c
tests/function.c

index 234175fc14395b53ef73e72a3230a0d1d0844a12..e6228373142009cdad6ca2b5482a56e26fb26987 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,14 @@
   * Work on the UDP protocol
   * Added get_by_key, set_by_key tests for C++ API
   * Fix for limit_maxbytes to be 64bit in stats
+  * Added Atom Smasher test (scale baby, scale!)
+  * Servers are now sorted, meaning that servers are now ordered so that
+    clients with the same lists, will have same distribution. (Idea from
+    Ross McFarland). MEMCACHED_BEHAVIOR_SORT_HOSTS was added to enable
+    this support.
+  * Added MEMCACHED_BAD_KEY_PROVIDED error for auto, set, and get operations 
+    when the library is compiled with --enable-debug. This additional code
+    will test for bad keys.
   
 0.15 Tue Jan 29 14:55:44 PST 2008
   * More work on the C++ API.
diff --git a/THANKS b/THANKS
index efbd621fd3633292b349cb1bf73142a56fe27fd6..45809cec22285ddc2682a4039559295c7c1885cb 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -7,3 +7,4 @@ Brian Pontz - Hsieh hash
 Tim Bunce - Perl Driver work and feedback on API
 Kevin Dalley - Bug Fixes
 Patrick Galbraith - work on C++ interface
+Ross McFarland - Idea for sorting servers.
index 25986cdf9082fdba76406d70fd082be2828c0dcb..e71f1438ff1fa52df95e0bb984dbd8fda6082b14 100755 (executable)
@@ -88,6 +88,11 @@ action that gets data causes this buffer to be be sent to the remote
 connection. Quiting the connection or closing down the connection will also
 cause the buffered data to be pushed to the remote connection. 
 
+=item MEMCACHED_BEHAVIOR_SORT_HOSTS
+
+Enabling this will cause hosts that are added to be placed in the host list in 
+sorted order. This will defeat consisten hashing.
+
 =back
 
 =head1 RETURN
index bdeb53983882377bd0b39e28ac03ebc846799c93..92000fe8ae11eb74bc12a647dc48bfce557c86bc 100644 (file)
@@ -67,6 +67,7 @@ typedef enum {
   MEMCACHED_FETCH_NOTFINISHED,
   MEMCACHED_TIMEOUT,
   MEMCACHED_BUFFERED,
+  MEMCACHED_BAD_KEY_PROVIDED,
   MEMCACHED_MAXIMUM_RETURN, /* Always add new error code before */
 } memcached_return;
 
@@ -99,6 +100,7 @@ typedef enum {
   MEMCACHED_BEHAVIOR_DISTRIBUTION,
   MEMCACHED_BEHAVIOR_BUFFER_REQUESTS,
   MEMCACHED_BEHAVIOR_USER_DATA,
+  MEMCACHED_BEHAVIOR_SORT_HOSTS,
 } memcached_behavior;
 
 typedef enum {
index 5589e3b967423bdf4139d912779b48196d6f637c..0783bcf43d2fe2fcc178576622583eeecc7b4ca0 100644 (file)
@@ -43,6 +43,7 @@ libmemcached_la_SOURCES = crc.c \
                          memcached_hosts.c \
                          memcached_io.c \
                          md5.c \
+                         memcached_key.c \
                          memcached_quit.c \
                          memcached_parse.c \
                          memcached_response.c \
index 3c707143e9bbdc9bc275448300c0c3941f4d04cd..ff54fe5738179c1a066ded2f826e4360698bee73 100644 (file)
@@ -21,7 +21,7 @@
 #include <fcntl.h>
 #include <sys/un.h>
 #include <netinet/tcp.h>
-#include "libmemcached_config.h"
+#include <libmemcached_config.h>
 
 #if TIME_WITH_SYS_TIME
 # include <sys/time.h>
@@ -65,6 +65,7 @@ typedef enum {
   MEM_USE_CACHE_LOOKUPS= (1 << 6),
   MEM_SUPPORT_CAS= (1 << 7),
   MEM_BUFFER_REQUESTS= (1 << 8),
+  MEM_USE_SORT_HOSTS= (1 << 9),
 } memcached_flags;
 
 /* Hashing algo */
@@ -110,5 +111,13 @@ memcached_return value_fetch(memcached_server_st *ptr,
                              memcached_result_st *result);
 void server_list_free(memcached_st *ptr, memcached_server_st *servers);
 
+memcached_return key_proof(char **keys, size_t *key_length, 
+                           unsigned int number_of_keys);
+
+#ifdef HAVE_DEBUG
+#define key_test(A,B,C) key_proof(A,B,C)
+#else
+#define key_test(A,B,C) MEMCACHED_SUCCESS
+#endif
 
 #endif /* __COMMON_H__ */
index 4af85e97bd385d56951aed7b192022482f23119b..36780dc5409f3dee8dc5151cf1c8dc1ed96cd06a 100644 (file)
@@ -17,6 +17,9 @@ static memcached_return memcached_auto(memcached_st *ptr,
   if (ptr->hosts == NULL || ptr->number_of_hosts == 0)
     return MEMCACHED_NO_SERVERS;
 
+  if (key_test(&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)
+    return MEMCACHED_BAD_KEY_PROVIDED;
+
   server_key= memcached_generate_hash(ptr, key, key_length);
 
   send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
index 62b767f7b037a85ca473d142fec64e044ba58204..1458c1a9a9372272c19850b17198a8f6ce2ce6a6 100644 (file)
@@ -49,6 +49,9 @@ memcached_return memcached_behavior_set(memcached_st *ptr,
   case MEMCACHED_BEHAVIOR_KETAMA:
     set_behavior_flag(ptr, MEM_USE_KETAMA, data);
     break;
+  case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+    set_behavior_flag(ptr, MEM_USE_SORT_HOSTS, data);
+    break;
   case MEMCACHED_BEHAVIOR_USER_DATA:
     ptr->user_data= data;
     break;
@@ -107,6 +110,9 @@ unsigned long long memcached_behavior_get(memcached_st *ptr,
   case MEMCACHED_BEHAVIOR_KETAMA:
     temp_flag= MEM_USE_KETAMA;
     break;
+  case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+    temp_flag= MEM_USE_SORT_HOSTS;
+    break;
   case MEMCACHED_BEHAVIOR_USER_DATA:
     return 0;
     //return (unsigned long long)ptr->user_data;
index 8c3180ab9caf7e39ea7e43815e34d2354bfe7424..cfbb13f43dfb40419a9db32bcd7c6217fa195cd7 100644 (file)
@@ -75,6 +75,9 @@ memcached_return memcached_mget_by_key(memcached_st *ptr,
   if (ptr->number_of_hosts == 0)
     return MEMCACHED_NO_SERVERS;
 
+  if (key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED)
+    return MEMCACHED_BAD_KEY_PROVIDED;
+
   if (ptr->flags & MEM_SUPPORT_CAS)
   {
     get_command= "gets ";
index 760eb39137615f1b1628d9855806484e1efd29a8..de006dd6794b6b5125583e24dfa2bd10e5786d78 100644 (file)
@@ -31,6 +31,25 @@ static void rebalance_wheel(memcached_st *ptr)
   }
 }
 
+static int compare_servers(const void *p1, const void *p2)
+{
+  int return_value;
+  memcached_server_st *a= (memcached_server_st *)p1;
+  memcached_server_st *b= (memcached_server_st *)p2;
+
+  return_value= strcmp(a->hostname, b->hostname);
+
+  if (return_value == 0)
+  {
+    if (a->port > b->port)
+      return_value++;
+    else
+      return_value--;
+  }
+
+  return return_value;
+}
+
 static void host_reset(memcached_st *ptr, memcached_server_st *host, 
                        char *hostname, unsigned int port,
                        memcached_connection type)
@@ -96,6 +115,9 @@ memcached_return memcached_server_push(memcached_st *ptr, memcached_server_st *l
   }
   ptr->hosts[0].count= ptr->number_of_hosts;
 
+  if (ptr->number_of_hosts > 1)
+    qsort(ptr->hosts, ptr->number_of_hosts, sizeof(memcached_server_st), compare_servers);
+
   rebalance_wheel(ptr);
 
   return MEMCACHED_SUCCESS;
@@ -158,6 +180,9 @@ static memcached_return server_add(memcached_st *ptr, char *hostname,
   ptr->number_of_hosts++;
   ptr->hosts[0].count++;
 
+  if (ptr->number_of_hosts > 1)
+    qsort(ptr->hosts, ptr->number_of_hosts, sizeof(memcached_server_st), compare_servers);
+
   rebalance_wheel(ptr);
 
   LIBMEMCACHED_MEMCACHED_SERVER_ADD_END();
@@ -197,6 +222,13 @@ memcached_server_st *memcached_server_list_append(memcached_server_st *ptr,
   /* Backwards compatibility hack */
   new_host_list[0].count++;
 
+  count= new_host_list[0].count;
+
+  if (new_host_list[0].count > 1)
+    qsort(new_host_list, count, sizeof(memcached_server_st), compare_servers);
+
+  new_host_list[0].count= count;
+
 
   *error= MEMCACHED_SUCCESS;
   return new_host_list;
index d8b124325aafb4c08270f0cadae4f423aa85e8bc..30585095fa9b8588b5e4cc3026217111702cd7c3 100644 (file)
@@ -66,6 +66,9 @@ static inline memcached_return memcached_send(memcached_st *ptr,
   if (ptr->number_of_hosts == 0)
     return MEMCACHED_NO_SERVERS;
 
+  if (key_test(&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)
+    return MEMCACHED_BAD_KEY_PROVIDED;
+
   server_key= memcached_generate_hash(ptr, master_key, master_key_length);
 
   if (cas)
index 8b8438bbf8c556a5636930835c5a502af59ef5d7..3271682d2fdfeed1b902e674d5306a674248c826 100644 (file)
@@ -68,6 +68,8 @@ char *memcached_strerror(memcached_st *ptr, memcached_return rc)
     return "ACTION QUEUED";
   case MEMCACHED_TIMEOUT:
     return "A TIMEOUT OCCURRED";
+  case MEMCACHED_BAD_KEY_PROVIDED:
+    return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE";
   case MEMCACHED_MAXIMUM_RETURN:
     return "Gibberish returned!";
   default:
index 1d3f87915fa3efd515bf05d51d2a1832e9dd504b..899d8b81af45ea9852cc056985660dce388f65fe 100644 (file)
 #define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
 
 /* Global Thread counter */
-unsigned int thread_counter;
+volatile unsigned int thread_counter;
 pthread_mutex_t counter_mutex;
 pthread_cond_t count_threshhold;
-unsigned int master_wakeup;
+volatile unsigned int master_wakeup;
 pthread_mutex_t sleeper_mutex;
 pthread_cond_t sleep_threshhold;
 
index c267fcee546b24e3dc45b2467493b4c8a57eef55..abe3a21e9cec52ab99e7d868ff099a5f7cba2a33 100644 (file)
 
 #include "test.h"
 
+/* Number of items generated for tests */
 #define GLOBAL_COUNT 100000
-#define TEST_COUNTER 100000
+
+/* Number of times to run the test loop */
+#define TEST_COUNTER 500000
 static uint32_t global_count;
 
 static pairs_st *global_pairs;
@@ -60,45 +63,51 @@ uint8_t drizzle(memcached_st *memc)
 {
   unsigned int x;
   memcached_return rc;
+  char *return_value;
+  size_t return_value_length;
+  uint32_t flags;
 
+infinite:
+  for (x= 0; x < TEST_COUNTER; x++)
   {
-    char *return_value;
-    size_t return_value_length;
-    uint32_t flags;
-
-    for (x= 0; x < TEST_COUNTER; x++)
-    {
-      uint32_t test_bit;
-      uint8_t which;
+    uint32_t test_bit;
+    uint8_t which;
 
-      test_bit= random() % GLOBAL_COUNT;
-      which= random() % 2;
+    test_bit= random() % GLOBAL_COUNT;
+    which= random() % 2;
 
-      if (which == 0)
-      {
-        return_value= memcached_get(memc, global_keys[test_bit], global_keys_length[test_bit],
-                                    &return_value_length, &flags, &rc);
-        if (rc == MEMCACHED_SUCCESS && return_value)
-          free(return_value);
-        else
-          WATCHPOINT_ERROR(rc);
-      } 
+    if (which == 0)
+    {
+      return_value= memcached_get(memc, global_keys[test_bit], global_keys_length[test_bit],
+                                  &return_value_length, &flags, &rc);
+      if (rc == MEMCACHED_SUCCESS && return_value)
+        free(return_value);
+      else if (rc == MEMCACHED_NOTFOUND)
+        continue;
       else
       {
-        rc= memcached_set(memc, global_pairs[test_bit].key, 
-                          global_pairs[test_bit].key_length,
-                          global_pairs[test_bit].value, 
-                          global_pairs[test_bit].value_length,
-                          0, 0);
-        if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
-        {
-          WATCHPOINT_ERROR(rc);
-          WATCHPOINT_ASSERT(0);
-        }
+        WATCHPOINT_ERROR(rc);
+        WATCHPOINT_ASSERT(rc);
+      }
+    } 
+    else
+    {
+      rc= memcached_set(memc, global_pairs[test_bit].key, 
+                        global_pairs[test_bit].key_length,
+                        global_pairs[test_bit].value, 
+                        global_pairs[test_bit].value_length,
+                        0, 0);
+      if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
+      {
+        WATCHPOINT_ERROR(rc);
+        WATCHPOINT_ASSERT(0);
       }
     }
   }
 
+  if (getenv("MEMCACHED_ATOM_BURIN_IN"))
+    goto infinite;
+
   return 0;
 }
 
@@ -142,19 +151,20 @@ memcached_return enable_consistent(memcached_st *memc)
   return MEMCACHED_SUCCESS;
 }
 
-test_st generate_tests[] ={
+test_st smash_tests[] ={
   {"generate_pairs", 1, generate_pairs },
+  {"drizzle", 1, drizzle },
   {"cleanup", 1, cleanup_pairs },
   {0, 0, 0}
 };
 
 
 collection_st collection[] ={
-  {"generate", 0, 0, generate_tests},
-  {"generate_hsieh", pre_hsieh, 0, generate_tests},
-  {"generate_hsieh_consistent", enable_consistent, 0, generate_tests},
-  {"generate_md5", pre_md5, 0, generate_tests},
-  {"generate_nonblock", pre_nonblock, 0, generate_tests},
+  {"smash", 0, 0, smash_tests},
+  {"smash_hsieh", pre_hsieh, 0, smash_tests},
+  {"smash_hsieh_consistent", enable_consistent, 0, smash_tests},
+  {"smash_md5", pre_md5, 0, smash_tests},
+  {"smash_nonblock", pre_nonblock, 0, smash_tests},
   {0, 0, 0, 0}
 };
 
index 2b01a268dd70354cd686ffaf9ff3e06d04a6cf53..b971134e2c8c33afc2e70f896b758d85f10c3025 100644 (file)
@@ -61,6 +61,32 @@ uint8_t server_list_null_test(memcached_st *ptr)
   return 0;
 }
 
+uint8_t server_sort_test(memcached_st *ptr)
+{
+  unsigned int setting;
+  memcached_server_st *server_list;
+  memcached_return rc;
+
+  setting= 1;
+  memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_SORT_HOSTS, &setting);
+
+  server_list= memcached_server_list_append(NULL, "arg", 0, &rc);
+  assert(server_list);
+
+  server_list= memcached_server_list_append(server_list, "localhost", 0, &rc);
+  assert(server_list);
+
+  server_list= memcached_server_list_append(server_list, "c", 0, &rc);
+  assert(server_list);
+
+  server_list= memcached_server_list_append(server_list, "abba", 0, &rc);
+  assert(server_list);
+
+  free(server_list);
+
+  return 0;
+}
+
 uint8_t allocation_test(memcached_st *not_used)
 {
   memcached_st *memc;
@@ -435,6 +461,25 @@ uint8_t flush_test(memcached_st *memc)
   return 0;
 }
 
+uint8_t bad_key_test(memcached_st *memc)
+{
+#ifdef HAVE_DEBUG
+  memcached_return rc;
+  char *key= "foo bad";
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+
+  string= memcached_get(memc, key, strlen(key),
+                        &string_length, &flags, &rc);
+  assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
+  assert(string_length ==  0);
+  assert(!string);
+#endif
+
+  return 0;
+}
+
 uint8_t get_test(memcached_st *memc)
 {
   memcached_return rc;
@@ -2312,6 +2357,7 @@ test_st tests[] ={
   {"init", 0, init_test },
   {"allocation", 0, allocation_test },
   {"server_list_null_test", 0, server_list_null_test},
+  {"server_sort", 0, server_sort_test},
   {"clone_test", 0, clone_test },
   {"error", 0, error_test },
   {"set", 0, set_test },
@@ -2338,6 +2384,7 @@ test_st tests[] ={
   {"behavior_test", 0, get_stats_keys },
   {"callback_test", 0, get_stats_keys },
   {"version_string_test", 0, version_string_test},
+  {"bad_key", 1, bad_key_test },
   {0, 0, 0}
 };