ck_ht: Add support for per-hash-table allocator.

Documentation and regressions tests have been updated to reflect this.
This functionality allows for individual hash tables use to different
allocation functions. Thanks to Wez Furlong for pointing out the necessary
documentation update for ck_ht.
ck_pring
Samy Al Bahra 13 years ago
parent af7b877414
commit 72a8adb599

@ -36,7 +36,7 @@ Concurrency Kit (libck, \-lck)
.Ft typedef void .Ft typedef void
.Fn ck_ht_hash_cb_t "ck_ht_hash_t *h" "const void *key" "size_t key_length" "uint64_t seed" .Fn ck_ht_hash_cb_t "ck_ht_hash_t *h" "const void *key" "size_t key_length" "uint64_t seed"
.Ft bool .Ft bool
.Fn ck_ht_init "ck_ht_t *ht" "enum ck_ht_mode mode" "ck_ht_hash_cb_t hash_function" "uint64_t capacity" "uint64_t seed" .Fn ck_ht_init "ck_ht_t *ht" "enum ck_ht_mode mode" "ck_ht_hash_cb_t *hash_function" "struct ck_malloc *allocator" "uint64_t capacity" "uint64_t seed"
.Sh DESCRIPTION .Sh DESCRIPTION
The The
.Fn ck_ht_init .Fn ck_ht_init
@ -63,7 +63,8 @@ to be interacted with using the
.Xr ck_ht_entry_value 3 , .Xr ck_ht_entry_value 3 ,
and and
.Xr ck_ht_entry_set 3 .Xr ck_ht_entry_set 3
functions. functions. Attempting a hash table operation with a key of value
NULL or (void *)UINTPTR_MAX will result in undefined behavior.
.It CK_HT_MODE_DIRECT .It CK_HT_MODE_DIRECT
The hash table is meant to store key-value pointers where The hash table is meant to store key-value pointers where
the key is of fixed width field compatible with the the key is of fixed width field compatible with the
@ -76,7 +77,8 @@ with using the
.Xr ck_ht_entry_value_direct 3 .Xr ck_ht_entry_value_direct 3
and and
.Xr ck_entry_set_direct 3 .Xr ck_entry_set_direct 3
functions. functions. Attempting a hash table operation with a key of value of 0 or
UINTPTR_MAX will result in undefined behavior.
.El .El
.Pp .Pp
The argument The argument
@ -106,6 +108,15 @@ argument is the initial seed associated with the hash table.
This initial seed is specified by the user in This initial seed is specified by the user in
.Xr ck_ht_init 3 . .Xr ck_ht_init 3 .
.Pp .Pp
The
.Fa allocator
argument is a pointer to a structure containing
.Fa malloc
and
.Fa free
function pointers which respectively define the memory allocation and
destruction functions to be used by the hash table being initialized.
.Pp
The argument The argument
.Fa capacity .Fa capacity
represents the initial number of key-value pairs the hash represents the initial number of key-value pairs the hash

