Home | History | Annotate | Line # | Download | only in isc
      1  1.1  christos /*	$NetBSD: ht.c,v 1.1 2024/02/18 20:57:49 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  1.1  christos  *
      6  1.1  christos  * SPDX-License-Identifier: MPL-2.0
      7  1.1  christos  *
      8  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  1.1  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  1.1  christos  *
     12  1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13  1.1  christos  * information regarding copyright ownership.
     14  1.1  christos  */
     15  1.1  christos 
     16  1.1  christos #include <inttypes.h>
     17  1.1  christos #include <string.h>
     18  1.1  christos 
     19  1.1  christos #include <isc/hash.h>
     20  1.1  christos #include <isc/ht.h>
     21  1.1  christos #include <isc/magic.h>
     22  1.1  christos #include <isc/mem.h>
     23  1.1  christos #include <isc/result.h>
     24  1.1  christos #include <isc/types.h>
     25  1.1  christos #include <isc/util.h>
     26  1.1  christos 
     27  1.1  christos typedef struct isc_ht_node isc_ht_node_t;
     28  1.1  christos 
     29  1.1  christos #define ISC_HT_MAGIC	 ISC_MAGIC('H', 'T', 'a', 'b')
     30  1.1  christos #define ISC_HT_VALID(ht) ISC_MAGIC_VALID(ht, ISC_HT_MAGIC)
     31  1.1  christos 
     32  1.1  christos #define HT_NO_BITS    0
     33  1.1  christos #define HT_MIN_BITS   1
     34  1.1  christos #define HT_MAX_BITS   32
     35  1.1  christos #define HT_OVERCOMMIT 3
     36  1.1  christos 
     37  1.1  christos #define HT_NEXTTABLE(idx)      ((idx == 0) ? 1 : 0)
     38  1.1  christos #define TRY_NEXTTABLE(idx, ht) (idx == ht->hindex && rehashing_in_progress(ht))
     39  1.1  christos 
     40  1.1  christos #define GOLDEN_RATIO_32 0x61C88647
     41  1.1  christos 
     42  1.1  christos #define HASHSIZE(bits) (UINT64_C(1) << (bits))
     43  1.1  christos 
     44  1.1  christos struct isc_ht_node {
     45  1.1  christos 	void *value;
     46  1.1  christos 	isc_ht_node_t *next;
     47  1.1  christos 	uint32_t hashval;
     48  1.1  christos 	size_t keysize;
     49  1.1  christos 	unsigned char key[];
     50  1.1  christos };
     51  1.1  christos 
     52  1.1  christos struct isc_ht {
     53  1.1  christos 	unsigned int magic;
     54  1.1  christos 	isc_mem_t *mctx;
     55  1.1  christos 	size_t count;
     56  1.1  christos 	bool case_sensitive;
     57  1.1  christos 	size_t size[2];
     58  1.1  christos 	uint8_t hashbits[2];
     59  1.1  christos 	isc_ht_node_t **table[2];
     60  1.1  christos 	uint8_t hindex;
     61  1.1  christos 	uint32_t hiter; /* rehashing iterator */
     62  1.1  christos };
     63  1.1  christos 
     64  1.1  christos struct isc_ht_iter {
     65  1.1  christos 	isc_ht_t *ht;
     66  1.1  christos 	size_t i;
     67  1.1  christos 	uint8_t hindex;
     68  1.1  christos 	isc_ht_node_t *cur;
     69  1.1  christos };
     70  1.1  christos 
     71  1.1  christos static isc_ht_node_t *
     72  1.1  christos isc__ht_find(const isc_ht_t *ht, const unsigned char *key,
     73  1.1  christos 	     const uint32_t keysize, const uint32_t hashval, const uint8_t idx);
     74  1.1  christos static void
     75  1.1  christos isc__ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize,
     76  1.1  christos 	    const uint32_t hashval, const uint8_t idx, void *value);
     77  1.1  christos static isc_result_t
     78  1.1  christos isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize,
     79  1.1  christos 	       const uint32_t hashval, const uint8_t idx);
     80  1.1  christos 
     81  1.1  christos static uint32_t
     82  1.1  christos rehash_bits(isc_ht_t *ht, size_t newcount);
     83  1.1  christos 
     84  1.1  christos static void
     85  1.1  christos hashtable_new(isc_ht_t *ht, const uint8_t idx, const uint8_t bits);
     86  1.1  christos static void
     87  1.1  christos hashtable_free(isc_ht_t *ht, const uint8_t idx);
     88  1.1  christos static void
     89  1.1  christos hashtable_rehash(isc_ht_t *ht, uint32_t newbits);
     90  1.1  christos static void
     91  1.1  christos hashtable_rehash_one(isc_ht_t *ht);
     92  1.1  christos static void
     93  1.1  christos maybe_rehash(isc_ht_t *ht, size_t newcount);
     94  1.1  christos 
     95  1.1  christos static isc_result_t
     96  1.1  christos isc__ht_iter_next(isc_ht_iter_t *it);
     97  1.1  christos 
     98  1.1  christos static uint8_t maptolower[] = {
     99  1.1  christos 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
    100  1.1  christos 	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    101  1.1  christos 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
    102  1.1  christos 	0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
    103  1.1  christos 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
    104  1.1  christos 	0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
    105  1.1  christos 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
    106  1.1  christos 	0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
    107  1.1  christos 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
    108  1.1  christos 	0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
    109  1.1  christos 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
    110  1.1  christos 	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    111  1.1  christos 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
    112  1.1  christos 	0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    113  1.1  christos 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
    114  1.1  christos 	0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
    115  1.1  christos 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
    116  1.1  christos 	0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
    117  1.1  christos 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
    118  1.1  christos 	0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
    119  1.1  christos 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
    120  1.1  christos 	0xfc, 0xfd, 0xfe, 0xff
    121  1.1  christos };
    122  1.1  christos 
    123  1.1  christos static int
    124  1.1  christos memcasecmp(const void *vs1, const void *vs2, size_t len) {
    125  1.1  christos 	uint8_t const *s1 = vs1;
    126  1.1  christos 	uint8_t const *s2 = vs2;
    127  1.1  christos 	for (size_t i = 0; i < len; i++) {
    128  1.1  christos 		uint8_t u1 = s1[i];
    129  1.1  christos 		uint8_t u2 = s2[i];
    130  1.1  christos 		int U1 = maptolower[u1];
    131  1.1  christos 		int U2 = maptolower[u2];
    132  1.1  christos 		int diff = U1 - U2;
    133  1.1  christos 		if (diff) {
    134  1.1  christos 			return diff;
    135  1.1  christos 		}
    136  1.1  christos 	}
    137  1.1  christos 	return 0;
    138  1.1  christos }
    139  1.1  christos 
    140  1.1  christos static bool
    141  1.1  christos isc__ht_node_match(isc_ht_node_t *node, const uint32_t hashval,
    142  1.1  christos 		   const uint8_t *key, uint32_t keysize, bool case_sensitive) {
    143  1.1  christos 	return (node->hashval == hashval && node->keysize == keysize &&
    144  1.1  christos 		(case_sensitive ? (memcmp(node->key, key, keysize) == 0)
    145  1.1  christos 				: (memcasecmp(node->key, key, keysize) == 0)));
    146  1.1  christos }
    147  1.1  christos 
    148  1.1  christos static uint32_t
    149  1.1  christos hash_32(uint32_t val, unsigned int bits) {
    150  1.1  christos 	REQUIRE(bits <= HT_MAX_BITS);
    151  1.1  christos 	/* High bits are more random. */
    152  1.1  christos 	return (val * GOLDEN_RATIO_32 >> (32 - bits));
    153  1.1  christos }
    154  1.1  christos 
    155  1.1  christos static bool
    156  1.1  christos rehashing_in_progress(const isc_ht_t *ht) {
    157  1.1  christos 	return (ht->table[HT_NEXTTABLE(ht->hindex)] != NULL);
    158  1.1  christos }
    159  1.1  christos 
    160  1.1  christos static bool
    161  1.1  christos hashtable_is_overcommited(isc_ht_t *ht) {
    162  1.1  christos 	return (ht->count >= (ht->size[ht->hindex] * HT_OVERCOMMIT));
    163  1.1  christos }
    164  1.1  christos 
    165  1.1  christos static uint32_t
    166  1.1  christos rehash_bits(isc_ht_t *ht, size_t newcount) {
    167  1.1  christos 	uint32_t newbits = ht->hashbits[ht->hindex];
    168  1.1  christos 
    169  1.1  christos 	while (newcount >= HASHSIZE(newbits) && newbits <= HT_MAX_BITS) {
    170  1.1  christos 		newbits += 1;
    171  1.1  christos 	}
    172  1.1  christos 
    173  1.1  christos 	return (newbits);
    174  1.1  christos }
    175  1.1  christos 
    176  1.1  christos /*
    177  1.1  christos  * Rebuild the hashtable to reduce the load factor
    178  1.1  christos  */
    179  1.1  christos static void
    180  1.1  christos hashtable_rehash(isc_ht_t *ht, uint32_t newbits) {
    181  1.1  christos 	uint8_t oldindex = ht->hindex;
    182  1.1  christos 	uint32_t oldbits = ht->hashbits[oldindex];
    183  1.1  christos 	uint8_t newindex = HT_NEXTTABLE(oldindex);
    184  1.1  christos 
    185  1.1  christos 	REQUIRE(ht->hashbits[oldindex] >= HT_MIN_BITS);
    186  1.1  christos 	REQUIRE(ht->hashbits[oldindex] <= HT_MAX_BITS);
    187  1.1  christos 	REQUIRE(ht->table[oldindex] != NULL);
    188  1.1  christos 
    189  1.1  christos 	REQUIRE(newbits <= HT_MAX_BITS);
    190  1.1  christos 	REQUIRE(ht->hashbits[newindex] == HT_NO_BITS);
    191  1.1  christos 	REQUIRE(ht->table[newindex] == NULL);
    192  1.1  christos 
    193  1.1  christos 	REQUIRE(newbits > oldbits);
    194  1.1  christos 
    195  1.1  christos 	hashtable_new(ht, newindex, newbits);
    196  1.1  christos 
    197  1.1  christos 	ht->hindex = newindex;
    198  1.1  christos 
    199  1.1  christos 	hashtable_rehash_one(ht);
    200  1.1  christos }
    201  1.1  christos 
    202  1.1  christos static void
    203  1.1  christos hashtable_rehash_one(isc_ht_t *ht) {
    204  1.1  christos 	isc_ht_node_t **newtable = ht->table[ht->hindex];
    205  1.1  christos 	uint32_t oldsize = ht->size[HT_NEXTTABLE(ht->hindex)];
    206  1.1  christos 	isc_ht_node_t **oldtable = ht->table[HT_NEXTTABLE(ht->hindex)];
    207  1.1  christos 	isc_ht_node_t *node = NULL;
    208  1.1  christos 	isc_ht_node_t *nextnode;
    209  1.1  christos 
    210  1.1  christos 	/* Find first non-empty node */
    211  1.1  christos 	while (ht->hiter < oldsize && oldtable[ht->hiter] == NULL) {
    212  1.1  christos 		ht->hiter++;
    213  1.1  christos 	}
    214  1.1  christos 
    215  1.1  christos 	/* Rehashing complete */
    216  1.1  christos 	if (ht->hiter == oldsize) {
    217  1.1  christos 		hashtable_free(ht, HT_NEXTTABLE(ht->hindex));
    218  1.1  christos 		ht->hiter = 0;
    219  1.1  christos 		return;
    220  1.1  christos 	}
    221  1.1  christos 
    222  1.1  christos 	/* Move the first non-empty node from old hashtable to new hashtable */
    223  1.1  christos 	for (node = oldtable[ht->hiter]; node != NULL; node = nextnode) {
    224  1.1  christos 		uint32_t hash = hash_32(node->hashval,
    225  1.1  christos 					ht->hashbits[ht->hindex]);
    226  1.1  christos 		nextnode = node->next;
    227  1.1  christos 		node->next = newtable[hash];
    228  1.1  christos 		newtable[hash] = node;
    229  1.1  christos 	}
    230  1.1  christos 
    231  1.1  christos 	oldtable[ht->hiter] = NULL;
    232  1.1  christos 
    233  1.1  christos 	ht->hiter++;
    234  1.1  christos }
    235  1.1  christos 
    236  1.1  christos static void
    237  1.1  christos maybe_rehash(isc_ht_t *ht, size_t newcount) {
    238  1.1  christos 	uint32_t newbits = rehash_bits(ht, newcount);
    239  1.1  christos 
    240  1.1  christos 	if (ht->hashbits[ht->hindex] < newbits && newbits <= HT_MAX_BITS) {
    241  1.1  christos 		hashtable_rehash(ht, newbits);
    242  1.1  christos 	}
    243  1.1  christos }
    244  1.1  christos 
    245  1.1  christos static void
    246  1.1  christos hashtable_new(isc_ht_t *ht, const uint8_t idx, const uint8_t bits) {
    247  1.1  christos 	size_t size;
    248  1.1  christos 	REQUIRE(ht->hashbits[idx] == HT_NO_BITS);
    249  1.1  christos 	REQUIRE(ht->table[idx] == NULL);
    250  1.1  christos 	REQUIRE(bits >= HT_MIN_BITS);
    251  1.1  christos 	REQUIRE(bits <= HT_MAX_BITS);
    252  1.1  christos 
    253  1.1  christos 	ht->hashbits[idx] = bits;
    254  1.1  christos 	ht->size[idx] = HASHSIZE(ht->hashbits[idx]);
    255  1.1  christos 
    256  1.1  christos 	size = ht->size[idx] * sizeof(isc_ht_node_t *);
    257  1.1  christos 
    258  1.1  christos 	ht->table[idx] = isc_mem_get(ht->mctx, size);
    259  1.1  christos 	memset(ht->table[idx], 0, size);
    260  1.1  christos }
    261  1.1  christos 
    262  1.1  christos static void
    263  1.1  christos hashtable_free(isc_ht_t *ht, const uint8_t idx) {
    264  1.1  christos 	size_t size = ht->size[idx] * sizeof(isc_ht_node_t *);
    265  1.1  christos 
    266  1.1  christos 	for (size_t i = 0; i < ht->size[idx]; i++) {
    267  1.1  christos 		isc_ht_node_t *node = ht->table[idx][i];
    268  1.1  christos 		while (node != NULL) {
    269  1.1  christos 			isc_ht_node_t *next = node->next;
    270  1.1  christos 			ht->count--;
    271  1.1  christos 			isc_mem_put(ht->mctx, node,
    272  1.1  christos 				    sizeof(*node) + node->keysize);
    273  1.1  christos 			node = next;
    274  1.1  christos 		}
    275  1.1  christos 	}
    276  1.1  christos 
    277  1.1  christos 	isc_mem_put(ht->mctx, ht->table[idx], size);
    278  1.1  christos 	ht->hashbits[idx] = HT_NO_BITS;
    279  1.1  christos 	ht->table[idx] = NULL;
    280  1.1  christos }
    281  1.1  christos 
    282  1.1  christos void
    283  1.1  christos isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits,
    284  1.1  christos 	    unsigned int options) {
    285  1.1  christos 	isc_ht_t *ht = NULL;
    286  1.1  christos 	bool case_sensitive = ((options & ISC_HT_CASE_INSENSITIVE) == 0);
    287  1.1  christos 
    288  1.1  christos 	REQUIRE(htp != NULL && *htp == NULL);
    289  1.1  christos 	REQUIRE(mctx != NULL);
    290  1.1  christos 	REQUIRE(bits >= 1 && bits <= HT_MAX_BITS);
    291  1.1  christos 
    292  1.1  christos 	ht = isc_mem_get(mctx, sizeof(*ht));
    293  1.1  christos 	*ht = (isc_ht_t){
    294  1.1  christos 		.case_sensitive = case_sensitive,
    295  1.1  christos 	};
    296  1.1  christos 
    297  1.1  christos 	isc_mem_attach(mctx, &ht->mctx);
    298  1.1  christos 
    299  1.1  christos 	hashtable_new(ht, 0, bits);
    300  1.1  christos 
    301  1.1  christos 	ht->magic = ISC_HT_MAGIC;
    302  1.1  christos 
    303  1.1  christos 	*htp = ht;
    304  1.1  christos }
    305  1.1  christos 
    306  1.1  christos void
    307  1.1  christos isc_ht_destroy(isc_ht_t **htp) {
    308  1.1  christos 	isc_ht_t *ht;
    309  1.1  christos 
    310  1.1  christos 	REQUIRE(htp != NULL);
    311  1.1  christos 	REQUIRE(ISC_HT_VALID(*htp));
    312  1.1  christos 
    313  1.1  christos 	ht = *htp;
    314  1.1  christos 	*htp = NULL;
    315  1.1  christos 	ht->magic = 0;
    316  1.1  christos 
    317  1.1  christos 	for (size_t i = 0; i <= 1; i++) {
    318  1.1  christos 		if (ht->table[i] != NULL) {
    319  1.1  christos 			hashtable_free(ht, i);
    320  1.1  christos 		}
    321  1.1  christos 	}
    322  1.1  christos 
    323  1.1  christos 	INSIST(ht->count == 0);
    324  1.1  christos 
    325  1.1  christos 	isc_mem_putanddetach(&ht->mctx, ht, sizeof(*ht));
    326  1.1  christos }
    327  1.1  christos 
    328  1.1  christos static void
    329  1.1  christos isc__ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize,
    330  1.1  christos 	    const uint32_t hashval, const uint8_t idx, void *value) {
    331  1.1  christos 	isc_ht_node_t *node;
    332  1.1  christos 	uint32_t hash;
    333  1.1  christos 
    334  1.1  christos 	hash = hash_32(hashval, ht->hashbits[idx]);
    335  1.1  christos 
    336  1.1  christos 	node = isc_mem_get(ht->mctx, sizeof(*node) + keysize);
    337  1.1  christos 	*node = (isc_ht_node_t){
    338  1.1  christos 		.keysize = keysize,
    339  1.1  christos 		.hashval = hashval,
    340  1.1  christos 		.next = ht->table[idx][hash],
    341  1.1  christos 		.value = value,
    342  1.1  christos 	};
    343  1.1  christos 
    344  1.1  christos 	memmove(node->key, key, keysize);
    345  1.1  christos 
    346  1.1  christos 	ht->count++;
    347  1.1  christos 	ht->table[idx][hash] = node;
    348  1.1  christos }
    349  1.1  christos 
    350  1.1  christos isc_result_t
    351  1.1  christos isc_ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize,
    352  1.1  christos 	   void *value) {
    353  1.1  christos 	uint32_t hashval;
    354  1.1  christos 
    355  1.1  christos 	REQUIRE(ISC_HT_VALID(ht));
    356  1.1  christos 	REQUIRE(key != NULL && keysize > 0);
    357  1.1  christos 
    358  1.1  christos 	if (rehashing_in_progress(ht)) {
    359  1.1  christos 		/* Rehash in progress */
    360  1.1  christos 		hashtable_rehash_one(ht);
    361  1.1  christos 	} else if (hashtable_is_overcommited(ht)) {
    362  1.1  christos 		/* Rehash requested */
    363  1.1  christos 		maybe_rehash(ht, ht->count);
    364  1.1  christos 	}
    365  1.1  christos 
    366  1.1  christos 	hashval = isc_hash32(key, keysize, ht->case_sensitive);
    367  1.1  christos 
    368  1.1  christos 	if (isc__ht_find(ht, key, keysize, hashval, ht->hindex) != NULL) {
    369  1.1  christos 		return (ISC_R_EXISTS);
    370  1.1  christos 	}
    371  1.1  christos 
    372  1.1  christos 	isc__ht_add(ht, key, keysize, hashval, ht->hindex, value);
    373  1.1  christos 
    374  1.1  christos 	return (ISC_R_SUCCESS);
    375  1.1  christos }
    376  1.1  christos 
    377  1.1  christos static isc_ht_node_t *
    378  1.1  christos isc__ht_find(const isc_ht_t *ht, const unsigned char *key,
    379  1.1  christos 	     const uint32_t keysize, const uint32_t hashval,
    380  1.1  christos 	     const uint8_t idx) {
    381  1.1  christos 	uint32_t hash;
    382  1.1  christos 	uint8_t findex = idx;
    383  1.1  christos 
    384  1.1  christos nexttable:
    385  1.1  christos 	hash = hash_32(hashval, ht->hashbits[findex]);
    386  1.1  christos 	for (isc_ht_node_t *node = ht->table[findex][hash]; node != NULL;
    387  1.1  christos 	     node = node->next)
    388  1.1  christos 	{
    389  1.1  christos 		if (isc__ht_node_match(node, hashval, key, keysize,
    390  1.1  christos 				       ht->case_sensitive))
    391  1.1  christos 		{
    392  1.1  christos 			return (node);
    393  1.1  christos 		}
    394  1.1  christos 	}
    395  1.1  christos 	if (TRY_NEXTTABLE(findex, ht)) {
    396  1.1  christos 		/*
    397  1.1  christos 		 * Rehashing in progress, check the other table
    398  1.1  christos 		 */
    399  1.1  christos 		findex = HT_NEXTTABLE(findex);
    400  1.1  christos 		goto nexttable;
    401  1.1  christos 	}
    402  1.1  christos 
    403  1.1  christos 	return (NULL);
    404  1.1  christos }
    405  1.1  christos 
    406  1.1  christos isc_result_t
    407  1.1  christos isc_ht_find(const isc_ht_t *ht, const unsigned char *key,
    408  1.1  christos 	    const uint32_t keysize, void **valuep) {
    409  1.1  christos 	uint32_t hashval;
    410  1.1  christos 	isc_ht_node_t *node;
    411  1.1  christos 
    412  1.1  christos 	REQUIRE(ISC_HT_VALID(ht));
    413  1.1  christos 	REQUIRE(key != NULL && keysize > 0);
    414  1.1  christos 	REQUIRE(valuep == NULL || *valuep == NULL);
    415  1.1  christos 
    416  1.1  christos 	hashval = isc_hash32(key, keysize, ht->case_sensitive);
    417  1.1  christos 
    418  1.1  christos 	node = isc__ht_find(ht, key, keysize, hashval, ht->hindex);
    419  1.1  christos 	if (node == NULL) {
    420  1.1  christos 		return (ISC_R_NOTFOUND);
    421  1.1  christos 	}
    422  1.1  christos 
    423  1.1  christos 	if (valuep != NULL) {
    424  1.1  christos 		*valuep = node->value;
    425  1.1  christos 	}
    426  1.1  christos 	return (ISC_R_SUCCESS);
    427  1.1  christos }
    428  1.1  christos 
    429  1.1  christos static isc_result_t
    430  1.1  christos isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize,
    431  1.1  christos 	       const uint32_t hashval, const uint8_t idx) {
    432  1.1  christos 	isc_ht_node_t *prev = NULL;
    433  1.1  christos 	uint32_t hash;
    434  1.1  christos 
    435  1.1  christos 	hash = hash_32(hashval, ht->hashbits[idx]);
    436  1.1  christos 
    437  1.1  christos 	for (isc_ht_node_t *node = ht->table[idx][hash]; node != NULL;
    438  1.1  christos 	     prev = node, node = node->next)
    439  1.1  christos 	{
    440  1.1  christos 		if (isc__ht_node_match(node, hashval, key, keysize,
    441  1.1  christos 				       ht->case_sensitive))
    442  1.1  christos 		{
    443  1.1  christos 			if (prev == NULL) {
    444  1.1  christos 				ht->table[idx][hash] = node->next;
    445  1.1  christos 			} else {
    446  1.1  christos 				prev->next = node->next;
    447  1.1  christos 			}
    448  1.1  christos 			isc_mem_put(ht->mctx, node,
    449  1.1  christos 				    sizeof(*node) + node->keysize);
    450  1.1  christos 			ht->count--;
    451  1.1  christos 
    452  1.1  christos 			return (ISC_R_SUCCESS);
    453  1.1  christos 		}
    454  1.1  christos 	}
    455  1.1  christos 
    456  1.1  christos 	return (ISC_R_NOTFOUND);
    457  1.1  christos }
    458  1.1  christos 
    459  1.1  christos isc_result_t
    460  1.1  christos isc_ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize) {
    461  1.1  christos 	uint32_t hashval;
    462  1.1  christos 	uint8_t hindex;
    463  1.1  christos 	isc_result_t result;
    464  1.1  christos 
    465  1.1  christos 	REQUIRE(ISC_HT_VALID(ht));
    466  1.1  christos 	REQUIRE(key != NULL && keysize > 0);
    467  1.1  christos 
    468  1.1  christos 	if (rehashing_in_progress(ht)) {
    469  1.1  christos 		/* Rehash in progress */
    470  1.1  christos 		hashtable_rehash_one(ht);
    471  1.1  christos 	}
    472  1.1  christos 
    473  1.1  christos 	hindex = ht->hindex;
    474  1.1  christos 	hashval = isc_hash32(key, keysize, ht->case_sensitive);
    475  1.1  christos nexttable:
    476  1.1  christos 	result = isc__ht_delete(ht, key, keysize, hashval, hindex);
    477  1.1  christos 
    478  1.1  christos 	if (result == ISC_R_NOTFOUND && TRY_NEXTTABLE(hindex, ht)) {
    479  1.1  christos 		/*
    480  1.1  christos 		 * Rehashing in progress, check the other table
    481  1.1  christos 		 */
    482  1.1  christos 		hindex = HT_NEXTTABLE(hindex);
    483  1.1  christos 		goto nexttable;
    484  1.1  christos 	}
    485  1.1  christos 
    486  1.1  christos 	return (result);
    487  1.1  christos }
    488  1.1  christos 
    489  1.1  christos void
    490  1.1  christos isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) {
    491  1.1  christos 	isc_ht_iter_t *it;
    492  1.1  christos 
    493  1.1  christos 	REQUIRE(ISC_HT_VALID(ht));
    494  1.1  christos 	REQUIRE(itp != NULL && *itp == NULL);
    495  1.1  christos 
    496  1.1  christos 	it = isc_mem_get(ht->mctx, sizeof(isc_ht_iter_t));
    497  1.1  christos 	*it = (isc_ht_iter_t){
    498  1.1  christos 		.ht = ht,
    499  1.1  christos 		.hindex = ht->hindex,
    500  1.1  christos 	};
    501  1.1  christos 
    502  1.1  christos 	*itp = it;
    503  1.1  christos }
    504  1.1  christos 
    505  1.1  christos void
    506  1.1  christos isc_ht_iter_destroy(isc_ht_iter_t **itp) {
    507  1.1  christos 	isc_ht_iter_t *it;
    508  1.1  christos 	isc_ht_t *ht;
    509  1.1  christos 
    510  1.1  christos 	REQUIRE(itp != NULL && *itp != NULL);
    511  1.1  christos 
    512  1.1  christos 	it = *itp;
    513  1.1  christos 	*itp = NULL;
    514  1.1  christos 	ht = it->ht;
    515  1.1  christos 	isc_mem_put(ht->mctx, it, sizeof(*it));
    516  1.1  christos }
    517  1.1  christos 
    518  1.1  christos isc_result_t
    519  1.1  christos isc_ht_iter_first(isc_ht_iter_t *it) {
    520  1.1  christos 	isc_ht_t *ht;
    521  1.1  christos 
    522  1.1  christos 	REQUIRE(it != NULL);
    523  1.1  christos 
    524  1.1  christos 	ht = it->ht;
    525  1.1  christos 
    526  1.1  christos 	it->hindex = ht->hindex;
    527  1.1  christos 	it->i = 0;
    528  1.1  christos 
    529  1.1  christos 	return (isc__ht_iter_next(it));
    530  1.1  christos }
    531  1.1  christos 
    532  1.1  christos static isc_result_t
    533  1.1  christos isc__ht_iter_next(isc_ht_iter_t *it) {
    534  1.1  christos 	isc_ht_t *ht = it->ht;
    535  1.1  christos 
    536  1.1  christos 	while (it->i < ht->size[it->hindex] &&
    537  1.1  christos 	       ht->table[it->hindex][it->i] == NULL)
    538  1.1  christos 	{
    539  1.1  christos 		it->i++;
    540  1.1  christos 	}
    541  1.1  christos 
    542  1.1  christos 	if (it->i < ht->size[it->hindex]) {
    543  1.1  christos 		it->cur = ht->table[it->hindex][it->i];
    544  1.1  christos 
    545  1.1  christos 		return (ISC_R_SUCCESS);
    546  1.1  christos 	}
    547  1.1  christos 
    548  1.1  christos 	if (TRY_NEXTTABLE(it->hindex, ht)) {
    549  1.1  christos 		it->hindex = HT_NEXTTABLE(it->hindex);
    550  1.1  christos 		it->i = 0;
    551  1.1  christos 		return (isc__ht_iter_next(it));
    552  1.1  christos 	}
    553  1.1  christos 
    554  1.1  christos 	return (ISC_R_NOMORE);
    555  1.1  christos }
    556  1.1  christos 
    557  1.1  christos isc_result_t
    558  1.1  christos isc_ht_iter_next(isc_ht_iter_t *it) {
    559  1.1  christos 	REQUIRE(it != NULL);
    560  1.1  christos 	REQUIRE(it->cur != NULL);
    561  1.1  christos 
    562  1.1  christos 	it->cur = it->cur->next;
    563  1.1  christos 
    564  1.1  christos 	if (it->cur != NULL) {
    565  1.1  christos 		return (ISC_R_SUCCESS);
    566  1.1  christos 	}
    567  1.1  christos 
    568  1.1  christos 	it->i++;
    569  1.1  christos 
    570  1.1  christos 	return (isc__ht_iter_next(it));
    571  1.1  christos }
    572  1.1  christos 
    573  1.1  christos isc_result_t
    574  1.1  christos isc_ht_iter_delcurrent_next(isc_ht_iter_t *it) {
    575  1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
    576  1.1  christos 	isc_ht_node_t *dnode = NULL;
    577  1.1  christos 	uint8_t dindex;
    578  1.1  christos 	isc_ht_t *ht;
    579  1.1  christos 	isc_result_t dresult;
    580  1.1  christos 
    581  1.1  christos 	REQUIRE(it != NULL);
    582  1.1  christos 	REQUIRE(it->cur != NULL);
    583  1.1  christos 
    584  1.1  christos 	ht = it->ht;
    585  1.1  christos 	dnode = it->cur;
    586  1.1  christos 	dindex = it->hindex;
    587  1.1  christos 
    588  1.1  christos 	result = isc_ht_iter_next(it);
    589  1.1  christos 
    590  1.1  christos 	dresult = isc__ht_delete(ht, dnode->key, dnode->keysize, dnode->hashval,
    591  1.1  christos 				 dindex);
    592  1.1  christos 	INSIST(dresult == ISC_R_SUCCESS);
    593  1.1  christos 
    594  1.1  christos 	return (result);
    595  1.1  christos }
    596  1.1  christos 
    597  1.1  christos void
    598  1.1  christos isc_ht_iter_current(isc_ht_iter_t *it, void **valuep) {
    599  1.1  christos 	REQUIRE(it != NULL);
    600  1.1  christos 	REQUIRE(it->cur != NULL);
    601  1.1  christos 	REQUIRE(valuep != NULL && *valuep == NULL);
    602  1.1  christos 
    603  1.1  christos 	*valuep = it->cur->value;
    604  1.1  christos }
    605  1.1  christos 
    606  1.1  christos void
    607  1.1  christos isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key,
    608  1.1  christos 		       size_t *keysize) {
    609  1.1  christos 	REQUIRE(it != NULL);
    610  1.1  christos 	REQUIRE(it->cur != NULL);
    611  1.1  christos 	REQUIRE(key != NULL && *key == NULL);
    612  1.1  christos 
    613  1.1  christos 	*key = it->cur->key;
    614  1.1  christos 	*keysize = it->cur->keysize;
    615  1.1  christos }
    616  1.1  christos 
    617  1.1  christos size_t
    618  1.1  christos isc_ht_count(const isc_ht_t *ht) {
    619  1.1  christos 	REQUIRE(ISC_HT_VALID(ht));
    620  1.1  christos 
    621  1.1  christos 	return (ht->count);
    622  1.1  christos }
    623