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