The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
hash.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Resizable hash tables
18 *
19 * The weird "reverse" function is based on an idea from
20 * "Split-Ordered Lists - Lock-free Resizable Hash Tables", with
21 * modifications so that they're not lock-free. :(
22 *
23 * However, the split-order idea allows a fast & easy splitting of the
24 * hash bucket chain when the hash table is resized. Without it, we'd
25 * have to check & update the pointers for every node in the buck chain,
26 * rather than being able to move 1/2 of the entries in the chain with
27 * one update.
28 *
29 * @file src/lib/util/hash.c
30 *
31 * @copyright 2005,2006 The FreeRADIUS server project
32 */
33RCSID("$Id: e6e634bb03557a2fd50ccc4c8466735f50d9e2b5 $")
34
35#include <freeradius-devel/util/hash.h>
36
37/*
38 * A reasonable number of buckets to start off with.
39 * Should be a power of two.
40 */
41#define FR_HASH_NUM_BUCKETS (64)
42
49
51 uint32_t num_elements; //!< Number of elements in the hash table.
52 uint32_t num_buckets; //!< Number of buckets (how long the array is) - power of 2 */
55
56 fr_free_t free; //!< Data free function.
57 fr_hash_t hash; //!< Hashing function.
58 fr_cmp_t cmp; //!< Comparison function.
59
60 char const *type; //!< Talloc type to check elements against.
61
63 fr_hash_entry_t **buckets; //!< Array of hash buckets.
64};
65
66#ifdef TESTING
67static int grow = 0;
68#endif
69
70/*
71 * 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";}}'
72 */
73static const uint8_t reversed_byte[256] = {
74 0, 128, 64, 192, 32, 160, 96, 224,
75 16, 144, 80, 208, 48, 176, 112, 240,
76 8, 136, 72, 200, 40, 168, 104, 232,
77 24, 152, 88, 216, 56, 184, 120, 248,
78 4, 132, 68, 196, 36, 164, 100, 228,
79 20, 148, 84, 212, 52, 180, 116, 244,
80 12, 140, 76, 204, 44, 172, 108, 236,
81 28, 156, 92, 220, 60, 188, 124, 252,
82 2, 130, 66, 194, 34, 162, 98, 226,
83 18, 146, 82, 210, 50, 178, 114, 242,
84 10, 138, 74, 202, 42, 170, 106, 234,
85 26, 154, 90, 218, 58, 186, 122, 250,
86 6, 134, 70, 198, 38, 166, 102, 230,
87 22, 150, 86, 214, 54, 182, 118, 246,
88 14, 142, 78, 206, 46, 174, 110, 238,
89 30, 158, 94, 222, 62, 190, 126, 254,
90 1, 129, 65, 193, 33, 161, 97, 225,
91 17, 145, 81, 209, 49, 177, 113, 241,
92 9, 137, 73, 201, 41, 169, 105, 233,
93 25, 153, 89, 217, 57, 185, 121, 249,
94 5, 133, 69, 197, 37, 165, 101, 229,
95 21, 149, 85, 213, 53, 181, 117, 245,
96 13, 141, 77, 205, 45, 173, 109, 237,
97 29, 157, 93, 221, 61, 189, 125, 253,
98 3, 131, 67, 195, 35, 163, 99, 227,
99 19, 147, 83, 211, 51, 179, 115, 243,
100 11, 139, 75, 203, 43, 171, 107, 235,
101 27, 155, 91, 219, 59, 187, 123, 251,
102 7, 135, 71, 199, 39, 167, 103, 231,
103 23, 151, 87, 215, 55, 183, 119, 247,
104 15, 143, 79, 207, 47, 175, 111, 239,
105 31, 159, 95, 223, 63, 191, 127, 255
106};
107
108
109/*
110 * 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";}}'
111 */
112static uint8_t parent_byte[256] = {
113 0, 0, 0, 1, 0, 1, 2, 3,
114 0, 1, 2, 3, 4, 5, 6, 7,
115 0, 1, 2, 3, 4, 5, 6, 7,
116 8, 9, 10, 11, 12, 13, 14, 15,
117 0, 1, 2, 3, 4, 5, 6, 7,
118 8, 9, 10, 11, 12, 13, 14, 15,
119 16, 17, 18, 19, 20, 21, 22, 23,
120 24, 25, 26, 27, 28, 29, 30, 31,
121 0, 1, 2, 3, 4, 5, 6, 7,
122 8, 9, 10, 11, 12, 13, 14, 15,
123 16, 17, 18, 19, 20, 21, 22, 23,
124 24, 25, 26, 27, 28, 29, 30, 31,
125 32, 33, 34, 35, 36, 37, 38, 39,
126 40, 41, 42, 43, 44, 45, 46, 47,
127 48, 49, 50, 51, 52, 53, 54, 55,
128 56, 57, 58, 59, 60, 61, 62, 63,
129 0, 1, 2, 3, 4, 5, 6, 7,
130 8, 9, 10, 11, 12, 13, 14, 15,
131 16, 17, 18, 19, 20, 21, 22, 23,
132 24, 25, 26, 27, 28, 29, 30, 31,
133 32, 33, 34, 35, 36, 37, 38, 39,
134 40, 41, 42, 43, 44, 45, 46, 47,
135 48, 49, 50, 51, 52, 53, 54, 55,
136 56, 57, 58, 59, 60, 61, 62, 63,
137 64, 65, 66, 67, 68, 69, 70, 71,
138 72, 73, 74, 75, 76, 77, 78, 79,
139 80, 81, 82, 83, 84, 85, 86, 87,
140 88, 89, 90, 91, 92, 93, 94, 95,
141 96, 97, 98, 99, 100, 101, 102, 103,
142 104, 105, 106, 107, 108, 109, 110, 111,
143 112, 113, 114, 115, 116, 117, 118, 119,
144 120, 121, 122, 123, 124, 125, 126, 127
145};
146
147
148/*
149 * Reverse a key.
150 */
152{
153 /*
154 * Cast to uint32_t is required because the
155 * default type of of the expression is an
156 * int and ubsan correctly complains that
157 * the result of 0xff << 24 won't fit in a
158 * signed 32bit integer.
159 */
160 return (((uint32_t)reversed_byte[key & 0xff] << 24) |
161 ((uint32_t)reversed_byte[(key >> 8) & 0xff] << 16) |
162 ((uint32_t)reversed_byte[(key >> 16) & 0xff] << 8) |
163 ((uint32_t)reversed_byte[(key >> 24) & 0xff]));
164}
165
166/*
167 * Take the parent by discarding the highest bit that is set.
168 */
170{
171 if (key > 0x00ffffff)
172 return (key & 0x00ffffff) | (parent_byte[key >> 24] << 24);
173
174 if (key > 0x0000ffff)
175 return (key & 0x0000ffff) | (parent_byte[key >> 16] << 16);
176
177 if (key > 0x000000ff)
178 return (key & 0x000000ff) | (parent_byte[key >> 8] << 8);
179
180 return parent_byte[key];
181}
182
183
184static CC_NO_UBSAN(undefined)
185fr_hash_entry_t *list_find(fr_hash_table_t *ht,
186 fr_hash_entry_t *head, uint32_t reversed, void const *data)
187{
188 fr_hash_entry_t *cur;
189
190 for (cur = head; cur != &ht->null; cur = cur->next) {
191 if (cur->reversed == reversed) {
192 if (ht->cmp) {
193 int cmp = ht->cmp(data, cur->data);
194 if (cmp > 0) break;
195 if (cmp < 0) continue;
196 }
197 return cur;
198 }
199 if (cur->reversed > reversed) break;
200 }
201
202 return NULL;
203}
204
205
206/*
207 * Inserts a new entry into the list, in order.
208 */
209static CC_NO_UBSAN(undefined)
210bool list_insert(fr_hash_table_t *ht,
212{
213 fr_hash_entry_t **last, *cur;
214
215 last = head;
216
217 for (cur = *head; cur != &ht->null; last = &(cur->next), cur = cur->next) {
218 if (cur->reversed > node->reversed) break;
219
220 if (cur->reversed == node->reversed) {
221 if (ht->cmp) {
222 int8_t cmp = ht->cmp(node->data, cur->data);
223 if (cmp > 0) break;
224 if (cmp < 0) continue;
225 }
226 return false;
227 }
228 }
229
230 node->next = *last;
231 *last = node;
232
233 return true;
234}
235
236
237/*
238 * Delete an entry from the list.
239 */
242{
243 fr_hash_entry_t **last, *cur;
244
245 last = head;
246
247 for (cur = *head; cur != &ht->null; cur = cur->next) {
248 if (cur == node) {
249 *last = node->next;
250 return;
251 }
252 last = &(cur->next);
253 }
254
255 fr_assert(0);
256}
257
259{
260 uint32_t i;
261 fr_hash_entry_t *node, *next;
262
263 if (ht->free) {
264 for (i = 0; i < ht->num_buckets; i++) {
265 if (ht->buckets[i]) for (node = ht->buckets[i];
266 node != &ht->null;
267 node = next) {
268 next = node->next;
269 if (!node->data) continue; /* dummy entry */
270
271 ht->free(node->data);
272 }
273 }
274 }
275
276 return 0;
277}
278
279/*
280 * Create the table.
281 *
282 * Memory usage in bytes is (20/3) * number of entries.
283 */
285 char const *type,
286 fr_hash_t hash_func,
287 fr_cmp_t cmp_func,
288 fr_free_t free_func)
289{
290 fr_hash_table_t *ht;
291
292 ht = talloc(ctx, fr_hash_table_t);
293 if (!ht) return NULL;
294 talloc_set_destructor(ht, _fr_hash_table_free);
295
296 *ht = (fr_hash_table_t){
297 .type = type,
298 .free = free_func,
299 .hash = hash_func,
300 .cmp = cmp_func,
301 .num_buckets = FR_HASH_NUM_BUCKETS,
302 .mask = FR_HASH_NUM_BUCKETS - 1,
303
304 /*
305 * Have a default load factor of 2.5. In practice this
306 * means that the average load will hit 3 before the
307 * table grows.
308 */
309 .next_grow = (FR_HASH_NUM_BUCKETS << 1) + (FR_HASH_NUM_BUCKETS >> 1),
310 .buckets = talloc_zero_array(ht, fr_hash_entry_t *, FR_HASH_NUM_BUCKETS)
311 };
312 if (unlikely(!ht->buckets)) {
313 talloc_free(ht);
314 return NULL;
315 }
316
317 ht->null.reversed = ~0;
318 ht->null.key = ~0;
319 ht->null.next = &ht->null;
320 ht->buckets[0] = &ht->null;
321
322 return ht;
323}
324
325
326/*
327 * If the current bucket is uninitialized, initialize it
328 * by recursively copying information from the parent.
329 *
330 * We may have a situation where entry E is a parent to 2 other
331 * entries E' and E". If we split E into E and E', then the
332 * nodes meant for E" end up in E or E', either of which is
333 * wrong. To solve that problem, we walk down the whole chain,
334 * inserting the elements into the correct place.
335 */
337{
338 uint32_t parent_entry;
339 fr_hash_entry_t **last, *cur;
340 uint32_t this;
341
342 parent_entry = parent_of(entry);
343
344 /* parent_entry == entry if and only if entry == 0 */
345
346 if (!ht->buckets[parent_entry]) {
347 fr_hash_table_fixup(ht, parent_entry);
348 }
349
350 /*
351 * Keep walking down cur, trying to find entries that
352 * don't belong here any more. There may be multiple
353 * ones, so we can't have a naive algorithm...
354 */
355 last = &ht->buckets[parent_entry];
356 this = parent_entry;
357
358 for (cur = *last; cur != &ht->null; cur = cur->next) {
359 uint32_t real_entry;
360
361 real_entry = cur->key & ht->mask;
362 if (real_entry != this) { /* ht->buckets[real_entry] == NULL */
363 *last = &ht->null;
364 ht->buckets[real_entry] = cur;
365 this = real_entry;
366 }
367
368 last = &(cur->next);
369 }
370
371 /*
372 * We may NOT have initialized this bucket, so do it now.
373 */
374 if (!ht->buckets[entry]) ht->buckets[entry] = &ht->null;
375}
376
377/*
378 * This should be a power of two. Changing it to 4 doesn't seem
379 * to make any difference.
380 */
381#define GROW_FACTOR (2)
382
383/*
384 * Set a maximum number of entries, which lets us avoid overflows
385 * on next_grow, GROW_FACTOR, etc.
386 */
387#define TABLE_MAX ((uint32_t) 0x20000000)
388
389/*
390 * Grow the hash table.
391 */
393{
394 fr_hash_entry_t **buckets;
395 size_t existing = talloc_get_size(ht->buckets);
396 size_t expanded;
397
398 /*
399 * Cap the growth, because we need to be able to set a
400 * mask, etc.
401 */
402 if (ht->num_buckets >= TABLE_MAX) return;
403
404 expanded = GROW_FACTOR * ht->num_buckets;
405 if (expanded > TABLE_MAX) expanded = TABLE_MAX;
406
407 buckets = talloc_realloc(ht, ht->buckets, fr_hash_entry_t *, expanded);
408 if (!buckets) return;
409
410 memset(((uint8_t *)buckets) + existing, 0, talloc_get_size(buckets) - existing);
411
412 ht->buckets = buckets;
413 ht->num_buckets = expanded;
414 ht->mask = ht->num_buckets - 1;
415 ht->next_grow *= GROW_FACTOR;
416
417#ifdef TESTING
418 grow = 1;
419 fprintf(stderr, "GROW TO %d\n", ht->num_buckets);
420#endif
421}
422
423/*
424 * Internal find a node routine.
425 */
426static inline CC_HINT(always_inline) fr_hash_entry_t *hash_table_find(fr_hash_table_t *ht,
427 uint32_t key, void const *data)
428{
429 uint32_t entry;
430 uint32_t reversed;
431
432 entry = key & ht->mask;
433 reversed = reverse(key);
434
435 if (!ht->buckets[entry]) fr_hash_table_fixup(ht, entry);
436
437 return list_find(ht, ht->buckets[entry], reversed, data);
438}
439
440/** Find data in a hash table
441 *
442 * @param[in] ht to find data in.
443 * @param[in] data to find. Will be passed to the
444 * hashing function.
445 * @return
446 * - The user data we found.
447 * - NULL if we couldn't find any matching data.
448 */
449CC_NO_UBSAN(function) /* UBSAN: false positive - htrie call with first argument of void * trips --fsanitize=function */
451{
452 fr_hash_entry_t *node;
453
454 node = hash_table_find(ht, ht->hash(data), data);
455 if (!node) return NULL;
456
457 return UNCONST(void *, node->data);
458}
459
460/** Hash table lookup with pre-computed key
461 *
462 * @param[in] ht to find data in.
463 * @param[in] key the precomputed key.
464 * @param[in] data for list matching.
465 * @return
466 * - The user data we found.
467 * - NULL if we couldn't find any matching data.
468 */
470{
471 fr_hash_entry_t *node;
472
473 node = hash_table_find(ht, key, data);
474 if (!node) return NULL;
475
476 return UNCONST(void *, node->data);
477}
478
479/** Insert data into a hash table
480 *
481 * @param[in] ht to insert data into.
482 * @param[in] data to insert. Will be passed to the
483 * hashing function.
484 * @return
485 * - true if data was inserted.
486 * - false if data already existed and was not inserted.
487 */
488CC_NO_UBSAN(function) /* UBSAN: false positive - htrie call with first argument of void * trips --fsanitize=function */
490{
491 uint32_t key;
492 uint32_t entry;
493 uint32_t reversed;
494 fr_hash_entry_t *node;
495
496#ifndef TALLOC_GET_TYPE_ABORT_NOOP
497 if (ht->type) (void)_talloc_get_type_abort(data, ht->type, __location__);
498#endif
499
500 if (ht->num_elements >= TABLE_MAX) return false;
501
502 key = ht->hash(data);
503 entry = key & ht->mask;
504 reversed = reverse(key);
505
506 if (!ht->buckets[entry]) fr_hash_table_fixup(ht, entry);
507
508 /*
509 * If we try to do our own memory allocation here, the
510 * speedup is only ~15% or so, which isn't worth it.
511 */
512 node = talloc_zero(ht, fr_hash_entry_t);
513 if (unlikely(!node)) return false;
514
515 node->next = &ht->null;
516 node->reversed = reversed;
517 node->key = key;
518 node->data = UNCONST(void *, data);
519
520 /* already in the table, can't insert it */
521 if (!list_insert(ht, &ht->buckets[entry], node)) {
522 talloc_free(node);
523 return false;
524 }
525
526 /*
527 * Check the load factor, and grow the table if
528 * necessary.
529 */
530 ht->num_elements++;
531 if (ht->num_elements >= ht->next_grow) fr_hash_table_grow(ht);
532
533 return true;
534}
535
536/** Replace old data with new data, OR insert if there is no old
537 *
538 * @param[out] old data that was replaced. If this argument
539 * is not NULL, then the old data will not
540 * be freed, even if a free function is
541 * configured.
542 * @param[in] ht to insert data into.
543 * @param[in] data to replace. Will be passed to the
544 * hashing function.
545 * @return
546 * - 1 if data was inserted (hash table grows)
547 * - 0 if data was replaced (hash table doesn't grow)
548 * - -1 if we failed to replace data
549 */
550CC_NO_UBSAN(function) /* UBSAN: false positive - htrie call with first argument of void * trips --fsanitize=function */
551int fr_hash_table_replace(void **old, fr_hash_table_t *ht, void const *data)
552{
553 fr_hash_entry_t *node;
554
555 node = hash_table_find(ht, ht->hash(data), data);
556 if (!node) {
557 if (old) *old = NULL;
558 return fr_hash_table_insert(ht, data) ? 1 : -1;
559 }
560
561 if (old) {
562 *old = node->data;
563 } else if (ht->free) {
564 ht->free(node->data);
565 }
566
567 node->data = UNCONST(void *, data);
568
569 return 0;
570}
571
572/** Remove an entry from the hash table, without freeing the data
573 *
574 * @param[in] ht to remove data from.
575 * @param[in] data to remove. Will be passed to the
576 * hashing function.
577 * @return
578 * - The user data we removed.
579 * - NULL if we couldn't find any matching data.
580 */
581CC_NO_UBSAN(function) /* UBSAN: false positive - htrie call with first argument of void * trips --fsanitize=function */
583{
584 uint32_t key;
585 uint32_t entry;
586 uint32_t reversed;
587 void *old;
588 fr_hash_entry_t *node;
589
590 key = ht->hash(data);
591 entry = key & ht->mask;
592 reversed = reverse(key);
593
594 if (!ht->buckets[entry]) fr_hash_table_fixup(ht, entry);
595
596 node = list_find(ht, ht->buckets[entry], reversed, data);
597 if (!node) return NULL;
598
599 list_delete(ht, &ht->buckets[entry], node);
600 ht->num_elements--;
601
602 old = node->data;
603 talloc_free(node);
604
605 return old;
606}
607
608/** Remove and free data (if a free function was specified)
609 *
610 * @param[in] ht to remove data from.
611 * @param[in] data to remove/free.
612 * @return
613 * - true if we removed data.
614 * - false if we couldn't find any matching data.
615 */
616CC_NO_UBSAN(function) /* UBSAN: false positive - htrie call with first argument of void * trips --fsanitize=function */
618{
619 void *old;
620
621 old = fr_hash_table_remove(ht, data);
622 if (!old) return false;
623
624 if (ht->free) ht->free(old);
625
626 return true;
627}
628
629/*
630 * Count number of elements
631 */
632CC_NO_UBSAN(function) /* UBSAN: false positive - htrie call with first argument of void * trips --fsanitize=function */
634{
635 return ht->num_elements;
636}
637
638/** Iterate over entries in a hash table
639 *
640 * @note If the hash table is modified the iterator should be considered invalidated.
641 *
642 * @param[in] ht to iterate over.
643 * @param[in] iter Pointer to an iterator struct, used to maintain
644 * state between calls.
645 * @return
646 * - User data.
647 * - NULL if at the end of the list.
648 */
650{
651 fr_hash_entry_t *node;
652 uint32_t i;
653
654 /*
655 * Return the next element in the bucket.
656 */
657 if (iter->next != &ht->null) {
658 node = iter->next;
659 iter->next = node->next;
660
661 return node->data;
662 }
663
664 /*
665 * We've wrapped around to bucket 0 again. That means we're done.
666 */
667 if (iter->bucket == 0) return NULL;
668
669 /*
670 * We might have to go through multiple empty
671 * buckets to find one that contains something
672 * we should return
673 */
674 i = iter->bucket - 1;
675 for (;;) {
676 if (!ht->buckets[i]) fr_hash_table_fixup(ht, i);
677
678 node = ht->buckets[i];
679 if (node == &ht->null) {
680 if (i == 0) break;
681 i--;
682 continue; /* This bucket was empty too... */
683 }
684
685 iter->next = node->next; /* Store the next one to examine */
686 iter->bucket = i;
687 return node->data;
688 }
689 iter->bucket = i;
690
691 return NULL;
692}
693
694/** Initialise an iterator
695 *
696 * @note If the hash table is modified the iterator should be considered invalidated.
697 *
698 * @param[in] ht to iterate over.
699 * @param[out] iter to initialise.
700 * @return
701 * - The first entry in the hash table.
702 * - NULL if the hash table is empty.
703 */
705{
706 iter->bucket = ht->num_buckets;
707 iter->next = &ht->null;
708
709 return fr_hash_table_iter_next(ht, iter);
710}
711
712/** Copy all entries out of a hash table into an array
713 *
714 * @param[in] ctx to allocate array in.
715 * @param[in] out array of hash table entries.
716 * @param[in] ht to flatter.
717 * @return
718 * - 0 on success.
719 * - -1 on failure.
720 */
721int fr_hash_table_flatten(TALLOC_CTX *ctx, void **out[], fr_hash_table_t *ht)
722{
723 uint64_t num = fr_hash_table_num_elements(ht), i;
724 fr_hash_iter_t iter;
725 void *item, **list;
726
727 if (unlikely(!(list = talloc_array(ctx, void *, num)))) return -1;
728
729 for (item = fr_hash_table_iter_init(ht, &iter), i = 0;
730 item;
731 item = fr_hash_table_iter_next(ht, &iter), i++) list[i] = item;
732
733 *out = list;
734
735 return 0;
736}
737
738/** Ensure all buckets are filled
739 *
740 * This must be called if the table will be read by multiple threads without
741 * synchronisation. Synchronisation is still required for updates.
742 *
743 * @param[in] ht to fill.
744 */
746{
747 uint32_t i;
748
749 if (!ht->num_buckets) return;
750
751
752 i = ht->num_buckets - 1;
753
754 while (true) {
755 if (!ht->buckets[i]) fr_hash_table_fixup(ht, i);
756 if (!i) break;
757 i--;
758 }
759}
760
761#ifdef TESTING
762/*
763 * Show what the hash table is doing.
764 */
765int fr_hash_table_info(fr_hash_table_t *ht)
766{
767 int i, a, collisions, uninitialized;
768 int array[256];
769
770 if (!ht) return 0;
771
772 uninitialized = collisions = 0;
773 memset(array, 0, sizeof(array));
774
775 for (i = 0; i < ht->num_buckets; i++) {
776 uint32_t key;
777 int load;
778 fr_hash_entry_t *node, *next;
779
780 /*
781 * If we haven't inserted or looked up an entry
782 * in a bucket, it's uninitialized.
783 */
784 if (!ht->buckets[i]) {
785 uninitialized++;
786 continue;
787 }
788
789 load = 0;
790 key = ~0;
791 for (node = ht->buckets[i]; node != &ht->null; node = next) {
792 if (node->reversed == key) {
793 collisions++;
794 } else {
795 key = node->reversed;
796 }
797 next = node->next;
798 load++;
799 }
800
801 if (load > 255) load = 255;
802 array[load]++;
803 }
804
805 printf("HASH TABLE %p\tbuckets: %d\t(%d uninitialized)\n", ht,
806 ht->num_buckets, uninitialized);
807 printf("\tnum entries %d\thash collisions %d\n",
808 ht->num_elements, collisions);
809
810 a = 0;
811 for (i = 1; i < 256; i++) {
812 if (!array[i]) continue;
813 printf("%d\t%d\n", i, array[i]);
814
815 /*
816 * Since the entries are ordered, the lookup cost
817 * for any one element in a chain is (on average)
818 * the cost of walking half of the chain.
819 */
820 if (i > 1) {
821 a += array[i] * i;
822 }
823 }
824 a /= 2;
825 a += array[1];
826
827 printf("\texpected lookup cost = %d/%d or %f\n\n",
828 ht->num_elements, a,
829 (float) ht->num_elements / (float) a);
830
831 return 0;
832}
833#endif
834
835
836#define FNV_MAGIC_INIT (0x811c9dc5)
837#define FNV_MAGIC_PRIME (0x01000193)
838
839/*
840 * A fast hash function. For details, see:
841 *
842 * http://www.isthe.com/chongo/tech/comp/fnv/
843 *
844 * Which also includes public domain source. We've re-written
845 * it here for our purposes.
846 */
847uint32_t fr_hash(void const *data, size_t size)
848{
849 uint8_t const *p = data;
850 uint8_t const *q = p + size;
852
853 /*
854 * FNV-1 hash each octet in the buffer
855 */
856 while (p != q) {
857 /*
858 * XOR the 8-bit quantity into the bottom of
859 * the hash.
860 */
861 hash ^= (uint32_t) (*p++);
862
863 /*
864 * Multiply by 32-bit magic FNV prime, mod 2^32
865 */
867#if 0
868 /*
869 * Potential optimization.
870 */
871 hash += (hash<<1) + (hash<<4) + (hash<<7) + (hash<<8) + (hash<<24);
872#endif
873 }
874
875 return hash;
876}
877
878/*
879 * Continue hashing data.
880 */
881uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
882{
883 uint8_t const *p = data;
884 uint8_t const *q;
885
886 if (size == 0) return hash; /* Avoid ubsan issues with access NULL pointer */
887
888 q = p + size;
889 while (p < q) {
890 hash ^= (uint32_t) (*p++);
892 }
893
894 return hash;
895}
896
897/*
898 * Hash a C string, so we loop over it once.
899 */
901{
903
904 while (*p) {
905 hash ^= (uint32_t) (*p++);
906 /* coverity[overflow_const] */
908 }
909
910 return hash;
911}
912
913/** Hash a C string, converting all chars to lowercase
914 *
915 */
917{
919
920 while (*p) {
921 hash ^= (uint32_t) (tolower((uint8_t) *p++));
922 /* coverity[overflow_const] */
924 }
925
926 return hash;
927}
928
929/*
930 * 64-bit variants of the above functions/
931 */
932#undef FNV_MAGIC_INIT
933#undef FNV_MAGIC_PRIME
934#define FNV_MAGIC_INIT ((uint64_t) 0xcbf29ce484222325)
935#define FNV_MAGIC_PRIME ((uint64_t) 0x00000100000001B3)
936
937/*
938 * A 64-bit version of the above hash
939 */
940uint64_t fr_hash64(void const *data, size_t size)
941{
942 uint8_t const *p = data;
943 uint8_t const *q = p + size;
944 uint64_t hash = FNV_MAGIC_INIT;
945
946 /*
947 * FNV-1 hash each octet in the buffer
948 */
949 while (p != q) {
950 /*
951 * XOR the 8-bit quantity into the bottom of
952 * the hash.
953 */
954 hash ^= (uint64_t) (*p++);
955
956 /*
957 * Multiply by 64-bit magic FNV prime, mod 2^64
958 */
960 }
961
962 return hash;
963}
964
965/*
966 * Continue hashing data.
967 */
968uint64_t fr_hash64_update(void const *data, size_t size, uint64_t hash)
969{
970 uint8_t const *p = data;
971 uint8_t const *q;
972
973 if (size == 0) return hash; /* Avoid ubsan issues with access NULL pointer */
974
975 q = p + size;
976 while (p < q) {
977 hash ^= (uint64_t) (*p++);
979 }
980
981 return hash;
982}
983
984/** Check hash table is sane
985 *
986 */
988{
989 fr_hash_iter_t iter;
990 void *ptr;
991
992 (void)talloc_get_type_abort(ht, fr_hash_table_t);
993 (void)talloc_get_type_abort(ht->buckets, fr_hash_entry_t *);
994
995 fr_assert(talloc_array_length(ht->buckets) == ht->num_buckets);
996
997 /*
998 * Check talloc headers on all data
999 */
1000 if (ht->type) {
1001 for (ptr = fr_hash_table_iter_init(ht, &iter);
1002 ptr;
1003 ptr = fr_hash_table_iter_next(ht, &iter)) {
1004 (void)_talloc_get_type_abort(ptr, ht->type, __location__);
1005 }
1006 }
1007}
1008
1009#ifdef TESTING
1010/*
1011 * cc -g -DTESTING -I ../include hash.c -o hash
1012 *
1013 * ./hash
1014 */
1015static uint32_t hash_int(void const *data)
1016{
1017 return fr_hash((int *) data, sizeof(int));
1018}
1019
1020#define MAX 1024*1024
1021int main(int argc, char **argv)
1022{
1023 int i, *p, *q, k;
1024 fr_hash_table_t *ht;
1025 int *array;
1026
1027 ht = fr_hash_table_alloc(NULL, hash_int, NULL, NULL);
1028 if (!ht) {
1029 fprintf(stderr, "Hash create failed\n");
1030 fr_exit(1);
1031 }
1032
1033 array = talloc_zero_array(NULL, int, MAX);
1034 if (!array) fr_exit(1);
1035
1036 for (i = 0; i < MAX; i++) {
1037 p = array + i;
1038 *p = i;
1039
1040 if (!fr_hash_table_insert(ht, p)) {
1041 fprintf(stderr, "Failed insert %08x\n", i);
1042 fr_exit(1);
1043 }
1044#ifdef TEST_INSERT
1045 q = fr_hash_table_find(ht, p);
1046 if (q != p) {
1047 fprintf(stderr, "Bad data %d\n", i);
1048 fr_exit(1);
1049 }
1050#endif
1051 }
1052
1053 fr_hash_table_info(ht);
1054
1055 /*
1056 * Build this to see how lookups result in shortening
1057 * of the hash chains.
1058 */
1059 if (1) {
1060 for (i = 0; i < MAX ; i++) {
1061 q = fr_hash_table_find(ht, &i);
1062 if (!q || *q != i) {
1063 fprintf(stderr, "Failed finding %d\n", i);
1064 fr_exit(1);
1065 }
1066
1067#if 0
1068 if (!fr_hash_table_delete(ht, &i)) {
1069 fprintf(stderr, "Failed deleting %d\n", i);
1070 fr_exit(1);
1071 }
1072 q = fr_hash_table_find(ht, &i);
1073 if (q) {
1074 fprintf(stderr, "Failed to delete %08x\n", i);
1075 fr_exit(1);
1076 }
1077#endif
1078 }
1079
1080 fr_hash_table_info(ht);
1081 }
1082
1083 fr_hash_table_free(ht);
1084 talloc_free(array);
1085
1086 return EXIT_SUCCESS;
1087}
1088#endif
#define load(_var)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:168
#define RCSID(id)
Definition build.h:488
#define CC_NO_UBSAN(_sanitize)
Definition build.h:431
#define unlikely(_x)
Definition build.h:384
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition debug.h:230
int main(int argc, char **argv)
Definition dhcpclient.c:530
void * fr_hash_table_iter_next(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Iterate over entries in a hash table.
Definition hash.c:649
void * fr_hash_table_find(fr_hash_table_t *ht, void const *data)
Find data in a hash table.
Definition hash.c:450
fr_hash_entry_t ** buckets
Array of hash buckets.
Definition hash.c:63
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition hash.c:704
char const * type
Talloc type to check elements against.
Definition hash.c:60
uint32_t next_grow
Definition hash.c:53
uint32_t fr_hash_case_string(char const *p)
Hash a C string, converting all chars to lowercase.
Definition hash.c:916
#define TABLE_MAX
Definition hash.c:387
static int _fr_hash_table_free(fr_hash_table_t *ht)
Definition hash.c:258
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
Definition hash.c:881
static uint8_t parent_byte[256]
Definition hash.c:112
uint32_t fr_hash(void const *data, size_t size)
Definition hash.c:847
uint64_t fr_hash64(void const *data, size_t size)
Definition hash.c:940
bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
Insert data into a hash table.
Definition hash.c:489
void * fr_hash_table_find_by_key(fr_hash_table_t *ht, uint32_t key, void const *data)
Hash table lookup with pre-computed key.
Definition hash.c:469
fr_hash_entry_t null
Definition hash.c:62
#define FNV_MAGIC_PRIME
Definition hash.c:837
fr_hash_t hash
Hashing function.
Definition hash.c:57
static fr_hash_entry_t * hash_table_find(fr_hash_table_t *ht, uint32_t key, void const *data)
Definition hash.c:426
fr_hash_entry_t * next
Definition hash.c:44
static uint32_t parent_of(uint32_t key)
Definition hash.c:169
fr_cmp_t cmp
Comparison function.
Definition hash.c:58
void * data
Definition hash.c:47
static const uint8_t reversed_byte[256]
Definition hash.c:73
uint32_t num_buckets
Number of buckets (how long the array is) - power of 2 *‍/.
Definition hash.c:52
void * fr_hash_table_remove(fr_hash_table_t *ht, void const *data)
Remove an entry from the hash table, without freeing the data.
Definition hash.c:582
int fr_hash_table_flatten(TALLOC_CTX *ctx, void **out[], fr_hash_table_t *ht)
Copy all entries out of a hash table into an array.
Definition hash.c:721
uint32_t mask
Definition hash.c:54
static void list_delete(fr_hash_table_t *ht, fr_hash_entry_t **head, fr_hash_entry_t *node)
Definition hash.c:240
static uint32_t reverse(uint32_t key)
Definition hash.c:151
uint32_t num_elements
Number of elements in the hash table.
Definition hash.c:51
uint32_t reversed
Definition hash.c:45
uint32_t fr_hash_string(char const *p)
Definition hash.c:900
bool fr_hash_table_delete(fr_hash_table_t *ht, void const *data)
Remove and free data (if a free function was specified)
Definition hash.c:617
#define FNV_MAGIC_INIT
Definition hash.c:836
void fr_hash_table_verify(fr_hash_table_t *ht)
Check hash table is sane.
Definition hash.c:987
fr_free_t free
Data free function.
Definition hash.c:56
fr_hash_table_t * _fr_hash_table_alloc(TALLOC_CTX *ctx, char const *type, fr_hash_t hash_func, fr_cmp_t cmp_func, fr_free_t free_func)
Definition hash.c:284
void fr_hash_table_fill(fr_hash_table_t *ht)
Ensure all buckets are filled.
Definition hash.c:745
uint32_t key
Definition hash.c:46
static void fr_hash_table_fixup(fr_hash_table_t *ht, uint32_t entry)
Definition hash.c:336
#define GROW_FACTOR
Definition hash.c:381
uint64_t fr_hash64_update(void const *data, size_t size, uint64_t hash)
Definition hash.c:968
int fr_hash_table_replace(void **old, fr_hash_table_t *ht, void const *data)
Replace old data with new data, OR insert if there is no old.
Definition hash.c:551
uint32_t fr_hash_table_num_elements(fr_hash_table_t *ht)
Definition hash.c:633
#define FR_HASH_NUM_BUCKETS
Definition hash.c:41
static void fr_hash_table_grow(fr_hash_table_t *ht)
Definition hash.c:392
Definition hash.c:43
struct fr_hash_table_s fr_hash_table_t
Definition hash.h:58
fr_hash_entry_t * next
the next node which we will return
Definition hash.h:43
uint32_t(* fr_hash_t)(void const *)
Definition hash.h:36
#define fr_hash_table_alloc(_ctx, _hash_node, _cmp_node, _free_node)
Definition hash.h:61
uint32_t bucket
the current buck that we are examining
Definition hash.h:42
Stores the state of the current iteration operation.
Definition hash.h:41
talloc_free(hp)
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
Definition lst.c:121
unsigned int uint32_t
unsigned char bool
unsigned char uint8_t
int8_t(* fr_cmp_t)(void const *a, void const *b)
Definition misc.h:38
void(* fr_free_t)(void *)
Definition misc.h:39
#define fr_assert(_expr)
Definition rad_assert.h:37
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
fr_aka_sim_id_type_t type
static fr_slen_t head
Definition xlat.h:420
static fr_slen_t data
Definition value.h:1340
static size_t char ** out
Definition value.h:1030