Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <stdint.h>
5 : #include <stdlib.h>
6 : #include <string.h>
7 :
8 : #include "alloc-util.h"
9 : #include "fileio.h"
10 : #include "hashmap.h"
11 : #include "macro.h"
12 : #include "memory-util.h"
13 : #include "mempool.h"
14 : #include "missing.h"
15 : #include "process-util.h"
16 : #include "random-util.h"
17 : #include "set.h"
18 : #include "siphash24.h"
19 : #include "string-util.h"
20 : #include "strv.h"
21 :
22 : #if ENABLE_DEBUG_HASHMAP
23 : #include <pthread.h>
24 : #include "list.h"
25 : #endif
26 :
27 : /*
28 : * Implementation of hashmaps.
29 : * Addressing: open
30 : * - uses less RAM compared to closed addressing (chaining), because
31 : * our entries are small (especially in Sets, which tend to contain
32 : * the majority of entries in systemd).
33 : * Collision resolution: Robin Hood
34 : * - tends to equalize displacement of entries from their optimal buckets.
35 : * Probe sequence: linear
36 : * - though theoretically worse than random probing/uniform hashing/double
37 : * hashing, it is good for cache locality.
38 : *
39 : * References:
40 : * Celis, P. 1986. Robin Hood Hashing.
41 : * Ph.D. Dissertation. University of Waterloo, Waterloo, Ont., Canada, Canada.
42 : * https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf
43 : * - The results are derived for random probing. Suggests deletion with
44 : * tombstones and two mean-centered search methods. None of that works
45 : * well for linear probing.
46 : *
47 : * Janson, S. 2005. Individual displacements for linear probing hashing with different insertion policies.
48 : * ACM Trans. Algorithms 1, 2 (October 2005), 177-213.
49 : * DOI=10.1145/1103963.1103964 http://doi.acm.org/10.1145/1103963.1103964
50 : * http://www.math.uu.se/~svante/papers/sj157.pdf
51 : * - Applies to Robin Hood with linear probing. Contains remarks on
52 : * the unsuitability of mean-centered search with linear probing.
53 : *
54 : * Viola, A. 2005. Exact distribution of individual displacements in linear probing hashing.
55 : * ACM Trans. Algorithms 1, 2 (October 2005), 214-242.
56 : * DOI=10.1145/1103963.1103965 http://doi.acm.org/10.1145/1103963.1103965
57 : * - Similar to Janson. Note that Viola writes about C_{m,n} (number of probes
58 : * in a successful search), and Janson writes about displacement. C = d + 1.
59 : *
60 : * Goossaert, E. 2013. Robin Hood hashing: backward shift deletion.
61 : * http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
62 : * - Explanation of backward shift deletion with pictures.
63 : *
64 : * Khuong, P. 2013. The Other Robin Hood Hashing.
65 : * http://www.pvk.ca/Blog/2013/11/26/the-other-robin-hood-hashing/
66 : * - Short summary of random vs. linear probing, and tombstones vs. backward shift.
67 : */
68 :
69 : /*
70 : * XXX Ideas for improvement:
71 : * For unordered hashmaps, randomize iteration order, similarly to Perl:
72 : * http://blog.booking.com/hardening-perls-hash-function.html
73 : */
74 :
75 : /* INV_KEEP_FREE = 1 / (1 - max_load_factor)
76 : * e.g. 1 / (1 - 0.8) = 5 ... keep one fifth of the buckets free. */
77 : #define INV_KEEP_FREE 5U
78 :
79 : /* Fields common to entries of all hashmap/set types */
80 : struct hashmap_base_entry {
81 : const void *key;
82 : };
83 :
84 : /* Entry types for specific hashmap/set types
85 : * hashmap_base_entry must be at the beginning of each entry struct. */
86 :
87 : struct plain_hashmap_entry {
88 : struct hashmap_base_entry b;
89 : void *value;
90 : };
91 :
92 : struct ordered_hashmap_entry {
93 : struct plain_hashmap_entry p;
94 : unsigned iterate_next, iterate_previous;
95 : };
96 :
97 : struct set_entry {
98 : struct hashmap_base_entry b;
99 : };
100 :
101 : /* In several functions it is advantageous to have the hash table extended
102 : * virtually by a couple of additional buckets. We reserve special index values
103 : * for these "swap" buckets. */
104 : #define _IDX_SWAP_BEGIN (UINT_MAX - 3)
105 : #define IDX_PUT (_IDX_SWAP_BEGIN + 0)
106 : #define IDX_TMP (_IDX_SWAP_BEGIN + 1)
107 : #define _IDX_SWAP_END (_IDX_SWAP_BEGIN + 2)
108 :
109 : #define IDX_FIRST (UINT_MAX - 1) /* special index for freshly initialized iterators */
110 : #define IDX_NIL UINT_MAX /* special index value meaning "none" or "end" */
111 :
112 : assert_cc(IDX_FIRST == _IDX_SWAP_END);
113 : assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST);
114 :
115 : /* Storage space for the "swap" buckets.
116 : * All entry types can fit into a ordered_hashmap_entry. */
117 : struct swap_entries {
118 : struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN];
119 : };
120 :
121 : /* Distance from Initial Bucket */
122 : typedef uint8_t dib_raw_t;
123 : #define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU) /* indicates DIB value is greater than representable */
124 : #define DIB_RAW_REHASH ((dib_raw_t)0xfeU) /* entry yet to be rehashed during in-place resize */
125 : #define DIB_RAW_FREE ((dib_raw_t)0xffU) /* a free bucket */
126 : #define DIB_RAW_INIT ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */
127 :
128 : #define DIB_FREE UINT_MAX
129 :
130 : #if ENABLE_DEBUG_HASHMAP
131 : struct hashmap_debug_info {
132 : LIST_FIELDS(struct hashmap_debug_info, debug_list);
133 : unsigned max_entries; /* high watermark of n_entries */
134 :
135 : /* who allocated this hashmap */
136 : int line;
137 : const char *file;
138 : const char *func;
139 :
140 : /* fields to detect modification while iterating */
141 : unsigned put_count; /* counts puts into the hashmap */
142 : unsigned rem_count; /* counts removals from hashmap */
143 : unsigned last_rem_idx; /* remembers last removal index */
144 : };
145 :
146 : /* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */
147 : static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
148 : static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER;
149 :
150 : #define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug;
151 :
152 : #else /* !ENABLE_DEBUG_HASHMAP */
153 : #define HASHMAP_DEBUG_FIELDS
154 : #endif /* ENABLE_DEBUG_HASHMAP */
155 :
156 : enum HashmapType {
157 : HASHMAP_TYPE_PLAIN,
158 : HASHMAP_TYPE_ORDERED,
159 : HASHMAP_TYPE_SET,
160 : _HASHMAP_TYPE_MAX
161 : };
162 :
163 : struct _packed_ indirect_storage {
164 : void *storage; /* where buckets and DIBs are stored */
165 : uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */
166 :
167 : unsigned n_entries; /* number of stored entries */
168 : unsigned n_buckets; /* number of buckets */
169 :
170 : unsigned idx_lowest_entry; /* Index below which all buckets are free.
171 : Makes "while(hashmap_steal_first())" loops
172 : O(n) instead of O(n^2) for unordered hashmaps. */
173 : uint8_t _pad[3]; /* padding for the whole HashmapBase */
174 : /* The bitfields in HashmapBase complete the alignment of the whole thing. */
175 : };
176 :
177 : struct direct_storage {
178 : /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit.
179 : * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit,
180 : * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */
181 : uint8_t storage[sizeof(struct indirect_storage)];
182 : };
183 :
184 : #define DIRECT_BUCKETS(entry_t) \
185 : (sizeof(struct direct_storage) / (sizeof(entry_t) + sizeof(dib_raw_t)))
186 :
187 : /* We should be able to store at least one entry directly. */
188 : assert_cc(DIRECT_BUCKETS(struct ordered_hashmap_entry) >= 1);
189 :
190 : /* We have 3 bits for n_direct_entries. */
191 : assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3));
192 :
193 : /* Hashmaps with directly stored entries all use this shared hash key.
194 : * It's no big deal if the key is guessed, because there can be only
195 : * a handful of directly stored entries in a hashmap. When a hashmap
196 : * outgrows direct storage, it gets its own key for indirect storage. */
197 : static uint8_t shared_hash_key[HASH_KEY_SIZE];
198 : static bool shared_hash_key_initialized;
199 :
200 : /* Fields that all hashmap/set types must have */
201 : struct HashmapBase {
202 : const struct hash_ops *hash_ops; /* hash and compare ops to use */
203 :
204 : union _packed_ {
205 : struct indirect_storage indirect; /* if has_indirect */
206 : struct direct_storage direct; /* if !has_indirect */
207 : };
208 :
209 : enum HashmapType type:2; /* HASHMAP_TYPE_* */
210 : bool has_indirect:1; /* whether indirect storage is used */
211 : unsigned n_direct_entries:3; /* Number of entries in direct storage.
212 : * Only valid if !has_indirect. */
213 : bool from_pool:1; /* whether was allocated from mempool */
214 : bool dirty:1; /* whether dirtied since last iterated_cache_get() */
215 : bool cached:1; /* whether this hashmap is being cached */
216 : HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */
217 : };
218 :
219 : /* Specific hash types
220 : * HashmapBase must be at the beginning of each hashmap struct. */
221 :
222 : struct Hashmap {
223 : struct HashmapBase b;
224 : };
225 :
226 : struct OrderedHashmap {
227 : struct HashmapBase b;
228 : unsigned iterate_list_head, iterate_list_tail;
229 : };
230 :
231 : struct Set {
232 : struct HashmapBase b;
233 : };
234 :
235 : typedef struct CacheMem {
236 : const void **ptr;
237 : size_t n_populated, n_allocated;
238 : bool active:1;
239 : } CacheMem;
240 :
241 : struct IteratedCache {
242 : HashmapBase *hashmap;
243 : CacheMem keys, values;
244 : };
245 :
246 : DEFINE_MEMPOOL(hashmap_pool, Hashmap, 8);
247 : DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8);
248 : /* No need for a separate Set pool */
249 : assert_cc(sizeof(Hashmap) == sizeof(Set));
250 :
251 : struct hashmap_type_info {
252 : size_t head_size;
253 : size_t entry_size;
254 : struct mempool *mempool;
255 : unsigned n_direct_buckets;
256 : };
257 :
258 : static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
259 : [HASHMAP_TYPE_PLAIN] = {
260 : .head_size = sizeof(Hashmap),
261 : .entry_size = sizeof(struct plain_hashmap_entry),
262 : .mempool = &hashmap_pool,
263 : .n_direct_buckets = DIRECT_BUCKETS(struct plain_hashmap_entry),
264 : },
265 : [HASHMAP_TYPE_ORDERED] = {
266 : .head_size = sizeof(OrderedHashmap),
267 : .entry_size = sizeof(struct ordered_hashmap_entry),
268 : .mempool = &ordered_hashmap_pool,
269 : .n_direct_buckets = DIRECT_BUCKETS(struct ordered_hashmap_entry),
270 : },
271 : [HASHMAP_TYPE_SET] = {
272 : .head_size = sizeof(Set),
273 : .entry_size = sizeof(struct set_entry),
274 : .mempool = &hashmap_pool,
275 : .n_direct_buckets = DIRECT_BUCKETS(struct set_entry),
276 : },
277 : };
278 :
279 : #if VALGRIND
280 : _destructor_ static void cleanup_pools(void) {
281 : _cleanup_free_ char *t = NULL;
282 : int r;
283 :
284 : /* Be nice to valgrind */
285 :
286 : /* The pool is only allocated by the main thread, but the memory can
287 : * be passed to other threads. Let's clean up if we are the main thread
288 : * and no other threads are live. */
289 : /* We build our own is_main_thread() here, which doesn't use C11
290 : * TLS based caching of the result. That's because valgrind apparently
291 : * doesn't like malloc() (which C11 TLS internally uses) to be called
292 : * from a GCC destructors. */
293 : if (getpid() != gettid())
294 : return;
295 :
296 : r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t);
297 : if (r < 0 || !streq(t, "1"))
298 : return;
299 :
300 : mempool_drop(&hashmap_pool);
301 : mempool_drop(&ordered_hashmap_pool);
302 : }
303 : #endif
304 :
305 6254666 : static unsigned n_buckets(HashmapBase *h) {
306 6254666 : return h->has_indirect ? h->indirect.n_buckets
307 6254666 : : hashmap_type_info[h->type].n_direct_buckets;
308 : }
309 :
310 475397 : static unsigned n_entries(HashmapBase *h) {
311 475397 : return h->has_indirect ? h->indirect.n_entries
312 475397 : : h->n_direct_entries;
313 : }
314 :
315 119283 : static void n_entries_inc(HashmapBase *h) {
316 119283 : if (h->has_indirect)
317 93037 : h->indirect.n_entries++;
318 : else
319 26246 : h->n_direct_entries++;
320 119283 : }
321 :
322 103699 : static void n_entries_dec(HashmapBase *h) {
323 103699 : if (h->has_indirect)
324 91971 : h->indirect.n_entries--;
325 : else
326 11728 : h->n_direct_entries--;
327 103699 : }
328 :
329 7411881 : static void *storage_ptr(HashmapBase *h) {
330 7411881 : return h->has_indirect ? h->indirect.storage
331 7411881 : : h->direct.storage;
332 : }
333 :
334 489125 : static uint8_t *hash_key(HashmapBase *h) {
335 489125 : return h->has_indirect ? h->indirect.hash_key
336 489125 : : shared_hash_key;
337 : }
338 :
339 489125 : static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
340 : struct siphash state;
341 : uint64_t hash;
342 :
343 489125 : siphash24_init(&state, hash_key(h));
344 :
345 489125 : h->hash_ops->hash(p, &state);
346 :
347 489125 : hash = siphash24_finalize(&state);
348 :
349 489125 : return (unsigned) (hash % n_buckets(h));
350 : }
351 : #define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
352 :
353 258603 : static void base_set_dirty(HashmapBase *h) {
354 258603 : h->dirty = true;
355 258603 : }
356 : #define hashmap_set_dirty(h) base_set_dirty(HASHMAP_BASE(h))
357 :
358 18331 : static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
359 : static uint8_t current[HASH_KEY_SIZE];
360 : static bool current_initialized = false;
361 :
362 : /* Returns a hash function key to use. In order to keep things
363 : * fast we will not generate a new key each time we allocate a
364 : * new hash table. Instead, we'll just reuse the most recently
365 : * generated one, except if we never generated one or when we
366 : * are rehashing an entire hash table because we reached a
367 : * fill level */
368 :
369 18331 : if (!current_initialized || !reuse_is_ok) {
370 7797 : random_bytes(current, sizeof(current));
371 7797 : current_initialized = true;
372 : }
373 :
374 18331 : memcpy(hash_key, current, sizeof(current));
375 18331 : }
376 :
377 5166848 : static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) {
378 10333696 : return (struct hashmap_base_entry*)
379 5166848 : ((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
380 : }
381 :
382 2796 : static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) {
383 2796 : return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
384 : }
385 :
386 344091 : static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap *h, unsigned idx) {
387 344091 : return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
388 : }
389 :
390 0 : static struct set_entry *set_bucket_at(Set *h, unsigned idx) {
391 0 : return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx);
392 : }
393 :
394 938481 : static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, unsigned idx) {
395 938481 : return &swap->e[idx - _IDX_SWAP_BEGIN];
396 : }
397 :
398 : /* Returns a pointer to the bucket at index idx.
399 : * Understands real indexes and swap indexes, hence "_virtual". */
400 1733257 : static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_entries *swap,
401 : unsigned idx) {
402 1733257 : if (idx < _IDX_SWAP_BEGIN)
403 1054398 : return bucket_at(h, idx);
404 :
405 678859 : if (idx < _IDX_SWAP_END)
406 678859 : return &bucket_at_swap(swap, idx)->p.b;
407 :
408 0 : assert_not_reached("Invalid index");
409 : }
410 :
411 2245033 : static dib_raw_t *dib_raw_ptr(HashmapBase *h) {
412 4490066 : return (dib_raw_t*)
413 2245033 : ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
414 : }
415 :
416 0 : static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) {
417 : return idx >= from ? idx - from
418 0 : : n_buckets(h) + idx - from;
419 : }
420 :
421 641097 : static unsigned bucket_calculate_dib(HashmapBase *h, unsigned idx, dib_raw_t raw_dib) {
422 : unsigned initial_bucket;
423 :
424 641097 : if (raw_dib == DIB_RAW_FREE)
425 0 : return DIB_FREE;
426 :
427 641097 : if (_likely_(raw_dib < DIB_RAW_OVERFLOW))
428 641097 : return raw_dib;
429 :
430 : /*
431 : * Having an overflow DIB value is very unlikely. The hash function
432 : * would have to be bad. For example, in a table of size 2^24 filled
433 : * to load factor 0.9 the maximum observed DIB is only about 60.
434 : * In theory (assuming I used Maxima correctly), for an infinite size
435 : * hash table with load factor 0.8 the probability of a given entry
436 : * having DIB > 40 is 1.9e-8.
437 : * This returns the correct DIB value by recomputing the hash value in
438 : * the unlikely case. XXX Hitting this case could be a hint to rehash.
439 : */
440 0 : initial_bucket = bucket_hash(h, bucket_at(h, idx)->key);
441 0 : return bucket_distance(h, idx, initial_bucket);
442 : }
443 :
444 452959 : static void bucket_set_dib(HashmapBase *h, unsigned idx, unsigned dib) {
445 452959 : dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE;
446 452959 : }
447 :
448 1084147 : static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) {
449 : dib_raw_t *dibs;
450 :
451 1084147 : dibs = dib_raw_ptr(h);
452 :
453 2073903 : for ( ; idx < n_buckets(h); idx++)
454 2039855 : if (dibs[idx] != DIB_RAW_FREE)
455 1050099 : return idx;
456 :
457 34048 : return IDX_NIL;
458 : }
459 :
460 103699 : static void bucket_mark_free(HashmapBase *h, unsigned idx) {
461 103699 : memzero(bucket_at(h, idx), hashmap_type_info[h->type].entry_size);
462 103699 : bucket_set_dib(h, idx, DIB_FREE);
463 103699 : }
464 :
465 623168 : static void bucket_move_entry(HashmapBase *h, struct swap_entries *swap,
466 : unsigned from, unsigned to) {
467 : struct hashmap_base_entry *e_from, *e_to;
468 :
469 623168 : assert(from != to);
470 :
471 623168 : e_from = bucket_at_virtual(h, swap, from);
472 623168 : e_to = bucket_at_virtual(h, swap, to);
473 :
474 623168 : memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size);
475 :
476 623168 : if (h->type == HASHMAP_TYPE_ORDERED) {
477 322128 : OrderedHashmap *lh = (OrderedHashmap*) h;
478 : struct ordered_hashmap_entry *le, *le_to;
479 :
480 322128 : le_to = (struct ordered_hashmap_entry*) e_to;
481 :
482 322128 : if (le_to->iterate_next != IDX_NIL) {
483 : le = (struct ordered_hashmap_entry*)
484 217791 : bucket_at_virtual(h, swap, le_to->iterate_next);
485 217791 : le->iterate_previous = to;
486 : }
487 :
488 322128 : if (le_to->iterate_previous != IDX_NIL) {
489 : le = (struct ordered_hashmap_entry*)
490 269130 : bucket_at_virtual(h, swap, le_to->iterate_previous);
491 269130 : le->iterate_next = to;
492 : }
493 :
494 322128 : if (lh->iterate_list_head == from)
495 52998 : lh->iterate_list_head = to;
496 322128 : if (lh->iterate_list_tail == from)
497 104337 : lh->iterate_list_tail = to;
498 : }
499 623168 : }
500 :
501 718754 : static unsigned next_idx(HashmapBase *h, unsigned idx) {
502 718754 : return (idx + 1U) % n_buckets(h);
503 : }
504 :
505 5 : static unsigned prev_idx(HashmapBase *h, unsigned idx) {
506 5 : return (n_buckets(h) + idx - 1U) % n_buckets(h);
507 : }
508 :
509 1218392 : static void *entry_value(HashmapBase *h, struct hashmap_base_entry *e) {
510 1218392 : switch (h->type) {
511 :
512 1182706 : case HASHMAP_TYPE_PLAIN:
513 : case HASHMAP_TYPE_ORDERED:
514 1182706 : return ((struct plain_hashmap_entry*)e)->value;
515 :
516 35686 : case HASHMAP_TYPE_SET:
517 35686 : return (void*) e->key;
518 :
519 0 : default:
520 0 : assert_not_reached("Unknown hashmap type");
521 : }
522 : }
523 :
524 103699 : static void base_remove_entry(HashmapBase *h, unsigned idx) {
525 : unsigned left, right, prev, dib;
526 : dib_raw_t raw_dib, *dibs;
527 :
528 103699 : dibs = dib_raw_ptr(h);
529 103699 : assert(dibs[idx] != DIB_RAW_FREE);
530 :
531 : #if ENABLE_DEBUG_HASHMAP
532 : h->debug.rem_count++;
533 : h->debug.last_rem_idx = idx;
534 : #endif
535 :
536 103699 : left = idx;
537 : /* Find the stop bucket ("right"). It is either free or has DIB == 0. */
538 154178 : for (right = next_idx(h, left); ; right = next_idx(h, right)) {
539 50479 : raw_dib = dibs[right];
540 154178 : if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
541 103699 : break;
542 :
543 : /* The buckets are not supposed to be all occupied and with DIB > 0.
544 : * That would mean we could make everyone better off by shifting them
545 : * backward. This scenario is impossible. */
546 50479 : assert(left != right);
547 : }
548 :
549 103699 : if (h->type == HASHMAP_TYPE_ORDERED) {
550 68833 : OrderedHashmap *lh = (OrderedHashmap*) h;
551 68833 : struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx);
552 :
553 68833 : if (le->iterate_next != IDX_NIL)
554 57390 : ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous;
555 : else
556 11443 : lh->iterate_list_tail = le->iterate_previous;
557 :
558 68833 : if (le->iterate_previous != IDX_NIL)
559 27 : ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next;
560 : else
561 68806 : lh->iterate_list_head = le->iterate_next;
562 : }
563 :
564 : /* Now shift all buckets in the interval (left, right) one step backwards */
565 154178 : for (prev = left, left = next_idx(h, left); left != right;
566 50479 : prev = left, left = next_idx(h, left)) {
567 50479 : dib = bucket_calculate_dib(h, left, dibs[left]);
568 50479 : assert(dib != 0);
569 50479 : bucket_move_entry(h, NULL, left, prev);
570 50479 : bucket_set_dib(h, prev, dib - 1);
571 : }
572 :
573 103699 : bucket_mark_free(h, prev);
574 103699 : n_entries_dec(h);
575 103699 : base_set_dirty(h);
576 103699 : }
577 : #define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx)
578 :
579 87809 : static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *i) {
580 : struct ordered_hashmap_entry *e;
581 : unsigned idx;
582 :
583 87809 : assert(h);
584 87809 : assert(i);
585 :
586 87809 : if (i->idx == IDX_NIL)
587 1008 : goto at_end;
588 :
589 86801 : if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL)
590 457 : goto at_end;
591 :
592 86344 : if (i->idx == IDX_FIRST) {
593 70010 : idx = h->iterate_list_head;
594 70010 : e = ordered_bucket_at(h, idx);
595 : } else {
596 16334 : idx = i->idx;
597 16334 : e = ordered_bucket_at(h, idx);
598 : /*
599 : * We allow removing the current entry while iterating, but removal may cause
600 : * a backward shift. The next entry may thus move one bucket to the left.
601 : * To detect when it happens, we remember the key pointer of the entry we were
602 : * going to iterate next. If it does not match, there was a backward shift.
603 : */
604 16334 : if (e->p.b.key != i->next_key) {
605 0 : idx = prev_idx(HASHMAP_BASE(h), idx);
606 0 : e = ordered_bucket_at(h, idx);
607 : }
608 16334 : assert(e->p.b.key == i->next_key);
609 : }
610 :
611 : #if ENABLE_DEBUG_HASHMAP
612 : i->prev_idx = idx;
613 : #endif
614 :
615 86344 : if (e->iterate_next != IDX_NIL) {
616 : struct ordered_hashmap_entry *n;
617 73926 : i->idx = e->iterate_next;
618 73926 : n = ordered_bucket_at(h, i->idx);
619 73926 : i->next_key = n->p.b.key;
620 : } else
621 12418 : i->idx = IDX_NIL;
622 :
623 86344 : return idx;
624 :
625 1465 : at_end:
626 1465 : i->idx = IDX_NIL;
627 1465 : return IDX_NIL;
628 : }
629 :
630 1067519 : static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
631 : unsigned idx;
632 :
633 1067519 : assert(h);
634 1067519 : assert(i);
635 :
636 1067519 : if (i->idx == IDX_NIL)
637 24494 : goto at_end;
638 :
639 1043025 : if (i->idx == IDX_FIRST) {
640 : /* fast forward to the first occupied bucket */
641 42690 : if (h->has_indirect) {
642 10241 : i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry);
643 10241 : h->indirect.idx_lowest_entry = i->idx;
644 : } else
645 32449 : i->idx = skip_free_buckets(h, 0);
646 :
647 42690 : if (i->idx == IDX_NIL)
648 1568 : goto at_end;
649 : } else {
650 : struct hashmap_base_entry *e;
651 :
652 1000335 : assert(i->idx > 0);
653 :
654 1000335 : e = bucket_at(h, i->idx);
655 : /*
656 : * We allow removing the current entry while iterating, but removal may cause
657 : * a backward shift. The next entry may thus move one bucket to the left.
658 : * To detect when it happens, we remember the key pointer of the entry we were
659 : * going to iterate next. If it does not match, there was a backward shift.
660 : */
661 1000335 : if (e->key != i->next_key)
662 0 : e = bucket_at(h, --i->idx);
663 :
664 1000335 : assert(e->key == i->next_key);
665 : }
666 :
667 1041457 : idx = i->idx;
668 : #if ENABLE_DEBUG_HASHMAP
669 : i->prev_idx = idx;
670 : #endif
671 :
672 1041457 : i->idx = skip_free_buckets(h, i->idx + 1);
673 1041457 : if (i->idx != IDX_NIL)
674 1008977 : i->next_key = bucket_at(h, i->idx)->key;
675 : else
676 32480 : i->idx = IDX_NIL;
677 :
678 1041457 : return idx;
679 :
680 26062 : at_end:
681 26062 : i->idx = IDX_NIL;
682 26062 : return IDX_NIL;
683 : }
684 :
685 1328951 : static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
686 1328951 : if (!h) {
687 173623 : i->idx = IDX_NIL;
688 173623 : return IDX_NIL;
689 : }
690 :
691 : #if ENABLE_DEBUG_HASHMAP
692 : if (i->idx == IDX_FIRST) {
693 : i->put_count = h->debug.put_count;
694 : i->rem_count = h->debug.rem_count;
695 : } else {
696 : /* While iterating, must not add any new entries */
697 : assert(i->put_count == h->debug.put_count);
698 : /* ... or remove entries other than the current one */
699 : assert(i->rem_count == h->debug.rem_count ||
700 : (i->rem_count == h->debug.rem_count - 1 &&
701 : i->prev_idx == h->debug.last_rem_idx));
702 : /* Reset our removals counter */
703 : i->rem_count = h->debug.rem_count;
704 : }
705 : #endif
706 :
707 87809 : return h->type == HASHMAP_TYPE_ORDERED ? hashmap_iterate_in_insertion_order((OrderedHashmap*) h, i)
708 1243137 : : hashmap_iterate_in_internal_order(h, i);
709 : }
710 :
711 749447 : bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
712 : struct hashmap_base_entry *e;
713 : void *data;
714 : unsigned idx;
715 :
716 749447 : idx = hashmap_iterate_entry(h, i);
717 749447 : if (idx == IDX_NIL) {
718 200031 : if (value)
719 200031 : *value = NULL;
720 200031 : if (key)
721 110098 : *key = NULL;
722 :
723 200031 : return false;
724 : }
725 :
726 549416 : e = bucket_at(h, idx);
727 549416 : data = entry_value(h, e);
728 549416 : if (value)
729 549416 : *value = data;
730 549416 : if (key)
731 512273 : *key = e->key;
732 :
733 549416 : return true;
734 : }
735 :
736 111487 : bool set_iterate(const Set *s, Iterator *i, void **value) {
737 111487 : return internal_hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL);
738 : }
739 :
740 : #define HASHMAP_FOREACH_IDX(idx, h, i) \
741 : for ((i) = ITERATOR_FIRST, (idx) = hashmap_iterate_entry((h), &(i)); \
742 : (idx != IDX_NIL); \
743 : (idx) = hashmap_iterate_entry((h), &(i)))
744 :
745 213 : IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h) {
746 : IteratedCache *cache;
747 :
748 213 : assert(h);
749 213 : assert(!h->cached);
750 :
751 213 : if (h->cached)
752 0 : return NULL;
753 :
754 213 : cache = new0(IteratedCache, 1);
755 213 : if (!cache)
756 0 : return NULL;
757 :
758 213 : cache->hashmap = h;
759 213 : h->cached = true;
760 :
761 213 : return cache;
762 : }
763 :
764 67698 : static void reset_direct_storage(HashmapBase *h) {
765 67698 : const struct hashmap_type_info *hi = &hashmap_type_info[h->type];
766 : void *p;
767 :
768 67698 : assert(!h->has_indirect);
769 :
770 67698 : p = mempset(h->direct.storage, 0, hi->entry_size * hi->n_direct_buckets);
771 67698 : memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
772 67698 : }
773 :
774 33819 : static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
775 : HashmapBase *h;
776 33819 : const struct hashmap_type_info *hi = &hashmap_type_info[type];
777 : bool up;
778 :
779 33819 : up = mempool_enabled();
780 :
781 33819 : h = up ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
782 33819 : if (!h)
783 0 : return NULL;
784 :
785 33819 : h->type = type;
786 33819 : h->from_pool = up;
787 33819 : h->hash_ops = hash_ops ?: &trivial_hash_ops;
788 :
789 33819 : if (type == HASHMAP_TYPE_ORDERED) {
790 21476 : OrderedHashmap *lh = (OrderedHashmap*)h;
791 21476 : lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
792 : }
793 :
794 33819 : reset_direct_storage(h);
795 :
796 33819 : if (!shared_hash_key_initialized) {
797 175 : random_bytes(shared_hash_key, sizeof(shared_hash_key));
798 175 : shared_hash_key_initialized= true;
799 : }
800 :
801 : #if ENABLE_DEBUG_HASHMAP
802 : h->debug.func = func;
803 : h->debug.file = file;
804 : h->debug.line = line;
805 : assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
806 : LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug);
807 : assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
808 : #endif
809 :
810 33819 : return h;
811 : }
812 :
813 1460 : Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
814 1460 : return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
815 : }
816 :
817 10262 : OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
818 10262 : return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
819 : }
820 :
821 5493 : Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
822 5493 : return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
823 : }
824 :
825 83471 : static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops,
826 : enum HashmapType type HASHMAP_DEBUG_PARAMS) {
827 : HashmapBase *q;
828 :
829 83471 : assert(h);
830 :
831 83471 : if (*h)
832 66869 : return 0;
833 :
834 16602 : q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS);
835 16602 : if (!q)
836 0 : return -ENOMEM;
837 :
838 16602 : *h = q;
839 16602 : return 0;
840 : }
841 :
842 22541 : int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
843 22541 : return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
844 : }
845 :
846 58164 : int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
847 58164 : return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
848 : }
849 :
850 2766 : int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
851 2766 : return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
852 : }
853 :
854 33818 : static void hashmap_free_no_clear(HashmapBase *h) {
855 33818 : assert(!h->has_indirect);
856 33818 : assert(h->n_direct_entries == 0);
857 :
858 : #if ENABLE_DEBUG_HASHMAP
859 : assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
860 : LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
861 : assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
862 : #endif
863 :
864 33818 : if (h->from_pool) {
865 : /* Ensure that the object didn't get migrated between threads. */
866 33789 : assert_se(is_main_thread());
867 33789 : mempool_free_tile(hashmap_type_info[h->type].mempool, h);
868 : } else
869 29 : free(h);
870 33818 : }
871 :
872 140695 : HashmapBase *internal_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
873 140695 : if (h) {
874 33818 : internal_hashmap_clear(h, default_free_key, default_free_value);
875 33818 : hashmap_free_no_clear(h);
876 : }
877 :
878 140695 : return NULL;
879 : }
880 :
881 33882 : void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
882 : free_func_t free_key, free_value;
883 33882 : if (!h)
884 3 : return;
885 :
886 33879 : free_key = h->hash_ops->free_key ?: default_free_key;
887 33879 : free_value = h->hash_ops->free_value ?: default_free_value;
888 :
889 33879 : if (free_key || free_value) {
890 :
891 : /* If destructor calls are defined, let's destroy things defensively: let's take the item out of the
892 : * hash table, and only then call the destructor functions. If these destructors then try to unregister
893 : * themselves from our hash table a second time, the entry is already gone. */
894 :
895 94302 : while (internal_hashmap_size(h) > 0) {
896 66532 : void *k = NULL;
897 : void *v;
898 :
899 66532 : v = internal_hashmap_first_key_and_value(h, true, &k);
900 :
901 66532 : if (free_key)
902 66279 : free_key(k);
903 :
904 66532 : if (free_value)
905 61065 : free_value(v);
906 : }
907 : }
908 :
909 33879 : if (h->has_indirect) {
910 10583 : free(h->indirect.storage);
911 10583 : h->has_indirect = false;
912 : }
913 :
914 33879 : h->n_direct_entries = 0;
915 33879 : reset_direct_storage(h);
916 :
917 33879 : if (h->type == HASHMAP_TYPE_ORDERED) {
918 21501 : OrderedHashmap *lh = (OrderedHashmap*) h;
919 21501 : lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
920 : }
921 :
922 33879 : base_set_dirty(h);
923 : }
924 :
925 : static int resize_buckets(HashmapBase *h, unsigned entries_add);
926 :
927 : /*
928 : * Finds an empty bucket to put an entry into, starting the scan at 'idx'.
929 : * Performs Robin Hood swaps as it goes. The entry to put must be placed
930 : * by the caller into swap slot IDX_PUT.
931 : * If used for in-place resizing, may leave a displaced entry in swap slot
932 : * IDX_PUT. Caller must rehash it next.
933 : * Returns: true if it left a displaced entry to rehash next in IDX_PUT,
934 : * false otherwise.
935 : */
936 225427 : static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
937 : struct swap_entries *swap) {
938 : dib_raw_t raw_dib, *dibs;
939 : unsigned dib, distance;
940 :
941 : #if ENABLE_DEBUG_HASHMAP
942 : h->debug.put_count++;
943 : #endif
944 :
945 225427 : dibs = dib_raw_ptr(h);
946 :
947 225427 : for (distance = 0; ; distance++) {
948 191128 : raw_dib = dibs[idx];
949 416555 : if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
950 225427 : if (raw_dib == DIB_RAW_REHASH)
951 21056 : bucket_move_entry(h, swap, idx, IDX_TMP);
952 :
953 225427 : if (h->has_indirect && h->indirect.idx_lowest_entry > idx)
954 33 : h->indirect.idx_lowest_entry = idx;
955 :
956 225427 : bucket_set_dib(h, idx, distance);
957 225427 : bucket_move_entry(h, swap, IDX_PUT, idx);
958 225427 : if (raw_dib == DIB_RAW_REHASH) {
959 21056 : bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
960 21056 : return true;
961 : }
962 :
963 204371 : return false;
964 : }
965 :
966 191128 : dib = bucket_calculate_dib(h, idx, raw_dib);
967 :
968 191128 : if (dib < distance) {
969 : /* Found a wealthier entry. Go Robin Hood! */
970 73354 : bucket_set_dib(h, idx, distance);
971 :
972 : /* swap the entries */
973 73354 : bucket_move_entry(h, swap, idx, IDX_TMP);
974 73354 : bucket_move_entry(h, swap, IDX_PUT, idx);
975 73354 : bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
976 :
977 73354 : distance = dib;
978 : }
979 :
980 191128 : idx = next_idx(h, idx);
981 : }
982 : }
983 :
984 : /*
985 : * Puts an entry into a hashmap, boldly - no check whether key already exists.
986 : * The caller must place the entry (only its key and value, not link indexes)
987 : * in swap slot IDX_PUT.
988 : * Caller must ensure: the key does not exist yet in the hashmap.
989 : * that resize is not needed if !may_resize.
990 : * Returns: 1 if entry was put successfully.
991 : * -ENOMEM if may_resize==true and resize failed with -ENOMEM.
992 : * Cannot return -ENOMEM if !may_resize.
993 : */
994 119283 : static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
995 : struct swap_entries *swap, bool may_resize) {
996 : struct ordered_hashmap_entry *new_entry;
997 : int r;
998 :
999 119283 : assert(idx < n_buckets(h));
1000 :
1001 119283 : new_entry = bucket_at_swap(swap, IDX_PUT);
1002 :
1003 119283 : if (may_resize) {
1004 118345 : r = resize_buckets(h, 1);
1005 118345 : if (r < 0)
1006 0 : return r;
1007 118345 : if (r > 0)
1008 18327 : idx = bucket_hash(h, new_entry->p.b.key);
1009 : }
1010 119283 : assert(n_entries(h) < n_buckets(h));
1011 :
1012 119283 : if (h->type == HASHMAP_TYPE_ORDERED) {
1013 69037 : OrderedHashmap *lh = (OrderedHashmap*) h;
1014 :
1015 69037 : new_entry->iterate_next = IDX_NIL;
1016 69037 : new_entry->iterate_previous = lh->iterate_list_tail;
1017 :
1018 69037 : if (lh->iterate_list_tail != IDX_NIL) {
1019 : struct ordered_hashmap_entry *old_tail;
1020 :
1021 57557 : old_tail = ordered_bucket_at(lh, lh->iterate_list_tail);
1022 57557 : assert(old_tail->iterate_next == IDX_NIL);
1023 57557 : old_tail->iterate_next = IDX_PUT;
1024 : }
1025 :
1026 69037 : lh->iterate_list_tail = IDX_PUT;
1027 69037 : if (lh->iterate_list_head == IDX_NIL)
1028 11480 : lh->iterate_list_head = IDX_PUT;
1029 : }
1030 :
1031 119283 : assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
1032 :
1033 119283 : n_entries_inc(h);
1034 : #if ENABLE_DEBUG_HASHMAP
1035 : h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
1036 : #endif
1037 :
1038 119283 : base_set_dirty(h);
1039 :
1040 119283 : return 1;
1041 : }
1042 : #define hashmap_put_boldly(h, idx, swap, may_resize) \
1043 : hashmap_base_put_boldly(HASHMAP_BASE(h), idx, swap, may_resize)
1044 :
1045 : /*
1046 : * Returns 0 if resize is not needed.
1047 : * 1 if successfully resized.
1048 : * -ENOMEM on allocation failure.
1049 : */
1050 118382 : static int resize_buckets(HashmapBase *h, unsigned entries_add) {
1051 : struct swap_entries swap;
1052 : void *new_storage;
1053 : dib_raw_t *old_dibs, *new_dibs;
1054 : const struct hashmap_type_info *hi;
1055 : unsigned idx, optimal_idx;
1056 : unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries;
1057 : uint8_t new_shift;
1058 : bool rehash_next;
1059 :
1060 118382 : assert(h);
1061 :
1062 118382 : hi = &hashmap_type_info[h->type];
1063 118382 : new_n_entries = n_entries(h) + entries_add;
1064 :
1065 : /* overflow? */
1066 118382 : if (_unlikely_(new_n_entries < entries_add))
1067 2 : return -ENOMEM;
1068 :
1069 : /* For direct storage we allow 100% load, because it's tiny. */
1070 118380 : if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets)
1071 26253 : return 0;
1072 :
1073 : /*
1074 : * Load factor = n/m = 1 - (1/INV_KEEP_FREE).
1075 : * From it follows: m = n + n/(INV_KEEP_FREE - 1)
1076 : */
1077 92127 : new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1);
1078 : /* overflow? */
1079 92127 : if (_unlikely_(new_n_buckets < new_n_entries))
1080 2 : return -ENOMEM;
1081 :
1082 92125 : if (_unlikely_(new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t))))
1083 0 : return -ENOMEM;
1084 :
1085 92125 : old_n_buckets = n_buckets(h);
1086 :
1087 92125 : if (_likely_(new_n_buckets <= old_n_buckets))
1088 73794 : return 0;
1089 :
1090 18331 : new_shift = log2u_round_up(MAX(
1091 : new_n_buckets * (hi->entry_size + sizeof(dib_raw_t)),
1092 : 2 * sizeof(struct direct_storage)));
1093 :
1094 : /* Realloc storage (buckets and DIB array). */
1095 18331 : new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL,
1096 18331 : 1U << new_shift);
1097 18331 : if (!new_storage)
1098 0 : return -ENOMEM;
1099 :
1100 : /* Must upgrade direct to indirect storage. */
1101 18331 : if (!h->has_indirect) {
1102 21166 : memcpy(new_storage, h->direct.storage,
1103 10583 : old_n_buckets * (hi->entry_size + sizeof(dib_raw_t)));
1104 10583 : h->indirect.n_entries = h->n_direct_entries;
1105 10583 : h->indirect.idx_lowest_entry = 0;
1106 10583 : h->n_direct_entries = 0;
1107 : }
1108 :
1109 : /* Get a new hash key. If we've just upgraded to indirect storage,
1110 : * allow reusing a previously generated key. It's still a different key
1111 : * from the shared one that we used for direct storage. */
1112 18331 : get_hash_key(h->indirect.hash_key, !h->has_indirect);
1113 :
1114 18331 : h->has_indirect = true;
1115 18331 : h->indirect.storage = new_storage;
1116 36662 : h->indirect.n_buckets = (1U << new_shift) /
1117 18331 : (hi->entry_size + sizeof(dib_raw_t));
1118 :
1119 18331 : old_dibs = (dib_raw_t*)((uint8_t*) new_storage + hi->entry_size * old_n_buckets);
1120 18331 : new_dibs = dib_raw_ptr(h);
1121 :
1122 : /*
1123 : * Move the DIB array to the new place, replacing valid DIB values with
1124 : * DIB_RAW_REHASH to indicate all of the used buckets need rehashing.
1125 : * Note: Overlap is not possible, because we have at least doubled the
1126 : * number of buckets and dib_raw_t is smaller than any entry type.
1127 : */
1128 152867 : for (idx = 0; idx < old_n_buckets; idx++) {
1129 134536 : assert(old_dibs[idx] != DIB_RAW_REHASH);
1130 134536 : new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE
1131 : : DIB_RAW_REHASH;
1132 : }
1133 :
1134 : /* Zero the area of newly added entries (including the old DIB area) */
1135 18331 : memzero(bucket_at(h, old_n_buckets),
1136 : (n_buckets(h) - old_n_buckets) * hi->entry_size);
1137 :
1138 : /* The upper half of the new DIB array needs initialization */
1139 18331 : memset(&new_dibs[old_n_buckets], DIB_RAW_INIT,
1140 18331 : (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t));
1141 :
1142 : /* Rehash entries that need it */
1143 18331 : n_rehashed = 0;
1144 152867 : for (idx = 0; idx < old_n_buckets; idx++) {
1145 134536 : if (new_dibs[idx] != DIB_RAW_REHASH)
1146 45264 : continue;
1147 :
1148 89272 : optimal_idx = bucket_hash(h, bucket_at(h, idx)->key);
1149 :
1150 : /*
1151 : * Not much to do if by luck the entry hashes to its current
1152 : * location. Just set its DIB.
1153 : */
1154 89272 : if (optimal_idx == idx) {
1155 4184 : new_dibs[idx] = 0;
1156 4184 : n_rehashed++;
1157 4184 : continue;
1158 : }
1159 :
1160 85088 : new_dibs[idx] = DIB_RAW_FREE;
1161 85088 : bucket_move_entry(h, &swap, idx, IDX_PUT);
1162 : /* bucket_move_entry does not clear the source */
1163 85088 : memzero(bucket_at(h, idx), hi->entry_size);
1164 :
1165 : do {
1166 : /*
1167 : * Find the new bucket for the current entry. This may make
1168 : * another entry homeless and load it into IDX_PUT.
1169 : */
1170 106144 : rehash_next = hashmap_put_robin_hood(h, optimal_idx, &swap);
1171 106144 : n_rehashed++;
1172 :
1173 : /* Did the current entry displace another one? */
1174 106144 : if (rehash_next)
1175 21056 : optimal_idx = bucket_hash(h, bucket_at_swap(&swap, IDX_PUT)->p.b.key);
1176 106144 : } while (rehash_next);
1177 : }
1178 :
1179 18331 : assert(n_rehashed == n_entries(h));
1180 :
1181 18331 : return 1;
1182 : }
1183 :
1184 : /*
1185 : * Finds an entry with a matching key
1186 : * Returns: index of the found entry, or IDX_NIL if not found.
1187 : */
1188 360470 : static unsigned base_bucket_scan(HashmapBase *h, unsigned idx, const void *key) {
1189 : struct hashmap_base_entry *e;
1190 : unsigned dib, distance;
1191 360470 : dib_raw_t *dibs = dib_raw_ptr(h);
1192 :
1193 360470 : assert(idx < n_buckets(h));
1194 :
1195 360470 : for (distance = 0; ; distance++) {
1196 579740 : if (dibs[idx] == DIB_RAW_FREE)
1197 180250 : return IDX_NIL;
1198 :
1199 399490 : dib = bucket_calculate_dib(h, idx, dibs[idx]);
1200 :
1201 399490 : if (dib < distance)
1202 83556 : return IDX_NIL;
1203 315934 : if (dib == distance) {
1204 240369 : e = bucket_at(h, idx);
1205 240369 : if (h->hash_ops->compare(e->key, key) == 0)
1206 96664 : return idx;
1207 : }
1208 :
1209 219270 : idx = next_idx(h, idx);
1210 : }
1211 : }
1212 : #define bucket_scan(h, idx, key) base_bucket_scan(HASHMAP_BASE(h), idx, key)
1213 :
1214 47271 : int hashmap_put(Hashmap *h, const void *key, void *value) {
1215 : struct swap_entries swap;
1216 : struct plain_hashmap_entry *e;
1217 : unsigned hash, idx;
1218 :
1219 47271 : assert(h);
1220 :
1221 47271 : hash = bucket_hash(h, key);
1222 47271 : idx = bucket_scan(h, hash, key);
1223 47271 : if (idx != IDX_NIL) {
1224 18 : e = plain_bucket_at(h, idx);
1225 18 : if (e->value == value)
1226 7 : return 0;
1227 11 : return -EEXIST;
1228 : }
1229 :
1230 47253 : e = &bucket_at_swap(&swap, IDX_PUT)->p;
1231 47253 : e->b.key = key;
1232 47253 : e->value = value;
1233 47253 : return hashmap_put_boldly(h, hash, &swap, true);
1234 : }
1235 :
1236 13500 : int set_put(Set *s, const void *key) {
1237 : struct swap_entries swap;
1238 : struct hashmap_base_entry *e;
1239 : unsigned hash, idx;
1240 :
1241 13500 : assert(s);
1242 :
1243 13500 : hash = bucket_hash(s, key);
1244 13500 : idx = bucket_scan(s, hash, key);
1245 13500 : if (idx != IDX_NIL)
1246 89 : return 0;
1247 :
1248 13411 : e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1249 13411 : e->key = key;
1250 13411 : return hashmap_put_boldly(s, hash, &swap, true);
1251 : }
1252 :
1253 59091 : int hashmap_replace(Hashmap *h, const void *key, void *value) {
1254 : struct swap_entries swap;
1255 : struct plain_hashmap_entry *e;
1256 : unsigned hash, idx;
1257 :
1258 59091 : assert(h);
1259 :
1260 59091 : hash = bucket_hash(h, key);
1261 59091 : idx = bucket_scan(h, hash, key);
1262 59091 : if (idx != IDX_NIL) {
1263 1488 : e = plain_bucket_at(h, idx);
1264 : #if ENABLE_DEBUG_HASHMAP
1265 : /* Although the key is equal, the key pointer may have changed,
1266 : * and this would break our assumption for iterating. So count
1267 : * this operation as incompatible with iteration. */
1268 : if (e->b.key != key) {
1269 : h->b.debug.put_count++;
1270 : h->b.debug.rem_count++;
1271 : h->b.debug.last_rem_idx = idx;
1272 : }
1273 : #endif
1274 1488 : e->b.key = key;
1275 1488 : e->value = value;
1276 1488 : hashmap_set_dirty(h);
1277 :
1278 1488 : return 0;
1279 : }
1280 :
1281 57603 : e = &bucket_at_swap(&swap, IDX_PUT)->p;
1282 57603 : e->b.key = key;
1283 57603 : e->value = value;
1284 57603 : return hashmap_put_boldly(h, hash, &swap, true);
1285 : }
1286 :
1287 256 : int hashmap_update(Hashmap *h, const void *key, void *value) {
1288 : struct plain_hashmap_entry *e;
1289 : unsigned hash, idx;
1290 :
1291 256 : assert(h);
1292 :
1293 256 : hash = bucket_hash(h, key);
1294 256 : idx = bucket_scan(h, hash, key);
1295 256 : if (idx == IDX_NIL)
1296 2 : return -ENOENT;
1297 :
1298 254 : e = plain_bucket_at(h, idx);
1299 254 : e->value = value;
1300 254 : hashmap_set_dirty(h);
1301 :
1302 254 : return 0;
1303 : }
1304 :
1305 138922 : void *internal_hashmap_get(HashmapBase *h, const void *key) {
1306 : struct hashmap_base_entry *e;
1307 : unsigned hash, idx;
1308 :
1309 138922 : if (!h)
1310 2516 : return NULL;
1311 :
1312 136406 : hash = bucket_hash(h, key);
1313 136406 : idx = bucket_scan(h, hash, key);
1314 136406 : if (idx == IDX_NIL)
1315 66668 : return NULL;
1316 :
1317 69738 : e = bucket_at(h, idx);
1318 69738 : return entry_value(h, e);
1319 : }
1320 :
1321 58915 : void *hashmap_get2(Hashmap *h, const void *key, void **key2) {
1322 : struct plain_hashmap_entry *e;
1323 : unsigned hash, idx;
1324 :
1325 58915 : if (!h)
1326 1129 : return NULL;
1327 :
1328 57786 : hash = bucket_hash(h, key);
1329 57786 : idx = bucket_scan(h, hash, key);
1330 57786 : if (idx == IDX_NIL)
1331 56764 : return NULL;
1332 :
1333 1022 : e = plain_bucket_at(h, idx);
1334 1022 : if (key2)
1335 1022 : *key2 = (void*) e->b.key;
1336 :
1337 1022 : return e->value;
1338 : }
1339 :
1340 14261 : bool internal_hashmap_contains(HashmapBase *h, const void *key) {
1341 : unsigned hash;
1342 :
1343 14261 : if (!h)
1344 14 : return false;
1345 :
1346 14247 : hash = bucket_hash(h, key);
1347 14247 : return bucket_scan(h, hash, key) != IDX_NIL;
1348 : }
1349 :
1350 70149 : void *internal_hashmap_remove(HashmapBase *h, const void *key) {
1351 : struct hashmap_base_entry *e;
1352 : unsigned hash, idx;
1353 : void *data;
1354 :
1355 70149 : if (!h)
1356 45606 : return NULL;
1357 :
1358 24543 : hash = bucket_hash(h, key);
1359 24543 : idx = bucket_scan(h, hash, key);
1360 24543 : if (idx == IDX_NIL)
1361 7504 : return NULL;
1362 :
1363 17039 : e = bucket_at(h, idx);
1364 17039 : data = entry_value(h, e);
1365 17039 : remove_entry(h, idx);
1366 :
1367 17039 : return data;
1368 : }
1369 :
1370 1458 : void *hashmap_remove2(Hashmap *h, const void *key, void **rkey) {
1371 : struct plain_hashmap_entry *e;
1372 : unsigned hash, idx;
1373 : void *data;
1374 :
1375 1458 : if (!h) {
1376 53 : if (rkey)
1377 53 : *rkey = NULL;
1378 53 : return NULL;
1379 : }
1380 :
1381 1405 : hash = bucket_hash(h, key);
1382 1405 : idx = bucket_scan(h, hash, key);
1383 1405 : if (idx == IDX_NIL) {
1384 1403 : if (rkey)
1385 1403 : *rkey = NULL;
1386 1403 : return NULL;
1387 : }
1388 :
1389 2 : e = plain_bucket_at(h, idx);
1390 2 : data = e->value;
1391 2 : if (rkey)
1392 2 : *rkey = (void*) e->b.key;
1393 :
1394 2 : remove_entry(h, idx);
1395 :
1396 2 : return data;
1397 : }
1398 :
1399 8 : int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
1400 : struct swap_entries swap;
1401 : struct plain_hashmap_entry *e;
1402 : unsigned old_hash, new_hash, idx;
1403 :
1404 8 : if (!h)
1405 2 : return -ENOENT;
1406 :
1407 6 : old_hash = bucket_hash(h, old_key);
1408 6 : idx = bucket_scan(h, old_hash, old_key);
1409 6 : if (idx == IDX_NIL)
1410 2 : return -ENOENT;
1411 :
1412 4 : new_hash = bucket_hash(h, new_key);
1413 4 : if (bucket_scan(h, new_hash, new_key) != IDX_NIL)
1414 2 : return -EEXIST;
1415 :
1416 2 : remove_entry(h, idx);
1417 :
1418 2 : e = &bucket_at_swap(&swap, IDX_PUT)->p;
1419 2 : e->b.key = new_key;
1420 2 : e->value = value;
1421 2 : assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
1422 :
1423 2 : return 0;
1424 : }
1425 :
1426 0 : int set_remove_and_put(Set *s, const void *old_key, const void *new_key) {
1427 : struct swap_entries swap;
1428 : struct hashmap_base_entry *e;
1429 : unsigned old_hash, new_hash, idx;
1430 :
1431 0 : if (!s)
1432 0 : return -ENOENT;
1433 :
1434 0 : old_hash = bucket_hash(s, old_key);
1435 0 : idx = bucket_scan(s, old_hash, old_key);
1436 0 : if (idx == IDX_NIL)
1437 0 : return -ENOENT;
1438 :
1439 0 : new_hash = bucket_hash(s, new_key);
1440 0 : if (bucket_scan(s, new_hash, new_key) != IDX_NIL)
1441 0 : return -EEXIST;
1442 :
1443 0 : remove_entry(s, idx);
1444 :
1445 0 : e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1446 0 : e->key = new_key;
1447 0 : assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1);
1448 :
1449 0 : return 0;
1450 : }
1451 :
1452 917 : int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) {
1453 : struct swap_entries swap;
1454 : struct plain_hashmap_entry *e;
1455 : unsigned old_hash, new_hash, idx_old, idx_new;
1456 :
1457 917 : if (!h)
1458 2 : return -ENOENT;
1459 :
1460 915 : old_hash = bucket_hash(h, old_key);
1461 915 : idx_old = bucket_scan(h, old_hash, old_key);
1462 915 : if (idx_old == IDX_NIL)
1463 2 : return -ENOENT;
1464 :
1465 913 : old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key;
1466 :
1467 913 : new_hash = bucket_hash(h, new_key);
1468 913 : idx_new = bucket_scan(h, new_hash, new_key);
1469 913 : if (idx_new != IDX_NIL)
1470 911 : if (idx_old != idx_new) {
1471 42 : remove_entry(h, idx_new);
1472 : /* Compensate for a possible backward shift. */
1473 42 : if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key)
1474 5 : idx_old = prev_idx(HASHMAP_BASE(h), idx_old);
1475 42 : assert(old_key == bucket_at(HASHMAP_BASE(h), idx_old)->key);
1476 : }
1477 :
1478 913 : remove_entry(h, idx_old);
1479 :
1480 913 : e = &bucket_at_swap(&swap, IDX_PUT)->p;
1481 913 : e->b.key = new_key;
1482 913 : e->value = value;
1483 913 : assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
1484 :
1485 913 : return 0;
1486 : }
1487 :
1488 3931 : void *internal_hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
1489 : struct hashmap_base_entry *e;
1490 : unsigned hash, idx;
1491 :
1492 3931 : if (!h)
1493 2 : return NULL;
1494 :
1495 3929 : hash = bucket_hash(h, key);
1496 3929 : idx = bucket_scan(h, hash, key);
1497 3929 : if (idx == IDX_NIL)
1498 78 : return NULL;
1499 :
1500 3851 : e = bucket_at(h, idx);
1501 3851 : if (entry_value(h, e) != value)
1502 2 : return NULL;
1503 :
1504 3849 : remove_entry(h, idx);
1505 :
1506 3849 : return value;
1507 : }
1508 :
1509 110869 : static unsigned find_first_entry(HashmapBase *h) {
1510 110869 : Iterator i = ITERATOR_FIRST;
1511 :
1512 110869 : if (!h || !n_entries(h))
1513 25718 : return IDX_NIL;
1514 :
1515 85151 : return hashmap_iterate_entry(h, &i);
1516 : }
1517 :
1518 110869 : void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
1519 : struct hashmap_base_entry *e;
1520 : void *key, *data;
1521 : unsigned idx;
1522 :
1523 110869 : idx = find_first_entry(h);
1524 110869 : if (idx == IDX_NIL) {
1525 25718 : if (ret_key)
1526 3425 : *ret_key = NULL;
1527 25718 : return NULL;
1528 : }
1529 :
1530 85151 : e = bucket_at(h, idx);
1531 85151 : key = (void*) e->key;
1532 85151 : data = entry_value(h, e);
1533 :
1534 85151 : if (remove)
1535 81751 : remove_entry(h, idx);
1536 :
1537 85151 : if (ret_key)
1538 67633 : *ret_key = key;
1539 :
1540 85151 : return data;
1541 : }
1542 :
1543 155695 : unsigned internal_hashmap_size(HashmapBase *h) {
1544 155695 : if (!h)
1545 36796 : return 0;
1546 :
1547 118899 : return n_entries(h);
1548 : }
1549 :
1550 20 : unsigned internal_hashmap_buckets(HashmapBase *h) {
1551 20 : if (!h)
1552 2 : return 0;
1553 :
1554 18 : return n_buckets(h);
1555 : }
1556 :
1557 4 : int internal_hashmap_merge(Hashmap *h, Hashmap *other) {
1558 : Iterator i;
1559 : unsigned idx;
1560 :
1561 4 : assert(h);
1562 :
1563 16 : HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
1564 12 : struct plain_hashmap_entry *pe = plain_bucket_at(other, idx);
1565 : int r;
1566 :
1567 12 : r = hashmap_put(h, pe->b.key, pe->value);
1568 12 : if (r < 0 && r != -EEXIST)
1569 0 : return r;
1570 : }
1571 :
1572 4 : return 0;
1573 : }
1574 :
1575 0 : int set_merge(Set *s, Set *other) {
1576 : Iterator i;
1577 : unsigned idx;
1578 :
1579 0 : assert(s);
1580 :
1581 0 : HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
1582 0 : struct set_entry *se = set_bucket_at(other, idx);
1583 : int r;
1584 :
1585 0 : r = set_put(s, se->b.key);
1586 0 : if (r < 0)
1587 0 : return r;
1588 : }
1589 :
1590 0 : return 0;
1591 : }
1592 :
1593 8 : int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) {
1594 : int r;
1595 :
1596 8 : assert(h);
1597 :
1598 8 : r = resize_buckets(h, entries_add);
1599 8 : if (r < 0)
1600 4 : return r;
1601 :
1602 4 : return 0;
1603 : }
1604 :
1605 : /*
1606 : * The same as hashmap_merge(), but every new item from other is moved to h.
1607 : * Keys already in h are skipped and stay in other.
1608 : * Returns: 0 on success.
1609 : * -ENOMEM on alloc failure, in which case no move has been done.
1610 : */
1611 31 : int internal_hashmap_move(HashmapBase *h, HashmapBase *other) {
1612 : struct swap_entries swap;
1613 : struct hashmap_base_entry *e, *n;
1614 : Iterator i;
1615 : unsigned idx;
1616 : int r;
1617 :
1618 31 : assert(h);
1619 :
1620 31 : if (!other)
1621 2 : return 0;
1622 :
1623 29 : assert(other->type == h->type);
1624 :
1625 : /*
1626 : * This reserves buckets for the worst case, where none of other's
1627 : * entries are yet present in h. This is preferable to risking
1628 : * an allocation failure in the middle of the moving and having to
1629 : * rollback or return a partial result.
1630 : */
1631 29 : r = resize_buckets(h, n_entries(other));
1632 29 : if (r < 0)
1633 0 : return r;
1634 :
1635 54 : HASHMAP_FOREACH_IDX(idx, other, i) {
1636 : unsigned h_hash;
1637 :
1638 25 : e = bucket_at(other, idx);
1639 25 : h_hash = bucket_hash(h, e->key);
1640 25 : if (bucket_scan(h, h_hash, e->key) != IDX_NIL)
1641 2 : continue;
1642 :
1643 23 : n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1644 23 : n->key = e->key;
1645 23 : if (h->type != HASHMAP_TYPE_SET)
1646 6 : ((struct plain_hashmap_entry*) n)->value =
1647 6 : ((struct plain_hashmap_entry*) e)->value;
1648 23 : assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1);
1649 :
1650 23 : remove_entry(other, idx);
1651 : }
1652 :
1653 29 : return 0;
1654 : }
1655 :
1656 84 : int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
1657 : struct swap_entries swap;
1658 : unsigned h_hash, other_hash, idx;
1659 : struct hashmap_base_entry *e, *n;
1660 : int r;
1661 :
1662 84 : assert(h);
1663 :
1664 84 : h_hash = bucket_hash(h, key);
1665 84 : if (bucket_scan(h, h_hash, key) != IDX_NIL)
1666 2 : return -EEXIST;
1667 :
1668 82 : if (!other)
1669 2 : return -ENOENT;
1670 :
1671 80 : assert(other->type == h->type);
1672 :
1673 80 : other_hash = bucket_hash(other, key);
1674 80 : idx = bucket_scan(other, other_hash, key);
1675 80 : if (idx == IDX_NIL)
1676 2 : return -ENOENT;
1677 :
1678 78 : e = bucket_at(other, idx);
1679 :
1680 78 : n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1681 78 : n->key = e->key;
1682 78 : if (h->type != HASHMAP_TYPE_SET)
1683 78 : ((struct plain_hashmap_entry*) n)->value =
1684 78 : ((struct plain_hashmap_entry*) e)->value;
1685 78 : r = hashmap_put_boldly(h, h_hash, &swap, true);
1686 78 : if (r < 0)
1687 0 : return r;
1688 :
1689 78 : remove_entry(other, idx);
1690 78 : return 0;
1691 : }
1692 :
1693 2 : HashmapBase *internal_hashmap_copy(HashmapBase *h) {
1694 : HashmapBase *copy;
1695 : int r;
1696 :
1697 2 : assert(h);
1698 :
1699 2 : copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS);
1700 2 : if (!copy)
1701 0 : return NULL;
1702 :
1703 2 : switch (h->type) {
1704 2 : case HASHMAP_TYPE_PLAIN:
1705 : case HASHMAP_TYPE_ORDERED:
1706 2 : r = hashmap_merge((Hashmap*)copy, (Hashmap*)h);
1707 2 : break;
1708 0 : case HASHMAP_TYPE_SET:
1709 0 : r = set_merge((Set*)copy, (Set*)h);
1710 0 : break;
1711 0 : default:
1712 0 : assert_not_reached("Unknown hashmap type");
1713 : }
1714 :
1715 2 : if (r < 0) {
1716 0 : internal_hashmap_free(copy, false, false);
1717 0 : return NULL;
1718 : }
1719 :
1720 2 : return copy;
1721 : }
1722 :
1723 963 : char **internal_hashmap_get_strv(HashmapBase *h) {
1724 : char **sv;
1725 : Iterator i;
1726 : unsigned idx, n;
1727 :
1728 963 : sv = new(char*, n_entries(h)+1);
1729 963 : if (!sv)
1730 0 : return NULL;
1731 :
1732 963 : n = 0;
1733 2445 : HASHMAP_FOREACH_IDX(idx, h, i)
1734 1482 : sv[n++] = entry_value(h, bucket_at(h, idx));
1735 963 : sv[n] = NULL;
1736 :
1737 963 : return sv;
1738 : }
1739 :
1740 10 : void *ordered_hashmap_next(OrderedHashmap *h, const void *key) {
1741 : struct ordered_hashmap_entry *e;
1742 : unsigned hash, idx;
1743 :
1744 10 : if (!h)
1745 1 : return NULL;
1746 :
1747 9 : hash = bucket_hash(h, key);
1748 9 : idx = bucket_scan(h, hash, key);
1749 9 : if (idx == IDX_NIL)
1750 1 : return NULL;
1751 :
1752 8 : e = ordered_bucket_at(h, idx);
1753 8 : if (e->iterate_next == IDX_NIL)
1754 2 : return NULL;
1755 6 : return ordered_bucket_at(h, e->iterate_next)->p.value;
1756 : }
1757 :
1758 7885 : int set_consume(Set *s, void *value) {
1759 : int r;
1760 :
1761 7885 : assert(s);
1762 7885 : assert(value);
1763 :
1764 7885 : r = set_put(s, value);
1765 7885 : if (r <= 0)
1766 59 : free(value);
1767 :
1768 7885 : return r;
1769 : }
1770 :
1771 825 : int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) {
1772 : int r;
1773 :
1774 825 : r = hashmap_ensure_allocated(h, &string_hash_ops_free_free);
1775 825 : if (r < 0)
1776 0 : return r;
1777 :
1778 825 : _cleanup_free_ char *kdup = NULL, *vdup = NULL;
1779 825 : kdup = strdup(k);
1780 825 : vdup = strdup(v);
1781 825 : if (!kdup || !vdup)
1782 0 : return -ENOMEM;
1783 :
1784 825 : r = hashmap_put(*h, kdup, vdup);
1785 825 : if (r < 0) {
1786 0 : if (r == -EEXIST && streq(v, hashmap_get(*h, kdup)))
1787 0 : return 0;
1788 0 : return r;
1789 : }
1790 :
1791 825 : assert(r > 0); /* 0 would mean vdup is already in the hashmap, which cannot be */
1792 825 : kdup = vdup = NULL;
1793 :
1794 825 : return 0;
1795 : }
1796 :
1797 4876 : int set_put_strdup(Set *s, const char *p) {
1798 : char *c;
1799 :
1800 4876 : assert(s);
1801 4876 : assert(p);
1802 :
1803 4876 : if (set_contains(s, (char*) p))
1804 88 : return 0;
1805 :
1806 4788 : c = strdup(p);
1807 4788 : if (!c)
1808 0 : return -ENOMEM;
1809 :
1810 4788 : return set_consume(s, c);
1811 : }
1812 :
1813 0 : int set_put_strdupv(Set *s, char **l) {
1814 0 : int n = 0, r;
1815 : char **i;
1816 :
1817 0 : assert(s);
1818 :
1819 0 : STRV_FOREACH(i, l) {
1820 0 : r = set_put_strdup(s, *i);
1821 0 : if (r < 0)
1822 0 : return r;
1823 :
1824 0 : n += r;
1825 : }
1826 :
1827 0 : return n;
1828 : }
1829 :
1830 0 : int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
1831 0 : const char *p = v;
1832 : int r;
1833 :
1834 0 : assert(s);
1835 0 : assert(v);
1836 :
1837 0 : for (;;) {
1838 : char *word;
1839 :
1840 0 : r = extract_first_word(&p, &word, separators, flags);
1841 0 : if (r <= 0)
1842 0 : return r;
1843 :
1844 0 : r = set_consume(s, word);
1845 0 : if (r < 0)
1846 0 : return r;
1847 : }
1848 : }
1849 :
1850 : /* expand the cachemem if needed, return true if newly (re)activated. */
1851 10613 : static int cachemem_maintain(CacheMem *mem, unsigned size) {
1852 10613 : assert(mem);
1853 :
1854 10613 : if (!GREEDY_REALLOC(mem->ptr, mem->n_allocated, size)) {
1855 2 : if (size > 0)
1856 0 : return -ENOMEM;
1857 : }
1858 :
1859 10613 : if (!mem->active) {
1860 13 : mem->active = true;
1861 13 : return true;
1862 : }
1863 :
1864 10600 : return false;
1865 : }
1866 :
1867 10501 : int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries) {
1868 10501 : bool sync_keys = false, sync_values = false;
1869 : unsigned size;
1870 : int r;
1871 :
1872 10501 : assert(cache);
1873 10501 : assert(cache->hashmap);
1874 :
1875 10501 : size = n_entries(cache->hashmap);
1876 :
1877 10501 : if (res_keys) {
1878 112 : r = cachemem_maintain(&cache->keys, size);
1879 112 : if (r < 0)
1880 0 : return r;
1881 :
1882 112 : sync_keys = r;
1883 : } else
1884 10389 : cache->keys.active = false;
1885 :
1886 10501 : if (res_values) {
1887 10501 : r = cachemem_maintain(&cache->values, size);
1888 10501 : if (r < 0)
1889 0 : return r;
1890 :
1891 10501 : sync_values = r;
1892 : } else
1893 0 : cache->values.active = false;
1894 :
1895 10501 : if (cache->hashmap->dirty) {
1896 122 : if (cache->keys.active)
1897 111 : sync_keys = true;
1898 122 : if (cache->values.active)
1899 122 : sync_values = true;
1900 :
1901 122 : cache->hashmap->dirty = false;
1902 : }
1903 :
1904 10501 : if (sync_keys || sync_values) {
1905 : unsigned i, idx;
1906 : Iterator iter;
1907 :
1908 123 : i = 0;
1909 491838 : HASHMAP_FOREACH_IDX(idx, cache->hashmap, iter) {
1910 : struct hashmap_base_entry *e;
1911 :
1912 491715 : e = bucket_at(cache->hashmap, idx);
1913 :
1914 491715 : if (sync_keys)
1915 491500 : cache->keys.ptr[i] = e->key;
1916 491715 : if (sync_values)
1917 491715 : cache->values.ptr[i] = entry_value(cache->hashmap, e);
1918 491715 : i++;
1919 : }
1920 : }
1921 :
1922 10501 : if (res_keys)
1923 112 : *res_keys = cache->keys.ptr;
1924 10501 : if (res_values)
1925 10501 : *res_values = cache->values.ptr;
1926 10501 : if (res_n_entries)
1927 10501 : *res_n_entries = size;
1928 :
1929 10501 : return 0;
1930 : }
1931 :
1932 213 : IteratedCache *iterated_cache_free(IteratedCache *cache) {
1933 213 : if (cache) {
1934 213 : free(cache->keys.ptr);
1935 213 : free(cache->values.ptr);
1936 : }
1937 :
1938 213 : return mfree(cache);
1939 : }
|