New growing hash functions, and other code to use them
authoraland <aland>
Wed, 12 Apr 2006 21:21:03 +0000 (21:21 +0000)
committeraland <aland>
Wed, 12 Apr 2006 21:21:03 +0000 (21:21 +0000)
src/include/libradius.h
src/lib/dict.c
src/lib/fifo.c
src/lib/hash.c
src/main/request_list.c
src/main/threads.c

index 8350163..98e5652 100644 (file)
@@ -439,30 +439,29 @@ int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order, int (*callback)(void *, void
 
 /* hash.c */
 typedef struct lrad_hash_table_t lrad_hash_table_t;
+typedef void (*lrad_hash_table_free_t)(void *);
+typedef int (*lrad_hash_table_walk_t)(void * /* ctx */, void * /* data */);
 
-lrad_hash_table_t *lrad_hash_table_create(int size, void (*freeNode)(void *),
-                                         int replace_flag);
+lrad_hash_table_t *lrad_hash_table_create(lrad_hash_table_free_t freeNode);
 void           lrad_hash_table_free(lrad_hash_table_t *ht);
-int            lrad_hash_table_insert(lrad_hash_table_t *ht, uint32_t key,
-                                      void *data);
+int            lrad_hash_table_insert(lrad_hash_table_t *ht, uint32_t key, void *data);
 int            lrad_hash_table_delete(lrad_hash_table_t *ht, uint32_t key);
+void           *lrad_hash_table_yank(lrad_hash_table_t *ht, uint32_t key);
+int            lrad_hash_table_replace(lrad_hash_table_t *ht, uint32_t key, void *data);
 void           *lrad_hash_table_finddata(lrad_hash_table_t *ht, uint32_t key);
 int            lrad_hash_table_num_elements(lrad_hash_table_t *ht);
 int            lrad_hash_table_walk(lrad_hash_table_t *ht,
-                                    int (*callback)(void * /* ctx */,
-                                                    void * /* data */),
-                                    void *context);
-int            lrad_hash_table_set_data_size(lrad_hash_table_t *ht,
-                                             size_t data_size);
+                                    lrad_hash_table_walk_t callback,
+                                    void *ctx);
 
 /*
  *     FIFOs
  */
 typedef struct lrad_fifo_t lrad_fifo_t;
-lrad_fifo_t *lrad_fifo_create(int max_entries, void (*freeNode)(void *));
+typedef void (*lrad_fifo_free_t)(void *);
+lrad_fifo_t *lrad_fifo_create(int max_entries, lrad_fifo_free_t freeNode);
 void lrad_fifo_free(lrad_fifo_t *fi);
 int lrad_fifo_push(lrad_fifo_t *fi, void *data);
 void *lrad_fifo_pop(lrad_fifo_t *fi);
-void *lrad_fifo_peek(lrad_fifo_t *fi);
 
 #endif /*LIBRADIUS_H*/
