]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/htable.c
ebl add sql_escape to catalog messages
[bacula/bacula] / bacula / src / lib / htable.c
index 790578fa7d6ef8ca29bd2d66e9c0c890f99d1b47..6bbf800e24d1955c90157b75bf863aba81ba3a35 100644 (file)
@@ -4,40 +4,36 @@
  *  htable is a hash table of items (pointers). This code is
  *    adapted and enhanced from code I wrote in 1982 for a
  *    relocatable linker.  At that time, the hash table size
- *    was fixed and a primary number, which essentially providing
- *    the hashing. In this program, the hash table can grow when
- *    it gets too full, so the table is a binary number. The
+ *    was fixed and a primary number, which essentially provides
+ *    the randomness. In this program, the hash table can grow when
+ *    it gets too full, so the table size here is a binary number. The
  *    hashing is provided using an idea from Tcl where the initial
- *    hash code is then "randomized" a simple calculation from
+ *    hash code is "randomized" using a simple calculation from
  *    a random number generator that multiplies by a big number
- *    then shifts the results down and does the binary division
- *    by masking.  Increasing the size of the hash table is simple
- *    simply create a new larger table, walk the old table and
- *    insert each entry into the new table.
+ *    (I multiply by a prime number, while Tcl did not)
+ *    then shifts the result down and does the binary division
+ *    by masking.  Increasing the size of the hash table is simple.
+ *    Just create a new larger table, walk the old table and
+ *    re-hash insert each entry into the new table.
+ *
  *
- *               
  *   Kern Sibbald, July MMIII
  *
  *   Version $Id$
  *
  */
 /*
-   Copyright (C) 2000-2003 Kern Sibbald and John Walker
+   Copyright (C) 2003-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
+   modify it under the terms of the GNU General Public License
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public
-   License along with this program; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
 
  */
 
@@ -65,28 +61,78 @@ void htable::hash_index(char *key)
    return;
 }
 
-htable::htable(void *item, void *link)
+htable::htable(void *item, void *link, int tsize)
 {
-   init(item, link);
+   init(item, link, tsize);
 }
 
-void htable::init(void *item, void *link)
+void htable::init(void *item, void *link, int tsize)
 {
+   int pwr;
+   tsize >>= 2;
+   for (pwr=0; tsize; pwr++) {
+      tsize >>= 1;
+   }
    loffset = (char *)link - (char *)item;
-   mask = 7;                         /* 3 bits => table size = 8 */
-   rshift = 27;                      /* start using bits 28, 29, 30 */
-   num_items = 0;                    /* number of entries in table */
-   buckets = 8;                      /* hash table size -- power of two */
-   max_items = buckets * 4;          /* allow average 4 entries per chain */
+   mask = ~((~0)<<pwr);               /* 3 bits => table size = 8 */
+   rshift = 30 - pwr;                 /* start using bits 28, 29, 30 */
+   num_items = 0;                     /* number of entries in table */
+   buckets = 1<<pwr;                  /* hash table size -- power of two */
+   max_items = buckets * 4;           /* allow average 4 entries per chain */
    table = (hlink **)malloc(buckets * sizeof(hlink *));
    memset(table, 0, buckets * sizeof(hlink *));
    walkptr = NULL;
    walk_index = 0;
 }
 
+uint32_t htable::size()
+{
+   return num_items;
+}
+
+/*
+ * Take each hash link and walk down the chain of items
+ *  that hash there counting them (i.e. the hits), 
+ *  then report that number.
+ *  Obiously, the more hits in a chain, the more time
+ *  it takes to reference them. Empty chains are not so
+ *  hot either -- as it means unused or wasted space.
+ */
+#define MAX_COUNT 20
+void htable::stats()
+{
+   int hits[MAX_COUNT];
+   int max = 0;
+   int i, j;
+   hlink *p;
+   printf("\n\nNumItems=%d\nTotal buckets=%d\n", num_items, buckets);
+   printf("Hits/bucket: buckets\n");
+   for (i=0; i < MAX_COUNT; i++) {
+      hits[i] = 0;
+   }
+   for (i=0; i<(int)buckets; i++) {
+      p = table[i];
+      j = 0;
+      while (p) {
+         p = (hlink *)(p->next);
+         j++;
+      }
+      if (j > max) {
+         max = j;
+      }
+      if (j < MAX_COUNT) {
+         hits[j]++;
+      }
+   }
+   for (i=0; i < MAX_COUNT; i++) {
+      printf("%2d:           %d\n",i, hits[i]);
+   }
+   printf("max hits in a bucket = %d\n", max);
+}
+
 void htable::grow_table()
 {
-   Dmsg1(000, "Grow called old size = %d\n", buckets);
+   Dmsg1(100, "Grow called old size = %d\n", buckets);
    /* Setup a bigger table */
    htable *big = (htable *)malloc(sizeof(htable));
    big->loffset = loffset;
@@ -101,7 +147,7 @@ void htable::grow_table()
    big->walk_index = 0;
    /* Insert all the items in the new hash table */
    Dmsg1(100, "Before copy num_items=%d\n", num_items);
-   /* 
+   /*
     * We walk through the old smaller tree getting items,
     * but since we are overwriting the colision links, we must
     * explicitly save the item->next pointer and walk each
@@ -113,10 +159,10 @@ void htable::grow_table()
       Dmsg1(100, "Grow insert: %s\n", ((hlink *)((char *)item+loffset))->key);
       big->insert(((hlink *)((char *)item+loffset))->key, item);
       if (ni) {
-        item = (void *)((char *)ni-loffset);
+         item = (void *)((char *)ni-loffset);
       } else {
-        walkptr = NULL;       
-        item = next();
+         walkptr = NULL;
+         item = next();
       }
    }
    Dmsg1(100, "After copy new num_items=%d\n", big->num_items);
@@ -133,9 +179,9 @@ bool htable::insert(char *key, void *item)
 {
    hlink *hp;
    if (lookup(key)) {
-      return false;                  /* already exists */
+      return false;                   /* already exists */
    }
