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