46 #define MAX_HASH_ENTRIES 30000
47 #define MAX_TEST_SECONDS 60
64 static int is_timed_out(
struct hash_test const *data) {
69 ast_test_status_update(data->
test,
"Now: %ld.%06ld Deadline: %ld.%06ld\n",
70 now.tv_sec, (
long)now.tv_usec,
77 static char *ht_new(
int i)
79 const int buflen = 12;
85 needed = snprintf(keybuf, buflen,
"key%08x", (
unsigned)i);
86 ast_assert(needed + 1 <= buflen);
91 static void ht_delete(
void *obj)
97 static void *hash_test_grow(
void *d)
102 for (i = 0; i < data->
max_grow; ++i) {
104 if (is_timed_out(data)) {
105 return "Growth timed out";
109 return "Allocation failed";
118 static void *hash_test_lookup(
void *d)
122 unsigned seed = time(NULL);
132 if (is_timed_out(data)) {
133 return "Lookup timed out";
143 i = rand_r(&seed) % max;
146 return "Allocation failed.";
150 if (!is_in_hashtab) {
151 return "key unexpectedly missing";
159 static void *hash_test_shrink(
void *d)
164 for (i = 1; i < data->
preload; ++i) {
165 char *obj = ht_new(-i);
170 return "Allocation failed";
173 deleted = from_hashtab != NULL;
176 ht_delete(from_hashtab);
178 return "could not delete object";
180 if (is_timed_out(data)) {
181 return "Shrink timed out";
188 static void *hash_test_count(
void *d)
201 if (strncmp(ht,
"key0", 4) == 0) {
208 if (last_count == count) {
213 }
else if (last_count > count) {
215 return "hashtab unexpectedly shrank";
218 if (is_timed_out(data)) {
219 return "Count timed out";
229 enum ast_test_result_state res = AST_TEST_PASS;
231 pthread_t grow_thread, count_thread, lookup_thread, shrink_thread;
232 void *thread_results;
237 info->name =
"thrash";
238 info->category =
"/main/hashtab/";
239 info->summary =
"Testing hashtab concurrency";
240 info->description =
"Test hashtab concurrency correctness.";
241 return AST_TEST_NOT_RUN;
246 ast_test_status_update(
test,
"Executing hash concurrency test...\n");
248 data.
preload = MAX_HASH_ENTRIES / 2;
256 ast_test_status_update(
test,
"Allocation failed\n");
258 return AST_TEST_FAIL;
263 for (i = 1; i < data.
preload; ++i) {
264 char *obj = ht_new(-i);
266 ast_test_status_update(
test,
"Allocation failed\n");
268 return AST_TEST_FAIL;
274 ast_pthread_create(&grow_thread, NULL, hash_test_grow, &data);
276 ast_pthread_create(&count_thread, NULL, hash_test_count, &data);
278 ast_pthread_create(&lookup_thread, NULL, hash_test_lookup, &data);
280 ast_pthread_create(&shrink_thread, NULL, hash_test_shrink, &data);
282 pthread_join(grow_thread, &thread_results);
283 if (thread_results != NULL) {
284 ast_test_status_update(
test,
"Growth thread failed: %s\n",
285 (
char *)thread_results);
289 pthread_join(count_thread, &thread_results);
290 if (thread_results != NULL) {
291 ast_test_status_update(
test,
"Count thread failed: %s\n",
292 (
char *)thread_results);
296 pthread_join(lookup_thread, &thread_results);
297 if (thread_results != NULL) {
298 ast_test_status_update(
test,
"Lookup thread failed: %s\n",
299 (
char *)thread_results);
303 pthread_join(shrink_thread, &thread_results);
304 if (thread_results != NULL) {
305 ast_test_status_update(
test,
"Shrink thread failed: %s\n",
306 (
char *)thread_results);
311 ast_test_status_update(
test,
312 "Invalid hashtab size. Expected: %d, Actual: %d\n",
321 static int unload_module(
void)
327 static int load_module(
void)
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int ast_hashtab_compare_strings_nocase(const void *a, const void *b)
Compares two strings for equality, ignoring case.
void * ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
Lookup this object in the hash table.
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
Time-related functions and macros.
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
void * ast_hashtab_next(struct ast_hashtab_iter *it)
Gets the next object in the list, advances iter one step returns null on end of traversal.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
int ast_hashtab_resize_java(struct ast_hashtab *tab)
Determines if a table resize should occur using the Java algorithm (if the table load factor is 75% o...
#define ast_hashtab_insert_immediate(tab, obj)
Insert without checking.
#define ast_malloc(len)
A wrapper for malloc()
void ast_hashtab_end_traversal(struct ast_hashtab_iter *it)
end the traversal, free the iterator, unlock if necc.
void * ast_hashtab_remove_object_via_lookup(struct ast_hashtab *tab, void *obj)
Looks up the object, removes the corresponding bucket.
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
an iterator for traversing the buckets
struct ast_hashtab * to_be_thrashed
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
#define AST_TEST_DEFINE(hdr)
struct ao2_container * to_be_thrashed
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
#define ast_hashtab_create(initial_buckets, compare, resize, newsize, hash, do_locking)
Create the hashtable list.
unsigned int ast_hashtab_hash_string_nocase(const void *obj)
Hashes a string to a number ignoring case.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
int ast_hashtab_size(struct ast_hashtab *tab)
Returns the number of elements stored in the hashtab.
void ast_hashtab_destroy(struct ast_hashtab *tab, void(*objdestroyfunc)(void *obj))
This func will free the hash table and all its memory.