add src/tests/test_uniq_skiplist.c

pull/37/head
YuQing 2020-01-21 10:06:48 +08:00
parent 91e0124ae5
commit 1c7069068b
5 changed files with 352 additions and 29 deletions

View File

@ -7,7 +7,7 @@ LIB_PATH = -lfastcommon -lpthread
ALL_PRGS = test_allocator test_skiplist test_multi_skiplist test_mblock test_blocked_queue \ 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_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_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) all: $(ALL_PRGS)
.c: .c:

View File

@ -13,6 +13,7 @@
#include "fastcommon/fast_allocator.h" #include "fastcommon/fast_allocator.h"
#define LOOP_COUNT (30 * 1000 * 1000) #define LOOP_COUNT (30 * 1000 * 1000)
#define barrier() __asm__ __volatile__("" ::: "memory")
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -35,6 +36,8 @@ int main(int argc, char *argv[])
start_time = get_current_time_ms(); start_time = get_current_time_ms();
sum = 0; sum = 0;
for (k=1; k<=LOOP_COUNT; k++) { for (k=1; k<=LOOP_COUNT; k++) {
__sync_synchronize();
//barrier();
__sync_add_and_fetch(&sum, k); __sync_add_and_fetch(&sum, k);
} }

View File

@ -0,0 +1,235 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#include <inttypes.h>
#include <sys/time.h>
#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; i<COUNT; i++) {
numbers[i] = multiple * i + 1;
}
for (i=0; i<COUNT; i++) {
index1 = LAST_INDEX * (int64_t)rand() / (int64_t)RAND_MAX;
index2 = LAST_INDEX * (int64_t)rand() / (int64_t)RAND_MAX;
if (index1 == index2) {
continue;
}
tmp = numbers[index1];
numbers[index1] = numbers[index2];
numbers[index2] = tmp;
}
}
static int test_insert()
{
int i;
int result;
int64_t start_time;
int64_t end_time;
void *value;
set_rand_numbers(1);
instance_count = 0;
start_time = get_current_time_ms();
for (i=0; i<COUNT; i++) {
if ((result=uniq_skiplist_insert(sl, numbers + i)) != 0) {
return result;
}
instance_count++;
}
assert(instance_count == COUNT);
end_time = get_current_time_ms();
printf("insert time used: %"PRId64" ms\n", end_time - start_time);
start_time = get_current_time_ms();
for (i=0; i<COUNT; i++) {
value = uniq_skiplist_find(sl, numbers + i);
assert(value != NULL && *((int *)value) == numbers[i]);
}
end_time = get_current_time_ms();
printf("find time used: %"PRId64" ms\n", end_time - start_time);
start_time = get_current_time_ms();
i = 0;
uniq_skiplist_iterator(sl, &iterator);
while ((value=uniq_skiplist_next(&iterator)) != NULL) {
i++;
if (i != *((int *)value)) {
fprintf(stderr, "i: %d != value: %d\n", i, *((int *)value));
break;
}
}
assert(i==COUNT);
end_time = get_current_time_ms();
printf("iterator time used: %"PRId64" ms\n", end_time - start_time);
return 0;
}
static void test_delete()
{
int i;
int64_t start_time;
int64_t end_time;
void *value;
start_time = get_current_time_ms();
for (i=0; i<COUNT; i++) {
assert(uniq_skiplist_delete(sl, numbers + i) == 0);
}
assert(instance_count == 0);
end_time = get_current_time_ms();
printf("delete time used: %"PRId64" ms\n", end_time - start_time);
start_time = get_current_time_ms();
for (i=0; i<COUNT; i++) {
value = uniq_skiplist_find(sl, numbers + i);
assert(value == NULL);
}
end_time = get_current_time_ms();
printf("find after delete time used: %"PRId64" ms\n", end_time - start_time);
i = 0;
uniq_skiplist_iterator(sl, &iterator);
while ((value=uniq_skiplist_next(&iterator)) != NULL) {
i++;
}
assert(i==0);
}
static void test_find_range()
{
int n_start;
int n_end;
int result;
int i;
int *value;
UniqSkiplistIterator iterator;
set_rand_numbers(2);
for (i=0; i<COUNT; i++) {
if ((result=uniq_skiplist_insert(sl, numbers + i)) != 0) {
return;
}
instance_count++;
}
n_start = 10;
n_end = 1;
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
assert(result == EINVAL);
n_start = -1;
n_end = 0;
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
assert(result == ENOENT);
n_start = 0;
n_end = 10;
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
assert(result == 0);
i = 0;
while ((value=(int *)uniq_skiplist_next(&iterator)) != NULL) {
printf("value: %d\n", *value);
i++;
}
printf("count: %d\n\n", i);
}
int main(int argc, char *argv[])
{
int result;
int64_t start_time;
int64_t end_time;
start_time = get_current_time_ms();
log_init();
numbers = (int *)malloc(sizeof(int) * COUNT);
srand(time(NULL));
fast_mblock_manager_init();
result = uniq_skiplist_init_ex(&factory, LEVEL_COUNT, compare_func,
free_test_func, 0, MIN_ALLOC_ONCE, 0);
if (result != 0) {
return result;
}
sl = uniq_skiplist_new(&factory, 2);
if (sl == NULL) {
return ENOMEM;
}
test_insert();
printf("\n");
fast_mblock_manager_stat_print(false);
test_delete();
printf("\n");
test_find_range();
test_delete();
printf("\n");
test_insert();
printf("\n");
/*
test_delete();
printf("\n");
*/
printf("skiplist level_count: %d\n", sl->top_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;
}

View File

@ -17,10 +17,36 @@
#include "logger.h" #include "logger.h"
#include "uniq_skiplist.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; i<SKIPLIST_MAX_LEVEL_COUNT; i++) {
element_count *= 2;
best_element_counts[i] = element_count;
}
}
int uniq_skiplist_init_ex(UniqSkiplistFactory *factory, int uniq_skiplist_init_ex(UniqSkiplistFactory *factory,
const int max_level_count, skiplist_compare_func compare_func, const int max_level_count, skiplist_compare_func compare_func,
skiplist_free_func free_func, const int alloc_skiplist_once, 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)
{ {
int bytes; int bytes;
int element_size; int element_size;
@ -28,6 +54,10 @@ int uniq_skiplist_init_ex(UniqSkiplistFactory *factory,
int alloc_elements_once; int alloc_elements_once;
int result; int result;
if (best_element_counts[0] == 0) {
init_best_element_counts();
}
if (max_level_count <= 0) { if (max_level_count <= 0) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"invalid max level count: %d", "invalid max level count: %d",
@ -73,7 +103,7 @@ int uniq_skiplist_init_ex(UniqSkiplistFactory *factory,
} }
} }
if ((result=fast_mblock_init_ex(&factory->skiplist_allocators, if ((result=fast_mblock_init_ex(&factory->skiplist_allocator,
sizeof(UniqSkiplist), alloc_skiplist_once > 0 ? sizeof(UniqSkiplist), alloc_skiplist_once > 0 ?
alloc_skiplist_once : 16 * 1024, NULL, false)) != 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->max_level_count = max_level_count;
factory->compare_func = compare_func; factory->compare_func = compare_func;
factory->free_func = free_func; factory->free_func = free_func;
factory->delay_free_seconds = delay_free_seconds;
srand(time(NULL)); srand(time(NULL));
return 0; return 0;
@ -96,7 +127,7 @@ void uniq_skiplist_destroy(UniqSkiplistFactory *factory)
return; return;
} }
fast_mblock_destroy(&factory->skiplist_allocators); fast_mblock_destroy(&factory->skiplist_allocator);
for (i=0; i<factory->max_level_count; i++) { for (i=0; i<factory->max_level_count; i++) {
fast_mblock_destroy(factory->node_allocators + i); fast_mblock_destroy(factory->node_allocators + i);
@ -131,7 +162,7 @@ UniqSkiplist *uniq_skiplist_new(UniqSkiplistFactory *factory,
} }
sl = (UniqSkiplist *)fast_mblock_alloc_object( sl = (UniqSkiplist *)fast_mblock_alloc_object(
&factory->skiplist_allocators); &factory->skiplist_allocator);
sl->element_count = 0; sl->element_count = 0;
sl->factory = factory; sl->factory = factory;
@ -159,16 +190,57 @@ UniqSkiplist *uniq_skiplist_new(UniqSkiplistFactory *factory,
return sl; 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) void uniq_skiplist_free(UniqSkiplist *sl)
{ {
UniqSkiplistNode *node; volatile UniqSkiplistNode *node;
UniqSkiplistNode *deleted; volatile UniqSkiplistNode *deleted;
if (sl->element_count == 0) if (sl->top == NULL) {
{
return; 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]; node = sl->top->links[0];
if (sl->factory->free_func != NULL) { if (sl->factory->free_func != NULL) {
while (node != sl->tail) { while (node != sl->tail) {
@ -176,18 +248,21 @@ void uniq_skiplist_free(UniqSkiplist *sl)
node = node->links[0]; node = node->links[0];
sl->factory->free_func(deleted->data); sl->factory->free_func(deleted->data);
fast_mblock_free_object(sl->factory->node_allocators + fast_mblock_free_object(sl->factory->node_allocators +
deleted->level_index, deleted); deleted->level_index, (void *)deleted);
} }
} else { } else {
while (node != sl->tail) { while (node != sl->tail) {
deleted = node; deleted = node;
node = node->links[0]; node = node->links[0];
fast_mblock_free_object(sl->factory->node_allocators + 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; sl->element_count = 0;
fast_mblock_free_object(&sl->factory->skiplist_allocator, sl);
} }
static inline int uniq_skiplist_get_level_index(UniqSkiplist *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 level_index;
int cmp; int cmp;
UniqSkiplistNode *node; UniqSkiplistNode *node;
UniqSkiplistNode *previous; volatile UniqSkiplistNode *previous;
UniqSkiplistNode *tmp_previous[SKIPLIST_MAX_LEVEL_COUNT]; volatile UniqSkiplistNode *tmp_previous[SKIPLIST_MAX_LEVEL_COUNT];
level_index = uniq_skiplist_get_level_index(sl); level_index = uniq_skiplist_get_level_index(sl);
previous = sl->top; previous = sl->top;
@ -253,12 +328,19 @@ int uniq_skiplist_insert(UniqSkiplist *sl, void *data)
node->level_index = level_index; node->level_index = level_index;
node->data = data; node->data = data;
__sync_synchronize();
//thread safe for one write with many read model //thread safe for one write with many read model
for (i=0; i<=level_index; i++) { for (i=0; i<=level_index; i++) {
node->links[i] = tmp_previous[i]->links[i]; node->links[i] = tmp_previous[i]->links[i];
tmp_previous[i]->links[i] = node; 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; return 0;
} }
@ -267,7 +349,7 @@ static UniqSkiplistNode *uniq_skiplist_get_equal_previous(UniqSkiplist *sl,
{ {
int i; int i;
int cmp; int cmp;
UniqSkiplistNode *previous; volatile UniqSkiplistNode *previous;
previous = sl->top; previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) { 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) { else if (cmp == 0) {
*level_index = i; *level_index = i;
return previous; return (UniqSkiplistNode *)previous;
} }
previous = previous->links[i]; previous = previous->links[i];
@ -293,7 +375,7 @@ static UniqSkiplistNode *uniq_skiplist_get_first_larger_or_equal(
{ {
int i; int i;
int cmp; int cmp;
UniqSkiplistNode *previous; volatile UniqSkiplistNode *previous;
previous = sl->top; previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) { for (i=sl->top_level_index; i>=0; i--) {
@ -303,14 +385,14 @@ static UniqSkiplistNode *uniq_skiplist_get_first_larger_or_equal(
break; break;
} }
else if (cmp == 0) { else if (cmp == 0) {
return previous->links[i]; return (UniqSkiplistNode *)previous->links[i];
} }
previous = previous->links[i]; previous = previous->links[i];
} }
} }
return previous->links[0]; return (UniqSkiplistNode *)previous->links[0];
} }
static UniqSkiplistNode *uniq_skiplist_get_first_larger( static UniqSkiplistNode *uniq_skiplist_get_first_larger(
@ -318,7 +400,7 @@ static UniqSkiplistNode *uniq_skiplist_get_first_larger(
{ {
int i; int i;
int cmp; int cmp;
UniqSkiplistNode *previous; volatile UniqSkiplistNode *previous;
previous = sl->top; previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) { for (i=sl->top_level_index; i>=0; i--) {
@ -328,22 +410,22 @@ static UniqSkiplistNode *uniq_skiplist_get_first_larger(
break; break;
} }
else if (cmp == 0) { else if (cmp == 0) {
return previous->links[i]->links[0]; return (UniqSkiplistNode *)previous->links[i]->links[0];
} }
previous = previous->links[i]; previous = previous->links[i];
} }
} }
return previous->links[0]; return (UniqSkiplistNode *)previous->links[0];
} }
int uniq_skiplist_delete(UniqSkiplist *sl, void *data) int uniq_skiplist_delete(UniqSkiplist *sl, void *data)
{ {
int i; int i;
int level_index; int level_index;
UniqSkiplistNode *previous; volatile UniqSkiplistNode *previous;
UniqSkiplistNode *deleted; volatile UniqSkiplistNode *deleted;
previous = uniq_skiplist_get_equal_previous(sl, data, &level_index); previous = uniq_skiplist_get_equal_previous(sl, data, &level_index);
if (previous == NULL) { if (previous == NULL) {
@ -365,7 +447,9 @@ int uniq_skiplist_delete(UniqSkiplist *sl, void *data)
if (sl->factory->free_func != NULL) { if (sl->factory->free_func != NULL) {
sl->factory->free_func(deleted->data); 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; return 0;
} }

View File

@ -22,15 +22,16 @@ typedef struct uniq_skiplist_node
{ {
void *data; void *data;
int level_index; int level_index;
struct uniq_skiplist_node *links[0]; volatile struct uniq_skiplist_node *links[0];
} UniqSkiplistNode; } UniqSkiplistNode;
typedef struct uniq_skiplist_factory typedef struct uniq_skiplist_factory
{ {
int max_level_count; int max_level_count;
int delay_free_seconds;
skiplist_compare_func compare_func; skiplist_compare_func compare_func;
skiplist_free_func free_func; skiplist_free_func free_func;
struct fast_mblock_man skiplist_allocators; struct fast_mblock_man skiplist_allocator;
struct fast_mblock_man *node_allocators; struct fast_mblock_man *node_allocators;
} UniqSkiplistFactory; } UniqSkiplistFactory;
@ -44,8 +45,8 @@ typedef struct uniq_skiplist
} UniqSkiplist; } UniqSkiplist;
typedef struct uniq_skiplist_iterator { typedef struct uniq_skiplist_iterator {
UniqSkiplistNode *current; volatile UniqSkiplistNode *current;
UniqSkiplistNode *tail; volatile UniqSkiplistNode *tail;
} UniqSkiplistIterator; } UniqSkiplistIterator;
#ifdef __cplusplus #ifdef __cplusplus
@ -60,7 +61,7 @@ extern "C" {
int uniq_skiplist_init_ex(UniqSkiplistFactory *factory, int uniq_skiplist_init_ex(UniqSkiplistFactory *factory,
const int max_level_count, skiplist_compare_func compare_func, const int max_level_count, skiplist_compare_func compare_func,
skiplist_free_func free_func, const int alloc_skiplist_once, 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); void uniq_skiplist_destroy(UniqSkiplistFactory *factory);