3 Routines for manipulating hash tables... */
6 * Copyright (c) 2014-2015 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1995-2003 by Internet Software Consortium
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Internet Systems Consortium, Inc.
25 * Redwood City, CA 94063
27 * https://www.isc.org/
33 #include <omapip/omapip_p.h>
38 find_length(const void *key
,
39 unsigned (*do_hash
)(const void *, unsigned, unsigned))
41 if (do_hash
== do_case_hash
|| do_hash
== do_string_hash
)
42 return strlen((const char *)key
);
43 if (do_hash
== do_number_hash
)
44 return sizeof(unsigned);
45 if (do_hash
== do_ip4_hash
)
48 log_debug("Unexpected hash function at %s:%d.", MDL
);
50 * If we get a hash function we don't specifically expect
51 * return a length of 0, this covers the case where a client
52 * id has a length of 0.
57 int new_hash_table (tp
, count
, file
, line
)
58 struct hash_table
**tp
;
63 struct hash_table
*rval
;
67 log_error ("%s(%d): new_hash_table called with null pointer.",
69 #if defined (POINTER_DEBUG)
75 log_error ("%s(%d): non-null target for new_hash_table.",
77 #if defined (POINTER_DEBUG)
82 /* There is one hash bucket in the structure. Allocate extra
83 * memory beyond the end of the structure to fulfill the requested
84 * count ("count - 1"). Do not let there be less than one.
91 rval
= dmalloc(sizeof(struct hash_table
) +
92 (extra
* sizeof(struct hash_bucket
*)), file
, line
);
95 rval
-> hash_count
= count
;
100 void free_hash_table (tp
, file
, line
)
101 struct hash_table
**tp
;
105 struct hash_table
*ptr
= *tp
;
107 #if defined (DEBUG_MEMORY_LEAKAGE) || \
108 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
110 struct hash_bucket
*hbc
, *hbn
= (struct hash_bucket
*)0;
112 for (i
= 0; ptr
!= NULL
&& i
< ptr
-> hash_count
; i
++) {
113 for (hbc
= ptr
-> buckets
[i
]; hbc
; hbc
= hbn
) {
115 if (ptr
-> dereferencer
&& hbc
-> value
)
116 (*ptr
-> dereferencer
) (&hbc
-> value
, MDL
);
118 for (hbc
= ptr
-> buckets
[i
]; hbc
; hbc
= hbn
) {
120 free_hash_bucket (hbc
, MDL
);
122 ptr
-> buckets
[i
] = (struct hash_bucket
*)0;
126 dfree((void *)ptr
, MDL
);
127 *tp
= (struct hash_table
*)0;
130 struct hash_bucket
*free_hash_buckets
;
132 #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
133 struct hash_bucket
*hash_bucket_hunks
;
135 void relinquish_hash_bucket_hunks ()
137 struct hash_bucket
*c
, *n
, **p
;
139 /* Account for all the hash buckets on the free list. */
140 p
= &free_hash_buckets
;
141 for (c
= free_hash_buckets
; c
; c
= c
-> next
) {
142 for (n
= hash_bucket_hunks
; n
; n
= n
-> next
) {
143 if (c
> n
&& c
< n
+ 127) {
149 /* If we didn't delete the hash bucket from the free list,
150 advance the pointer. */
155 for (c
= hash_bucket_hunks
; c
; c
= n
) {
157 if (c
-> len
!= 126) {
158 log_info ("hashbucket %lx hash_buckets %d free %u",
159 (unsigned long)c
, 127, c
-> len
);
166 struct hash_bucket
*new_hash_bucket (file
, line
)
170 struct hash_bucket
*rval
;
172 if (!free_hash_buckets
) {
173 rval
= dmalloc (127 * sizeof (struct hash_bucket
),
177 # if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
178 rval
-> next
= hash_bucket_hunks
;
179 hash_bucket_hunks
= rval
;
180 hash_bucket_hunks
-> len
= 0;
184 for (; i
< 127; i
++) {
185 rval
-> next
= free_hash_buckets
;
186 free_hash_buckets
= rval
;
190 rval
= free_hash_buckets
;
191 free_hash_buckets
= rval
-> next
;
195 void free_hash_bucket (ptr
, file
, line
)
196 struct hash_bucket
*ptr
;
200 #if defined (DEBUG_MALLOC_POOL)
201 struct hash_bucket
*hp
;
203 for (hp
= free_hash_buckets
; hp
; hp
= hp
-> next
) {
205 log_error ("hash bucket freed twice!");
210 ptr
-> next
= free_hash_buckets
;
211 free_hash_buckets
= ptr
;
214 int new_hash(struct hash_table
**rp
,
215 hash_reference referencer
,
216 hash_dereference dereferencer
,
218 unsigned (*hasher
)(const void *, unsigned, unsigned),
219 const char *file
, int line
)
222 hsize
= DEFAULT_HASH_SIZE
;
224 if (!new_hash_table (rp
, hsize
, file
, line
))
227 memset ((*rp
)->buckets
, 0, hsize
* sizeof(struct hash_bucket
*));
229 (*rp
)->referencer
= referencer
;
230 (*rp
)->dereferencer
= dereferencer
;
231 (*rp
)->do_hash
= hasher
;
233 if (hasher
== do_case_hash
)
234 (*rp
)->cmp
= casecmp
;
242 do_case_hash(const void *name
, unsigned len
, unsigned size
)
244 register unsigned accum
= 0;
245 register const unsigned char *s
= name
;
250 /* Make the hash case-insensitive. */
255 /* Add the character in... */
256 accum
= (accum
<< 1) + c
;
258 /* Add carry back in... */
259 while (accum
> 65535) {
260 accum
= (accum
& 65535) + (accum
>> 16);
268 do_string_hash(const void *name
, unsigned len
, unsigned size
)
270 register unsigned accum
= 0;
271 register const unsigned char *s
= (const unsigned char *)name
;
275 /* Add the character in... */
276 accum
= (accum
<< 1) + *s
++;
278 /* Add carry back in... */
279 while (accum
> 65535) {
280 accum
= (accum
& 65535) + (accum
>> 16);
286 /* Client identifiers are generally 32-bits of ordinary
287 * non-randomness followed by 24-bits of unordinary randomness.
288 * So, end-align in 24-bit chunks, and xor any preceding data
289 * just to mix it up a little.
292 do_id_hash(const void *name
, unsigned len
, unsigned size
)
294 register unsigned accum
= 0;
295 register const unsigned char *s
= (const unsigned char *)name
;
296 const unsigned char *end
= s
+ len
;
302 * The switch handles our starting conditions, then we hash the
303 * remaining bytes in groups of 3
326 do_number_hash(const void *key
, unsigned len
, unsigned size
)
328 register unsigned number
= *((const unsigned *)key
);
330 return number
% size
;
334 do_ip4_hash(const void *key
, unsigned len
, unsigned size
)
338 memcpy(&number
, key
, 4);
340 number
= ntohl(number
);
342 return number
% size
;
346 hash_report(struct hash_table
*table
)
348 static unsigned char retbuf
[sizeof("Contents/Size (%): "
349 "2147483647/2147483647 "
351 "Min/max: 2147483647/2147483647")];
352 unsigned curlen
, pct
, contents
=0, minlen
=UINT_MAX
, maxlen
=0;
354 struct hash_bucket
*bp
;
357 return (unsigned char *) "No table.";
359 if (table
->hash_count
== 0)
360 return (unsigned char *) "Invalid hash table.";
362 for (i
= 0 ; i
< table
->hash_count
; i
++) {
365 bp
= table
->buckets
[i
];
379 if (contents
>= (UINT_MAX
/ 100))
380 pct
= contents
/ ((table
->hash_count
/ 100) + 1);
382 pct
= (contents
* 100) / table
->hash_count
;
384 if (contents
> 2147483647 ||
385 table
->hash_count
> 2147483647 ||
387 minlen
> 2147483647 ||
389 return (unsigned char *) "Report out of range for display.";
391 sprintf((char *)retbuf
,
392 "Contents/Size (%%): %u/%u (%u%%). Min/max: %u/%u",
393 contents
, table
->hash_count
, pct
, minlen
, maxlen
);
398 void add_hash (table
, key
, len
, pointer
, file
, line
)
399 struct hash_table
*table
;
402 hashed_object_t
*pointer
;
407 struct hash_bucket
*bp
;
414 len
= find_length(key
, table
->do_hash
);
416 hashno
= (*table
->do_hash
)(key
, len
, table
->hash_count
);
417 bp
= new_hash_bucket (file
, line
);
420 log_error ("Can't add entry to hash table: no memory.");
424 if (table
-> referencer
) {
426 (*(table
-> referencer
)) (foo
, pointer
, file
, line
);
428 bp
-> value
= pointer
;
429 bp
-> next
= table
-> buckets
[hashno
];
431 table
-> buckets
[hashno
] = bp
;
434 void delete_hash_entry (table
, key
, len
, file
, line
)
435 struct hash_table
*table
;
442 struct hash_bucket
*bp
, *pbp
= (struct hash_bucket
*)0;
449 len
= find_length(key
, table
->do_hash
);
451 hashno
= (*table
->do_hash
)(key
, len
, table
->hash_count
);
453 /* Go through the list looking for an entry that matches;
454 if we find it, delete it. */
455 for (bp
= table
-> buckets
[hashno
]; bp
; bp
= bp
-> next
) {
457 !strcmp ((const char *)bp
->name
, key
)) ||
459 !(table
-> cmp
)(bp
->name
, key
, len
))) {
461 pbp
-> next
= bp
-> next
;
463 table
-> buckets
[hashno
] = bp
-> next
;
465 if (bp
-> value
&& table
-> dereferencer
) {
467 (*(table
-> dereferencer
)) (foo
, file
, line
);
469 free_hash_bucket (bp
, file
, line
);
472 pbp
= bp
; /* jwg, 9/6/96 - nice catch! */
476 int hash_lookup (vp
, table
, key
, len
, file
, line
)
477 hashed_object_t
**vp
;
478 struct hash_table
*table
;
485 struct hash_bucket
*bp
;
490 len
= find_length(key
, table
->do_hash
);
493 log_fatal("Internal inconsistency: storage value has not been "
494 "initialized to zero (from %s:%d).", file
, line
);
497 hashno
= (*table
->do_hash
)(key
, len
, table
->hash_count
);
499 for (bp
= table
-> buckets
[hashno
]; bp
; bp
= bp
-> next
) {
501 && !(*table
->cmp
)(bp
->name
, key
, len
)) {
502 if (table
-> referencer
)
503 (*table
-> referencer
) (vp
, bp
-> value
,
513 int hash_foreach (struct hash_table
*table
, hash_foreach_func func
)
516 struct hash_bucket
*bp
, *next
;
522 for (i
= 0; i
< table
-> hash_count
; i
++) {
523 bp
= table
-> buckets
[i
];
526 if ((*func
)(bp
->name
, bp
->len
, bp
->value
)
536 int casecmp (const void *v1
, const void *v2
, size_t len
)
539 const unsigned char *s
= v1
;
540 const unsigned char *t
= v2
;
542 for (i
= 0; i
< len
; i
++)