Browse Source

lib: Better hashing of string values using Bernstein hash

* hash.{h,c}: (string_hash_make) Hash optimised for strings, current
  implementation using Bernstein hash, which offers a good compromise
  between distribution and performance.
* distribute.c: (distribute_hash_make) use previous instead of additive
  string hash.
* if_rmap.c: (if_rmap_hash_make) ditto
Stephen Hemminger 9 years ago
parent
commit
6392aa83c4
4 changed files with 19 additions and 16 deletions
  1. 4 9
      lib/distribute.c
  2. 11 0
      lib/hash.c
  3. 2 0
      lib/hash.h
  4. 2 7
      lib/if_rmap.c

+ 4 - 9
lib/distribute.c

@@ -114,16 +114,11 @@ distribute_get (const char *ifname)
 }
 
 static unsigned int
-distribute_hash_make (struct distribute *dist)
+distribute_hash_make (void *arg)
 {
-  unsigned int i, key;
+  const struct distribute *dist = arg;
 
-  key = 0;
-  if (dist->ifname)
-    for (i = 0; i < strlen (dist->ifname); i++)
-      key += dist->ifname[i];
-
-  return key;
+  return dist->ifname ? string_hash_make (dist->ifname) : 0;
 }
 
 /* If two distribute-list have same value then return 1 else return
@@ -763,7 +758,7 @@ distribute_list_reset ()
 void
 distribute_list_init (int node)
 {
-  disthash = hash_create ((unsigned int (*) (void *)) distribute_hash_make,
+  disthash = hash_create (distribute_hash_make,
                           (int (*) (const void *, const void *)) distribute_cmp);
 
   if(node==RIP_NODE) {

+ 11 - 0
lib/hash.c

@@ -101,6 +101,17 @@ hash_lookup (struct hash *hash, void *data)
   return hash_get (hash, data, NULL);
 }
 
+/* Simple Bernstein hash which is simple and fast for common case */
+unsigned int string_hash_make (const char *str)
+{
+  unsigned int hash = 0;
+
+  while (*str)
+    hash = (hash * 33) ^ (unsigned int) *str++;
+
+  return hash;
+}
+
 /* This function release registered value from specified hash.  When
    release is successfully finished, return the data pointer in the
    hash backet.  */

+ 2 - 0
lib/hash.h

@@ -70,4 +70,6 @@ extern void hash_iterate (struct hash *,
 extern void hash_clean (struct hash *, void (*) (void *));
 extern void hash_free (struct hash *);
 
+extern unsigned int string_hash_make (const char *);
+
 #endif /* _ZEBRA_HASH_H */

+ 2 - 7
lib/if_rmap.c

@@ -109,14 +109,9 @@ if_rmap_get (const char *ifname)
 static unsigned int
 if_rmap_hash_make (void *data)
 {
-  struct if_rmap *if_rmap = data;
-  unsigned int i, key;
+  const struct if_rmap *if_rmap = data;
 
-  key = 0;
-  for (i = 0; i < strlen (if_rmap->ifname); i++)
-    key += if_rmap->ifname[i];
-
-  return key;
+  return string_hash_make (if_rmap->ifname);
 }
 
 static int