diff --git a/src/Makefile.in b/src/Makefile.in index fa213f8..fa4d65b 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -10,7 +10,7 @@ FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \ avl_tree.lo ioevent.lo ioevent_loop.lo fast_task_queue.lo \ fast_timer.lo process_ctrl.lo fast_mblock.lo \ connection_pool.lo fast_mpool.lo fast_allocator.lo \ - fast_buffer.lo skiplist.lo + fast_buffer.lo skiplist.lo multi_skiplist.lo FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \ logger.o sockopt.o base64.o sched_thread.o \ @@ -18,7 +18,7 @@ FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \ avl_tree.o ioevent.o ioevent_loop.o fast_task_queue.o \ fast_timer.o process_ctrl.o fast_mblock.o \ connection_pool.o fast_mpool.o fast_allocator.o \ - fast_buffer.o skiplist.o + fast_buffer.o skiplist.o multi_skiplist.o HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \ shared_func.h pthread_func.h ini_file_reader.h _os_define.h \ @@ -26,7 +26,7 @@ HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \ avl_tree.h ioevent.h ioevent_loop.h fast_task_queue.h \ fast_timer.h process_ctrl.h fast_mblock.h \ connection_pool.h fast_mpool.h fast_allocator.h \ - fast_buffer.h skiplist.h + fast_buffer.h skiplist.h multi_skiplist.h ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS) diff --git a/src/multi_skiplist.c b/src/multi_skiplist.c new file mode 100644 index 0000000..5201960 --- /dev/null +++ b/src/multi_skiplist.c @@ -0,0 +1,291 @@ +/** +* Copyright (C) 2015 Happy Fish / YuQing +* +* libfastcommon may be copied only under the terms of the GNU General +* Public License V3, which may be found in the FastDFS source kit. +* Please visit the FastDFS Home Page http://www.csource.org/ for more detail. +**/ + +//multi_skiplist.c + +#include +#include +#include +#include +#include +#include +#include "logger.h" +#include "multi_skiplist.h" + +int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count, + multi_skiplist_compare_func compare_func, const int min_alloc_elements_once) +{ + int bytes; + int element_size; + int i; + int alloc_elements_once; + int result; + struct fast_mblock_man *top_mblock; + + if (level_count <= 0) { + logError("file: "__FILE__", line: %d, " + "invalid level count: %d", + __LINE__, level_count); + return EINVAL; + } + + if (level_count > 20) { + logError("file: "__FILE__", line: %d, " + "level count: %d is too large", + __LINE__, level_count); + return E2BIG; + } + + bytes = sizeof(struct fast_mblock_man) * level_count; + sl->mblocks = (struct fast_mblock_man *)malloc(bytes); + if (sl->mblocks == NULL) { + logError("file: "__FILE__", line: %d, " + "malloc %d bytes fail, errno: %d, error info: %s", + __LINE__, bytes, errno, STRERROR(errno)); + return errno != 0 ? errno : ENOMEM; + } + memset(sl->mblocks, 0, bytes); + + 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(MultiSkiplistNode) + sizeof(MultiSkiplistNode *) * (i + 1); + if ((result=fast_mblock_init_ex(sl->mblocks + i, + element_size, alloc_elements_once, NULL, false)) != 0) + { + return result; + } + if (alloc_elements_once < 1024 * 1024) { + alloc_elements_once *= 2; + } + } + + sl->top_level_index = level_count - 1; + top_mblock = sl->mblocks + sl->top_level_index; + sl->top = (MultiSkiplistNode *)fast_mblock_alloc_object(top_mblock); + if (sl->top == NULL) { + return ENOMEM; + } + memset(sl->top, 0, top_mblock->info.element_size); + + sl->tail = (MultiSkiplistNode *)fast_mblock_alloc_object(sl->mblocks + 0); + if (sl->tail == NULL) { + return ENOMEM; + } + memset(sl->tail, 0, sl->mblocks[0].info.element_size); + + if ((result=fast_mblock_init_ex(&sl->data_mblock, + sizeof(MultiSkiplistData), alloc_elements_once, + NULL, false)) != 0) + { + return result; + } + + for (i=0; itop->links[i] = sl->tail; + } + + sl->level_count = level_count; + sl->compare_func = compare_func; + + srand(time(NULL)); + return 0; +} + +void multi_skiplist_destroy(MultiSkiplist *sl) +{ + int i; + + if (sl->mblocks == NULL) { + return; + } + + for (i=0; ilevel_count; i++) { + fast_mblock_destroy(sl->mblocks + i); + } + fast_mblock_destroy(&sl->data_mblock); + + free(sl->mblocks); + sl->mblocks = NULL; +} + +static MultiSkiplistNode *multi_skiplist_get_previous(MultiSkiplist *sl, void *data, + int *level_index) +{ + int i; + int cmp; + MultiSkiplistNode *previous; + MultiSkiplistNode *found; + + found = NULL; + previous = sl->top; + for (i=sl->top_level_index; i>=0; i--) { + while (previous->links[i] != sl->tail) { + cmp = sl->compare_func(data, previous->links[i]->head->data); + if (cmp < 0) { + break; + } + else if (cmp == 0) { + found = previous; + *level_index = i; + goto DONE; + } + + previous = previous->links[i]; + } + } + +DONE: + return found; +} + + +static inline int multi_skiplist_get_level_index(MultiSkiplist *sl) +{ + int i; + + for (i=0; itop_level_index; i++) { + if (rand() < RAND_MAX / 2) { + break; + } + } + + return i; +} + +int multi_skiplist_insert(MultiSkiplist *sl, void *data) +{ + int i; + int level_index; + MultiSkiplistData *dataNode; + MultiSkiplistNode *node; + MultiSkiplistNode *previous; + MultiSkiplistNode *current = NULL; + + dataNode = (MultiSkiplistData *)fast_mblock_alloc_object(&sl->data_mblock); + if (dataNode == NULL) { + return ENOMEM; + } + dataNode->data = data; + dataNode->next = NULL; + + previous = multi_skiplist_get_previous(sl, data, &level_index); + if (previous != NULL) { + node = previous->links[level_index]; + node->tail->next = dataNode; + node->tail = dataNode; + return 0; + } + + level_index = multi_skiplist_get_level_index(sl); + node = (MultiSkiplistNode *)fast_mblock_alloc_object(sl->mblocks + level_index); + if (node == NULL) { + fast_mblock_free_object(&sl->data_mblock, dataNode); + return ENOMEM; + } + + previous = sl->top; + for (i=sl->top_level_index; i>level_index; i--) { + while (previous->links[i] != sl->tail && sl->compare_func(data, + previous->links[i]->head->data) > 0) + { + previous = previous->links[i]; + } + } + + while (i >= 0) { + while (previous->links[i] != sl->tail && sl->compare_func(data, + previous->links[i]->head->data) > 0) + { + previous = previous->links[i]; + } + + current = previous->links[i]; + previous->links[i] = node; + node->links[i] = current; + + i--; + } + + node->head = dataNode; + node->tail = dataNode; + return 0; +} + +int multi_skiplist_do_delete(MultiSkiplist *sl, void *data, + const bool delete_all) +{ + int i; + int level_index; + MultiSkiplistNode *previous; + MultiSkiplistNode *deleted; + MultiSkiplistData *dataNode; + MultiSkiplistData *dataCurrent; + + previous = multi_skiplist_get_previous(sl, data, &level_index); + if (previous == NULL) { + return ENOENT; + } + + deleted = previous->links[level_index]; + if (delete_all) { + dataCurrent = deleted->head; + while (dataCurrent != NULL) { + dataNode = dataCurrent; + dataCurrent = dataCurrent->next; + fast_mblock_free_object(&sl->data_mblock, dataNode); + } + } + else { + dataNode = deleted->head; + deleted->head = dataNode->next; + if (deleted->head != NULL) { + fast_mblock_free_object(&sl->data_mblock, dataNode); + return 0; + } + } + + for (i=level_index; i>=0; i--) { + while (previous->links[i] != sl->tail && sl->compare_func(data, + previous->links[i]->head->data) > 0) + { + previous = previous->links[i]; + } + + previous->links[i] = previous->links[i]->links[i]; + } + + fast_mblock_free_object(sl->mblocks + level_index, deleted); + return 0; +} + +int multi_skiplist_delete(MultiSkiplist *sl, void *data) +{ + return multi_skiplist_do_delete(sl, data, false); +} + +int multi_skiplist_delete_all(MultiSkiplist *sl, void *data) +{ + return multi_skiplist_do_delete(sl, data, true); +} + +void *multi_skiplist_find(MultiSkiplist *sl, void *data) +{ + int level_index; + MultiSkiplistNode *previous; + + previous = multi_skiplist_get_previous(sl, data, &level_index); + return (previous != NULL) ? previous->links[level_index]->head->data : NULL; +} + diff --git a/src/multi_skiplist.h b/src/multi_skiplist.h new file mode 100644 index 0000000..0c7d6dd --- /dev/null +++ b/src/multi_skiplist.h @@ -0,0 +1,108 @@ +/** +* Copyright (C) 2015 Happy Fish / YuQing +* +* libfastcommon may be copied only under the terms of the GNU General +* Public License V3, which may be found in the FastDFS source kit. +* Please visit the FastDFS Home Page http://www.csource.org/ for more detail. +**/ + +//multi_skiplist.h, support stable sort :) +#ifndef _MULTI_SKIPLIST_H +#define _MULTI_SKIPLIST_H + +#include +#include +#include +#include "common_define.h" +#include "fast_mblock.h" + +typedef int (*multi_skiplist_compare_func)(const void *p1, const void *p2); + +typedef struct multi_skiplist_data +{ + void *data; + struct multi_skiplist_data *next; +} MultiSkiplistData; + +typedef struct multi_skiplist_node +{ + MultiSkiplistData *head; + MultiSkiplistData *tail; + struct multi_skiplist_node *links[0]; +} MultiSkiplistNode; + +typedef struct multi_skiplist +{ + int level_count; + int top_level_index; + multi_skiplist_compare_func compare_func; + struct fast_mblock_man data_mblock; //data node allocators + struct fast_mblock_man *mblocks; //node allocators + MultiSkiplistNode *top; //the top node + MultiSkiplistNode *tail; //the tail node for terminate +} MultiSkiplist; + +typedef struct multi_skiplist_iterator { + MultiSkiplist *sl; + struct { + MultiSkiplistNode *node; + MultiSkiplistData *data; + } current; +} MultiSkiplistIterator; + +#ifdef __cplusplus +extern "C" { +#endif + +#define SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE 128 + +#define multi_skiplist_init(sl, level_count, compare_func) \ + multi_skiplist_init_ex(sl, level_count, compare_func, \ + SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE) + +int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count, + multi_skiplist_compare_func compare_func, const int min_alloc_elements_once); + +void multi_skiplist_destroy(MultiSkiplist *sl); + +int multi_skiplist_insert(MultiSkiplist *sl, void *data); +int multi_skiplist_delete(MultiSkiplist *sl, void *data); +int multi_skiplist_delete_all(MultiSkiplist *sl, void *data); +void *multi_skiplist_find(MultiSkiplist *sl, void *data); + +static inline void multi_skiplist_iterator(MultiSkiplist *sl, MultiSkiplistIterator *iterator) +{ + iterator->sl = sl; + iterator->current.node = sl->top->links[0]; + if (iterator->current.node != iterator->sl->tail) { + iterator->current.data = iterator->current.node->head; + } + else { + iterator->current.data = NULL; + } +} + +static inline void *multi_skiplist_next(MultiSkiplistIterator *iterator) +{ + void *data; + + if (iterator->current.data == NULL) { + if (iterator->current.node == iterator->sl->tail) { + return NULL; + } + + iterator->current.node = iterator->current.node->links[0]; + iterator->current.data = iterator->current.node->head; + } + + data = iterator->current.data->data; + iterator->current.data = iterator->current.data->next; + return data; +} + +#ifdef __cplusplus +} +#endif + +#endif +