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