ck_hs: Add ck_hs_apply function for in-band mutation.

Allows for the application of a user-specified function to avoid
re-probe for get conditional put / delete and in-band mutation
use-cases.
ck_pring
Samy Al Bahra 10 years ago
parent 67aac7f865
commit bc0618e1b4

@ -630,6 +630,91 @@ ck_hs_fas(struct ck_hs *hs,
return true; return true;
} }
/*
* An apply function takes two arguments. The first argument is a pointer to a
* pre-existing object. The second argument is a pointer to the fifth argument
* passed to ck_hs_apply. If a non-NULL pointer is passed to the first argument
* and the return value of the apply function is NULL, then the pre-existing
* value is deleted. If the return pointer is the same as the one passed to the
* apply function then no changes are made to the hash table. If the first
* argument is non-NULL and the return pointer is different than that passed to
* the apply function, then the pre-existing value is replaced. For
* replacement, it is required that the value itself is identical to the
* previous value.
*/
bool
ck_hs_apply(struct ck_hs *hs,
unsigned long h,
const void *key,
ck_hs_apply_fn_t *fn,
void *cl)
{
void **slot, **first, *object, *insert, *delta;
unsigned long n_probes;
struct ck_hs_map *map;
restart:
map = hs->map;
slot = ck_hs_map_probe(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_HS_PROBE_INSERT);
if (slot == NULL && first == NULL) {
if (ck_hs_grow(hs, map->capacity << 1) == false)
return false;
goto restart;
}
delta = fn(object, cl);
if (delta == NULL) {
/*
* The apply function has requested deletion. If the object doesn't exist,
* then exit early.
*/
if (CK_CC_UNLIKELY(object == NULL))
return true;
/* Otherwise, mark slot as deleted. */
ck_pr_store_ptr(slot, CK_HS_TOMBSTONE);
return true;
}
/* The apply function has not requested hash set modification so exit early. */
if (delta == object)
return true;
/* A modification or insertion has been requested. */
ck_hs_map_bound_set(map, h, n_probes);
insert = ck_hs_marshal(hs->mode, delta, h);
if (first != NULL) {
/*
* This follows the same semantics as ck_hs_set, please refer to that
* function for documentation.
*/
ck_pr_store_ptr(first, insert);
if (object != NULL) {
ck_pr_inc_uint(&map->generation[h & CK_HS_G_MASK]);
ck_pr_fence_atomic_store();
ck_pr_store_ptr(slot, CK_HS_TOMBSTONE);
}
} else {
/*
* If we are storing into same slot, then atomic store is sufficient
* for replacement.
*/
ck_pr_store_ptr(slot, insert);
}
if (object == NULL) {
map->n_entries++;
if ((map->n_entries << 1) > map->capacity)
ck_hs_grow(hs, map->capacity << 1);
}
return true;
}
bool bool
ck_hs_set(struct ck_hs *hs, ck_hs_set(struct ck_hs *hs,
unsigned long h, unsigned long h,

Loading…
Cancel
Save