-   sm_check(__FILE__, __LINE__, False);
+   sm_check(__FILE__, __LINE__, false);
    ASSERT(index < buckets);
    Dmsg2(100, "Insert: hash=0x%x index=%d\n", (unsigned)hash, index);
    hp = (hlink *)(((char *)item)+loffset);
@@ -152,7 +198,7 @@ bool htable::insert(char *key, void *item)
       Dmsg2(100, "num_items=%d max_items=%d\n", num_items, max_items);
       grow_table();
    }
-   sm_check(__FILE__, __LINE__, False);
+   sm_check(__FILE__, __LINE__, false);
    Dmsg3(100, "Leave insert index=%d num_items=%d key=%s\n", index, num_items, key);
    return true;
 }
@@ -164,7 +210,7 @@ void *htable::lookup(char *key)
 //    Dmsg2(100, "hp=0x%x key=%s\n", (long)hp, hp->key);
       if (hash == hp->hash && strcmp(key, hp->key) == 0) {
          Dmsg1(100, "lookup return %x\n", ((char *)hp)-loffset);
-        return ((char *)hp)-loffset;
+         return ((char *)hp)-loffset;
       }
    }
    return NULL;
@@ -180,14 +226,14 @@ void *htable::next()
       walkptr = table[walk_index++];
       if (walkptr) {
          Dmsg3(100, "new walkptr=0x%x next=0x%x inx=%d\n", (unsigned)walkptr,
-           (unsigned)(walkptr->next), walk_index-1);
+            (unsigned)(walkptr->next), walk_index-1);
       }
    }
    if (walkptr) {
-      Dmsg2(100, "next: rtn 0x%x walk_index=%d\n", 
-        (unsigned)(((char *)walkptr)-loffset), walk_index);
+      Dmsg2(100, "next: rtn 0x%x walk_index=%d\n",
+         (unsigned)(((char *)walkptr)-loffset), walk_index);
       return ((char *)walkptr)-loffset;
-   } 
+   }
    Dmsg0(100, "next: return NULL\n");
    return NULL;
 }
@@ -195,19 +241,19 @@ void *htable::next()
 void *htable::first()
 {
    Dmsg0(100, "Enter first\n");
-   walkptr = table[0];               /* get first bucket */
-   walk_index = 1;                   /* Point to next index */
+   walkptr = table[0];                /* get first bucket */
+   walk_index = 1;                    /* Point to next index */
    while (!walkptr && walk_index < buckets) {
       walkptr = table[walk_index++];  /* go to next bucket */
       if (walkptr) {
          Dmsg3(100, "first new walkptr=0x%x next=0x%x inx=%d\n", (unsigned)walkptr,
-           (unsigned)(walkptr->next), walk_index-1);
+            (unsigned)(walkptr->next), walk_index-1);
       }
    }
    if (walkptr) {
       Dmsg1(100, "Leave first walkptr=0x%x\n", (unsigned)walkptr);
       return ((char *)walkptr)-loffset;
-   } 
+   }
    Dmsg0(100, "Leave first walkptr=NULL\n");
    return NULL;
 }
@@ -248,9 +294,9 @@ int main()
    int count = 0;
 
    jcrtbl = (htable *)malloc(sizeof(htable));
-   jcrtbl->init(jcr, &jcr->link);
-    
-   Dmsg0(000, "Insert NITEMS items 0-19\n");
+   jcrtbl->init(jcr, &jcr->link, NITEMS);
+
+   Dmsg1(000, "Inserting %d items\n", NITEMS);
    for (int i=0; i<NITEMS; i++) {
       sprintf(mkey, "This is htable item %d", i);
       jcr = (MYJCR *)malloc(sizeof(MYJCR));
@@ -259,7 +305,7 @@ int main()
 
       jcrtbl->insert(jcr->key, jcr);
       if (i == 10) {
-        save_jcr = jcr;
+         save_jcr = jcr;
       }
    }
    if (!(item = (MYJCR *)jcrtbl->lookup(save_jcr->key))) {
@@ -268,9 +314,10 @@ int main()
       printf("Item 10's key is: %s\n", item->key);
    }
 
+   jcrtbl->stats();
    printf("Walk the hash table:\n");
-   for (MYJCR *jcr=(MYJCR *)jcrtbl->first(); jcr; jcr=(MYJCR *)jcrtbl->next() ) {
-      printf("htable item = %s\n", jcr->key);
+   foreach_htable (jcr, jcrtbl) {
+//    printf("htable item = %s\n", jcr->key);
       free(jcr->key);
       count++;
    }
@@ -281,7 +328,7 @@ int main()
    free(jcrtbl);
    printf("Freed jcrtbl\n");
 
-   sm_dump(False);
+   sm_dump(false);
 
 }
 #endif