xref: /freebsd/sys/contrib/ck/src/ck_ht.c (revision 74e9b5f29ad0056bbe11a30c91dfa0705fa19cd5)
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