From: Brian Aker Date: Wed, 20 Jan 2010 02:22:17 +0000 (-0800) Subject: Updating tree for new function work in libhashkit. X-Git-Tag: 0.40~75 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=42771008c1a69a2bfac10bbc89d00094d738e896;p=awesomized%2Flibmemcached Updating tree for new function work in libhashkit. --- diff --git a/libhashkit/function.c b/libhashkit/function.c new file mode 100644 index 00000000..445859d2 --- /dev/null +++ b/libhashkit/function.c @@ -0,0 +1,197 @@ +/* HashKit + * Copyright (C) 2010 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#include "common.h" + +uint32_t hashkit_generate_value(const hashkit_st *self, const char *key, size_t key_length) +{ + return self->base_hash.function(key, key_length, self->base_hash.context); +} + +static hashkit_return_t _set_function(struct hashkit_function_st *self, hashkit_hash_algorithm_t hash_algorithm) +{ + switch (hash_algorithm) + { + case HASHKIT_HASH_DEFAULT: + self->function= hashkit_one_at_a_time; + break; + case HASHKIT_HASH_MD5: + self->function= hashkit_md5; + break; + case HASHKIT_HASH_CRC: + self->function= hashkit_crc32; + break; + case HASHKIT_HASH_FNV1_64: + self->function= hashkit_fnv1_64; + break; + case HASHKIT_HASH_FNV1A_64: + self->function= hashkit_fnv1a_64; + break; + case HASHKIT_HASH_FNV1_32: + self->function= hashkit_fnv1_32; + break; + case HASHKIT_HASH_FNV1A_32: + self->function= hashkit_fnv1a_32; + break; + case HASHKIT_HASH_HSIEH: +#ifdef HAVE_HSIEH_HASH + self->function= hashkit_hsieh; + break; +#else + return HASHKIT_FAILURE; +#endif + case HASHKIT_HASH_MURMUR: + self->function= hashkit_murmur; + break; + case HASHKIT_HASH_JENKINS: + self->function= hashkit_jenkins; + break; + case HASHKIT_HASH_CUSTOM: + case HASHKIT_HASH_MAX: + default: + return HASHKIT_FAILURE; + break; + } + + self->context= NULL; + + return HASHKIT_SUCCESS; +} + +hashkit_return_t hashkit_set_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm) +{ + return _set_function(&self->base_hash, hash_algorithm); +} + +hashkit_return_t hashkit_set_distribution_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm) +{ + return _set_function(&self->distribution_hash, hash_algorithm); +} + +static hashkit_return_t _set_custom_function(struct hashkit_function_st *self, hashkit_hash_fn function, void *context) +{ + if (function) + { + self->function= function; + self->context= context; + + return HASHKIT_SUCCESS; + } + + return HASHKIT_FAILURE; +} + +hashkit_return_t hashkit_set_custom_function(hashkit_st *self, hashkit_hash_fn function, void *context) +{ + return _set_custom_function(&self->base_hash, function, context); +} + +hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context) +{ + return _set_custom_function(&self->distribution_hash, function, context); +} + +static hashkit_hash_algorithm_t get_function_type(const hashkit_hash_fn function) +{ + if (function == hashkit_one_at_a_time) + { + return HASHKIT_HASH_DEFAULT; + } + else if (function == hashkit_md5) + { + return HASHKIT_HASH_MD5; + } + else if (function == hashkit_crc32) + { + return HASHKIT_HASH_CRC; + } + else if (function == hashkit_fnv1_64) + { + return HASHKIT_HASH_FNV1_64; + } + else if (function == hashkit_fnv1a_64) + { + return HASHKIT_HASH_FNV1A_64; + } + else if (function == hashkit_fnv1_32) + { + return HASHKIT_HASH_FNV1_32; + } + else if (function == hashkit_fnv1a_32) + { + return HASHKIT_HASH_FNV1A_32; + } +#ifdef HAVE_HSIEH_HASH + else if (function == hashkit_hsieh) + { + return HASHKIT_HASH_HSIEH; + } +#endif + else if (function == hashkit_murmur) + { + return HASHKIT_HASH_MURMUR; + } + else if (function == hashkit_jenkins) + { + return HASHKIT_HASH_JENKINS; + } + + return HASHKIT_HASH_CUSTOM; +} + +hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *self) +{ + return get_function_type(self->base_hash.function); +} + +hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self) +{ + return get_function_type(self->distribution_hash.function); +} + +uint32_t libhashkit_generate_value(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm) +{ + switch (hash_algorithm) + { + case HASHKIT_HASH_DEFAULT: + return libhashkit_one_at_a_time(key, key_length); + case HASHKIT_HASH_MD5: + return libhashkit_md5(key, key_length); + case HASHKIT_HASH_CRC: + return libhashkit_crc32(key, key_length); + case HASHKIT_HASH_FNV1_64: + return libhashkit_fnv1_64(key, key_length); + case HASHKIT_HASH_FNV1A_64: + return libhashkit_fnv1a_64(key, key_length); + case HASHKIT_HASH_FNV1_32: + return libhashkit_fnv1_32(key, key_length); + case HASHKIT_HASH_FNV1A_32: + return libhashkit_fnv1a_32(key, key_length); + case HASHKIT_HASH_HSIEH: +#ifdef HAVE_HSIEH_HASH + return libhashkit_hsieh(key, key_length); +#else + return 1; +#endif + case HASHKIT_HASH_MURMUR: + return libhashkit_murmur(key, key_length); + case HASHKIT_HASH_JENKINS: + return libhashkit_jenkins(key, key_length); + case HASHKIT_HASH_CUSTOM: + case HASHKIT_HASH_MAX: + default: +#ifdef HAVE_DEBUG + fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n"); + fflush(stderr); + assert(0); +#endif + break; + } + + return 1; +} diff --git a/libhashkit/function.h b/libhashkit/function.h new file mode 100644 index 00000000..8a550ec6 --- /dev/null +++ b/libhashkit/function.h @@ -0,0 +1,54 @@ +/* HashKit + * Copyright (C) 2010 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + */ + +#ifndef HASHKIT_FUNCTION_H +#define HASHKIT_FUNCTION_H + +#ifdef __cplusplus +extern "C" { +#endif + +HASHKIT_API +uint32_t hashkit_generate_value(const hashkit_st *self, const char *key, size_t key_length); + +/** + This sets/gets the default function we will be using. +*/ +HASHKIT_API +hashkit_return_t hashkit_set_function(hashkit_st *hash, hashkit_hash_algorithm_t hash_algorithm); + +HASHKIT_API +hashkit_return_t hashkit_set_custom_function(hashkit_st *hash, hashkit_hash_fn function, void *context); + +HASHKIT_API +hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *hash); + +/** + This sets/gets the function we use for distribution. +*/ +HASHKIT_API +hashkit_return_t hashkit_set_distribution_function(hashkit_st *hash, hashkit_hash_algorithm_t hash_algorithm); + +HASHKIT_API +hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context); + +HASHKIT_API +hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self); + +/** + This is a utilitly function provided so that you can directly access hashes with a hashkit_st. +*/ + +HASHKIT_API +uint32_t libhashkit_generate_value(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm); + +#ifdef __cplusplus +} +#endif + +#endif /* HASHKIT_FUNCTION_H */ diff --git a/libhashkit/hashkit.c b/libhashkit/hashkit.c index 9a7e93e9..47c9e580 100644 --- a/libhashkit/hashkit.c +++ b/libhashkit/hashkit.c @@ -13,12 +13,21 @@ static const hashkit_st global_default_hash= { .function= hashkit_one_at_a_time, .context= NULL }, + .flags= { + .is_base_same_distributed= false, + } }; -/** - @note We make no assumptions that "hashk" has been, or not been allocated from heap/stack. We just know we didn't do it. -*/ -hashkit_st *hashkit_create(hashkit_st *self) +static inline bool _hashkit_init(hashkit_st *self) +{ + self->base_hash= global_default_hash.base_hash; + self->distribution_hash= global_default_hash.base_hash; + self->flags= global_default_hash.flags; + + return true; +} + +static inline hashkit_st *_hashkit_create(hashkit_st *self) { if (self == NULL) { @@ -35,7 +44,19 @@ hashkit_st *hashkit_create(hashkit_st *self) self->options.is_allocated= false; } - self->base_hash= global_default_hash.base_hash; + return self; +} + +hashkit_st *hashkit_create(hashkit_st *self) +{ + self= _hashkit_create(self); + if (! self) + return self; + + if (! _hashkit_init(self)) + { + hashkit_free(self); + } return self; } @@ -57,7 +78,7 @@ hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source) } /* new_clone will be a pointer to destination */ - destination= hashkit_create(destination); + destination= _hashkit_create(destination); // Should only happen on allocation failure. if (destination == NULL) @@ -66,6 +87,8 @@ hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source) } destination->base_hash= source->base_hash; + destination->distribution_hash= source->distribution_hash; + destination->flags= source->flags; return destination; } @@ -73,166 +96,13 @@ hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source) bool hashkit_compare(const hashkit_st *first, const hashkit_st *second) { if (first->base_hash.function == second->base_hash.function && - first->base_hash.context == second->base_hash.context) - return true; - - return false; -} - -uint32_t hashkit_generate_value(const hashkit_st *self, const char *key, size_t key_length) -{ - return self->base_hash.function(key, key_length, self->base_hash.context); -} - -hashkit_return_t hashkit_set_base_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm) -{ - switch (hash_algorithm) + first->base_hash.context == second->base_hash.context && + first->distribution_hash.function == second->distribution_hash.function && + first->distribution_hash.context == second->distribution_hash.context && + first->flags.is_base_same_distributed == second->flags.is_base_same_distributed) { - case HASHKIT_HASH_DEFAULT: - self->base_hash.function= hashkit_one_at_a_time; - break; - case HASHKIT_HASH_MD5: - self->base_hash.function= hashkit_md5; - break; - case HASHKIT_HASH_CRC: - self->base_hash.function= hashkit_crc32; - break; - case HASHKIT_HASH_FNV1_64: - self->base_hash.function= hashkit_fnv1_64; - break; - case HASHKIT_HASH_FNV1A_64: - self->base_hash.function= hashkit_fnv1a_64; - break; - case HASHKIT_HASH_FNV1_32: - self->base_hash.function= hashkit_fnv1_32; - break; - case HASHKIT_HASH_FNV1A_32: - self->base_hash.function= hashkit_fnv1a_32; - break; - case HASHKIT_HASH_HSIEH: -#ifdef HAVE_HSIEH_HASH - self->base_hash.function= hashkit_hsieh; - break; -#else - return HASHKIT_FAILURE; -#endif - case HASHKIT_HASH_MURMUR: - self->base_hash.function= hashkit_murmur; - break; - case HASHKIT_HASH_JENKINS: - self->base_hash.function= hashkit_jenkins; - break; - case HASHKIT_HASH_CUSTOM: - case HASHKIT_HASH_MAX: - default: - return HASHKIT_FAILURE; - break; - } - - self->base_hash.context= NULL; - - return HASHKIT_SUCCESS; -} - -hashkit_return_t hashkit_set_base_function_custom(hashkit_st *self, hashkit_hash_fn function, void *context) -{ - if (function) - { - self->base_hash.function= function; - self->base_hash.context= context; - - return HASHKIT_SUCCESS; - } - - return HASHKIT_FAILURE; -} - -hashkit_hash_algorithm_t hashkit_get_base_function(const hashkit_st *self) -{ - if (self->base_hash.function == hashkit_one_at_a_time) - { - return HASHKIT_HASH_DEFAULT; - } - else if (self->base_hash.function == hashkit_md5) - { - return HASHKIT_HASH_MD5; - } - else if (self->base_hash.function == hashkit_crc32) - { - return HASHKIT_HASH_CRC; - } - else if (self->base_hash.function == hashkit_fnv1_64) - { - return HASHKIT_HASH_FNV1_64; - } - else if (self->base_hash.function == hashkit_fnv1a_64) - { - return HASHKIT_HASH_FNV1A_64; - } - else if (self->base_hash.function == hashkit_fnv1_32) - { - return HASHKIT_HASH_FNV1_32; - } - else if (self->base_hash.function == hashkit_fnv1a_32) - { - return HASHKIT_HASH_FNV1A_32; - } -#ifdef HAVE_HSIEH_HASH - else if (self->base_hash.function == hashkit_hsieh) - { - return HASHKIT_HASH_HSIEH; - } -#endif - else if (self->base_hash.function == hashkit_murmur) - { - return HASHKIT_HASH_MURMUR; - } - else if (self->base_hash.function == hashkit_jenkins) - { - return HASHKIT_HASH_JENKINS; - } - - return HASHKIT_HASH_CUSTOM; -} - -uint32_t libhashkit_generate_value(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm) -{ - switch (hash_algorithm) - { - case HASHKIT_HASH_DEFAULT: - return libhashkit_one_at_a_time(key, key_length); - case HASHKIT_HASH_MD5: - return libhashkit_md5(key, key_length); - case HASHKIT_HASH_CRC: - return libhashkit_crc32(key, key_length); - case HASHKIT_HASH_FNV1_64: - return libhashkit_fnv1_64(key, key_length); - case HASHKIT_HASH_FNV1A_64: - return libhashkit_fnv1a_64(key, key_length); - case HASHKIT_HASH_FNV1_32: - return libhashkit_fnv1_32(key, key_length); - case HASHKIT_HASH_FNV1A_32: - return libhashkit_fnv1a_32(key, key_length); - case HASHKIT_HASH_HSIEH: -#ifdef HAVE_HSIEH_HASH - return libhashkit_hsieh(key, key_length); -#else - return 1; -#endif - case HASHKIT_HASH_MURMUR: - return libhashkit_murmur(key, key_length); - case HASHKIT_HASH_JENKINS: - return libhashkit_jenkins(key, key_length); - case HASHKIT_HASH_CUSTOM: - case HASHKIT_HASH_MAX: - default: -#ifdef HAVE_DEBUG - fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n"); - fflush(stderr); - assert(0); -#endif - break; + return true; } - return 1; + return false; } diff --git a/libhashkit/hashkit.h b/libhashkit/hashkit.h index 9b0b32ef..1def040d 100644 --- a/libhashkit/hashkit.h +++ b/libhashkit/hashkit.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -26,10 +27,14 @@ extern "C" { struct hashkit_st { - struct { + struct hashkit_function_st { hashkit_hash_fn function; void *context; - } base_hash; + } base_hash, distribution_hash; + + struct { + bool is_base_same_distributed:1; + } flags; struct { bool is_allocated:1; @@ -48,21 +53,6 @@ bool hashkit_compare(const hashkit_st *first, const hashkit_st *second); HASHKIT_API void hashkit_free(hashkit_st *hash); -HASHKIT_API -uint32_t hashkit_generate_value(const hashkit_st *self, const char *key, size_t key_length); - -HASHKIT_API -hashkit_return_t hashkit_set_base_function(hashkit_st *hash, hashkit_hash_algorithm_t hash_algorithm); - -HASHKIT_API -hashkit_hash_algorithm_t hashkit_get_base_function(const hashkit_st *hash); - -HASHKIT_API -hashkit_return_t hashkit_set_base_function_custom(hashkit_st *hash, hashkit_hash_fn function, void *context); - -HASHKIT_API -uint32_t libhashkit_generate_value(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm); - #define hashkit_is_allocated(__object) ((__object)->options.is_allocated) #define hashkit_is_initialized(__object) ((__object)->options.is_initialized) diff --git a/libhashkit/include.am b/libhashkit/include.am index 7bcd7801..97aac9da 100644 --- a/libhashkit/include.am +++ b/libhashkit/include.am @@ -14,6 +14,7 @@ lib_LTLIBRARIES+= libhashkit/libhashkit.la nobase_include_HEADERS+= \ libhashkit/algorithm.h \ libhashkit/behavior.h \ + libhashkit/function.h \ libhashkit/hashkit.h \ libhashkit/strerror.h \ libhashkit/types.h \ @@ -27,6 +28,7 @@ libhashkit_libhashkit_la_SOURCES= \ libhashkit/behavior.c \ libhashkit/crc32.c \ libhashkit/fnv.c \ + libhashkit/function.c \ libhashkit/hashkit.c \ libhashkit/jenkins.c \ libhashkit/ketama.c \ diff --git a/libmemcached/behavior.c b/libmemcached/behavior.c index 67a261d3..ba4db737 100644 --- a/libmemcached/behavior.c +++ b/libmemcached/behavior.c @@ -266,9 +266,9 @@ uint64_t memcached_behavior_get(memcached_st *ptr, case MEMCACHED_BEHAVIOR_KETAMA: return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0; case MEMCACHED_BEHAVIOR_HASH: - return hashkit_get_base_function(&ptr->hashkit); + return hashkit_get_function(&ptr->hashkit); case MEMCACHED_BEHAVIOR_KETAMA_HASH: - return hashkit_get_base_function(&ptr->distribution_hashkit); + return hashkit_get_function(&ptr->distribution_hashkit); case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return ptr->server_failure_limit; case MEMCACHED_BEHAVIOR_SORT_HOSTS: @@ -382,25 +382,25 @@ memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type) { hashkit_return_t rc; - rc= hashkit_set_base_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type); + rc= hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type); return rc == HASHKIT_SUCCESS ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; } memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr) { - return (memcached_hash_t)hashkit_get_base_function(&ptr->hashkit); + return (memcached_hash_t)hashkit_get_function(&ptr->hashkit); } memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type) { hashkit_return_t rc; - rc= hashkit_set_base_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type); + rc= hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type); return rc == HASHKIT_SUCCESS ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE; } memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr) { - return (memcached_hash_t)hashkit_get_base_function(&ptr->distribution_hashkit); + return (memcached_hash_t)hashkit_get_function(&ptr->distribution_hashkit); } diff --git a/tests/hashkit_functions.c b/tests/hashkit_functions.c index b7403e18..2642f76a 100644 --- a/tests/hashkit_functions.c +++ b/tests/hashkit_functions.c @@ -305,7 +305,7 @@ static test_return_t hashkit_generate_value_test(hashkit_st *hashk) return TEST_SUCCESS; } -static test_return_t hashkit_set_base_function_test(hashkit_st *hashk) +static test_return_t hashkit_set_function_test(hashkit_st *hashk) { for (hashkit_hash_algorithm_t algo = HASHKIT_HASH_DEFAULT; algo < HASHKIT_HASH_MAX; algo++) { @@ -314,7 +314,7 @@ static test_return_t hashkit_set_base_function_test(hashkit_st *hashk) const char **ptr; uint32_t *list; - rc= hashkit_set_base_function(hashk, algo); + rc= hashkit_set_function(hashk, algo); /* Hsieh is disabled most of the time for patent issues */ if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_HSIEH) @@ -383,14 +383,14 @@ static uint32_t hash_test_function(const char *string, size_t string_length, voi return libhashkit_md5(string, string_length); } -static test_return_t hashkit_set_base_function_custom_test(hashkit_st *hashk) +static test_return_t hashkit_set_custom_function_test(hashkit_st *hashk) { hashkit_return_t rc; uint32_t x; const char **ptr; - rc= hashkit_set_base_function_custom(hashk, hash_test_function, NULL); + rc= hashkit_set_custom_function(hashk, hash_test_function, NULL); test_true(rc == HASHKIT_SUCCESS); for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++) @@ -404,7 +404,39 @@ static test_return_t hashkit_set_base_function_custom_test(hashkit_st *hashk) return TEST_SUCCESS; } -static test_return_t hashkit_get_base_function_test(hashkit_st *hashk) +static test_return_t hashkit_set_distribution_function_test(hashkit_st *hashk) +{ + for (hashkit_hash_algorithm_t algo = HASHKIT_HASH_DEFAULT; algo < HASHKIT_HASH_MAX; algo++) + { + hashkit_return_t rc; + + rc= hashkit_set_distribution_function(hashk, algo); + + /* Hsieh is disabled most of the time for patent issues */ + if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_HSIEH) + continue; + + if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_CUSTOM) + continue; + + test_true(rc == HASHKIT_SUCCESS); + } + + return TEST_SUCCESS; +} + +static test_return_t hashkit_set_custom_distribution_function_test(hashkit_st *hashk) +{ + hashkit_return_t rc; + + rc= hashkit_set_custom_distribution_function(hashk, hash_test_function, NULL); + test_true(rc == HASHKIT_SUCCESS); + + return TEST_SUCCESS; +} + + +static test_return_t hashkit_get_function_test(hashkit_st *hashk) { for (hashkit_hash_algorithm_t algo = HASHKIT_HASH_DEFAULT; algo < HASHKIT_HASH_MAX; algo++) { @@ -413,10 +445,10 @@ static test_return_t hashkit_get_base_function_test(hashkit_st *hashk) if (HASHKIT_HASH_CUSTOM || HASHKIT_HASH_HSIEH) continue; - rc= hashkit_set_base_function(hashk, algo); + rc= hashkit_set_function(hashk, algo); test_true(rc == HASHKIT_SUCCESS); - test_true(hashkit_get_base_function(hashk) == algo); + test_true(hashkit_get_function(hashk) == algo); } return TEST_SUCCESS; } @@ -434,9 +466,11 @@ static test_return_t hashkit_compare_test(hashkit_st *hashk) test_st hashkit_st_functions[] ={ {"hashkit_generate_value", 0, (test_callback_fn)hashkit_generate_value_test}, - {"hashkit_set_base_function", 0, (test_callback_fn)hashkit_set_base_function_test}, - {"hashkit_set_base_function_custom", 0, (test_callback_fn)hashkit_set_base_function_custom_test}, - {"hashkit_get_base_function", 0, (test_callback_fn)hashkit_get_base_function_test}, + {"hashkit_set_function", 0, (test_callback_fn)hashkit_set_function_test}, + {"hashkit_set_custom_function", 0, (test_callback_fn)hashkit_set_custom_function_test}, + {"hashkit_get_function", 0, (test_callback_fn)hashkit_get_function_test}, + {"hashkit_set_distribution_function", 0, (test_callback_fn)hashkit_set_distribution_function_test}, + {"hashkit_set_custom_distribution_function", 0, (test_callback_fn)hashkit_set_custom_distribution_function_test}, {"hashkit_compare", 0, (test_callback_fn)hashkit_compare_test}, {0, 0, 0} };