Patch for "murmur" hash algorithm.
[awesomized/libmemcached] / lib / memcached_hash.c
index 74cd636059cc267cee8cb8c1e1b9793916a6b00a..f365cc0ee6815b817e3304573b316a0d3f098144 100644 (file)
-#include <memcached.h>
+#include "common.h"
 
-unsigned int memcached_generate_hash(char *key, size_t key_length)
+/* Defines */
+static uint64_t FNV_64_INIT= 0xcbf29ce484222325LL;
+static uint64_t FNV_64_PRIME= 0x100000001b3LL;
+
+static uint32_t FNV_32_INIT= 2166136261UL;
+static uint32_t FNV_32_PRIME= 16777619;
+
+/* Prototypes */
+static uint32_t internal_generate_hash(char *key, size_t key_length);
+static uint32_t internal_generate_md5(char *key, size_t key_length);
+static uint32_t internal_generate_ketama_md5(char *key, size_t key_length);
+
+unsigned int memcached_generate_hash(memcached_st *ptr, char *key, size_t key_length)
+{
+  uint32_t hash= 1; /* Just here to remove compile warning */
+  unsigned int x;
+
+  WATCHPOINT_ASSERT(ptr->number_of_hosts);
+
+  if (ptr->number_of_hosts == 1)
+    return 0;
+
+  switch (ptr->hash)
+  {
+  case MEMCACHED_HASH_DEFAULT:
+    hash= internal_generate_hash(key, key_length);
+    break;
+  case MEMCACHED_HASH_MD5:
+    hash= internal_generate_md5(key, key_length);
+    break;
+  case MEMCACHED_HASH_CRC:
+    hash= ((hash_crc32(key, key_length) >> 16) & 0x7fff);
+    if (hash == 0)
+      hash= 1;
+    break;
+    /* FNV hash'es lifted from Dustin Sallings work */
+  case MEMCACHED_HASH_FNV1_64: 
+    {
+      /* Thanks to pierre@demartines.com for the pointer */
+      uint64_t temp_hash;
+
+      temp_hash= FNV_64_INIT;
+      for (x= 0; x < key_length; x++) 
+      {
+        temp_hash *= FNV_64_PRIME;
+        temp_hash ^= key[x];
+      }
+      hash= (uint32_t)temp_hash;
+    }
+    break;
+  case MEMCACHED_HASH_FNV1A_64: 
+    {
+      hash= FNV_64_INIT;
+      for (x= 0; x < key_length; x++) 
+      {
+        hash ^= key[x];
+        hash *= FNV_64_PRIME;
+      }
+    }
+    break;
+  case MEMCACHED_HASH_FNV1_32: 
+    {
+      hash= FNV_32_INIT;
+      for (x= 0; x < key_length; x++) 
+      {
+        hash *= FNV_32_PRIME;
+        hash ^= key[x];
+      }
+    }
+    break;
+  case MEMCACHED_HASH_FNV1A_32: 
+    {
+      hash= FNV_32_INIT;
+      for (x= 0; x < key_length; x++) 
+      {
+        hash ^= key[x];
+        hash *= FNV_32_PRIME;
+      }
+    }
+    break;
+    case MEMCACHED_HASH_KETAMA: 
+    {
+      hash= internal_generate_ketama_md5(key, key_length);
+      break;
+    }
+    case MEMCACHED_HASH_HSIEH:
+    {
+      hash= hsieh_hash(key, key_length);
+      break;
+    }
+    case MEMCACHED_HASH_MURMUR:
+    {
+      hash= murmur_hash(key, key_length);
+      break;
+    }
+  }
+
+  WATCHPOINT_ASSERT(hash);
+
+  if (ptr->distribution == MEMCACHED_DISTRIBUTION_MODULA)
+  {
+    return hash % ptr->number_of_hosts;
+  }
+  else
+  {
+    unsigned int server_key;
+
+    server_key= hash % MEMCACHED_WHEEL_SIZE;
+
+    return ptr->wheel[server_key];
+  }
+}
+
+static uint32_t internal_generate_hash(char *key, size_t key_length)
 {
-  unsigned int x = key_length;
-  char *ptr = key;
-  unsigned int value = 0;
+  char *ptr= key;
+  uint32_t value= 0;
 
-  while (x--
+  while (--key_length
   {
     value += *ptr++;
     value += (value << 10);
@@ -18,3 +130,27 @@ unsigned int memcached_generate_hash(char *key, size_t key_length)
 
   return value == 0 ? 1 : value;
 }
+
+static uint32_t internal_generate_md5(char *key, size_t key_length)
+{
+  unsigned char results[16];
+
+  md5_signature((unsigned char*)key, (unsigned int)key_length, results);
+
+  return (uint32_t)(( results[3] << 24 )
+                    | ( results[2] << 16 )
+                    | ( results[1] <<  8 )
+                    |   results[0] );
+}
+
+static uint32_t internal_generate_ketama_md5(char *key, size_t key_length)
+{
+  unsigned char results[16];
+
+  md5_signature((unsigned char*)key, (unsigned int)key_length, results);
+
+  return ((uint32_t) (results[3] & 0xFF) << 24)
+    | ((uint32_t) (results[2] & 0xFF) << 16)
+    | ((uint32_t) (results[1] & 0xFF) << 8)
+    | (results[0] & 0xFF);
+}