add skiplist_set.[hc] and skiplist bug fixed
parent
6d9d71005a
commit
fd894d810b
3
HISTORY
3
HISTORY
|
|
@ -1,11 +1,12 @@
|
|||
|
||||
Version 1.38 2018-05-21
|
||||
Version 1.38 2018-05-29
|
||||
* connection_pool.c: set err_no to 0 when success
|
||||
* shared_func.h: add functions float2buff / buff2float, double2buff / buff2double
|
||||
* logger.h: add function log_get_level_caption
|
||||
* add files: common_blocked_queue.[hc]
|
||||
* add files: multi_socket_client.[hc]
|
||||
* ioevent.[hc]: remove care_events in FreeBSD or MacOS
|
||||
* add skiplist_set.[hc] and skiplist bug fixed
|
||||
|
||||
Version 1.37 2018-02-24
|
||||
* ini_file_reader.c function annotations LOCAL_IP_GET support index, such as:
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \
|
|||
fast_buffer.lo multi_skiplist.lo flat_skiplist.lo \
|
||||
system_info.lo fast_blocked_queue.lo id_generator.lo \
|
||||
char_converter.lo char_convert_loader.lo common_blocked_queue.lo \
|
||||
multi_socket_client.lo
|
||||
multi_socket_client.lo skiplist_set.lo
|
||||
|
||||
FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
|
||||
logger.o sockopt.o base64.o sched_thread.o \
|
||||
|
|
@ -25,7 +25,7 @@ FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
|
|||
fast_buffer.o multi_skiplist.o flat_skiplist.o \
|
||||
system_info.o fast_blocked_queue.o id_generator.o \
|
||||
char_converter.o char_convert_loader.o common_blocked_queue.o \
|
||||
multi_socket_client.o
|
||||
multi_socket_client.o skiplist_set.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 \
|
||||
|
|
@ -37,7 +37,7 @@ HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
|
|||
skiplist_common.h system_info.h fast_blocked_queue.h \
|
||||
php7_ext_wrapper.h id_generator.h char_converter.h \
|
||||
char_convert_loader.h common_blocked_queue.h \
|
||||
multi_socket_client.h
|
||||
multi_socket_client.h skiplist_set.h
|
||||
|
||||
ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS)
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,15 @@ int flat_skiplist_init_ex(FlatSkiplist *sl, const int level_count,
|
|||
return E2BIG;
|
||||
}
|
||||
|
||||
bytes = sizeof(FlatSkiplistNode *) * level_count;
|
||||
sl->tmp_previous = (FlatSkiplistNode **)malloc(bytes);
|
||||
if (sl->tmp_previous == 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;
|
||||
}
|
||||
|
||||
bytes = sizeof(struct fast_mblock_man) * level_count;
|
||||
sl->mblocks = (struct fast_mblock_man *)malloc(bytes);
|
||||
if (sl->mblocks == NULL) {
|
||||
|
|
@ -145,13 +154,13 @@ int flat_skiplist_insert(FlatSkiplist *sl, void *data)
|
|||
int level_index;
|
||||
FlatSkiplistNode *node;
|
||||
FlatSkiplistNode *previous;
|
||||
FlatSkiplistNode *current = NULL;
|
||||
|
||||
level_index = flat_skiplist_get_level_index(sl);
|
||||
node = (FlatSkiplistNode *)fast_mblock_alloc_object(sl->mblocks + level_index);
|
||||
if (node == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
node->data = data;
|
||||
|
||||
previous = sl->top;
|
||||
for (i=sl->top_level_index; i>level_index; i--) {
|
||||
|
|
@ -169,16 +178,20 @@ int flat_skiplist_insert(FlatSkiplist *sl, void *data)
|
|||
previous = previous->links[i];
|
||||
}
|
||||
|
||||
current = previous->links[i];
|
||||
previous->links[i] = node;
|
||||
node->links[i] = current;
|
||||
|
||||
sl->tmp_previous[i] = previous;
|
||||
i--;
|
||||
}
|
||||
|
||||
//set previous links of level 0
|
||||
node->prev = previous;
|
||||
current->prev = node;
|
||||
node->data = data;
|
||||
previous->links[0]->prev = node;
|
||||
|
||||
//thread safe for one write with many read model
|
||||
for (i=0; i<=level_index; i++) {
|
||||
node->links[i] = sl->tmp_previous[i]->links[i];
|
||||
sl->tmp_previous[i]->links[i] = node;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -188,9 +201,7 @@ static FlatSkiplistNode *flat_skiplist_get_previous(FlatSkiplist *sl, void *data
|
|||
int i;
|
||||
int cmp;
|
||||
FlatSkiplistNode *previous;
|
||||
FlatSkiplistNode *found;
|
||||
|
||||
found = NULL;
|
||||
previous = sl->top;
|
||||
for (i=sl->top_level_index; i>=0; i--) {
|
||||
while (previous->links[i] != sl->tail) {
|
||||
|
|
@ -199,17 +210,15 @@ static FlatSkiplistNode *flat_skiplist_get_previous(FlatSkiplist *sl, void *data
|
|||
break;
|
||||
}
|
||||
else if (cmp == 0) {
|
||||
found = previous;
|
||||
*level_index = i;
|
||||
goto DONE;
|
||||
return previous;
|
||||
}
|
||||
|
||||
previous = previous->links[i];
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
return found;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int flat_skiplist_delete(FlatSkiplist *sl, void *data)
|
||||
|
|
@ -226,13 +235,11 @@ int flat_skiplist_delete(FlatSkiplist *sl, void *data)
|
|||
|
||||
deleted = previous->links[level_index];
|
||||
for (i=level_index; i>=0; i--) {
|
||||
while (previous->links[i] != sl->tail && sl->compare_func(data,
|
||||
previous->links[i]->data) < 0)
|
||||
{
|
||||
while (previous->links[i] != sl->tail && previous->links[i] != deleted) {
|
||||
previous = previous->links[i];
|
||||
}
|
||||
|
||||
assert(sl->compare_func(data, previous->links[i]->data) == 0);
|
||||
assert(previous->links[i] == deleted);
|
||||
previous->links[i] = previous->links[i]->links[i];
|
||||
}
|
||||
|
||||
|
|
@ -277,13 +284,17 @@ int flat_skiplist_find_all(FlatSkiplist *sl, void *data, FlatSkiplistIterator *i
|
|||
return ENOENT;
|
||||
}
|
||||
|
||||
last = previous->links[0]->links[0];
|
||||
previous = previous->links[level_index];
|
||||
last = previous->links[0];
|
||||
while (last != sl->tail && sl->compare_func(data, last->data) == 0) {
|
||||
last = last->links[0];
|
||||
}
|
||||
|
||||
do {
|
||||
previous = previous->prev;
|
||||
} while (previous != sl->top && sl->compare_func(data, previous->data) == 0);
|
||||
|
||||
iterator->top = previous;
|
||||
iterator->current = last->prev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ typedef struct flat_skiplist
|
|||
struct fast_mblock_man *mblocks; //node allocators
|
||||
FlatSkiplistNode *top; //the top node
|
||||
FlatSkiplistNode *tail; //the tail node for interator
|
||||
FlatSkiplistNode **tmp_previous; //thread safe for insert
|
||||
} FlatSkiplist;
|
||||
|
||||
typedef struct flat_skiplist_iterator {
|
||||
|
|
@ -79,6 +80,33 @@ static inline void *flat_skiplist_next(FlatSkiplistIterator *iterator)
|
|||
return data;
|
||||
}
|
||||
|
||||
static inline bool flat_skiplist_empty(FlatSkiplist *sl)
|
||||
{
|
||||
return sl->top->links[0] == sl->tail;
|
||||
}
|
||||
|
||||
typedef const char * (*flat_skiplist_tostring_func)(void *data, char *buff, const int size);
|
||||
|
||||
static inline void flat_skiplist_print(FlatSkiplist *sl, flat_skiplist_tostring_func tostring_func)
|
||||
{
|
||||
int i;
|
||||
FlatSkiplistNode *current;
|
||||
char buff[1024];
|
||||
|
||||
printf("###################\n");
|
||||
for (i=sl->top_level_index; i>=0; i--) {
|
||||
printf("level %d: ", i);
|
||||
current = sl->top->links[i];
|
||||
while (current != sl->tail) {
|
||||
printf("%s ", tostring_func(current->data, buff, sizeof(buff)));
|
||||
current = current->links[i];
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("###################\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -43,6 +43,15 @@ int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
|
|||
return E2BIG;
|
||||
}
|
||||
|
||||
bytes = sizeof(MultiSkiplistNode *) * level_count;
|
||||
sl->tmp_previous = (MultiSkiplistNode **)malloc(bytes);
|
||||
if (sl->tmp_previous == 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;
|
||||
}
|
||||
|
||||
bytes = sizeof(struct fast_mblock_man) * level_count;
|
||||
sl->mblocks = (struct fast_mblock_man *)malloc(bytes);
|
||||
if (sl->mblocks == NULL) {
|
||||
|
|
@ -149,9 +158,7 @@ static MultiSkiplistNode *multi_skiplist_get_previous(MultiSkiplist *sl, void *d
|
|||
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) {
|
||||
|
|
@ -160,17 +167,15 @@ static MultiSkiplistNode *multi_skiplist_get_previous(MultiSkiplist *sl, void *d
|
|||
break;
|
||||
}
|
||||
else if (cmp == 0) {
|
||||
found = previous;
|
||||
*level_index = i;
|
||||
goto DONE;
|
||||
return previous;
|
||||
}
|
||||
|
||||
previous = previous->links[i];
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
return found;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void multi_skiplist_free_data_node(MultiSkiplist *sl,
|
||||
|
|
@ -202,7 +207,6 @@ int multi_skiplist_insert(MultiSkiplist *sl, void *data)
|
|||
MultiSkiplistData *dataNode;
|
||||
MultiSkiplistNode *node;
|
||||
MultiSkiplistNode *previous;
|
||||
MultiSkiplistNode *current = NULL;
|
||||
|
||||
dataNode = (MultiSkiplistData *)fast_mblock_alloc_object(&sl->data_mblock);
|
||||
if (dataNode == NULL) {
|
||||
|
|
@ -242,15 +246,19 @@ int multi_skiplist_insert(MultiSkiplist *sl, void *data)
|
|||
previous = previous->links[i];
|
||||
}
|
||||
|
||||
current = previous->links[i];
|
||||
previous->links[i] = node;
|
||||
node->links[i] = current;
|
||||
|
||||
sl->tmp_previous[i] = previous;
|
||||
i--;
|
||||
}
|
||||
|
||||
node->head = dataNode;
|
||||
node->tail = dataNode;
|
||||
|
||||
//thread safe for one write with many read model
|
||||
for (i=0; i<=level_index; i++) {
|
||||
node->links[i] = sl->tmp_previous[i]->links[i];
|
||||
sl->tmp_previous[i]->links[i] = node;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -283,12 +291,13 @@ int multi_skiplist_do_delete(MultiSkiplist *sl, void *data,
|
|||
}
|
||||
|
||||
for (i=level_index; i>=0; i--) {
|
||||
while (previous->links[i] != sl->tail && sl->compare_func(data,
|
||||
previous->links[i]->head->data) > 0)
|
||||
while (previous->links[i] != sl->tail &&
|
||||
previous->links[i] != deleted)
|
||||
{
|
||||
previous = previous->links[i];
|
||||
}
|
||||
|
||||
assert(previous->links[i] == deleted);
|
||||
previous->links[i] = previous->links[i]->links[i];
|
||||
}
|
||||
|
||||
|
|
@ -339,9 +348,9 @@ int multi_skiplist_find_all(MultiSkiplist *sl, void *data,
|
|||
return ENOENT;
|
||||
}
|
||||
else {
|
||||
iterator->current.node = previous;
|
||||
iterator->tail = previous->links[0]->links[0];
|
||||
iterator->current.node = previous->links[level_index];
|
||||
iterator->tail = iterator->current.node->links[0];
|
||||
iterator->current.data = iterator->current.node->head;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ typedef struct multi_skiplist
|
|||
struct fast_mblock_man *mblocks; //node allocators
|
||||
MultiSkiplistNode *top; //the top node
|
||||
MultiSkiplistNode *tail; //the tail node for terminate
|
||||
MultiSkiplistNode **tmp_previous; //thread safe for insert
|
||||
} MultiSkiplist;
|
||||
|
||||
typedef struct multi_skiplist_iterator {
|
||||
|
|
@ -76,9 +77,14 @@ static inline void multi_skiplist_iterator(MultiSkiplist *sl,
|
|||
MultiSkiplistIterator *iterator)
|
||||
{
|
||||
iterator->tail = sl->tail;
|
||||
iterator->current.node = sl->top;
|
||||
iterator->current.node = sl->top->links[0];
|
||||
if (iterator->current.node != sl->tail) {
|
||||
iterator->current.data = iterator->current.node->head;
|
||||
}
|
||||
else {
|
||||
iterator->current.data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void *multi_skiplist_next(MultiSkiplistIterator *iterator)
|
||||
{
|
||||
|
|
@ -100,6 +106,33 @@ static inline void *multi_skiplist_next(MultiSkiplistIterator *iterator)
|
|||
return data;
|
||||
}
|
||||
|
||||
static inline bool multi_skiplist_empty(MultiSkiplist *sl)
|
||||
{
|
||||
return sl->top->links[0] == sl->tail;
|
||||
}
|
||||
|
||||
typedef const char * (*multi_skiplist_tostring_func)(void *data, char *buff, const int size);
|
||||
|
||||
static inline void multi_skiplist_print(MultiSkiplist *sl, multi_skiplist_tostring_func tostring_func)
|
||||
{
|
||||
int i;
|
||||
MultiSkiplistNode *current;
|
||||
char buff[1024];
|
||||
|
||||
printf("###################\n");
|
||||
for (i=sl->top_level_index; i>=0; i--) {
|
||||
printf("level %d: ", i);
|
||||
current = sl->top->links[i];
|
||||
while (current != sl->tail) {
|
||||
printf("%s ", tostring_func(current->head->data, buff, sizeof(buff)));
|
||||
current = current->links[i];
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("###################\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -96,14 +96,11 @@ static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
|
|||
int bytes;
|
||||
int result;
|
||||
|
||||
logInfo("file: "__FILE__", line: %d, "
|
||||
"send remain: %d", __LINE__, entry->remain);
|
||||
result = 0;
|
||||
while (entry->remain > 0) {
|
||||
bytes = write(entry->conn->sock, entry->send_buffer->data +
|
||||
(entry->send_buffer->length - entry->remain), entry->remain);
|
||||
|
||||
logInfo("sock: %d, write bytes: %d, remain: %d", entry->conn->sock, bytes, entry->remain);
|
||||
if (bytes < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
break;
|
||||
|
|
@ -217,8 +214,6 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
|
|||
int bytes;
|
||||
int result;
|
||||
|
||||
logInfo("file: "__FILE__", line: %d, "
|
||||
"recv remain: %d", __LINE__, entry->remain);
|
||||
result = 0;
|
||||
while (entry->remain > 0) {
|
||||
bytes = read(entry->conn->sock, entry->recv_buffer.data +
|
||||
|
|
@ -322,9 +317,11 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
logInfo("file: "__FILE__", line: %d, pulling_count: %d, "
|
||||
"success_count: %d\n", __LINE__,
|
||||
client->pulling_count, client->success_count);
|
||||
*/
|
||||
if (client->pulling_count > 0) {
|
||||
int i;
|
||||
for (i=0; i<client->entry_count; i++) {
|
||||
|
|
|
|||
|
|
@ -31,17 +31,19 @@ struct fast_multi_sock_entry;
|
|||
|
||||
//return the body length
|
||||
typedef int (*fast_multi_sock_client_get_body_length_func)(const FastBuffer *recv_buffer);
|
||||
|
||||
//IO deal fucntion
|
||||
typedef int (*fast_multi_sock_client_io_func)(struct fast_multi_sock_client *client,
|
||||
struct fast_multi_sock_entry *entry);
|
||||
|
||||
typedef struct fast_multi_sock_entry {
|
||||
ConnectionInfo *conn;
|
||||
ConnectionInfo *conn; //the socket must be non-block socket
|
||||
FastBuffer *send_buffer; //send buffer for internal use
|
||||
fast_multi_sock_client_io_func io_callback; //for internal use
|
||||
FastBuffer recv_buffer; //recv buffer
|
||||
int remain; //remain bytes
|
||||
int error_no; //0 for success
|
||||
bool done;
|
||||
int error_no; //0 for success, != 0 fail
|
||||
int remain; //remain bytes, for internal use
|
||||
bool done; //for internal use
|
||||
} FastMultiSockEntry;
|
||||
|
||||
typedef struct fast_multi_sock_client {
|
||||
|
|
|
|||
129
src/skiplist.h
129
src/skiplist.h
|
|
@ -17,9 +17,11 @@
|
|||
#include "skiplist_common.h"
|
||||
#include "flat_skiplist.h"
|
||||
#include "multi_skiplist.h"
|
||||
#include "skiplist_set.h"
|
||||
|
||||
#define SKIPLIST_TYPE_FLAT 0
|
||||
#define SKIPLIST_TYPE_MULTI 1
|
||||
#define SKIPLIST_TYPE_SET 2
|
||||
|
||||
typedef struct skiplist
|
||||
{
|
||||
|
|
@ -27,6 +29,7 @@ typedef struct skiplist
|
|||
union {
|
||||
FlatSkiplist flat;
|
||||
MultiSkiplist multi;
|
||||
SkiplistSet set;
|
||||
} u;
|
||||
} Skiplist;
|
||||
|
||||
|
|
@ -35,6 +38,7 @@ typedef struct skiplist_iterator {
|
|||
union {
|
||||
FlatSkiplistIterator flat;
|
||||
MultiSkiplistIterator multi;
|
||||
SkiplistSetIterator set;
|
||||
} u;
|
||||
} SkiplistIterator;
|
||||
|
||||
|
|
@ -51,95 +55,166 @@ static inline int skiplist_init_ex(Skiplist *sl, const int level_count,
|
|||
const int min_alloc_elements_once, const int type)
|
||||
{
|
||||
sl->type = type;
|
||||
if (type == SKIPLIST_TYPE_FLAT) {
|
||||
switch (type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return flat_skiplist_init_ex(&sl->u.flat, level_count,
|
||||
compare_func, free_func, min_alloc_elements_once);
|
||||
}
|
||||
else {
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return multi_skiplist_init_ex(&sl->u.multi, level_count,
|
||||
compare_func, free_func, min_alloc_elements_once);
|
||||
case SKIPLIST_TYPE_SET:
|
||||
return skiplist_set_init_ex(&sl->u.set, level_count,
|
||||
compare_func, free_func, min_alloc_elements_once);
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void skiplist_destroy(Skiplist *sl)
|
||||
{
|
||||
if (sl->type == SKIPLIST_TYPE_FLAT) {
|
||||
switch (sl->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
flat_skiplist_destroy(&sl->u.flat);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
multi_skiplist_destroy(&sl->u.multi);
|
||||
break;
|
||||
case SKIPLIST_TYPE_SET:
|
||||
skiplist_set_destroy(&sl->u.set);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int skiplist_insert(Skiplist *sl, void *data)
|
||||
{
|
||||
if (sl->type == SKIPLIST_TYPE_FLAT) {
|
||||
switch (sl->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return flat_skiplist_insert(&sl->u.flat, data);
|
||||
}
|
||||
else {
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return multi_skiplist_insert(&sl->u.multi, data);
|
||||
case SKIPLIST_TYPE_SET:
|
||||
return skiplist_set_insert(&sl->u.set, data);
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int skiplist_delete(Skiplist *sl, void *data)
|
||||
{
|
||||
if (sl->type == SKIPLIST_TYPE_FLAT) {
|
||||
switch (sl->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return flat_skiplist_delete(&sl->u.flat, data);
|
||||
}
|
||||
else {
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return multi_skiplist_delete(&sl->u.multi, data);
|
||||
case SKIPLIST_TYPE_SET:
|
||||
return skiplist_set_delete(&sl->u.set, data);
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int skiplist_delete_all(Skiplist *sl, void *data, int *delete_count)
|
||||
{
|
||||
if (sl->type == SKIPLIST_TYPE_FLAT) {
|
||||
int result;
|
||||
switch (sl->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return flat_skiplist_delete_all(&sl->u.flat, data, delete_count);
|
||||
}
|
||||
else {
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return multi_skiplist_delete_all(&sl->u.multi, data, delete_count);
|
||||
case SKIPLIST_TYPE_SET:
|
||||
result = skiplist_set_delete(&sl->u.set, data);
|
||||
*delete_count = (result == 0) ? 1 : 0;
|
||||
return result;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void *skiplist_find(Skiplist *sl, void *data)
|
||||
{
|
||||
if (sl->type == SKIPLIST_TYPE_FLAT) {
|
||||
switch (sl->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return flat_skiplist_find(&sl->u.flat, data);
|
||||
}
|
||||
else {
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return multi_skiplist_find(&sl->u.multi, data);
|
||||
case SKIPLIST_TYPE_SET:
|
||||
return skiplist_set_find(&sl->u.set, data);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int skiplist_find_all(Skiplist *sl, void *data, SkiplistIterator *iterator)
|
||||
{
|
||||
iterator->type = sl->type;
|
||||
if (sl->type == SKIPLIST_TYPE_FLAT) {
|
||||
switch (sl->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return flat_skiplist_find_all(&sl->u.flat, data, &iterator->u.flat);
|
||||
}
|
||||
else {
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return multi_skiplist_find_all(&sl->u.multi, data, &iterator->u.multi);
|
||||
case SKIPLIST_TYPE_SET:
|
||||
return EOPNOTSUPP;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void skiplist_iterator(Skiplist *sl, SkiplistIterator *iterator)
|
||||
{
|
||||
iterator->type = sl->type;
|
||||
if (sl->type == SKIPLIST_TYPE_FLAT) {
|
||||
switch (sl->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return flat_skiplist_iterator(&sl->u.flat, &iterator->u.flat);
|
||||
}
|
||||
else {
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return multi_skiplist_iterator(&sl->u.multi, &iterator->u.multi);
|
||||
case SKIPLIST_TYPE_SET:
|
||||
return skiplist_set_iterator(&sl->u.set, &iterator->u.set);
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void *skiplist_next(SkiplistIterator *iterator)
|
||||
{
|
||||
if (iterator->type == SKIPLIST_TYPE_FLAT) {
|
||||
switch (iterator->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return flat_skiplist_next(&iterator->u.flat);
|
||||
}
|
||||
else {
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return multi_skiplist_next(&iterator->u.multi);
|
||||
case SKIPLIST_TYPE_SET:
|
||||
return skiplist_set_next(&iterator->u.set);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool skiplist_empty(Skiplist *sl)
|
||||
{
|
||||
switch (sl->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return flat_skiplist_empty(&sl->u.flat);
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return multi_skiplist_empty(&sl->u.multi);
|
||||
case SKIPLIST_TYPE_SET:
|
||||
return skiplist_set_empty(&sl->u.set);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char* skiplist_get_type_caption(Skiplist *sl)
|
||||
{
|
||||
switch (sl->type) {
|
||||
case SKIPLIST_TYPE_FLAT:
|
||||
return "flat";
|
||||
case SKIPLIST_TYPE_MULTI:
|
||||
return "multi";
|
||||
case SKIPLIST_TYPE_SET:
|
||||
return "set";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,270 @@
|
|||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
//skiplist_set.c
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "logger.h"
|
||||
#include "skiplist_set.h"
|
||||
|
||||
int skiplist_set_init_ex(SkiplistSet *sl, const int level_count,
|
||||
skiplist_compare_func compare_func, skiplist_free_func free_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 > 30) {
|
||||
logError("file: "__FILE__", line: %d, "
|
||||
"level count: %d is too large",
|
||||
__LINE__, level_count);
|
||||
return E2BIG;
|
||||
}
|
||||
|
||||
bytes = sizeof(SkiplistSetNode *) * level_count;
|
||||
sl->tmp_previous = (SkiplistSetNode **)malloc(bytes);
|
||||
if (sl->tmp_previous == 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;
|
||||
}
|
||||
|
||||
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(SkiplistSetNode) + sizeof(SkiplistSetNode *) * (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 = (SkiplistSetNode *)fast_mblock_alloc_object(top_mblock);
|
||||
if (sl->top == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
memset(sl->top, 0, top_mblock->info.element_size);
|
||||
|
||||
sl->tail = (SkiplistSetNode *)fast_mblock_alloc_object(sl->mblocks + 0);
|
||||
if (sl->tail == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
memset(sl->tail, 0, sl->mblocks[0].info.element_size);
|
||||
|
||||
for (i=0; i<level_count; i++) {
|
||||
sl->top->links[i] = sl->tail;
|
||||
}
|
||||
|
||||
sl->level_count = level_count;
|
||||
sl->compare_func = compare_func;
|
||||
sl->free_func = free_func;
|
||||
|
||||
srand(time(NULL));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void skiplist_set_destroy(SkiplistSet *sl)
|
||||
{
|
||||
int i;
|
||||
SkiplistSetNode *node;
|
||||
SkiplistSetNode *deleted;
|
||||
|
||||
if (sl->mblocks == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sl->free_func != NULL) {
|
||||
node = sl->top->links[0];
|
||||
while (node != sl->tail) {
|
||||
deleted = node;
|
||||
node = node->links[0];
|
||||
sl->free_func(deleted->data);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<sl->level_count; i++) {
|
||||
fast_mblock_destroy(sl->mblocks + i);
|
||||
}
|
||||
|
||||
free(sl->mblocks);
|
||||
sl->mblocks = NULL;
|
||||
}
|
||||
|
||||
static inline int skiplist_set_get_level_index(SkiplistSet *sl)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<sl->top_level_index; i++) {
|
||||
if (rand() < RAND_MAX / 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int skiplist_set_insert(SkiplistSet *sl, void *data)
|
||||
{
|
||||
int i;
|
||||
int level_index;
|
||||
int cmp;
|
||||
SkiplistSetNode *node;
|
||||
SkiplistSetNode *previous;
|
||||
|
||||
level_index = skiplist_set_get_level_index(sl);
|
||||
previous = sl->top;
|
||||
for (i=sl->top_level_index; i>level_index; i--) {
|
||||
while (previous->links[i] != sl->tail) {
|
||||
cmp = sl->compare_func(data, previous->links[i]->data);
|
||||
if (cmp < 0) {
|
||||
break;
|
||||
}
|
||||
else if (cmp == 0) {
|
||||
return EEXIST;
|
||||
}
|
||||
|
||||
previous = previous->links[i];
|
||||
}
|
||||
}
|
||||
|
||||
while (i >= 0) {
|
||||
while (previous->links[i] != sl->tail) {
|
||||
cmp = sl->compare_func(data, previous->links[i]->data);
|
||||
if (cmp < 0) {
|
||||
break;
|
||||
}
|
||||
else if (cmp == 0) {
|
||||
return EEXIST;
|
||||
}
|
||||
|
||||
previous = previous->links[i];
|
||||
}
|
||||
|
||||
sl->tmp_previous[i] = previous;
|
||||
i--;
|
||||
}
|
||||
|
||||
node = (SkiplistSetNode *)fast_mblock_alloc_object(sl->mblocks + level_index);
|
||||
if (node == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
node->data = data;
|
||||
|
||||
//thread safe for one write with many read model
|
||||
for (i=0; i<=level_index; i++) {
|
||||
node->links[i] = sl->tmp_previous[i]->links[i];
|
||||
sl->tmp_previous[i]->links[i] = node;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SkiplistSetNode *skiplist_set_get_previous(SkiplistSet *sl, void *data,
|
||||
int *level_index)
|
||||
{
|
||||
int i;
|
||||
int cmp;
|
||||
SkiplistSetNode *previous;
|
||||
|
||||
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]->data);
|
||||
if (cmp < 0) {
|
||||
break;
|
||||
}
|
||||
else if (cmp == 0) {
|
||||
*level_index = i;
|
||||
return previous;
|
||||
}
|
||||
|
||||
previous = previous->links[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int skiplist_set_delete(SkiplistSet *sl, void *data)
|
||||
{
|
||||
int i;
|
||||
int level_index;
|
||||
SkiplistSetNode *previous;
|
||||
SkiplistSetNode *deleted;
|
||||
|
||||
previous = skiplist_set_get_previous(sl, data, &level_index);
|
||||
if (previous == NULL) {
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
deleted = previous->links[level_index];
|
||||
for (i=level_index; i>=0; i--) {
|
||||
while (previous->links[i] != sl->tail &&
|
||||
previous->links[i] != deleted)
|
||||
{
|
||||
previous = previous->links[i];
|
||||
}
|
||||
|
||||
assert(previous->links[i] == deleted);
|
||||
previous->links[i] = previous->links[i]->links[i];
|
||||
}
|
||||
|
||||
if (sl->free_func != NULL) {
|
||||
sl->free_func(deleted->data);
|
||||
}
|
||||
fast_mblock_free_object(sl->mblocks + level_index, deleted);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *skiplist_set_find(SkiplistSet *sl, void *data)
|
||||
{
|
||||
int level_index;
|
||||
SkiplistSetNode *previous;
|
||||
|
||||
previous = skiplist_set_get_previous(sl, data, &level_index);
|
||||
return (previous != NULL) ? previous->links[level_index]->data : NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
//skiplist_set.h, support stable sort :)
|
||||
#ifndef _SKIPLIST_SET_H
|
||||
#define _SKIPLIST_SET_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "common_define.h"
|
||||
#include "skiplist_common.h"
|
||||
#include "fast_mblock.h"
|
||||
|
||||
typedef struct skiplist_set_node
|
||||
{
|
||||
void *data;
|
||||
struct skiplist_set_node *links[0];
|
||||
} SkiplistSetNode;
|
||||
|
||||
typedef struct skiplist_set
|
||||
{
|
||||
int level_count;
|
||||
int top_level_index;
|
||||
skiplist_compare_func compare_func;
|
||||
skiplist_free_func free_func;
|
||||
struct fast_mblock_man *mblocks; //node allocators
|
||||
SkiplistSetNode *top; //the top node
|
||||
SkiplistSetNode *tail; //the tail node for interator
|
||||
SkiplistSetNode **tmp_previous; //thread safe for insert
|
||||
} SkiplistSet;
|
||||
|
||||
typedef struct skiplist_set_iterator {
|
||||
SkiplistSetNode *tail;
|
||||
SkiplistSetNode *current;
|
||||
} SkiplistSetIterator;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define skiplist_set_init(sl, level_count, compare_func, free_func) \
|
||||
skiplist_set_init_ex(sl, level_count, compare_func, free_func, \
|
||||
SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE)
|
||||
|
||||
int skiplist_set_init_ex(SkiplistSet *sl, const int level_count,
|
||||
skiplist_compare_func compare_func, skiplist_free_func free_func,
|
||||
const int min_alloc_elements_once);
|
||||
|
||||
void skiplist_set_destroy(SkiplistSet *sl);
|
||||
|
||||
int skiplist_set_insert(SkiplistSet *sl, void *data);
|
||||
int skiplist_set_delete(SkiplistSet *sl, void *data);
|
||||
void *skiplist_set_find(SkiplistSet *sl, void *data);
|
||||
|
||||
static inline void skiplist_set_iterator(SkiplistSet *sl, SkiplistSetIterator *iterator)
|
||||
{
|
||||
iterator->tail = sl->tail;
|
||||
iterator->current = sl->top->links[0];
|
||||
}
|
||||
|
||||
static inline void *skiplist_set_next(SkiplistSetIterator *iterator)
|
||||
{
|
||||
void *data;
|
||||
|
||||
if (iterator->current == iterator->tail) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = iterator->current->data;
|
||||
iterator->current = iterator->current->links[0];
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline bool skiplist_set_empty(SkiplistSet *sl)
|
||||
{
|
||||
return sl->top->links[0] == sl->tail;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
.SUFFIXES: .c .o
|
||||
|
||||
COMPILE = $(CC) -g -O1 -Wall -D_FILE_OFFSET_BITS=64 -g -DDEBUG_FLAG
|
||||
COMPILE = $(CC) -g -O3 -Wall -D_FILE_OFFSET_BITS=64 -g -DDEBUG_FLAG
|
||||
INC_PATH = -I/usr/local/include
|
||||
LIB_PATH = -lfastcommon -lpthread
|
||||
|
||||
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_logger
|
||||
test_id_generator test_ini_parser test_char_convert test_char_convert_loader \
|
||||
test_logger test_skiplist_set
|
||||
|
||||
all: $(ALL_PRGS)
|
||||
.c:
|
||||
|
|
|
|||
|
|
@ -118,6 +118,14 @@ static int compare_record(const void *p1, const void *p2)
|
|||
return ((Record *)p1)->key - ((Record *)p2)->key;
|
||||
}
|
||||
|
||||
/*
|
||||
static const char * skiplist_tostring(void *data, char *buff, const int size)
|
||||
{
|
||||
snprintf(buff, size, "%d(%04x)", ((Record *)data)->key, (int)(((long)data) & 0xFFFFL));
|
||||
return buff;
|
||||
}
|
||||
*/
|
||||
|
||||
static int test_stable_sort()
|
||||
{
|
||||
#define RECORDS 32
|
||||
|
|
@ -127,13 +135,19 @@ static int test_stable_sort()
|
|||
int index2;
|
||||
int delete_count;
|
||||
int total_delete_count;
|
||||
int occur_count;
|
||||
int max_occur_count;
|
||||
int previous_key;
|
||||
int max_occur_key;
|
||||
Skiplist sl;
|
||||
SkiplistIterator iterator;
|
||||
Record records[RECORDS];
|
||||
Record tmp_records[RECORDS];
|
||||
Record *record;
|
||||
Record target;
|
||||
void *value;
|
||||
|
||||
printf("test_stable_sort ...\n");
|
||||
instance_count = 0;
|
||||
result = skiplist_init_ex(&sl, 12, compare_record,
|
||||
free_test_func, 128, skiplist_type);
|
||||
|
|
@ -146,6 +160,7 @@ static int test_stable_sort()
|
|||
records[i].key = i + 1;
|
||||
}
|
||||
|
||||
if (skiplist_type != SKIPLIST_TYPE_SET) {
|
||||
for (i=0; i<RECORDS/4; i++) {
|
||||
index1 = (RECORDS - 1) * (int64_t)rand() / (int64_t)RAND_MAX;
|
||||
index2 = RECORDS - 1 - index1;
|
||||
|
|
@ -153,9 +168,34 @@ static int test_stable_sort()
|
|||
records[index1].key = records[index2].key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(tmp_records, records, sizeof(tmp_records));
|
||||
qsort(tmp_records, RECORDS, sizeof(Record), compare_record);
|
||||
max_occur_count = 0;
|
||||
max_occur_key = 0;
|
||||
i = 0;
|
||||
while (i < RECORDS) {
|
||||
occur_count = 1;
|
||||
previous_key = tmp_records[i].key;
|
||||
i++;
|
||||
while (i < RECORDS && tmp_records[i].key == previous_key) {
|
||||
i++;
|
||||
occur_count++;
|
||||
}
|
||||
if (occur_count > max_occur_count) {
|
||||
max_occur_key = previous_key;
|
||||
max_occur_count = occur_count;
|
||||
}
|
||||
}
|
||||
printf("max_occur_key: %d, max_occur_count: %d\n\n", max_occur_key, max_occur_count);
|
||||
|
||||
|
||||
for (i=0; i<RECORDS; i++) {
|
||||
if ((result=skiplist_insert(&sl, records + i)) != 0) {
|
||||
fprintf(stderr, "skiplist_insert insert fail, "
|
||||
"errno: %d, error info: %s\n",
|
||||
result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
instance_count++;
|
||||
|
|
@ -176,8 +216,13 @@ static int test_stable_sort()
|
|||
}
|
||||
assert(i==RECORDS);
|
||||
|
||||
target.key = 10;
|
||||
target.key = max_occur_key;
|
||||
target.line = 0;
|
||||
if (skiplist_type == SKIPLIST_TYPE_SET) {
|
||||
record = (Record *)skiplist_find(&sl, &target);
|
||||
assert(record != NULL && record->key == target.key);
|
||||
}
|
||||
else {
|
||||
if (skiplist_find_all(&sl, &target, &iterator) == 0) {
|
||||
printf("found key: %d\n", target.key);
|
||||
}
|
||||
|
|
@ -188,20 +233,44 @@ static int test_stable_sort()
|
|||
printf("%d => #%d\n", record->key, record->line);
|
||||
}
|
||||
printf("found record count: %d\n", i);
|
||||
}
|
||||
|
||||
/*
|
||||
if (skiplist_type == SKIPLIST_TYPE_FLAT) {
|
||||
flat_skiplist_print(&sl.u.flat, skiplist_tostring);
|
||||
}
|
||||
else if (skiplist_type == SKIPLIST_TYPE_MULTI) {
|
||||
multi_skiplist_print(&sl.u.multi, skiplist_tostring);
|
||||
}
|
||||
*/
|
||||
|
||||
total_delete_count = 0;
|
||||
for (i=0; i<RECORDS; i++) {
|
||||
if ((result=skiplist_delete_all(&sl, records + i,
|
||||
&delete_count)) == 0)
|
||||
do {
|
||||
delete_count = 0;
|
||||
if ((result=skiplist_delete(&sl, records + i)) == 0)
|
||||
{
|
||||
delete_count = 1;
|
||||
total_delete_count += delete_count;
|
||||
}
|
||||
assert((result == 0 && delete_count > 0) ||
|
||||
(result != 0 && delete_count == 0));
|
||||
|
||||
} while (result == 0);
|
||||
|
||||
}
|
||||
assert(total_delete_count == RECORDS);
|
||||
assert(instance_count == 0);
|
||||
|
||||
/*
|
||||
if (skiplist_type == SKIPLIST_TYPE_FLAT) {
|
||||
flat_skiplist_print(&sl.u.flat, skiplist_tostring);
|
||||
}
|
||||
else if (skiplist_type == SKIPLIST_TYPE_MULTI) {
|
||||
multi_skiplist_print(&sl.u.multi, skiplist_tostring);
|
||||
}
|
||||
*/
|
||||
|
||||
i = 0;
|
||||
skiplist_iterator(&sl, &iterator);
|
||||
while ((value=skiplist_next(&iterator)) != NULL) {
|
||||
|
|
@ -230,9 +299,10 @@ int main(int argc, char *argv[])
|
|||
if (strcasecmp(argv[1], "multi") == 0 || strcmp(argv[1], "1") == 0) {
|
||||
skiplist_type = SKIPLIST_TYPE_MULTI;
|
||||
}
|
||||
else if (strcasecmp(argv[1], "set") == 0 || strcmp(argv[1], "2") == 0) {
|
||||
skiplist_type = SKIPLIST_TYPE_SET;
|
||||
}
|
||||
}
|
||||
printf("skiplist type: %s\n",
|
||||
skiplist_type == SKIPLIST_TYPE_FLAT ? "flat" : "multi");
|
||||
|
||||
numbers = (int *)malloc(sizeof(int) * COUNT);
|
||||
srand(time(NULL));
|
||||
|
|
@ -257,6 +327,7 @@ int main(int argc, char *argv[])
|
|||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
printf("skiplist type: %s\n", skiplist_get_type_caption(&sl));
|
||||
|
||||
test_insert();
|
||||
printf("\n");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
#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/skiplist_set.h"
|
||||
#include "fastcommon/logger.h"
|
||||
#include "fastcommon/shared_func.h"
|
||||
|
||||
#define COUNT 1000000
|
||||
#define LEVEL_COUNT 16
|
||||
#define MIN_ALLOC_ONCE 32
|
||||
#define LAST_INDEX (COUNT - 1)
|
||||
|
||||
static int *numbers;
|
||||
static SkiplistSet sl;
|
||||
static SkiplistSetIterator 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);
|
||||
}
|
||||
|
||||
static int test_insert()
|
||||
{
|
||||
int i;
|
||||
int result;
|
||||
int64_t start_time;
|
||||
int64_t end_time;
|
||||
void *value;
|
||||
|
||||
instance_count = 0;
|
||||
start_time = get_current_time_ms();
|
||||
for (i=0; i<COUNT; i++) {
|
||||
if ((result=skiplist_set_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 = skiplist_set_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;
|
||||
skiplist_set_iterator(&sl, &iterator);
|
||||
while ((value=skiplist_set_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(skiplist_set_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 = skiplist_set_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;
|
||||
skiplist_set_iterator(&sl, &iterator);
|
||||
while ((value=skiplist_set_next(&iterator)) != NULL) {
|
||||
i++;
|
||||
}
|
||||
assert(i==0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int tmp;
|
||||
int index1;
|
||||
int index2;
|
||||
int result;
|
||||
|
||||
log_init();
|
||||
numbers = (int *)malloc(sizeof(int) * COUNT);
|
||||
srand(time(NULL));
|
||||
for (i=0; i<COUNT; i++) {
|
||||
numbers[i] = 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;
|
||||
}
|
||||
|
||||
fast_mblock_manager_init();
|
||||
result = skiplist_set_init_ex(&sl, LEVEL_COUNT, compare_func,
|
||||
free_test_func, MIN_ALLOC_ONCE);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
test_insert();
|
||||
printf("\n");
|
||||
|
||||
fast_mblock_manager_stat_print(false);
|
||||
|
||||
test_delete();
|
||||
printf("\n");
|
||||
|
||||
test_insert();
|
||||
printf("\n");
|
||||
|
||||
/*
|
||||
test_delete();
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
skiplist_set_destroy(&sl);
|
||||
assert(instance_count == 0);
|
||||
|
||||
printf("pass OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue