11fb62fb0SOlivier Houchard /*
21fb62fb0SOlivier Houchard * Copyright 2012-2015 Samy Al Bahra.
31fb62fb0SOlivier Houchard * All rights reserved.
41fb62fb0SOlivier Houchard *
51fb62fb0SOlivier Houchard * Redistribution and use in source and binary forms, with or without
61fb62fb0SOlivier Houchard * modification, are permitted provided that the following conditions
71fb62fb0SOlivier Houchard * are met:
81fb62fb0SOlivier Houchard * 1. Redistributions of source code must retain the above copyright
91fb62fb0SOlivier Houchard * notice, this list of conditions and the following disclaimer.
101fb62fb0SOlivier Houchard * 2. Redistributions in binary form must reproduce the above copyright
111fb62fb0SOlivier Houchard * notice, this list of conditions and the following disclaimer in the
121fb62fb0SOlivier Houchard * documentation and/or other materials provided with the distribution.
131fb62fb0SOlivier Houchard *
141fb62fb0SOlivier Houchard * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151fb62fb0SOlivier Houchard * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161fb62fb0SOlivier Houchard * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171fb62fb0SOlivier Houchard * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181fb62fb0SOlivier Houchard * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191fb62fb0SOlivier Houchard * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201fb62fb0SOlivier Houchard * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211fb62fb0SOlivier Houchard * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221fb62fb0SOlivier Houchard * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231fb62fb0SOlivier Houchard * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241fb62fb0SOlivier Houchard * SUCH DAMAGE.
251fb62fb0SOlivier Houchard */
261fb62fb0SOlivier Houchard
271fb62fb0SOlivier Houchard #define CK_HT_IM
281fb62fb0SOlivier Houchard #include <ck_ht.h>
291fb62fb0SOlivier Houchard
301fb62fb0SOlivier Houchard /*
311fb62fb0SOlivier Houchard * This implementation borrows several techniques from Josh Dybnis's
321fb62fb0SOlivier Houchard * nbds library which can be found at http://code.google.com/p/nbds
331fb62fb0SOlivier Houchard */
341fb62fb0SOlivier Houchard #include <ck_cc.h>
351fb62fb0SOlivier Houchard #include <ck_md.h>
361fb62fb0SOlivier Houchard #include <ck_pr.h>
371fb62fb0SOlivier Houchard #include <ck_stdint.h>
381fb62fb0SOlivier Houchard #include <ck_stdbool.h>
391fb62fb0SOlivier Houchard #include <ck_string.h>
401fb62fb0SOlivier Houchard
411fb62fb0SOlivier Houchard #include "ck_ht_hash.h"
421fb62fb0SOlivier Houchard #include "ck_internal.h"
431fb62fb0SOlivier Houchard
441fb62fb0SOlivier Houchard #ifndef CK_HT_BUCKET_LENGTH
451fb62fb0SOlivier Houchard
461fb62fb0SOlivier Houchard #ifdef CK_HT_PP
471fb62fb0SOlivier Houchard #define CK_HT_BUCKET_SHIFT 2ULL
481fb62fb0SOlivier Houchard #else
491fb62fb0SOlivier Houchard #define CK_HT_BUCKET_SHIFT 1ULL
501fb62fb0SOlivier Houchard #endif
511fb62fb0SOlivier Houchard
521fb62fb0SOlivier Houchard #define CK_HT_BUCKET_LENGTH (1U << CK_HT_BUCKET_SHIFT)
531fb62fb0SOlivier Houchard #define CK_HT_BUCKET_MASK (CK_HT_BUCKET_LENGTH - 1)
541fb62fb0SOlivier Houchard #endif
551fb62fb0SOlivier Houchard
561fb62fb0SOlivier Houchard #ifndef CK_HT_PROBE_DEFAULT
571fb62fb0SOlivier Houchard #define CK_HT_PROBE_DEFAULT 64ULL
581fb62fb0SOlivier Houchard #endif
591fb62fb0SOlivier Houchard
601fb62fb0SOlivier Houchard #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_STORE_8)
611fb62fb0SOlivier Houchard #define CK_HT_WORD uint8_t
621fb62fb0SOlivier Houchard #define CK_HT_WORD_MAX UINT8_MAX
631fb62fb0SOlivier Houchard #define CK_HT_STORE(x, y) ck_pr_store_8(x, y)
641fb62fb0SOlivier Houchard #define CK_HT_LOAD(x) ck_pr_load_8(x)
651fb62fb0SOlivier Houchard #elif defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_STORE_16)
661fb62fb0SOlivier Houchard #define CK_HT_WORD uint16_t
671fb62fb0SOlivier Houchard #define CK_HT_WORD_MAX UINT16_MAX
681fb62fb0SOlivier Houchard #define CK_HT_STORE(x, y) ck_pr_store_16(x, y)
691fb62fb0SOlivier Houchard #define CK_HT_LOAD(x) ck_pr_load_16(x)
701fb62fb0SOlivier Houchard #elif defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_STORE_32)
711fb62fb0SOlivier Houchard #define CK_HT_WORD uint32_t
721fb62fb0SOlivier Houchard #define CK_HT_WORD_MAX UINT32_MAX
731fb62fb0SOlivier Houchard #define CK_HT_STORE(x, y) ck_pr_store_32(x, y)
741fb62fb0SOlivier Houchard #define CK_HT_LOAD(x) ck_pr_load_32(x)
751fb62fb0SOlivier Houchard #else
761fb62fb0SOlivier Houchard #error "ck_ht is not supported on your platform."
771fb62fb0SOlivier Houchard #endif
781fb62fb0SOlivier Houchard
791fb62fb0SOlivier Houchard struct ck_ht_map {
801fb62fb0SOlivier Houchard unsigned int mode;
811fb62fb0SOlivier Houchard CK_HT_TYPE deletions;
821fb62fb0SOlivier Houchard CK_HT_TYPE probe_maximum;
831fb62fb0SOlivier Houchard CK_HT_TYPE probe_length;
841fb62fb0SOlivier Houchard CK_HT_TYPE probe_limit;
851fb62fb0SOlivier Houchard CK_HT_TYPE size;
861fb62fb0SOlivier Houchard CK_HT_TYPE n_entries;
871fb62fb0SOlivier Houchard CK_HT_TYPE mask;
881fb62fb0SOlivier Houchard CK_HT_TYPE capacity;
891fb62fb0SOlivier Houchard CK_HT_TYPE step;
901fb62fb0SOlivier Houchard CK_HT_WORD *probe_bound;
911fb62fb0SOlivier Houchard struct ck_ht_entry *entries;
921fb62fb0SOlivier Houchard };
931fb62fb0SOlivier Houchard
941fb62fb0SOlivier Houchard void
ck_ht_stat(struct ck_ht * table,struct ck_ht_stat * st)951fb62fb0SOlivier Houchard ck_ht_stat(struct ck_ht *table,
961fb62fb0SOlivier Houchard struct ck_ht_stat *st)
971fb62fb0SOlivier Houchard {
981fb62fb0SOlivier Houchard struct ck_ht_map *map = table->map;
991fb62fb0SOlivier Houchard
1001fb62fb0SOlivier Houchard st->n_entries = map->n_entries;
1011fb62fb0SOlivier Houchard st->probe_maximum = map->probe_maximum;
1021fb62fb0SOlivier Houchard return;
1031fb62fb0SOlivier Houchard }
1041fb62fb0SOlivier Houchard
1051fb62fb0SOlivier Houchard void
ck_ht_hash(struct ck_ht_hash * h,struct ck_ht * table,const void * key,uint16_t key_length)1061fb62fb0SOlivier Houchard ck_ht_hash(struct ck_ht_hash *h,
1071fb62fb0SOlivier Houchard struct ck_ht *table,
1081fb62fb0SOlivier Houchard const void *key,
1091fb62fb0SOlivier Houchard uint16_t key_length)
1101fb62fb0SOlivier Houchard {
1111fb62fb0SOlivier Houchard
1121fb62fb0SOlivier Houchard table->h(h, key, key_length, table->seed);
1131fb62fb0SOlivier Houchard return;
1141fb62fb0SOlivier Houchard }
1151fb62fb0SOlivier Houchard
1161fb62fb0SOlivier Houchard void
ck_ht_hash_direct(struct ck_ht_hash * h,struct ck_ht * table,uintptr_t key)1171fb62fb0SOlivier Houchard ck_ht_hash_direct(struct ck_ht_hash *h,
1181fb62fb0SOlivier Houchard struct ck_ht *table,
1191fb62fb0SOlivier Houchard uintptr_t key)
1201fb62fb0SOlivier Houchard {
1211fb62fb0SOlivier Houchard
1221fb62fb0SOlivier Houchard ck_ht_hash(h, table, &key, sizeof(key));
1231fb62fb0SOlivier Houchard return;
1241fb62fb0SOlivier Houchard }
1251fb62fb0SOlivier Houchard
1261fb62fb0SOlivier Houchard static void
ck_ht_hash_wrapper(struct ck_ht_hash * h,const void * key,size_t length,uint64_t seed)1271fb62fb0SOlivier Houchard ck_ht_hash_wrapper(struct ck_ht_hash *h,
1281fb62fb0SOlivier Houchard const void *key,
1291fb62fb0SOlivier Houchard size_t length,
1301fb62fb0SOlivier Houchard uint64_t seed)
1311fb62fb0SOlivier Houchard {
1321fb62fb0SOlivier Houchard
1331fb62fb0SOlivier Houchard h->value = (unsigned long)MurmurHash64A(key, length, seed);
1341fb62fb0SOlivier Houchard return;
1351fb62fb0SOlivier Houchard }
1361fb62fb0SOlivier Houchard
1371fb62fb0SOlivier Houchard static struct ck_ht_map *
ck_ht_map_create(struct ck_ht * table,CK_HT_TYPE entries)1381fb62fb0SOlivier Houchard ck_ht_map_create(struct ck_ht *table, CK_HT_TYPE entries)
1391fb62fb0SOlivier Houchard {
1401fb62fb0SOlivier Houchard struct ck_ht_map *map;
1411fb62fb0SOlivier Houchard CK_HT_TYPE size;
1421fb62fb0SOlivier Houchard uintptr_t prefix;
1431fb62fb0SOlivier Houchard uint32_t n_entries;
1441fb62fb0SOlivier Houchard
1451fb62fb0SOlivier Houchard n_entries = ck_internal_power_2(entries);
1461fb62fb0SOlivier Houchard if (n_entries < CK_HT_BUCKET_LENGTH)
1471fb62fb0SOlivier Houchard n_entries = CK_HT_BUCKET_LENGTH;
1481fb62fb0SOlivier Houchard
1491fb62fb0SOlivier Houchard size = sizeof(struct ck_ht_map) +
1501fb62fb0SOlivier Houchard (sizeof(struct ck_ht_entry) * n_entries + CK_MD_CACHELINE - 1);
1511fb62fb0SOlivier Houchard
1521fb62fb0SOlivier Houchard if (table->mode & CK_HT_WORKLOAD_DELETE) {
1531fb62fb0SOlivier Houchard prefix = sizeof(CK_HT_WORD) * n_entries;
1541fb62fb0SOlivier Houchard size += prefix;
1551fb62fb0SOlivier Houchard } else {
1561fb62fb0SOlivier Houchard prefix = 0;
1571fb62fb0SOlivier Houchard }
1581fb62fb0SOlivier Houchard
1591fb62fb0SOlivier Houchard map = table->m->malloc(size);
1601fb62fb0SOlivier Houchard if (map == NULL)
1611fb62fb0SOlivier Houchard return NULL;
1621fb62fb0SOlivier Houchard
1631fb62fb0SOlivier Houchard map->mode = table->mode;
1641fb62fb0SOlivier Houchard map->size = size;
1651fb62fb0SOlivier Houchard map->probe_limit = ck_internal_max_64(n_entries >>
1661fb62fb0SOlivier Houchard (CK_HT_BUCKET_SHIFT + 2), CK_HT_PROBE_DEFAULT);
1671fb62fb0SOlivier Houchard
1681fb62fb0SOlivier Houchard map->deletions = 0;
1691fb62fb0SOlivier Houchard map->probe_maximum = 0;
1701fb62fb0SOlivier Houchard map->capacity = n_entries;
171*271ce402SOlivier Houchard map->step = ck_cc_ffsll(map->capacity);
1721fb62fb0SOlivier Houchard map->mask = map->capacity - 1;
1731fb62fb0SOlivier Houchard map->n_entries = 0;
1741fb62fb0SOlivier Houchard map->entries = (struct ck_ht_entry *)(((uintptr_t)&map[1] + prefix +
1751fb62fb0SOlivier Houchard CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1));
1761fb62fb0SOlivier Houchard
1771fb62fb0SOlivier Houchard if (table->mode & CK_HT_WORKLOAD_DELETE) {
1781fb62fb0SOlivier Houchard map->probe_bound = (CK_HT_WORD *)&map[1];
1791fb62fb0SOlivier Houchard memset(map->probe_bound, 0, prefix);
1801fb62fb0SOlivier Houchard } else {
1811fb62fb0SOlivier Houchard map->probe_bound = NULL;
1821fb62fb0SOlivier Houchard }
1831fb62fb0SOlivier Houchard
1841fb62fb0SOlivier Houchard memset(map->entries, 0, sizeof(struct ck_ht_entry) * n_entries);
1851fb62fb0SOlivier Houchard ck_pr_fence_store();
1861fb62fb0SOlivier Houchard return map;
1871fb62fb0SOlivier Houchard }
1881fb62fb0SOlivier Houchard
1891fb62fb0SOlivier Houchard static inline void
ck_ht_map_bound_set(struct ck_ht_map * m,struct ck_ht_hash h,CK_HT_TYPE n_probes)1901fb62fb0SOlivier Houchard ck_ht_map_bound_set(struct ck_ht_map *m,
1911fb62fb0SOlivier Houchard struct ck_ht_hash h,
1921fb62fb0SOlivier Houchard CK_HT_TYPE n_probes)
1931fb62fb0SOlivier Houchard {
1941fb62fb0SOlivier Houchard CK_HT_TYPE offset = h.value & m->mask;
1951fb62fb0SOlivier Houchard
1961fb62fb0SOlivier Houchard if (n_probes > m->probe_maximum)
1971fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&m->probe_maximum, n_probes);
1981fb62fb0SOlivier Houchard
1991fb62fb0SOlivier Houchard if (m->probe_bound != NULL && m->probe_bound[offset] < n_probes) {
2001fb62fb0SOlivier Houchard if (n_probes >= CK_HT_WORD_MAX)
2011fb62fb0SOlivier Houchard n_probes = CK_HT_WORD_MAX;
2021fb62fb0SOlivier Houchard
2031fb62fb0SOlivier Houchard CK_HT_STORE(&m->probe_bound[offset], n_probes);
2041fb62fb0SOlivier Houchard ck_pr_fence_store();
2051fb62fb0SOlivier Houchard }
2061fb62fb0SOlivier Houchard
2071fb62fb0SOlivier Houchard return;
2081fb62fb0SOlivier Houchard }
2091fb62fb0SOlivier Houchard
2101fb62fb0SOlivier Houchard static inline CK_HT_TYPE
ck_ht_map_bound_get(struct ck_ht_map * m,struct ck_ht_hash h)2111fb62fb0SOlivier Houchard ck_ht_map_bound_get(struct ck_ht_map *m, struct ck_ht_hash h)
2121fb62fb0SOlivier Houchard {
2131fb62fb0SOlivier Houchard CK_HT_TYPE offset = h.value & m->mask;
2141fb62fb0SOlivier Houchard CK_HT_TYPE r = CK_HT_WORD_MAX;
2151fb62fb0SOlivier Houchard
2161fb62fb0SOlivier Houchard if (m->probe_bound != NULL) {
2171fb62fb0SOlivier Houchard r = CK_HT_LOAD(&m->probe_bound[offset]);
2181fb62fb0SOlivier Houchard if (r == CK_HT_WORD_MAX)
2191fb62fb0SOlivier Houchard r = CK_HT_TYPE_LOAD(&m->probe_maximum);
2201fb62fb0SOlivier Houchard } else {
2211fb62fb0SOlivier Houchard r = CK_HT_TYPE_LOAD(&m->probe_maximum);
2221fb62fb0SOlivier Houchard }
2231fb62fb0SOlivier Houchard
2241fb62fb0SOlivier Houchard return r;
2251fb62fb0SOlivier Houchard }
2261fb62fb0SOlivier Houchard
2271fb62fb0SOlivier Houchard static void
ck_ht_map_destroy(struct ck_malloc * m,struct ck_ht_map * map,bool defer)2281fb62fb0SOlivier Houchard ck_ht_map_destroy(struct ck_malloc *m, struct ck_ht_map *map, bool defer)
2291fb62fb0SOlivier Houchard {
2301fb62fb0SOlivier Houchard
2311fb62fb0SOlivier Houchard m->free(map, map->size, defer);
2321fb62fb0SOlivier Houchard return;
2331fb62fb0SOlivier Houchard }
2341fb62fb0SOlivier Houchard
2351fb62fb0SOlivier Houchard static inline size_t
ck_ht_map_probe_next(struct ck_ht_map * map,size_t offset,ck_ht_hash_t h,size_t probes)2361fb62fb0SOlivier Houchard ck_ht_map_probe_next(struct ck_ht_map *map, size_t offset, ck_ht_hash_t h, size_t probes)
2371fb62fb0SOlivier Houchard {
2381fb62fb0SOlivier Houchard ck_ht_hash_t r;
2391fb62fb0SOlivier Houchard size_t stride;
2401fb62fb0SOlivier Houchard unsigned long level = (unsigned long)probes >> CK_HT_BUCKET_SHIFT;
2411fb62fb0SOlivier Houchard
2421fb62fb0SOlivier Houchard r.value = (h.value >> map->step) >> level;
2431fb62fb0SOlivier Houchard stride = (r.value & ~CK_HT_BUCKET_MASK) << 1
2441fb62fb0SOlivier Houchard | (r.value & CK_HT_BUCKET_MASK);
2451fb62fb0SOlivier Houchard
2461fb62fb0SOlivier Houchard return (offset + level +
2471fb62fb0SOlivier Houchard (stride | CK_HT_BUCKET_LENGTH)) & map->mask;
2481fb62fb0SOlivier Houchard }
2491fb62fb0SOlivier Houchard
2501fb62fb0SOlivier Houchard bool
ck_ht_init(struct ck_ht * table,unsigned int mode,ck_ht_hash_cb_t * h,struct ck_malloc * m,CK_HT_TYPE entries,uint64_t seed)2511fb62fb0SOlivier Houchard ck_ht_init(struct ck_ht *table,
2521fb62fb0SOlivier Houchard unsigned int mode,
2531fb62fb0SOlivier Houchard ck_ht_hash_cb_t *h,
2541fb62fb0SOlivier Houchard struct ck_malloc *m,
2551fb62fb0SOlivier Houchard CK_HT_TYPE entries,
2561fb62fb0SOlivier Houchard uint64_t seed)
2571fb62fb0SOlivier Houchard {
2581fb62fb0SOlivier Houchard
2591fb62fb0SOlivier Houchard if (m == NULL || m->malloc == NULL || m->free == NULL)
2601fb62fb0SOlivier Houchard return false;
2611fb62fb0SOlivier Houchard
2621fb62fb0SOlivier Houchard table->m = m;
2631fb62fb0SOlivier Houchard table->mode = mode;
2641fb62fb0SOlivier Houchard table->seed = seed;
2651fb62fb0SOlivier Houchard
2661fb62fb0SOlivier Houchard if (h == NULL) {
2671fb62fb0SOlivier Houchard table->h = ck_ht_hash_wrapper;
2681fb62fb0SOlivier Houchard } else {
2691fb62fb0SOlivier Houchard table->h = h;
2701fb62fb0SOlivier Houchard }
2711fb62fb0SOlivier Houchard
2721fb62fb0SOlivier Houchard table->map = ck_ht_map_create(table, entries);
2731fb62fb0SOlivier Houchard return table->map != NULL;
2741fb62fb0SOlivier Houchard }
2751fb62fb0SOlivier Houchard
2761fb62fb0SOlivier Houchard static struct ck_ht_entry *
ck_ht_map_probe_wr(struct ck_ht_map * map,ck_ht_hash_t h,ck_ht_entry_t * snapshot,ck_ht_entry_t ** available,const void * key,uint16_t key_length,CK_HT_TYPE * probe_limit,CK_HT_TYPE * probe_wr)2771fb62fb0SOlivier Houchard ck_ht_map_probe_wr(struct ck_ht_map *map,
2781fb62fb0SOlivier Houchard ck_ht_hash_t h,
2791fb62fb0SOlivier Houchard ck_ht_entry_t *snapshot,
2801fb62fb0SOlivier Houchard ck_ht_entry_t **available,
2811fb62fb0SOlivier Houchard const void *key,
2821fb62fb0SOlivier Houchard uint16_t key_length,
2831fb62fb0SOlivier Houchard CK_HT_TYPE *probe_limit,
2841fb62fb0SOlivier Houchard CK_HT_TYPE *probe_wr)
2851fb62fb0SOlivier Houchard {
2861fb62fb0SOlivier Houchard struct ck_ht_entry *bucket, *cursor;
2871fb62fb0SOlivier Houchard struct ck_ht_entry *first = NULL;
2881fb62fb0SOlivier Houchard size_t offset, i, j;
2891fb62fb0SOlivier Houchard CK_HT_TYPE probes = 0;
2901fb62fb0SOlivier Houchard CK_HT_TYPE limit;
2911fb62fb0SOlivier Houchard
2921fb62fb0SOlivier Houchard if (probe_limit == NULL) {
2931fb62fb0SOlivier Houchard limit = ck_ht_map_bound_get(map, h);
2941fb62fb0SOlivier Houchard } else {
2951fb62fb0SOlivier Houchard limit = CK_HT_TYPE_MAX;
2961fb62fb0SOlivier Houchard }
2971fb62fb0SOlivier Houchard
2981fb62fb0SOlivier Houchard offset = h.value & map->mask;
2991fb62fb0SOlivier Houchard for (i = 0; i < map->probe_limit; i++) {
3001fb62fb0SOlivier Houchard /*
3011fb62fb0SOlivier Houchard * Probe on a complete cache line first. Scan forward and wrap around to
3021fb62fb0SOlivier Houchard * the beginning of the cache line. Only when the complete cache line has
3031fb62fb0SOlivier Houchard * been scanned do we move on to the next row.
3041fb62fb0SOlivier Houchard */
3051fb62fb0SOlivier Houchard bucket = (void *)((uintptr_t)(map->entries + offset) &
3061fb62fb0SOlivier Houchard ~(CK_MD_CACHELINE - 1));
3071fb62fb0SOlivier Houchard
3081fb62fb0SOlivier Houchard for (j = 0; j < CK_HT_BUCKET_LENGTH; j++) {
3091fb62fb0SOlivier Houchard uint16_t k;
3101fb62fb0SOlivier Houchard
3111fb62fb0SOlivier Houchard if (probes++ > limit)
3121fb62fb0SOlivier Houchard break;
3131fb62fb0SOlivier Houchard
3141fb62fb0SOlivier Houchard cursor = bucket + ((j + offset) & (CK_HT_BUCKET_LENGTH - 1));
3151fb62fb0SOlivier Houchard
3161fb62fb0SOlivier Houchard /*
3171fb62fb0SOlivier Houchard * It is probably worth it to encapsulate probe state
3181fb62fb0SOlivier Houchard * in order to prevent a complete reprobe sequence in
3191fb62fb0SOlivier Houchard * the case of intermittent writers.
3201fb62fb0SOlivier Houchard */
3211fb62fb0SOlivier Houchard if (cursor->key == CK_HT_KEY_TOMBSTONE) {
3221fb62fb0SOlivier Houchard if (first == NULL) {
3231fb62fb0SOlivier Houchard first = cursor;
3241fb62fb0SOlivier Houchard *probe_wr = probes;
3251fb62fb0SOlivier Houchard }
3261fb62fb0SOlivier Houchard
3271fb62fb0SOlivier Houchard continue;
3281fb62fb0SOlivier Houchard }
3291fb62fb0SOlivier Houchard
3301fb62fb0SOlivier Houchard if (cursor->key == CK_HT_KEY_EMPTY)
3311fb62fb0SOlivier Houchard goto leave;
3321fb62fb0SOlivier Houchard
3331fb62fb0SOlivier Houchard if (cursor->key == (uintptr_t)key)
3341fb62fb0SOlivier Houchard goto leave;
3351fb62fb0SOlivier Houchard
3361fb62fb0SOlivier Houchard if (map->mode & CK_HT_MODE_BYTESTRING) {
3371fb62fb0SOlivier Houchard void *pointer;
3381fb62fb0SOlivier Houchard
3391fb62fb0SOlivier Houchard /*
3401fb62fb0SOlivier Houchard * Check memoized portion of hash value before
3411fb62fb0SOlivier Houchard * expensive full-length comparison.
3421fb62fb0SOlivier Houchard */
3431fb62fb0SOlivier Houchard k = ck_ht_entry_key_length(cursor);
3441fb62fb0SOlivier Houchard if (k != key_length)
3451fb62fb0SOlivier Houchard continue;
3461fb62fb0SOlivier Houchard
3471fb62fb0SOlivier Houchard #ifdef CK_HT_PP
3481fb62fb0SOlivier Houchard if ((cursor->value >> CK_MD_VMA_BITS) != ((h.value >> 32) & CK_HT_KEY_MASK))
3491fb62fb0SOlivier Houchard continue;
3501fb62fb0SOlivier Houchard #else
3511fb62fb0SOlivier Houchard if (cursor->hash != h.value)
3521fb62fb0SOlivier Houchard continue;
3531fb62fb0SOlivier Houchard #endif
3541fb62fb0SOlivier Houchard
3551fb62fb0SOlivier Houchard pointer = ck_ht_entry_key(cursor);
3561fb62fb0SOlivier Houchard if (memcmp(pointer, key, key_length) == 0)
3571fb62fb0SOlivier Houchard goto leave;
3581fb62fb0SOlivier Houchard }
3591fb62fb0SOlivier Houchard }
3601fb62fb0SOlivier Houchard
3611fb62fb0SOlivier Houchard offset = ck_ht_map_probe_next(map, offset, h, probes);
3621fb62fb0SOlivier Houchard }
3631fb62fb0SOlivier Houchard
3641fb62fb0SOlivier Houchard cursor = NULL;
3651fb62fb0SOlivier Houchard
3661fb62fb0SOlivier Houchard leave:
3671fb62fb0SOlivier Houchard if (probe_limit != NULL) {
3681fb62fb0SOlivier Houchard *probe_limit = probes;
3691fb62fb0SOlivier Houchard } else if (first == NULL) {
3701fb62fb0SOlivier Houchard *probe_wr = probes;
3711fb62fb0SOlivier Houchard }
3721fb62fb0SOlivier Houchard
3731fb62fb0SOlivier Houchard *available = first;
3741fb62fb0SOlivier Houchard
3751fb62fb0SOlivier Houchard if (cursor != NULL) {
3761fb62fb0SOlivier Houchard *snapshot = *cursor;
3771fb62fb0SOlivier Houchard }
3781fb62fb0SOlivier Houchard
3791fb62fb0SOlivier Houchard return cursor;
3801fb62fb0SOlivier Houchard }
3811fb62fb0SOlivier Houchard
3821fb62fb0SOlivier Houchard bool
ck_ht_gc(struct ck_ht * ht,unsigned long cycles,unsigned long seed)3831fb62fb0SOlivier Houchard ck_ht_gc(struct ck_ht *ht, unsigned long cycles, unsigned long seed)
3841fb62fb0SOlivier Houchard {
3851fb62fb0SOlivier Houchard CK_HT_WORD *bounds = NULL;
3861fb62fb0SOlivier Houchard struct ck_ht_map *map = ht->map;
3871fb62fb0SOlivier Houchard CK_HT_TYPE maximum, i;
3881fb62fb0SOlivier Houchard CK_HT_TYPE size = 0;
3891fb62fb0SOlivier Houchard
3901fb62fb0SOlivier Houchard if (map->n_entries == 0) {
3911fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->probe_maximum, 0);
3921fb62fb0SOlivier Houchard if (map->probe_bound != NULL)
3931fb62fb0SOlivier Houchard memset(map->probe_bound, 0, sizeof(CK_HT_WORD) * map->capacity);
3941fb62fb0SOlivier Houchard
3951fb62fb0SOlivier Houchard return true;
3961fb62fb0SOlivier Houchard }
3971fb62fb0SOlivier Houchard
3981fb62fb0SOlivier Houchard if (cycles == 0) {
3991fb62fb0SOlivier Houchard maximum = 0;
4001fb62fb0SOlivier Houchard
4011fb62fb0SOlivier Houchard if (map->probe_bound != NULL) {
4021fb62fb0SOlivier Houchard size = sizeof(CK_HT_WORD) * map->capacity;
4031fb62fb0SOlivier Houchard bounds = ht->m->malloc(size);
4041fb62fb0SOlivier Houchard if (bounds == NULL)
4051fb62fb0SOlivier Houchard return false;
4061fb62fb0SOlivier Houchard
4071fb62fb0SOlivier Houchard memset(bounds, 0, size);
4081fb62fb0SOlivier Houchard }
4091fb62fb0SOlivier Houchard } else {
4101fb62fb0SOlivier Houchard maximum = map->probe_maximum;
4111fb62fb0SOlivier Houchard }
4121fb62fb0SOlivier Houchard
4131fb62fb0SOlivier Houchard for (i = 0; i < map->capacity; i++) {
4141fb62fb0SOlivier Houchard struct ck_ht_entry *entry, *priority, snapshot;
4151fb62fb0SOlivier Houchard struct ck_ht_hash h;
4161fb62fb0SOlivier Houchard CK_HT_TYPE probes_wr;
4171fb62fb0SOlivier Houchard CK_HT_TYPE offset;
4181fb62fb0SOlivier Houchard
4191fb62fb0SOlivier Houchard entry = &map->entries[(i + seed) & map->mask];
4201fb62fb0SOlivier Houchard if (entry->key == CK_HT_KEY_EMPTY ||
4211fb62fb0SOlivier Houchard entry->key == CK_HT_KEY_TOMBSTONE) {
4221fb62fb0SOlivier Houchard continue;
4231fb62fb0SOlivier Houchard }
4241fb62fb0SOlivier Houchard
4251fb62fb0SOlivier Houchard if (ht->mode & CK_HT_MODE_BYTESTRING) {
4261fb62fb0SOlivier Houchard #ifndef CK_HT_PP
4271fb62fb0SOlivier Houchard h.value = entry->hash;
4281fb62fb0SOlivier Houchard #else
4291fb62fb0SOlivier Houchard ht->h(&h, ck_ht_entry_key(entry), ck_ht_entry_key_length(entry),
4301fb62fb0SOlivier Houchard ht->seed);
4311fb62fb0SOlivier Houchard #endif
4321fb62fb0SOlivier Houchard entry = ck_ht_map_probe_wr(map, h, &snapshot, &priority,
4331fb62fb0SOlivier Houchard ck_ht_entry_key(entry),
4341fb62fb0SOlivier Houchard ck_ht_entry_key_length(entry),
4351fb62fb0SOlivier Houchard NULL, &probes_wr);
4361fb62fb0SOlivier Houchard } else {
4371fb62fb0SOlivier Houchard #ifndef CK_HT_PP
4381fb62fb0SOlivier Houchard h.value = entry->hash;
4391fb62fb0SOlivier Houchard #else
4401fb62fb0SOlivier Houchard ht->h(&h, &entry->key, sizeof(entry->key), ht->seed);
4411fb62fb0SOlivier Houchard #endif
4421fb62fb0SOlivier Houchard entry = ck_ht_map_probe_wr(map, h, &snapshot, &priority,
4431fb62fb0SOlivier Houchard (void *)entry->key,
4441fb62fb0SOlivier Houchard sizeof(entry->key),
4451fb62fb0SOlivier Houchard NULL, &probes_wr);
4461fb62fb0SOlivier Houchard }
4471fb62fb0SOlivier Houchard
4481fb62fb0SOlivier Houchard offset = h.value & map->mask;
4491fb62fb0SOlivier Houchard
4501fb62fb0SOlivier Houchard if (priority != NULL) {
4511fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1);
4521fb62fb0SOlivier Houchard ck_pr_fence_store();
4531fb62fb0SOlivier Houchard #ifndef CK_HT_PP
4541fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&priority->key_length, entry->key_length);
4551fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&priority->hash, entry->hash);
4561fb62fb0SOlivier Houchard #endif
4571fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&priority->value, (void *)entry->value);
4581fb62fb0SOlivier Houchard ck_pr_fence_store();
4591fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&priority->key, (void *)entry->key);
4601fb62fb0SOlivier Houchard ck_pr_fence_store();
4611fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1);
4621fb62fb0SOlivier Houchard ck_pr_fence_store();
4631fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&entry->key, (void *)CK_HT_KEY_TOMBSTONE);
4641fb62fb0SOlivier Houchard ck_pr_fence_store();
4651fb62fb0SOlivier Houchard }
4661fb62fb0SOlivier Houchard
4671fb62fb0SOlivier Houchard if (cycles == 0) {
4681fb62fb0SOlivier Houchard if (probes_wr > maximum)
4691fb62fb0SOlivier Houchard maximum = probes_wr;
4701fb62fb0SOlivier Houchard
4711fb62fb0SOlivier Houchard if (probes_wr >= CK_HT_WORD_MAX)
4721fb62fb0SOlivier Houchard probes_wr = CK_HT_WORD_MAX;
4731fb62fb0SOlivier Houchard
4741fb62fb0SOlivier Houchard if (bounds != NULL && probes_wr > bounds[offset])
4751fb62fb0SOlivier Houchard bounds[offset] = probes_wr;
4761fb62fb0SOlivier Houchard } else if (--cycles == 0)
4771fb62fb0SOlivier Houchard break;
4781fb62fb0SOlivier Houchard }
4791fb62fb0SOlivier Houchard
4801fb62fb0SOlivier Houchard if (maximum != map->probe_maximum)
4811fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->probe_maximum, maximum);
4821fb62fb0SOlivier Houchard
4831fb62fb0SOlivier Houchard if (bounds != NULL) {
4841fb62fb0SOlivier Houchard for (i = 0; i < map->capacity; i++)
4851fb62fb0SOlivier Houchard CK_HT_STORE(&map->probe_bound[i], bounds[i]);
4861fb62fb0SOlivier Houchard
4871fb62fb0SOlivier Houchard ht->m->free(bounds, size, false);
4881fb62fb0SOlivier Houchard }
4891fb62fb0SOlivier Houchard
4901fb62fb0SOlivier Houchard return true;
4911fb62fb0SOlivier Houchard }
4921fb62fb0SOlivier Houchard
4931fb62fb0SOlivier Houchard static struct ck_ht_entry *
ck_ht_map_probe_rd(struct ck_ht_map * map,ck_ht_hash_t h,ck_ht_entry_t * snapshot,const void * key,uint16_t key_length)4941fb62fb0SOlivier Houchard ck_ht_map_probe_rd(struct ck_ht_map *map,
4951fb62fb0SOlivier Houchard ck_ht_hash_t h,
4961fb62fb0SOlivier Houchard ck_ht_entry_t *snapshot,
4971fb62fb0SOlivier Houchard const void *key,
4981fb62fb0SOlivier Houchard uint16_t key_length)
4991fb62fb0SOlivier Houchard {
5001fb62fb0SOlivier Houchard struct ck_ht_entry *bucket, *cursor;
5011fb62fb0SOlivier Houchard size_t offset, i, j;
5021fb62fb0SOlivier Houchard CK_HT_TYPE probes = 0;
5031fb62fb0SOlivier Houchard CK_HT_TYPE probe_maximum;
5041fb62fb0SOlivier Houchard
5051fb62fb0SOlivier Houchard #ifndef CK_HT_PP
5061fb62fb0SOlivier Houchard CK_HT_TYPE d = 0;
5071fb62fb0SOlivier Houchard CK_HT_TYPE d_prime = 0;
5081fb62fb0SOlivier Houchard retry:
5091fb62fb0SOlivier Houchard #endif
5101fb62fb0SOlivier Houchard
5111fb62fb0SOlivier Houchard probe_maximum = ck_ht_map_bound_get(map, h);
5121fb62fb0SOlivier Houchard offset = h.value & map->mask;
5131fb62fb0SOlivier Houchard
5141fb62fb0SOlivier Houchard for (i = 0; i < map->probe_limit; i++) {
5151fb62fb0SOlivier Houchard /*
5161fb62fb0SOlivier Houchard * Probe on a complete cache line first. Scan forward and wrap around to
5171fb62fb0SOlivier Houchard * the beginning of the cache line. Only when the complete cache line has
5181fb62fb0SOlivier Houchard * been scanned do we move on to the next row.
5191fb62fb0SOlivier Houchard */
5201fb62fb0SOlivier Houchard bucket = (void *)((uintptr_t)(map->entries + offset) &
5211fb62fb0SOlivier Houchard ~(CK_MD_CACHELINE - 1));
5221fb62fb0SOlivier Houchard
5231fb62fb0SOlivier Houchard for (j = 0; j < CK_HT_BUCKET_LENGTH; j++) {
5241fb62fb0SOlivier Houchard uint16_t k;
5251fb62fb0SOlivier Houchard
5261fb62fb0SOlivier Houchard if (probes++ > probe_maximum)
5271fb62fb0SOlivier Houchard return NULL;
5281fb62fb0SOlivier Houchard
5291fb62fb0SOlivier Houchard cursor = bucket + ((j + offset) & (CK_HT_BUCKET_LENGTH - 1));
5301fb62fb0SOlivier Houchard
5311fb62fb0SOlivier Houchard #ifdef CK_HT_PP
5321fb62fb0SOlivier Houchard snapshot->key = (uintptr_t)ck_pr_load_ptr(&cursor->key);
5331fb62fb0SOlivier Houchard ck_pr_fence_load();
5341fb62fb0SOlivier Houchard snapshot->value = (uintptr_t)ck_pr_load_ptr(&cursor->value);
5351fb62fb0SOlivier Houchard #else
5361fb62fb0SOlivier Houchard d = CK_HT_TYPE_LOAD(&map->deletions);
5371fb62fb0SOlivier Houchard snapshot->key = (uintptr_t)ck_pr_load_ptr(&cursor->key);
5381fb62fb0SOlivier Houchard ck_pr_fence_load();
5391fb62fb0SOlivier Houchard snapshot->key_length = CK_HT_TYPE_LOAD(&cursor->key_length);
5401fb62fb0SOlivier Houchard snapshot->hash = CK_HT_TYPE_LOAD(&cursor->hash);
5411fb62fb0SOlivier Houchard snapshot->value = (uintptr_t)ck_pr_load_ptr(&cursor->value);
5421fb62fb0SOlivier Houchard #endif
5431fb62fb0SOlivier Houchard
5441fb62fb0SOlivier Houchard /*
5451fb62fb0SOlivier Houchard * It is probably worth it to encapsulate probe state
5461fb62fb0SOlivier Houchard * in order to prevent a complete reprobe sequence in
5471fb62fb0SOlivier Houchard * the case of intermittent writers.
5481fb62fb0SOlivier Houchard */
5491fb62fb0SOlivier Houchard if (snapshot->key == CK_HT_KEY_TOMBSTONE)
5501fb62fb0SOlivier Houchard continue;
5511fb62fb0SOlivier Houchard
5521fb62fb0SOlivier Houchard if (snapshot->key == CK_HT_KEY_EMPTY)
5531fb62fb0SOlivier Houchard goto leave;
5541fb62fb0SOlivier Houchard
5551fb62fb0SOlivier Houchard if (snapshot->key == (uintptr_t)key)
5561fb62fb0SOlivier Houchard goto leave;
5571fb62fb0SOlivier Houchard
5581fb62fb0SOlivier Houchard if (map->mode & CK_HT_MODE_BYTESTRING) {
5591fb62fb0SOlivier Houchard void *pointer;
5601fb62fb0SOlivier Houchard
5611fb62fb0SOlivier Houchard /*
5621fb62fb0SOlivier Houchard * Check memoized portion of hash value before
5631fb62fb0SOlivier Houchard * expensive full-length comparison.
5641fb62fb0SOlivier Houchard */
5651fb62fb0SOlivier Houchard k = ck_ht_entry_key_length(snapshot);
5661fb62fb0SOlivier Houchard if (k != key_length)
5671fb62fb0SOlivier Houchard continue;
5681fb62fb0SOlivier Houchard #ifdef CK_HT_PP
5691fb62fb0SOlivier Houchard if ((snapshot->value >> CK_MD_VMA_BITS) != ((h.value >> 32) & CK_HT_KEY_MASK))
5701fb62fb0SOlivier Houchard continue;
5711fb62fb0SOlivier Houchard #else
5721fb62fb0SOlivier Houchard if (snapshot->hash != h.value)
5731fb62fb0SOlivier Houchard continue;
5741fb62fb0SOlivier Houchard
5751fb62fb0SOlivier Houchard d_prime = CK_HT_TYPE_LOAD(&map->deletions);
5761fb62fb0SOlivier Houchard
5771fb62fb0SOlivier Houchard /*
5781fb62fb0SOlivier Houchard * It is possible that the slot was
5791fb62fb0SOlivier Houchard * replaced, initiate a re-probe.
5801fb62fb0SOlivier Houchard */
5811fb62fb0SOlivier Houchard if (d != d_prime)
5821fb62fb0SOlivier Houchard goto retry;
5831fb62fb0SOlivier Houchard #endif
5841fb62fb0SOlivier Houchard
5851fb62fb0SOlivier Houchard pointer = ck_ht_entry_key(snapshot);
5861fb62fb0SOlivier Houchard if (memcmp(pointer, key, key_length) == 0)
5871fb62fb0SOlivier Houchard goto leave;
5881fb62fb0SOlivier Houchard }
5891fb62fb0SOlivier Houchard }
5901fb62fb0SOlivier Houchard
5911fb62fb0SOlivier Houchard offset = ck_ht_map_probe_next(map, offset, h, probes);
5921fb62fb0SOlivier Houchard }
5931fb62fb0SOlivier Houchard
5941fb62fb0SOlivier Houchard return NULL;
5951fb62fb0SOlivier Houchard
5961fb62fb0SOlivier Houchard leave:
5971fb62fb0SOlivier Houchard return cursor;
5981fb62fb0SOlivier Houchard }
5991fb62fb0SOlivier Houchard
6001fb62fb0SOlivier Houchard CK_HT_TYPE
ck_ht_count(struct ck_ht * table)6011fb62fb0SOlivier Houchard ck_ht_count(struct ck_ht *table)
6021fb62fb0SOlivier Houchard {
6031fb62fb0SOlivier Houchard struct ck_ht_map *map = ck_pr_load_ptr(&table->map);
6041fb62fb0SOlivier Houchard
6051fb62fb0SOlivier Houchard return CK_HT_TYPE_LOAD(&map->n_entries);
6061fb62fb0SOlivier Houchard }
6071fb62fb0SOlivier Houchard
6081fb62fb0SOlivier Houchard bool
ck_ht_next(struct ck_ht * table,struct ck_ht_iterator * i,struct ck_ht_entry ** entry)6091fb62fb0SOlivier Houchard ck_ht_next(struct ck_ht *table,
6101fb62fb0SOlivier Houchard struct ck_ht_iterator *i,
6111fb62fb0SOlivier Houchard struct ck_ht_entry **entry)
6121fb62fb0SOlivier Houchard {
6131fb62fb0SOlivier Houchard struct ck_ht_map *map = table->map;
6141fb62fb0SOlivier Houchard uintptr_t key;
6151fb62fb0SOlivier Houchard
6161fb62fb0SOlivier Houchard if (i->offset >= map->capacity)
6171fb62fb0SOlivier Houchard return false;
6181fb62fb0SOlivier Houchard
6191fb62fb0SOlivier Houchard do {
6201fb62fb0SOlivier Houchard key = map->entries[i->offset].key;
6211fb62fb0SOlivier Houchard if (key != CK_HT_KEY_EMPTY && key != CK_HT_KEY_TOMBSTONE)
6221fb62fb0SOlivier Houchard break;
6231fb62fb0SOlivier Houchard } while (++i->offset < map->capacity);
6241fb62fb0SOlivier Houchard
6251fb62fb0SOlivier Houchard if (i->offset >= map->capacity)
6261fb62fb0SOlivier Houchard return false;
6271fb62fb0SOlivier Houchard
6281fb62fb0SOlivier Houchard *entry = map->entries + i->offset++;
6291fb62fb0SOlivier Houchard return true;
6301fb62fb0SOlivier Houchard }
6311fb62fb0SOlivier Houchard
6321fb62fb0SOlivier Houchard bool
ck_ht_reset_size_spmc(struct ck_ht * table,CK_HT_TYPE size)6331fb62fb0SOlivier Houchard ck_ht_reset_size_spmc(struct ck_ht *table, CK_HT_TYPE size)
6341fb62fb0SOlivier Houchard {
6351fb62fb0SOlivier Houchard struct ck_ht_map *map, *update;
6361fb62fb0SOlivier Houchard
6371fb62fb0SOlivier Houchard map = table->map;
6381fb62fb0SOlivier Houchard update = ck_ht_map_create(table, size);
6391fb62fb0SOlivier Houchard if (update == NULL)
6401fb62fb0SOlivier Houchard return false;
6411fb62fb0SOlivier Houchard
6421fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&table->map, update);
6431fb62fb0SOlivier Houchard ck_ht_map_destroy(table->m, map, true);
6441fb62fb0SOlivier Houchard return true;
6451fb62fb0SOlivier Houchard }
6461fb62fb0SOlivier Houchard
6471fb62fb0SOlivier Houchard bool
ck_ht_reset_spmc(struct ck_ht * table)6481fb62fb0SOlivier Houchard ck_ht_reset_spmc(struct ck_ht *table)
6491fb62fb0SOlivier Houchard {
6501fb62fb0SOlivier Houchard struct ck_ht_map *map = table->map;
6511fb62fb0SOlivier Houchard
6521fb62fb0SOlivier Houchard return ck_ht_reset_size_spmc(table, map->capacity);
6531fb62fb0SOlivier Houchard }
6541fb62fb0SOlivier Houchard
6551fb62fb0SOlivier Houchard bool
ck_ht_grow_spmc(struct ck_ht * table,CK_HT_TYPE capacity)6561fb62fb0SOlivier Houchard ck_ht_grow_spmc(struct ck_ht *table, CK_HT_TYPE capacity)
6571fb62fb0SOlivier Houchard {
6581fb62fb0SOlivier Houchard struct ck_ht_map *map, *update;
6591fb62fb0SOlivier Houchard struct ck_ht_entry *bucket, *previous;
6601fb62fb0SOlivier Houchard struct ck_ht_hash h;
6611fb62fb0SOlivier Houchard size_t k, i, j, offset;
6621fb62fb0SOlivier Houchard CK_HT_TYPE probes;
6631fb62fb0SOlivier Houchard
6641fb62fb0SOlivier Houchard restart:
6651fb62fb0SOlivier Houchard map = table->map;
6661fb62fb0SOlivier Houchard
6671fb62fb0SOlivier Houchard if (map->capacity >= capacity)
6681fb62fb0SOlivier Houchard return false;
6691fb62fb0SOlivier Houchard
6701fb62fb0SOlivier Houchard update = ck_ht_map_create(table, capacity);
6711fb62fb0SOlivier Houchard if (update == NULL)
6721fb62fb0SOlivier Houchard return false;
6731fb62fb0SOlivier Houchard
6741fb62fb0SOlivier Houchard for (k = 0; k < map->capacity; k++) {
6751fb62fb0SOlivier Houchard previous = &map->entries[k];
6761fb62fb0SOlivier Houchard
6771fb62fb0SOlivier Houchard if (previous->key == CK_HT_KEY_EMPTY || previous->key == CK_HT_KEY_TOMBSTONE)
6781fb62fb0SOlivier Houchard continue;
6791fb62fb0SOlivier Houchard
6801fb62fb0SOlivier Houchard if (table->mode & CK_HT_MODE_BYTESTRING) {
6811fb62fb0SOlivier Houchard #ifdef CK_HT_PP
6821fb62fb0SOlivier Houchard void *key;
6831fb62fb0SOlivier Houchard uint16_t key_length;
6841fb62fb0SOlivier Houchard
6851fb62fb0SOlivier Houchard key = ck_ht_entry_key(previous);
6861fb62fb0SOlivier Houchard key_length = ck_ht_entry_key_length(previous);
6871fb62fb0SOlivier Houchard #endif
6881fb62fb0SOlivier Houchard
6891fb62fb0SOlivier Houchard #ifndef CK_HT_PP
6901fb62fb0SOlivier Houchard h.value = previous->hash;
6911fb62fb0SOlivier Houchard #else
6921fb62fb0SOlivier Houchard table->h(&h, key, key_length, table->seed);
6931fb62fb0SOlivier Houchard #endif
6941fb62fb0SOlivier Houchard } else {
6951fb62fb0SOlivier Houchard #ifndef CK_HT_PP
6961fb62fb0SOlivier Houchard h.value = previous->hash;
6971fb62fb0SOlivier Houchard #else
6981fb62fb0SOlivier Houchard table->h(&h, &previous->key, sizeof(previous->key), table->seed);
6991fb62fb0SOlivier Houchard #endif
7001fb62fb0SOlivier Houchard }
7011fb62fb0SOlivier Houchard
7021fb62fb0SOlivier Houchard offset = h.value & update->mask;
7031fb62fb0SOlivier Houchard probes = 0;
7041fb62fb0SOlivier Houchard
7051fb62fb0SOlivier Houchard for (i = 0; i < update->probe_limit; i++) {
7061fb62fb0SOlivier Houchard bucket = (void *)((uintptr_t)(update->entries + offset) & ~(CK_MD_CACHELINE - 1));
7071fb62fb0SOlivier Houchard
7081fb62fb0SOlivier Houchard for (j = 0; j < CK_HT_BUCKET_LENGTH; j++) {
7091fb62fb0SOlivier Houchard struct ck_ht_entry *cursor = bucket + ((j + offset) & (CK_HT_BUCKET_LENGTH - 1));
7101fb62fb0SOlivier Houchard
7111fb62fb0SOlivier Houchard probes++;
7121fb62fb0SOlivier Houchard if (CK_CC_LIKELY(cursor->key == CK_HT_KEY_EMPTY)) {
7131fb62fb0SOlivier Houchard *cursor = *previous;
7141fb62fb0SOlivier Houchard update->n_entries++;
7151fb62fb0SOlivier Houchard ck_ht_map_bound_set(update, h, probes);
7161fb62fb0SOlivier Houchard break;
7171fb62fb0SOlivier Houchard }
7181fb62fb0SOlivier Houchard }
7191fb62fb0SOlivier Houchard
7201fb62fb0SOlivier Houchard if (j < CK_HT_BUCKET_LENGTH)
7211fb62fb0SOlivier Houchard break;
7221fb62fb0SOlivier Houchard
7231fb62fb0SOlivier Houchard offset = ck_ht_map_probe_next(update, offset, h, probes);
7241fb62fb0SOlivier Houchard }
7251fb62fb0SOlivier Houchard
7261fb62fb0SOlivier Houchard if (i == update->probe_limit) {
7271fb62fb0SOlivier Houchard /*
7281fb62fb0SOlivier Houchard * We have hit the probe limit, the map needs to be even
7291fb62fb0SOlivier Houchard * larger.
7301fb62fb0SOlivier Houchard */
7311fb62fb0SOlivier Houchard ck_ht_map_destroy(table->m, update, false);
7321fb62fb0SOlivier Houchard capacity <<= 1;
7331fb62fb0SOlivier Houchard goto restart;
7341fb62fb0SOlivier Houchard }
7351fb62fb0SOlivier Houchard }
7361fb62fb0SOlivier Houchard
7371fb62fb0SOlivier Houchard ck_pr_fence_store();
7381fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&table->map, update);
7391fb62fb0SOlivier Houchard ck_ht_map_destroy(table->m, map, true);
7401fb62fb0SOlivier Houchard return true;
7411fb62fb0SOlivier Houchard }
7421fb62fb0SOlivier Houchard
7431fb62fb0SOlivier Houchard bool
ck_ht_remove_spmc(struct ck_ht * table,ck_ht_hash_t h,ck_ht_entry_t * entry)7441fb62fb0SOlivier Houchard ck_ht_remove_spmc(struct ck_ht *table,
7451fb62fb0SOlivier Houchard ck_ht_hash_t h,
7461fb62fb0SOlivier Houchard ck_ht_entry_t *entry)
7471fb62fb0SOlivier Houchard {
7481fb62fb0SOlivier Houchard struct ck_ht_map *map;
7491fb62fb0SOlivier Houchard struct ck_ht_entry *candidate, snapshot;
7501fb62fb0SOlivier Houchard
7511fb62fb0SOlivier Houchard map = table->map;
7521fb62fb0SOlivier Houchard
7531fb62fb0SOlivier Houchard if (table->mode & CK_HT_MODE_BYTESTRING) {
7541fb62fb0SOlivier Houchard candidate = ck_ht_map_probe_rd(map, h, &snapshot,
7551fb62fb0SOlivier Houchard ck_ht_entry_key(entry),
7561fb62fb0SOlivier Houchard ck_ht_entry_key_length(entry));
7571fb62fb0SOlivier Houchard } else {
7581fb62fb0SOlivier Houchard candidate = ck_ht_map_probe_rd(map, h, &snapshot,
7591fb62fb0SOlivier Houchard (void *)entry->key,
7601fb62fb0SOlivier Houchard sizeof(entry->key));
7611fb62fb0SOlivier Houchard }
7621fb62fb0SOlivier Houchard
7631fb62fb0SOlivier Houchard /* No matching entry was found. */
7641fb62fb0SOlivier Houchard if (candidate == NULL || snapshot.key == CK_HT_KEY_EMPTY)
7651fb62fb0SOlivier Houchard return false;
7661fb62fb0SOlivier Houchard
7671fb62fb0SOlivier Houchard *entry = snapshot;
7681fb62fb0SOlivier Houchard
7691fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->key, (void *)CK_HT_KEY_TOMBSTONE);
7701fb62fb0SOlivier Houchard ck_pr_fence_store();
7711fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->n_entries, map->n_entries - 1);
7721fb62fb0SOlivier Houchard return true;
7731fb62fb0SOlivier Houchard }
7741fb62fb0SOlivier Houchard
7751fb62fb0SOlivier Houchard bool
ck_ht_get_spmc(struct ck_ht * table,ck_ht_hash_t h,ck_ht_entry_t * entry)7761fb62fb0SOlivier Houchard ck_ht_get_spmc(struct ck_ht *table,
7771fb62fb0SOlivier Houchard ck_ht_hash_t h,
7781fb62fb0SOlivier Houchard ck_ht_entry_t *entry)
7791fb62fb0SOlivier Houchard {
7801fb62fb0SOlivier Houchard struct ck_ht_entry *candidate, snapshot;
7811fb62fb0SOlivier Houchard struct ck_ht_map *map;
7821fb62fb0SOlivier Houchard CK_HT_TYPE d, d_prime;
7831fb62fb0SOlivier Houchard
7841fb62fb0SOlivier Houchard restart:
7851fb62fb0SOlivier Houchard map = ck_pr_load_ptr(&table->map);
7861fb62fb0SOlivier Houchard
7871fb62fb0SOlivier Houchard /*
7881fb62fb0SOlivier Houchard * Platforms that cannot read key and key_length atomically must reprobe
7891fb62fb0SOlivier Houchard * on the scan of any single entry.
7901fb62fb0SOlivier Houchard */
7911fb62fb0SOlivier Houchard d = CK_HT_TYPE_LOAD(&map->deletions);
7921fb62fb0SOlivier Houchard
7931fb62fb0SOlivier Houchard if (table->mode & CK_HT_MODE_BYTESTRING) {
7941fb62fb0SOlivier Houchard candidate = ck_ht_map_probe_rd(map, h, &snapshot,
7951fb62fb0SOlivier Houchard ck_ht_entry_key(entry), ck_ht_entry_key_length(entry));
7961fb62fb0SOlivier Houchard } else {
7971fb62fb0SOlivier Houchard candidate = ck_ht_map_probe_rd(map, h, &snapshot,
7981fb62fb0SOlivier Houchard (void *)entry->key, sizeof(entry->key));
7991fb62fb0SOlivier Houchard }
8001fb62fb0SOlivier Houchard
8011fb62fb0SOlivier Houchard d_prime = CK_HT_TYPE_LOAD(&map->deletions);
8021fb62fb0SOlivier Houchard if (d != d_prime) {
8031fb62fb0SOlivier Houchard /*
8041fb62fb0SOlivier Houchard * It is possible we have read (K, V'). Only valid states are
8051fb62fb0SOlivier Houchard * (K, V), (K', V') and (T, V). Restart load operation in face
8061fb62fb0SOlivier Houchard * of concurrent deletions or replacements.
8071fb62fb0SOlivier Houchard */
8081fb62fb0SOlivier Houchard goto restart;
8091fb62fb0SOlivier Houchard }
8101fb62fb0SOlivier Houchard
8111fb62fb0SOlivier Houchard if (candidate == NULL || snapshot.key == CK_HT_KEY_EMPTY)
8121fb62fb0SOlivier Houchard return false;
8131fb62fb0SOlivier Houchard
8141fb62fb0SOlivier Houchard *entry = snapshot;
8151fb62fb0SOlivier Houchard return true;
8161fb62fb0SOlivier Houchard }
8171fb62fb0SOlivier Houchard
8181fb62fb0SOlivier Houchard bool
ck_ht_set_spmc(struct ck_ht * table,ck_ht_hash_t h,ck_ht_entry_t * entry)8191fb62fb0SOlivier Houchard ck_ht_set_spmc(struct ck_ht *table,
8201fb62fb0SOlivier Houchard ck_ht_hash_t h,
8211fb62fb0SOlivier Houchard ck_ht_entry_t *entry)
8221fb62fb0SOlivier Houchard {
8231fb62fb0SOlivier Houchard struct ck_ht_entry snapshot, *candidate, *priority;
8241fb62fb0SOlivier Houchard struct ck_ht_map *map;
8251fb62fb0SOlivier Houchard CK_HT_TYPE probes, probes_wr;
8261fb62fb0SOlivier Houchard bool empty = false;
8271fb62fb0SOlivier Houchard
8281fb62fb0SOlivier Houchard for (;;) {
8291fb62fb0SOlivier Houchard map = table->map;
8301fb62fb0SOlivier Houchard
8311fb62fb0SOlivier Houchard if (table->mode & CK_HT_MODE_BYTESTRING) {
8321fb62fb0SOlivier Houchard candidate = ck_ht_map_probe_wr(map, h, &snapshot, &priority,
8331fb62fb0SOlivier Houchard ck_ht_entry_key(entry),
8341fb62fb0SOlivier Houchard ck_ht_entry_key_length(entry),
8351fb62fb0SOlivier Houchard &probes, &probes_wr);
8361fb62fb0SOlivier Houchard } else {
8371fb62fb0SOlivier Houchard candidate = ck_ht_map_probe_wr(map, h, &snapshot, &priority,
8381fb62fb0SOlivier Houchard (void *)entry->key,
8391fb62fb0SOlivier Houchard sizeof(entry->key),
8401fb62fb0SOlivier Houchard &probes, &probes_wr);
8411fb62fb0SOlivier Houchard }
8421fb62fb0SOlivier Houchard
8431fb62fb0SOlivier Houchard if (priority != NULL) {
8441fb62fb0SOlivier Houchard probes = probes_wr;
8451fb62fb0SOlivier Houchard break;
8461fb62fb0SOlivier Houchard }
8471fb62fb0SOlivier Houchard
8481fb62fb0SOlivier Houchard if (candidate != NULL)
8491fb62fb0SOlivier Houchard break;
8501fb62fb0SOlivier Houchard
8511fb62fb0SOlivier Houchard if (ck_ht_grow_spmc(table, map->capacity << 1) == false)
8521fb62fb0SOlivier Houchard return false;
8531fb62fb0SOlivier Houchard }
8541fb62fb0SOlivier Houchard
8551fb62fb0SOlivier Houchard if (candidate == NULL) {
8561fb62fb0SOlivier Houchard candidate = priority;
8571fb62fb0SOlivier Houchard empty = true;
8581fb62fb0SOlivier Houchard }
8591fb62fb0SOlivier Houchard
8601fb62fb0SOlivier Houchard if (candidate->key != CK_HT_KEY_EMPTY &&
8611fb62fb0SOlivier Houchard priority != NULL && candidate != priority) {
8621fb62fb0SOlivier Houchard /*
8631fb62fb0SOlivier Houchard * Entry is moved into another position in probe sequence.
8641fb62fb0SOlivier Houchard * We avoid a state of (K, B) (where [K, B] -> [K', B]) by
8651fb62fb0SOlivier Houchard * guaranteeing a forced reprobe before transitioning from K to
8661fb62fb0SOlivier Houchard * T. (K, B) implies (K, B, D') so we will reprobe successfully
8671fb62fb0SOlivier Houchard * from this transient state.
8681fb62fb0SOlivier Houchard */
8691fb62fb0SOlivier Houchard probes = probes_wr;
8701fb62fb0SOlivier Houchard
8711fb62fb0SOlivier Houchard #ifndef CK_HT_PP
8721fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&priority->key_length, entry->key_length);
8731fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&priority->hash, entry->hash);
8741fb62fb0SOlivier Houchard #endif
8751fb62fb0SOlivier Houchard
8761fb62fb0SOlivier Houchard /*
8771fb62fb0SOlivier Houchard * Readers must observe version counter change before they
8781fb62fb0SOlivier Houchard * observe re-use. If they observe re-use, it is at most
8791fb62fb0SOlivier Houchard * a tombstone.
8801fb62fb0SOlivier Houchard */
8811fb62fb0SOlivier Houchard if (priority->value == CK_HT_KEY_TOMBSTONE) {
8821fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1);
8831fb62fb0SOlivier Houchard ck_pr_fence_store();
8841fb62fb0SOlivier Houchard }
8851fb62fb0SOlivier Houchard
8861fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&priority->value, (void *)entry->value);
8871fb62fb0SOlivier Houchard ck_pr_fence_store();
8881fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&priority->key, (void *)entry->key);
8891fb62fb0SOlivier Houchard ck_pr_fence_store();
8901fb62fb0SOlivier Houchard
8911fb62fb0SOlivier Houchard /*
8921fb62fb0SOlivier Houchard * Make sure that readers who observe the tombstone would
8931fb62fb0SOlivier Houchard * also observe counter change.
8941fb62fb0SOlivier Houchard */
8951fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1);
8961fb62fb0SOlivier Houchard ck_pr_fence_store();
8971fb62fb0SOlivier Houchard
8981fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->key, (void *)CK_HT_KEY_TOMBSTONE);
8991fb62fb0SOlivier Houchard ck_pr_fence_store();
9001fb62fb0SOlivier Houchard } else {
9011fb62fb0SOlivier Houchard /*
9021fb62fb0SOlivier Houchard * In this case we are inserting a new entry or replacing
9031fb62fb0SOlivier Houchard * an existing entry. Yes, this can be combined into above branch,
9041fb62fb0SOlivier Houchard * but isn't because you are actually looking at dying code
9051fb62fb0SOlivier Houchard * (ck_ht is effectively deprecated and is being replaced soon).
9061fb62fb0SOlivier Houchard */
9071fb62fb0SOlivier Houchard bool replace = candidate->key != CK_HT_KEY_EMPTY &&
9081fb62fb0SOlivier Houchard candidate->key != CK_HT_KEY_TOMBSTONE;
9091fb62fb0SOlivier Houchard
9101fb62fb0SOlivier Houchard if (priority != NULL) {
9111fb62fb0SOlivier Houchard if (priority->key == CK_HT_KEY_TOMBSTONE) {
9121fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1);
9131fb62fb0SOlivier Houchard ck_pr_fence_store();
9141fb62fb0SOlivier Houchard }
9151fb62fb0SOlivier Houchard
9161fb62fb0SOlivier Houchard candidate = priority;
9171fb62fb0SOlivier Houchard probes = probes_wr;
9181fb62fb0SOlivier Houchard }
9191fb62fb0SOlivier Houchard
9201fb62fb0SOlivier Houchard #ifdef CK_HT_PP
9211fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->value, (void *)entry->value);
9221fb62fb0SOlivier Houchard ck_pr_fence_store();
9231fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->key, (void *)entry->key);
9241fb62fb0SOlivier Houchard #else
9251fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&candidate->key_length, entry->key_length);
9261fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&candidate->hash, entry->hash);
9271fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->value, (void *)entry->value);
9281fb62fb0SOlivier Houchard ck_pr_fence_store();
9291fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->key, (void *)entry->key);
9301fb62fb0SOlivier Houchard #endif
9311fb62fb0SOlivier Houchard
9321fb62fb0SOlivier Houchard /*
9331fb62fb0SOlivier Houchard * If we are insert a new entry then increment number
9341fb62fb0SOlivier Houchard * of entries associated with map.
9351fb62fb0SOlivier Houchard */
9361fb62fb0SOlivier Houchard if (replace == false)
9371fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->n_entries, map->n_entries + 1);
9381fb62fb0SOlivier Houchard }
9391fb62fb0SOlivier Houchard
9401fb62fb0SOlivier Houchard ck_ht_map_bound_set(map, h, probes);
9411fb62fb0SOlivier Houchard
9421fb62fb0SOlivier Houchard /* Enforce a load factor of 0.5. */
9431fb62fb0SOlivier Houchard if (map->n_entries * 2 > map->capacity)
9441fb62fb0SOlivier Houchard ck_ht_grow_spmc(table, map->capacity << 1);
9451fb62fb0SOlivier Houchard
9461fb62fb0SOlivier Houchard if (empty == true) {
9471fb62fb0SOlivier Houchard entry->key = CK_HT_KEY_EMPTY;
9481fb62fb0SOlivier Houchard } else {
9491fb62fb0SOlivier Houchard *entry = snapshot;
9501fb62fb0SOlivier Houchard }
9511fb62fb0SOlivier Houchard
9521fb62fb0SOlivier Houchard return true;
9531fb62fb0SOlivier Houchard }
9541fb62fb0SOlivier Houchard
9551fb62fb0SOlivier Houchard bool
ck_ht_put_spmc(struct ck_ht * table,ck_ht_hash_t h,ck_ht_entry_t * entry)9561fb62fb0SOlivier Houchard ck_ht_put_spmc(struct ck_ht *table,
9571fb62fb0SOlivier Houchard ck_ht_hash_t h,
9581fb62fb0SOlivier Houchard ck_ht_entry_t *entry)
9591fb62fb0SOlivier Houchard {
9601fb62fb0SOlivier Houchard struct ck_ht_entry snapshot, *candidate, *priority;
9611fb62fb0SOlivier Houchard struct ck_ht_map *map;
9621fb62fb0SOlivier Houchard CK_HT_TYPE probes, probes_wr;
9631fb62fb0SOlivier Houchard
9641fb62fb0SOlivier Houchard for (;;) {
9651fb62fb0SOlivier Houchard map = table->map;
9661fb62fb0SOlivier Houchard
9671fb62fb0SOlivier Houchard if (table->mode & CK_HT_MODE_BYTESTRING) {
9681fb62fb0SOlivier Houchard candidate = ck_ht_map_probe_wr(map, h, &snapshot, &priority,
9691fb62fb0SOlivier Houchard ck_ht_entry_key(entry),
9701fb62fb0SOlivier Houchard ck_ht_entry_key_length(entry),
9711fb62fb0SOlivier Houchard &probes, &probes_wr);
9721fb62fb0SOlivier Houchard } else {
9731fb62fb0SOlivier Houchard candidate = ck_ht_map_probe_wr(map, h, &snapshot, &priority,
9741fb62fb0SOlivier Houchard (void *)entry->key,
9751fb62fb0SOlivier Houchard sizeof(entry->key),
9761fb62fb0SOlivier Houchard &probes, &probes_wr);
9771fb62fb0SOlivier Houchard }
9781fb62fb0SOlivier Houchard
9791fb62fb0SOlivier Houchard if (candidate != NULL || priority != NULL)
9801fb62fb0SOlivier Houchard break;
9811fb62fb0SOlivier Houchard
9821fb62fb0SOlivier Houchard if (ck_ht_grow_spmc(table, map->capacity << 1) == false)
9831fb62fb0SOlivier Houchard return false;
9841fb62fb0SOlivier Houchard }
9851fb62fb0SOlivier Houchard
9861fb62fb0SOlivier Houchard if (priority != NULL) {
9871fb62fb0SOlivier Houchard /* Version counter is updated before re-use. */
9881fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->deletions, map->deletions + 1);
9891fb62fb0SOlivier Houchard ck_pr_fence_store();
9901fb62fb0SOlivier Houchard
9911fb62fb0SOlivier Houchard /* Re-use tombstone if one was found. */
9921fb62fb0SOlivier Houchard candidate = priority;
9931fb62fb0SOlivier Houchard probes = probes_wr;
9941fb62fb0SOlivier Houchard } else if (candidate->key != CK_HT_KEY_EMPTY &&
9951fb62fb0SOlivier Houchard candidate->key != CK_HT_KEY_TOMBSTONE) {
9961fb62fb0SOlivier Houchard /*
9971fb62fb0SOlivier Houchard * If the snapshot key is non-empty and the value field is not
9981fb62fb0SOlivier Houchard * a tombstone then an identical key was found. As store does
9991fb62fb0SOlivier Houchard * not implement replacement, we will fail.
10001fb62fb0SOlivier Houchard */
10011fb62fb0SOlivier Houchard return false;
10021fb62fb0SOlivier Houchard }
10031fb62fb0SOlivier Houchard
10041fb62fb0SOlivier Houchard ck_ht_map_bound_set(map, h, probes);
10051fb62fb0SOlivier Houchard
10061fb62fb0SOlivier Houchard #ifdef CK_HT_PP
10071fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->value, (void *)entry->value);
10081fb62fb0SOlivier Houchard ck_pr_fence_store();
10091fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->key, (void *)entry->key);
10101fb62fb0SOlivier Houchard #else
10111fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&candidate->key_length, entry->key_length);
10121fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&candidate->hash, entry->hash);
10131fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->value, (void *)entry->value);
10141fb62fb0SOlivier Houchard ck_pr_fence_store();
10151fb62fb0SOlivier Houchard ck_pr_store_ptr_unsafe(&candidate->key, (void *)entry->key);
10161fb62fb0SOlivier Houchard #endif
10171fb62fb0SOlivier Houchard
10181fb62fb0SOlivier Houchard CK_HT_TYPE_STORE(&map->n_entries, map->n_entries + 1);
10191fb62fb0SOlivier Houchard
10201fb62fb0SOlivier Houchard /* Enforce a load factor of 0.5. */
10211fb62fb0SOlivier Houchard if (map->n_entries * 2 > map->capacity)
10221fb62fb0SOlivier Houchard ck_ht_grow_spmc(table, map->capacity << 1);
10231fb62fb0SOlivier Houchard
10241fb62fb0SOlivier Houchard return true;
10251fb62fb0SOlivier Houchard }
10261fb62fb0SOlivier Houchard
10271fb62fb0SOlivier Houchard void
ck_ht_destroy(struct ck_ht * table)10281fb62fb0SOlivier Houchard ck_ht_destroy(struct ck_ht *table)
10291fb62fb0SOlivier Houchard {
10301fb62fb0SOlivier Houchard
10311fb62fb0SOlivier Houchard ck_ht_map_destroy(table->m, table->map, false);
10321fb62fb0SOlivier Houchard return;
10331fb62fb0SOlivier Houchard }
1034