Coverage Report

Created: 2026-08-31 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/hashmap.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*
15
 * This is an implementation of the Robin Hood hash table algorithm as
16
 * described in [a] with simple linear searching, and backwards shift
17
 * deletion algorithm as described in [b] and [c].
18
 *
19
 * Further work:
20
 * 1. Implement 4.1 Speeding up Searches - 4.4 Smart Search [a]
21
 * 2. Implement A Fast Concurrent and Resizable Robin Hood Hash Table [b]
22
 *
23
 * a. https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf paper.
24
 * b. https://dspace.mit.edu/bitstream/handle/1721.1/130693/1251799942-MIT.pdf
25
 * c.
26
 * https://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
27
 */
28
29
#include <ctype.h>
30
#include <inttypes.h>
31
#include <string.h>
32
33
#include <isc/ascii.h>
34
#include <isc/atomic.h>
35
#include <isc/hash.h>
36
#include <isc/hashmap.h>
37
#include <isc/magic.h>
38
#include <isc/mem.h>
39
#include <isc/result.h>
40
#include <isc/types.h>
41
#include <isc/util.h>
42
43
#define APPROX_99_PERCENT(x) (((x) * 1013) >> 10)
44
#define APPROX_95_PERCENT(x) (((x) * 972) >> 10)
45
402k
#define APPROX_90_PERCENT(x) (((x) * 921) >> 10)
46
#define APPROX_85_PERCENT(x) (((x) * 870) >> 10)
47
25.5k
#define APPROX_40_PERCENT(x) (((x) * 409) >> 10)
48
#define APPROX_35_PERCENT(x) (((x) * 359) >> 10)
49
#define APPROX_30_PERCENT(x) (((x) * 308) >> 10)
50
#define APPROX_25_PERCENT(x) (((x) * 256) >> 10)
51
0
#define APPROX_20_PERCENT(x) (((x) * 205) >> 10)
52
#define APPROX_15_PERCENT(x) (((x) * 154) >> 10)
53
#define APPROX_10_PERCENT(x) (((x) * 103) >> 10)
54
#define APPROX_05_PERCENT(x) (((x) * 52) >> 10)
55
#define APPROX_01_PERCENT(x) (((x) * 11) >> 10)
56
57
89.1k
#define ISC_HASHMAP_MAGIC    ISC_MAGIC('H', 'M', 'a', 'p')
58
#define ISC_HASHMAP_VALID(hashmap) ISC_MAGIC_VALID(hashmap, ISC_HASHMAP_MAGIC)
59
60
/* We have two tables for incremental rehashing */
61
133k
#define HASHMAP_NUM_TABLES 2
62
63
140k
#define HASHSIZE(bits) (UINT64_C(1) << (bits))
64
65
57.3k
#define HASHMAP_NO_BITS  0U
66
0
#define HASHMAP_MIN_BITS 1U
67
415k
#define HASHMAP_MAX_BITS 32U
68
69
typedef struct hashmap_node {
70
  const void *key;
71
  void *value;
72
  uint32_t hashval;
73
  uint32_t psl;
74
} hashmap_node_t;
75
76
typedef struct hashmap_table {
77
  size_t size;
78
  uint8_t hashbits;
79
  uint32_t hashmask;
80
  hashmap_node_t *table;
81
} hashmap_table_t;
82
83
struct isc_hashmap {
84
  unsigned int magic;
85
  uint8_t hindex;
86
  uint32_t hiter; /* rehashing iterator */
87
  isc_mem_t *mctx;
88
  size_t count;
89
  hashmap_table_t tables[HASHMAP_NUM_TABLES];
90
  atomic_uint_fast32_t iterators;
91
};
92
93
struct isc_hashmap_iter {
94
  isc_hashmap_t *hashmap;
95
  size_t i;
96
  size_t size;
97
  uint8_t hindex;
98
  hashmap_node_t *cur;
99
};
100
101
static isc_result_t
102
hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval,
103
      isc_hashmap_match_fn match, const uint8_t *key, void *value,
104
      void **foundp, uint8_t idx);
