11fb62fb0SOlivier Houchard /*
21fb62fb0SOlivier Houchard * Copyright 2014-2015 Olivier Houchard.
31fb62fb0SOlivier Houchard * Copyright 2012-2015 Samy Al Bahra.
41fb62fb0SOlivier Houchard * All rights reserved.
51fb62fb0SOlivier Houchard *
61fb62fb0SOlivier Houchard * Redistribution and use in source and binary forms, with or without
71fb62fb0SOlivier Houchard * modification, are permitted provided that the following conditions
81fb62fb0SOlivier Houchard * are met:
91fb62fb0SOlivier Houchard * 1. Redistributions of source code must retain the above copyright
101fb62fb0SOlivier Houchard * notice, this list of conditions and the following disclaimer.
111fb62fb0SOlivier Houchard * 2. Redistributions in binary form must reproduce the above copyright
121fb62fb0SOlivier Houchard * notice, this list of conditions and the following disclaimer in the
131fb62fb0SOlivier Houchard * documentation and/or other materials provided with the distribution.
141fb62fb0SOlivier Houchard *
151fb62fb0SOlivier Houchard * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161fb62fb0SOlivier Houchard * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171fb62fb0SOlivier Houchard * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181fb62fb0SOlivier Houchard * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191fb62fb0SOlivier Houchard * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201fb62fb0SOlivier Houchard * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211fb62fb0SOlivier Houchard * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221fb62fb0SOlivier Houchard * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231fb62fb0SOlivier Houchard * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241fb62fb0SOlivier Houchard * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251fb62fb0SOlivier Houchard * SUCH DAMAGE.
261fb62fb0SOlivier Houchard */
271fb62fb0SOlivier Houchard
281fb62fb0SOlivier Houchard #include <ck_cc.h>
291fb62fb0SOlivier Houchard #include <ck_rhs.h>
301fb62fb0SOlivier Houchard #include <ck_limits.h>
311fb62fb0SOlivier Houchard #include <ck_md.h>
321fb62fb0SOlivier Houchard #include <ck_pr.h>
331fb62fb0SOlivier Houchard #include <ck_stdint.h>
341fb62fb0SOlivier Houchard #include <ck_stdbool.h>
351fb62fb0SOlivier Houchard #include <ck_string.h>
361fb62fb0SOlivier Houchard
371fb62fb0SOlivier Houchard #include "ck_internal.h"
381fb62fb0SOlivier Houchard
391fb62fb0SOlivier Houchard #ifndef CK_RHS_PROBE_L1_SHIFT
401fb62fb0SOlivier Houchard #define CK_RHS_PROBE_L1_SHIFT 3ULL
411fb62fb0SOlivier Houchard #endif /* CK_RHS_PROBE_L1_SHIFT */
421fb62fb0SOlivier Houchard
431fb62fb0SOlivier Houchard #define CK_RHS_PROBE_L1 (1 << CK_RHS_PROBE_L1_SHIFT)
441fb62fb0SOlivier Houchard #define CK_RHS_PROBE_L1_MASK (CK_RHS_PROBE_L1 - 1)
451fb62fb0SOlivier Houchard
461fb62fb0SOlivier Houchard #ifndef CK_RHS_PROBE_L1_DEFAULT
471fb62fb0SOlivier Houchard #define CK_RHS_PROBE_L1_DEFAULT CK_MD_CACHELINE
481fb62fb0SOlivier Houchard #endif
491fb62fb0SOlivier Houchard
501fb62fb0SOlivier Houchard #define CK_RHS_VMA_MASK ((uintptr_t)((1ULL << CK_MD_VMA_BITS) - 1))
511fb62fb0SOlivier Houchard #define CK_RHS_VMA(x) \
521fb62fb0SOlivier Houchard ((void *)((uintptr_t)(x) & CK_RHS_VMA_MASK))
531fb62fb0SOlivier Houchard
541fb62fb0SOlivier Houchard #define CK_RHS_EMPTY NULL
551fb62fb0SOlivier Houchard #define CK_RHS_G (1024)
561fb62fb0SOlivier Houchard #define CK_RHS_G_MASK (CK_RHS_G - 1)
571fb62fb0SOlivier Houchard
581fb62fb0SOlivier Houchard #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_STORE_8)
591fb62fb0SOlivier Houchard #define CK_RHS_WORD uint8_t
601fb62fb0SOlivier Houchard #define CK_RHS_WORD_MAX UINT8_MAX
611fb62fb0SOlivier Houchard #define CK_RHS_STORE(x, y) ck_pr_store_8(x, y)
621fb62fb0SOlivier Houchard #define CK_RHS_LOAD(x) ck_pr_load_8(x)
631fb62fb0SOlivier Houchard #elif defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_STORE_16)
641fb62fb0SOlivier Houchard #define CK_RHS_WORD uint16_t
651fb62fb0SOlivier Houchard #define CK_RHS_WORD_MAX UINT16_MAX
661fb62fb0SOlivier Houchard #define CK_RHS_STORE(x, y) ck_pr_store_16(x, y)
671fb62fb0SOlivier Houchard #define CK_RHS_LOAD(x) ck_pr_load_16(x)
681fb62fb0SOlivier Houchard #elif defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_STORE_32)
691fb62fb0SOlivier Houchard #define CK_RHS_WORD uint32_t
701fb62fb0SOlivier Houchard #define CK_RHS_WORD_MAX UINT32_MAX
711fb62fb0SOlivier Houchard #define CK_RHS_STORE(x, y) ck_pr_store_32(x, y)
721fb62fb0SOlivier Houchard #define CK_RHS_LOAD(x) ck_pr_load_32(x)
731fb62fb0SOlivier Houchard #else
741fb62fb0SOlivier Houchard #error "ck_rhs is not supported on your platform."
751fb62fb0SOlivier Houchard #endif
761fb62fb0SOlivier Houchard
771fb62fb0SOlivier Houchard #define CK_RHS_MAX_WANTED 0xffff
781fb62fb0SOlivier Houchard
791fb62fb0SOlivier Houchard enum ck_rhs_probe_behavior {
801fb62fb0SOlivier Houchard CK_RHS_PROBE = 0, /* Default behavior. */
811fb62fb0SOlivier Houchard CK_RHS_PROBE_RH, /* Short-circuit if RH slot found. */
821fb62fb0SOlivier Houchard CK_RHS_PROBE_INSERT, /* Short-circuit on probe bound if tombstone found. */
831fb62fb0SOlivier Houchard
841fb62fb0SOlivier Houchard CK_RHS_PROBE_ROBIN_HOOD,/* Look for the first slot available for the entry we are about to replace, only used to internally implement Robin Hood */
851fb62fb0SOlivier Houchard CK_RHS_PROBE_NO_RH, /* Don't do the RH dance */
861fb62fb0SOlivier Houchard };
871fb62fb0SOlivier Houchard struct ck_rhs_entry_desc {
881fb62fb0SOlivier Houchard unsigned int probes;
891fb62fb0SOlivier Houchard unsigned short wanted;
901fb62fb0SOlivier Houchard CK_RHS_WORD probe_bound;
911fb62fb0SOlivier Houchard bool in_rh;
921fb62fb0SOlivier Houchard const void *entry;
931fb62fb0SOlivier Houchard } CK_CC_ALIGN(16);
941fb62fb0SOlivier Houchard
951fb62fb0SOlivier Houchard struct ck_rhs_no_entry_desc {
961fb62fb0SOlivier Houchard unsigned int probes;
971fb62fb0SOlivier Houchard unsigned short wanted;
981fb62fb0SOlivier Houchard CK_RHS_WORD probe_bound;
991fb62fb0SOlivier Houchard bool in_rh;
1001fb62fb0SOlivier Houchard } CK_CC_ALIGN(8);
1011fb62fb0SOlivier Houchard
1021fb62fb0SOlivier Houchard typedef long ck_rhs_probe_cb_t(struct ck_rhs *hs,
1031fb62fb0SOlivier Houchard struct ck_rhs_map *map,
1041fb62fb0SOlivier Houchard unsigned long *n_probes,
1051fb62fb0SOlivier Houchard long *priority,
1061fb62fb0SOlivier Houchard unsigned long h,
1071fb62fb0SOlivier Houchard const void *key,
1081fb62fb0SOlivier Houchard const void **object,
1091fb62fb0SOlivier Houchard unsigned long probe_limit,
1101fb62fb0SOlivier Houchard enum ck_rhs_probe_behavior behavior);
1111fb62fb0SOlivier Houchard
1121fb62fb0SOlivier Houchard struct ck_rhs_map {
1131fb62fb0SOlivier Houchard unsigned int generation[CK_RHS_G];
1141fb62fb0SOlivier Houchard unsigned int probe_maximum;
1151fb62fb0SOlivier Houchard unsigned long mask;
1161fb62fb0SOlivier Houchard unsigned long step;
1171fb62fb0SOlivier Houchard unsigned int probe_limit;
1181fb62fb0SOlivier Houchard unsigned long n_entries;
1191fb62fb0SOlivier Houchard unsigned long capacity;
1201fb62fb0SOlivier Houchard unsigned long size;
1211fb62fb0SOlivier Houchard unsigned long max_entries;
1221fb62fb0SOlivier Houchard char offset_mask;
1231fb62fb0SOlivier Houchard union {
1241fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *descs;
1251fb62fb0SOlivier Houchard struct ck_rhs_no_entry {
1261fb62fb0SOlivier Houchard const void **entries;
1271fb62fb0SOlivier Houchard struct ck_rhs_no_entry_desc *descs;
1281fb62fb0SOlivier Houchard } no_entries;
1291fb62fb0SOlivier Houchard } entries;
1301fb62fb0SOlivier Houchard bool read_mostly;
1311fb62fb0SOlivier Houchard ck_rhs_probe_cb_t *probe_func;
1321fb62fb0SOlivier Houchard };
1331fb62fb0SOlivier Houchard
1341fb62fb0SOlivier Houchard static CK_CC_INLINE const void *
ck_rhs_entry(struct ck_rhs_map * map,long offset)1351fb62fb0SOlivier Houchard ck_rhs_entry(struct ck_rhs_map *map, long offset)
1361fb62fb0SOlivier Houchard {
1371fb62fb0SOlivier Houchard
1381fb62fb0SOlivier Houchard if (map->read_mostly)
1391fb62fb0SOlivier Houchard return (map->entries.no_entries.entries[offset]);
1401fb62fb0SOlivier Houchard else
1411fb62fb0SOlivier Houchard return (map->entries.descs[offset].entry);
1421fb62fb0SOlivier Houchard }
1431fb62fb0SOlivier Houchard
1441fb62fb0SOlivier Houchard static CK_CC_INLINE const void **
ck_rhs_entry_addr(struct ck_rhs_map * map,long offset)1451fb62fb0SOlivier Houchard ck_rhs_entry_addr(struct ck_rhs_map *map, long offset)
1461fb62fb0SOlivier Houchard {
1471fb62fb0SOlivier Houchard
1481fb62fb0SOlivier Houchard if (map->read_mostly)
1491fb62fb0SOlivier Houchard return (&map->entries.no_entries.entries[offset]);
1501fb62fb0SOlivier Houchard else
1511fb62fb0SOlivier Houchard return (&map->entries.descs[offset].entry);
1521fb62fb0SOlivier Houchard }
1531fb62fb0SOlivier Houchard
1541fb62fb0SOlivier Houchard static CK_CC_INLINE struct ck_rhs_entry_desc *
ck_rhs_desc(struct ck_rhs_map * map,long offset)1551fb62fb0SOlivier Houchard ck_rhs_desc(struct ck_rhs_map *map, long offset)
1561fb62fb0SOlivier Houchard {
1571fb62fb0SOlivier Houchard
1581fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(map->read_mostly))
1591fb62fb0SOlivier Houchard return ((struct ck_rhs_entry_desc *)(void *)&map->entries.no_entries.descs[offset]);
1601fb62fb0SOlivier Houchard else
1611fb62fb0SOlivier Houchard return (&map->entries.descs[offset]);
1621fb62fb0SOlivier Houchard }
1631fb62fb0SOlivier Houchard
1641fb62fb0SOlivier Houchard static CK_CC_INLINE void
ck_rhs_wanted_inc(struct ck_rhs_map * map,long offset)1651fb62fb0SOlivier Houchard ck_rhs_wanted_inc(struct ck_rhs_map *map, long offset)
1661fb62fb0SOlivier Houchard {
1671fb62fb0SOlivier Houchard
1681fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(map->read_mostly))
1691fb62fb0SOlivier Houchard map->entries.no_entries.descs[offset].wanted++;
1701fb62fb0SOlivier Houchard else
1711fb62fb0SOlivier Houchard map->entries.descs[offset].wanted++;
1721fb62fb0SOlivier Houchard }
1731fb62fb0SOlivier Houchard
1741fb62fb0SOlivier Houchard static CK_CC_INLINE unsigned int
ck_rhs_probes(struct ck_rhs_map * map,long offset)1751fb62fb0SOlivier Houchard ck_rhs_probes(struct ck_rhs_map *map, long offset)
1761fb62fb0SOlivier Houchard {
1771fb62fb0SOlivier Houchard
1781fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(map->read_mostly))
1791fb62fb0SOlivier Houchard return (map->entries.no_entries.descs[offset].probes);
1801fb62fb0SOlivier Houchard else
1811fb62fb0SOlivier Houchard return (map->entries.descs[offset].probes);
1821fb62fb0SOlivier Houchard }
1831fb62fb0SOlivier Houchard
1841fb62fb0SOlivier Houchard static CK_CC_INLINE void
ck_rhs_set_probes(struct ck_rhs_map * map,long offset,unsigned int value)1851fb62fb0SOlivier Houchard ck_rhs_set_probes(struct ck_rhs_map *map, long offset, unsigned int value)
1861fb62fb0SOlivier Houchard {
1871fb62fb0SOlivier Houchard
1881fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(map->read_mostly))
1891fb62fb0SOlivier Houchard map->entries.no_entries.descs[offset].probes = value;
1901fb62fb0SOlivier Houchard else
1911fb62fb0SOlivier Houchard map->entries.descs[offset].probes = value;
1921fb62fb0SOlivier Houchard }
1931fb62fb0SOlivier Houchard
1941fb62fb0SOlivier Houchard static CK_CC_INLINE CK_RHS_WORD
ck_rhs_probe_bound(struct ck_rhs_map * map,long offset)1951fb62fb0SOlivier Houchard ck_rhs_probe_bound(struct ck_rhs_map *map, long offset)
1961fb62fb0SOlivier Houchard {
1971fb62fb0SOlivier Houchard
1981fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(map->read_mostly))
1991fb62fb0SOlivier Houchard return (map->entries.no_entries.descs[offset].probe_bound);
2001fb62fb0SOlivier Houchard else
2011fb62fb0SOlivier Houchard return (map->entries.descs[offset].probe_bound);
2021fb62fb0SOlivier Houchard }
2031fb62fb0SOlivier Houchard
2041fb62fb0SOlivier Houchard static CK_CC_INLINE CK_RHS_WORD *
ck_rhs_probe_bound_addr(struct ck_rhs_map * map,long offset)2051fb62fb0SOlivier Houchard ck_rhs_probe_bound_addr(struct ck_rhs_map *map, long offset)
2061fb62fb0SOlivier Houchard {
2071fb62fb0SOlivier Houchard
2081fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(map->read_mostly))
2091fb62fb0SOlivier Houchard return (&map->entries.no_entries.descs[offset].probe_bound);
2101fb62fb0SOlivier Houchard else
2111fb62fb0SOlivier Houchard return (&map->entries.descs[offset].probe_bound);
2121fb62fb0SOlivier Houchard }
2131fb62fb0SOlivier Houchard
2141fb62fb0SOlivier Houchard
2151fb62fb0SOlivier Houchard static CK_CC_INLINE bool
ck_rhs_in_rh(struct ck_rhs_map * map,long offset)2161fb62fb0SOlivier Houchard ck_rhs_in_rh(struct ck_rhs_map *map, long offset)
2171fb62fb0SOlivier Houchard {
2181fb62fb0SOlivier Houchard
2191fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(map->read_mostly))
2201fb62fb0SOlivier Houchard return (map->entries.no_entries.descs[offset].in_rh);
2211fb62fb0SOlivier Houchard else
2221fb62fb0SOlivier Houchard return (map->entries.descs[offset].in_rh);
2231fb62fb0SOlivier Houchard }
2241fb62fb0SOlivier Houchard
2251fb62fb0SOlivier Houchard static CK_CC_INLINE void
ck_rhs_set_rh(struct ck_rhs_map * map,long offset)2261fb62fb0SOlivier Houchard ck_rhs_set_rh(struct ck_rhs_map *map, long offset)
2271fb62fb0SOlivier Houchard {
2281fb62fb0SOlivier Houchard
2291fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(map->read_mostly))
2301fb62fb0SOlivier Houchard map->entries.no_entries.descs[offset].in_rh = true;
2311fb62fb0SOlivier Houchard else
2321fb62fb0SOlivier Houchard map->entries.descs[offset].in_rh = true;
2331fb62fb0SOlivier Houchard }
2341fb62fb0SOlivier Houchard
2351fb62fb0SOlivier Houchard static CK_CC_INLINE void
ck_rhs_unset_rh(struct ck_rhs_map * map,long offset)2361fb62fb0SOlivier Houchard ck_rhs_unset_rh(struct ck_rhs_map *map, long offset)
2371fb62fb0SOlivier Houchard {
2381fb62fb0SOlivier Houchard
2391fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(map->read_mostly))
2401fb62fb0SOlivier Houchard map->entries.no_entries.descs[offset].in_rh = false;
2411fb62fb0SOlivier Houchard else
2421fb62fb0SOlivier Houchard map->entries.descs[offset].in_rh = false;
2431fb62fb0SOlivier Houchard }
2441fb62fb0SOlivier Houchard
2451fb62fb0SOlivier Houchard
2461fb62fb0SOlivier Houchard #define CK_RHS_DEFAULT_LOAD_FACTOR 50
2471fb62fb0SOlivier Houchard
2481fb62fb0SOlivier Houchard static ck_rhs_probe_cb_t ck_rhs_map_probe;
2491fb62fb0SOlivier Houchard static ck_rhs_probe_cb_t ck_rhs_map_probe_rm;
2501fb62fb0SOlivier Houchard
2511fb62fb0SOlivier Houchard bool
ck_rhs_set_load_factor(struct ck_rhs * hs,unsigned int load_factor)2521fb62fb0SOlivier Houchard ck_rhs_set_load_factor(struct ck_rhs *hs, unsigned int load_factor)
2531fb62fb0SOlivier Houchard {
2541fb62fb0SOlivier Houchard struct ck_rhs_map *map = hs->map;
2551fb62fb0SOlivier Houchard
2561fb62fb0SOlivier Houchard if (load_factor == 0 || load_factor > 100)
2571fb62fb0SOlivier Houchard return false;
2581fb62fb0SOlivier Houchard
2591fb62fb0SOlivier Houchard hs->load_factor = load_factor;
2601fb62fb0SOlivier Houchard map->max_entries = (map->capacity * (unsigned long)hs->load_factor) / 100;
2611fb62fb0SOlivier Houchard while (map->n_entries > map->max_entries) {
2621fb62fb0SOlivier Houchard if (ck_rhs_grow(hs, map->capacity << 1) == false)
2631fb62fb0SOlivier Houchard return false;
2641fb62fb0SOlivier Houchard map = hs->map;
2651fb62fb0SOlivier Houchard }
2661fb62fb0SOlivier Houchard return true;
2671fb62fb0SOlivier Houchard }
2681fb62fb0SOlivier Houchard
2691fb62fb0SOlivier Houchard void
ck_rhs_iterator_init(struct ck_rhs_iterator * iterator)2701fb62fb0SOlivier Houchard ck_rhs_iterator_init(struct ck_rhs_iterator *iterator)
2711fb62fb0SOlivier Houchard {
2721fb62fb0SOlivier Houchard
2731fb62fb0SOlivier Houchard iterator->cursor = NULL;
2741fb62fb0SOlivier Houchard iterator->offset = 0;
2751fb62fb0SOlivier Houchard return;
2761fb62fb0SOlivier Houchard }
2771fb62fb0SOlivier Houchard
2781fb62fb0SOlivier Houchard bool
ck_rhs_next(struct ck_rhs * hs,struct ck_rhs_iterator * i,void ** key)2791fb62fb0SOlivier Houchard ck_rhs_next(struct ck_rhs *hs, struct ck_rhs_iterator *i, void **key)
2801fb62fb0SOlivier Houchard {
2811fb62fb0SOlivier Houchard struct ck_rhs_map *map = hs->map;
2821fb62fb0SOlivier Houchard void *value;
2831fb62fb0SOlivier Houchard
2841fb62fb0SOlivier Houchard if (i->offset >= map->capacity)
2851fb62fb0SOlivier Houchard return false;
2861fb62fb0SOlivier Houchard
2871fb62fb0SOlivier Houchard do {
2881fb62fb0SOlivier Houchard value = CK_CC_DECONST_PTR(ck_rhs_entry(map, i->offset));
2891fb62fb0SOlivier Houchard if (value != CK_RHS_EMPTY) {
2901fb62fb0SOlivier Houchard #ifdef CK_RHS_PP
2911fb62fb0SOlivier Houchard if (hs->mode & CK_RHS_MODE_OBJECT)
2921fb62fb0SOlivier Houchard value = CK_RHS_VMA(value);
2931fb62fb0SOlivier Houchard #endif
2941fb62fb0SOlivier Houchard i->offset++;
2951fb62fb0SOlivier Houchard *key = value;
2961fb62fb0SOlivier Houchard return true;
2971fb62fb0SOlivier Houchard }
2981fb62fb0SOlivier Houchard } while (++i->offset < map->capacity);
2991fb62fb0SOlivier Houchard
3001fb62fb0SOlivier Houchard return false;
3011fb62fb0SOlivier Houchard }
3021fb62fb0SOlivier Houchard
3031fb62fb0SOlivier Houchard void
ck_rhs_stat(struct ck_rhs * hs,struct ck_rhs_stat * st)3041fb62fb0SOlivier Houchard ck_rhs_stat(struct ck_rhs *hs, struct ck_rhs_stat *st)
3051fb62fb0SOlivier Houchard {
3061fb62fb0SOlivier Houchard struct ck_rhs_map *map = hs->map;
3071fb62fb0SOlivier Houchard
3081fb62fb0SOlivier Houchard st->n_entries = map->n_entries;
3091fb62fb0SOlivier Houchard st->probe_maximum = map->probe_maximum;
3101fb62fb0SOlivier Houchard return;
3111fb62fb0SOlivier Houchard }
3121fb62fb0SOlivier Houchard
3131fb62fb0SOlivier Houchard unsigned long
ck_rhs_count(struct ck_rhs * hs)3141fb62fb0SOlivier Houchard ck_rhs_count(struct ck_rhs *hs)
3151fb62fb0SOlivier Houchard {
3161fb62fb0SOlivier Houchard
3171fb62fb0SOlivier Houchard return hs->map->n_entries;
3181fb62fb0SOlivier Houchard }
3191fb62fb0SOlivier Houchard
3201fb62fb0SOlivier Houchard static void
ck_rhs_map_destroy(struct ck_malloc * m,struct ck_rhs_map * map,bool defer)3211fb62fb0SOlivier Houchard ck_rhs_map_destroy(struct ck_malloc *m, struct ck_rhs_map *map, bool defer)
3221fb62fb0SOlivier Houchard {
3231fb62fb0SOlivier Houchard
3241fb62fb0SOlivier Houchard m->free(map, map->size, defer);
3251fb62fb0SOlivier Houchard return;
3261fb62fb0SOlivier Houchard }
3271fb62fb0SOlivier Houchard
3281fb62fb0SOlivier Houchard void
ck_rhs_destroy(struct ck_rhs * hs)3291fb62fb0SOlivier Houchard ck_rhs_destroy(struct ck_rhs *hs)
3301fb62fb0SOlivier Houchard {
3311fb62fb0SOlivier Houchard
3321fb62fb0SOlivier Houchard ck_rhs_map_destroy(hs->m, hs->map, false);
3331fb62fb0SOlivier Houchard return;
3341fb62fb0SOlivier Houchard }
3351fb62fb0SOlivier Houchard
3361fb62fb0SOlivier Houchard static struct ck_rhs_map *
ck_rhs_map_create(struct ck_rhs * hs,unsigned long entries)3371fb62fb0SOlivier Houchard ck_rhs_map_create(struct ck_rhs *hs, unsigned long entries)
3381fb62fb0SOlivier Houchard {
3391fb62fb0SOlivier Houchard struct ck_rhs_map *map;
3401fb62fb0SOlivier Houchard unsigned long size, n_entries, limit;
3411fb62fb0SOlivier Houchard
3421fb62fb0SOlivier Houchard n_entries = ck_internal_power_2(entries);
3431fb62fb0SOlivier Houchard if (n_entries < CK_RHS_PROBE_L1)
3441fb62fb0SOlivier Houchard n_entries = CK_RHS_PROBE_L1;
3451fb62fb0SOlivier Houchard
3461fb62fb0SOlivier Houchard if (hs->mode & CK_RHS_MODE_READ_MOSTLY)
3471fb62fb0SOlivier Houchard size = sizeof(struct ck_rhs_map) +
3481fb62fb0SOlivier Houchard (sizeof(void *) * n_entries +
3491fb62fb0SOlivier Houchard sizeof(struct ck_rhs_no_entry_desc) * n_entries +
3501fb62fb0SOlivier Houchard 2 * CK_MD_CACHELINE - 1);
3511fb62fb0SOlivier Houchard else
3521fb62fb0SOlivier Houchard size = sizeof(struct ck_rhs_map) +
3531fb62fb0SOlivier Houchard (sizeof(struct ck_rhs_entry_desc) * n_entries +
3541fb62fb0SOlivier Houchard CK_MD_CACHELINE - 1);
3551fb62fb0SOlivier Houchard map = hs->m->malloc(size);
3561fb62fb0SOlivier Houchard if (map == NULL)
3571fb62fb0SOlivier Houchard return NULL;
3581fb62fb0SOlivier Houchard map->read_mostly = !!(hs->mode & CK_RHS_MODE_READ_MOSTLY);
3591fb62fb0SOlivier Houchard
3601fb62fb0SOlivier Houchard map->size = size;
3611fb62fb0SOlivier Houchard /* We should probably use a more intelligent heuristic for default probe length. */
3621fb62fb0SOlivier Houchard limit = ck_internal_max(n_entries >> (CK_RHS_PROBE_L1_SHIFT + 2), CK_RHS_PROBE_L1_DEFAULT);
3631fb62fb0SOlivier Houchard if (limit > UINT_MAX)
3641fb62fb0SOlivier Houchard limit = UINT_MAX;
3651fb62fb0SOlivier Houchard
3661fb62fb0SOlivier Houchard map->probe_limit = (unsigned int)limit;
3671fb62fb0SOlivier Houchard map->probe_maximum = 0;
3681fb62fb0SOlivier Houchard map->capacity = n_entries;
369*271ce402SOlivier Houchard map->step = ck_cc_ffsl(n_entries);
3701fb62fb0SOlivier Houchard map->mask = n_entries - 1;
3711fb62fb0SOlivier Houchard map->n_entries = 0;
3721fb62fb0SOlivier Houchard
3731fb62fb0SOlivier Houchard map->max_entries = (map->capacity * (unsigned long)hs->load_factor) / 100;
3741fb62fb0SOlivier Houchard /* Align map allocation to cache line. */
3751fb62fb0SOlivier Houchard if (map->read_mostly) {
3761fb62fb0SOlivier Houchard map->entries.no_entries.entries = (void *)(((uintptr_t)&map[1] +
3771fb62fb0SOlivier Houchard CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1));
3781fb62fb0SOlivier Houchard map->entries.no_entries.descs = (void *)(((uintptr_t)map->entries.no_entries.entries + (sizeof(void *) * n_entries) + CK_MD_CACHELINE - 1) &~ (CK_MD_CACHELINE - 1));
3791fb62fb0SOlivier Houchard memset(map->entries.no_entries.entries, 0,
3801fb62fb0SOlivier Houchard sizeof(void *) * n_entries);
3811fb62fb0SOlivier Houchard memset(map->entries.no_entries.descs, 0,
3821fb62fb0SOlivier Houchard sizeof(struct ck_rhs_no_entry_desc) * n_entries);
3831fb62fb0SOlivier Houchard map->offset_mask = (CK_MD_CACHELINE / sizeof(void *)) - 1;
3841fb62fb0SOlivier Houchard map->probe_func = ck_rhs_map_probe_rm;
3851fb62fb0SOlivier Houchard
3861fb62fb0SOlivier Houchard } else {
3871fb62fb0SOlivier Houchard map->entries.descs = (void *)(((uintptr_t)&map[1] +
3881fb62fb0SOlivier Houchard CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1));
3891fb62fb0SOlivier Houchard memset(map->entries.descs, 0, sizeof(struct ck_rhs_entry_desc) * n_entries);
3901fb62fb0SOlivier Houchard map->offset_mask = (CK_MD_CACHELINE / sizeof(struct ck_rhs_entry_desc)) - 1;
3911fb62fb0SOlivier Houchard map->probe_func = ck_rhs_map_probe;
3921fb62fb0SOlivier Houchard }
3931fb62fb0SOlivier Houchard memset(map->generation, 0, sizeof map->generation);
3941fb62fb0SOlivier Houchard
3951fb62fb0SOlivier Houchard /* Commit entries purge with respect to map publication. */
3961fb62fb0SOlivier Houchard ck_pr_fence_store();
3971fb62fb0SOlivier Houchard return map;
3981fb62fb0SOlivier Houchard }
3991fb62fb0SOlivier Houchard
4001fb62fb0SOlivier Houchard bool
ck_rhs_reset_size(struct ck_rhs * hs,unsigned long capacity)4011fb62fb0SOlivier Houchard ck_rhs_reset_size(struct ck_rhs *hs, unsigned long capacity)
4021fb62fb0SOlivier Houchard {
4031fb62fb0SOlivier Houchard struct ck_rhs_map *map, *previous;
4041fb62fb0SOlivier Houchard
4051fb62fb0SOlivier Houchard previous = hs->map;
4061fb62fb0SOlivier Houchard map = ck_rhs_map_create(hs, capacity);
4071fb62fb0SOlivier Houchard if (map == NULL)
4081fb62fb0SOlivier Houchard return false;
4091fb62fb0SOlivier Houchard
4101fb62fb0SOlivier Houchard ck_pr_store_ptr(&hs->map, map);
4111fb62fb0SOlivier Houchard ck_rhs_map_destroy(hs->m, previous, true);
4121fb62fb0SOlivier Houchard return true;
4131fb62fb0SOlivier Houchard }
4141fb62fb0SOlivier Houchard
4151fb62fb0SOlivier Houchard bool
ck_rhs_reset(struct ck_rhs * hs)4161fb62fb0SOlivier Houchard ck_rhs_reset(struct ck_rhs *hs)
4171fb62fb0SOlivier Houchard {
4181fb62fb0SOlivier Houchard struct ck_rhs_map *previous;
4191fb62fb0SOlivier Houchard
4201fb62fb0SOlivier Houchard previous = hs->map;
4211fb62fb0SOlivier Houchard return ck_rhs_reset_size(hs, previous->capacity);
4221fb62fb0SOlivier Houchard }
4231fb62fb0SOlivier Houchard
4241fb62fb0SOlivier Houchard static inline unsigned long
ck_rhs_map_probe_next(struct ck_rhs_map * map,unsigned long offset,unsigned long probes)4251fb62fb0SOlivier Houchard ck_rhs_map_probe_next(struct ck_rhs_map *map,
4261fb62fb0SOlivier Houchard unsigned long offset,
4271fb62fb0SOlivier Houchard unsigned long probes)
4281fb62fb0SOlivier Houchard {
4291fb62fb0SOlivier Houchard
4301fb62fb0SOlivier Houchard if (probes & map->offset_mask) {
4311fb62fb0SOlivier Houchard offset = (offset &~ map->offset_mask) +
4321fb62fb0SOlivier Houchard ((offset + 1) & map->offset_mask);
4331fb62fb0SOlivier Houchard return offset;
4341fb62fb0SOlivier Houchard } else
4351fb62fb0SOlivier Houchard return (offset + probes) & map->mask;
4361fb62fb0SOlivier Houchard }
4371fb62fb0SOlivier Houchard
4381fb62fb0SOlivier Houchard static inline unsigned long
ck_rhs_map_probe_prev(struct ck_rhs_map * map,unsigned long offset,unsigned long probes)4391fb62fb0SOlivier Houchard ck_rhs_map_probe_prev(struct ck_rhs_map *map, unsigned long offset,
4401fb62fb0SOlivier Houchard unsigned long probes)
4411fb62fb0SOlivier Houchard {
4421fb62fb0SOlivier Houchard
4431fb62fb0SOlivier Houchard if (probes & map->offset_mask) {
4441fb62fb0SOlivier Houchard offset = (offset &~ map->offset_mask) + ((offset - 1) &
4451fb62fb0SOlivier Houchard map->offset_mask);
4461fb62fb0SOlivier Houchard return offset;
4471fb62fb0SOlivier Houchard } else
4481fb62fb0SOlivier Houchard return ((offset - probes) & map->mask);
4491fb62fb0SOlivier Houchard }
4501fb62fb0SOlivier Houchard
4511fb62fb0SOlivier Houchard
4521fb62fb0SOlivier Houchard static inline void
ck_rhs_map_bound_set(struct ck_rhs_map * m,unsigned long h,unsigned long n_probes)4531fb62fb0SOlivier Houchard ck_rhs_map_bound_set(struct ck_rhs_map *m,
4541fb62fb0SOlivier Houchard unsigned long h,
4551fb62fb0SOlivier Houchard unsigned long n_probes)
4561fb62fb0SOlivier Houchard {
4571fb62fb0SOlivier Houchard unsigned long offset = h & m->mask;
4581fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc;
4591fb62fb0SOlivier Houchard
4601fb62fb0SOlivier Houchard if (n_probes > m->probe_maximum)
4611fb62fb0SOlivier Houchard ck_pr_store_uint(&m->probe_maximum, n_probes);
4621fb62fb0SOlivier Houchard if (!(m->read_mostly)) {
4631fb62fb0SOlivier Houchard desc = &m->entries.descs[offset];
4641fb62fb0SOlivier Houchard
4651fb62fb0SOlivier Houchard if (desc->probe_bound < n_probes) {
4661fb62fb0SOlivier Houchard if (n_probes > CK_RHS_WORD_MAX)
4671fb62fb0SOlivier Houchard n_probes = CK_RHS_WORD_MAX;
4681fb62fb0SOlivier Houchard
4691fb62fb0SOlivier Houchard CK_RHS_STORE(&desc->probe_bound, n_probes);
4701fb62fb0SOlivier Houchard ck_pr_fence_store();
4711fb62fb0SOlivier Houchard }
4721fb62fb0SOlivier Houchard }
4731fb62fb0SOlivier Houchard
4741fb62fb0SOlivier Houchard return;
4751fb62fb0SOlivier Houchard }
4761fb62fb0SOlivier Houchard
4771fb62fb0SOlivier Houchard static inline unsigned int
ck_rhs_map_bound_get(struct ck_rhs_map * m,unsigned long h)4781fb62fb0SOlivier Houchard ck_rhs_map_bound_get(struct ck_rhs_map *m, unsigned long h)
4791fb62fb0SOlivier Houchard {
4801fb62fb0SOlivier Houchard unsigned long offset = h & m->mask;
4811fb62fb0SOlivier Houchard unsigned int r = CK_RHS_WORD_MAX;
4821fb62fb0SOlivier Houchard
4831fb62fb0SOlivier Houchard if (m->read_mostly)
4841fb62fb0SOlivier Houchard r = ck_pr_load_uint(&m->probe_maximum);
4851fb62fb0SOlivier Houchard else {
4861fb62fb0SOlivier Houchard r = CK_RHS_LOAD(&m->entries.descs[offset].probe_bound);
4871fb62fb0SOlivier Houchard if (r == CK_RHS_WORD_MAX)
4881fb62fb0SOlivier Houchard r = ck_pr_load_uint(&m->probe_maximum);
4891fb62fb0SOlivier Houchard }
4901fb62fb0SOlivier Houchard return r;
4911fb62fb0SOlivier Houchard }
4921fb62fb0SOlivier Houchard
4931fb62fb0SOlivier Houchard bool
ck_rhs_grow(struct ck_rhs * hs,unsigned long capacity)4941fb62fb0SOlivier Houchard ck_rhs_grow(struct ck_rhs *hs,
4951fb62fb0SOlivier Houchard unsigned long capacity)
4961fb62fb0SOlivier Houchard {
4971fb62fb0SOlivier Houchard struct ck_rhs_map *map, *update;
4981fb62fb0SOlivier Houchard const void *previous, *prev_saved;
4991fb62fb0SOlivier Houchard unsigned long k, offset, probes;
5001fb62fb0SOlivier Houchard
5011fb62fb0SOlivier Houchard restart:
5021fb62fb0SOlivier Houchard map = hs->map;
5031fb62fb0SOlivier Houchard if (map->capacity > capacity)
5041fb62fb0SOlivier Houchard return false;
5051fb62fb0SOlivier Houchard
5061fb62fb0SOlivier Houchard update = ck_rhs_map_create(hs, capacity);
5071fb62fb0SOlivier Houchard if (update == NULL)
5081fb62fb0SOlivier Houchard return false;
5091fb62fb0SOlivier Houchard
5101fb62fb0SOlivier Houchard for (k = 0; k < map->capacity; k++) {
5111fb62fb0SOlivier Houchard unsigned long h;
5121fb62fb0SOlivier Houchard
5131fb62fb0SOlivier Houchard prev_saved = previous = ck_rhs_entry(map, k);
5141fb62fb0SOlivier Houchard if (previous == CK_RHS_EMPTY)
5151fb62fb0SOlivier Houchard continue;
5161fb62fb0SOlivier Houchard
5171fb62fb0SOlivier Houchard #ifdef CK_RHS_PP
5181fb62fb0SOlivier Houchard if (hs->mode & CK_RHS_MODE_OBJECT)
5191fb62fb0SOlivier Houchard previous = CK_RHS_VMA(previous);
5201fb62fb0SOlivier Houchard #endif
5211fb62fb0SOlivier Houchard
5221fb62fb0SOlivier Houchard h = hs->hf(previous, hs->seed);
5231fb62fb0SOlivier Houchard offset = h & update->mask;
5241fb62fb0SOlivier Houchard probes = 0;
5251fb62fb0SOlivier Houchard
5261fb62fb0SOlivier Houchard for (;;) {
5271fb62fb0SOlivier Houchard const void **cursor = ck_rhs_entry_addr(update, offset);
5281fb62fb0SOlivier Houchard
5291fb62fb0SOlivier Houchard if (probes++ == update->probe_limit) {
5301fb62fb0SOlivier Houchard /*
5311fb62fb0SOlivier Houchard * We have hit the probe limit, map needs to be even larger.
5321fb62fb0SOlivier Houchard */
5331fb62fb0SOlivier Houchard ck_rhs_map_destroy(hs->m, update, false);
5341fb62fb0SOlivier Houchard capacity <<= 1;
5351fb62fb0SOlivier Houchard goto restart;
5361fb62fb0SOlivier Houchard }
5371fb62fb0SOlivier Houchard
5381fb62fb0SOlivier Houchard if (CK_CC_LIKELY(*cursor == CK_RHS_EMPTY)) {
5391fb62fb0SOlivier Houchard *cursor = prev_saved;
5401fb62fb0SOlivier Houchard update->n_entries++;
5411fb62fb0SOlivier Houchard ck_rhs_set_probes(update, offset, probes);
5421fb62fb0SOlivier Houchard ck_rhs_map_bound_set(update, h, probes);
5431fb62fb0SOlivier Houchard break;
5441fb62fb0SOlivier Houchard } else if (ck_rhs_probes(update, offset) < probes) {
5451fb62fb0SOlivier Houchard const void *tmp = prev_saved;
5461fb62fb0SOlivier Houchard unsigned int old_probes;
5471fb62fb0SOlivier Houchard prev_saved = previous = *cursor;
5481fb62fb0SOlivier Houchard #ifdef CK_RHS_PP
5491fb62fb0SOlivier Houchard if (hs->mode & CK_RHS_MODE_OBJECT)
5501fb62fb0SOlivier Houchard previous = CK_RHS_VMA(previous);
5511fb62fb0SOlivier Houchard #endif
5521fb62fb0SOlivier Houchard *cursor = tmp;
5531fb62fb0SOlivier Houchard ck_rhs_map_bound_set(update, h, probes);
5541fb62fb0SOlivier Houchard h = hs->hf(previous, hs->seed);
5551fb62fb0SOlivier Houchard old_probes = ck_rhs_probes(update, offset);
5561fb62fb0SOlivier Houchard ck_rhs_set_probes(update, offset, probes);
5571fb62fb0SOlivier Houchard probes = old_probes - 1;
5581fb62fb0SOlivier Houchard continue;
5591fb62fb0SOlivier Houchard }
5601fb62fb0SOlivier Houchard ck_rhs_wanted_inc(update, offset);
5611fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(update, offset, probes);
5621fb62fb0SOlivier Houchard }
5631fb62fb0SOlivier Houchard
5641fb62fb0SOlivier Houchard }
5651fb62fb0SOlivier Houchard
5661fb62fb0SOlivier Houchard ck_pr_fence_store();
5671fb62fb0SOlivier Houchard ck_pr_store_ptr(&hs->map, update);
5681fb62fb0SOlivier Houchard ck_rhs_map_destroy(hs->m, map, true);
5691fb62fb0SOlivier Houchard return true;
5701fb62fb0SOlivier Houchard }
5711fb62fb0SOlivier Houchard
5721fb62fb0SOlivier Houchard bool
ck_rhs_rebuild(struct ck_rhs * hs)5731fb62fb0SOlivier Houchard ck_rhs_rebuild(struct ck_rhs *hs)
5741fb62fb0SOlivier Houchard {
5751fb62fb0SOlivier Houchard
5761fb62fb0SOlivier Houchard return ck_rhs_grow(hs, hs->map->capacity);
5771fb62fb0SOlivier Houchard }
5781fb62fb0SOlivier Houchard
5791fb62fb0SOlivier Houchard static long
ck_rhs_map_probe_rm(struct ck_rhs * hs,struct ck_rhs_map * map,unsigned long * n_probes,long * priority,unsigned long h,const void * key,const void ** object,unsigned long probe_limit,enum ck_rhs_probe_behavior behavior)5801fb62fb0SOlivier Houchard ck_rhs_map_probe_rm(struct ck_rhs *hs,
5811fb62fb0SOlivier Houchard struct ck_rhs_map *map,
5821fb62fb0SOlivier Houchard unsigned long *n_probes,
5831fb62fb0SOlivier Houchard long *priority,
5841fb62fb0SOlivier Houchard unsigned long h,
5851fb62fb0SOlivier Houchard const void *key,
5861fb62fb0SOlivier Houchard const void **object,
5871fb62fb0SOlivier Houchard unsigned long probe_limit,
5881fb62fb0SOlivier Houchard enum ck_rhs_probe_behavior behavior)
5891fb62fb0SOlivier Houchard {
5901fb62fb0SOlivier Houchard const void *k;
5911fb62fb0SOlivier Houchard const void *compare;
5921fb62fb0SOlivier Houchard long pr = -1;
5931fb62fb0SOlivier Houchard unsigned long offset, probes, opl;
5941fb62fb0SOlivier Houchard
5951fb62fb0SOlivier Houchard #ifdef CK_RHS_PP
5961fb62fb0SOlivier Houchard /* If we are storing object pointers, then we may leverage pointer packing. */
5971fb62fb0SOlivier Houchard unsigned long hv = 0;
5981fb62fb0SOlivier Houchard
5991fb62fb0SOlivier Houchard if (hs->mode & CK_RHS_MODE_OBJECT) {
6001fb62fb0SOlivier Houchard hv = (h >> 25) & CK_RHS_KEY_MASK;
6011fb62fb0SOlivier Houchard compare = CK_RHS_VMA(key);
6021fb62fb0SOlivier Houchard } else {
6031fb62fb0SOlivier Houchard compare = key;
6041fb62fb0SOlivier Houchard }
6051fb62fb0SOlivier Houchard #else
6061fb62fb0SOlivier Houchard compare = key;
6071fb62fb0SOlivier Houchard #endif
6081fb62fb0SOlivier Houchard *object = NULL;
6091fb62fb0SOlivier Houchard if (behavior != CK_RHS_PROBE_ROBIN_HOOD) {
6101fb62fb0SOlivier Houchard probes = 0;
6111fb62fb0SOlivier Houchard offset = h & map->mask;
6121fb62fb0SOlivier Houchard } else {
6131fb62fb0SOlivier Houchard /* Restart from the bucket we were previously in */
6141fb62fb0SOlivier Houchard probes = *n_probes;
6151fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, *priority,
6161fb62fb0SOlivier Houchard probes);
6171fb62fb0SOlivier Houchard }
6181fb62fb0SOlivier Houchard opl = probe_limit;
6191fb62fb0SOlivier Houchard
6201fb62fb0SOlivier Houchard for (;;) {
6211fb62fb0SOlivier Houchard if (probes++ == probe_limit) {
6221fb62fb0SOlivier Houchard if (probe_limit == opl || pr != -1) {
6231fb62fb0SOlivier Houchard k = CK_RHS_EMPTY;
6241fb62fb0SOlivier Houchard goto leave;
6251fb62fb0SOlivier Houchard }
6261fb62fb0SOlivier Houchard /*
6271fb62fb0SOlivier Houchard * If no eligible slot has been found yet, continue probe
6281fb62fb0SOlivier Houchard * sequence with original probe limit.
6291fb62fb0SOlivier Houchard */
6301fb62fb0SOlivier Houchard probe_limit = opl;
6311fb62fb0SOlivier Houchard }
6321fb62fb0SOlivier Houchard k = ck_pr_load_ptr(&map->entries.no_entries.entries[offset]);
6331fb62fb0SOlivier Houchard if (k == CK_RHS_EMPTY)
6341fb62fb0SOlivier Houchard goto leave;
6351fb62fb0SOlivier Houchard
6361fb62fb0SOlivier Houchard if (behavior != CK_RHS_PROBE_NO_RH) {
6371fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc = (void *)&map->entries.no_entries.descs[offset];
6381fb62fb0SOlivier Houchard
6391fb62fb0SOlivier Houchard if (pr == -1 &&
6401fb62fb0SOlivier Houchard desc->in_rh == false && desc->probes < probes) {
6411fb62fb0SOlivier Houchard pr = offset;
6421fb62fb0SOlivier Houchard *n_probes = probes;
6431fb62fb0SOlivier Houchard
6441fb62fb0SOlivier Houchard if (behavior == CK_RHS_PROBE_RH ||
6451fb62fb0SOlivier Houchard behavior == CK_RHS_PROBE_ROBIN_HOOD) {
6461fb62fb0SOlivier Houchard k = CK_RHS_EMPTY;
6471fb62fb0SOlivier Houchard goto leave;
6481fb62fb0SOlivier Houchard }
6491fb62fb0SOlivier Houchard }
6501fb62fb0SOlivier Houchard }
6511fb62fb0SOlivier Houchard
6521fb62fb0SOlivier Houchard if (behavior != CK_RHS_PROBE_ROBIN_HOOD) {
6531fb62fb0SOlivier Houchard #ifdef CK_RHS_PP
6541fb62fb0SOlivier Houchard if (hs->mode & CK_RHS_MODE_OBJECT) {
6551fb62fb0SOlivier Houchard if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv) {
6561fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, offset, probes);
6571fb62fb0SOlivier Houchard continue;
6581fb62fb0SOlivier Houchard }
6591fb62fb0SOlivier Houchard
6601fb62fb0SOlivier Houchard k = CK_RHS_VMA(k);
6611fb62fb0SOlivier Houchard }
6621fb62fb0SOlivier Houchard #endif
6631fb62fb0SOlivier Houchard
6641fb62fb0SOlivier Houchard if (k == compare)
6651fb62fb0SOlivier Houchard goto leave;
6661fb62fb0SOlivier Houchard
6671fb62fb0SOlivier Houchard if (hs->compare == NULL) {
6681fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, offset, probes);
6691fb62fb0SOlivier Houchard continue;
6701fb62fb0SOlivier Houchard }
6711fb62fb0SOlivier Houchard
6721fb62fb0SOlivier Houchard if (hs->compare(k, key) == true)
6731fb62fb0SOlivier Houchard goto leave;
6741fb62fb0SOlivier Houchard }
6751fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, offset, probes);
6761fb62fb0SOlivier Houchard }
6771fb62fb0SOlivier Houchard leave:
6781fb62fb0SOlivier Houchard if (probes > probe_limit) {
6791fb62fb0SOlivier Houchard offset = -1;
6801fb62fb0SOlivier Houchard } else {
6811fb62fb0SOlivier Houchard *object = k;
6821fb62fb0SOlivier Houchard }
6831fb62fb0SOlivier Houchard
6841fb62fb0SOlivier Houchard if (pr == -1)
6851fb62fb0SOlivier Houchard *n_probes = probes;
6861fb62fb0SOlivier Houchard
6871fb62fb0SOlivier Houchard *priority = pr;
6881fb62fb0SOlivier Houchard return offset;
6891fb62fb0SOlivier Houchard }
6901fb62fb0SOlivier Houchard
6911fb62fb0SOlivier Houchard static long
ck_rhs_map_probe(struct ck_rhs * hs,struct ck_rhs_map * map,unsigned long * n_probes,long * priority,unsigned long h,const void * key,const void ** object,unsigned long probe_limit,enum ck_rhs_probe_behavior behavior)6921fb62fb0SOlivier Houchard ck_rhs_map_probe(struct ck_rhs *hs,
6931fb62fb0SOlivier Houchard struct ck_rhs_map *map,
6941fb62fb0SOlivier Houchard unsigned long *n_probes,
6951fb62fb0SOlivier Houchard long *priority,
6961fb62fb0SOlivier Houchard unsigned long h,
6971fb62fb0SOlivier Houchard const void *key,
6981fb62fb0SOlivier Houchard const void **object,
6991fb62fb0SOlivier Houchard unsigned long probe_limit,
7001fb62fb0SOlivier Houchard enum ck_rhs_probe_behavior behavior)
7011fb62fb0SOlivier Houchard {
7021fb62fb0SOlivier Houchard const void *k;
7031fb62fb0SOlivier Houchard const void *compare;
7041fb62fb0SOlivier Houchard long pr = -1;
7051fb62fb0SOlivier Houchard unsigned long offset, probes, opl;
7061fb62fb0SOlivier Houchard
7071fb62fb0SOlivier Houchard #ifdef CK_RHS_PP
7081fb62fb0SOlivier Houchard /* If we are storing object pointers, then we may leverage pointer packing. */
7091fb62fb0SOlivier Houchard unsigned long hv = 0;
7101fb62fb0SOlivier Houchard
7111fb62fb0SOlivier Houchard if (hs->mode & CK_RHS_MODE_OBJECT) {
7121fb62fb0SOlivier Houchard hv = (h >> 25) & CK_RHS_KEY_MASK;
7131fb62fb0SOlivier Houchard compare = CK_RHS_VMA(key);
7141fb62fb0SOlivier Houchard } else {
7151fb62fb0SOlivier Houchard compare = key;
7161fb62fb0SOlivier Houchard }
7171fb62fb0SOlivier Houchard #else
7181fb62fb0SOlivier Houchard compare = key;
7191fb62fb0SOlivier Houchard #endif
7201fb62fb0SOlivier Houchard
7211fb62fb0SOlivier Houchard *object = NULL;
7221fb62fb0SOlivier Houchard if (behavior != CK_RHS_PROBE_ROBIN_HOOD) {
7231fb62fb0SOlivier Houchard probes = 0;
7241fb62fb0SOlivier Houchard offset = h & map->mask;
7251fb62fb0SOlivier Houchard } else {
7261fb62fb0SOlivier Houchard /* Restart from the bucket we were previously in */
7271fb62fb0SOlivier Houchard probes = *n_probes;
7281fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, *priority,
7291fb62fb0SOlivier Houchard probes);
7301fb62fb0SOlivier Houchard }
7311fb62fb0SOlivier Houchard opl = probe_limit;
7321fb62fb0SOlivier Houchard if (behavior == CK_RHS_PROBE_INSERT)
7331fb62fb0SOlivier Houchard probe_limit = ck_rhs_map_bound_get(map, h);
7341fb62fb0SOlivier Houchard
7351fb62fb0SOlivier Houchard for (;;) {
7361fb62fb0SOlivier Houchard if (probes++ == probe_limit) {
7371fb62fb0SOlivier Houchard if (probe_limit == opl || pr != -1) {
7381fb62fb0SOlivier Houchard k = CK_RHS_EMPTY;
7391fb62fb0SOlivier Houchard goto leave;
7401fb62fb0SOlivier Houchard }
7411fb62fb0SOlivier Houchard /*
7421fb62fb0SOlivier Houchard * If no eligible slot has been found yet, continue probe
7431fb62fb0SOlivier Houchard * sequence with original probe limit.
7441fb62fb0SOlivier Houchard */
7451fb62fb0SOlivier Houchard probe_limit = opl;
7461fb62fb0SOlivier Houchard }
7471fb62fb0SOlivier Houchard k = ck_pr_load_ptr(&map->entries.descs[offset].entry);
7481fb62fb0SOlivier Houchard if (k == CK_RHS_EMPTY)
7491fb62fb0SOlivier Houchard goto leave;
7501fb62fb0SOlivier Houchard if ((behavior != CK_RHS_PROBE_NO_RH)) {
7511fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc = &map->entries.descs[offset];
7521fb62fb0SOlivier Houchard
7531fb62fb0SOlivier Houchard if (pr == -1 &&
7541fb62fb0SOlivier Houchard desc->in_rh == false && desc->probes < probes) {
7551fb62fb0SOlivier Houchard pr = offset;
7561fb62fb0SOlivier Houchard *n_probes = probes;
7571fb62fb0SOlivier Houchard
7581fb62fb0SOlivier Houchard if (behavior == CK_RHS_PROBE_RH ||
7591fb62fb0SOlivier Houchard behavior == CK_RHS_PROBE_ROBIN_HOOD) {
7601fb62fb0SOlivier Houchard k = CK_RHS_EMPTY;
7611fb62fb0SOlivier Houchard goto leave;
7621fb62fb0SOlivier Houchard }
7631fb62fb0SOlivier Houchard }
7641fb62fb0SOlivier Houchard }
7651fb62fb0SOlivier Houchard
7661fb62fb0SOlivier Houchard if (behavior != CK_RHS_PROBE_ROBIN_HOOD) {
7671fb62fb0SOlivier Houchard #ifdef CK_RHS_PP
7681fb62fb0SOlivier Houchard if (hs->mode & CK_RHS_MODE_OBJECT) {
7691fb62fb0SOlivier Houchard if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv) {
7701fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, offset, probes);
7711fb62fb0SOlivier Houchard continue;
7721fb62fb0SOlivier Houchard }
7731fb62fb0SOlivier Houchard
7741fb62fb0SOlivier Houchard k = CK_RHS_VMA(k);
7751fb62fb0SOlivier Houchard }
7761fb62fb0SOlivier Houchard #endif
7771fb62fb0SOlivier Houchard
7781fb62fb0SOlivier Houchard if (k == compare)
7791fb62fb0SOlivier Houchard goto leave;
7801fb62fb0SOlivier Houchard
7811fb62fb0SOlivier Houchard if (hs->compare == NULL) {
7821fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, offset, probes);
7831fb62fb0SOlivier Houchard continue;
7841fb62fb0SOlivier Houchard }
7851fb62fb0SOlivier Houchard
7861fb62fb0SOlivier Houchard if (hs->compare(k, key) == true)
7871fb62fb0SOlivier Houchard goto leave;
7881fb62fb0SOlivier Houchard }
7891fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, offset, probes);
7901fb62fb0SOlivier Houchard }
7911fb62fb0SOlivier Houchard leave:
7921fb62fb0SOlivier Houchard if (probes > probe_limit) {
7931fb62fb0SOlivier Houchard offset = -1;
7941fb62fb0SOlivier Houchard } else {
7951fb62fb0SOlivier Houchard *object = k;
7961fb62fb0SOlivier Houchard }
7971fb62fb0SOlivier Houchard
7981fb62fb0SOlivier Houchard if (pr == -1)
7991fb62fb0SOlivier Houchard *n_probes = probes;
8001fb62fb0SOlivier Houchard
8011fb62fb0SOlivier Houchard *priority = pr;
8021fb62fb0SOlivier Houchard return offset;
8031fb62fb0SOlivier Houchard }
8041fb62fb0SOlivier Houchard
8051fb62fb0SOlivier Houchard static inline const void *
ck_rhs_marshal(unsigned int mode,const void * key,unsigned long h)8061fb62fb0SOlivier Houchard ck_rhs_marshal(unsigned int mode, const void *key, unsigned long h)
8071fb62fb0SOlivier Houchard {
8081fb62fb0SOlivier Houchard #ifdef CK_RHS_PP
8091fb62fb0SOlivier Houchard const void *insert;
8101fb62fb0SOlivier Houchard
8111fb62fb0SOlivier Houchard if (mode & CK_RHS_MODE_OBJECT) {
8121fb62fb0SOlivier Houchard insert = (void *)((uintptr_t)CK_RHS_VMA(key) | ((h >> 25) << CK_MD_VMA_BITS));
8131fb62fb0SOlivier Houchard } else {
8141fb62fb0SOlivier Houchard insert = key;
8151fb62fb0SOlivier Houchard }
8161fb62fb0SOlivier Houchard
8171fb62fb0SOlivier Houchard return insert;
8181fb62fb0SOlivier Houchard #else
8191fb62fb0SOlivier Houchard (void)mode;
8201fb62fb0SOlivier Houchard (void)h;
8211fb62fb0SOlivier Houchard
8221fb62fb0SOlivier Houchard return key;
8231fb62fb0SOlivier Houchard #endif
8241fb62fb0SOlivier Houchard }
8251fb62fb0SOlivier Houchard
8261fb62fb0SOlivier Houchard bool
ck_rhs_gc(struct ck_rhs * hs)8271fb62fb0SOlivier Houchard ck_rhs_gc(struct ck_rhs *hs)
8281fb62fb0SOlivier Houchard {
8291fb62fb0SOlivier Houchard unsigned long i;
8301fb62fb0SOlivier Houchard struct ck_rhs_map *map = hs->map;
8311fb62fb0SOlivier Houchard
8321fb62fb0SOlivier Houchard unsigned int max_probes = 0;
8331fb62fb0SOlivier Houchard for (i = 0; i < map->capacity; i++) {
8341fb62fb0SOlivier Houchard if (ck_rhs_probes(map, i) > max_probes)
8351fb62fb0SOlivier Houchard max_probes = ck_rhs_probes(map, i);
8361fb62fb0SOlivier Houchard }
8371fb62fb0SOlivier Houchard map->probe_maximum = max_probes;
8381fb62fb0SOlivier Houchard return true;
8391fb62fb0SOlivier Houchard }
8401fb62fb0SOlivier Houchard
8411fb62fb0SOlivier Houchard static void
ck_rhs_add_wanted(struct ck_rhs * hs,long end_offset,long old_slot,unsigned long h)8421fb62fb0SOlivier Houchard ck_rhs_add_wanted(struct ck_rhs *hs, long end_offset, long old_slot,
8431fb62fb0SOlivier Houchard unsigned long h)
8441fb62fb0SOlivier Houchard {
8451fb62fb0SOlivier Houchard struct ck_rhs_map *map = hs->map;
8461fb62fb0SOlivier Houchard long offset;
8471fb62fb0SOlivier Houchard unsigned int probes = 1;
8481fb62fb0SOlivier Houchard bool found_slot = false;
8491fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc;
8501fb62fb0SOlivier Houchard
8511fb62fb0SOlivier Houchard offset = h & map->mask;
8521fb62fb0SOlivier Houchard
8531fb62fb0SOlivier Houchard if (old_slot == -1)
8541fb62fb0SOlivier Houchard found_slot = true;
8551fb62fb0SOlivier Houchard while (offset != end_offset) {
8561fb62fb0SOlivier Houchard if (offset == old_slot)
8571fb62fb0SOlivier Houchard found_slot = true;
8581fb62fb0SOlivier Houchard if (found_slot) {
8591fb62fb0SOlivier Houchard desc = ck_rhs_desc(map, offset);
8601fb62fb0SOlivier Houchard if (desc->wanted < CK_RHS_MAX_WANTED)
8611fb62fb0SOlivier Houchard desc->wanted++;
8621fb62fb0SOlivier Houchard }
8631fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, offset, probes);
8641fb62fb0SOlivier Houchard probes++;
8651fb62fb0SOlivier Houchard }
8661fb62fb0SOlivier Houchard }
8671fb62fb0SOlivier Houchard
8681fb62fb0SOlivier Houchard static unsigned long
ck_rhs_remove_wanted(struct ck_rhs * hs,long offset,long limit)8691fb62fb0SOlivier Houchard ck_rhs_remove_wanted(struct ck_rhs *hs, long offset, long limit)
8701fb62fb0SOlivier Houchard {
8711fb62fb0SOlivier Houchard struct ck_rhs_map *map = hs->map;
8721fb62fb0SOlivier Houchard int probes = ck_rhs_probes(map, offset);
8731fb62fb0SOlivier Houchard bool do_remove = true;
8741fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc;
8751fb62fb0SOlivier Houchard
8761fb62fb0SOlivier Houchard while (probes > 1) {
8771fb62fb0SOlivier Houchard probes--;
8781fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_prev(map, offset, probes);
8791fb62fb0SOlivier Houchard if (offset == limit)
8801fb62fb0SOlivier Houchard do_remove = false;
8811fb62fb0SOlivier Houchard if (do_remove) {
8821fb62fb0SOlivier Houchard desc = ck_rhs_desc(map, offset);
8831fb62fb0SOlivier Houchard if (desc->wanted != CK_RHS_MAX_WANTED)
8841fb62fb0SOlivier Houchard desc->wanted--;
8851fb62fb0SOlivier Houchard }
8861fb62fb0SOlivier Houchard }
8871fb62fb0SOlivier Houchard return offset;
8881fb62fb0SOlivier Houchard }
8891fb62fb0SOlivier Houchard
8901fb62fb0SOlivier Houchard static long
ck_rhs_get_first_offset(struct ck_rhs_map * map,unsigned long offset,unsigned int probes)8911fb62fb0SOlivier Houchard ck_rhs_get_first_offset(struct ck_rhs_map *map, unsigned long offset, unsigned int probes)
8921fb62fb0SOlivier Houchard {
8931fb62fb0SOlivier Houchard while (probes > (unsigned long)map->offset_mask + 1) {
8941fb62fb0SOlivier Houchard offset -= ((probes - 1) &~ map->offset_mask);
8951fb62fb0SOlivier Houchard offset &= map->mask;
8961fb62fb0SOlivier Houchard offset = (offset &~ map->offset_mask) +
8971fb62fb0SOlivier Houchard ((offset - map->offset_mask) & map->offset_mask);
8981fb62fb0SOlivier Houchard probes -= map->offset_mask + 1;
8991fb62fb0SOlivier Houchard }
9001fb62fb0SOlivier Houchard return ((offset &~ map->offset_mask) + ((offset - (probes - 1)) & map->offset_mask));
9011fb62fb0SOlivier Houchard }
9021fb62fb0SOlivier Houchard
9031fb62fb0SOlivier Houchard #define CK_RHS_MAX_RH 512
9041fb62fb0SOlivier Houchard
9051fb62fb0SOlivier Houchard static int
ck_rhs_put_robin_hood(struct ck_rhs * hs,long orig_slot,struct ck_rhs_entry_desc * desc)9061fb62fb0SOlivier Houchard ck_rhs_put_robin_hood(struct ck_rhs *hs,
9071fb62fb0SOlivier Houchard long orig_slot, struct ck_rhs_entry_desc *desc)
9081fb62fb0SOlivier Houchard {
9091fb62fb0SOlivier Houchard long slot, first;
9101fb62fb0SOlivier Houchard const void *object, *insert;
9111fb62fb0SOlivier Houchard unsigned long n_probes;
9121fb62fb0SOlivier Houchard struct ck_rhs_map *map;
9131fb62fb0SOlivier Houchard unsigned long h = 0;
9141fb62fb0SOlivier Houchard long prev;
9151fb62fb0SOlivier Houchard void *key;
9161fb62fb0SOlivier Houchard long prevs[CK_RHS_MAX_RH];
9171fb62fb0SOlivier Houchard unsigned int prevs_nb = 0;
9181fb62fb0SOlivier Houchard unsigned int i;
9191fb62fb0SOlivier Houchard
9201fb62fb0SOlivier Houchard map = hs->map;
9211fb62fb0SOlivier Houchard first = orig_slot;
9221fb62fb0SOlivier Houchard n_probes = desc->probes;
9231fb62fb0SOlivier Houchard restart:
9241fb62fb0SOlivier Houchard key = CK_CC_DECONST_PTR(ck_rhs_entry(map, first));
9251fb62fb0SOlivier Houchard insert = key;
9261fb62fb0SOlivier Houchard #ifdef CK_RHS_PP
9271fb62fb0SOlivier Houchard if (hs->mode & CK_RHS_MODE_OBJECT)
9281fb62fb0SOlivier Houchard key = CK_RHS_VMA(key);
9291fb62fb0SOlivier Houchard #endif
9301fb62fb0SOlivier Houchard orig_slot = first;
9311fb62fb0SOlivier Houchard ck_rhs_set_rh(map, orig_slot);
9321fb62fb0SOlivier Houchard
9331fb62fb0SOlivier Houchard slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object,
9341fb62fb0SOlivier Houchard map->probe_limit, prevs_nb == CK_RHS_MAX_RH ?
9351fb62fb0SOlivier Houchard CK_RHS_PROBE_NO_RH : CK_RHS_PROBE_ROBIN_HOOD);
9361fb62fb0SOlivier Houchard
9371fb62fb0SOlivier Houchard if (slot == -1 && first == -1) {
9381fb62fb0SOlivier Houchard if (ck_rhs_grow(hs, map->capacity << 1) == false) {
9391fb62fb0SOlivier Houchard desc->in_rh = false;
9401fb62fb0SOlivier Houchard
9411fb62fb0SOlivier Houchard for (i = 0; i < prevs_nb; i++)
9421fb62fb0SOlivier Houchard ck_rhs_unset_rh(map, prevs[i]);
9431fb62fb0SOlivier Houchard
9441fb62fb0SOlivier Houchard return -1;
9451fb62fb0SOlivier Houchard }
9461fb62fb0SOlivier Houchard
9471fb62fb0SOlivier Houchard return 1;
9481fb62fb0SOlivier Houchard }
9491fb62fb0SOlivier Houchard
9501fb62fb0SOlivier Houchard if (first != -1) {
9511fb62fb0SOlivier Houchard desc = ck_rhs_desc(map, first);
9521fb62fb0SOlivier Houchard int old_probes = desc->probes;
9531fb62fb0SOlivier Houchard
9541fb62fb0SOlivier Houchard desc->probes = n_probes;
9551fb62fb0SOlivier Houchard h = ck_rhs_get_first_offset(map, first, n_probes);
9561fb62fb0SOlivier Houchard ck_rhs_map_bound_set(map, h, n_probes);
9571fb62fb0SOlivier Houchard prev = orig_slot;
9581fb62fb0SOlivier Houchard prevs[prevs_nb++] = prev;
9591fb62fb0SOlivier Houchard n_probes = old_probes;
9601fb62fb0SOlivier Houchard goto restart;
9611fb62fb0SOlivier Houchard } else {
9621fb62fb0SOlivier Houchard /* An empty slot was found. */
9631fb62fb0SOlivier Houchard h = ck_rhs_get_first_offset(map, slot, n_probes);
9641fb62fb0SOlivier Houchard ck_rhs_map_bound_set(map, h, n_probes);
9651fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
9661fb62fb0SOlivier Houchard ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
9671fb62fb0SOlivier Houchard ck_pr_fence_atomic_store();
9681fb62fb0SOlivier Houchard ck_rhs_set_probes(map, slot, n_probes);
9691fb62fb0SOlivier Houchard desc->in_rh = 0;
9701fb62fb0SOlivier Houchard ck_rhs_add_wanted(hs, slot, orig_slot, h);
9711fb62fb0SOlivier Houchard }
9721fb62fb0SOlivier Houchard while (prevs_nb > 0) {
9731fb62fb0SOlivier Houchard prev = prevs[--prevs_nb];
9741fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, orig_slot),
9751fb62fb0SOlivier Houchard ck_rhs_entry(map, prev));
9761fb62fb0SOlivier Houchard h = ck_rhs_get_first_offset(map, orig_slot,
9771fb62fb0SOlivier Houchard desc->probes);
9781fb62fb0SOlivier Houchard ck_rhs_add_wanted(hs, orig_slot, prev, h);
9791fb62fb0SOlivier Houchard ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
9801fb62fb0SOlivier Houchard ck_pr_fence_atomic_store();
9811fb62fb0SOlivier Houchard orig_slot = prev;
9821fb62fb0SOlivier Houchard desc->in_rh = false;
9831fb62fb0SOlivier Houchard desc = ck_rhs_desc(map, orig_slot);
9841fb62fb0SOlivier Houchard }
9851fb62fb0SOlivier Houchard return 0;
9861fb62fb0SOlivier Houchard }
9871fb62fb0SOlivier Houchard
9881fb62fb0SOlivier Houchard static void
ck_rhs_do_backward_shift_delete(struct ck_rhs * hs,long slot)9891fb62fb0SOlivier Houchard ck_rhs_do_backward_shift_delete(struct ck_rhs *hs, long slot)
9901fb62fb0SOlivier Houchard {
9911fb62fb0SOlivier Houchard struct ck_rhs_map *map = hs->map;
9921fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc, *new_desc = NULL;
9931fb62fb0SOlivier Houchard unsigned long h;
9941fb62fb0SOlivier Houchard
9951fb62fb0SOlivier Houchard desc = ck_rhs_desc(map, slot);
9961fb62fb0SOlivier Houchard h = ck_rhs_remove_wanted(hs, slot, -1);
9971fb62fb0SOlivier Houchard while (desc->wanted > 0) {
9981fb62fb0SOlivier Houchard unsigned long offset = 0, tmp_offset;
9991fb62fb0SOlivier Houchard unsigned long wanted_probes = 1;
10001fb62fb0SOlivier Houchard unsigned int probe = 0;
10011fb62fb0SOlivier Houchard unsigned int max_probes;
10021fb62fb0SOlivier Houchard
10031fb62fb0SOlivier Houchard /* Find a successor */
10041fb62fb0SOlivier Houchard while (wanted_probes < map->probe_maximum) {
10051fb62fb0SOlivier Houchard probe = wanted_probes;
10061fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, slot, probe);
10071fb62fb0SOlivier Houchard while (probe < map->probe_maximum) {
10081fb62fb0SOlivier Houchard new_desc = ck_rhs_desc(map, offset);
10091fb62fb0SOlivier Houchard if (new_desc->probes == probe + 1)
10101fb62fb0SOlivier Houchard break;
10111fb62fb0SOlivier Houchard probe++;
10121fb62fb0SOlivier Houchard offset = ck_rhs_map_probe_next(map, offset,
10131fb62fb0SOlivier Houchard probe);
10141fb62fb0SOlivier Houchard }
10151fb62fb0SOlivier Houchard if (probe < map->probe_maximum)
10161fb62fb0SOlivier Houchard break;
10171fb62fb0SOlivier Houchard wanted_probes++;
10181fb62fb0SOlivier Houchard }
10191fb62fb0SOlivier Houchard if (!(wanted_probes < map->probe_maximum)) {
10201fb62fb0SOlivier Houchard desc->wanted = 0;
10211fb62fb0SOlivier Houchard break;
10221fb62fb0SOlivier Houchard }
10231fb62fb0SOlivier Houchard desc->probes = wanted_probes;
10241fb62fb0SOlivier Houchard h = ck_rhs_remove_wanted(hs, offset, slot);
10251fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, slot),
10261fb62fb0SOlivier Houchard ck_rhs_entry(map, offset));
10271fb62fb0SOlivier Houchard ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
10281fb62fb0SOlivier Houchard ck_pr_fence_atomic_store();
10291fb62fb0SOlivier Houchard if (wanted_probes < CK_RHS_WORD_MAX) {
10301fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *hdesc = ck_rhs_desc(map, h);
10311fb62fb0SOlivier Houchard if (hdesc->wanted == 1)
10321fb62fb0SOlivier Houchard CK_RHS_STORE(&hdesc->probe_bound,
10331fb62fb0SOlivier Houchard wanted_probes);
10341fb62fb0SOlivier Houchard else if (hdesc->probe_bound == CK_RHS_WORD_MAX ||
10351fb62fb0SOlivier Houchard hdesc->probe_bound == new_desc->probes) {
10361fb62fb0SOlivier Houchard probe++;
10371fb62fb0SOlivier Houchard if (hdesc->probe_bound == CK_RHS_WORD_MAX)
10381fb62fb0SOlivier Houchard max_probes = map->probe_maximum;
10391fb62fb0SOlivier Houchard else {
10401fb62fb0SOlivier Houchard max_probes = hdesc->probe_bound;
10411fb62fb0SOlivier Houchard max_probes--;
10421fb62fb0SOlivier Houchard }
10431fb62fb0SOlivier Houchard tmp_offset = ck_rhs_map_probe_next(map, offset,
10441fb62fb0SOlivier Houchard probe);
10451fb62fb0SOlivier Houchard while (probe < max_probes) {
10461fb62fb0SOlivier Houchard if (h == (unsigned long)ck_rhs_get_first_offset(map, tmp_offset, probe))
10471fb62fb0SOlivier Houchard break;
10481fb62fb0SOlivier Houchard probe++;
10491fb62fb0SOlivier Houchard tmp_offset = ck_rhs_map_probe_next(map, tmp_offset, probe);
10501fb62fb0SOlivier Houchard }
10511fb62fb0SOlivier Houchard if (probe == max_probes)
10521fb62fb0SOlivier Houchard CK_RHS_STORE(&hdesc->probe_bound,
10531fb62fb0SOlivier Houchard wanted_probes);
10541fb62fb0SOlivier Houchard }
10551fb62fb0SOlivier Houchard }
10561fb62fb0SOlivier Houchard if (desc->wanted < CK_RHS_MAX_WANTED)
10571fb62fb0SOlivier Houchard desc->wanted--;
10581fb62fb0SOlivier Houchard slot = offset;
10591fb62fb0SOlivier Houchard desc = new_desc;
10601fb62fb0SOlivier Houchard }
10611fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), CK_RHS_EMPTY);
10621fb62fb0SOlivier Houchard if ((desc->probes - 1) < CK_RHS_WORD_MAX)
10631fb62fb0SOlivier Houchard CK_RHS_STORE(ck_rhs_probe_bound_addr(map, h),
10641fb62fb0SOlivier Houchard desc->probes - 1);
10651fb62fb0SOlivier Houchard desc->probes = 0;
10661fb62fb0SOlivier Houchard }
10671fb62fb0SOlivier Houchard
10681fb62fb0SOlivier Houchard bool
ck_rhs_fas(struct ck_rhs * hs,unsigned long h,const void * key,void ** previous)10691fb62fb0SOlivier Houchard ck_rhs_fas(struct ck_rhs *hs,
10701fb62fb0SOlivier Houchard unsigned long h,
10711fb62fb0SOlivier Houchard const void *key,
10721fb62fb0SOlivier Houchard void **previous)
10731fb62fb0SOlivier Houchard {
10741fb62fb0SOlivier Houchard long slot, first;
10751fb62fb0SOlivier Houchard const void *object;
10761fb62fb0SOlivier Houchard const void *insert;
10771fb62fb0SOlivier Houchard unsigned long n_probes;
10781fb62fb0SOlivier Houchard struct ck_rhs_map *map = hs->map;
10791fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc, *desc2;
10801fb62fb0SOlivier Houchard
10811fb62fb0SOlivier Houchard *previous = NULL;
10821fb62fb0SOlivier Houchard restart:
10831fb62fb0SOlivier Houchard slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object,
10841fb62fb0SOlivier Houchard ck_rhs_map_bound_get(map, h), CK_RHS_PROBE);
10851fb62fb0SOlivier Houchard
10861fb62fb0SOlivier Houchard /* Replacement semantics presume existence. */
10871fb62fb0SOlivier Houchard if (object == NULL)
10881fb62fb0SOlivier Houchard return false;
10891fb62fb0SOlivier Houchard
10901fb62fb0SOlivier Houchard insert = ck_rhs_marshal(hs->mode, key, h);
10911fb62fb0SOlivier Houchard
10921fb62fb0SOlivier Houchard if (first != -1) {
10931fb62fb0SOlivier Houchard int ret;
10941fb62fb0SOlivier Houchard
10951fb62fb0SOlivier Houchard desc = ck_rhs_desc(map, slot);
10961fb62fb0SOlivier Houchard desc2 = ck_rhs_desc(map, first);
10971fb62fb0SOlivier Houchard desc->in_rh = true;
10981fb62fb0SOlivier Houchard ret = ck_rhs_put_robin_hood(hs, first, desc2);
10991fb62fb0SOlivier Houchard desc->in_rh = false;
11001fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(ret == 1))
11011fb62fb0SOlivier Houchard goto restart;
11021fb62fb0SOlivier Houchard else if (CK_CC_UNLIKELY(ret != 0))
11031fb62fb0SOlivier Houchard return false;
11041fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert);
11051fb62fb0SOlivier Houchard ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
11061fb62fb0SOlivier Houchard ck_pr_fence_atomic_store();
11071fb62fb0SOlivier Houchard desc2->probes = n_probes;
11081fb62fb0SOlivier Houchard ck_rhs_add_wanted(hs, first, -1, h);
11091fb62fb0SOlivier Houchard ck_rhs_do_backward_shift_delete(hs, slot);
11101fb62fb0SOlivier Houchard } else {
11111fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
11121fb62fb0SOlivier Houchard ck_rhs_set_probes(map, slot, n_probes);
11131fb62fb0SOlivier Houchard }
11141fb62fb0SOlivier Houchard *previous = CK_CC_DECONST_PTR(object);
11151fb62fb0SOlivier Houchard return true;
11161fb62fb0SOlivier Houchard }
11171fb62fb0SOlivier Houchard
11181fb62fb0SOlivier Houchard /*
11191fb62fb0SOlivier Houchard * An apply function takes two arguments. The first argument is a pointer to a
11201fb62fb0SOlivier Houchard * pre-existing object. The second argument is a pointer to the fifth argument
11211fb62fb0SOlivier Houchard * passed to ck_hs_apply. If a non-NULL pointer is passed to the first argument
11221fb62fb0SOlivier Houchard * and the return value of the apply function is NULL, then the pre-existing
11231fb62fb0SOlivier Houchard * value is deleted. If the return pointer is the same as the one passed to the
11241fb62fb0SOlivier Houchard * apply function then no changes are made to the hash table. If the first
11251fb62fb0SOlivier Houchard * argument is non-NULL and the return pointer is different than that passed to
11261fb62fb0SOlivier Houchard * the apply function, then the pre-existing value is replaced. For
11271fb62fb0SOlivier Houchard * replacement, it is required that the value itself is identical to the
11281fb62fb0SOlivier Houchard * previous value.
11291fb62fb0SOlivier Houchard */
11301fb62fb0SOlivier Houchard bool
ck_rhs_apply(struct ck_rhs * hs,unsigned long h,const void * key,ck_rhs_apply_fn_t * fn,void * cl)11311fb62fb0SOlivier Houchard ck_rhs_apply(struct ck_rhs *hs,
11321fb62fb0SOlivier Houchard unsigned long h,
11331fb62fb0SOlivier Houchard const void *key,
11341fb62fb0SOlivier Houchard ck_rhs_apply_fn_t *fn,
11351fb62fb0SOlivier Houchard void *cl)
11361fb62fb0SOlivier Houchard {
11371fb62fb0SOlivier Houchard const void *insert;
11381fb62fb0SOlivier Houchard const void *object, *delta = false;
11391fb62fb0SOlivier Houchard unsigned long n_probes;
11401fb62fb0SOlivier Houchard long slot, first;
11411fb62fb0SOlivier Houchard struct ck_rhs_map *map;
11421fb62fb0SOlivier Houchard bool delta_set = false;
11431fb62fb0SOlivier Houchard
11441fb62fb0SOlivier Houchard restart:
11451fb62fb0SOlivier Houchard map = hs->map;
11461fb62fb0SOlivier Houchard
11471fb62fb0SOlivier Houchard slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_RHS_PROBE_INSERT);
11481fb62fb0SOlivier Houchard if (slot == -1 && first == -1) {
11491fb62fb0SOlivier Houchard if (ck_rhs_grow(hs, map->capacity << 1) == false)
11501fb62fb0SOlivier Houchard return false;
11511fb62fb0SOlivier Houchard
11521fb62fb0SOlivier Houchard goto restart;
11531fb62fb0SOlivier Houchard }
11541fb62fb0SOlivier Houchard if (!delta_set) {
11551fb62fb0SOlivier Houchard delta = fn(CK_CC_DECONST_PTR(object), cl);
11561fb62fb0SOlivier Houchard delta_set = true;
11571fb62fb0SOlivier Houchard }
11581fb62fb0SOlivier Houchard
11591fb62fb0SOlivier Houchard if (delta == NULL) {
11601fb62fb0SOlivier Houchard /*
11611fb62fb0SOlivier Houchard * The apply function has requested deletion. If the object doesn't exist,
11621fb62fb0SOlivier Houchard * then exit early.
11631fb62fb0SOlivier Houchard */
11641fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(object == NULL))
11651fb62fb0SOlivier Houchard return true;
11661fb62fb0SOlivier Houchard
11671fb62fb0SOlivier Houchard /* Otherwise, delete it. */
11681fb62fb0SOlivier Houchard ck_rhs_do_backward_shift_delete(hs, slot);
11691fb62fb0SOlivier Houchard return true;
11701fb62fb0SOlivier Houchard }
11711fb62fb0SOlivier Houchard
11721fb62fb0SOlivier Houchard /* The apply function has not requested hash set modification so exit early. */
11731fb62fb0SOlivier Houchard if (delta == object)
11741fb62fb0SOlivier Houchard return true;
11751fb62fb0SOlivier Houchard
11761fb62fb0SOlivier Houchard /* A modification or insertion has been requested. */
11771fb62fb0SOlivier Houchard ck_rhs_map_bound_set(map, h, n_probes);
11781fb62fb0SOlivier Houchard
11791fb62fb0SOlivier Houchard insert = ck_rhs_marshal(hs->mode, delta, h);
11801fb62fb0SOlivier Houchard if (first != -1) {
11811fb62fb0SOlivier Houchard /*
11821fb62fb0SOlivier Houchard * This follows the same semantics as ck_hs_set, please refer to that
11831fb62fb0SOlivier Houchard * function for documentation.
11841fb62fb0SOlivier Houchard */
11851fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc = NULL, *desc2;
11861fb62fb0SOlivier Houchard if (slot != -1) {
11871fb62fb0SOlivier Houchard desc = ck_rhs_desc(map, slot);
11881fb62fb0SOlivier Houchard desc->in_rh = true;
11891fb62fb0SOlivier Houchard }
11901fb62fb0SOlivier Houchard desc2 = ck_rhs_desc(map, first);
11911fb62fb0SOlivier Houchard int ret = ck_rhs_put_robin_hood(hs, first, desc2);
11921fb62fb0SOlivier Houchard if (slot != -1)
11931fb62fb0SOlivier Houchard desc->in_rh = false;
11941fb62fb0SOlivier Houchard
11951fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(ret == 1))
11961fb62fb0SOlivier Houchard goto restart;
11971fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(ret == -1))
11981fb62fb0SOlivier Houchard return false;
11991fb62fb0SOlivier Houchard /* If an earlier bucket was found, then store entry there. */
12001fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert);
12011fb62fb0SOlivier Houchard desc2->probes = n_probes;
12021fb62fb0SOlivier Houchard /*
12031fb62fb0SOlivier Houchard * If a duplicate key was found, then delete it after
12041fb62fb0SOlivier Houchard * signaling concurrent probes to restart. Optionally,
12051fb62fb0SOlivier Houchard * it is possible to install tombstone after grace
12061fb62fb0SOlivier Houchard * period if we can guarantee earlier position of
12071fb62fb0SOlivier Houchard * duplicate key.
12081fb62fb0SOlivier Houchard */
12091fb62fb0SOlivier Houchard ck_rhs_add_wanted(hs, first, -1, h);
12101fb62fb0SOlivier Houchard if (object != NULL) {
12111fb62fb0SOlivier Houchard ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
12121fb62fb0SOlivier Houchard ck_pr_fence_atomic_store();
12131fb62fb0SOlivier Houchard ck_rhs_do_backward_shift_delete(hs, slot);
12141fb62fb0SOlivier Houchard }
12151fb62fb0SOlivier Houchard } else {
12161fb62fb0SOlivier Houchard /*
12171fb62fb0SOlivier Houchard * If we are storing into same slot, then atomic store is sufficient
12181fb62fb0SOlivier Houchard * for replacement.
12191fb62fb0SOlivier Houchard */
12201fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
12211fb62fb0SOlivier Houchard ck_rhs_set_probes(map, slot, n_probes);
12221fb62fb0SOlivier Houchard if (object == NULL)
12231fb62fb0SOlivier Houchard ck_rhs_add_wanted(hs, slot, -1, h);
12241fb62fb0SOlivier Houchard }
12251fb62fb0SOlivier Houchard
12261fb62fb0SOlivier Houchard if (object == NULL) {
12271fb62fb0SOlivier Houchard map->n_entries++;
12281fb62fb0SOlivier Houchard if ((map->n_entries ) > map->max_entries)
12291fb62fb0SOlivier Houchard ck_rhs_grow(hs, map->capacity << 1);
12301fb62fb0SOlivier Houchard }
12311fb62fb0SOlivier Houchard return true;
12321fb62fb0SOlivier Houchard }
12331fb62fb0SOlivier Houchard
12341fb62fb0SOlivier Houchard bool
ck_rhs_set(struct ck_rhs * hs,unsigned long h,const void * key,void ** previous)12351fb62fb0SOlivier Houchard ck_rhs_set(struct ck_rhs *hs,
12361fb62fb0SOlivier Houchard unsigned long h,
12371fb62fb0SOlivier Houchard const void *key,
12381fb62fb0SOlivier Houchard void **previous)
12391fb62fb0SOlivier Houchard {
12401fb62fb0SOlivier Houchard long slot, first;
12411fb62fb0SOlivier Houchard const void *object;
12421fb62fb0SOlivier Houchard const void *insert;
12431fb62fb0SOlivier Houchard unsigned long n_probes;
12441fb62fb0SOlivier Houchard struct ck_rhs_map *map;
12451fb62fb0SOlivier Houchard
12461fb62fb0SOlivier Houchard *previous = NULL;
12471fb62fb0SOlivier Houchard
12481fb62fb0SOlivier Houchard restart:
12491fb62fb0SOlivier Houchard map = hs->map;
12501fb62fb0SOlivier Houchard
12511fb62fb0SOlivier Houchard slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_RHS_PROBE_INSERT);
12521fb62fb0SOlivier Houchard if (slot == -1 && first == -1) {
12531fb62fb0SOlivier Houchard if (ck_rhs_grow(hs, map->capacity << 1) == false)
12541fb62fb0SOlivier Houchard return false;
12551fb62fb0SOlivier Houchard
12561fb62fb0SOlivier Houchard goto restart;
12571fb62fb0SOlivier Houchard }
12581fb62fb0SOlivier Houchard ck_rhs_map_bound_set(map, h, n_probes);
12591fb62fb0SOlivier Houchard insert = ck_rhs_marshal(hs->mode, key, h);
12601fb62fb0SOlivier Houchard
12611fb62fb0SOlivier Houchard if (first != -1) {
12621fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc = NULL, *desc2;
12631fb62fb0SOlivier Houchard if (slot != -1) {
12641fb62fb0SOlivier Houchard desc = ck_rhs_desc(map, slot);
12651fb62fb0SOlivier Houchard desc->in_rh = true;
12661fb62fb0SOlivier Houchard }
12671fb62fb0SOlivier Houchard desc2 = ck_rhs_desc(map, first);
12681fb62fb0SOlivier Houchard int ret = ck_rhs_put_robin_hood(hs, first, desc2);
12691fb62fb0SOlivier Houchard if (slot != -1)
12701fb62fb0SOlivier Houchard desc->in_rh = false;
12711fb62fb0SOlivier Houchard
12721fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(ret == 1))
12731fb62fb0SOlivier Houchard goto restart;
12741fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(ret == -1))
12751fb62fb0SOlivier Houchard return false;
12761fb62fb0SOlivier Houchard /* If an earlier bucket was found, then store entry there. */
12771fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert);
12781fb62fb0SOlivier Houchard desc2->probes = n_probes;
12791fb62fb0SOlivier Houchard /*
12801fb62fb0SOlivier Houchard * If a duplicate key was found, then delete it after
12811fb62fb0SOlivier Houchard * signaling concurrent probes to restart. Optionally,
12821fb62fb0SOlivier Houchard * it is possible to install tombstone after grace
12831fb62fb0SOlivier Houchard * period if we can guarantee earlier position of
12841fb62fb0SOlivier Houchard * duplicate key.
12851fb62fb0SOlivier Houchard */
12861fb62fb0SOlivier Houchard ck_rhs_add_wanted(hs, first, -1, h);
12871fb62fb0SOlivier Houchard if (object != NULL) {
12881fb62fb0SOlivier Houchard ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
12891fb62fb0SOlivier Houchard ck_pr_fence_atomic_store();
12901fb62fb0SOlivier Houchard ck_rhs_do_backward_shift_delete(hs, slot);
12911fb62fb0SOlivier Houchard }
12921fb62fb0SOlivier Houchard
12931fb62fb0SOlivier Houchard } else {
12941fb62fb0SOlivier Houchard /*
12951fb62fb0SOlivier Houchard * If we are storing into same slot, then atomic store is sufficient
12961fb62fb0SOlivier Houchard * for replacement.
12971fb62fb0SOlivier Houchard */
12981fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
12991fb62fb0SOlivier Houchard ck_rhs_set_probes(map, slot, n_probes);
13001fb62fb0SOlivier Houchard if (object == NULL)
13011fb62fb0SOlivier Houchard ck_rhs_add_wanted(hs, slot, -1, h);
13021fb62fb0SOlivier Houchard }
13031fb62fb0SOlivier Houchard
13041fb62fb0SOlivier Houchard if (object == NULL) {
13051fb62fb0SOlivier Houchard map->n_entries++;
13061fb62fb0SOlivier Houchard if ((map->n_entries ) > map->max_entries)
13071fb62fb0SOlivier Houchard ck_rhs_grow(hs, map->capacity << 1);
13081fb62fb0SOlivier Houchard }
13091fb62fb0SOlivier Houchard
13101fb62fb0SOlivier Houchard *previous = CK_CC_DECONST_PTR(object);
13111fb62fb0SOlivier Houchard return true;
13121fb62fb0SOlivier Houchard }
13131fb62fb0SOlivier Houchard
13141fb62fb0SOlivier Houchard static bool
ck_rhs_put_internal(struct ck_rhs * hs,unsigned long h,const void * key,enum ck_rhs_probe_behavior behavior)13151fb62fb0SOlivier Houchard ck_rhs_put_internal(struct ck_rhs *hs,
13161fb62fb0SOlivier Houchard unsigned long h,
13171fb62fb0SOlivier Houchard const void *key,
13181fb62fb0SOlivier Houchard enum ck_rhs_probe_behavior behavior)
13191fb62fb0SOlivier Houchard {
13201fb62fb0SOlivier Houchard long slot, first;
13211fb62fb0SOlivier Houchard const void *object;
13221fb62fb0SOlivier Houchard const void *insert;
13231fb62fb0SOlivier Houchard unsigned long n_probes;
13241fb62fb0SOlivier Houchard struct ck_rhs_map *map;
13251fb62fb0SOlivier Houchard
13261fb62fb0SOlivier Houchard restart:
13271fb62fb0SOlivier Houchard map = hs->map;
13281fb62fb0SOlivier Houchard
13291fb62fb0SOlivier Houchard slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object,
13301fb62fb0SOlivier Houchard map->probe_limit, behavior);
13311fb62fb0SOlivier Houchard
13321fb62fb0SOlivier Houchard if (slot == -1 && first == -1) {
13331fb62fb0SOlivier Houchard if (ck_rhs_grow(hs, map->capacity << 1) == false)
13341fb62fb0SOlivier Houchard return false;
13351fb62fb0SOlivier Houchard
13361fb62fb0SOlivier Houchard goto restart;
13371fb62fb0SOlivier Houchard }
13381fb62fb0SOlivier Houchard
13391fb62fb0SOlivier Houchard /* Fail operation if a match was found. */
13401fb62fb0SOlivier Houchard if (object != NULL)
13411fb62fb0SOlivier Houchard return false;
13421fb62fb0SOlivier Houchard
13431fb62fb0SOlivier Houchard ck_rhs_map_bound_set(map, h, n_probes);
13441fb62fb0SOlivier Houchard insert = ck_rhs_marshal(hs->mode, key, h);
13451fb62fb0SOlivier Houchard
13461fb62fb0SOlivier Houchard if (first != -1) {
13471fb62fb0SOlivier Houchard struct ck_rhs_entry_desc *desc = ck_rhs_desc(map, first);
13481fb62fb0SOlivier Houchard int ret = ck_rhs_put_robin_hood(hs, first, desc);
13491fb62fb0SOlivier Houchard if (CK_CC_UNLIKELY(ret == 1))
13501fb62fb0SOlivier Houchard return ck_rhs_put_internal(hs, h, key, behavior);
13511fb62fb0SOlivier Houchard else if (CK_CC_UNLIKELY(ret == -1))
13521fb62fb0SOlivier Houchard return false;
13531fb62fb0SOlivier Houchard /* Insert key into first bucket in probe sequence. */
13541fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert);
13551fb62fb0SOlivier Houchard desc->probes = n_probes;
13561fb62fb0SOlivier Houchard ck_rhs_add_wanted(hs, first, -1, h);
13571fb62fb0SOlivier Houchard } else {
13581fb62fb0SOlivier Houchard /* An empty slot was found. */
13591fb62fb0SOlivier Houchard ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
13601fb62fb0SOlivier Houchard ck_rhs_set_probes(map, slot, n_probes);
13611fb62fb0SOlivier Houchard ck_rhs_add_wanted(hs, slot, -1, h);
13621fb62fb0SOlivier Houchard }
13631fb62fb0SOlivier Houchard
13641fb62fb0SOlivier Houchard map->n_entries++;
13651fb62fb0SOlivier Houchard if ((map->n_entries ) > map->max_entries)
13661fb62fb0SOlivier Houchard ck_rhs_grow(hs, map->capacity << 1);
13671fb62fb0SOlivier Houchard return true;
13681fb62fb0SOlivier Houchard }
13691fb62fb0SOlivier Houchard
13701fb62fb0SOlivier Houchard bool
ck_rhs_put(struct ck_rhs * hs,unsigned long h,const void * key)13711fb62fb0SOlivier Houchard ck_rhs_put(struct ck_rhs *hs,
13721fb62fb0SOlivier Houchard unsigned long h,
13731fb62fb0SOlivier Houchard const void *key)
13741fb62fb0SOlivier Houchard {
13751fb62fb0SOlivier Houchard
13761fb62fb0SOlivier Houchard return ck_rhs_put_internal(hs, h, key, CK_RHS_PROBE_INSERT);
13771fb62fb0SOlivier Houchard }
13781fb62fb0SOlivier Houchard
13791fb62fb0SOlivier Houchard bool
ck_rhs_put_unique(struct ck_rhs * hs,unsigned long h,const void * key)13801fb62fb0SOlivier Houchard ck_rhs_put_unique(struct ck_rhs *hs,
13811fb62fb0SOlivier Houchard unsigned long h,
13821fb62fb0SOlivier Houchard const void *key)
13831fb62fb0SOlivier Houchard {
13841fb62fb0SOlivier Houchard
13851fb62fb0SOlivier Houchard return ck_rhs_put_internal(hs, h, key, CK_RHS_PROBE_RH);
13861fb62fb0SOlivier Houchard }
13871fb62fb0SOlivier Houchard
13881fb62fb0SOlivier Houchard void *
ck_rhs_get(struct ck_rhs * hs,unsigned long h,const void * key)13891fb62fb0SOlivier Houchard ck_rhs_get(struct ck_rhs *hs,
13901fb62fb0SOlivier Houchard unsigned long h,
13911fb62fb0SOlivier Houchard const void *key)
13921fb62fb0SOlivier Houchard {
13931fb62fb0SOlivier Houchard long first;
13941fb62fb0SOlivier Houchard const void *object;
13951fb62fb0SOlivier Houchard struct ck_rhs_map *map;
13961fb62fb0SOlivier Houchard unsigned long n_probes;
13971fb62fb0SOlivier Houchard unsigned int g, g_p, probe;
13981fb62fb0SOlivier Houchard unsigned int *generation;
13991fb62fb0SOlivier Houchard
14001fb62fb0SOlivier Houchard do {
14011fb62fb0SOlivier Houchard map = ck_pr_load_ptr(&hs->map);
14021fb62fb0SOlivier Houchard generation = &map->generation[h & CK_RHS_G_MASK];
14031fb62fb0SOlivier Houchard g = ck_pr_load_uint(generation);
14041fb62fb0SOlivier Houchard probe = ck_rhs_map_bound_get(map, h);
14051fb62fb0SOlivier Houchard ck_pr_fence_load();
14061fb62fb0SOlivier Houchard
14071fb62fb0SOlivier Houchard first = -1;
14081fb62fb0SOlivier Houchard map->probe_func(hs, map, &n_probes, &first, h, key, &object, probe, CK_RHS_PROBE_NO_RH);
14091fb62fb0SOlivier Houchard
14101fb62fb0SOlivier Houchard ck_pr_fence_load();
14111fb62fb0SOlivier Houchard g_p = ck_pr_load_uint(generation);
14121fb62fb0SOlivier Houchard } while (g != g_p);
14131fb62fb0SOlivier Houchard
14141fb62fb0SOlivier Houchard return CK_CC_DECONST_PTR(object);
14151fb62fb0SOlivier Houchard }
14161fb62fb0SOlivier Houchard
14171fb62fb0SOlivier Houchard void *
ck_rhs_remove(struct ck_rhs * hs,unsigned long h,const void * key)14181fb62fb0SOlivier Houchard ck_rhs_remove(struct ck_rhs *hs,
14191fb62fb0SOlivier Houchard unsigned long h,
14201fb62fb0SOlivier Houchard const void *key)
14211fb62fb0SOlivier Houchard {
14221fb62fb0SOlivier Houchard long slot, first;
14231fb62fb0SOlivier Houchard const void *object;
14241fb62fb0SOlivier Houchard struct ck_rhs_map *map = hs->map;
14251fb62fb0SOlivier Houchard unsigned long n_probes;
14261fb62fb0SOlivier Houchard
14271fb62fb0SOlivier Houchard slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object,
14281fb62fb0SOlivier Houchard ck_rhs_map_bound_get(map, h), CK_RHS_PROBE_NO_RH);
14291fb62fb0SOlivier Houchard if (object == NULL)
14301fb62fb0SOlivier Houchard return NULL;
14311fb62fb0SOlivier Houchard
14321fb62fb0SOlivier Houchard map->n_entries--;
14331fb62fb0SOlivier Houchard ck_rhs_do_backward_shift_delete(hs, slot);
14341fb62fb0SOlivier Houchard return CK_CC_DECONST_PTR(object);
14351fb62fb0SOlivier Houchard }
14361fb62fb0SOlivier Houchard
14371fb62fb0SOlivier Houchard bool
ck_rhs_move(struct ck_rhs * hs,struct ck_rhs * source,ck_rhs_hash_cb_t * hf,ck_rhs_compare_cb_t * compare,struct ck_malloc * m)14381fb62fb0SOlivier Houchard ck_rhs_move(struct ck_rhs *hs,
14391fb62fb0SOlivier Houchard struct ck_rhs *source,
14401fb62fb0SOlivier Houchard ck_rhs_hash_cb_t *hf,
14411fb62fb0SOlivier Houchard ck_rhs_compare_cb_t *compare,
14421fb62fb0SOlivier Houchard struct ck_malloc *m)
14431fb62fb0SOlivier Houchard {
14441fb62fb0SOlivier Houchard
14451fb62fb0SOlivier Houchard if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL)
14461fb62fb0SOlivier Houchard return false;
14471fb62fb0SOlivier Houchard
14481fb62fb0SOlivier Houchard hs->mode = source->mode;
14491fb62fb0SOlivier Houchard hs->seed = source->seed;
14501fb62fb0SOlivier Houchard hs->map = source->map;
14511fb62fb0SOlivier Houchard hs->load_factor = source->load_factor;
14521fb62fb0SOlivier Houchard hs->m = m;
14531fb62fb0SOlivier Houchard hs->hf = hf;
14541fb62fb0SOlivier Houchard hs->compare = compare;
14551fb62fb0SOlivier Houchard return true;
14561fb62fb0SOlivier Houchard }
14571fb62fb0SOlivier Houchard
14581fb62fb0SOlivier Houchard bool
ck_rhs_init(struct ck_rhs * hs,unsigned int mode,ck_rhs_hash_cb_t * hf,ck_rhs_compare_cb_t * compare,struct ck_malloc * m,unsigned long n_entries,unsigned long seed)14591fb62fb0SOlivier Houchard ck_rhs_init(struct ck_rhs *hs,
14601fb62fb0SOlivier Houchard unsigned int mode,
14611fb62fb0SOlivier Houchard ck_rhs_hash_cb_t *hf,
14621fb62fb0SOlivier Houchard ck_rhs_compare_cb_t *compare,
14631fb62fb0SOlivier Houchard struct ck_malloc *m,
14641fb62fb0SOlivier Houchard unsigned long n_entries,
14651fb62fb0SOlivier Houchard unsigned long seed)
14661fb62fb0SOlivier Houchard {
14671fb62fb0SOlivier Houchard
14681fb62fb0SOlivier Houchard if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL)
14691fb62fb0SOlivier Houchard return false;
14701fb62fb0SOlivier Houchard
14711fb62fb0SOlivier Houchard hs->m = m;
14721fb62fb0SOlivier Houchard hs->mode = mode;
14731fb62fb0SOlivier Houchard hs->seed = seed;
14741fb62fb0SOlivier Houchard hs->hf = hf;
14751fb62fb0SOlivier Houchard hs->compare = compare;
14761fb62fb0SOlivier Houchard hs->load_factor = CK_RHS_DEFAULT_LOAD_FACTOR;
14771fb62fb0SOlivier Houchard
14781fb62fb0SOlivier Houchard hs->map = ck_rhs_map_create(hs, n_entries);
14791fb62fb0SOlivier Houchard return hs->map != NULL;
14801fb62fb0SOlivier Houchard }
1481