skiplist support stable sort

pull/5/head
yuqing 2015-12-25 19:02:36 +08:00
parent 159d69983b
commit a6ef605c6e
4 changed files with 124 additions and 20 deletions

View File

@ -1,7 +1,7 @@
Version 1.24 2015-12-25 Version 1.24 2015-12-25
* php extension compiled on PHP 7 * php extension compiled on PHP 7
* add skiplist * add skiplist which support stable sort
* make.sh: use sed to replace perl * make.sh: use sed to replace perl
Version 1.23 2015-11-16 Version 1.23 2015-11-16

View File

@ -18,11 +18,12 @@
#include "skiplist.h" #include "skiplist.h"
int skiplist_init_ex(Skiplist *sl, const int level_count, int skiplist_init_ex(Skiplist *sl, const int level_count,
skiplist_compare_func compare_func, const int alloc_elements_once) skiplist_compare_func compare_func, const int min_alloc_elements_once)
{ {
int bytes; int bytes;
int element_size; int element_size;
int i; int i;
int alloc_elements_once;
int result; int result;
struct fast_mblock_man *top_mblock; struct fast_mblock_man *top_mblock;
@ -33,7 +34,7 @@ int skiplist_init_ex(Skiplist *sl, const int level_count,
return EINVAL; return EINVAL;
} }
if (level_count > 32) { if (level_count > 20) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"level count: %d is too large", "level count: %d is too large",
__LINE__, level_count); __LINE__, level_count);
@ -50,13 +51,24 @@ int skiplist_init_ex(Skiplist *sl, const int level_count,
} }
memset(sl->mblocks, 0, bytes); memset(sl->mblocks, 0, bytes);
for (i=0; i<level_count; i++) { alloc_elements_once = min_alloc_elements_once;
if (alloc_elements_once <= 0) {
alloc_elements_once = SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE;
}
else if (alloc_elements_once > 1024) {
alloc_elements_once = 1024;
}
for (i=level_count-1; i>=0; i--) {
element_size = sizeof(SkiplistNode) + sizeof(SkiplistNode *) * (i + 1); element_size = sizeof(SkiplistNode) + sizeof(SkiplistNode *) * (i + 1);
if ((result=fast_mblock_init_ex(sl->mblocks + i, if ((result=fast_mblock_init_ex(sl->mblocks + i,
element_size, alloc_elements_once, NULL, false)) != 0) element_size, alloc_elements_once, NULL, false)) != 0)
{ {
return result; return result;
} }
if (alloc_elements_once < 1024 * 1024) {
alloc_elements_once *= 2;
}
} }
sl->top_level_index = level_count - 1; sl->top_level_index = level_count - 1;
@ -67,6 +79,17 @@ int skiplist_init_ex(Skiplist *sl, const int level_count,
} }
memset(sl->top, 0, top_mblock->info.element_size); memset(sl->top, 0, top_mblock->info.element_size);
sl->tail = (SkiplistNode *)fast_mblock_alloc_object(sl->mblocks + 0);
if (sl->tail == NULL) {
return ENOMEM;
}
memset(sl->tail, 0, sl->mblocks[0].info.element_size);
sl->tail->prev = sl->top;
for (i=0; i<level_count; i++) {
sl->top->links[i] = sl->tail;
}
sl->level_count = level_count; sl->level_count = level_count;
sl->compare_func = compare_func; sl->compare_func = compare_func;
@ -109,7 +132,7 @@ int skiplist_insert(Skiplist *sl, void *data)
int level_index; int level_index;
SkiplistNode *node; SkiplistNode *node;
SkiplistNode *previous; SkiplistNode *previous;
SkiplistNode *current; SkiplistNode *current = NULL;
level_index = skiplist_get_level_index(sl); level_index = skiplist_get_level_index(sl);
node = (SkiplistNode *)fast_mblock_alloc_object(sl->mblocks + level_index); node = (SkiplistNode *)fast_mblock_alloc_object(sl->mblocks + level_index);
@ -119,16 +142,16 @@ int skiplist_insert(Skiplist *sl, void *data)
previous = sl->top; previous = sl->top;
for (i=sl->top_level_index; i>level_index; i--) { for (i=sl->top_level_index; i>level_index; i--) {
while (previous->links[i] != NULL && sl->compare_func(data, while (previous->links[i] != sl->tail && sl->compare_func(data,
previous->links[i]->data) > 0) previous->links[i]->data) < 0)
{ {
previous = previous->links[i]; previous = previous->links[i];
} }
} }
while (i >= 0) { while (i >= 0) {
while (previous->links[i] != NULL && sl->compare_func(data, while (previous->links[i] != sl->tail && sl->compare_func(data,
previous->links[i]->data) > 0) previous->links[i]->data) < 0)
{ {
previous = previous->links[i]; previous = previous->links[i];
} }
@ -140,6 +163,8 @@ int skiplist_insert(Skiplist *sl, void *data)
i--; i--;
} }
node->prev = previous;
current->prev = node;
node->data = data; node->data = data;
return 0; return 0;
} }
@ -155,9 +180,9 @@ static SkiplistNode *skiplist_get_previous(Skiplist *sl, void *data,
found = NULL; found = NULL;
previous = sl->top; previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) { for (i=sl->top_level_index; i>=0; i--) {
while (previous->links[i] != NULL) { while (previous->links[i] != sl->tail) {
cmp = sl->compare_func(data, previous->links[i]->data); cmp = sl->compare_func(data, previous->links[i]->data);
if (cmp < 0) { if (cmp > 0) {
break; break;
} }
else if (cmp == 0) { else if (cmp == 0) {
@ -188,8 +213,8 @@ int skiplist_delete(Skiplist *sl, void *data)
deleted = previous->links[level_index]; deleted = previous->links[level_index];
for (i=level_index; i>=0; i--) { for (i=level_index; i>=0; i--) {
while (previous->links[i] != NULL && sl->compare_func(data, while (previous->links[i] != sl->tail && sl->compare_func(data,
previous->links[i]->data) > 0) previous->links[i]->data) < 0)
{ {
previous = previous->links[i]; previous = previous->links[i];
} }
@ -198,6 +223,8 @@ int skiplist_delete(Skiplist *sl, void *data)
previous->links[i] = previous->links[i]->links[i]; previous->links[i] = previous->links[i]->links[i];
} }
deleted->links[0]->prev = previous;
fast_mblock_free_object(sl->mblocks + level_index, deleted); fast_mblock_free_object(sl->mblocks + level_index, deleted);
return 0; return 0;
} }

View File

@ -6,7 +6,7 @@
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail. * Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/ **/
//skiplist.h //skiplist.h, support stable sort :)
#ifndef _SKIPLIST_H #ifndef _SKIPLIST_H
#define _SKIPLIST_H #define _SKIPLIST_H
@ -21,7 +21,7 @@ typedef int (*skiplist_compare_func)(const void *p1, const void *p2);
typedef struct skiplist_node typedef struct skiplist_node
{ {
void *data; void *data;
// struct skiplist_node *prev; //for stable sort struct skiplist_node *prev; //for stable sort
struct skiplist_node *links[0]; struct skiplist_node *links[0];
} SkiplistNode; } SkiplistNode;
@ -32,9 +32,11 @@ typedef struct skiplist
skiplist_compare_func compare_func; skiplist_compare_func compare_func;
struct fast_mblock_man *mblocks; //node allocators struct fast_mblock_man *mblocks; //node allocators
SkiplistNode *top; //the top node SkiplistNode *top; //the top node
SkiplistNode *tail; //the tail node for interator
} Skiplist; } Skiplist;
typedef struct skiplist_iterator { typedef struct skiplist_iterator {
Skiplist *sl;
SkiplistNode *current; SkiplistNode *current;
} SkiplistIterator; } SkiplistIterator;
@ -42,11 +44,14 @@ typedef struct skiplist_iterator {
extern "C" { extern "C" {
#endif #endif
#define SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE 128
#define skiplist_init(sl, level_count, compare_func) \ #define skiplist_init(sl, level_count, compare_func) \
skiplist_init_ex(sl, level_count, compare_func, 1024) skiplist_init_ex(sl, level_count, compare_func, \
SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE)
int skiplist_init_ex(Skiplist *sl, const int level_count, int skiplist_init_ex(Skiplist *sl, const int level_count,
skiplist_compare_func compare_func, const int alloc_elements_once); skiplist_compare_func compare_func, const int min_alloc_elements_once);
void skiplist_destroy(Skiplist *sl); void skiplist_destroy(Skiplist *sl);
@ -56,19 +61,20 @@ void *skiplist_find(Skiplist *sl, void *data);
static inline void skiplist_iterator(Skiplist *sl, SkiplistIterator *iterator) static inline void skiplist_iterator(Skiplist *sl, SkiplistIterator *iterator)
{ {
iterator->current = sl->top->links[0]; iterator->sl = sl;
iterator->current = sl->tail->prev;
} }
static inline void *skiplist_next(SkiplistIterator *iterator) static inline void *skiplist_next(SkiplistIterator *iterator)
{ {
void *data; void *data;
if (iterator->current == NULL) { if (iterator->current == iterator->sl->top) {
return NULL; return NULL;
} }
data = iterator->current->data; data = iterator->current->data;
iterator->current = iterator->current->links[0]; iterator->current = iterator->current->prev;
return data; return data;
} }

View File

@ -91,6 +91,72 @@ static void test_delete()
assert(i==0); assert(i==0);
} }
typedef struct record
{
int line;
int key;
} Record;
static int compare_record(const void *p1, const void *p2)
{
return ((Record *)p1)->key - ((Record *)p2)->key;
}
static int test_stable_sort()
{
#define RECORDS 20
int i;
int result;
int index1;
int index2;
Skiplist sl;
SkiplistIterator iterator;
Record records[RECORDS];
Record *record;
void *value;
result = skiplist_init_ex(&sl, 16, compare_record, 128);
if (result != 0) {
return result;
}
for (i=0; i<RECORDS; i++) {
records[i].line = i + 1;
records[i].key = i + 1;
}
for (i=0; i<RECORDS/4; i++) {
index1 = (RECORDS - 1) * (int64_t)rand() / (int64_t)RAND_MAX;
index2 = RECORDS - 1 - index1;
if (index1 != index2) {
records[index1].key = records[index2].key;
}
}
for (i=0; i<RECORDS; i++) {
if ((result=skiplist_insert(&sl, records + i)) != 0) {
return result;
}
}
for (i=0; i<RECORDS; i++) {
value = skiplist_find(&sl, records + i);
assert(value != NULL && ((Record *)value)->key == records[i].key);
}
i = 0;
skiplist_iterator(&sl, &iterator);
while ((value=skiplist_next(&iterator)) != NULL) {
i++;
record = (Record *)value;
printf("%d => #%d\n", record->key, record->line);
}
assert(i==RECORDS);
skiplist_destroy(&sl);
return 0;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int i; int i;
@ -117,6 +183,7 @@ int main(int argc, char *argv[])
numbers[index2] = tmp; numbers[index2] = tmp;
} }
fast_mblock_manager_init();
result = skiplist_init_ex(&sl, 12, compare_func, 128); result = skiplist_init_ex(&sl, 12, compare_func, 128);
if (result != 0) { if (result != 0) {
return result; return result;
@ -125,6 +192,8 @@ int main(int argc, char *argv[])
test_insert(); test_insert();
printf("\n"); printf("\n");
fast_mblock_manager_stat_print(false);
test_delete(); test_delete();
printf("\n"); printf("\n");
@ -135,6 +204,8 @@ int main(int argc, char *argv[])
printf("\n"); printf("\n");
skiplist_destroy(&sl); skiplist_destroy(&sl);
test_stable_sort();
printf("pass OK\n"); printf("pass OK\n");
return 0; return 0;
} }