105
106
static void
107
hashmap_rehash_one(isc_hashmap_t *hashmap);
108
static void
109
hashmap_rehash_start_grow(isc_hashmap_t *hashmap);
110
static void
111
hashmap_rehash_start_shrink(isc_hashmap_t *hashmap);
112
static bool
113
over_threshold(isc_hashmap_t *hashmap);
114
static bool
115
under_threshold(isc_hashmap_t *hashmap);
116
117
static uint8_t
118
1.21M
hashmap_nexttable(uint8_t idx) {
119
1.21M
  return (idx == 0) ? 1 : 0;
120
1.21M
}
121
122
static bool
123
1.10M
rehashing_in_progress(const isc_hashmap_t *hashmap) {
124
1.10M
  return hashmap->tables[hashmap_nexttable(hashmap->hindex)].table !=
125
1.10M
         NULL;
126
1.10M
}
127
128
static bool
129
235k
try_nexttable(const isc_hashmap_t *hashmap, uint8_t idx) {
130
235k
  return idx == hashmap->hindex && rehashing_in_progress(hashmap);
131
235k
}
132
133
static void
134
hashmap_node_init(hashmap_node_t *node, const uint32_t hashval,
135
477k
      const uint8_t *key, void *value) {
136
477k
  *node = (hashmap_node_t){
137
477k
    .value = value,
138
477k
    .hashval = hashval,
139
477k
    .key = key,
140
477k
    .psl = 0,
141
477k
  };
142
477k
}
143
144
ISC_ATTR_UNUSED static void
145
0
hashmap_dump_table(const isc_hashmap_t *hashmap, const uint8_t idx) {
146
0
  fprintf(stderr,
147
0
    "====== %" PRIu8 " (bits = %" PRIu8 ", size = %zu =====\n", idx,
148
0
    hashmap->tables[idx].hashbits, hashmap->tables[idx].size);
149
0
  for (size_t i = 0; i < hashmap->tables[idx].size; i++) {
150
0
    hashmap_node_t *node = &hashmap->tables[idx].table[i];
151
0
    if (node->key != NULL) {
152
0
      uint32_t hash = isc_hash_bits32(
153
0
        node->hashval, hashmap->tables[idx].hashbits);
154
0
      fprintf(stderr,
155
0
        "%p: %zu -> %p"
156
0
        ", value = %p"
157
0
        ", hash = %" PRIu32 ", hashval = %" PRIu32
158
0
        ", psl = %" PRIu32 ", key = %s\n",
159
0
        hashmap, i, node, node->value, hash,
160
0
        node->hashval, node->psl, (char *)node->key);
161
0
    }
162
0
  }
163
0
  fprintf(stderr, "================\n\n");
164
0
}
165
166
static void
167
hashmap_create_table(isc_hashmap_t *hashmap, const uint8_t idx,
168
57.3k
         const uint8_t bits) {
169
57.3k
  REQUIRE(hashmap->tables[idx].hashbits == HASHMAP_NO_BITS);
170
57.3k
  REQUIRE(hashmap->tables[idx].table == NULL);
171
57.3k
  REQUIRE(bits >= HASHMAP_MIN_BITS);
172
57.3k
  REQUIRE(bits <= HASHMAP_MAX_BITS);
173
174
57.3k
  hashmap->tables[idx] = (hashmap_table_t){
175
57.3k
    .hashbits = bits,
176
57.3k
    .hashmask = HASHSIZE(bits) - 1,
177
57.3k
    .size = HASHSIZE(bits),
178
57.3k
  };
179
180
57.3k
  hashmap->tables[idx].table =
181
57.3k
    isc_mem_cget(hashmap->mctx, hashmap->tables[idx].size,
182
57.3k
           sizeof(hashmap->tables[idx].table[0]));
183
57.3k
}
184
185
static void
186
57.3k
hashmap_free_table(isc_hashmap_t *hashmap, const uint8_t idx, bool cleanup) {
187
57.3k
  size_t size;
188
189
57.3k
  if (cleanup) {
190
320k
    for (size_t i = 0; i < hashmap->tables[idx].size; i++) {
191
272k
      hashmap_node_t *node = &hashmap->tables[idx].table[i];
192
272k
      if (node->key != NULL) {
193
92.3k
        *node = (hashmap_node_t){ 0 };
194
92.3k
        hashmap->count--;
195
92.3k
      }
196
272k
    }
197
48.5k
  }
198
199
57.3k
  size = hashmap->tables[idx].size *
200
57.3k
         sizeof(hashmap->tables[idx].table[0]);
201
57.3k
  isc_mem_put(hashmap->mctx, hashmap->tables[idx].table, size);
202
203
57.3k
  hashmap->tables[idx] = (hashmap_table_t){
204
57.3k
    .hashbits = HASHMAP_NO_BITS,
205
57.3k
  };
206
57.3k
}
207
208
void
209
44.5k
isc_hashmap_create(isc_mem_t *mctx, uint8_t bits, isc_hashmap_t **hashmapp) {
210
44.5k
  isc_hashmap_t *hashmap = isc_mem_get(mctx, sizeof(*hashmap));
211
212
44.5k
  REQUIRE(hashmapp != NULL && *hashmapp == NULL);
213
44.5k
  REQUIRE(mctx != NULL);
214
44.5k
  REQUIRE(bits >= HASHMAP_MIN_BITS && bits <= HASHMAP_MAX_BITS);
215
216
44.5k
  *hashmap = (isc_hashmap_t){
217
44.5k
    .magic = ISC_HASHMAP_MAGIC,
218
44.5k
  };
219
44.5k
  isc_mem_attach(mctx, &hashmap->mctx);
220
221
44.5k
  hashmap_create_table(hashmap, 0, bits);
222
223
44.5k
  hashmap->magic = ISC_HASHMAP_MAGIC;
224
225
44.5k
  *hashmapp = hashmap;
226
44.5k
}
227
228
void
229
44.5k
isc_hashmap_destroy(isc_hashmap_t **hashmapp) {
230
44.5k
  isc_hashmap_t *hashmap;
231
232
44.5k
  REQUIRE(hashmapp != NULL && *hashmapp != NULL);
233
44.5k
  REQUIRE(ISC_HASHMAP_VALID(*hashmapp));
234
235
44.5k
  hashmap = *hashmapp;
236
44.5k
  *hashmapp = NULL;
237
238
44.5k
  hashmap->magic = 0;
239
240
133k
  for (size_t i = 0; i < HASHMAP_NUM_TABLES; i++) {
241
89.0k
    if (hashmap->tables[i].table != NULL) {
242
48.5k
      hashmap_free_table(hashmap, i, true);
243
48.5k
    }
244
89.0k
  }
245
44.5k
  INSIST(hashmap->count == 0);
246
247
44.5k
  isc_mem_putanddetach(&hashmap->mctx, hashmap, sizeof(*hashmap));
248
44.5k
}
249
250
static hashmap_node_t *
251
hashmap_find(const isc_hashmap_t *hashmap, const uint32_t hashval,
252
       isc_hashmap_match_fn match, const uint8_t *key, uint32_t *pslp,
253
228k
       uint8_t *idxp) {
254
228k
  uint32_t hash;
255
228k
  uint32_t psl;
256
228k
  uint8_t idx = *idxp;
257
228k
  uint32_t pos;
258
259
228k
nexttable:
260
228k
  psl = 0;
261
228k
  hash = isc_hash_bits32(hashval, hashmap->tables[idx].hashbits);
262
263
253k
  while (true) {
264
253k
    hashmap_node_t *node = NULL;
265
266
253k
    pos = (hash + psl) & hashmap->tables[idx].hashmask;
267
268
253k
    node = &hashmap->tables[idx].table[pos];
269
270
253k
    if (node->key == NULL || psl > node->psl) {
271
218k
      break;
272
218k
    }
273
274
35.0k
    if (node->hashval == hashval) {
275
10.2k
      if (match(node->value, key)) {
276
10.1k
        *pslp = psl;
277
10.1k
        *idxp = idx;
278
10.1k
        return node;
279
10.1k
      }
280
10.2k
    }
281
282
24.8k
    psl++;
283
24.8k
  }
284
218k
  if (try_nexttable(hashmap, idx)) {
285
0
    idx = hashmap_nexttable(idx);
286
0
    goto nexttable;
287
0
  }
288
289
218k
  return NULL;
290
218k
}
291
292
isc_result_t
293
isc_hashmap_find(const isc_hashmap_t *hashmap, const uint32_t hashval,
294
184k
     isc_hashmap_match_fn match, const void *key, void **valuep) {
295
184k
  REQUIRE(ISC_HASHMAP_VALID(hashmap));
296
184k
  REQUIRE(valuep == NULL || *valuep == NULL);
297
298
184k
  uint8_t idx = hashmap->hindex;
299
184k
  hashmap_node_t *node = hashmap_find(hashmap, hashval, match, key,
300
184k
              &(uint32_t){ 0 }, &idx);
301
184k
  if (node == NULL) {
302
183k
    return ISC_R_NOTFOUND;
303
183k
  }
304
305
251
  INSIST(node->key != NULL);
306
251
  SET_IF_NOT_NULL(valuep, node->value);
307
251
  return ISC_R_SUCCESS;
308
184k
}
309
310
static bool
311
hashmap_delete_node(isc_hashmap_t *hashmap, hashmap_node_t *entry,
312
        uint32_t hashval, uint32_t psl, const uint8_t idx,
313
44.5k
        size_t size) {
314
44.5k
  uint32_t pos;
315
44.5k
  uint32_t hash;
316
44.5k
  bool last = false;
317
318
44.5k
  hashmap->count--;
319
320
44.5k
  hash = isc_hash_bits32(hashval, hashmap->tables[idx].hashbits);
321
44.5k
  pos = (hash + psl) & hashmap->tables[idx].hashmask;
322
323
82.8k
  while (true) {
324
82.8k
    hashmap_node_t *node = NULL;
325
326
82.8k
    pos = (pos + 1) & hashmap->tables[idx].hashmask;
327
82.8k
    INSIST(pos < hashmap->tables[idx].size);
328
329
82.8k
    node = &hashmap->tables[idx].table[pos];
330
331
82.8k
    if (node->key == NULL || node->psl == 0) {
332
44.5k
      break;
333
44.5k
    }
334
335
38.3k
    if ((pos % size) == 0) {
336
0
      last = true;
337
0
    }
338
339
38.3k
    node->psl--;
340
38.3k
    *entry = *node;
341
38.3k
    entry = &hashmap->tables[idx].table[pos];
342
38.3k
  }
343
344
44.5k
  *entry = (hashmap_node_t){ 0 };
345
44.5k
  return last;
346
44.5k
}
347
348
static void
349
53.3k
hashmap_rehash_one(isc_hashmap_t *hashmap) {
350
53.3k
  uint8_t oldidx = hashmap_nexttable(hashmap->hindex);
351
53.3k
  uint32_t oldsize = hashmap->tables[oldidx].size;
352
53.3k
  hashmap_node_t *oldtable = hashmap->tables[oldidx].table;
353
53.3k
  hashmap_node_t node;
354
355
  /* Don't rehash when iterating */
356
53.3k
  INSIST(atomic_load_acquire(&hashmap->iterators) == 0);
357
358
  /* Find first non-empty node */
359
93.4k
  while (hashmap->hiter < oldsize && oldtable[hashmap->hiter].key == NULL)
360
40.1k
  {
361
40.1k
    hashmap->hiter++;
362
40.1k
  }
363
364
  /* Rehashing complete */
365
53.3k
  if (hashmap->hiter == oldsize) {
366
8.80k
    hashmap_free_table(hashmap, hashmap_nexttable(hashmap->hindex),
367
8.80k
           false);
368
8.80k
    hashmap->hiter = 0;
369
8.80k
    return;
370
8.80k
  }
371
372
  /* Move the first non-empty node from old table to new table */
373
44.5k
  node = oldtable[hashmap->hiter];
374
375
44.5k
  (void)hashmap_delete_node(hashmap, &oldtable[hashmap->hiter],
376
44.5k
          node.hashval, node.psl, oldidx, UINT32_MAX);
377
378
44.5k
  isc_result_t result = hashmap_add(hashmap, node.hashval, NULL, node.key,
379
44.5k
            node.value, NULL, hashmap->hindex);
380
44.5k
  INSIST(result == ISC_R_SUCCESS);
381
382
  /*
383
   * we don't increase the hiter here because the table has been reordered
384
   * when we deleted the old node
385
   */
386
44.5k
}
387
388
static uint32_t
389
12.7k
grow_bits(isc_hashmap_t *hashmap) {
390
12.7k
  uint32_t newbits = hashmap->tables[hashmap->hindex].hashbits + 1;
391
12.7k
  size_t newsize = HASHSIZE(newbits);
392
393
25.5k
  while (hashmap->count > APPROX_40_PERCENT(newsize)) {
394
12.7k
    newbits += 1;
395
12.7k
    newsize = HASHSIZE(newbits);
396
12.7k
  }
397
12.7k
  if (newbits > HASHMAP_MAX_BITS) {
398
0
    newbits = HASHMAP_MAX_BITS;
399
0
  }
400
401
12.7k
  return newbits;
402
12.7k
}
403
404
static uint32_t
405
0
shrink_bits(isc_hashmap_t *hashmap) {
406
0
  uint32_t newbits = hashmap->tables[hashmap->hindex].hashbits - 1;
407
408
0
  if (newbits <= HASHMAP_MIN_BITS) {
409
0
    newbits = HASHMAP_MIN_BITS;
410
0
  }
411
412
0
  return newbits;
413
0
}
414
415
static void
416
12.7k
hashmap_rehash_start_grow(isc_hashmap_t *hashmap) {
417
12.7k
  uint32_t newbits;
418
12.7k
  uint8_t oldindex = hashmap->hindex;
419
12.7k
  uint32_t oldbits = hashmap->tables[oldindex].hashbits;
420
12.7k
  uint8_t newindex = hashmap_nexttable(oldindex);
421
422
12.7k
  REQUIRE(!rehashing_in_progress(hashmap));
423
424
12.7k
  newbits = grow_bits(hashmap);
425
426
12.7k
  if (newbits > oldbits) {
427
12.7k
    hashmap_create_table(hashmap, newindex, newbits);
428
12.7k
    hashmap->hindex = newindex;
429
12.7k
  }
430
12.7k
}
431
432
static void
433
0
hashmap_rehash_start_shrink(isc_hashmap_t *hashmap) {
434
0
  uint32_t newbits;
435
0
  uint8_t oldindex = hashmap->hindex;
436
0
  uint32_t oldbits = hashmap->tables[oldindex].hashbits;
437
0
  uint8_t newindex = hashmap_nexttable(oldindex);
438
439
0
  REQUIRE(!rehashing_in_progress(hashmap));
440
441
0
  newbits = shrink_bits(hashmap);
442
443
0
  if (newbits < oldbits) {
444
0
    hashmap_create_table(hashmap, newindex, newbits);
445
0
    hashmap->hindex = newindex;
446
0
  }
447
0
}
448
449
isc_result_t
450
isc_hashmap_delete(isc_hashmap_t *hashmap, const uint32_t hashval,
451
0
       isc_hashmap_match_fn match, const void *key) {
452
0
  REQUIRE(ISC_HASHMAP_VALID(hashmap));
453
0
  REQUIRE(key != NULL);
454
455
0
  hashmap_node_t *node;
456
0
  isc_result_t result = ISC_R_NOTFOUND;
457
0
  uint32_t psl = 0;
458
0
  uint8_t idx;
459
460
0
  if (rehashing_in_progress(hashmap)) {
461
0
    hashmap_rehash_one(hashmap);
462
0
  } else if (under_threshold(hashmap)) {
463
0
    hashmap_rehash_start_shrink(hashmap);
464
0
    hashmap_rehash_one(hashmap);
465
0
  }
466
467
  /* Initialize idx after possible shrink start */
468
0
  idx = hashmap->hindex;
469
470
0
  node = hashmap_find(hashmap, hashval, match, key, &psl, &idx);
471
0
  if (node != NULL) {
472
0
    INSIST(node->key != NULL);
473
0
    (void)hashmap_delete_node(hashmap, node, hashval, psl, idx,
474
0
            UINT32_MAX);
475
0
    result = ISC_R_SUCCESS;
476
0
  }
477
478
0
  return result;
479
0
}
480
481
static bool
482
402k
over_threshold(isc_hashmap_t *hashmap) {
483
402k
  uint32_t bits = hashmap->tables[hashmap->hindex].hashbits;
484
402k
  if (bits == HASHMAP_MAX_BITS) {
485
0
    return false;
486
0
  }
487
402k
  size_t threshold = APPROX_90_PERCENT(HASHSIZE(bits));
488
402k
  return hashmap->count > threshold;
489
402k
}
490
491
static bool
492
0
under_threshold(isc_hashmap_t *hashmap) {
493
0
  uint32_t bits = hashmap->tables[hashmap->hindex].hashbits;
494
0
  if (bits == HASHMAP_MIN_BITS) {
495
0
    return false;
496
0
  }
497
0
  size_t threshold = APPROX_20_PERCENT(HASHSIZE(bits));
498
0
  return hashmap->count < threshold;
499
0
}
500
501
static isc_result_t
502
hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval,
503
      isc_hashmap_match_fn match, const uint8_t *key, void *value,
504
477k
      void **foundp, uint8_t idx) {
505
477k
  uint32_t hash;
506
477k
  uint32_t psl = 0;
507
477k
  hashmap_node_t node;
508
477k
  hashmap_node_t *current = NULL;
509
477k
  uint32_t pos;
510
511
477k
  INSIST(atomic_load_acquire(&hashmap->iterators) == 0);
512
513
477k
  hash = isc_hash_bits32(hashval, hashmap->tables[idx].hashbits);
514
515
  /* Initialize the node to be store to 'node' */
516
477k
  hashmap_node_init(&node, hashval, key, value);
517
518
477k
  psl = 0;
519
635k
  while (true) {
520
635k
    pos = (hash + psl) & hashmap->tables[idx].hashmask;
521
522
635k
    current = &hashmap->tables[idx].table[pos];
523
524
    /* Found an empty node */
525
635k
    if (current->key == NULL) {
526
136k
      break;
527
136k
    }
528
529
498k
    if (current->hashval == hashval) {
530
340k
      if (match != NULL && match(current->value, key)) {
531
340k
        SET_IF_NOT_NULL(foundp, current->value);
532
340k
        return ISC_R_EXISTS;
533
340k
      }
534
340k
    }
535
536
    /* Found rich node */
537
158k
    if (node.psl > current->psl) {
538
      /* Swap the poor with the rich node */
539
29.2k
      ISC_SWAP(*current, node);
540
29.2k
    }
541
542
158k
    node.psl++;
543
158k
    psl++;
544
158k
  }
545
546
  /*
547
   * Possible optimalization - start growing when the poor node is too far
548
   */
549
#if ISC_HASHMAP_GROW_FAST
550
  if (psl > hashmap->hashbits[idx]) {
551
    if (!rehashing_in_progress(hashmap)) {
552
      hashmap_rehash_start_grow(hashmap);
553
    }
554
  }
555
#endif
556
557
136k
  hashmap->count++;
558
559
  /* We found an empty place, store entry into current node */
560
136k
  *current = node;
561
562
136k
  return ISC_R_SUCCESS;
563
477k
}
564
565
isc_result_t
566
isc_hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval,
567
    isc_hashmap_match_fn match, const void *key, void *value,
