add src/tests/test_uniq_skiplist.c
parent
91e0124ae5
commit
1c7069068b
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue