Extended consistent hash logic to handle splice (should distribute keys much
author <brian@gir.local> <>
Thu, 29 Nov 2007 03:48:02 +0000 (19:48 -0800)
committer <brian@gir.local> <>
Thu, 29 Nov 2007 03:48:02 +0000 (19:48 -0800)
more evenly then previous design).

include/memcached.h
lib/memcached.c
lib/memcached_hash.c
lib/memcached_hosts.c

index 3d1bfcd873180e64ecbec4d8cd79e819655aa065..194170ef1427959f0e067ac940e69e1e3a40c38f 100644 (file)
@@ -33,6 +33,8 @@ typedef struct memcached_server_st memcached_server_st;
 #define MEMCACHED_MAX_KEY 251 /* We add one to have it null terminated */
 #define MEMCACHED_MAX_BUFFER HUGE_STRING_LEN
 #define MEMCACHED_MAX_HOST_LENGTH 64
+#define MEMCACHED_WHEEL_SIZE 1024
+#define MEMCACHED_STRIDE 4
 
 typedef enum {
   MEMCACHED_SUCCESS,
@@ -67,6 +69,11 @@ typedef enum {
   MEMCACHED_MAXIMUM_RETURN, /* Always add new error code before */
 } memcached_return;
 
+typedef enum {
+  MEMCACHED_DISTRIBUTION_MODULUS,
+  MEMCACHED_DISTRIBUTION_CONSISTENT,
+} memcached_server_distribution;
+
 typedef enum {
   MEMCACHED_BEHAVIOR_NO_BLOCK,
   MEMCACHED_BEHAVIOR_TCP_NODELAY,
@@ -184,6 +191,8 @@ struct memcached_st {
   int32_t poll_timeout;
   memcached_string_st result_buffer;
   memcached_hash hash;
+  memcached_server_distribution distribution;
+  unsigned int wheel[MEMCACHED_WHEEL_SIZE];
   memcached_return warning; /* Future Use */
 };
 
index e40c3db4c229d1b02e984abb7daa2aba439b2c70..1ed39a915feb628e759369dba68be4f5acb4079e 100644 (file)
@@ -23,6 +23,7 @@ memcached_st *memcached_create(memcached_st *ptr)
   string_ptr= memcached_string_create(ptr, &ptr->result_buffer, 0);
   WATCHPOINT_ASSERT(string_ptr);
   ptr->poll_timeout= -1;
+  ptr->distribution= MEMCACHED_DISTRIBUTION_MODULUS;
 
   return ptr;
 }
@@ -75,6 +76,7 @@ memcached_st *memcached_clone(memcached_st *clone, memcached_st *ptr)
   new_clone->send_size= ptr->send_size;
   new_clone->recv_size= ptr->recv_size;
   new_clone->poll_timeout= ptr->poll_timeout;
+  new_clone->distribution= ptr->distribution;
 
   return new_clone;
 }
index 9cc846a80e8ab568b047d4b7e8c9896a9b4f9da9..95d7f8622d23975e61015d38ff9e49c8450e9a11 100644 (file)
@@ -85,18 +85,18 @@ unsigned int memcached_generate_hash(memcached_st *ptr, char *key, size_t key_le
   }
 
   WATCHPOINT_ASSERT(hash);
-  if (ptr->flags & MEM_USE_KETAMA)
+
+  if (ptr->distribution == MEMCACHED_DISTRIBUTION_MODULUS)
   {
-    WATCHPOINT_ASSERT(0);
-    return 0;
+    return hash % ptr->number_of_hosts;
   }
   else
   {
     unsigned int server_key;
 
-    server_key= hash % ptr->number_of_hosts;
+    server_key= hash % MEMCACHED_WHEEL_SIZE;
 
-    return server_key;
+    return ptr->wheel[server_key];
   }
 }
 
index 0090625c4ff2bef08dd6a18a7acc3a296900d157..3517d824698c4f359d9e188ff1734bc5e49614da 100644 (file)
@@ -6,6 +6,34 @@ static memcached_return server_add(memcached_st *ptr, char *hostname,
                                    unsigned int port,
                                    memcached_connection type);
 
+#define MEMCACHED_WHEEL_SIZE 1024
+#define MEMCACHED_STRIDE 4
+static void rebalance_wheel(memcached_st *ptr)
+{
+  unsigned int x;
+  unsigned int y;
+  unsigned int latch;
+  unsigned int range;
+
+  range= (MEMCACHED_WHEEL_SIZE / ptr->number_of_hosts);
+
+  /* Seed the Wheel */
+  memset(ptr->wheel, 0, sizeof(unsigned int) * MEMCACHED_WHEEL_SIZE);
+
+  for (latch= y= x= 0; x < MEMCACHED_WHEEL_SIZE; x++, latch++)
+  {
+    if (latch == MEMCACHED_STRIDE)
+    {
+      y++;
+      if (y == ptr->number_of_hosts)
+        y= 0;
+      latch= 0;
+    }
+
+    ptr->wheel[x]= y;
+  }
+}
+
 static void host_reset(memcached_server_st *host, char *hostname, unsigned int port,
                        memcached_connection type)
 {
@@ -48,6 +76,8 @@ memcached_return memcached_server_push(memcached_st *ptr, memcached_server_st *l
   }
   ptr->hosts[0].count= ptr->number_of_hosts;
 
+  rebalance_wheel(ptr);
+
   return MEMCACHED_SUCCESS;
 }
 
@@ -104,6 +134,8 @@ static memcached_return server_add(memcached_st *ptr, char *hostname,
   ptr->number_of_hosts++;
   ptr->hosts[0].count++;
 
+  rebalance_wheel(ptr);
+
   LIBMEMCACHED_MEMCACHED_SERVER_ADD_END();
 
   return MEMCACHED_SUCCESS;