568
443k
    void **foundp) {
569
443k
  REQUIRE(ISC_HASHMAP_VALID(hashmap));
570
443k
  REQUIRE(key != NULL);
571
572
443k
  if (rehashing_in_progress(hashmap)) {
573
40.5k
    hashmap_rehash_one(hashmap);
574
402k
  } else if (over_threshold(hashmap)) {
575
12.7k
    hashmap_rehash_start_grow(hashmap);
576
12.7k
    hashmap_rehash_one(hashmap);
577
12.7k
  }
578
579
443k
  if (rehashing_in_progress(hashmap)) {
580
44.5k
    uint8_t fidx = hashmap_nexttable(hashmap->hindex);
581
44.5k
    uint32_t psl;
582
583
    /* Look for the value in the old table */
584
44.5k
    hashmap_node_t *found = hashmap_find(hashmap, hashval, match,
585
44.5k
                 key, &psl, &fidx);
586
44.5k
    if (found != NULL) {
587
9.93k
      INSIST(found->key != NULL);
588
9.93k
      SET_IF_NOT_NULL(foundp, found->value);
589
9.93k
      return ISC_R_EXISTS;
590
9.93k
    }
591
44.5k
  }
592
593
433k
  return hashmap_add(hashmap, hashval, match, key, value, foundp,
594
433k
         hashmap->hindex);
595
443k
}
596
597
void
598
17.3k
isc_hashmap_iter_create(isc_hashmap_t *hashmap, isc_hashmap_iter_t **iterp) {
599
17.3k
  isc_hashmap_iter_t *iter;
600
601
17.3k
  REQUIRE(ISC_HASHMAP_VALID(hashmap));
602
17.3k
  REQUIRE(iterp != NULL && *iterp == NULL);
603
604
17.3k
  iter = isc_mem_get(hashmap->mctx, sizeof(*iter));
605
17.3k
  *iter = (isc_hashmap_iter_t){
606
17.3k
    .hashmap = hashmap,
607
17.3k
    .hindex = hashmap->hindex,
608
17.3k
  };
609
610
17.3k
  (void)atomic_fetch_add_release(&hashmap->iterators, 1);
611
612
17.3k
  *iterp = iter;
613
17.3k
}
614
615
void
616
17.3k
isc_hashmap_iter_destroy(isc_hashmap_iter_t **iterp) {
617
17.3k
  isc_hashmap_iter_t *iter;
618
17.3k
  isc_hashmap_t *hashmap;
619
620
17.3k
  REQUIRE(iterp != NULL && *iterp != NULL);
621
622
17.3k
  iter = *iterp;
623
17.3k
  *iterp = NULL;
624
17.3k
  hashmap = iter->hashmap;
625
17.3k
  isc_mem_put(hashmap->mctx, iter, sizeof(*iter));
626
627
17.3k
  INSIST(atomic_fetch_sub_release(&hashmap->iterators, 1) > 0);
628
17.3k
}
629
630
static isc_result_t
631
17.3k
isc__hashmap_iter_next(isc_hashmap_iter_t *iter) {
632
17.3k
  isc_hashmap_t *hashmap = iter->hashmap;
633
634
52.1k
  while (iter->i < iter->size &&
635
34.7k
         hashmap->tables[iter->hindex].table[iter->i].key == NULL)
636
34.7k
  {
637
34.7k
    iter->i++;
638
34.7k
  }
639
640
17.3k
  if (iter->i < iter->size) {
641
0
    iter->cur = &hashmap->tables[iter->hindex].table[iter->i];
642
643
0
    return ISC_R_SUCCESS;
644
0
  }
645
646
17.3k
  if (try_nexttable(hashmap, iter->hindex)) {
647
0
    iter->hindex = hashmap_nexttable(iter->hindex);
648
0
    iter->i = hashmap->hiter;
649
0
    iter->size = hashmap->tables[iter->hindex].size;
650
0
    return isc__hashmap_iter_next(iter);
651
0
  }
652
653
17.3k
  return ISC_R_NOMORE;
654
17.3k
}
655
656
isc_result_t
657
17.3k
isc_hashmap_iter_first(isc_hashmap_iter_t *iter) {
658
17.3k
  REQUIRE(iter != NULL);
659
660
17.3k
  iter->hindex = iter->hashmap->hindex;
661
17.3k
  iter->i = 0;
662
17.3k
  iter->size = iter->hashmap->tables[iter->hashmap->hindex].size;
663
664
17.3k
  return isc__hashmap_iter_next(iter);
665
17.3k
}
666
667
isc_result_t
668
0
isc_hashmap_iter_next(isc_hashmap_iter_t *iter) {
669
0
  REQUIRE(iter != NULL);
670
0
  REQUIRE(iter->cur != NULL);
671
672
0
  iter->i++;
673
674
0
  return isc__hashmap_iter_next(iter);
675
0
}
676
677
isc_result_t
678
0
isc_hashmap_iter_delcurrent_next(isc_hashmap_iter_t *iter) {
679
0
  REQUIRE(iter != NULL);
680
0
  REQUIRE(iter->cur != NULL);
681
682
0
  hashmap_node_t *node =
683
0
    &iter->hashmap->tables[iter->hindex].table[iter->i];
684
685
0
  if (hashmap_delete_node(iter->hashmap, node, node->hashval, node->psl,
686
0
        iter->hindex, iter->size))
687
0
  {
688
    /*
689
     * We have seen the new last element so reduce the size
690
     * so we don't iterate over it twice.
691
     */
692
0
    INSIST(iter->size != 0);
693
0
    iter->size--;
694
0
  }
695
696
0
  return isc__hashmap_iter_next(iter);
697
0
}
698
699
void
700
0
isc_hashmap_iter_current(isc_hashmap_iter_t *it, void **valuep) {
701
0
  REQUIRE(it != NULL);
702
0
  REQUIRE(it->cur != NULL);
703
0
  REQUIRE(valuep != NULL && *valuep == NULL);
704
705
0
  *valuep = it->cur->value;
706
0
}
707
708
void
709
0
isc_hashmap_iter_currentkey(isc_hashmap_iter_t *it, const unsigned char **key) {
710
0
  REQUIRE(it != NULL);
711
0
  REQUIRE(it->cur != NULL);
712
0
  REQUIRE(key != NULL && *key == NULL);
713
714
0
  *key = it->cur->key;
715
0
}
716
717
unsigned int
718
0
isc_hashmap_count(isc_hashmap_t *hashmap) {
719
0
  REQUIRE(ISC_HASHMAP_VALID(hashmap));
720
721
0
  return hashmap->count;
722
0
}