2 * Copyright 2012-2015 Samy Al Bahra.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <ck_limits.h>
32 #include <ck_stdint.h>
33 #include <ck_stdbool.h>
34 #include <ck_string.h>
36 #include "ck_internal.h"
38 #ifndef CK_HS_PROBE_L1_SHIFT
39 #define CK_HS_PROBE_L1_SHIFT 3ULL
40 #endif /* CK_HS_PROBE_L1_SHIFT */
42 #define CK_HS_PROBE_L1 (1 << CK_HS_PROBE_L1_SHIFT)
43 #define CK_HS_PROBE_L1_MASK (CK_HS_PROBE_L1 - 1)
45 #ifndef CK_HS_PROBE_L1_DEFAULT
46 #define CK_HS_PROBE_L1_DEFAULT CK_MD_CACHELINE
49 #define CK_HS_VMA_MASK ((uintptr_t)((1ULL << CK_MD_VMA_BITS) - 1))
50 #define CK_HS_VMA(x) \
51 ((void *)((uintptr_t)(x) & CK_HS_VMA_MASK))
53 #define CK_HS_EMPTY NULL
54 #define CK_HS_TOMBSTONE ((void *)~(uintptr_t)0)
56 #define CK_HS_G_MASK (CK_HS_G - 1)
58 #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_STORE_8)
59 #define CK_HS_WORD uint8_t
60 #define CK_HS_WORD_MAX UINT8_MAX
61 #define CK_HS_STORE(x, y) ck_pr_store_8(x, y)
62 #define CK_HS_LOAD(x) ck_pr_load_8(x)
63 #elif defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_STORE_16)
64 #define CK_HS_WORD uint16_t
65 #define CK_HS_WORD_MAX UINT16_MAX
66 #define CK_HS_STORE(x, y) ck_pr_store_16(x, y)
67 #define CK_HS_LOAD(x) ck_pr_load_16(x)
68 #elif defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_STORE_32)
69 #define CK_HS_WORD uint32_t
70 #define CK_HS_WORD_MAX UINT32_MAX
71 #define CK_HS_STORE(x, y) ck_pr_store_32(x, y)
72 #define CK_HS_LOAD(x) ck_pr_load_32(x)
74 #error "ck_hs is not supported on your platform."
77 enum ck_hs_probe_behavior {
78 CK_HS_PROBE = 0, /* Default behavior. */
79 CK_HS_PROBE_TOMBSTONE, /* Short-circuit on tombstone. */
80 CK_HS_PROBE_INSERT /* Short-circuit on probe bound if tombstone found. */
84 unsigned int generation[CK_HS_G];
85 unsigned int probe_maximum;
88 unsigned int probe_limit;
89 unsigned int tombstones;
90 unsigned long n_entries;
91 unsigned long capacity;
93 CK_HS_WORD *probe_bound;
98 ck_hs_map_signal(struct ck_hs_map *map, unsigned long h)
102 ck_pr_store_uint(&map->generation[h],
103 map->generation[h] + 1);
109 _ck_hs_next(struct ck_hs *hs, struct ck_hs_map *map, struct ck_hs_iterator *i, void **key)
112 if (i->offset >= map->capacity)
116 value = CK_CC_DECONST_PTR(map->entries[i->offset]);
117 if (value != CK_HS_EMPTY && value != CK_HS_TOMBSTONE) {
119 if (hs->mode & CK_HS_MODE_OBJECT)
120 value = CK_HS_VMA(value);
122 (void)hs; /* Avoid unused parameter warning. */
128 } while (++i->offset < map->capacity);
134 ck_hs_iterator_init(struct ck_hs_iterator *iterator)
137 iterator->cursor = NULL;
138 iterator->offset = 0;
139 iterator->map = NULL;
144 ck_hs_next(struct ck_hs *hs, struct ck_hs_iterator *i, void **key)
146 return _ck_hs_next(hs, hs->map, i, key);
150 ck_hs_next_spmc(struct ck_hs *hs, struct ck_hs_iterator *i, void **key)
152 struct ck_hs_map *m = i->map;
154 m = i->map = ck_pr_load_ptr(&hs->map);
156 return _ck_hs_next(hs, m, i, key);
160 ck_hs_stat(struct ck_hs *hs, struct ck_hs_stat *st)
162 struct ck_hs_map *map = hs->map;
164 st->n_entries = map->n_entries;
165 st->tombstones = map->tombstones;
166 st->probe_maximum = map->probe_maximum;
171 ck_hs_count(struct ck_hs *hs)
174 return hs->map->n_entries;
178 ck_hs_map_destroy(struct ck_malloc *m, struct ck_hs_map *map, bool defer)
181 m->free(map, map->size, defer);
186 ck_hs_destroy(struct ck_hs *hs)
189 ck_hs_map_destroy(hs->m, hs->map, false);
193 static struct ck_hs_map *
194 ck_hs_map_create(struct ck_hs *hs, unsigned long entries)
196 struct ck_hs_map *map;
197 unsigned long size, n_entries, prefix, limit;
199 n_entries = ck_internal_power_2(entries);
200 if (n_entries < CK_HS_PROBE_L1)
201 n_entries = CK_HS_PROBE_L1;
203 size = sizeof(struct ck_hs_map) + (sizeof(void *) * n_entries + CK_MD_CACHELINE - 1);
205 if (hs->mode & CK_HS_MODE_DELETE) {
206 prefix = sizeof(CK_HS_WORD) * n_entries;
212 map = hs->m->malloc(size);
218 /* We should probably use a more intelligent heuristic for default probe length. */
219 limit = ck_internal_max(n_entries >> (CK_HS_PROBE_L1_SHIFT + 2), CK_HS_PROBE_L1_DEFAULT);
220 if (limit > UINT_MAX)
223 map->probe_limit = (unsigned int)limit;
224 map->probe_maximum = 0;
225 map->capacity = n_entries;
226 map->step = ck_cc_ffsl(n_entries);
227 map->mask = n_entries - 1;
230 /* Align map allocation to cache line. */
231 map->entries = (void *)(((uintptr_t)&map[1] + prefix +
232 CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1));
234 memset(map->entries, 0, sizeof(void *) * n_entries);
235 memset(map->generation, 0, sizeof map->generation);
237 if (hs->mode & CK_HS_MODE_DELETE) {
238 map->probe_bound = (CK_HS_WORD *)&map[1];
239 memset(map->probe_bound, 0, prefix);
241 map->probe_bound = NULL;
244 /* Commit entries purge with respect to map publication. */
250 ck_hs_reset_size(struct ck_hs *hs, unsigned long capacity)
252 struct ck_hs_map *map, *previous;
255 map = ck_hs_map_create(hs, capacity);
259 ck_pr_store_ptr(&hs->map, map);
260 ck_hs_map_destroy(hs->m, previous, true);
265 ck_hs_reset(struct ck_hs *hs)
267 struct ck_hs_map *previous;
270 return ck_hs_reset_size(hs, previous->capacity);
273 static inline unsigned long
274 ck_hs_map_probe_next(struct ck_hs_map *map,
275 unsigned long offset,
278 unsigned long probes)
280 unsigned long r, stride;
282 r = (h >> map->step) >> level;
283 stride = (r & ~CK_HS_PROBE_L1_MASK) << 1 | (r & CK_HS_PROBE_L1_MASK);
285 return (offset + (probes >> CK_HS_PROBE_L1_SHIFT) +
286 (stride | CK_HS_PROBE_L1)) & map->mask;
290 ck_hs_map_bound_set(struct ck_hs_map *m,
292 unsigned long n_probes)
294 unsigned long offset = h & m->mask;
296 if (n_probes > m->probe_maximum)
297 ck_pr_store_uint(&m->probe_maximum, n_probes);
299 if (m->probe_bound != NULL && m->probe_bound[offset] < n_probes) {
300 if (n_probes > CK_HS_WORD_MAX)
301 n_probes = CK_HS_WORD_MAX;
303 CK_HS_STORE(&m->probe_bound[offset], n_probes);
310 static inline unsigned int
311 ck_hs_map_bound_get(struct ck_hs_map *m, unsigned long h)
313 unsigned long offset = h & m->mask;
314 unsigned int r = CK_HS_WORD_MAX;
316 if (m->probe_bound != NULL) {
317 r = CK_HS_LOAD(&m->probe_bound[offset]);
318 if (r == CK_HS_WORD_MAX)
319 r = ck_pr_load_uint(&m->probe_maximum);
321 r = ck_pr_load_uint(&m->probe_maximum);
328 ck_hs_grow(struct ck_hs *hs,
329 unsigned long capacity)
331 struct ck_hs_map *map, *update;
332 unsigned long k, i, j, offset, probes;
333 const void *previous, **bucket;
337 if (map->capacity > capacity)
340 update = ck_hs_map_create(hs, capacity);
344 for (k = 0; k < map->capacity; k++) {
347 previous = map->entries[k];
348 if (previous == CK_HS_EMPTY || previous == CK_HS_TOMBSTONE)
352 if (hs->mode & CK_HS_MODE_OBJECT)
353 previous = CK_HS_VMA(previous);
356 h = hs->hf(previous, hs->seed);
357 offset = h & update->mask;
361 bucket = (const void **)((uintptr_t)&update->entries[offset] & ~(CK_MD_CACHELINE - 1));
363 for (j = 0; j < CK_HS_PROBE_L1; j++) {
364 const void **cursor = bucket + ((j + offset) & (CK_HS_PROBE_L1 - 1));
366 if (probes++ == update->probe_limit)
369 if (CK_CC_LIKELY(*cursor == CK_HS_EMPTY)) {
370 *cursor = map->entries[k];
373 ck_hs_map_bound_set(update, h, probes);
378 if (j < CK_HS_PROBE_L1)
381 offset = ck_hs_map_probe_next(update, offset, h, i++, probes);
384 if (probes > update->probe_limit) {
386 * We have hit the probe limit, map needs to be even larger.
388 ck_hs_map_destroy(hs->m, update, false);
395 ck_pr_store_ptr(&hs->map, update);
396 ck_hs_map_destroy(hs->m, map, true);
401 ck_hs_map_postinsert(struct ck_hs *hs, struct ck_hs_map *map)
405 if ((map->n_entries << 1) > map->capacity)
406 ck_hs_grow(hs, map->capacity << 1);
412 ck_hs_rebuild(struct ck_hs *hs)
415 return ck_hs_grow(hs, hs->map->capacity);
419 ck_hs_map_probe(struct ck_hs *hs,
420 struct ck_hs_map *map,
421 unsigned long *n_probes,
422 const void ***priority,
426 unsigned long probe_limit,
427 enum ck_hs_probe_behavior behavior)
429 const void **bucket, **cursor, *k, *compare;
430 const void **pr = NULL;
431 unsigned long offset, j, i, probes, opl;
434 /* If we are storing object pointers, then we may leverage pointer packing. */
435 unsigned long hv = 0;
437 if (hs->mode & CK_HS_MODE_OBJECT) {
438 hv = (h >> 25) & CK_HS_KEY_MASK;
439 compare = CK_HS_VMA(key);
447 offset = h & map->mask;
452 if (behavior == CK_HS_PROBE_INSERT)
453 probe_limit = ck_hs_map_bound_get(map, h);
456 bucket = (const void **)((uintptr_t)&map->entries[offset] & ~(CK_MD_CACHELINE - 1));
458 for (j = 0; j < CK_HS_PROBE_L1; j++) {
459 cursor = bucket + ((j + offset) & (CK_HS_PROBE_L1 - 1));
461 if (probes++ == probe_limit) {
462 if (probe_limit == opl || pr != NULL) {
468 * If no eligible slot has been found yet, continue probe
469 * sequence with original probe limit.
474 k = ck_pr_load_ptr(cursor);
475 if (k == CK_HS_EMPTY)
478 if (k == CK_HS_TOMBSTONE) {
483 if (behavior == CK_HS_PROBE_TOMBSTONE) {
493 if (hs->mode & CK_HS_MODE_OBJECT) {
494 if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv)
504 if (hs->compare == NULL)
507 if (hs->compare(k, key) == true)
511 offset = ck_hs_map_probe_next(map, offset, h, i++, probes);
515 if (probes > probe_limit) {
528 static inline const void *
529 ck_hs_marshal(unsigned int mode, const void *key, unsigned long h)
534 if (mode & CK_HS_MODE_OBJECT) {
535 insert = (void *)((uintptr_t)CK_HS_VMA(key) |
536 ((h >> 25) << CK_MD_VMA_BITS));
551 ck_hs_gc(struct ck_hs *hs, unsigned long cycles, unsigned long seed)
553 unsigned long size = 0;
555 struct ck_hs_map *map = hs->map;
556 unsigned int maximum;
557 CK_HS_WORD *bounds = NULL;
559 if (map->n_entries == 0) {
560 ck_pr_store_uint(&map->probe_maximum, 0);
561 if (map->probe_bound != NULL)
562 memset(map->probe_bound, 0, sizeof(CK_HS_WORD) * map->capacity);
570 if (map->probe_bound != NULL) {
571 size = sizeof(CK_HS_WORD) * map->capacity;
572 bounds = hs->m->malloc(size);
576 memset(bounds, 0, size);
579 maximum = map->probe_maximum;
582 for (i = 0; i < map->capacity; i++) {
583 const void **first, *object, **slot, *entry;
584 unsigned long n_probes, offset, h;
586 entry = map->entries[(i + seed) & map->mask];
587 if (entry == CK_HS_EMPTY || entry == CK_HS_TOMBSTONE)
591 if (hs->mode & CK_HS_MODE_OBJECT)
592 entry = CK_HS_VMA(entry);
595 h = hs->hf(entry, hs->seed);
596 offset = h & map->mask;
598 slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, entry, &object,
599 ck_hs_map_bound_get(map, h), CK_HS_PROBE);
602 const void *insert = ck_hs_marshal(hs->mode, entry, h);
604 ck_pr_store_ptr(first, insert);
605 ck_hs_map_signal(map, h);
606 ck_pr_store_ptr(slot, CK_HS_TOMBSTONE);
610 if (n_probes > maximum)
613 if (n_probes > CK_HS_WORD_MAX)
614 n_probes = CK_HS_WORD_MAX;
616 if (bounds != NULL && n_probes > bounds[offset])
617 bounds[offset] = n_probes;
618 } else if (--cycles == 0)
623 * The following only apply to garbage collection involving
624 * a full scan of all entries.
626 if (maximum != map->probe_maximum)
627 ck_pr_store_uint(&map->probe_maximum, maximum);
629 if (bounds != NULL) {
630 for (i = 0; i < map->capacity; i++)
631 CK_HS_STORE(&map->probe_bound[i], bounds[i]);
633 hs->m->free(bounds, size, false);
640 ck_hs_fas(struct ck_hs *hs,
645 const void **slot, **first, *object, *insert;
646 struct ck_hs_map *map = hs->map;
647 unsigned long n_probes;
650 slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object,
651 ck_hs_map_bound_get(map, h), CK_HS_PROBE);
653 /* Replacement semantics presume existence. */
657 insert = ck_hs_marshal(hs->mode, key, h);
660 ck_pr_store_ptr(first, insert);
661 ck_hs_map_signal(map, h);
662 ck_pr_store_ptr(slot, CK_HS_TOMBSTONE);
664 ck_pr_store_ptr(slot, insert);
667 *previous = CK_CC_DECONST_PTR(object);
672 * An apply function takes two arguments. The first argument is a pointer to a
673 * pre-existing object. The second argument is a pointer to the fifth argument
674 * passed to ck_hs_apply. If a non-NULL pointer is passed to the first argument
675 * and the return value of the apply function is NULL, then the pre-existing
676 * value is deleted. If the return pointer is the same as the one passed to the
677 * apply function then no changes are made to the hash table. If the first
678 * argument is non-NULL and the return pointer is different than that passed to
679 * the apply function, then the pre-existing value is replaced. For
680 * replacement, it is required that the value itself is identical to the
684 ck_hs_apply(struct ck_hs *hs,
687 ck_hs_apply_fn_t *fn,
690 const void **slot, **first, *object, *delta, *insert;
691 unsigned long n_probes;
692 struct ck_hs_map *map;
697 slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_HS_PROBE_INSERT);
698 if (slot == NULL && first == NULL) {
699 if (ck_hs_grow(hs, map->capacity << 1) == false)
705 delta = fn(CK_CC_DECONST_PTR(object), cl);
708 * The apply function has requested deletion. If the object doesn't exist,
711 if (CK_CC_UNLIKELY(object == NULL))
714 /* Otherwise, mark slot as deleted. */
715 ck_pr_store_ptr(slot, CK_HS_TOMBSTONE);
721 /* The apply function has not requested hash set modification so exit early. */
725 /* A modification or insertion has been requested. */
726 ck_hs_map_bound_set(map, h, n_probes);
728 insert = ck_hs_marshal(hs->mode, delta, h);
731 * This follows the same semantics as ck_hs_set, please refer to that
732 * function for documentation.
734 ck_pr_store_ptr(first, insert);
736 if (object != NULL) {
737 ck_hs_map_signal(map, h);
738 ck_pr_store_ptr(slot, CK_HS_TOMBSTONE);
742 * If we are storing into same slot, then atomic store is sufficient
745 ck_pr_store_ptr(slot, insert);
749 ck_hs_map_postinsert(hs, map);
755 ck_hs_set(struct ck_hs *hs,
760 const void **slot, **first, *object, *insert;
761 unsigned long n_probes;
762 struct ck_hs_map *map;
769 slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_HS_PROBE_INSERT);
770 if (slot == NULL && first == NULL) {
771 if (ck_hs_grow(hs, map->capacity << 1) == false)
777 ck_hs_map_bound_set(map, h, n_probes);
778 insert = ck_hs_marshal(hs->mode, key, h);
781 /* If an earlier bucket was found, then store entry there. */
782 ck_pr_store_ptr(first, insert);
785 * If a duplicate key was found, then delete it after
786 * signaling concurrent probes to restart. Optionally,
787 * it is possible to install tombstone after grace
788 * period if we can guarantee earlier position of
791 if (object != NULL) {
792 ck_hs_map_signal(map, h);
793 ck_pr_store_ptr(slot, CK_HS_TOMBSTONE);
797 * If we are storing into same slot, then atomic store is sufficient
800 ck_pr_store_ptr(slot, insert);
804 ck_hs_map_postinsert(hs, map);
806 *previous = CK_CC_DECONST_PTR(object);
810 CK_CC_INLINE static bool
811 ck_hs_put_internal(struct ck_hs *hs,
814 enum ck_hs_probe_behavior behavior)
816 const void **slot, **first, *object, *insert;
817 unsigned long n_probes;
818 struct ck_hs_map *map;
823 slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object,
824 map->probe_limit, behavior);
826 if (slot == NULL && first == NULL) {
827 if (ck_hs_grow(hs, map->capacity << 1) == false)
833 /* Fail operation if a match was found. */
837 ck_hs_map_bound_set(map, h, n_probes);
838 insert = ck_hs_marshal(hs->mode, key, h);
841 /* Insert key into first bucket in probe sequence. */
842 ck_pr_store_ptr(first, insert);
844 /* An empty slot was found. */
845 ck_pr_store_ptr(slot, insert);
848 ck_hs_map_postinsert(hs, map);
853 ck_hs_put(struct ck_hs *hs,
858 return ck_hs_put_internal(hs, h, key, CK_HS_PROBE_INSERT);
862 ck_hs_put_unique(struct ck_hs *hs,
867 return ck_hs_put_internal(hs, h, key, CK_HS_PROBE_TOMBSTONE);
871 ck_hs_get(struct ck_hs *hs,
875 const void **first, *object;
876 struct ck_hs_map *map;
877 unsigned long n_probes;
878 unsigned int g, g_p, probe;
879 unsigned int *generation;
882 map = ck_pr_load_ptr(&hs->map);
883 generation = &map->generation[h & CK_HS_G_MASK];
884 g = ck_pr_load_uint(generation);
885 probe = ck_hs_map_bound_get(map, h);
888 ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, probe, CK_HS_PROBE);
891 g_p = ck_pr_load_uint(generation);
894 return CK_CC_DECONST_PTR(object);
898 ck_hs_remove(struct ck_hs *hs,
902 const void **slot, **first, *object;
903 struct ck_hs_map *map = hs->map;
904 unsigned long n_probes;
906 slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object,
907 ck_hs_map_bound_get(map, h), CK_HS_PROBE);
911 ck_pr_store_ptr(slot, CK_HS_TOMBSTONE);
914 return CK_CC_DECONST_PTR(object);
918 ck_hs_move(struct ck_hs *hs,
919 struct ck_hs *source,
921 ck_hs_compare_cb_t *compare,
925 if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL)
928 hs->mode = source->mode;
929 hs->seed = source->seed;
930 hs->map = source->map;
933 hs->compare = compare;
938 ck_hs_init(struct ck_hs *hs,
941 ck_hs_compare_cb_t *compare,
943 unsigned long n_entries,
947 if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL)
954 hs->compare = compare;
956 hs->map = ck_hs_map_create(hs, n_entries);
957 return hs->map != NULL;