From 1c7069068bd029ef8a2ac387f1b820cd90395253 Mon Sep 17 00:00:00 2001 From: YuQing <384681@qq.com> Date: Tue, 21 Jan 2020 10:06:48 +0800 Subject: [PATCH] add src/tests/test_uniq_skiplist.c --- src/tests/Makefile | 2 +- src/tests/test_pthread_lock.c | 3 + src/tests/test_uniq_skiplist.c | 235 +++++++++++++++++++++++++++++++++ src/uniq_skiplist.c | 130 ++++++++++++++---- src/uniq_skiplist.h | 11 +- 5 files changed, 352 insertions(+), 29 deletions(-) create mode 100644 src/tests/test_uniq_skiplist.c diff --git a/src/tests/Makefile b/src/tests/Makefile index 1ce1513..a689cb2 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -7,7 +7,7 @@ LIB_PATH = -lfastcommon -lpthread ALL_PRGS = test_allocator test_skiplist test_multi_skiplist test_mblock test_blocked_queue \ test_id_generator test_ini_parser test_char_convert test_char_convert_loader \ test_logger test_skiplist_set test_crc32 test_thourands_seperator test_sched_thread \ - test_json_parser test_pthread_lock + test_json_parser test_pthread_lock test_uniq_skiplist all: $(ALL_PRGS) .c: diff --git a/src/tests/test_pthread_lock.c b/src/tests/test_pthread_lock.c index c8ad263..b30523e 100644 --- a/src/tests/test_pthread_lock.c +++ b/src/tests/test_pthread_lock.c @@ -13,6 +13,7 @@ #include "fastcommon/fast_allocator.h" #define LOOP_COUNT (30 * 1000 * 1000) +#define barrier() __asm__ __volatile__("" ::: "memory") int main(int argc, char *argv[]) { @@ -35,6 +36,8 @@ int main(int argc, char *argv[]) start_time = get_current_time_ms(); sum = 0; for (k=1; k<=LOOP_COUNT; k++) { + __sync_synchronize(); + //barrier(); __sync_add_and_fetch(&sum, k); } diff --git a/src/tests/test_uniq_skiplist.c b/src/tests/test_uniq_skiplist.c new file mode 100644 index 0000000..9ed3ea1 --- /dev/null +++ b/src/tests/test_uniq_skiplist.c @@ -0,0 +1,235 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "fastcommon/uniq_skiplist.h" +#include "fastcommon/logger.h" +#include "fastcommon/shared_func.h" + +#define COUNT 1000000 +#define LEVEL_COUNT 16 +#define MIN_ALLOC_ONCE 8 +#define LAST_INDEX (COUNT - 1) + +static int *numbers; +static UniqSkiplistFactory factory; +static UniqSkiplist *sl = NULL; +static UniqSkiplistIterator iterator; +static int instance_count = 0; + +static void free_test_func(void *ptr) +{ + instance_count--; +} + +static int compare_func(const void *p1, const void *p2) +{ + return *((int *)p1) - *((int *)p2); +} + +void set_rand_numbers(const int multiple) +{ + int i; + int tmp; + int index1; + int index2; + + for (i=0; itop_level_index + 1); + + uniq_skiplist_free(sl); + fast_mblock_manager_stat_print(false); + + uniq_skiplist_destroy(&factory); + assert(instance_count == 0); + + end_time = get_current_time_ms(); + printf("pass OK, time used: %"PRId64" ms\n", end_time - start_time); + return 0; +} + diff --git a/src/uniq_skiplist.c b/src/uniq_skiplist.c index 459aabb..dd43a98 100644 --- a/src/uniq_skiplist.c +++ b/src/uniq_skiplist.c @@ -17,10 +17,36 @@ #include "logger.h" #include "uniq_skiplist.h" +static int best_element_counts[SKIPLIST_MAX_LEVEL_COUNT] = {0}; + +#define UNIQ_SKIPLIST_FREE_MBLOCK_OBJECT(sl, level_index, deleted) \ + do { \ + if (sl->factory->delay_free_seconds > 0) { \ + fast_mblock_delay_free_object(sl->factory->node_allocators + \ + level_index, (void *)deleted, \ + sl->factory->delay_free_seconds); \ + } else { \ + fast_mblock_free_object(sl->factory->node_allocators + \ + level_index, (void *)deleted); \ + } \ + } while (0) + +static void init_best_element_counts() +{ + int i; + int element_count; + + element_count = 1; + for (i=0; iskiplist_allocators, + if ((result=fast_mblock_init_ex(&factory->skiplist_allocator, sizeof(UniqSkiplist), alloc_skiplist_once > 0 ? alloc_skiplist_once : 16 * 1024, NULL, false)) != 0) { @@ -83,6 +113,7 @@ int uniq_skiplist_init_ex(UniqSkiplistFactory *factory, factory->max_level_count = max_level_count; factory->compare_func = compare_func; factory->free_func = free_func; + factory->delay_free_seconds = delay_free_seconds; srand(time(NULL)); return 0; @@ -96,7 +127,7 @@ void uniq_skiplist_destroy(UniqSkiplistFactory *factory) return; } - fast_mblock_destroy(&factory->skiplist_allocators); + fast_mblock_destroy(&factory->skiplist_allocator); for (i=0; imax_level_count; i++) { fast_mblock_destroy(factory->node_allocators + i); @@ -131,7 +162,7 @@ UniqSkiplist *uniq_skiplist_new(UniqSkiplistFactory *factory, } sl = (UniqSkiplist *)fast_mblock_alloc_object( - &factory->skiplist_allocators); + &factory->skiplist_allocator); sl->element_count = 0; sl->factory = factory; @@ -159,16 +190,57 @@ UniqSkiplist *uniq_skiplist_new(UniqSkiplistFactory *factory, return sl; } +static int uniq_skiplist_grow(UniqSkiplist *sl) +{ + int top_level_index; + int old_top_level_index; + int i; + struct fast_mblock_man *top_mblock; + UniqSkiplistNode *old_top; + UniqSkiplistNode *top; + + top_level_index = sl->top_level_index + 1; + if (top_level_index >= sl->factory->max_level_count) { + return E2BIG; + } + + top_mblock = sl->factory->node_allocators + top_level_index; + top = (UniqSkiplistNode *)fast_mblock_alloc_object(top_mblock); + if (top == NULL) { + return ENOMEM; + } + memset(top, 0, top_mblock->info.element_size); + + top->links[top_level_index] = sl->tail; + for (i=0; i<=sl->top_level_index; i++) { + top->links[i] = sl->top->links[i]; + } + + old_top_level_index = sl->top_level_index; + old_top = sl->top; + sl->top = top; + + __sync_synchronize(); + sl->top_level_index = top_level_index; + + UNIQ_SKIPLIST_FREE_MBLOCK_OBJECT(sl, old_top_level_index, old_top); + return 0; +} + void uniq_skiplist_free(UniqSkiplist *sl) { - UniqSkiplistNode *node; - UniqSkiplistNode *deleted; + volatile UniqSkiplistNode *node; + volatile UniqSkiplistNode *deleted; - if (sl->element_count == 0) - { + if (sl->top == NULL) { return; } + fast_mblock_free_object(sl->factory->node_allocators + + sl->top_level_index, (void *)sl->top); + fast_mblock_free_object(sl->factory->node_allocators + 0, + (void *)sl->tail); + node = sl->top->links[0]; if (sl->factory->free_func != NULL) { while (node != sl->tail) { @@ -176,18 +248,21 @@ void uniq_skiplist_free(UniqSkiplist *sl) node = node->links[0]; sl->factory->free_func(deleted->data); fast_mblock_free_object(sl->factory->node_allocators + - deleted->level_index, deleted); + deleted->level_index, (void *)deleted); } } else { while (node != sl->tail) { deleted = node; node = node->links[0]; fast_mblock_free_object(sl->factory->node_allocators + - deleted->level_index, deleted); + deleted->level_index, (void *)deleted); } } + sl->top = NULL; + sl->tail = NULL; sl->element_count = 0; + fast_mblock_free_object(&sl->factory->skiplist_allocator, sl); } static inline int uniq_skiplist_get_level_index(UniqSkiplist *sl) @@ -209,8 +284,8 @@ int uniq_skiplist_insert(UniqSkiplist *sl, void *data) int level_index; int cmp; UniqSkiplistNode *node; - UniqSkiplistNode *previous; - UniqSkiplistNode *tmp_previous[SKIPLIST_MAX_LEVEL_COUNT]; + volatile UniqSkiplistNode *previous; + volatile UniqSkiplistNode *tmp_previous[SKIPLIST_MAX_LEVEL_COUNT]; level_index = uniq_skiplist_get_level_index(sl); previous = sl->top; @@ -253,12 +328,19 @@ int uniq_skiplist_insert(UniqSkiplist *sl, void *data) node->level_index = level_index; node->data = data; + __sync_synchronize(); + //thread safe for one write with many read model for (i=0; i<=level_index; i++) { node->links[i] = tmp_previous[i]->links[i]; tmp_previous[i]->links[i] = node; } + sl->element_count++; + if (sl->element_count > best_element_counts[sl->top_level_index]) { + uniq_skiplist_grow(sl); + } + return 0; } @@ -267,7 +349,7 @@ static UniqSkiplistNode *uniq_skiplist_get_equal_previous(UniqSkiplist *sl, { int i; int cmp; - UniqSkiplistNode *previous; + volatile UniqSkiplistNode *previous; previous = sl->top; for (i=sl->top_level_index; i>=0; i--) { @@ -278,7 +360,7 @@ static UniqSkiplistNode *uniq_skiplist_get_equal_previous(UniqSkiplist *sl, } else if (cmp == 0) { *level_index = i; - return previous; + return (UniqSkiplistNode *)previous; } previous = previous->links[i]; @@ -293,7 +375,7 @@ static UniqSkiplistNode *uniq_skiplist_get_first_larger_or_equal( { int i; int cmp; - UniqSkiplistNode *previous; + volatile UniqSkiplistNode *previous; previous = sl->top; for (i=sl->top_level_index; i>=0; i--) { @@ -303,14 +385,14 @@ static UniqSkiplistNode *uniq_skiplist_get_first_larger_or_equal( break; } else if (cmp == 0) { - return previous->links[i]; + return (UniqSkiplistNode *)previous->links[i]; } previous = previous->links[i]; } } - return previous->links[0]; + return (UniqSkiplistNode *)previous->links[0]; } static UniqSkiplistNode *uniq_skiplist_get_first_larger( @@ -318,7 +400,7 @@ static UniqSkiplistNode *uniq_skiplist_get_first_larger( { int i; int cmp; - UniqSkiplistNode *previous; + volatile UniqSkiplistNode *previous; previous = sl->top; for (i=sl->top_level_index; i>=0; i--) { @@ -328,22 +410,22 @@ static UniqSkiplistNode *uniq_skiplist_get_first_larger( break; } else if (cmp == 0) { - return previous->links[i]->links[0]; + return (UniqSkiplistNode *)previous->links[i]->links[0]; } previous = previous->links[i]; } } - return previous->links[0]; + return (UniqSkiplistNode *)previous->links[0]; } int uniq_skiplist_delete(UniqSkiplist *sl, void *data) { int i; int level_index; - UniqSkiplistNode *previous; - UniqSkiplistNode *deleted; + volatile UniqSkiplistNode *previous; + volatile UniqSkiplistNode *deleted; previous = uniq_skiplist_get_equal_previous(sl, data, &level_index); if (previous == NULL) { @@ -365,7 +447,9 @@ int uniq_skiplist_delete(UniqSkiplist *sl, void *data) if (sl->factory->free_func != NULL) { sl->factory->free_func(deleted->data); } - fast_mblock_free_object(sl->factory->node_allocators + level_index, deleted); + + UNIQ_SKIPLIST_FREE_MBLOCK_OBJECT(sl, level_index, deleted); + sl->element_count--; return 0; } diff --git a/src/uniq_skiplist.h b/src/uniq_skiplist.h index d2804fd..b939d09 100644 --- a/src/uniq_skiplist.h +++ b/src/uniq_skiplist.h @@ -22,15 +22,16 @@ typedef struct uniq_skiplist_node { void *data; int level_index; - struct uniq_skiplist_node *links[0]; + volatile struct uniq_skiplist_node *links[0]; } UniqSkiplistNode; typedef struct uniq_skiplist_factory { int max_level_count; + int delay_free_seconds; skiplist_compare_func compare_func; skiplist_free_func free_func; - struct fast_mblock_man skiplist_allocators; + struct fast_mblock_man skiplist_allocator; struct fast_mblock_man *node_allocators; } UniqSkiplistFactory; @@ -44,8 +45,8 @@ typedef struct uniq_skiplist } UniqSkiplist; typedef struct uniq_skiplist_iterator { - UniqSkiplistNode *current; - UniqSkiplistNode *tail; + volatile UniqSkiplistNode *current; + volatile UniqSkiplistNode *tail; } UniqSkiplistIterator; #ifdef __cplusplus @@ -60,7 +61,7 @@ extern "C" { int uniq_skiplist_init_ex(UniqSkiplistFactory *factory, const int max_level_count, skiplist_compare_func compare_func, skiplist_free_func free_func, const int alloc_skiplist_once, - const int min_alloc_elements_once); + const int min_alloc_elements_once, const int delay_free_seconds); void uniq_skiplist_destroy(UniqSkiplistFactory *factory);