index b27cebb..6c16c6c 100644 (file)
@@ -108,7 +108,7 @@ static uint32_t dict_hashname(const char *name)
        p = name;
        q = buffer;
        while (*p && (len < sizeof(buffer))) {
-               if (isalpha((int) *p)) {
+               if (isalpha(*p)) {
                        *(q++) = tolower((int) *(p++));
                } else {
                        *(q++) = *(p++);
@@ -251,7 +251,7 @@ int dict_addvendor(const char *name, int value)
        dv->vendorpec  = value;
        dv->type = dv->length = 1; /* defaults */
 
-       if (lrad_hash_table_insert(vendors_byname, hash, dv) == 0) {
+       if (!lrad_hash_table_insert(vendors_byname, hash, dv)) {
                DICT_VENDOR *old_dv;
 
                old_dv = lrad_hash_table_finddata(vendors_byname, hash);
@@ -275,17 +275,19 @@ int dict_addvendor(const char *name, int value)
         *      Insert the SAME pointer (not free'd when this tree is
         *      deleted), into another tree.
         *
-        *      If the newly inserted entry is a duplicate of an existing
-        *      entry, then the old entry is tossed, and the new one
-        *      replaces it.  This behaviour is configured in the
-        *      lrad_hash_table_create() function.
-        *
         *      We want this behaviour because we want OLD names for
         *      the attributes to be read from the configuration
         *      files, but when we're printing them, (and looking up
         *      by value) we want to use the NEW name.
         */
-       lrad_hash_table_insert(vendors_byvalue, dv->vendorpec, dv);
+       if (!lrad_hash_table_replace(vendors_byvalue,
+                                   lrad_hash(&dv->vendorpec,
+                                             sizeof(dv->vendorpec)),
+                                   dv)) {
+               librad_log("dict_addvendor: Failed inserting vendor %s",
+                          name);
+               return -1;
+       }
 
        return 0;
 }
@@ -379,7 +381,7 @@ int dict_addattr(const char *name, int vendor, int type, int value,
        /*
         *      Insert the attribute, only if it's not a duplicate.
         */
-       if (lrad_hash_table_insert(attributes_byname, hash, attr) == 0) {
+       if (!lrad_hash_table_insert(attributes_byname, hash, attr)) {
                DICT_ATTR       *a;
 
                /*
@@ -406,17 +408,17 @@ int dict_addattr(const char *name, int vendor, int type, int value,
         *      Insert the SAME pointer (not free'd when this tree is
         *      deleted), into another tree.
         *
-        *      If the newly inserted entry is a duplicate of an existing
-        *      entry, then the old entry is tossed, and the new one
-        *      replaces it.  This behaviour is configured in the
-        *      lrad_hash_table_create() function.
-        *
         *      We want this behaviour because we want OLD names for
         *      the attributes to be read from the configuration
         *      files, but when we're printing them, (and looking up
         *      by value) we want to use the NEW name.
         */
-       lrad_hash_table_insert(attributes_byvalue, (uint32_t) attr->attr, attr);
+       if (!lrad_hash_table_replace(attributes_byvalue,
+                                   lrad_hash(&attr->attr, sizeof(attr->attr)),
+                                   attr)) {
+               librad_log("dict_addattr: Failed inserting attribute name %s", name);
+               return -1;
+       }
 
        return 0;
 }
@@ -481,7 +483,7 @@ int dict_addvalue(const char *namestr, const char *attrstr, int value)
        /*
         *      Add the value into the dictionary.
         */
-       if (lrad_hash_table_insert(values_byname, hash, dval) == 0) {
+       if (!lrad_hash_table_insert(values_byname, hash, dval)) {
                if (dattr) {
                        DICT_VALUE *old;
                        
@@ -507,7 +509,11 @@ int dict_addvalue(const char *namestr, const char *attrstr, int value)
         */
        hash = dval->attr;
        hash = lrad_hash_update(&dval->value, sizeof(dval->value), hash);
-       lrad_hash_table_insert(values_byvalue, hash, dval);
+       if (!lrad_hash_table_replace(values_byvalue, hash, dval)) {     
+               librad_log("dict_addvalue: Failed inserting value %s",
+                          namestr);
+               return -1;
+       }
 
        return 0;
 }
@@ -679,7 +685,7 @@ static int process_value(const char* fn, const int line, char **argv,
         *      if it sees values which look like integers, so we can't
         *      use them here.
         */
-       if (isdigit((int) argv[1][0])) {
+       if (isdigit(argv[1][0])) {
                librad_log("dict_init: %s[%d]: Names for VALUEs cannot start with a digit.",
                           fn, line);
        }
@@ -1066,7 +1072,7 @@ int dict_init(const char *dir, const char *fn)
         *
         *      Each vendor is malloc'd, so the free function is free.
         */
-       vendors_byname = lrad_hash_table_create(8, free, 0);
+       vendors_byname = lrad_hash_table_create(free);
        if (!vendors_byname) {
                return -1;
        }
@@ -1076,7 +1082,7 @@ int dict_init(const char *dir, const char *fn)
         *      be vendors of the same value.  If there are, we
         *      pick the latest one.
         */
-       vendors_byvalue = lrad_hash_table_create(8, NULL, 1);
+       vendors_byvalue = lrad_hash_table_create(NULL);
        if (!vendors_byvalue) {
                return -1;
        }
@@ -1087,7 +1093,7 @@ int dict_init(const char *dir, const char *fn)
         *
         *      Each attribute is malloc'd, so the free function is free.
         */
-       attributes_byname = lrad_hash_table_create(11, free, 0);
+       attributes_byname = lrad_hash_table_create(free);
        if (!attributes_byname) {
                return -1;
        }
@@ -1097,17 +1103,17 @@ int dict_init(const char *dir, const char *fn)
         *      be attributes of the same value.  If there are, we
         *      pick the latest one.
         */
-       attributes_byvalue = lrad_hash_table_create(11, NULL, 1);
+       attributes_byvalue = lrad_hash_table_create(NULL);
        if (!attributes_byvalue) {
                return -1;
        }
 
-       values_byname = lrad_hash_table_create(11, free, 0);
+       values_byname = lrad_hash_table_create(free);
        if (!values_byname) {
                return -1;
        }
 
-       values_byvalue = lrad_hash_table_create(11, NULL, 1);
+       values_byvalue = lrad_hash_table_create(NULL);
        if (!values_byvalue) {
                return -1;
        }
@@ -1141,8 +1147,8 @@ int dict_init(const char *dir, const char *fn)
                        hash = lrad_hash_update(&this->dval->attr,
                                                sizeof(this->dval->attr),
                                                this->hash);
-                       if (lrad_hash_table_insert(values_byname,
-                                                  hash, this->dval) == 0) {
+                       if (!lrad_hash_table_replace(values_byname,
+                                                    hash, this->dval)) {
                                librad_log("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
                                return -1;
                        }
@@ -1152,13 +1158,14 @@ int dict_init(const char *dir, const char *fn)
                         *      prefer the new name when printing
                         *      values.
                         */
-                       hash = (uint32_t) this->dval->attr;
+                       hash = lrad_hash(&this->dval->attr,
+                                        sizeof(this->dval->attr));
                        hash = lrad_hash_update(&this->dval->value,
                                                sizeof(this->dval->value),
                                                hash);
                        if (!lrad_hash_table_finddata(values_byvalue, hash)) {
-                               lrad_hash_table_insert(values_byvalue,
-                                                      hash, this->dval);
+                               lrad_hash_table_replace(values_byvalue,
+                                                       hash, this->dval);
                        }
                        free(this);
 
@@ -1177,7 +1184,8 @@ int dict_init(const char *dir, const char *fn)
  */
 DICT_ATTR *dict_attrbyvalue(int val)
 {
-       return lrad_hash_table_finddata(attributes_byvalue, (uint32_t) val);
+       return lrad_hash_table_finddata(attributes_byvalue,
+                                       lrad_hash(&val, sizeof(val)));
 }
 
 /*
@@ -1243,5 +1251,6 @@ int dict_vendorbyname(const char *name)
  */
 DICT_VENDOR *dict_vendorbyvalue(int vendor)
 {
-       return lrad_hash_table_finddata(vendors_byvalue, (uint32_t) vendor);
+       return lrad_hash_table_finddata(vendors_byvalue,
+                                       lrad_hash(&vendor, sizeof(vendor)));
 }
index 25bd659..bb88f69 100644 (file)
@@ -32,20 +32,22 @@ static const char rcsid[] = "$Id$";
 #include <freeradius-devel/missing.h>
 #include <freeradius-devel/libradius.h>
 
-/*
- *     The fifo is based on the hash tables, not for speed, but to
- *     allow the fifo to grow automatically.  If we put array code
- *     here to implement fifos, then we have to mix the semantics of
- *     fifo push/pull with array re-sizing, which could add bugs.
- */
+typedef struct lrad_fifo_entry_t {
+       struct lrad_fifo_entry_t *next;
+       void                    *data;
+} lrad_fifo_entry_t;
+
 struct lrad_fifo_t {
-       lrad_hash_table_t *ht;
-       int head;
-       int tail;
+       lrad_fifo_entry_t *head, **tail;
+       lrad_fifo_entry_t *freelist;
+
+       int num_elements;
        int max_entries;
+       lrad_fifo_free_t freeNode;
 };
 
-lrad_fifo_t *lrad_fifo_create(int max_entries, void (*freeNode)(void *))
+
+lrad_fifo_t *lrad_fifo_create(int max_entries, lrad_fifo_free_t freeNode)
 {
        lrad_fifo_t *fi;
 
@@ -56,84 +58,101 @@ lrad_fifo_t *lrad_fifo_create(int max_entries, void (*freeNode)(void *))
 
        memset(fi, 0, sizeof(*fi));
 
-       fi->ht = lrad_hash_table_create(5, freeNode, 0);
-       if (!fi->ht) {
-               free(fi);
-               return NULL;
-       }
-
        fi->max_entries = max_entries;
+       fi->freeNode = freeNode;
 
        return fi;
 }
 
+static void lrad_fifo_free_entries(lrad_fifo_t *fi, lrad_fifo_entry_t *head)
+{
+       lrad_fifo_entry_t *next;
+
+       while (head) {
+               next = head->next;
+
+               if (fi->freeNode && head->data) fi->freeNode(head->data);
+               free(head);
+
+               head = next;
+       }
+}
+
 void lrad_fifo_free(lrad_fifo_t *fi)
 {
        if (!fi) return;
 
-       if (fi->ht) lrad_hash_table_free(fi->ht);
+       lrad_fifo_free_entries(fi, fi->head);
+       lrad_fifo_free_entries(fi, fi->freelist);
 
        free(fi);
 }
 
-int lrad_fifo_push(lrad_fifo_t *fi, void *data)
+static lrad_fifo_entry_t *lrad_fifo_alloc_entry(lrad_fifo_t *fi)
 {
-       if (!fi || !fi->ht || !data) return 0;
-
-       if (lrad_hash_table_num_elements(fi->ht) >= fi->max_entries) return 0;
-
-       if (!lrad_hash_table_insert(fi->ht, fi->tail, data)) return 0;
+       lrad_fifo_entry_t *entry;
+
+       if (fi->freelist) {
+               entry = fi->freelist;
+               fi->freelist = entry->next;
+       } else {
+               entry = malloc(sizeof(*entry));
+               if (!entry) return NULL;
+       }
 
-       fi->tail++;
-       
-       return 1;
+       memset(entry, 0, sizeof(*entry));
+       return entry;
 }
 
-void *lrad_fifo_pop(lrad_fifo_t *fi)
+int lrad_fifo_push(lrad_fifo_t *fi, void *data)
 {
-       void *data;
+       lrad_fifo_entry_t *entry;
 
-       if (!fi || !fi->ht) return 0;
+       if (!fi || !data) return 0;
 
-       if (lrad_hash_table_num_elements(fi->ht) == 0) {
-               fi->head = fi->tail = 0;
-               return NULL;
-       }
+       if (fi->num_elements >= fi->max_entries) return 0;
+
+       entry = lrad_fifo_alloc_entry(fi);
+       if (!entry) return 0;
 
-       data = lrad_hash_table_finddata(fi->ht, fi->head);
-       if (!data) {
-               /*
-                *      This is a SERIOUS error!
-                *      How do we recover from it?
-                *      What do we do?
-                */
-               fi->head++;
-               return NULL;
+       if (!fi->head) {
+               fi->head = entry;
+       } else {
+               *fi->tail = entry;
        }
+       fi->tail = &(entry->next);
 
-       lrad_hash_table_delete(fi->ht, fi->head++);
+       fi->num_elements++;
 
-       return data;
+       return 1;
 }
 
-void *lrad_fifo_peek(lrad_fifo_t *fi)
+static void lrad_fifo_free_entry(lrad_fifo_t *fi, lrad_fifo_entry_t *entry)
+{
+       entry->data = NULL;
+       entry->next = fi->freelist;
+       fi->freelist = entry->next;
+}
+
+
+void *lrad_fifo_pop(lrad_fifo_t *fi)
 {
        void *data;
+       lrad_fifo_entry_t *entry;
 
-       if (!fi || !fi->ht) return 0;
+       if (!fi || !fi->head) return 0;
 
-       if (lrad_hash_table_num_elements(fi->ht) == 0) {
-               return NULL;
-       }
+       entry = fi->head;
+       fi->head = entry->next;
+
+       data = entry->data;
+       lrad_fifo_free_entry(fi, entry);
+
+       fi->num_elements--;
 
-       data = lrad_hash_table_finddata(fi->ht, fi->head);
-       if (!data) {
-               /*
-                *      This is a SERIOUS error!
-                *      How do we recover from it?
-                *      What do we do?
-                */
-               return NULL;
+       if (!fi->head) {
+               fi->tail = NULL;
+               fi->num_elements = 0;
        }
 
        return data;
index 8049f85..325df73 100644 (file)
@@ -40,18 +40,30 @@ static const char rcsid[] = "$Id$";
 #include <freeradius-devel/missing.h>
 #include <freeradius-devel/libradius.h>
 
+/*
+ *     A reasonable number of buckets to start off with.
+ *     Should be a power of two.
+ */
+#define LRAD_HASH_NUM_BUCKETS (64)
+
 typedef struct lrad_hash_entry_t {
        struct lrad_hash_entry_t *next;
-       uint32_t        key; /* reversed image of the key */
-       void            *data;
+       uint32_t        reversed;
+       uint32_t        key;
+       void            *data;
 } lrad_hash_entry_t;
 
+
 struct lrad_hash_table_t {
        int                     num_elements;
        int                     num_buckets; /* power of 2 */
-       int                     replace_flag;
-       size_t                  data_size;
-       void                    (*free)(void *);
+       int                     next_grow;
+       int                     mask;
+
+       lrad_hash_table_free_t  free;
+
+       lrad_hash_entry_t       null;
+
        lrad_hash_entry_t       **buckets;
 };
 
@@ -59,7 +71,6 @@ struct lrad_hash_table_t {
 static int grow = 0;
 #endif
 
-
 /*
  * perl -e 'foreach $i (0..255) {$r = 0; foreach $j (0 .. 7 ) { if (($i & ( 1<< $j)) != 0) { $r |= (1 << (7 - $j));}} print $r, ", ";if (($i & 7) == 7) {print "\n";}}'
  */
@@ -100,6 +111,45 @@ static const uint8_t reversed_byte[256] = {
 
 
 /*
+ * perl -e 'foreach $i (0..255) {$r = 0;foreach $j (0 .. 7) { $r = $i & (1 << (7 - $j)); last if ($r)} print $i & ~($r), ", ";if (($i & 7) == 7) {print "\n";}}'
+ */
+static uint8_t parent_byte[256] = {
+       0, 0, 0, 1, 0, 1, 2, 3,
+       0, 1, 2, 3, 4, 5, 6, 7,
+       0, 1, 2, 3, 4, 5, 6, 7,
+       8, 9, 10, 11, 12, 13, 14, 15,
+       0, 1, 2, 3, 4, 5, 6, 7,
+       8, 9, 10, 11, 12, 13, 14, 15,
+       16, 17, 18, 19, 20, 21, 22, 23,
+       24, 25, 26, 27, 28, 29, 30, 31,
+       0, 1, 2, 3, 4, 5, 6, 7,
+       8, 9, 10, 11, 12, 13, 14, 15,
+       16, 17, 18, 19, 20, 21, 22, 23,
+       24, 25, 26, 27, 28, 29, 30, 31,
+       32, 33, 34, 35, 36, 37, 38, 39,
+       40, 41, 42, 43, 44, 45, 46, 47,
+       48, 49, 50, 51, 52, 53, 54, 55,
+       56, 57, 58, 59, 60, 61, 62, 63,
+       0, 1, 2, 3, 4, 5, 6, 7,
+       8, 9, 10, 11, 12, 13, 14, 15,
+       16, 17, 18, 19, 20, 21, 22, 23,
+       24, 25, 26, 27, 28, 29, 30, 31,
+       32, 33, 34, 35, 36, 37, 38, 39,
+       40, 41, 42, 43, 44, 45, 46, 47,
+       48, 49, 50, 51, 52, 53, 54, 55,
+       56, 57, 58, 59, 60, 61, 62, 63,
+       64, 65, 66, 67, 68, 69, 70, 71,
+       72, 73, 74, 75, 76, 77, 78, 79,
+       80, 81, 82, 83, 84, 85, 86, 87,
+       88, 89, 90, 91, 92, 93, 94, 95,
+       96, 97, 98, 99, 100, 101, 102, 103,
+       104, 105, 106, 107, 108, 109, 110, 111,
+       112, 113, 114, 115, 116, 117, 118, 119,
+       120, 121, 122, 123, 124, 125, 126, 127
+};
+
+
+/*
  *     Reverse a key.
  */
 static uint32_t reverse(uint32_t key)
@@ -110,30 +160,54 @@ static uint32_t reverse(uint32_t key)
                (reversed_byte[(key >> 24) & 0xff]));
 }
 
-static lrad_hash_entry_t *list_find(lrad_hash_entry_t *head, uint32_t key)
+/*
+ *     Take the parent by discarding the highest bit that is set.
+ */
+static uint32_t parent_of(uint32_t key)
+{
+       if (key > 0x00ffffff)
+               return (key & 0x00ffffff) | (parent_byte[key >> 24] << 24);
+
+       if (key > 0x0000ffff)
+               return (key & 0x0000ffff) | (parent_byte[key >> 16] << 16);
+
+       if (key > 0x000000ff)
+               return (key & 0x000000ff) | (parent_byte[key >> 8] << 8);
+       
+       return parent_byte[key];
+}
+
+
+static lrad_hash_entry_t *list_find(lrad_hash_table_t *ht,
+                                   lrad_hash_entry_t *head,
+                                   uint32_t reversed)
 {
        lrad_hash_entry_t *cur;
 
-       for (cur = head; cur != NULL; cur = cur->next) {
-               if (cur->key > key) return NULL;
-               if (cur->key == key) return cur;
+       for (cur = head; cur != &ht->null; cur = cur->next) {
+               if (cur->reversed == reversed) return cur;
+               if (cur->reversed > reversed) return NULL;
        }
 
        return NULL;
 }
 
+
 /*
  *     Inserts a new entry into the list, in order.
  */
-static int list_insert(lrad_hash_entry_t **head, lrad_hash_entry_t *node)
+static int list_insert(lrad_hash_table_t *ht,
+                      lrad_hash_entry_t **head, lrad_hash_entry_t *node)
 {
        lrad_hash_entry_t **last, *cur;
 
        last = head;
 
-       for (cur = *head; cur != NULL; cur = cur->next) {
-               if (cur->key > node->key) break;
+       for (cur = *head; cur != &ht->null; cur = cur->next) {
+               if (cur->reversed > node->reversed) break;
                last = &(cur->next);
+
+               if (cur->reversed == node->reversed) return 0;
        }
 
        node->next = *last;
@@ -146,13 +220,14 @@ static int list_insert(lrad_hash_entry_t **head, lrad_hash_entry_t *node)
 /*
  *     Delete an entry from the list.
  */
-static int list_delete(lrad_hash_entry_t **head, lrad_hash_entry_t *node)
+static int list_delete(lrad_hash_table_t *ht,
+                      lrad_hash_entry_t **head, lrad_hash_entry_t *node)
 {
        lrad_hash_entry_t **last, *cur;
 
        last = head;
-       
-       for (cur = *head; cur != NULL; cur = cur->next) {
+
+       for (cur = *head; cur != &ht->null; cur = cur->next) {
                if (cur == node) break;
                last = &(cur->next);
        }
@@ -163,61 +238,134 @@ static int list_delete(lrad_hash_entry_t **head, lrad_hash_entry_t *node)
 
 
 /*
- *     Split a list.  Everything >= key is returned, and the returned
- *     list is removed from the input list.
+ *     Create the table.
+ *
+ *     Memory usage in bytes is (20/3) * number of entries.
  */
-static lrad_hash_entry_t *list_split(lrad_hash_entry_t **head, uint32_t key)
+lrad_hash_table_t *lrad_hash_table_create(lrad_hash_table_free_t freeNode)
 {
-       lrad_hash_entry_t **last, *cur;
+       lrad_hash_table_t *ht;
 
-       last = head;
-       
-       for (cur = *head; cur != NULL; cur = cur->next) {
-               if (cur->key >= key) break;
-               last = &(cur->next);
+       ht = malloc(sizeof(*ht));
+       if (!ht) return NULL;
+
+       memset(ht, 0, sizeof(*ht));
+       ht->free = freeNode;
+       ht->num_buckets = LRAD_HASH_NUM_BUCKETS;
+       ht->mask = ht->num_buckets - 1;
+
+       /*
+        *      Have a default load factor of 2.5.  In practice this
+        *      means that the average load will hit 3 before the
+        *      table grows.
+        */
+       ht->next_grow = (ht->num_buckets << 1) + (ht->num_buckets >> 1);
+
+       ht->buckets = malloc(sizeof(*ht->buckets) * ht->num_buckets);
+       if (!ht->buckets) {
+               free(ht);
+               return NULL;
        }
+       memset(ht->buckets, 0, sizeof(*ht->buckets) * ht->num_buckets);
 
-       *last = NULL;
+       ht->null.reversed = ~0;
+       ht->null.key = ~0;
+       ht->null.next = &ht->null;
 
-       return cur;
+       ht->buckets[0] = &ht->null;
+
+       return ht;
 }
 
 
 /*
- *     Create the table.  Size is a power of two (i.e. 1..31)
+ *     If the current bucket is uninitialized, initialize it
+ *     by recursively copying information from the parent.
+ *
+ *     We may have a situation where entry E is a parent to 2 other
+ *     entries E' and E".  If we split E into E and E', then the
+ *     nodes meant for E" end up in E or E', both of which are wrong.
+ *     To solve that problem, we walk down the whole chain, trying to
+ *     insert the elements into the correct place.
+ *
+ *     This slows down the growth a bit, but it works.
  */
-lrad_hash_table_t *lrad_hash_table_create(int size, void (*freeNode)(void *),
-                                         int replace_flag)
+static void lrad_hash_table_fixup(lrad_hash_table_t *ht, uint32_t entry)
 {
-       lrad_hash_table_t *ht;
+       uint32_t parent_entry = parent_of(entry);
+       lrad_hash_entry_t **last, *cur;
+       uint32_t this;
 
-       if ((size <= 1) || (size > 31)) return NULL;
+       parent_entry = parent_of(entry);
+
+       /* parent_entry == entry if and only if entry == 0 */
+
+       if (!ht->buckets[parent_entry]) {
+               lrad_hash_table_fixup(ht, parent_entry);
+       }       
 
        /*
-        *      Get the nearest power of two.
+        *      Keep walking down cur, trying to find entries that
+        *      don't belong here any more.  There may be multiple
+        *      ones, so we can't have a naive algorithm...
         */
-       size = 1 << size;
+       last = &ht->buckets[parent_entry];
+       this = parent_entry;
+       
+       for (cur = *last; cur != &ht->null; cur = cur->next) {
+               uint32_t real_entry;
+
+               real_entry = cur->key & ht->mask;
+               if (real_entry != this) { /* ht->buckets[real_entry] == NULL */
+                       *last = &ht->null;
+                       ht->buckets[real_entry] = cur;
+                       this = real_entry;
+               }
 
-       ht = malloc(sizeof(*ht));
-       if (!ht) return NULL;
+               last = &(cur->next);
+       }
 
-       memset(ht, 0, sizeof(*ht));
-       ht->free = freeNode;
-       ht->num_buckets = size;
-       ht->replace_flag = replace_flag;
+       /*
+        *      We may NOT have initialized this bucket, so do it now.
+        */
+       if (!ht->buckets[entry]) ht->buckets[entry] = &ht->null;
+}
 
-       ht->buckets = malloc(sizeof(*ht->buckets) * ht->num_buckets);
-       if (!ht->buckets) {
-               free(ht);
-               return NULL;            
-       }
-       memset(ht->buckets, 0, sizeof(*ht->buckets) * ht->num_buckets);
+/*
+ *     This should be a power of two.  Changing it to 4 doesn't seem
+ *     to make any difference.
+ */
+#define GROW_FACTOR (2)
 
-       return ht;
+/*
+ *     Grow the hash table.
+ */
+static void lrad_hash_table_grow(lrad_hash_table_t *ht)
+{
+       lrad_hash_entry_t **buckets;
+       
+       buckets = malloc(sizeof(*buckets) * GROW_FACTOR * ht->num_buckets);
+       if (!buckets) return;
+
+       memcpy(buckets, ht->buckets,
+              sizeof(*buckets) * ht->num_buckets);
+       memset(&buckets[ht->num_buckets], 0,
+              sizeof(*buckets) * ht->num_buckets);
+       
+       free(ht->buckets);
+       ht->buckets = buckets;
+       ht->num_buckets *= GROW_FACTOR; 
+       ht->next_grow *= GROW_FACTOR;
+       ht->mask = ht->num_buckets - 1;
+#ifdef TESTING
+       grow = 1;
+       fprintf(stderr, "GROW TO %d\n", ht->num_buckets);
+#endif
 }
 
+
 /*
- *     Insert data, OR copy it, if ht->data_size != 0
+ *     Insert data.
  */
 int lrad_hash_table_insert(lrad_hash_table_t *ht, uint32_t key, void *data)
 {
@@ -227,73 +375,37 @@ int lrad_hash_table_insert(lrad_hash_table_t *ht, uint32_t key, void *data)
 
        if (!ht || !data) return 0;
 
-       entry = key & (ht->num_buckets - 1);
+       entry = key & ht->mask;
        reversed = reverse(key);
 
+       if (!ht->buckets[entry]) lrad_hash_table_fixup(ht, entry);
+
        /*
-        *      Already in the table.
+        *      If we try to do our own memory allocation here, the
+        *      speedup is only ~15% or so, which isn't worth it.
         */
-       node = list_find(ht->buckets[entry], reversed);
-       if (node) {
-               if (!ht->replace_flag) return 0;
+       node = malloc(sizeof(*node));
+       if (!node) return 0;
+       memset(node, 0, sizeof(*node));
 
-               list_delete(&ht->buckets[entry], node);
+       node->next = &ht->null;
+       node->reversed = reversed;
+       node->key = key;
+       node->data = data;
 
-               if (ht->free && node->data) ht->free(node->data);
-               /*
-                *      Fall through to re-using the node.
-                */
-       } else {
-               node = malloc(sizeof(*node) + ht->data_size);
-               if (!node) return 0;
-               ht->num_elements++;
-       }
-       memset(node, 0, sizeof(*node) + ht->data_size);
-       
-       node->next = NULL;
-       node->key = reversed;
-       if (ht->data_size) {
-               node->data = &node[1]; /* point to the end of the node */
-               memcpy(node->data, data, ht->data_size);
-       } else {
-               node->data = data;
+       /* already in the table, can't insert it */
+       if (!list_insert(ht, &ht->buckets[entry], node)) {
+               free(node);
+               return 0;
        }
 
-       list_insert(&(ht->buckets[entry]), node);
-
        /*
         *      Check the load factor, and grow the table if
         *      necessary.
         */
-       if (ht->num_elements >= (3 * ht->num_buckets)) {
-               int i;
-               lrad_hash_entry_t **buckets;
-
-               buckets = malloc(sizeof(*buckets) * 2 * ht->num_buckets);
-               if (!buckets) return 1;
-
-               memcpy(buckets, ht->buckets,
-                      sizeof(*buckets) * ht->num_buckets);
-
-               /*
-                *      Split the hash entries.
-                *
-                *      When we double the size of the hash array, we
-                *      do O(N/2) work.  Since this only happens after
-                *      we've inserted N elements,  we're still amortized
-                *      at O(1) inserts, deletes, and updates.
-                */
-               for (i = 0; i < ht->num_buckets; i++) {
-                       buckets[ht->num_buckets + i] = list_split(&buckets[i],
-                                                                 reverse((uint32_t) i + ht->num_buckets));
-               }
-               free(ht->buckets);
-               ht->buckets = buckets;
-               ht->num_buckets *= 2;
-#ifdef TESTING
-               grow = 1;
-               fprintf(stderr, "GROW TO %d\n", ht->num_buckets);
-#endif
+       ht->num_elements++;
+       if (ht->num_elements >= ht->next_grow) {
+               lrad_hash_table_grow(ht);
        }
 
        return 1;
@@ -301,48 +413,101 @@ int lrad_hash_table_insert(lrad_hash_table_t *ht, uint32_t key, void *data)
 
 
 /*
- *     Find data from a key.
+ *     Internal find a node routine.
  */
-void *lrad_hash_table_finddata(lrad_hash_table_t *ht, uint32_t key)
+static lrad_hash_entry_t *lrad_hash_table_find(lrad_hash_table_t *ht,
+                                              uint32_t key)
 {
        uint32_t entry;
        uint32_t reversed;
-       lrad_hash_entry_t *node;
 
-       entry = key & (ht->num_buckets - 1);
+       if (!ht) return NULL;
+
+       entry = key & ht->mask;
        reversed = reverse(key);
 
-       if (!ht) return NULL;
+       if (!ht->buckets[entry]) lrad_hash_table_fixup(ht, entry);
+
+       return list_find(ht, ht->buckets[entry], reversed);
+}
+
+
+/*
+ *     Replace old data with new data
+ */
+int lrad_hash_table_replace(lrad_hash_table_t *ht, uint32_t key, void *data)
+{
+       lrad_hash_entry_t *node;
+
+       if (!data) return 0;
+
+       node = lrad_hash_table_find(ht, key);
+       if (!node) return lrad_hash_table_insert(ht, key, data);
+
+       if (ht->free) ht->free(node->data);
+       node->data = data;
+
+       return 1;
+}
+
 
-       node = list_find(ht->buckets[entry], reversed);
+/*
+ *     Find data from a template
+ */
+void *lrad_hash_table_finddata(lrad_hash_table_t *ht, uint32_t key)
+{
+       lrad_hash_entry_t *node;
+
+       node = lrad_hash_table_find(ht, key);
        if (!node) return NULL;
 
-       return node->data;      /* may be NULL */
+       return node->data;
 }
 
 
+
 /*
- *     Delete a piece of data from the hash table.
+ *     Yank an entry from the hash table, without freeing the data.
  */
-int lrad_hash_table_delete(lrad_hash_table_t *ht, uint32_t key)
+void *lrad_hash_table_yank(lrad_hash_table_t *ht, uint32_t key)
 {
        uint32_t entry;
        uint32_t reversed;
+       void *data;
        lrad_hash_entry_t *node;
 
        if (!ht) return 0;
 
-       entry = key & (ht->num_buckets - 1);
+       entry = key & ht->mask;
        reversed = reverse(key);
 
-       node = list_find(ht->buckets[entry], reversed);
-       if (!node) return 0;
-       
-       if (ht->free) ht->free(node->data);
-       list_delete(&ht->buckets[entry], node);
+       if (!ht->buckets[entry]) lrad_hash_table_fixup(ht, entry);
+
+       node = list_find(ht, ht->buckets[entry], reversed);
+       if (!node) return NULL;
+
+       list_delete(ht, &ht->buckets[entry], node);
        ht->num_elements--;
 
+       data = node->data;
        free(node);
+
+       return data;
+}
+
+
+/*
+ *     Delete a piece of data from the hash table.
+ */
+int lrad_hash_table_delete(lrad_hash_table_t *ht, uint32_t key)
+{
+       void *data;
+
+       data = lrad_hash_table_yank(ht, key);
+       if (!data) return 0;
+
+       if (ht->free) ht->free(data);
+
        return 1;
 }
 
@@ -359,7 +524,7 @@ void lrad_hash_table_free(lrad_hash_table_t *ht)
        /*
         *      The entries MUST be all in one linked list.
         */
-       for (node = ht->buckets[0]; node != NULL; node = next) {
+       for (node = ht->buckets[0]; node != &ht->null; node = next) {
                next = node->next;
 
                if (!node->data) continue; /* dummy entry */
@@ -388,8 +553,7 @@ int lrad_hash_table_num_elements(lrad_hash_table_t *ht)
  *     Walk over the nodes, allowing deletes & inserts to happen.
  */
 int lrad_hash_table_walk(lrad_hash_table_t *ht,
-                        int (*callback)(void * /* ctx */,
-                                        void * /* data */),
+                        lrad_hash_table_walk_t callback,
                         void *context)
 {
        int i, rcode;;
@@ -401,7 +565,7 @@ int lrad_hash_table_walk(lrad_hash_table_t *ht,
 
                if (!ht->buckets[i]) continue;
 
-               for (node = ht->buckets[i]; node != NULL; node = next) {
+               for (node = ht->buckets[i]; node != &ht->null; node = next) {
                        next = node->next;
 
                        rcode = callback(context, node->data);
@@ -413,21 +577,79 @@ int lrad_hash_table_walk(lrad_hash_table_t *ht,
 }
 
 
+#ifdef TESTING
 /*
- *     For users that have a small amount of data, and wish to associate
- *     it directly with the hash entry, this saves a bit of memory &
- *     malloc/free stuff.
+ *     Show what the hash table is doing.
  */
-int lrad_hash_table_set_data_size(lrad_hash_table_t *ht, size_t data_size)
+int lrad_hash_table_info(lrad_hash_table_t *ht)
 {
-      if (!ht || ht->free) return 0;
+       int i, a, collisions, uninitialized;
+       int array[256];
+
+       if (!ht) return 0;
+
+       uninitialized = collisions = 0;
+       memset(array, 0, sizeof(array));
+
+       for (i = 0; i < ht->num_buckets; i++) {
+               uint32_t key;
+               int load;
+               lrad_hash_entry_t *node, *next;
+
+               /*
+                *      If we haven't inserted or looked up an entry
+                *      in a bucket, it's uninitialized.
+                */
+               if (!ht->buckets[i]) {
+                       uninitialized++;
+                       continue;
+               }
+
+               load = 0;
+               key = ~0;
+               for (node = ht->buckets[i]; node != &ht->null; node = next) {
+                       if (node->reversed == key) {
+                               collisions++;
+                       } else {
+                               key = node->reversed;
+                       }
+                       next = node->next;
+                       load++;
+               }
 
-      if (ht->num_elements != 0) return 0;
+               if (load > 255) load = 255;
+               array[load]++;
+       }
+
+       printf("HASH TABLE %p\tbuckets: %d\t(%d uninitialized)\n", ht,
+               ht->num_buckets, uninitialized);
+       printf("\tnum entries %d\thash collisions %d\n",
+               ht->num_elements, collisions);
 
-      ht->data_size = data_size;
+       a = 0;
+       for (i = 1; i < 256; i++) {
+               if (!array[i]) continue;
+               printf("%d\t%d\n", i, array[i]);
 
-      return 1;
+               /*
+                *      Since the entries are ordered, the lookup cost
+                *      for any one element in a chain is (on average)
+                *      the cost of walking half of the chain.
+                */
+               if (i > 1) {
+                       a += array[i] * i;
+               }
+       }
+       a /= 2;
+       a += array[1];
+
+       printf("\texpected lookup cost = %d/%d or %f\n\n",
+              ht->num_elements, a,
+              (float) ht->num_elements / (float) a);
+
+       return 0;
 }
+#endif
 
 
 #define FNV_MAGIC_INIT (0x811c9dc5)
@@ -525,57 +747,74 @@ uint32_t lrad_hash_fold(uint32_t hash, int bits)
 #include <stdio.h>
 #include <stdlib.h>
 
-#define MAX 8000
+#define MAX 1024*64
 int main(int argc, char **argv)
 {
-       uint32_t i, *p, *q;
+       uint32_t hash;
+       int i, *p, *q, k;
        lrad_hash_table_t *ht;
+       int *array;
 
-       ht = lrad_hash_table_create(10, free, 0);
+       ht = lrad_hash_table_create(NULL);
        if (!ht) {
                fprintf(stderr, "Hash create failed\n");
                exit(1);
        }
 
+       array = malloc(sizeof(int) * MAX);
+
        for (i = 0; i < MAX; i++) {
-               p = malloc(sizeof(i));
+               p = array + i;
                *p = i;
-               if (!lrad_hash_table_insert(ht, i, p)) {
+               hash = lrad_hash(&i, sizeof(i));
+
+               if (!lrad_hash_table_insert(ht, hash, p)) {
                        fprintf(stderr, "Failed insert %08x\n", i);
                        exit(1);
                }
-
-               if (grow) {
-                       uint32_t j;
-
-                       for (j = 0; j < i; j++) {
-                               q = lrad_hash_table_finddata(ht, j);
-                               if (!q || (*q != j)) {
-                                       fprintf(stderr, "BAD DATA %d %p\n",
-                                               j, q);
-                                       exit(1);
-                               }
-                       }
-                       grow = 0;
-               }
-
-               q = lrad_hash_table_finddata(ht, i);
+#ifdef TEST_INSERT
+               q = lrad_hash_table_finddata(ht, hash);
                if (q != p) {
                        fprintf(stderr, "Bad data %d\n", i);
                        exit(1);
                }
+#endif
        }
 
-       for (i = 0; i < MAX; i++) {
-               lrad_hash_table_delete(ht, i);
-               q = lrad_hash_table_finddata(ht, i);
-               if (q) {
-                       fprintf(stderr, "Failed to delete %08x\n", i);
-                       exit(1);
+       lrad_hash_table_info(ht);
+
+       /*
+        *      Build this to see how lookups result in shortening
+        *      of the hash chains.
+        */
+       if (0) {
+               for (i = 0; i < MAX ; i++) {
+                       hash = lrad_hash(&i, sizeof(i));
+                       
+                       q = lrad_hash_table_finddata(ht, hash);
+                       if (!q || *q != i) {
+                               fprintf(stderr, "Failed finding %d\n", i);
+                               exit(1);
+                       }
+                       
+#if 0
+                       if (!lrad_hash_table_delete(ht, hash)) {
+                               fprintf(stderr, "Failed deleting %d\n", i);
+                               exit(1);
+                       }
+                       q = lrad_hash_table_finddata(ht, hash);
+                       if (q) {
+                               fprintf(stderr, "Failed to delete %08x\n", i);
+                               exit(1);
+                       }
+#endif
                }
+
+               lrad_hash_table_info(ht);
        }
 
        lrad_hash_table_free(ht);
+       free(array);
 
        exit(0);
 }
index ef34ec4..23137bc 100644 (file)
@@ -35,15 +35,8 @@ static const char rcsid[] = "$Id$";
 
 struct request_list_t {
        lrad_hash_table_t *ht;
-       int collisions;
 };
 
-typedef struct request_entry_t {
-       struct request_entry_t *next;
-       REQUEST                *request;
-} request_entry_t;
-
-
 #ifdef HAVE_PTHREAD_H
 static pthread_mutex_t proxy_mutex;
 #else
@@ -205,58 +198,6 @@ static void packet_hash(RADIUS_PACKET *packet)
 }
 
 
-static int packet_cmp(const RADIUS_PACKET *a, const RADIUS_PACKET *b)
-{
-
-       if (a->id != b->id) return 0;
-
-       if (a->src_port != b->src_port) return 0;
-
-       switch (a->dst_ipaddr.af) {
-       case AF_INET:
-               if (memcmp(&a->dst_ipaddr.ipaddr.ip4addr,
-                          &b->dst_ipaddr.ipaddr.ip4addr,
-                          sizeof(a->dst_ipaddr.ipaddr.ip4addr)) != 0)
-                       return 0;
-               if (memcmp(&a->src_ipaddr.ipaddr.ip4addr,
-                          &b->src_ipaddr.ipaddr.ip4addr,
-                          sizeof(a->src_ipaddr.ipaddr.ip4addr)) != 0)
-                       return 0;
-               break;
-       case AF_INET6:
-               if (memcmp(&a->dst_ipaddr.ipaddr.ip6addr,
-                          &b->dst_ipaddr.ipaddr.ip6addr,
-                          sizeof(a->dst_ipaddr.ipaddr.ip6addr)) != 0)
-                       return 0;
-               if (memcmp(&a->src_ipaddr.ipaddr.ip6addr,
-                          &b->src_ipaddr.ipaddr.ip6addr,
-                          sizeof(a->src_ipaddr.ipaddr.ip6addr)) != 0)
-                       return 0;
-               break;
-       default:
-               return 0;
-               break;
-       }
-
-       /*
-        *      These next comparisons should reall be assertions.
-        */
-       if (a->src_ipaddr.af != b->src_ipaddr.af) return 0;
-
-       if (a->dst_ipaddr.af != b->dst_ipaddr.af) return 0;
-
-       if (a->sockfd != b->sockfd) return 0;
-
-       if (a->code != b->code) return 0;
-
-       if (a->dst_port != b->dst_port) return 0;
-
-       /*
-        *      Everything's equal.  Say so.
-        */
-       return 1;
-}
-
 /*
  *     Compare two REQUEST data structures, based on a number
  *     of criteria, for proxied packets.
@@ -334,11 +275,10 @@ request_list_t *rl_init(void)
         */
        memset(rl, 0, sizeof(*rl));
 
-       rl->ht = lrad_hash_table_create(10, NULL, 0);
+       rl->ht = lrad_hash_table_create(NULL);
        if (!rl->ht) {
                rad_assert("FAIL" == NULL);
        }
-       lrad_hash_table_set_data_size(rl->ht, sizeof(request_entry_t));
 
        return rl;
 }
@@ -417,28 +357,21 @@ int rl_init_proxy(void)
 
 static int rl_free_entry(void *ctx, void *data)
 {
-       request_entry_t *next, *entry = data;
-       REQUEST *request;
-
+       REQUEST *request = data;
+       
        ctx = ctx;              /* -Wunused */
 
-       for (entry = data; entry != NULL; entry = next) {
-               next = entry->next;
-               request = entry->request;
-
 #ifdef HAVE_PTHREAD_H 
-               /*
-                *      If someone is processing this request, kill
-                *      them, and mark the request as not being used.
-                */
-               if (request->child_pid != NO_SUCH_CHILD_PID) {
-                       pthread_kill(request->child_pid, SIGKILL);
-                       request->child_pid = NO_SUCH_CHILD_PID;
-               }
-#endif
-               request_free(&request);
-               if (entry != data) free(entry);
+       /*
+        *      If someone is processing this request, kill
+        *      them, and mark the request as not being used.
+        */
+       if (request->child_pid != NO_SUCH_CHILD_PID) {
+               pthread_kill(request->child_pid, SIGKILL);
+               request->child_pid = NO_SUCH_CHILD_PID;
        }
+#endif
+       request_free(&request);
 
        return 0;
 }
@@ -543,8 +476,6 @@ static void rl_delete_proxy(REQUEST *request, rbnode_t *node)
  */
 void rl_yank(request_list_t *rl, REQUEST *request)
 {
-       request_entry_t *entry;
-
 #ifdef WITH_SNMP
        /*
         *      Update the SNMP statistics.
@@ -585,45 +516,7 @@ void rl_yank(request_list_t *rl, REQUEST *request)
        /*
         *      Delete the request from the list.
         */
-       entry = lrad_hash_table_finddata(rl->ht, request->packet->hash);
-
-       /*
-        *      The entry managed by the hash table is being deleted.
-        */
-       if (entry->request == request) {
-               if (entry->next) {
-                       request_entry_t *next = entry->next;
-                       entry->next = next->next;
-                       entry->request = next->request;
-                       free(next);
-                       
-                       rad_assert(rl->collisions > 0);
-                       rl->collisions--;
-               } else {
-                       lrad_hash_table_delete(rl->ht, request->packet->hash);
-               }
-
-       } else {                /* a secondary entry is being deleted */
-               request_entry_t *this, *next, **last;
-
-               last = &entry->next;
-               for (this = entry->next; this != NULL; this = next) {
-                       next = this->next;
-                       
-                       if (this->request != request) {
-                               last = &this->next;
-                               continue;
-                       }
-
-                       *last = this->next;
-                       free(this);
-
-                       rad_assert(rl->collisions > 0);
-                       rl->collisions--;
-                       break;
-               }
-       }
-
+       lrad_hash_table_delete(rl->ht, request->packet->hash);
        
        /*
         *      If there's a proxied packet, and we're still
@@ -656,28 +549,7 @@ void rl_delete(request_list_t *rl, REQUEST *request)
  */
 int rl_add(request_list_t *rl, REQUEST *request)
 {
-       request_entry_t *entry, myentry;
-
-       entry = lrad_hash_table_finddata(rl->ht, request->packet->hash);
-       if (!entry) {
-               myentry.next = NULL;
-               myentry.request = request;
-               return lrad_hash_table_insert(rl->ht, request->packet->hash,
-                                             &myentry);
-       }
-
-       /*
-        *      Collision: insert it into a linked list (yuck)
-        */
-       entry->next = rad_malloc(sizeof(*entry));
-       entry->next->next = NULL;
-       entry->next->request = request;
-
-       DEBUG3(" FYI: hash collision...");
-
-       rl->collisions++;
-
-       return 1;
+       return lrad_hash_table_insert(rl->ht, request->packet->hash, request);
 }
 
 /*
@@ -692,23 +564,9 @@ int rl_add(request_list_t *rl, REQUEST *request)
  */
 REQUEST *rl_find(request_list_t *rl, RADIUS_PACKET *packet)
 {
-       request_entry_t *entry;
-
        packet_hash(packet);
 
-       entry = lrad_hash_table_finddata(rl->ht, packet->hash);
-       if (!entry) return NULL;
-
-       /*
-        *      Call a packet comparison function?
-        */
-       while (entry && !packet_cmp(packet, entry->request->packet)) {
-               entry = entry->next;
-       }
-
-       if (!entry) return NULL;
-
-       return entry->request;
+       return lrad_hash_table_finddata(rl->ht, packet->hash);
 }
 
 /*
@@ -1041,7 +899,7 @@ REQUEST *rl_find_proxy(RADIUS_PACKET *packet)
  */
 int rl_num_requests(request_list_t *rl)
 {
-       return lrad_hash_table_num_elements(rl->ht) + rl->collisions;
+       return lrad_hash_table_num_elements(rl->ht);
 }
 
 
@@ -1068,11 +926,7 @@ static int refresh_request(void *ctx, void *data)
        rl_walk_t *info = (rl_walk_t *) ctx;
        child_pid_t child_pid;
        request_list_t *rl = info->rl;
-       request_entry_t *entry = data;
-       request_entry_t *next = entry->next;
-       REQUEST *request = entry->request;
-
-       if (next) refresh_request(ctx, next);
+       REQUEST *request = data;
 
        rad_assert(request->magic == REQUEST_MAGIC);
 
index 623a3c4..f8cca7c 100644 (file)
@@ -248,7 +248,7 @@ static int reap_callback(void *ctx, void *data)
         *      Else no child, or was already reaped
         */
 
-       lrad_hash_table_delete(ht, pid);
+       lrad_hash_table_delete(ht, lrad_hash(&pid, sizeof(pid)));
 
        return 0;
 }
@@ -797,13 +797,11 @@ int thread_pool_init(int spawn_flag)
                /*
                 *      Create the hash table of child PID's
                 */
-               thread_pool.waiters = lrad_hash_table_create(8, NULL, 0);
+               thread_pool.waiters = lrad_hash_table_create(free);
                if (!thread_pool.waiters) {
                        radlog(L_ERR, "FATAL: Failed to set up wait hash");
                        exit(1);
                }
-               lrad_hash_table_set_data_size(thread_pool.waiters,
-                                             sizeof(pid_t));
        }
 
        /*
@@ -1106,6 +1104,9 @@ pid_t rad_fork(int exec_wait)
        child_pid = fork();
        if (child_pid > 0) {
                int rcode;
+               pid_t *ptr = rad_malloc(sizeof(*ptr));
+
+               *ptr = child_pid;
 
                /*
                 *      Lock the mutex.
@@ -1113,7 +1114,9 @@ pid_t rad_fork(int exec_wait)
                pthread_mutex_lock(&thread_pool.wait_mutex);
 
                rcode = lrad_hash_table_insert(thread_pool.waiters,
-                                              child_pid, &child_pid);
+                                              lrad_hash(&child_pid,
+                                                        sizeof(child_pid)),
+                                              ptr);
                
                /*
                 *      Unlock the mutex.