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