uniq_skiplist support bidirection
parent
4e53bd3e2d
commit
759fd117d8
|
|
@ -13,7 +13,7 @@ int common_blocked_queue_init_ex(struct common_blocked_queue *queue,
|
|||
{
|
||||
int result;
|
||||
|
||||
if ((result=init_pthread_lock(&(queue->lock))) != 0)
|
||||
if ((result=init_pthread_lock(&queue->lock)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, "
|
||||
"init_pthread_lock fail, errno: %d, error info: %s",
|
||||
|
|
@ -21,8 +21,7 @@ int common_blocked_queue_init_ex(struct common_blocked_queue *queue,
|
|||
return result;
|
||||
}
|
||||
|
||||
result = pthread_cond_init(&(queue->cond), NULL);
|
||||
if (result != 0)
|
||||
if ((result=pthread_cond_init(&queue->cond, NULL)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, "
|
||||
"pthread_cond_init fail, "
|
||||
|
|
|
|||
|
|
@ -3092,3 +3092,13 @@ int fc_init_buffer(BufferInfo *buffer, const int buffer_size)
|
|||
buffer->length = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fc_free_buffer(BufferInfo *buffer)
|
||||
{
|
||||
if (buffer->buff != NULL)
|
||||
{
|
||||
free(buffer->buff);
|
||||
buffer->buff = NULL;
|
||||
buffer->alloc_size = buffer->length = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -945,6 +945,13 @@ int fc_ceil_prime(const int n);
|
|||
*/
|
||||
int fc_init_buffer(BufferInfo *buffer, const int buffer_size);
|
||||
|
||||
/** free buffer
|
||||
* parameters:
|
||||
* buffer: the buffer to free
|
||||
* return: none
|
||||
*/
|
||||
void fc_free_buffer(BufferInfo *buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ void set_rand_numbers(const int multiple)
|
|||
}
|
||||
|
||||
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;
|
||||
index1 = (LAST_INDEX * (int64_t)rand()) / (int64_t)RAND_MAX;
|
||||
index2 = (LAST_INDEX * (int64_t)rand()) / (int64_t)RAND_MAX;
|
||||
if (index1 == index2) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -140,6 +140,7 @@ static void test_find_range()
|
|||
int n_end;
|
||||
int result;
|
||||
int i;
|
||||
int count;
|
||||
int *value;
|
||||
UniqSkiplistIterator iterator;
|
||||
|
||||
|
|
@ -157,15 +158,63 @@ static void test_find_range()
|
|||
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
|
||||
assert(result == EINVAL);
|
||||
|
||||
n_start = -100;
|
||||
n_end = -1;
|
||||
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
|
||||
assert(result == ENOENT);
|
||||
|
||||
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;
|
||||
n_end = 0;
|
||||
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
|
||||
assert(result == ENOENT);
|
||||
|
||||
n_start = 2 * COUNT;
|
||||
n_end = 2 * COUNT;
|
||||
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
|
||||
assert(result == ENOENT);
|
||||
count = uniq_skiplist_iterator_count(&iterator);
|
||||
assert(count == 0);
|
||||
|
||||
n_start = 2 * COUNT;
|
||||
n_end = 4 * COUNT;
|
||||
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
|
||||
assert(result == ENOENT);
|
||||
count = uniq_skiplist_iterator_count(&iterator);
|
||||
assert(count == 0);
|
||||
|
||||
n_start = -100;
|
||||
n_end = 2;
|
||||
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
|
||||
assert(result == 0);
|
||||
count = uniq_skiplist_iterator_count(&iterator);
|
||||
if (n_end % 2 == 0) {
|
||||
assert(count == n_end / 2);
|
||||
} else {
|
||||
assert(count == n_end / 2 + 1);
|
||||
}
|
||||
|
||||
n_start = 0;
|
||||
n_end = COUNT;
|
||||
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
|
||||
count = uniq_skiplist_iterator_count(&iterator);
|
||||
assert(count == (n_end - n_start) / 2);
|
||||
|
||||
n_start = COUNT;
|
||||
n_end = 2 * COUNT;
|
||||
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
|
||||
count = uniq_skiplist_iterator_count(&iterator);
|
||||
assert(count == (n_end - n_start) / 2);
|
||||
|
||||
n_start = 100;
|
||||
n_end = 152;
|
||||
result = uniq_skiplist_find_range(sl, &n_start, &n_end, &iterator);
|
||||
count = uniq_skiplist_iterator_count(&iterator);
|
||||
assert(count == (n_end - n_start) / 2);
|
||||
|
||||
i = 0;
|
||||
while ((value=(int *)uniq_skiplist_next(&iterator)) != NULL) {
|
||||
|
|
@ -175,6 +224,23 @@ static void test_find_range()
|
|||
printf("count: %d\n\n", i);
|
||||
}
|
||||
|
||||
static void test_reverse_iterator()
|
||||
{
|
||||
UniqSkiplistNode *node;
|
||||
int v;
|
||||
int *value;
|
||||
|
||||
v = 21;
|
||||
node = uniq_skiplist_find_ge_node(sl, &v);
|
||||
if (node != NULL) {
|
||||
while (node != sl->top) {
|
||||
value = (int *)node->data;
|
||||
printf("value: %d\n", *value);
|
||||
node = (UniqSkiplistNode *)LEVEL0_DOUBLE_CHAIN_PREV_LINK(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int result;
|
||||
|
|
@ -189,7 +255,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
fast_mblock_manager_init();
|
||||
result = uniq_skiplist_init_ex(&factory, LEVEL_COUNT, compare_func,
|
||||
free_test_func, 0, MIN_ALLOC_ONCE, 0);
|
||||
free_test_func, 0, MIN_ALLOC_ONCE, 0, true);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
|
@ -209,6 +275,8 @@ int main(int argc, char *argv[])
|
|||
|
||||
test_find_range();
|
||||
|
||||
test_reverse_iterator();
|
||||
|
||||
test_delete();
|
||||
printf("\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "logger.h"
|
||||
#include "uniq_skiplist.h"
|
||||
|
||||
|
|
@ -46,12 +45,14 @@ static void init_best_element_counts()
|
|||
int uniq_skiplist_init_ex(UniqSkiplistFactory *factory,
|
||||
const int max_level_count, skiplist_compare_func compare_func,
|
||||
uniq_skiplist_free_func free_func, const int alloc_skiplist_once,
|
||||
const int min_alloc_elements_once, const int delay_free_seconds)
|
||||
const int min_alloc_elements_once, const int delay_free_seconds,
|
||||
const bool bidirection)
|
||||
{
|
||||
char name[64];
|
||||
int bytes;
|
||||
int element_size;
|
||||
int i;
|
||||
int extra_links_count;
|
||||
int alloc_elements_once;
|
||||
int result;
|
||||
|
||||
|
|
@ -91,10 +92,11 @@ int uniq_skiplist_init_ex(UniqSkiplistFactory *factory,
|
|||
alloc_elements_once = 1024;
|
||||
}
|
||||
|
||||
extra_links_count = bidirection ? 1 : 0;
|
||||
for (i=max_level_count-1; i>=0; i--) {
|
||||
sprintf(name, "sl-level%02d", i);
|
||||
element_size = sizeof(UniqSkiplistNode) +
|
||||
sizeof(UniqSkiplistNode *) * (i + 1);
|
||||
sizeof(UniqSkiplistNode *) * (i + 1 + extra_links_count);
|
||||
if ((result=fast_mblock_init_ex1(factory->node_allocators + i,
|
||||
name, element_size, alloc_elements_once, NULL, NULL, false)) != 0)
|
||||
{
|
||||
|
|
@ -120,6 +122,7 @@ int uniq_skiplist_init_ex(UniqSkiplistFactory *factory,
|
|||
}
|
||||
memset(factory->tail, 0, factory->node_allocators[0].info.element_size);
|
||||
|
||||
factory->bidirection = bidirection;
|
||||
factory->max_level_count = max_level_count;
|
||||
factory->compare_func = compare_func;
|
||||
factory->free_func = free_func;
|
||||
|
|
@ -186,6 +189,10 @@ UniqSkiplist *uniq_skiplist_new(UniqSkiplistFactory *factory,
|
|||
return NULL;
|
||||
}
|
||||
memset(sl->top, 0, top_mblock->info.element_size);
|
||||
sl->top->level_index = sl->top_level_index;
|
||||
if (sl->factory->bidirection) {
|
||||
LEVEL0_DOUBLE_CHAIN_TAIL(sl) = sl->top;
|
||||
}
|
||||
|
||||
for (i=0; i<level_count; i++) {
|
||||
sl->top->links[i] = sl->factory->tail;
|
||||
|
|
@ -214,6 +221,7 @@ static int uniq_skiplist_grow(UniqSkiplist *sl)
|
|||
return ENOMEM;
|
||||
}
|
||||
memset(top, 0, top_mblock->info.element_size);
|
||||
top->level_index = top_level_index;
|
||||
|
||||
top->links[top_level_index] = sl->factory->tail;
|
||||
for (i=0; i<=sl->top_level_index; i++) {
|
||||
|
|
@ -227,6 +235,11 @@ static int uniq_skiplist_grow(UniqSkiplist *sl)
|
|||
compile_barrier();
|
||||
sl->top_level_index = top_level_index;
|
||||
|
||||
if (sl->factory->bidirection) {
|
||||
LEVEL0_DOUBLE_CHAIN_TAIL(sl) =
|
||||
LEVEL0_DOUBLE_CHAIN_PREV_LINK(old_top);
|
||||
}
|
||||
|
||||
UNIQ_SKIPLIST_FREE_MBLOCK_OBJECT(sl, old_top_level_index, old_top);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -332,6 +345,14 @@ int uniq_skiplist_insert(UniqSkiplist *sl, void *data)
|
|||
compile_barrier();
|
||||
|
||||
//thread safe for one write with many read model
|
||||
if (sl->factory->bidirection) {
|
||||
LEVEL0_DOUBLE_CHAIN_PREV_LINK(node) = tmp_previous[0];
|
||||
if (tmp_previous[0]->links[0] == sl->factory->tail) {
|
||||
LEVEL0_DOUBLE_CHAIN_TAIL(sl) = node;
|
||||
} else {
|
||||
LEVEL0_DOUBLE_CHAIN_PREV_LINK(tmp_previous[0]->links[0]) = node;
|
||||
}
|
||||
}
|
||||
for (i=0; i<=level_index; i++) {
|
||||
node->links[i] = tmp_previous[i]->links[i];
|
||||
tmp_previous[i]->links[i] = node;
|
||||
|
|
@ -441,10 +462,19 @@ int uniq_skiplist_delete(UniqSkiplist *sl, void *data)
|
|||
previous = previous->links[i];
|
||||
}
|
||||
|
||||
assert(previous->links[i] == deleted);
|
||||
previous->links[i] = previous->links[i]->links[i];
|
||||
}
|
||||
|
||||
if (sl->factory->bidirection) {
|
||||
if (deleted->links[0] == sl->factory->tail) {
|
||||
LEVEL0_DOUBLE_CHAIN_TAIL(sl) =
|
||||
LEVEL0_DOUBLE_CHAIN_PREV_LINK(deleted);
|
||||
} else {
|
||||
LEVEL0_DOUBLE_CHAIN_PREV_LINK(deleted->links[0]) =
|
||||
LEVEL0_DOUBLE_CHAIN_PREV_LINK(deleted);
|
||||
}
|
||||
}
|
||||
|
||||
if (sl->factory->free_func != NULL) {
|
||||
sl->factory->free_func(deleted->data,
|
||||
sl->factory->delay_free_seconds);
|
||||
|
|
@ -482,7 +512,7 @@ int uniq_skiplist_find_all(UniqSkiplist *sl, void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *uniq_skiplist_find_ge(UniqSkiplist *sl, void *data)
|
||||
UniqSkiplistNode *uniq_skiplist_find_ge_node(UniqSkiplist *sl, void *data)
|
||||
{
|
||||
UniqSkiplistNode *node;
|
||||
node = uniq_skiplist_get_first_larger_or_equal(sl, data);
|
||||
|
|
@ -490,7 +520,7 @@ void *uniq_skiplist_find_ge(UniqSkiplist *sl, void *data)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return node->data;
|
||||
return node;
|
||||
}
|
||||
|
||||
int uniq_skiplist_find_range(UniqSkiplist *sl, void *start_data,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ typedef struct uniq_skiplist_factory
|
|||
{
|
||||
int max_level_count;
|
||||
int delay_free_seconds;
|
||||
bool bidirection; //if need reverse iteration for level 0
|
||||
skiplist_compare_func compare_func;
|
||||
uniq_skiplist_free_func free_func;
|
||||
UniqSkiplistNode *tail; //the tail node for interator
|
||||
|
|
@ -60,12 +61,13 @@ extern "C" {
|
|||
#define uniq_skiplist_init(factory, max_level_count, compare_func, free_func) \
|
||||
uniq_skiplist_init_ex(factory, max_level_count, \
|
||||
compare_func, free_func, 64 * 1024, \
|
||||
SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE, 0)
|
||||
SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE, 0, false)
|
||||
|
||||
int uniq_skiplist_init_ex(UniqSkiplistFactory *factory,
|
||||
const int max_level_count, skiplist_compare_func compare_func,
|
||||
uniq_skiplist_free_func free_func, const int alloc_skiplist_once,
|
||||
const int min_alloc_elements_once, const int delay_free_seconds);
|
||||
const int min_alloc_elements_once, const int delay_free_seconds,
|
||||
const bool bidirection);
|
||||
|
||||
void uniq_skiplist_destroy(UniqSkiplistFactory *factory);
|
||||
|
||||
|
|
@ -81,7 +83,19 @@ int uniq_skiplist_find_all(UniqSkiplist *sl, void *data,
|
|||
UniqSkiplistIterator *iterator);
|
||||
int uniq_skiplist_find_range(UniqSkiplist *sl, void *start_data,
|
||||
void *end_data, UniqSkiplistIterator *iterator);
|
||||
void *uniq_skiplist_find_ge(UniqSkiplist *sl, void *data);
|
||||
|
||||
UniqSkiplistNode *uniq_skiplist_find_ge_node(UniqSkiplist *sl, void *data);
|
||||
|
||||
static inline void *uniq_skiplist_find_ge(UniqSkiplist *sl, void *data)
|
||||
{
|
||||
UniqSkiplistNode *node;
|
||||
node = uniq_skiplist_find_ge_node(sl, data);
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return node->data;
|
||||
}
|
||||
|
||||
static inline void uniq_skiplist_iterator(UniqSkiplist *sl,
|
||||
UniqSkiplistIterator *iterator)
|
||||
|
|
@ -103,11 +117,38 @@ static inline void *uniq_skiplist_next(UniqSkiplistIterator *iterator)
|
|||
return data;
|
||||
}
|
||||
|
||||
static inline int uniq_skiplist_iterator_count(UniqSkiplistIterator *iterator)
|
||||
{
|
||||
volatile UniqSkiplistNode *current;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
current = iterator->current;
|
||||
while (current != iterator->tail) {
|
||||
++count;
|
||||
current = current->links[0];
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline void *uniq_skiplist_get_first(UniqSkiplist *sl)
|
||||
{
|
||||
if (sl->top->links[0] != sl->factory->tail) {
|
||||
return sl->top->links[0]->data;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool uniq_skiplist_empty(UniqSkiplist *sl)
|
||||
{
|
||||
return sl->top->links[0] == sl->factory->tail;
|
||||
}
|
||||
|
||||
#define LEVEL0_DOUBLE_CHAIN_PREV_LINK(node) node->links[node->level_index + 1]
|
||||
#define LEVEL0_DOUBLE_CHAIN_TAIL(sl) LEVEL0_DOUBLE_CHAIN_PREV_LINK(sl->top)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue