Added MEMCACHED_HASH_HSIEH.
authorBrian Aker <brian@tangent.org>
Sun, 25 Nov 2007 22:01:18 +0000 (14:01 -0800)
committerBrian Aker <brian@tangent.org>
Sun, 25 Nov 2007 22:01:18 +0000 (14:01 -0800)
ChangeLog
THANKS
include/memcached.h
lib/Makefile.am
lib/common.h
lib/hsieh_hash.c [new file with mode: 0644]
lib/memcached_hash.c
lib/memcached_stats.c
tests/function.c

index 14b627de908ebe7c6cda90b552b482f51804056f..338adce12af3dc0022a725b34bbfa05d42d87f4d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,8 @@
     did not need to be enabled to be enabled (performance issue).
   * Rewrote bounds checking code for get calls.
   * "make test" now starts its own memcached servers.
+  * Added Hseih hash (MEMCACHED_HASH_HSIEH), which is showing about 7%
+    performance over standard hash.
 
 0.10 Tue Nov 20 23:22:31 PST 2007
   * Added append binary test.
diff --git a/THANKS b/THANKS
index 1aea2bf0a704b5ea42853dcef40f7c4aaba831aa..d5ee9764c8a4609febf46b72b4847add799456cf 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -3,3 +3,4 @@ Cal Heldenbrand - Awesome feedback on performance
 Dustin Sallings - Insight into protocol
 Tobias Luetke - Performance Feedback
 Andre Cruz - Help with getting the CRC Hash function to match other connectors
+Brian Pontz - Hsieh hash
index bf50f456c2acb0cb0fb5e3dfb1a6b37c42967a03..4e60cca0fa2a6475133b4a5f56ea973a4685dfbd 100644 (file)
@@ -87,6 +87,7 @@ typedef enum {
   MEMCACHED_HASH_FNV1_32,
   MEMCACHED_HASH_FNV1A_32,
   MEMCACHED_HASH_KETAMA,
+  MEMCACHED_HASH_HSIEH,
 } memcached_hash;
 
 typedef enum {
index 8a96e41ef2b2d62f7d333d40ddbcd628eebe1579..62673bc96d698da34cb66f4f074a345b60f65725 100644 (file)
@@ -26,6 +26,7 @@ noinst_HEADERS = libmemcached_probes.h \
 
 lib_LTLIBRARIES = libmemcached.la
 libmemcached_la_SOURCES = crc.c \
+                         hsieh_hash.c \
                          memcached.c \
                          memcached_auto.c \
                          memcached_behavior.c \
index 73913c1c05e98f187ddee33687470b4821db4f4c..d4a7baca7a002676e0607ca3287626122cca49b8 100644 (file)
@@ -51,6 +51,7 @@ typedef enum {
 void md5_signature(unsigned char *key, unsigned int length, unsigned char *result);
 uint32_t hash_crc32(const char *data,
                     size_t data_len);
+uint32_t hsieh_hash(char *key, size_t key_length);
 
 memcached_return memcached_connect(memcached_st *ptr, unsigned int server_key);
 memcached_return memcached_response(memcached_st *ptr, 
diff --git a/lib/hsieh_hash.c b/lib/hsieh_hash.c
new file mode 100644 (file)
index 0000000..9f42a94
--- /dev/null
@@ -0,0 +1,65 @@
+/* By Paul Hsieh (C) 2004, 2005.  Covered under the Paul Hsieh
+ * derivative license. 
+ * See: http://www.azillionmonkeys.com/qed/weblicense.html for license
+ * details.
+ * http://www.azillionmonkeys.com/qed/hash.html
+*/
+
+#include "common.h"
+
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__))
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+                      +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+uint32_t hsieh_hash(char *key, size_t key_length)
+{
+  uint32_t hash = 0, tmp;
+  int rem;
+
+  if (key_length <= 0 || key == NULL) return 0;
+
+  rem = key_length & 3;
+  key_length >>= 2;
+
+  /* Main loop */
+  for (;key_length > 0; key_length--) {
+    hash  += get16bits (key);
+    tmp    = (get16bits (key+2) << 11) ^ hash;
+    hash   = (hash << 16) ^ tmp;
+    key  += 2*sizeof (uint16_t);
+    hash  += hash >> 11;
+  }
+
+  /* Handle end cases */
+  switch (rem) {
+  case 3: hash += get16bits (key);
+          hash ^= hash << 16;
+          hash ^= key[sizeof (uint16_t)] << 18;
+          hash += hash >> 11;
+          break;
+  case 2: hash += get16bits (key);
+          hash ^= hash << 11;
+          hash += hash >> 17;
+          break;
+  case 1: hash += *key;
+          hash ^= hash << 10;
+          hash += hash >> 1;
+  }
+
+  /* Force "avalanching" of final 127 bits */
+  hash ^= hash << 3;
+  hash += hash >> 5;
+  hash ^= hash << 4;
+  hash += hash >> 17;
+  hash ^= hash << 25;
+  hash += hash >> 6;
+
+  return hash;
+}
+
index 32e82e76d8623c99ddb89d3d657dfde32c192d50..9cc846a80e8ab568b047d4b7e8c9896a9b4f9da9 100644 (file)
@@ -77,6 +77,11 @@ unsigned int memcached_generate_hash(memcached_st *ptr, char *key, size_t key_le
       hash= internal_generate_ketama_md5(key, key_length);
       break;
     }
+    case MEMCACHED_HASH_HSIEH:
+    {
+      hash= hsieh_hash(key, key_length);
+      break;
+    }
   }
 
   WATCHPOINT_ASSERT(hash);