@ -78,6 +78,7 @@ typedef void ck_ht_hash_cb_t(ck_ht_hash_t *, const void *, size_t, uint64_t);
struct ck_ht_map; struct ck_ht_map;
struct ck_ht { struct ck_ht {
struct ck_malloc *m;
struct ck_ht_map *map; struct ck_ht_map *map;
enum ck_ht_mode mode; enum ck_ht_mode mode;
uint64_t seed; uint64_t seed;
@ -219,7 +220,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(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); 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_allocator_set(struct ck_malloc *);
bool ck_ht_init(ck_ht_t *, enum ck_ht_mode, ck_ht_hash_cb_t *, uint64_t, uint64_t); bool ck_ht_init(ck_ht_t *, enum ck_ht_mode, ck_ht_hash_cb_t *, struct ck_malloc *, uint64_t, uint64_t);
void ck_ht_destroy(ck_ht_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_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 *); bool ck_ht_put_spmc(ck_ht_t *, ck_ht_hash_t, ck_ht_entry_t *);

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

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

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

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

@ -74,8 +74,6 @@ struct ck_ht_map {
struct ck_ht_entry *entries; struct ck_ht_entry *entries;
}; };
static struct ck_malloc allocator;
void void
ck_ht_hash(struct ck_ht_hash *h, ck_ht_hash(struct ck_ht_hash *h,
struct ck_ht *table, struct ck_ht *table,
@ -108,21 +106,8 @@ ck_ht_hash_wrapper(struct ck_ht_hash *h,
return; return;
} }
bool
ck_ht_allocator_set(struct ck_malloc *m)
{
if (m->malloc == NULL || m->free == NULL)
return false;
allocator.malloc = m->malloc;
allocator.free = m->free;
return true;
}
static struct ck_ht_map * static struct ck_ht_map *
ck_ht_map_create(enum ck_ht_mode mode, uint64_t entries) ck_ht_map_create(struct ck_ht *table, uint64_t entries)
{ {
struct ck_ht_map *map; struct ck_ht_map *map;
uint64_t size, n_entries; uint64_t size, n_entries;
@ -131,11 +116,11 @@ ck_ht_map_create(enum ck_ht_mode mode, uint64_t entries)
size = sizeof(struct ck_ht_map) + size = sizeof(struct ck_ht_map) +
(sizeof(struct ck_ht_entry) * n_entries + CK_MD_CACHELINE - 1); (sizeof(struct ck_ht_entry) * n_entries + CK_MD_CACHELINE - 1);
map = allocator.malloc(size); map = table->m->malloc(size);
if (map == NULL) if (map == NULL)
return NULL; return NULL;
map->mode = mode; map->mode = table->mode;
map->size = size; map->size = size;
map->probe_limit = ck_internal_max_64(n_entries >> map->probe_limit = ck_internal_max_64(n_entries >>
(CK_HT_BUCKET_SHIFT + 2), CK_HT_PROBE_DEFAULT); (CK_HT_BUCKET_SHIFT + 2), CK_HT_PROBE_DEFAULT);
@ -150,7 +135,7 @@ ck_ht_map_create(enum ck_ht_mode mode, uint64_t entries)
CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1)); CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1));
if (map->entries == NULL) { if (map->entries == NULL) {
allocator.free(map, size, false); table->m->free(map, size, false);
return NULL; return NULL;
} }
@ -159,10 +144,10 @@ ck_ht_map_create(enum ck_ht_mode mode, uint64_t entries)
} }
static void static void
ck_ht_map_destroy(struct ck_ht_map *map, bool defer) ck_ht_map_destroy(struct ck_malloc *m, struct ck_ht_map *map, bool defer)
{ {
allocator.free(map, map->size, defer); m->free(map, map->size, defer);
return; return;
} }
@ -180,9 +165,18 @@ ck_ht_map_probe_next(struct ck_ht_map *map, size_t offset, ck_ht_hash_t h)
} }
bool bool
ck_ht_init(ck_ht_t *table, enum ck_ht_mode mode, ck_ht_hash_cb_t *h, uint64_t entries, uint64_t seed) ck_ht_init(ck_ht_t *table,
enum ck_ht_mode mode,
ck_ht_hash_cb_t *h,
struct ck_malloc *m,
uint64_t entries,
uint64_t seed)
{ {
if (m == NULL || m->malloc == NULL || m->free == NULL)
return false;
table->m = m;
table->mode = mode; table->mode = mode;
table->seed = seed; table->seed = seed;
@ -192,7 +186,7 @@ ck_ht_init(ck_ht_t *table, enum ck_ht_mode mode, ck_ht_hash_cb_t *h, uint64_t en
table->h = h; table->h = h;
} }
table->map = ck_ht_map_create(mode, entries); table->map = ck_ht_map_create(table, entries);
return table->map != NULL; return table->map != NULL;
} }
@ -369,12 +363,12 @@ ck_ht_reset_spmc(struct ck_ht *table)
struct ck_ht_map *map, *update; struct ck_ht_map *map, *update;
map = table->map; map = table->map;
update = ck_ht_map_create(table->mode, map->capacity); update = ck_ht_map_create(table, map->capacity);
if (update == NULL) if (update == NULL)
return false; return false;
ck_pr_store_ptr(&table->map, update); ck_pr_store_ptr(&table->map, update);
ck_ht_map_destroy(map, true); ck_ht_map_destroy(table->m, map, true);
return true; return true;
} }
@ -393,7 +387,7 @@ restart:
if (map->capacity >= capacity) if (map->capacity >= capacity)
return false; return false;
update = ck_ht_map_create(table->mode, capacity); update = ck_ht_map_create(table, capacity);
if (update == NULL) if (update == NULL)
return false; return false;
@ -447,7 +441,7 @@ restart:
* We have hit the probe limit, the map needs to be even * We have hit the probe limit, the map needs to be even
* larger. * larger.
*/ */
ck_ht_map_destroy(update, false); ck_ht_map_destroy(table->m, update, false);
capacity <<= 1; capacity <<= 1;
goto restart; goto restart;
} }
@ -455,7 +449,7 @@ restart:
ck_pr_fence_store(); ck_pr_fence_store();
ck_pr_store_ptr(&table->map, update); ck_pr_store_ptr(&table->map, update);
ck_ht_map_destroy(map, true); ck_ht_map_destroy(table->m, map, true);
return true; return true;
} }
@ -720,7 +714,7 @@ void
ck_ht_destroy(struct ck_ht *table) ck_ht_destroy(struct ck_ht *table)
{ {
ck_ht_map_destroy(table->map, false); ck_ht_map_destroy(table->m, table->map, false);
return; return;
} }

Loading…
Cancel
Save