ck_ht: Add support for user-specified hash functions.

ck_pring
Samy Al Bahra 13 years ago
parent a361153e07
commit 18d74f55a1

@ -69,11 +69,19 @@ typedef struct ck_ht_entry ck_ht_entry_t;
#define CK_HT_KEY_EMPTY ((uintptr_t)0)
#define CK_HT_KEY_TOMBSTONE (~(uintptr_t)0)
/*
* Hash callback function. First argument is updated to contain a hash value,
* second argument is the key, third argument is key length and final argument
* is the hash table seed value.
*/
typedef void ck_ht_hash_cb_t(ck_ht_hash_t *, const void *, size_t, uint64_t);
struct ck_ht_map;
struct ck_ht {
struct ck_ht_map *map;
enum ck_ht_mode mode;
uint64_t seed;
ck_ht_hash_cb_t *h;
};
typedef struct ck_ht ck_ht_t;
@ -211,7 +219,7 @@ bool ck_ht_next(ck_ht_t *, ck_ht_iterator_t *, ck_ht_entry_t **entry);
void ck_ht_hash(ck_ht_hash_t *, ck_ht_t *, const void *, uint16_t);
void ck_ht_hash_direct(ck_ht_hash_t *, ck_ht_t *, uintptr_t);
bool ck_ht_allocator_set(struct ck_malloc *);
bool ck_ht_init(ck_ht_t *, enum ck_ht_mode, uint64_t, uint64_t);
bool ck_ht_init(ck_ht_t *, enum ck_ht_mode, ck_ht_hash_cb_t *, uint64_t, uint64_t);
void ck_ht_destroy(ck_ht_t *);
bool ck_ht_set_spmc(ck_ht_t *, ck_ht_hash_t, ck_ht_entry_t *);
bool ck_ht_put_spmc(ck_ht_t *, ck_ht_hash_t, ck_ht_entry_t *);

@ -127,7 +127,7 @@ table_init(void)
ck_epoch_register(&epoch_ht, &epoch_wr);
srand48((long int)time(NULL));
ck_ht_allocator_set(&my_allocator);
if (ck_ht_init(&ht, CK_HT_MODE_BYTESTRING, 8, lrand48()) == false) {
if (ck_ht_init(&ht, CK_HT_MODE_BYTESTRING, NULL, 8, lrand48()) == false) {
perror("ck_ht_init");
exit(EXIT_FAILURE);
}
@ -232,7 +232,7 @@ ht_reader(void *unused)
if (strcmp(r, keys[i]) == 0)
continue;
fprintf(stderr, "ERROR: Found invalid value: [%s]\n", r);
fprintf(stderr, "ERROR: Found invalid value: [%s] but expected [%s]\n", r, keys[i]);
exit(EXIT_FAILURE);
}
a += rdtsc() - s;
@ -345,6 +345,7 @@ main(int argc, char *argv[])
for (i = 0; i < keys_length; i++)
d += table_insert(keys[i]) == false;
fprintf(stderr, " [S] %d readers, 1 writer.\n", n_threads);
fprintf(stderr, " [S] %zu entries stored and %u duplicates.\n\n",
table_count(), d);

@ -126,7 +126,7 @@ table_init(void)
ck_epoch_register(&epoch_ht, &epoch_wr);
srand48((long int)time(NULL));
ck_ht_allocator_set(&my_allocator);
if (ck_ht_init(&ht, CK_HT_MODE_DIRECT, 8, lrand48()) == false) {
if (ck_ht_init(&ht, CK_HT_MODE_DIRECT, NULL, 8, lrand48()) == false) {
perror("ck_ht_init");
exit(EXIT_FAILURE);
}

@ -74,7 +74,7 @@ table_init(void)
srand48((long int)time(NULL));
ck_ht_allocator_set(&my_allocator);
if (ck_ht_init(&ht, CK_HT_MODE_BYTESTRING, 8, lrand48()) == false) {
if (ck_ht_init(&ht, CK_HT_MODE_BYTESTRING, NULL, 8, lrand48()) == false) {
perror("ck_ht_init");
exit(EXIT_FAILURE);
}

@ -78,7 +78,7 @@ main(void)
ck_ht_entry_t *cursor;
ck_ht_allocator_set(&my_allocator);
if (ck_ht_init(&ht, CK_HT_MODE_BYTESTRING, 8, 6602834) == false) {
if (ck_ht_init(&ht, CK_HT_MODE_BYTESTRING, NULL, 8, 6602834) == false) {
perror("ck_ht_init");
exit(EXIT_FAILURE);
}
@ -247,7 +247,7 @@ main(void)
}
ck_ht_destroy(&ht);
if (ck_ht_init(&ht, CK_HT_MODE_DIRECT, 8, 6602834) == false) {
if (ck_ht_init(&ht, CK_HT_MODE_DIRECT, NULL, 8, 6602834) == false) {
perror("ck_ht_init");
exit(EXIT_FAILURE);
}

@ -97,6 +97,16 @@ ck_ht_hash_direct(struct ck_ht_hash *h,
return;
}
static void
ck_ht_hash_wrapper(struct ck_ht_hash *h,
const void *key,
size_t length,
uint64_t seed)
{
h->value = MurmurHash64A(key, length, seed);
return;
}
bool
ck_ht_allocator_set(struct ck_malloc *m)
@ -170,13 +180,19 @@ ck_ht_map_probe_next(struct ck_ht_map *map, size_t offset, ck_ht_hash_t h)
}
bool
ck_ht_init(ck_ht_t *table, enum ck_ht_mode mode, uint64_t entries, uint64_t seed)
ck_ht_init(ck_ht_t *table, enum ck_ht_mode mode, ck_ht_hash_cb_t *h, uint64_t entries, uint64_t seed)
{
table->mode = mode;
table->seed = seed;
table->map = ck_ht_map_create(mode, entries);
if (h == NULL) {
table->h = ck_ht_hash_wrapper;
} else {
table->h = h;
}
table->map = ck_ht_map_create(mode, entries);
return table->map != NULL;
}
@ -267,19 +283,6 @@ retry:
if (map->mode == CK_HT_MODE_BYTESTRING) {
void *pointer;
#ifndef CK_HT_PP
if (probe_limit == NULL) {
d_prime = ck_pr_load_64(&map->deletions);
/*
* It is possible that the slot was
* replaced, initiate a re-probe.
*/
if (d != d_prime)
goto retry;
}
#endif
/*
* Check memoized portion of hash value before
* expensive full-length comparison.
@ -294,11 +297,27 @@ retry:
#else
if (snapshot->hash != h.value)
continue;
if (probe_limit == NULL) {
d_prime = ck_pr_load_64(&map->deletions);
/*
* It is possible that the slot was
* replaced, initiate a re-probe.
*/
if (d != d_prime)
goto retry;
}
#endif
pointer = ck_ht_entry_key(snapshot);
if (memcmp(pointer, key, key_length) == 0)
goto leave;
} else {
d_prime = ck_pr_load_64(&map->deletions);
if (d != d_prime)
goto retry;
}
}
@ -396,9 +415,9 @@ restart:
key = ck_ht_entry_key(previous);
key_length = ck_ht_entry_key_length(previous);
ck_ht_hash(&h, table, key, key_length);
table->h(&h, key, key_length, table->seed);
} else {
ck_ht_hash(&h, table, &previous->key, sizeof(previous->key));
table->h(&h, &previous->key, sizeof(previous->key), table->seed);
}
offset = h.value & update->mask;

Loading…
Cancel
Save