index aea668756d8535f0528494463df5857f9092d421..04ef31ba2678f69767b2f99a07758c25dbdec499 100644 (file)
@@ -93,27 +93,27 @@ static void set_data(memcached_stat_st *stat, char *key, char *value)
   }
   else if (!memcmp("connection_structures", key, strlen("connection_structures")))
   {
-    //stat->connection_structures= strtol(value, (char **)NULL, 10);
+    stat->connection_structures= strtol(value, (char **)NULL, 10);
   }
   else if (!memcmp("cmd_get", key, strlen("cmd_get")))
   {
-    //stat->cmd_get= strtoll(value, (char **)NULL, 10);
+    stat->cmd_get= strtoll(value, (char **)NULL, 10);
   }
   else if (!memcmp("cmd_set", key, strlen("cmd_set")))
   {
-    //stat->cmd_set= strtoll(value, (char **)NULL, 10);
+    stat->cmd_set= strtoll(value, (char **)NULL, 10);
   }
   else if (!memcmp("get_hits", key, strlen("get_hits")))
   {
-    //stat->get_hits= strtoll(value, (char **)NULL, 10);
+    stat->get_hits= strtoll(value, (char **)NULL, 10);
   }
   else if (!memcmp("get_misses", key, strlen("get_misses")))
   {
-    //stat->get_misses= (uint64_t)strtoll(value, (char **)NULL, 10);
+    stat->get_misses= (uint64_t)strtoll(value, (char **)NULL, 10);
   }
   else if (!memcmp("evictions", key, strlen("evictions")))
   {
-    //stat->evictions= (uint64_t)strtoll(value, (char **)NULL, 10);
+    stat->evictions= (uint64_t)strtoll(value, (char **)NULL, 10);
   }
   else if (!memcmp("bytes_read", key, strlen("bytes_read")))
   {
@@ -125,7 +125,7 @@ static void set_data(memcached_stat_st *stat, char *key, char *value)
   }
   else if (!memcmp("limit_maxbytes", key, strlen("limit_maxbytes")))
   {
-    //stat->limit_maxbytes= strtol(value, (char **)NULL, 10);
+    stat->limit_maxbytes= strtol(value, (char **)NULL, 10);
   }
   else if (!memcmp("threads", key, strlen("threads")))
   {
index 4ab8fc26d9595f55ad46fd87d6f896016f3f9a42..b5af2b5038eb7cae54dc6f58f4244a624ce723a4 100644 (file)
@@ -1576,6 +1576,14 @@ memcached_return pre_crc(memcached_st *memc)
   return MEMCACHED_SUCCESS;
 }
 
+memcached_return pre_hsieh(memcached_st *memc)
+{
+  memcached_hash value= MEMCACHED_HASH_HSIEH;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, &value);
+
+  return MEMCACHED_SUCCESS;
+}
+
 memcached_return pre_hash_fnv1_64(memcached_st *memc)
 {
   memcached_hash value= MEMCACHED_HASH_FNV1_64;
@@ -1786,6 +1794,7 @@ collection_st collection[] ={
   {"nodelay", pre_nodelay, 0, tests},
   {"md5", pre_md5, 0, tests},
   {"crc", pre_crc, 0, tests},
+  {"hsieh", pre_hsieh, 0, tests},
   {"fnv1_64", pre_hash_fnv1_64, 0, tests},
   {"fnv1a_64", pre_hash_fnv1a_64, 0, tests},
   {"fnv1_32", pre_hash_fnv1_32, 0, tests},
@@ -1801,6 +1810,7 @@ collection_st collection[] ={
   {"result", 0, 0, result_tests},
   {"user", 0, 0, user_tests},
   {"generate", 0, 0, generate_tests},
+  {"generate_hsieh", pre_hsieh, 0, generate_tests},
   {"generate_nonblock", pre_nonblock, 0, generate_tests},
   {0, 0, 0, 0}
 };