diff --git a/include/ck_ht.h b/include/ck_ht.h index 931844f..7a7640b 100644 --- a/include/ck_ht.h +++ b/include/ck_ht.h @@ -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 *); diff --git a/regressions/ck_ht/benchmark/parallel_bytestring.c b/regressions/ck_ht/benchmark/parallel_bytestring.c index b0cd551..6d19b35 100644 --- a/regressions/ck_ht/benchmark/parallel_bytestring.c +++ b/regressions/ck_ht/benchmark/parallel_bytestring.c @@ -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); diff --git a/regressions/ck_ht/benchmark/parallel_direct.c b/regressions/ck_ht/benchmark/parallel_direct.c index 3801bb7..761bf47 100644 --- a/regressions/ck_ht/benchmark/parallel_direct.c +++ b/regressions/ck_ht/benchmark/parallel_direct.c @@ -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); } diff --git a/regressions/ck_ht/benchmark/serial.c b/regressions/ck_ht/benchmark/serial.c index 2085662..718b581 100644 --- a/regressions/ck_ht/benchmark/serial.c +++ b/regressions/ck_ht/benchmark/serial.c @@ -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); } diff --git a/regressions/ck_ht/validate/serial.c b/regressions/ck_ht/validate/serial.c index 2cf6c86..f3d0ae5 100644 --- a/regressions/ck_ht/validate/serial.c +++ b/regressions/ck_ht/validate/serial.c @@ -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); } diff --git a/src/ck_ht.c b/src/ck_ht.c index 5b5dcd3..2750164 100644 --- a/src/ck_ht.c +++ b/src/ck_ht.c @@ -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;