depend on libfastcommon
parent
b832e104b2
commit
8a9ec249fa
4
HISTORY
4
HISTORY
|
|
@ -1,4 +1,8 @@
|
|||
|
||||
Version 5.04 2014-08-19
|
||||
* add fastdfs.spec for build RPM on Linux
|
||||
* depend on libfastcommon
|
||||
|
||||
Version 5.03 2014-08-10
|
||||
* network send and recv retry when error EINTR happen
|
||||
* support mac OS Darwin
|
||||
|
|
|
|||
34
INSTALL
34
INSTALL
|
|
@ -6,43 +6,47 @@ Please visit the FastDFS Home Page for more detail.
|
|||
English language: http://english.csource.org/
|
||||
Chinese language: http://www.csource.org/
|
||||
|
||||
#step 1. download FastDFS source package and unpack it,
|
||||
#step 1. download libfastcommon source package from github and install it,
|
||||
the github address:
|
||||
https://github.com/happyfish100/libfastcommon.git
|
||||
|
||||
#step 2. download FastDFS source package and unpack it,
|
||||
tar xzf FastDFS_v5.x.tar.gz
|
||||
#for example:
|
||||
tar xzf FastDFS_v5.01.tar.gz
|
||||
tar xzf FastDFS_v5.04.tar.gz
|
||||
|
||||
#step 2. enter the FastDFS dir
|
||||
#step 3. enter the FastDFS dir
|
||||
cd FastDFS
|
||||
|
||||
#step 3. execute:
|
||||
#step 4. execute:
|
||||
./make.sh
|
||||
|
||||
#step 4. make install
|
||||
#step 5. make install
|
||||
./make.sh install
|
||||
|
||||
#step 5. edit/modify the config file of tracker and storage
|
||||
#step 6. edit/modify the config file of tracker and storage
|
||||
|
||||
#step 6. run server programs
|
||||
#step 7. run server programs
|
||||
#start the tracker server:
|
||||
/usr/local/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
|
||||
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
|
||||
#in Linux, you can start fdfs_trackerd as a service:
|
||||
/sbin/service fdfs_trackerd start
|
||||
|
||||
#start the storage server:
|
||||
/usr/local/bin/fdfs_storaged /etc/fdfs/storage.conf restart
|
||||
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
|
||||
#in Linux, you can start fdfs_storaged as a service:
|
||||
/sbin/service fdfs_storaged start
|
||||
|
||||
#step 7. run test program
|
||||
#step 8. run test program
|
||||
#run the client test program:
|
||||
/usr/local/bin/fdfs_test <client_conf_filename> <operation>
|
||||
/usr/local/bin/fdfs_test1 <client_conf_filename> <operation>
|
||||
/usr/bin/fdfs_test <client_conf_filename> <operation>
|
||||
/usr/bin/fdfs_test1 <client_conf_filename> <operation>
|
||||
#for example, upload a file:
|
||||
/usr/local/bin/fdfs_test conf/client.conf upload /usr/include/stdlib.h
|
||||
/usr/bin/fdfs_test conf/client.conf upload /usr/include/stdlib.h
|
||||
|
||||
#step 8. run monitor program
|
||||
#step 9. run monitor program
|
||||
#run the monitor program:
|
||||
/usr/local/bin/fdfs_monitor <client_conf_filename>
|
||||
/usr/bin/fdfs_monitor <client_conf_filename>
|
||||
|
||||
|
||||
tracker server config file sample please see conf/tracker.conf
|
||||
|
|
|
|||
|
|
@ -3,24 +3,13 @@
|
|||
COMPILE = $(CC) $(CFLAGS)
|
||||
ENABLE_STATIC_LIB = $(ENABLE_STATIC_LIB)
|
||||
ENABLE_SHARED_LIB = $(ENABLE_SHARED_LIB)
|
||||
INC_PATH = -I../common -I../tracker -I/usr/include
|
||||
LIB_PATH = $(LIBS)
|
||||
INC_PATH = -I../common -I../tracker -I/usr/include/fastcommon
|
||||
LIB_PATH = $(LIBS) -lfastcommon
|
||||
TARGET_PATH = $(TARGET_PREFIX)/bin
|
||||
TARGET_LIB = $(TARGET_PREFIX)/lib64
|
||||
TARGET_INC = $(TARGET_PREFIX)/include
|
||||
CONFIG_PATH = $(TARGET_CONF_PATH)
|
||||
|
||||
FAST_STATIC_OBJS = ../common/hash.o ../common/chain.o \
|
||||
../common/shared_func.o ../common/ini_file_reader.o \
|
||||
../common/logger.o ../common/sockopt.o \
|
||||
../common/base64.o ../common/sched_thread.o \
|
||||
../common/http_func.o ../common/md5.o \
|
||||
../common/pthread_func.o ../common/local_ip_func.o \
|
||||
../common/avl_tree.o ../common/connection_pool.o \
|
||||
../common/ioevent.o ../common/ioevent_loop.o \
|
||||
../common/fast_task_queue.o ../common/fast_timer.o \
|
||||
../common/process_ctrl.o ../common/fast_mblock.o
|
||||
|
||||
FDFS_STATIC_OBJS = ../common/fdfs_global.o ../common/fdfs_http_shared.o \
|
||||
../common/mime_file_parser.o ../tracker/tracker_proto.o \
|
||||
../tracker/fdfs_shared_func.o \
|
||||
|
|
@ -28,18 +17,7 @@ FDFS_STATIC_OBJS = ../common/fdfs_global.o ../common/fdfs_http_shared.o \
|
|||
tracker_client.o client_func.o \
|
||||
client_global.o storage_client.o
|
||||
|
||||
STATIC_OBJS = $(FAST_STATIC_OBJS) $(FDFS_STATIC_OBJS)
|
||||
|
||||
FAST_SHARED_OBJS = ../common/hash.lo ../common/chain.lo \
|
||||
../common/shared_func.lo ../common/ini_file_reader.lo \
|
||||
../common/logger.lo ../common/sockopt.lo \
|
||||
../common/base64.lo ../common/sched_thread.lo \
|
||||
../common/http_func.lo ../common/md5.lo \
|
||||
../common/pthread_func.lo ../common/local_ip_func.lo \
|
||||
../common/avl_tree.lo ../common/connection_pool.lo \
|
||||
../common/ioevent.lo ../common/ioevent_loop.lo \
|
||||
../common/fast_task_queue.lo ../common/fast_timer.lo \
|
||||
../common/process_ctrl.lo ../common/fast_mblock.lo
|
||||
STATIC_OBJS = $(FDFS_STATIC_OBJS)
|
||||
|
||||
FDFS_SHARED_OBJS = ../common/fdfs_global.lo ../common/fdfs_http_shared.lo \
|
||||
../common/mime_file_parser.lo ../tracker/tracker_proto.lo \
|
||||
|
|
@ -48,18 +26,6 @@ FDFS_SHARED_OBJS = ../common/fdfs_global.lo ../common/fdfs_http_shared.lo \
|
|||
tracker_client.lo client_func.lo \
|
||||
client_global.lo storage_client.lo
|
||||
|
||||
FAST_HEADER_FILES = ../common/common_define.h ../common/hash.h \
|
||||
../common/chain.h ../common/logger.h \
|
||||
../common/base64.h ../common/shared_func.h \
|
||||
../common/pthread_func.h ../common/ini_file_reader.h \
|
||||
../common/sockopt.h ../common/sched_thread.h \
|
||||
../common/http_func.h ../common/md5.h ../common/_os_bits.h \
|
||||
../common/local_ip_func.h ../common/avl_tree.h \
|
||||
../common/connection_pool.h ../common/ioevent.h \
|
||||
../common/ioevent_loop.h ../common/fast_task_queue.h \
|
||||
../common/fast_timer.h ../common/process_ctrl.h \
|
||||
../common/fast_mblock.h
|
||||
|
||||
FDFS_HEADER_FILES = ../common/fdfs_define.h ../common/fdfs_global.h \
|
||||
../common/mime_file_parser.h ../common/fdfs_http_shared.h \
|
||||
../tracker/tracker_types.h ../tracker/tracker_proto.h \
|
||||
|
|
@ -68,29 +34,23 @@ FDFS_HEADER_FILES = ../common/fdfs_define.h ../common/fdfs_global.h \
|
|||
tracker_client.h storage_client.h storage_client1.h \
|
||||
client_func.h client_global.h fdfs_client.h
|
||||
|
||||
ALL_OBJS = $(STATIC_OBJS) $(FAST_SHARED_OBJS) $(FDFS_SHARED_OBJS)
|
||||
ALL_OBJS = $(STATIC_OBJS) $(FDFS_SHARED_OBJS)
|
||||
|
||||
ALL_PRGS = fdfs_monitor fdfs_test fdfs_test1 fdfs_crc32 fdfs_upload_file \
|
||||
fdfs_download_file fdfs_delete_file fdfs_file_info \
|
||||
fdfs_appender_test fdfs_appender_test1 fdfs_append_file \
|
||||
fdfs_upload_appender
|
||||
|
||||
STATIC_LIBS = libfastcommon.a libfdfsclient.a
|
||||
STATIC_LIBS = libfdfsclient.a
|
||||
|
||||
SHARED_LIBS = libfastcommon.so libfdfsclient.so
|
||||
SHARED_LIBS = libfdfsclient.so
|
||||
CLIENT_SHARED_LIBS = libfdfsclient.so
|
||||
|
||||
ALL_LIBS = $(STATIC_LIBS) $(SHARED_LIBS)
|
||||
|
||||
all: $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
||||
libfastcommon.so:
|
||||
$(COMPILE) -o $@ $< -shared $(FAST_SHARED_OBJS) $(LIB_PATH)
|
||||
# ln -fs libfastcommon.so.1 libfastcommon.so
|
||||
libfdfsclient.so:
|
||||
$(COMPILE) -o $@ $< -shared $(FDFS_SHARED_OBJS) $(LIB_PATH) -lfastcommon
|
||||
# ln -fs libfdfsclient.so.1 libfdfsclient.so
|
||||
libfastcommon.a:
|
||||
ar cru $@ $< $(FAST_STATIC_OBJS)
|
||||
$(COMPILE) -o $@ $< -shared $(FDFS_SHARED_OBJS) $(LIB_PATH)
|
||||
libfdfsclient.a:
|
||||
ar cru $@ $< $(FDFS_STATIC_OBJS)
|
||||
.o:
|
||||
|
|
@ -111,7 +71,7 @@ install:
|
|||
|
||||
mkdir -p $(TARGET_INC)/fastdfs
|
||||
cp -f $(FDFS_HEADER_FILES) $(TARGET_INC)/fastdfs
|
||||
if [ ! -f $(CONFIG_PATH)/client.conf ]; then cp -f ../conf/client.conf $(CONFIG_PATH)/client.conf.sample; fi
|
||||
if [ ! -f $(CONFIG_PATH)/client.conf.sample ]; then cp -f ../conf/client.conf $(CONFIG_PATH)/client.conf.sample; fi
|
||||
clean:
|
||||
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.SUFFIXES: .c .o
|
||||
|
||||
COMPILE = $(CC) -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -g -O -DDEBUG_FLAG -DOS_LINUX -DIOEVENT_USE_EPOLL
|
||||
INC_PATH = -I/usr/local/include/fastcommon -I/usr/local/include/fastdfs
|
||||
INC_PATH = -I/usr/include/fastcommon -I/usr/include/fastdfs
|
||||
LIB_PATH = -L/usr/local/lib -lfastcommon -lfdfsclient -lpthread -ldl -rdynamic
|
||||
TARGET_PATH = $(TARGET_PATH)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.SUFFIXES: .c .o
|
||||
|
||||
COMPILE = $(CC) $(CFLAGS)
|
||||
INC_PATH = -I/usr/local/include/fastcommon -I/usr/local/include/fastdfs
|
||||
INC_PATH = -I/usr/include/fastcommon -I/usr/include/fastdfs
|
||||
LIB_PATH = -L/usr/local/lib -lfastcommon -lfdfsclient $(LIBS)
|
||||
TARGET_PATH = $(TARGET_PATH)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,789 +0,0 @@
|
|||
#include "avl_tree.h"
|
||||
|
||||
int avl_tree_init(AVLTreeInfo *tree, FreeDataFunc free_data_func, \
|
||||
CompareFunc compare_func)
|
||||
{
|
||||
tree->root = NULL;
|
||||
tree->free_data_func = free_data_func;
|
||||
tree->compare_func = compare_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void avl_tree_destroy_loop(FreeDataFunc free_data_func, \
|
||||
AVLTreeNode *pCurrentNode)
|
||||
{
|
||||
if (pCurrentNode->left != NULL)
|
||||
{
|
||||
avl_tree_destroy_loop(free_data_func, pCurrentNode->left);
|
||||
}
|
||||
if (pCurrentNode->right != NULL)
|
||||
{
|
||||
avl_tree_destroy_loop(free_data_func, pCurrentNode->right);
|
||||
}
|
||||
|
||||
if (free_data_func != NULL)
|
||||
{
|
||||
free_data_func(pCurrentNode->data);
|
||||
}
|
||||
free(pCurrentNode);
|
||||
}
|
||||
|
||||
void avl_tree_destroy(AVLTreeInfo *tree)
|
||||
{
|
||||
if (tree == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (tree->root != NULL)
|
||||
{
|
||||
avl_tree_destroy_loop(tree->free_data_func, tree->root);
|
||||
tree->root = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static AVLTreeNode *createTreeNode(AVLTreeNode *pParentNode, void *target_data)
|
||||
{
|
||||
AVLTreeNode *pNewNode;
|
||||
pNewNode = (AVLTreeNode *)malloc(sizeof(AVLTreeNode));
|
||||
if (pNewNode == NULL)
|
||||
{
|
||||
/*
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes fail!\n", __LINE__, \
|
||||
(int)sizeof(AVLTreeNode));
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pNewNode->left = pNewNode->right = NULL;
|
||||
pNewNode->data = target_data;
|
||||
pNewNode->balance = 0;
|
||||
|
||||
return pNewNode;
|
||||
}
|
||||
|
||||
static void avlRotateLeft(AVLTreeNode *pRotateNode, AVLTreeNode **ppRaiseNode)
|
||||
{
|
||||
*ppRaiseNode = pRotateNode->right;
|
||||
pRotateNode->right = (*ppRaiseNode)->left;
|
||||
(*ppRaiseNode)->left = pRotateNode;
|
||||
}
|
||||
|
||||
static void avlRotateRight(AVLTreeNode *pRotateNode, AVLTreeNode **ppRaiseNode)
|
||||
{
|
||||
*ppRaiseNode = pRotateNode->left;
|
||||
pRotateNode->left = (*ppRaiseNode)->right;
|
||||
(*ppRaiseNode)->right = pRotateNode;
|
||||
}
|
||||
|
||||
static void avlLeftBalanceWhenInsert(AVLTreeNode **pTreeNode, int *taller)
|
||||
{
|
||||
AVLTreeNode *leftsub;
|
||||
AVLTreeNode *rightsub;
|
||||
|
||||
leftsub = (*pTreeNode)->left;
|
||||
switch (leftsub->balance)
|
||||
{
|
||||
case -1 :
|
||||
(*pTreeNode)->balance = leftsub->balance = 0;
|
||||
avlRotateRight (*pTreeNode, pTreeNode);
|
||||
*taller = 0;
|
||||
break;
|
||||
case 0 :
|
||||
break;
|
||||
case 1 :
|
||||
rightsub = leftsub->right;
|
||||
switch ( rightsub->balance )
|
||||
{
|
||||
case -1:
|
||||
(*pTreeNode)->balance = 1;
|
||||
leftsub->balance = 0;
|
||||
break;
|
||||
case 0 :
|
||||
(*pTreeNode)->balance = leftsub->balance = 0;
|
||||
break;
|
||||
case 1 :
|
||||
(*pTreeNode)->balance = 0;
|
||||
leftsub->balance = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
rightsub->balance = 0;
|
||||
avlRotateLeft( leftsub, &((*pTreeNode)->left));
|
||||
avlRotateRight(*pTreeNode, pTreeNode);
|
||||
*taller = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void avlRightBalanceWhenInsert(AVLTreeNode **pTreeNode, int *taller)
|
||||
{
|
||||
AVLTreeNode *rightsub;
|
||||
AVLTreeNode *leftsub;
|
||||
|
||||
rightsub = (*pTreeNode)->right;
|
||||
switch (rightsub->balance)
|
||||
{
|
||||
case 1:
|
||||
(*pTreeNode)->balance = rightsub->balance = 0;
|
||||
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||
*taller = 0;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
case -1:
|
||||
leftsub = rightsub->left;
|
||||
switch (leftsub->balance)
|
||||
{
|
||||
case 1 :
|
||||
(*pTreeNode)->balance = -1;
|
||||
rightsub->balance = 0;
|
||||
break;
|
||||
case 0 :
|
||||
(*pTreeNode)->balance = rightsub->balance = 0;
|
||||
break;
|
||||
case -1 :
|
||||
(*pTreeNode)->balance = 0;
|
||||
rightsub->balance = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
leftsub->balance = 0;
|
||||
avlRotateRight(rightsub, &((*pTreeNode)->right));
|
||||
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||
*taller = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int avl_tree_insert_loop(CompareFunc compare_func, AVLTreeNode **pCurrentNode, \
|
||||
void *target_data, int *taller)
|
||||
{
|
||||
int nCompRes;
|
||||
int success;
|
||||
|
||||
if (*pCurrentNode == NULL)
|
||||
{
|
||||
*pCurrentNode = createTreeNode(*pCurrentNode, target_data);
|
||||
if (*pCurrentNode != NULL)
|
||||
{
|
||||
*taller = 1;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
nCompRes = compare_func((*pCurrentNode)->data, target_data);
|
||||
if (nCompRes > 0)
|
||||
{
|
||||
success = avl_tree_insert_loop(compare_func, \
|
||||
&((*pCurrentNode)->left), target_data, taller);
|
||||
if (*taller != 0)
|
||||
{
|
||||
switch ((*pCurrentNode)->balance)
|
||||
{
|
||||
case -1:
|
||||
avlLeftBalanceWhenInsert(pCurrentNode, taller);
|
||||
break;
|
||||
case 0:
|
||||
(*pCurrentNode)->balance = -1;
|
||||
break;
|
||||
case 1:
|
||||
(*pCurrentNode)->balance = 0;
|
||||
*taller = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nCompRes < 0)
|
||||
{
|
||||
success = avl_tree_insert_loop(compare_func, \
|
||||
&((*pCurrentNode)->right), target_data, taller);
|
||||
if (*taller != 0)
|
||||
{
|
||||
switch ((*pCurrentNode)->balance)
|
||||
{
|
||||
case -1:
|
||||
(*pCurrentNode)->balance = 0;
|
||||
*taller = 0;
|
||||
break;
|
||||
case 0:
|
||||
(*pCurrentNode)->balance = 1;
|
||||
break;
|
||||
case 1:
|
||||
avlRightBalanceWhenInsert(pCurrentNode, taller);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
int avl_tree_insert(AVLTreeInfo *tree, void *data)
|
||||
{
|
||||
int taller;
|
||||
|
||||
taller = 0;
|
||||
return avl_tree_insert_loop(tree->compare_func, &(tree->root), \
|
||||
data, &taller);
|
||||
}
|
||||
|
||||
static int avl_tree_replace_loop(CompareFunc compare_func, \
|
||||
FreeDataFunc free_data_func, AVLTreeNode **pCurrentNode, \
|
||||
void *target_data, int *taller)
|
||||
{
|
||||
int nCompRes;
|
||||
int success;
|
||||
|
||||
if (*pCurrentNode == NULL )
|
||||
{
|
||||
*pCurrentNode = createTreeNode(*pCurrentNode, target_data);
|
||||
if (*pCurrentNode != NULL)
|
||||
{
|
||||
*taller = 1;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
nCompRes = compare_func((*pCurrentNode)->data, target_data);
|
||||
if (nCompRes > 0)
|
||||
{
|
||||
success = avl_tree_replace_loop(compare_func, free_data_func,
|
||||
&((*pCurrentNode)->left), target_data, taller);
|
||||
if (*taller != 0)
|
||||
{
|
||||
switch ((*pCurrentNode)->balance)
|
||||
{
|
||||
case -1:
|
||||
avlLeftBalanceWhenInsert(pCurrentNode, taller);
|
||||
break;
|
||||
case 0:
|
||||
(*pCurrentNode)->balance = -1;
|
||||
break;
|
||||
case 1:
|
||||
(*pCurrentNode)->balance = 0;
|
||||
*taller = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nCompRes < 0)
|
||||
{
|
||||
success = avl_tree_replace_loop(compare_func, free_data_func,
|
||||
&((*pCurrentNode)->right), target_data, taller);
|
||||
if (*taller != 0)
|
||||
{
|
||||
switch ((*pCurrentNode)->balance)
|
||||
{
|
||||
case -1 :
|
||||
(*pCurrentNode)->balance = 0;
|
||||
*taller = 0;
|
||||
break;
|
||||
case 0 :
|
||||
(*pCurrentNode)->balance = 1;
|
||||
break;
|
||||
case 1 :
|
||||
avlRightBalanceWhenInsert(pCurrentNode, taller);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (free_data_func != NULL)
|
||||
{
|
||||
free_data_func((*pCurrentNode)->data);
|
||||
}
|
||||
(*pCurrentNode)->data = target_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
int avl_tree_replace(AVLTreeInfo *tree, void *data)
|
||||
{
|
||||
int taller;
|
||||
|
||||
taller = 0;
|
||||
return avl_tree_replace_loop(tree->compare_func, \
|
||||
tree->free_data_func, &(tree->root), data, &taller);
|
||||
}
|
||||
|
||||
static AVLTreeNode *avl_tree_find_loop(CompareFunc compare_func, \
|
||||
AVLTreeNode *pCurrentNode, void *target_data)
|
||||
{
|
||||
int nCompRes;
|
||||
nCompRes = compare_func(pCurrentNode->data, target_data);
|
||||
if (nCompRes > 0)
|
||||
{
|
||||
if (pCurrentNode->left == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return avl_tree_find_loop(compare_func, \
|
||||
pCurrentNode->left, target_data);
|
||||
}
|
||||
}
|
||||
else if (nCompRes < 0)
|
||||
{
|
||||
if (pCurrentNode->right == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return avl_tree_find_loop(compare_func, \
|
||||
pCurrentNode->right, target_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return pCurrentNode;
|
||||
}
|
||||
}
|
||||
|
||||
static void *avl_tree_find_ge_loop(CompareFunc compare_func, \
|
||||
AVLTreeNode *pCurrentNode, void *target_data)
|
||||
{
|
||||
int nCompRes;
|
||||
void *found;
|
||||
|
||||
nCompRes = compare_func(pCurrentNode->data, target_data);
|
||||
if (nCompRes > 0)
|
||||
{
|
||||
if (pCurrentNode->left == NULL)
|
||||
{
|
||||
return pCurrentNode->data;
|
||||
}
|
||||
|
||||
found = avl_tree_find_ge_loop(compare_func, \
|
||||
pCurrentNode->left, target_data);
|
||||
return found != NULL ? found : pCurrentNode->data;
|
||||
}
|
||||
else if (nCompRes < 0)
|
||||
{
|
||||
if (pCurrentNode->right == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return avl_tree_find_ge_loop(compare_func, \
|
||||
pCurrentNode->right, target_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return pCurrentNode->data;
|
||||
}
|
||||
}
|
||||
|
||||
void *avl_tree_find(AVLTreeInfo *tree, void *target_data)
|
||||
{
|
||||
AVLTreeNode *found;
|
||||
|
||||
if (tree->root == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
found = avl_tree_find_loop(tree->compare_func, \
|
||||
tree->root, target_data);
|
||||
|
||||
return found != NULL ? found->data : NULL;
|
||||
}
|
||||
|
||||
void *avl_tree_find_ge(AVLTreeInfo *tree, void *target_data)
|
||||
{
|
||||
void *found;
|
||||
|
||||
if (tree->root == NULL)
|
||||
{
|
||||
found = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = avl_tree_find_ge_loop(tree->compare_func, \
|
||||
tree->root, target_data);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static void avlLeftBalanceWhenDelete(AVLTreeNode **pTreeNode, int *shorter)
|
||||
{
|
||||
AVLTreeNode *leftsub;
|
||||
AVLTreeNode *rightsub;
|
||||
|
||||
leftsub = (*pTreeNode)->left;
|
||||
switch (leftsub->balance)
|
||||
{
|
||||
case -1:
|
||||
(*pTreeNode)->balance = leftsub->balance = 0;
|
||||
avlRotateRight (*pTreeNode, pTreeNode);
|
||||
break;
|
||||
case 0:
|
||||
leftsub->balance = 1;
|
||||
avlRotateRight(*pTreeNode, pTreeNode);
|
||||
*shorter = 0;
|
||||
break;
|
||||
case 1:
|
||||
rightsub = leftsub->right;
|
||||
switch ( rightsub->balance )
|
||||
{
|
||||
case -1:
|
||||
(*pTreeNode)->balance = 1;
|
||||
leftsub->balance = 0;
|
||||
break;
|
||||
case 0 :
|
||||
(*pTreeNode)->balance = leftsub->balance = 0;
|
||||
break;
|
||||
case 1 :
|
||||
(*pTreeNode)->balance = 0;
|
||||
leftsub->balance = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
rightsub->balance = 0;
|
||||
avlRotateLeft( leftsub, &((*pTreeNode)->left));
|
||||
avlRotateRight(*pTreeNode, pTreeNode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void avlRightBalanceWhenDelete(AVLTreeNode **pTreeNode, int *shorter)
|
||||
{
|
||||
AVLTreeNode *rightsub;
|
||||
AVLTreeNode *leftsub;
|
||||
|
||||
rightsub = (*pTreeNode)->right;
|
||||
switch (rightsub->balance)
|
||||
{
|
||||
case 1:
|
||||
(*pTreeNode)->balance = rightsub->balance = 0;
|
||||
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||
break;
|
||||
case 0:
|
||||
rightsub->balance = -1;
|
||||
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||
*shorter = 0;
|
||||
break;
|
||||
case -1:
|
||||
leftsub = rightsub->left;
|
||||
switch (leftsub->balance)
|
||||
{
|
||||
case 1:
|
||||
(*pTreeNode)->balance = -1;
|
||||
rightsub->balance = 0;
|
||||
break;
|
||||
case 0:
|
||||
(*pTreeNode)->balance = rightsub->balance = 0;
|
||||
break;
|
||||
case -1:
|
||||
(*pTreeNode)->balance = 0;
|
||||
rightsub->balance = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
leftsub->balance = 0;
|
||||
avlRotateRight(rightsub, &((*pTreeNode)->right));
|
||||
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int avl_tree_delete_loop(AVLTreeInfo *tree, AVLTreeNode **pCurrentNode,\
|
||||
void *target_data, int *shorter, AVLTreeNode *pDeletedDataNode)
|
||||
{
|
||||
int nCompRes;
|
||||
bool result;
|
||||
AVLTreeNode *leftsub;
|
||||
AVLTreeNode *rightsub;
|
||||
|
||||
if (pDeletedDataNode != NULL)
|
||||
{
|
||||
if ((*pCurrentNode)->right == NULL)
|
||||
{
|
||||
pDeletedDataNode->data = (*pCurrentNode)->data;
|
||||
leftsub = (*pCurrentNode)->left;
|
||||
|
||||
free(*pCurrentNode);
|
||||
*pCurrentNode = leftsub;
|
||||
*shorter = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
nCompRes = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nCompRes = tree->compare_func((*pCurrentNode)->data, target_data);
|
||||
}
|
||||
|
||||
if (nCompRes > 0)
|
||||
{
|
||||
if ((*pCurrentNode)->left == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = avl_tree_delete_loop(tree, &((*pCurrentNode)->left), \
|
||||
target_data, shorter, pDeletedDataNode);
|
||||
if (*shorter != 0)
|
||||
{
|
||||
switch ((*pCurrentNode)->balance)
|
||||
{
|
||||
case -1:
|
||||
(*pCurrentNode)->balance = 0;
|
||||
break;
|
||||
case 0:
|
||||
(*pCurrentNode)->balance = 1;
|
||||
*shorter = 0;
|
||||
break;
|
||||
case 1:
|
||||
avlRightBalanceWhenDelete(pCurrentNode, shorter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if (nCompRes < 0)
|
||||
{
|
||||
if ((*pCurrentNode)->right == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = avl_tree_delete_loop(tree, &((*pCurrentNode)->right), \
|
||||
target_data, shorter, pDeletedDataNode);
|
||||
if (*shorter != 0)
|
||||
{
|
||||
switch ((*pCurrentNode)->balance)
|
||||
{
|
||||
case -1:
|
||||
avlLeftBalanceWhenDelete(pCurrentNode, shorter);
|
||||
break;
|
||||
case 0:
|
||||
(*pCurrentNode)->balance = -1;
|
||||
*shorter = 0;
|
||||
break;
|
||||
case 1:
|
||||
(*pCurrentNode)->balance = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tree->free_data_func != NULL)
|
||||
{
|
||||
tree->free_data_func((*pCurrentNode)->data);
|
||||
}
|
||||
|
||||
leftsub = (*pCurrentNode)->left;
|
||||
rightsub = (*pCurrentNode)->right;
|
||||
if (leftsub == NULL)
|
||||
{
|
||||
free(*pCurrentNode);
|
||||
*pCurrentNode = rightsub;
|
||||
}
|
||||
else if (rightsub == NULL)
|
||||
{
|
||||
free(*pCurrentNode);
|
||||
*pCurrentNode = leftsub;
|
||||
}
|
||||
else
|
||||
{
|
||||
avl_tree_delete_loop(tree, &((*pCurrentNode)->left), \
|
||||
target_data, shorter, *pCurrentNode);
|
||||
|
||||
if (*shorter != 0)
|
||||
{
|
||||
switch ((*pCurrentNode)->balance)
|
||||
{
|
||||
case -1:
|
||||
(*pCurrentNode)->balance = 0;
|
||||
break;
|
||||
case 0:
|
||||
(*pCurrentNode)->balance = 1;
|
||||
*shorter = 0;
|
||||
break;
|
||||
case 1:
|
||||
avlRightBalanceWhenDelete(pCurrentNode, shorter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
*shorter = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int avl_tree_delete(AVLTreeInfo *tree, void *data)
|
||||
{
|
||||
int shorter;
|
||||
|
||||
if (tree->root == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
shorter = 0;
|
||||
return avl_tree_delete_loop(tree, &(tree->root), data, &shorter, NULL);
|
||||
}
|
||||
|
||||
static int avl_tree_walk_loop(DataOpFunc data_op_func, \
|
||||
AVLTreeNode *pCurrentNode, void *args)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (pCurrentNode->left != NULL)
|
||||
{
|
||||
result = avl_tree_walk_loop(data_op_func, \
|
||||
pCurrentNode->left, args);
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if ((result=data_op_func(pCurrentNode->data, args)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
if (pCurrentNode->balance >= -1 && pCurrentNode->balance <= 1)
|
||||
{
|
||||
//printf("==%d\n", pCurrentNode->balance);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("==bad %d!!!!!!!!!!!!\n", pCurrentNode->balance);
|
||||
}
|
||||
*/
|
||||
|
||||
if (pCurrentNode->right != NULL)
|
||||
{
|
||||
result = avl_tree_walk_loop(data_op_func, \
|
||||
pCurrentNode->right, args);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int avl_tree_walk(AVLTreeInfo *tree, DataOpFunc data_op_func, void *args)
|
||||
{
|
||||
if (tree->root == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return avl_tree_walk_loop(data_op_func, tree->root, args);
|
||||
}
|
||||
}
|
||||
|
||||
static void avl_tree_count_loop(AVLTreeNode *pCurrentNode, int *count)
|
||||
{
|
||||
if (pCurrentNode->left != NULL)
|
||||
{
|
||||
avl_tree_count_loop(pCurrentNode->left, count);
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
|
||||
if (pCurrentNode->right != NULL)
|
||||
{
|
||||
avl_tree_count_loop(pCurrentNode->right, count);
|
||||
}
|
||||
}
|
||||
|
||||
int avl_tree_count(AVLTreeInfo *tree)
|
||||
{
|
||||
int count;
|
||||
if (tree->root == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
avl_tree_count_loop(tree->root, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
int avl_tree_depth(AVLTreeInfo *tree)
|
||||
{
|
||||
int depth;
|
||||
AVLTreeNode *pNode;
|
||||
|
||||
if (tree->root == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
depth = 0;
|
||||
pNode = tree->root;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
if (pNode->balance == -1)
|
||||
{
|
||||
pNode = pNode->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNode = pNode->right;
|
||||
}
|
||||
depth++;
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
/*
|
||||
static void avl_tree_print_loop(AVLTreeNode *pCurrentNode)
|
||||
{
|
||||
printf("%ld left: %ld, right: %ld, balance: %d\n", pCurrentNode->data,
|
||||
pCurrentNode->left != NULL ? pCurrentNode->left->data : 0,
|
||||
pCurrentNode->right != NULL ? pCurrentNode->right->data : 0,
|
||||
pCurrentNode->balance);
|
||||
|
||||
if (pCurrentNode->left != NULL)
|
||||
{
|
||||
avl_tree_print_loop(pCurrentNode->left);
|
||||
}
|
||||
|
||||
if (pCurrentNode->right != NULL)
|
||||
{
|
||||
avl_tree_print_loop(pCurrentNode->right);
|
||||
}
|
||||
}
|
||||
|
||||
void avl_tree_print(AVLTreeInfo *tree)
|
||||
{
|
||||
if (tree->root == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
avl_tree_print_loop(tree->root);
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
|
||||
#ifndef AVL_TREE_H
|
||||
#define AVL_TREE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include "common_define.h"
|
||||
|
||||
typedef struct tagAVLTreeNode {
|
||||
void *data;
|
||||
struct tagAVLTreeNode *left;
|
||||
struct tagAVLTreeNode *right;
|
||||
byte balance;
|
||||
} AVLTreeNode;
|
||||
|
||||
typedef int (*DataOpFunc) (void *data, void *args);
|
||||
|
||||
typedef struct tagAVLTreeInfo {
|
||||
AVLTreeNode *root;
|
||||
FreeDataFunc free_data_func;
|
||||
CompareFunc compare_func;
|
||||
} AVLTreeInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int avl_tree_init(AVLTreeInfo *tree, FreeDataFunc free_data_func, \
|
||||
CompareFunc compare_func);
|
||||
void avl_tree_destroy(AVLTreeInfo *tree);
|
||||
|
||||
int avl_tree_insert(AVLTreeInfo *tree, void *data);
|
||||
int avl_tree_replace(AVLTreeInfo *tree, void *data);
|
||||
int avl_tree_delete(AVLTreeInfo *tree, void *data);
|
||||
void *avl_tree_find(AVLTreeInfo *tree, void *target_data);
|
||||
void *avl_tree_find_ge(AVLTreeInfo *tree, void *target_data);
|
||||
int avl_tree_walk(AVLTreeInfo *tree, DataOpFunc data_op_func, void *args);
|
||||
int avl_tree_count(AVLTreeInfo *tree);
|
||||
int avl_tree_depth(AVLTreeInfo *tree);
|
||||
//void avl_tree_print(AVLTreeInfo *tree);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
393
common/base64.c
393
common/base64.c
|
|
@ -1,393 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "base64.h"
|
||||
|
||||
/**
|
||||
* Marker value for chars we just ignore, e.g. \n \r high ascii
|
||||
*/
|
||||
#define BASE64_IGNORE -1
|
||||
|
||||
/**
|
||||
* Marker for = trailing pad
|
||||
*/
|
||||
#define BASE64_PAD -2
|
||||
|
||||
/**
|
||||
* determines how long the lines are that are generated by encode.
|
||||
* Ignored by decode.
|
||||
* @param length 0 means no newlines inserted. Must be a multiple of 4.
|
||||
*/
|
||||
void base64_set_line_length(struct base64_context *context, const int length)
|
||||
{
|
||||
context->line_length = (length / 4) * 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* How lines are separated.
|
||||
* Ignored by decode.
|
||||
* @param context->line_separator may be "" but not null.
|
||||
* Usually contains only a combination of chars \n and \r.
|
||||
* Could be any chars not in set A-Z a-z 0-9 + /.
|
||||
*/
|
||||
void base64_set_line_separator(struct base64_context *context, \
|
||||
const char *pLineSeparator)
|
||||
{
|
||||
context->line_sep_len = snprintf(context->line_separator, \
|
||||
sizeof(context->line_separator), "%s", pLineSeparator);
|
||||
}
|
||||
|
||||
void base64_init_ex(struct base64_context *context, const int nLineLength, \
|
||||
const unsigned char chPlus, const unsigned char chSplash, \
|
||||
const unsigned char chPad)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(context, 0, sizeof(struct base64_context));
|
||||
|
||||
context->line_length = nLineLength;
|
||||
context->line_separator[0] = '\n';
|
||||
context->line_separator[1] = '\0';
|
||||
context->line_sep_len = 1;
|
||||
|
||||
// build translate valueToChar table only once.
|
||||
// 0..25 -> 'A'..'Z'
|
||||
for (i=0; i<=25; i++)
|
||||
{
|
||||
context->valueToChar[i] = (char)('A'+i);
|
||||
}
|
||||
// 26..51 -> 'a'..'z'
|
||||
for (i=0; i<=25; i++ )
|
||||
{
|
||||
context->valueToChar[i+26] = (char)('a'+i);
|
||||
}
|
||||
// 52..61 -> '0'..'9'
|
||||
for (i=0; i<=9; i++ )
|
||||
{
|
||||
context->valueToChar[i+52] = (char)('0'+i);
|
||||
}
|
||||
context->valueToChar[62] = chPlus;
|
||||
context->valueToChar[63] = chSplash;
|
||||
|
||||
memset(context->charToValue, BASE64_IGNORE, sizeof(context->charToValue));
|
||||
for (i=0; i<64; i++ )
|
||||
{
|
||||
context->charToValue[context->valueToChar[i]] = i;
|
||||
}
|
||||
|
||||
context->pad_ch = chPad;
|
||||
context->charToValue[chPad] = BASE64_PAD;
|
||||
}
|
||||
|
||||
int base64_get_encode_length(struct base64_context *context, const int nSrcLen)
|
||||
{
|
||||
// Each group or partial group of 3 bytes becomes four chars
|
||||
// covered quotient
|
||||
int outputLength;
|
||||
|
||||
outputLength = ((nSrcLen + 2) / 3) * 4;
|
||||
|
||||
// account for trailing newlines, on all but the very last line
|
||||
if (context->line_length != 0)
|
||||
{
|
||||
int lines = (outputLength + context->line_length - 1) /
|
||||
context->line_length - 1;
|
||||
if ( lines > 0 )
|
||||
{
|
||||
outputLength += lines * context->line_sep_len;
|
||||
}
|
||||
}
|
||||
|
||||
return outputLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an arbitrary array of bytes as base64 printable ASCII.
|
||||
* It will be broken into lines of 72 chars each. The last line is not
|
||||
* terminated with a line separator.
|
||||
* The output will always have an even multiple of data characters,
|
||||
* exclusive of \n. It is padded out with =.
|
||||
*/
|
||||
char *base64_encode_ex(struct base64_context *context, const char *src, \
|
||||
const int nSrcLen, char *dest, int *dest_len, const bool bPad)
|
||||
{
|
||||
int linePos;
|
||||
int leftover;
|
||||
int combined;
|
||||
char *pDest;
|
||||
int c0, c1, c2, c3;
|
||||
unsigned char *pRaw;
|
||||
unsigned char *pEnd;
|
||||
const char *ppSrcs[2];
|
||||
int lens[2];
|
||||
char szPad[3];
|
||||
int k;
|
||||
int loop;
|
||||
|
||||
if (nSrcLen <= 0)
|
||||
{
|
||||
*dest = '\0';
|
||||
*dest_len = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
linePos = 0;
|
||||
lens[0] = (nSrcLen / 3) * 3;
|
||||
lens[1] = 3;
|
||||
leftover = nSrcLen - lens[0];
|
||||
ppSrcs[0] = src;
|
||||
ppSrcs[1] = szPad;
|
||||
|
||||
szPad[0] = szPad[1] = szPad[2] = '\0';
|
||||
switch (leftover)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
loop = 1;
|
||||
break;
|
||||
case 1:
|
||||
loop = 2;
|
||||
szPad[0] = src[nSrcLen-1];
|
||||
break;
|
||||
case 2:
|
||||
loop = 2;
|
||||
szPad[0] = src[nSrcLen-2];
|
||||
szPad[1] = src[nSrcLen-1];
|
||||
break;
|
||||
}
|
||||
|
||||
pDest = dest;
|
||||
for (k=0; k<loop; k++)
|
||||
{
|
||||
pEnd = (unsigned char *)ppSrcs[k] + lens[k];
|
||||
for (pRaw=(unsigned char *)ppSrcs[k]; pRaw<pEnd; pRaw+=3)
|
||||
{
|
||||
// Start a new line if next 4 chars won't fit on the current line
|
||||
// We can't encapsulete the following code since the variable need to
|
||||
// be local to this incarnation of encode.
|
||||
linePos += 4;
|
||||
if (linePos > context->line_length)
|
||||
{
|
||||
if (context->line_length != 0)
|
||||
{
|
||||
memcpy(pDest, context->line_separator, context->line_sep_len);
|
||||
pDest += context->line_sep_len;
|
||||
}
|
||||
linePos = 4;
|
||||
}
|
||||
|
||||
// get next three bytes in unsigned form lined up,
|
||||
// in big-endian order
|
||||
combined = ((*pRaw) << 16) | ((*(pRaw+1)) << 8) | (*(pRaw+2));
|
||||
|
||||
// break those 24 bits into a 4 groups of 6 bits,
|
||||
// working LSB to MSB.
|
||||
c3 = combined & 0x3f;
|
||||
combined >>= 6;
|
||||
c2 = combined & 0x3f;
|
||||
combined >>= 6;
|
||||
c1 = combined & 0x3f;
|
||||
combined >>= 6;
|
||||
c0 = combined & 0x3f;
|
||||
|
||||
// Translate into the equivalent alpha character
|
||||
// emitting them in big-endian order.
|
||||
*pDest++ = context->valueToChar[c0];
|
||||
*pDest++ = context->valueToChar[c1];
|
||||
*pDest++ = context->valueToChar[c2];
|
||||
*pDest++ = context->valueToChar[c3];
|
||||
}
|
||||
}
|
||||
|
||||
*pDest = '\0';
|
||||
*dest_len = pDest - dest;
|
||||
|
||||
// deal with leftover bytes
|
||||
switch (leftover)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
// nothing to do
|
||||
break;
|
||||
case 1:
|
||||
// One leftover byte generates xx==
|
||||
if (bPad)
|
||||
{
|
||||
*(pDest-1) = context->pad_ch;
|
||||
*(pDest-2) = context->pad_ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(pDest-2) = '\0';
|
||||
*dest_len -= 2;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Two leftover bytes generates xxx=
|
||||
if (bPad)
|
||||
{
|
||||
*(pDest-1) = context->pad_ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(pDest-1) = '\0';
|
||||
*dest_len -= 1;
|
||||
}
|
||||
break;
|
||||
} // end switch;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *base64_decode_auto(struct base64_context *context, const char *src, \
|
||||
const int nSrcLen, char *dest, int *dest_len)
|
||||
{
|
||||
int nRemain;
|
||||
int nPadLen;
|
||||
int nNewLen;
|
||||
char tmpBuff[256];
|
||||
char *pBuff;
|
||||
|
||||
nRemain = nSrcLen % 4;
|
||||
if (nRemain == 0)
|
||||
{
|
||||
return base64_decode(context, src, nSrcLen, dest, dest_len);
|
||||
}
|
||||
|
||||
nPadLen = 4 - nRemain;
|
||||
nNewLen = nSrcLen + nPadLen;
|
||||
if (nNewLen <= sizeof(tmpBuff))
|
||||
{
|
||||
pBuff = tmpBuff;
|
||||
}
|
||||
else
|
||||
{
|
||||
pBuff = (char *)malloc(nNewLen);
|
||||
if (pBuff == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't malloc %d bytes\n", \
|
||||
nSrcLen + nPadLen + 1);
|
||||
*dest_len = 0;
|
||||
*dest = '\0';
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(pBuff, src, nSrcLen);
|
||||
memset(pBuff + nSrcLen, context->pad_ch, nPadLen);
|
||||
|
||||
base64_decode(context, pBuff, nNewLen, dest, dest_len);
|
||||
|
||||
if (pBuff != tmpBuff)
|
||||
{
|
||||
free(pBuff);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode a well-formed complete base64 string back into an array of bytes.
|
||||
* It must have an even multiple of 4 data characters (not counting \n),
|
||||
* padded out with = as needed.
|
||||
*/
|
||||
char *base64_decode(struct base64_context *context, const char *src, \
|
||||
const int nSrcLen, char *dest, int *dest_len)
|
||||
{
|
||||
// tracks where we are in a cycle of 4 input chars.
|
||||
int cycle;
|
||||
|
||||
// where we combine 4 groups of 6 bits and take apart as 3 groups of 8.
|
||||
int combined;
|
||||
|
||||
// will be an even multiple of 4 chars, plus some embedded \n
|
||||
int dummies;
|
||||
int value;
|
||||
unsigned char *pSrc;
|
||||
unsigned char *pSrcEnd;
|
||||
char *pDest;
|
||||
|
||||
cycle = 0;
|
||||
combined = 0;
|
||||
dummies = 0;
|
||||
pDest = dest;
|
||||
pSrcEnd = (unsigned char *)src + nSrcLen;
|
||||
for (pSrc=(unsigned char *)src; pSrc<pSrcEnd; pSrc++)
|
||||
{
|
||||
value = context->charToValue[*pSrc];
|
||||
switch (value)
|
||||
{
|
||||
case BASE64_IGNORE:
|
||||
// e.g. \n, just ignore it.
|
||||
break;
|
||||
case BASE64_PAD:
|
||||
value = 0;
|
||||
dummies++;
|
||||
// fallthrough
|
||||
default:
|
||||
/* regular value character */
|
||||
switch (cycle)
|
||||
{
|
||||
case 0:
|
||||
combined = value;
|
||||
cycle = 1;
|
||||
break;
|
||||
case 1:
|
||||
combined <<= 6;
|
||||
combined |= value;
|
||||
cycle = 2;
|
||||
break;
|
||||
case 2:
|
||||
combined <<= 6;
|
||||
combined |= value;
|
||||
cycle = 3;
|
||||
break;
|
||||
case 3:
|
||||
combined <<= 6;
|
||||
combined |= value;
|
||||
// we have just completed a cycle of 4 chars.
|
||||
// the four 6-bit values are in combined in big-endian order
|
||||
// peel them off 8 bits at a time working lsb to msb
|
||||
// to get our original 3 8-bit bytes back
|
||||
|
||||
*pDest++ = (char)(combined >> 16);
|
||||
*pDest++ = (char)((combined & 0x0000FF00) >> 8);
|
||||
*pDest++ = (char)(combined & 0x000000FF);
|
||||
|
||||
cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // end for
|
||||
|
||||
if (cycle != 0)
|
||||
{
|
||||
*dest = '\0';
|
||||
*dest_len = 0;
|
||||
fprintf(stderr, "Input to decode not an even multiple of " \
|
||||
"4 characters; pad with %c\n", context->pad_ch);
|
||||
return dest;
|
||||
}
|
||||
|
||||
*dest_len = (pDest - dest) - dummies;
|
||||
*(dest + (*dest_len)) = '\0';
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
134
common/base64.h
134
common/base64.h
|
|
@ -1,134 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//base64.h
|
||||
|
||||
#ifndef _BASE64_H
|
||||
#define _BASE64_H
|
||||
|
||||
#include "common_define.h"
|
||||
|
||||
struct base64_context
|
||||
{
|
||||
char line_separator[16];
|
||||
int line_sep_len;
|
||||
|
||||
/**
|
||||
* max chars per line, excluding line_separator. A multiple of 4.
|
||||
*/
|
||||
int line_length;
|
||||
|
||||
/**
|
||||
* letter of the alphabet used to encode binary values 0..63
|
||||
*/
|
||||
unsigned char valueToChar[64];
|
||||
|
||||
/**
|
||||
* binary value encoded by a given letter of the alphabet 0..63
|
||||
*/
|
||||
int charToValue[256];
|
||||
int pad_ch;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** use stardand base64 charset
|
||||
*/
|
||||
#define base64_init(context, nLineLength) \
|
||||
base64_init_ex(context, nLineLength, '+', '/', '=')
|
||||
|
||||
|
||||
/** stardand base64 encode
|
||||
*/
|
||||
#define base64_encode(context, src, nSrcLen, dest, dest_len) \
|
||||
base64_encode_ex(context, src, nSrcLen, dest, dest_len, true)
|
||||
|
||||
/** base64 init function, before use base64 function, you should call
|
||||
* this function
|
||||
* parameters:
|
||||
* context: the base64 context
|
||||
* nLineLength: length of a line, 0 for never add line seperator
|
||||
* chPlus: specify a char for base64 char plus (+)
|
||||
* chSplash: specify a char for base64 char splash (/)
|
||||
* chPad: specify a char for base64 padding char =
|
||||
* return: none
|
||||
*/
|
||||
void base64_init_ex(struct base64_context *context, const int nLineLength, \
|
||||
const unsigned char chPlus, const unsigned char chSplash, \
|
||||
const unsigned char chPad);
|
||||
|
||||
/** calculate the encoded length of the source buffer
|
||||
* parameters:
|
||||
* context: the base64 context
|
||||
* nSrcLen: the source buffer length
|
||||
* return: the encoded length of the source buffer
|
||||
*/
|
||||
int base64_get_encode_length(struct base64_context *context, const int nSrcLen);
|
||||
|
||||
/** base64 encode buffer
|
||||
* parameters:
|
||||
* context: the base64 context
|
||||
* src: the source buffer
|
||||
* nSrcLen: the source buffer length
|
||||
* dest: the dest buffer
|
||||
* dest_len: return dest buffer length
|
||||
* bPad: if padding
|
||||
* return: the encoded buffer
|
||||
*/
|
||||
char *base64_encode_ex(struct base64_context *context, const char *src, \
|
||||
const int nSrcLen, char *dest, int *dest_len, const bool bPad);
|
||||
|
||||
/** base64 decode buffer, work only with padding source string
|
||||
* parameters:
|
||||
* context: the base64 context
|
||||
* src: the source buffer with padding
|
||||
* nSrcLen: the source buffer length
|
||||
* dest: the dest buffer
|
||||
* dest_len: return dest buffer length
|
||||
* return: the decoded buffer
|
||||
*/
|
||||
char *base64_decode(struct base64_context *context, const char *src, \
|
||||
const int nSrcLen, char *dest, int *dest_len);
|
||||
|
||||
/** base64 decode buffer, can work with no padding source string
|
||||
* parameters:
|
||||
* context: the base64 context
|
||||
* src: the source buffer with padding or no padding
|
||||
* nSrcLen: the source buffer length
|
||||
* dest: the dest buffer
|
||||
* dest_len: return dest buffer length
|
||||
* return: the decoded buffer
|
||||
*/
|
||||
char *base64_decode_auto(struct base64_context *context, const char *src, \
|
||||
const int nSrcLen, char *dest, int *dest_len);
|
||||
|
||||
/** set line separator string, such as \n or \r\n
|
||||
* parameters:
|
||||
* context: the base64 context
|
||||
* pLineSeparator: the line separator string
|
||||
* return: none
|
||||
*/
|
||||
void base64_set_line_separator(struct base64_context *context, \
|
||||
const char *pLineSeparator);
|
||||
|
||||
/** set line length, 0 for never add line separators
|
||||
* parameters:
|
||||
* context: the base64 context
|
||||
* length: the line length
|
||||
* return: none
|
||||
*/
|
||||
void base64_set_line_length(struct base64_context *context, const int length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
325
common/chain.c
325
common/chain.c
|
|
@ -1,325 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "chain.h"
|
||||
//#include "use_mmalloc.h"
|
||||
|
||||
void chain_init(ChainList *pList, const int type, FreeDataFunc freeDataFunc, \
|
||||
CompareFunc compareFunc)
|
||||
{
|
||||
if (pList == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pList->head = NULL;
|
||||
pList->tail = NULL;
|
||||
pList->type = type;
|
||||
pList->freeDataFunc = freeDataFunc;
|
||||
pList->compareFunc = compareFunc;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void chain_destroy(ChainList *pList)
|
||||
{
|
||||
ChainNode *pNode;
|
||||
ChainNode *pDeleted;
|
||||
if (pList == NULL || pList->head == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pNode = pList->head;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
pDeleted = pNode;
|
||||
pNode = pNode->next;
|
||||
|
||||
freeChainNode(pList, pDeleted);
|
||||
}
|
||||
|
||||
pList->head = pList->tail = NULL;
|
||||
}
|
||||
|
||||
void freeChainNode(ChainList *pList, ChainNode *pChainNode)
|
||||
{
|
||||
if (pList->freeDataFunc != NULL)
|
||||
{
|
||||
pList->freeDataFunc(pChainNode->data);
|
||||
}
|
||||
|
||||
free(pChainNode);
|
||||
}
|
||||
|
||||
int insertNodePrior(ChainList *pList, void *data)
|
||||
{
|
||||
ChainNode *pNode;
|
||||
if (pList == NULL)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
pNode = (ChainNode *)malloc(sizeof(ChainNode));
|
||||
if (pNode == NULL)
|
||||
{
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
pNode->data = data;
|
||||
pNode->next = pList->head;
|
||||
|
||||
pList->head = pNode;
|
||||
if (pList->tail == NULL)
|
||||
{
|
||||
pList->tail = pNode;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int appendNode(ChainList *pList, void *data)
|
||||
{
|
||||
ChainNode *pNode;
|
||||
if (pList == NULL)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
pNode = (ChainNode *)malloc(sizeof(ChainNode));
|
||||
if (pNode == NULL)
|
||||
{
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
pNode->data = data;
|
||||
pNode->next = NULL;
|
||||
|
||||
if (pList->tail != NULL)
|
||||
{
|
||||
pList->tail->next = pNode;
|
||||
}
|
||||
|
||||
pList->tail = pNode;
|
||||
if (pList->head == NULL)
|
||||
{
|
||||
pList->head = pNode;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int insertNodeAsc(ChainList *pList, void *data)
|
||||
{
|
||||
ChainNode *pNew;
|
||||
ChainNode *pNode;
|
||||
ChainNode *pPrevious;
|
||||
if (pList == NULL || pList->compareFunc == NULL)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
pNew = (ChainNode *)malloc(sizeof(ChainNode));
|
||||
if (pNew == NULL)
|
||||
{
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
pNew->data = data;
|
||||
|
||||
pPrevious = NULL;
|
||||
pNode = pList->head;
|
||||
while (pNode != NULL && pList->compareFunc(pNode->data, data) < 0)
|
||||
{
|
||||
pPrevious = pNode;
|
||||
pNode = pNode->next;
|
||||
}
|
||||
|
||||
pNew->next = pNode;
|
||||
if (pPrevious == NULL)
|
||||
{
|
||||
pList->head = pNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrevious->next = pNew;
|
||||
}
|
||||
|
||||
if (pNode == NULL)
|
||||
{
|
||||
pList->tail = pNew;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addNode(ChainList *pList, void *data)
|
||||
{
|
||||
if (pList->type == CHAIN_TYPE_INSERT)
|
||||
{
|
||||
return insertNodePrior(pList, data);
|
||||
}
|
||||
else if (pList->type == CHAIN_TYPE_APPEND)
|
||||
{
|
||||
return appendNode(pList, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
return insertNodeAsc(pList, data);
|
||||
}
|
||||
}
|
||||
|
||||
void deleteNodeEx(ChainList *pList, ChainNode *pPreviousNode, \
|
||||
ChainNode *pDeletedNode)
|
||||
{
|
||||
if (pDeletedNode == pList->head)
|
||||
{
|
||||
pList->head = pDeletedNode->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPreviousNode->next = pDeletedNode->next;
|
||||
}
|
||||
|
||||
if (pDeletedNode == pList->tail)
|
||||
{
|
||||
pList->tail = pPreviousNode;
|
||||
}
|
||||
|
||||
freeChainNode(pList, pDeletedNode);
|
||||
}
|
||||
|
||||
void deleteToNodePrevious(ChainList *pList, ChainNode *pPreviousNode, \
|
||||
ChainNode *pDeletedNext)
|
||||
{
|
||||
ChainNode *pNode;
|
||||
ChainNode *pDeletedNode;
|
||||
|
||||
if (pPreviousNode == NULL)
|
||||
{
|
||||
pNode = pList->head;
|
||||
pList->head = pDeletedNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNode = pPreviousNode->next;
|
||||
pPreviousNode->next = pDeletedNext;
|
||||
}
|
||||
|
||||
while (pNode != NULL && pNode != pDeletedNext)
|
||||
{
|
||||
pDeletedNode = pNode;
|
||||
pNode = pNode->next;
|
||||
freeChainNode(pList, pDeletedNode);
|
||||
}
|
||||
|
||||
if (pDeletedNext == NULL)
|
||||
{
|
||||
pList->tail = pPreviousNode;
|
||||
}
|
||||
}
|
||||
|
||||
void *chain_pop_head(ChainList *pList)
|
||||
{
|
||||
ChainNode *pDeletedNode;
|
||||
void *data;
|
||||
|
||||
pDeletedNode = pList->head;
|
||||
if (pDeletedNode == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pList->head = pDeletedNode->next;
|
||||
if (pList->head == NULL)
|
||||
{
|
||||
pList->tail = NULL;
|
||||
}
|
||||
|
||||
data = pDeletedNode->data;
|
||||
free(pDeletedNode);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int chain_count(ChainList *pList)
|
||||
{
|
||||
ChainNode *pNode;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
pNode = pList->head;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
count++;
|
||||
pNode = pNode->next;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int deleteNode(ChainList *pList, void *data, bool bDeleteAll)
|
||||
{
|
||||
ChainNode *pNode;
|
||||
ChainNode *pPrevious;
|
||||
ChainNode *pDeleted;
|
||||
int nCount;
|
||||
int nCompareRes;
|
||||
|
||||
if (pList == NULL || pList->compareFunc == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nCount = 0;
|
||||
pPrevious = NULL;
|
||||
pNode = pList->head;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
nCompareRes = pList->compareFunc(pNode->data, data);
|
||||
if (nCompareRes == 0)
|
||||
{
|
||||
pDeleted = pNode;
|
||||
pNode = pNode->next;
|
||||
|
||||
deleteNodeEx(pList, pPrevious, pDeleted);
|
||||
nCount++;
|
||||
|
||||
if (!bDeleteAll)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if(nCompareRes > 0 && pList->type == CHAIN_TYPE_SORTED)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pPrevious = pNode;
|
||||
pNode = pNode->next;
|
||||
}
|
||||
|
||||
return nCount;
|
||||
}
|
||||
|
||||
int deleteOne(ChainList *pList, void *data)
|
||||
{
|
||||
return deleteNode(pList, data, false);
|
||||
}
|
||||
|
||||
int deleteAll(ChainList *pList, void *data)
|
||||
{
|
||||
return deleteNode(pList, data, true);
|
||||
}
|
||||
|
||||
148
common/chain.h
148
common/chain.h
|
|
@ -1,148 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#ifndef CHAIN_H
|
||||
#define CHAIN_H
|
||||
|
||||
#include "common_define.h"
|
||||
|
||||
#define CHAIN_TYPE_INSERT 0 //insert new node before head
|
||||
#define CHAIN_TYPE_APPEND 1 //insert new node after tail
|
||||
#define CHAIN_TYPE_SORTED 2 //sorted chain
|
||||
|
||||
typedef struct tagChainNode
|
||||
{
|
||||
void *data;
|
||||
struct tagChainNode *next;
|
||||
} ChainNode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
ChainNode *head;
|
||||
ChainNode *tail;
|
||||
FreeDataFunc freeDataFunc;
|
||||
CompareFunc compareFunc;
|
||||
} ChainList;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** chain init function
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* type: chain type, value is one of following:
|
||||
* CHAIN_TYPE_INSERT: insert new node before head
|
||||
* CHAIN_TYPE_APPEND: insert new node after tail
|
||||
* CHAIN_TYPE_SORTED: sorted chain
|
||||
* freeDataFunc: free data function pointer, can be NULL
|
||||
* compareFunc: compare data function pointer, can be NULL,
|
||||
* must set when type is CHAIN_TYPE_SORTED
|
||||
* return: none
|
||||
*/
|
||||
void chain_init(ChainList *pList, const int type, FreeDataFunc freeDataFunc, \
|
||||
CompareFunc compareFunc);
|
||||
|
||||
/** destroy chain
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* return: none
|
||||
*/
|
||||
void chain_destroy(ChainList *pList);
|
||||
|
||||
|
||||
/** get the chain node count
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* return: chain node count
|
||||
*/
|
||||
int chain_count(ChainList *pList);
|
||||
|
||||
/** add a new node to the chain
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* data: the data to add
|
||||
* return: error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int addNode(ChainList *pList, void *data);
|
||||
|
||||
/** free the chain node
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* pChainNode: the chain node to free
|
||||
* return: none
|
||||
*/
|
||||
void freeChainNode(ChainList *pList, ChainNode *pChainNode);
|
||||
|
||||
/** delete the chain node
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* pPreviousNode: the previous chain node
|
||||
* pDeletedNode: the chain node to delete
|
||||
* return: none
|
||||
*/
|
||||
void deleteNodeEx(ChainList *pList, ChainNode *pPreviousNode, \
|
||||
ChainNode *pDeletedNode);
|
||||
|
||||
/** delete the chain nodes from pPreviousNode->next to pDeletedNext
|
||||
* (not including pDeletedNext)
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* pPreviousNode: the previous chain node, delete from pPreviousNode->next
|
||||
* pDeletedNext: the chain node after the deleted node
|
||||
* return: none
|
||||
*/
|
||||
void deleteToNodePrevious(ChainList *pList, ChainNode *pPreviousNode, \
|
||||
ChainNode *pDeletedNext);
|
||||
|
||||
/** delete the chain node using data compare function
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* data: the first node whose data equals this will be deleted
|
||||
* return: delete chain node count, < 0 fail
|
||||
*/
|
||||
int deleteOne(ChainList *pList, void *data);
|
||||
|
||||
/** delete all chain nodes using data compare function
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* data: the node whose data equals this will be deleted
|
||||
* return: delete chain node count, < 0 fail
|
||||
*/
|
||||
int deleteAll(ChainList *pList, void *data);
|
||||
|
||||
/** pop up a chain nodes from chain head
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* return: the head node, return NULL when the chain is empty
|
||||
*/
|
||||
void *chain_pop_head(ChainList *pList);
|
||||
|
||||
/** add a chain nodes before the chain head
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* data: the node to insert
|
||||
* return: error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int insertNodePrior(ChainList *pList, void *data);
|
||||
|
||||
/** add a chain nodes after the chain tail
|
||||
* parameters:
|
||||
* pList: the chain list
|
||||
* data: the node to insert
|
||||
* return: error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int appendNode(ChainList *pList, void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//common_define.h
|
||||
|
||||
#ifndef _COMMON_DEFINE_H_
|
||||
#define _COMMON_DEFINE_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include <windows.h>
|
||||
#include <winsock.h>
|
||||
typedef UINT in_addr_t;
|
||||
#define FILE_SEPERATOR "\\"
|
||||
#define THREAD_ENTRANCE_FUNC_DECLARE DWORD WINAPI
|
||||
#define THREAD_RETURN_VALUE 0
|
||||
typedef DWORD (WINAPI *ThreadEntranceFunc)(LPVOID lpThreadParameter);
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#define FILE_SEPERATOR "/"
|
||||
typedef int SOCKET;
|
||||
#define closesocket close
|
||||
#define INVALID_SOCKET -1
|
||||
#define THREAD_ENTRANCE_FUNC_DECLARE void *
|
||||
typedef void *LPVOID;
|
||||
#define THREAD_RETURN_VALUE NULL
|
||||
typedef void * (*ThreadEntranceFunc)(LPVOID lpThreadParameter);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
|
||||
#endif
|
||||
|
||||
#ifdef OS_LINUX
|
||||
#define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
|
||||
#endif
|
||||
|
||||
#include "_os_bits.h"
|
||||
|
||||
#ifdef OS_BITS
|
||||
#if OS_BITS == 64
|
||||
#define INT64_PRINTF_FORMAT "%ld"
|
||||
#else
|
||||
#define INT64_PRINTF_FORMAT "%lld"
|
||||
#endif
|
||||
#else
|
||||
#define INT64_PRINTF_FORMAT "%lld"
|
||||
#endif
|
||||
|
||||
#ifdef OFF_BITS
|
||||
#if OFF_BITS == 64
|
||||
#define OFF_PRINTF_FORMAT INT64_PRINTF_FORMAT
|
||||
#else
|
||||
#define OFF_PRINTF_FORMAT "%d"
|
||||
#endif
|
||||
#else
|
||||
#define OFF_PRINTF_FORMAT INT64_PRINTF_FORMAT
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#define USE_SENDFILE
|
||||
#endif
|
||||
|
||||
#define MAX_PATH_SIZE 256
|
||||
#define LOG_FILE_DIR "logs"
|
||||
#define CONF_FILE_DIR "conf"
|
||||
#define DEFAULT_CONNECT_TIMEOUT 30
|
||||
#define DEFAULT_NETWORK_TIMEOUT 30
|
||||
#define DEFAULT_MAX_CONNECTONS 256
|
||||
#define DEFAULT_WORK_THREADS 4
|
||||
#define SYNC_LOG_BUFF_DEF_INTERVAL 10
|
||||
#define TIME_NONE -1
|
||||
|
||||
#define IP_ADDRESS_SIZE 16
|
||||
#define INFINITE_FILE_SIZE (256 * 1024LL * 1024 * 1024 * 1024 * 1024LL)
|
||||
|
||||
#ifndef byte
|
||||
#define byte signed char
|
||||
#endif
|
||||
|
||||
#ifndef ubyte
|
||||
#define ubyte unsigned char
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE ((in_addr_t) 0xffffffff)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ECANCELED
|
||||
#define ECANCELED 125
|
||||
#endif
|
||||
|
||||
#ifndef ENONET
|
||||
#define ENONET 64 /* Machine is not on the network */
|
||||
#endif
|
||||
|
||||
#define IS_UPPER_HEX(ch) ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F'))
|
||||
#define STRERROR(no) (strerror(no) != NULL ? strerror(no) : "Unkown error")
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte hour;
|
||||
byte minute;
|
||||
} TimeInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char major;
|
||||
char minor;
|
||||
} Version;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *key;
|
||||
char *value;
|
||||
} KeyValuePair;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *buff;
|
||||
int alloc_size;
|
||||
int length;
|
||||
} BufferInfo;
|
||||
|
||||
typedef void (*FreeDataFunc)(void *ptr);
|
||||
typedef int (*CompareFunc)(void *p1, void *p2);
|
||||
typedef void* (*MallocFunc)(size_t size);
|
||||
|
||||
#define TO_UPPERCASE(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 32 : c)
|
||||
#define MEM_ALIGN(x) (((x) + 7) & (~7))
|
||||
|
||||
#ifdef WIN32
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,350 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "logger.h"
|
||||
#include "sockopt.h"
|
||||
#include "shared_func.h"
|
||||
#include "sched_thread.h"
|
||||
#include "connection_pool.h"
|
||||
|
||||
int conn_pool_init(ConnectionPool *cp, int connect_timeout, \
|
||||
const int max_count_per_entry, const int max_idle_time)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result=init_pthread_lock(&cp->lock)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
cp->connect_timeout = connect_timeout;
|
||||
cp->max_count_per_entry = max_count_per_entry;
|
||||
cp->max_idle_time = max_idle_time;
|
||||
|
||||
return hash_init(&(cp->hash_array), simple_hash, 1024, 0.75);
|
||||
}
|
||||
|
||||
void conn_pool_destroy(ConnectionPool *cp)
|
||||
{
|
||||
pthread_mutex_lock(&cp->lock);
|
||||
hash_destroy(&(cp->hash_array));
|
||||
pthread_mutex_unlock(&cp->lock);
|
||||
|
||||
pthread_mutex_destroy(&cp->lock);
|
||||
}
|
||||
|
||||
void conn_pool_disconnect_server(ConnectionInfo *pConnection)
|
||||
{
|
||||
if (pConnection->sock >= 0)
|
||||
{
|
||||
close(pConnection->sock);
|
||||
pConnection->sock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int conn_pool_connect_server(ConnectionInfo *pConnection, \
|
||||
const int connect_timeout)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (pConnection->sock >= 0)
|
||||
{
|
||||
close(pConnection->sock);
|
||||
}
|
||||
|
||||
pConnection->sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(pConnection->sock < 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"socket create failed, errno: %d, " \
|
||||
"error info: %s", __LINE__, errno, STRERROR(errno));
|
||||
return errno != 0 ? errno : EPERM;
|
||||
}
|
||||
|
||||
if ((result=tcpsetnonblockopt(pConnection->sock)) != 0)
|
||||
{
|
||||
close(pConnection->sock);
|
||||
pConnection->sock = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result=connectserverbyip_nb(pConnection->sock, \
|
||||
pConnection->ip_addr, pConnection->port, \
|
||||
connect_timeout)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"connect to %s:%d fail, errno: %d, " \
|
||||
"error info: %s", __LINE__, pConnection->ip_addr, \
|
||||
pConnection->port, result, STRERROR(result));
|
||||
|
||||
close(pConnection->sock);
|
||||
pConnection->sock = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int conn_pool_get_key(const ConnectionInfo *conn, char *key, int *key_len)
|
||||
{
|
||||
struct in_addr sin_addr;
|
||||
|
||||
if (inet_aton(conn->ip_addr, &sin_addr) == 0)
|
||||
{
|
||||
*key_len = 0;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
int2buff(sin_addr.s_addr, key);
|
||||
*key_len = 4 + sprintf(key + 4, "%d", conn->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConnectionInfo *conn_pool_get_connection(ConnectionPool *cp,
|
||||
const ConnectionInfo *conn, int *err_no)
|
||||
{
|
||||
char key[32];
|
||||
int key_len;
|
||||
int bytes;
|
||||
char *p;
|
||||
ConnectionManager *cm;
|
||||
ConnectionNode *node;
|
||||
ConnectionInfo *ci;
|
||||
time_t current_time;
|
||||
|
||||
*err_no = conn_pool_get_key(conn, key, &key_len);
|
||||
if (*err_no != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&cp->lock);
|
||||
cm = (ConnectionManager *)hash_find(&cp->hash_array, key, key_len);
|
||||
if (cm == NULL)
|
||||
{
|
||||
cm = (ConnectionManager *)malloc(sizeof(ConnectionManager));
|
||||
if (cm == NULL)
|
||||
{
|
||||
*err_no = errno != 0 ? errno : ENOMEM;
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes fail, errno: %d, " \
|
||||
"error info: %s", __LINE__, \
|
||||
(int)sizeof(ConnectionManager), \
|
||||
*err_no, STRERROR(*err_no));
|
||||
pthread_mutex_unlock(&cp->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cm->head = NULL;
|
||||
cm->total_count = 0;
|
||||
cm->free_count = 0;
|
||||
if ((*err_no=init_pthread_lock(&cm->lock)) != 0)
|
||||
{
|
||||
pthread_mutex_unlock(&cp->lock);
|
||||
return NULL;
|
||||
}
|
||||
hash_insert(&cp->hash_array, key, key_len, cm);
|
||||
}
|
||||
pthread_mutex_unlock(&cp->lock);
|
||||
|
||||
current_time = get_current_time();
|
||||
pthread_mutex_lock(&cm->lock);
|
||||
while (1)
|
||||
{
|
||||
if (cm->head == NULL)
|
||||
{
|
||||
if ((cp->max_count_per_entry > 0) &&
|
||||
(cm->total_count >= cp->max_count_per_entry))
|
||||
{
|
||||
*err_no = ENOSPC;
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"connections: %d of server %s:%d " \
|
||||
"exceed limit: %d", __LINE__, \
|
||||
cm->total_count, conn->ip_addr, \
|
||||
conn->port, cp->max_count_per_entry);
|
||||
pthread_mutex_unlock(&cm->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bytes = sizeof(ConnectionInfo) + sizeof(ConnectionNode);
|
||||
p = (char *)malloc(bytes);
|
||||
if (p == NULL)
|
||||
{
|
||||
*err_no = errno != 0 ? errno : ENOMEM;
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes fail, errno: %d, " \
|
||||
"error info: %s", __LINE__, \
|
||||
bytes, *err_no, STRERROR(*err_no));
|
||||
pthread_mutex_unlock(&cm->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = (ConnectionNode *)(p + sizeof(ConnectionInfo));
|
||||
node->conn = (ConnectionInfo *)p;
|
||||
node->manager = cm;
|
||||
node->next = NULL;
|
||||
node->atime = 0;
|
||||
|
||||
cm->total_count++;
|
||||
pthread_mutex_unlock(&cm->lock);
|
||||
|
||||
memcpy(node->conn, conn, sizeof(ConnectionInfo));
|
||||
node->conn->sock = -1;
|
||||
*err_no = conn_pool_connect_server(node->conn, \
|
||||
cp->connect_timeout);
|
||||
if (*err_no != 0)
|
||||
{
|
||||
pthread_mutex_lock(&cm->lock);
|
||||
cm->total_count--; //rollback
|
||||
pthread_mutex_unlock(&cm->lock);
|
||||
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"server %s:%d, new connection: %d, " \
|
||||
"total_count: %d, free_count: %d", \
|
||||
__LINE__, conn->ip_addr, conn->port, \
|
||||
node->conn->sock, cm->total_count, \
|
||||
cm->free_count);
|
||||
return node->conn;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = cm->head;
|
||||
ci = node->conn;
|
||||
cm->head = node->next;
|
||||
cm->free_count--;
|
||||
|
||||
if (current_time - node->atime > cp->max_idle_time)
|
||||
{
|
||||
cm->total_count--;
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"server %s:%d, connection: %d idle " \
|
||||
"time: %d exceeds max idle time: %d, "\
|
||||
"total_count: %d, free_count: %d", \
|
||||
__LINE__, conn->ip_addr, conn->port, \
|
||||
ci->sock, \
|
||||
(int)(current_time - node->atime), \
|
||||
cp->max_idle_time, cm->total_count, \
|
||||
cm->free_count);
|
||||
|
||||
conn_pool_disconnect_server(ci);
|
||||
free(ci);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&cm->lock);
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"server %s:%d, reuse connection: %d, " \
|
||||
"total_count: %d, free_count: %d",
|
||||
__LINE__, conn->ip_addr, conn->port,
|
||||
ci->sock, cm->total_count, cm->free_count);
|
||||
return ci;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int conn_pool_close_connection_ex(ConnectionPool *cp, ConnectionInfo *conn,
|
||||
const bool bForce)
|
||||
{
|
||||
char key[32];
|
||||
int result;
|
||||
int key_len;
|
||||
ConnectionManager *cm;
|
||||
ConnectionNode *node;
|
||||
|
||||
result = conn_pool_get_key(conn, key, &key_len);
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&cp->lock);
|
||||
cm = (ConnectionManager *)hash_find(&cp->hash_array, key, key_len);
|
||||
pthread_mutex_unlock(&cp->lock);
|
||||
if (cm == NULL)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"hash entry of server %s:%d not exist", __LINE__, \
|
||||
conn->ip_addr, conn->port);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
node = (ConnectionNode *)(((char *)conn) + sizeof(ConnectionInfo));
|
||||
if (node->manager != cm)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"manager of server entry %s:%d is invalid!", \
|
||||
__LINE__, conn->ip_addr, conn->port);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&cm->lock);
|
||||
if (bForce)
|
||||
{
|
||||
cm->total_count--;
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"server %s:%d, release connection: %d, " \
|
||||
"total_count: %d, free_count: %d",
|
||||
__LINE__, conn->ip_addr, conn->port,
|
||||
conn->sock, cm->total_count, cm->free_count);
|
||||
|
||||
conn_pool_disconnect_server(conn);
|
||||
free(conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
node->atime = get_current_time();
|
||||
node->next = cm->head;
|
||||
cm->head = node;
|
||||
cm->free_count++;
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"server %s:%d, free connection: %d, " \
|
||||
"total_count: %d, free_count: %d",
|
||||
__LINE__, conn->ip_addr, conn->port,
|
||||
conn->sock, cm->total_count, cm->free_count);
|
||||
}
|
||||
pthread_mutex_unlock(&cm->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _conn_count_walk(const int index, const HashData *data, void *args)
|
||||
{
|
||||
int *count;
|
||||
ConnectionManager *cm;
|
||||
ConnectionNode *node;
|
||||
|
||||
count = (int *)args;
|
||||
cm = (ConnectionManager *)data->value;
|
||||
node = cm->head;
|
||||
while (node != NULL)
|
||||
{
|
||||
(*count)++;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conn_pool_get_connection_count(ConnectionPool *cp)
|
||||
{
|
||||
int count;
|
||||
count = 0;
|
||||
hash_walk(&cp->hash_array, _conn_count_walk, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//connection_pool.h
|
||||
|
||||
#ifndef _CONNECTION_POOL_H
|
||||
#define _CONNECTION_POOL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "common_define.h"
|
||||
#include "pthread_func.h"
|
||||
#include "hash.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int sock;
|
||||
int port;
|
||||
char ip_addr[IP_ADDRESS_SIZE];
|
||||
} ConnectionInfo;
|
||||
|
||||
struct tagConnectionManager;
|
||||
|
||||
typedef struct tagConnectionNode {
|
||||
ConnectionInfo *conn;
|
||||
struct tagConnectionManager *manager;
|
||||
struct tagConnectionNode *next;
|
||||
time_t atime; //last access time
|
||||
} ConnectionNode;
|
||||
|
||||
typedef struct tagConnectionManager {
|
||||
ConnectionNode *head;
|
||||
int total_count; //total connections
|
||||
int free_count; //free connections
|
||||
pthread_mutex_t lock;
|
||||
} ConnectionManager;
|
||||
|
||||
typedef struct tagConnectionPool {
|
||||
HashArray hash_array; //key is ip:port, value is ConnectionManager
|
||||
pthread_mutex_t lock;
|
||||
int connect_timeout;
|
||||
int max_count_per_entry; //0 means no limit
|
||||
|
||||
/*
|
||||
connections whose the idle time exceeds this time will be closed
|
||||
*/
|
||||
int max_idle_time;
|
||||
} ConnectionPool;
|
||||
|
||||
int conn_pool_init(ConnectionPool *cp, int connect_timeout, \
|
||||
const int max_count_per_entry, const int max_idle_time);
|
||||
void conn_pool_destroy(ConnectionPool *cp);
|
||||
|
||||
ConnectionInfo *conn_pool_get_connection(ConnectionPool *cp,
|
||||
const ConnectionInfo *conn, int *err_no);
|
||||
|
||||
#define conn_pool_close_connection(cp, conn) \
|
||||
conn_pool_close_connection_ex(cp, conn, false)
|
||||
|
||||
int conn_pool_close_connection_ex(ConnectionPool *cp, ConnectionInfo *conn,
|
||||
const bool bForce);
|
||||
|
||||
void conn_pool_disconnect_server(ConnectionInfo *pConnection);
|
||||
|
||||
int conn_pool_connect_server(ConnectionInfo *pConnection, \
|
||||
const int connect_timeout);
|
||||
|
||||
int conn_pool_get_connection_count(ConnectionPool *cp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
//fast_mblock.c
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/resource.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include "fast_mblock.h"
|
||||
#include "logger.h"
|
||||
#include "shared_func.h"
|
||||
#include "pthread_func.h"
|
||||
|
||||
int fast_mblock_init(struct fast_mblock_man *mblock, const int element_size, \
|
||||
const int alloc_elements_once)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (element_size <= 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"invalid block size: %d", \
|
||||
__LINE__, element_size);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
mblock->element_size = MEM_ALIGN(element_size);
|
||||
if (alloc_elements_once > 0)
|
||||
{
|
||||
mblock->alloc_elements_once = alloc_elements_once;
|
||||
}
|
||||
else
|
||||
{
|
||||
int block_size;
|
||||
block_size = MEM_ALIGN(sizeof(struct fast_mblock_node) \
|
||||
+ mblock->element_size);
|
||||
mblock->alloc_elements_once = (1024 * 1024) / block_size;
|
||||
}
|
||||
|
||||
if ((result=init_pthread_lock(&(mblock->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"init_pthread_lock fail, errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
mblock->malloc_chain_head = NULL;
|
||||
mblock->free_chain_head = NULL;
|
||||
mblock->total_count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
|
||||
{
|
||||
struct fast_mblock_node *pNode;
|
||||
struct fast_mblock_malloc *pMallocNode;
|
||||
char *pNew;
|
||||
char *pTrunkStart;
|
||||
char *p;
|
||||
char *pLast;
|
||||
int block_size;
|
||||
int alloc_size;
|
||||
|
||||
block_size = MEM_ALIGN(sizeof(struct fast_mblock_node) + \
|
||||
mblock->element_size);
|
||||
alloc_size = sizeof(struct fast_mblock_malloc) + block_size * \
|
||||
mblock->alloc_elements_once;
|
||||
|
||||
pNew = (char *)malloc(alloc_size);
|
||||
if (pNew == NULL)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, alloc_size, errno, STRERROR(errno));
|
||||
return errno != 0 ? errno : ENOMEM;
|
||||
}
|
||||
memset(pNew, 0, alloc_size);
|
||||
|
||||
pMallocNode = (struct fast_mblock_malloc *)pNew;
|
||||
|
||||
pTrunkStart = pNew + sizeof(struct fast_mblock_malloc);
|
||||
pLast = pNew + (alloc_size - block_size);
|
||||
for (p=pTrunkStart; p<pLast; p += block_size)
|
||||
{
|
||||
pNode = (struct fast_mblock_node *)p;
|
||||
pNode->next = (struct fast_mblock_node *)(p + block_size);
|
||||
}
|
||||
((struct fast_mblock_node *)pLast)->next = NULL;
|
||||
mblock->free_chain_head = (struct fast_mblock_node *)pTrunkStart;
|
||||
|
||||
pMallocNode->next = mblock->malloc_chain_head;
|
||||
mblock->malloc_chain_head = pMallocNode;
|
||||
mblock->total_count += mblock->alloc_elements_once;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fast_mblock_destroy(struct fast_mblock_man *mblock)
|
||||
{
|
||||
struct fast_mblock_malloc *pMallocNode;
|
||||
struct fast_mblock_malloc *pMallocTmp;
|
||||
|
||||
if (mblock->malloc_chain_head == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pMallocNode = mblock->malloc_chain_head;
|
||||
while (pMallocNode != NULL)
|
||||
{
|
||||
pMallocTmp = pMallocNode;
|
||||
pMallocNode = pMallocNode->next;
|
||||
|
||||
free(pMallocTmp);
|
||||
}
|
||||
mblock->malloc_chain_head = NULL;
|
||||
mblock->free_chain_head = NULL;
|
||||
mblock->total_count = 0;
|
||||
|
||||
pthread_mutex_destroy(&(mblock->lock));
|
||||
}
|
||||
|
||||
struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock)
|
||||
{
|
||||
struct fast_mblock_node *pNode;
|
||||
int result;
|
||||
|
||||
if ((result=pthread_mutex_lock(&(mblock->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_lock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mblock->free_chain_head != NULL)
|
||||
{
|
||||
pNode = mblock->free_chain_head;
|
||||
mblock->free_chain_head = pNode->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((result=fast_mblock_prealloc(mblock)) == 0)
|
||||
{
|
||||
pNode = mblock->free_chain_head;
|
||||
mblock->free_chain_head = pNode->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((result=pthread_mutex_unlock(&(mblock->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_unlock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
return pNode;
|
||||
}
|
||||
|
||||
int fast_mblock_free(struct fast_mblock_man *mblock, \
|
||||
struct fast_mblock_node *pNode)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result=pthread_mutex_lock(&(mblock->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_lock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
pNode->next = mblock->free_chain_head;
|
||||
mblock->free_chain_head = pNode;
|
||||
|
||||
if ((result=pthread_mutex_unlock(&(mblock->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_unlock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fast_mblock_free_count(struct fast_mblock_man *mblock)
|
||||
{
|
||||
struct fast_mblock_node *pNode;
|
||||
int count;
|
||||
int result;
|
||||
|
||||
if ((result=pthread_mutex_lock(&(mblock->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_lock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
pNode = mblock->free_chain_head;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
pNode = pNode->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
if ((result=pthread_mutex_unlock(&(mblock->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_unlock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//fast_mblock.h
|
||||
|
||||
#ifndef _FAST_MBLOCK_H
|
||||
#define _FAST_MBLOCK_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "common_define.h"
|
||||
#include "chain.h"
|
||||
|
||||
/* free node chain */
|
||||
struct fast_mblock_node
|
||||
{
|
||||
struct fast_mblock_node *next;
|
||||
char data[0]; //the data buffer
|
||||
};
|
||||
|
||||
/* malloc chain */
|
||||
struct fast_mblock_malloc
|
||||
{
|
||||
struct fast_mblock_malloc *next;
|
||||
};
|
||||
|
||||
struct fast_mblock_man
|
||||
{
|
||||
struct fast_mblock_node *free_chain_head; //free node chain
|
||||
struct fast_mblock_malloc *malloc_chain_head; //malloc chain to be freed
|
||||
int element_size; //element size
|
||||
int alloc_elements_once; //alloc elements once
|
||||
int total_count; //total element count
|
||||
pthread_mutex_t lock; //the lock for read / write free node chain
|
||||
};
|
||||
|
||||
#define fast_mblock_to_node_ptr(data_ptr) \
|
||||
(struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \
|
||||
&((struct fast_mblock_node *)0)->data))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
mblock init
|
||||
parameters:
|
||||
mblock: the mblock pointer
|
||||
element_size: element size, such as sizeof(struct xxx)
|
||||
alloc_elements_once: malloc elements once, 0 for malloc 1MB once
|
||||
return error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int fast_mblock_init(struct fast_mblock_man *mblock, const int element_size, \
|
||||
const int alloc_elements_once);
|
||||
|
||||
/**
|
||||
mblock destroy
|
||||
parameters:
|
||||
mblock: the mblock pointer
|
||||
*/
|
||||
void fast_mblock_destroy(struct fast_mblock_man *mblock);
|
||||
|
||||
/**
|
||||
alloc a node from the mblock
|
||||
parameters:
|
||||
mblock: the mblock pointer
|
||||
return the alloced node, return NULL if fail
|
||||
*/
|
||||
struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock);
|
||||
|
||||
/**
|
||||
free a node (put a node to the mblock)
|
||||
parameters:
|
||||
mblock: the mblock pointer
|
||||
pNode: the node to free
|
||||
return the alloced node, return NULL if fail
|
||||
*/
|
||||
int fast_mblock_free(struct fast_mblock_man *mblock, \
|
||||
struct fast_mblock_node *pNode);
|
||||
|
||||
/**
|
||||
get node count of the mblock
|
||||
parameters:
|
||||
mblock: the mblock pointer
|
||||
return the free node count of the mblock, return -1 if fail
|
||||
*/
|
||||
int fast_mblock_free_count(struct fast_mblock_man *mblock);
|
||||
|
||||
#define fast_mblock_total_count(mblock) (mblock)->total_count
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,504 +0,0 @@
|
|||
//fast_task_queue.c
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/resource.h>
|
||||
#include <pthread.h>
|
||||
#include <inttypes.h>
|
||||
#include "fast_task_queue.h"
|
||||
#include "logger.h"
|
||||
#include "shared_func.h"
|
||||
#include "pthread_func.h"
|
||||
|
||||
static struct fast_task_queue g_free_queue;
|
||||
|
||||
struct mpool_chain {
|
||||
struct fast_task_info *blocks;
|
||||
struct fast_task_info *last_block; //last block
|
||||
struct mpool_chain *next;
|
||||
} *g_mpool = NULL;
|
||||
|
||||
#define ALIGNED_TASK_INFO_SIZE MEM_ALIGN(sizeof(struct fast_task_info))
|
||||
|
||||
int task_queue_init(struct fast_task_queue *pQueue)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result=init_pthread_lock(&(pQueue->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"init_pthread_lock fail, errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
pQueue->head = NULL;
|
||||
pQueue->tail = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mpool_chain *malloc_mpool(const int block_size, \
|
||||
const int total_alloc_size)
|
||||
{
|
||||
struct fast_task_info *pTask;
|
||||
char *p;
|
||||
char *pCharEnd;
|
||||
struct mpool_chain *mpool;
|
||||
|
||||
mpool = (struct mpool_chain *)malloc(sizeof(struct mpool_chain));
|
||||
if (mpool == NULL)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, (int)sizeof(struct mpool_chain), \
|
||||
errno, STRERROR(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mpool->next = NULL;
|
||||
mpool->blocks = (struct fast_task_info *)malloc(total_alloc_size);
|
||||
if (mpool->blocks == NULL)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, total_alloc_size, \
|
||||
errno, STRERROR(errno));
|
||||
free(mpool);
|
||||
return NULL;
|
||||
}
|
||||
memset(mpool->blocks, 0, total_alloc_size);
|
||||
|
||||
pCharEnd = ((char *)mpool->blocks) + total_alloc_size;
|
||||
for (p=(char *)mpool->blocks; p<pCharEnd; p += block_size)
|
||||
{
|
||||
pTask = (struct fast_task_info *)p;
|
||||
pTask->size = g_free_queue.min_buff_size;
|
||||
|
||||
pTask->arg = p + ALIGNED_TASK_INFO_SIZE;
|
||||
if (g_free_queue.malloc_whole_block)
|
||||
{
|
||||
pTask->data = (char *)pTask->arg + \
|
||||
g_free_queue.arg_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTask->data = (char *)malloc(pTask->size);
|
||||
if (pTask->data == NULL)
|
||||
{
|
||||
char *pt;
|
||||
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, pTask->size, \
|
||||
errno, STRERROR(errno));
|
||||
|
||||
for (pt=(char *)mpool->blocks; pt < p; \
|
||||
pt += block_size)
|
||||
{
|
||||
free(((struct fast_task_info *)pt)->data);
|
||||
}
|
||||
|
||||
free(mpool->blocks);
|
||||
free(mpool);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mpool->last_block = (struct fast_task_info *)(pCharEnd - block_size);
|
||||
for (p=(char *)mpool->blocks; p<(char *)mpool->last_block; p += block_size)
|
||||
{
|
||||
pTask = (struct fast_task_info *)p;
|
||||
pTask->next = (struct fast_task_info *)(p + block_size);
|
||||
}
|
||||
mpool->last_block->next = NULL;
|
||||
|
||||
return mpool;
|
||||
}
|
||||
|
||||
int free_queue_init(const int max_connections, const int min_buff_size, \
|
||||
const int max_buff_size, const int arg_size)
|
||||
{
|
||||
int64_t total_size;
|
||||
struct mpool_chain *mpool;
|
||||
int block_size;
|
||||
int alloc_size;
|
||||
int result;
|
||||
int loop_count;
|
||||
int aligned_min_size;
|
||||
int aligned_max_size;
|
||||
int aligned_arg_size;
|
||||
rlim_t max_data_size;
|
||||
|
||||
if ((result=init_pthread_lock(&(g_free_queue.lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"init_pthread_lock fail, errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
aligned_min_size = MEM_ALIGN(min_buff_size);
|
||||
aligned_max_size = MEM_ALIGN(max_buff_size);
|
||||
aligned_arg_size = MEM_ALIGN(arg_size);
|
||||
block_size = ALIGNED_TASK_INFO_SIZE + aligned_arg_size;
|
||||
alloc_size = block_size * max_connections;
|
||||
if (aligned_max_size > aligned_min_size)
|
||||
{
|
||||
total_size = alloc_size;
|
||||
g_free_queue.malloc_whole_block = false;
|
||||
max_data_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct rlimit rlimit_data;
|
||||
|
||||
if (getrlimit(RLIMIT_DATA, &rlimit_data) < 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call getrlimit fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, errno, STRERROR(errno));
|
||||
return errno != 0 ? errno : EPERM;
|
||||
}
|
||||
if (rlimit_data.rlim_cur == RLIM_INFINITY)
|
||||
{
|
||||
max_data_size = 256 * 1024 * 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
max_data_size = rlimit_data.rlim_cur;
|
||||
if (max_data_size > 256 * 1024 * 1024)
|
||||
{
|
||||
max_data_size = 256 * 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_data_size >= (int64_t)(block_size + aligned_min_size) *
|
||||
(int64_t)max_connections)
|
||||
{
|
||||
total_size = alloc_size + (int64_t)aligned_min_size *
|
||||
max_connections;
|
||||
g_free_queue.malloc_whole_block = true;
|
||||
block_size += aligned_min_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_size = alloc_size;
|
||||
g_free_queue.malloc_whole_block = false;
|
||||
max_data_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"max_connections: %d, min_buff_size: %d, max_buff_size: %d, " \
|
||||
"block_size: %d, arg_size: %d, max_data_size: %d, " \
|
||||
"total_size: %"PRId64, __LINE__, \
|
||||
max_connections, aligned_min_size, aligned_max_size, \
|
||||
block_size, aligned_arg_size, (int)max_data_size, total_size);
|
||||
|
||||
g_free_queue.max_connections = max_connections;
|
||||
g_free_queue.min_buff_size = aligned_min_size;
|
||||
g_free_queue.max_buff_size = aligned_max_size;
|
||||
g_free_queue.arg_size = aligned_arg_size;
|
||||
|
||||
if ((!g_free_queue.malloc_whole_block) || \
|
||||
(total_size <= max_data_size))
|
||||
{
|
||||
loop_count = 1;
|
||||
mpool = malloc_mpool(block_size, total_size);
|
||||
if (mpool == NULL)
|
||||
{
|
||||
return errno != 0 ? errno : ENOMEM;
|
||||
}
|
||||
g_mpool = mpool;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct mpool_chain *previous_mpool;
|
||||
int remain_count;
|
||||
int alloc_once;
|
||||
int current_count;
|
||||
int current_alloc_size;
|
||||
|
||||
mpool = NULL;
|
||||
previous_mpool = NULL;
|
||||
loop_count = 0;
|
||||
remain_count = max_connections;
|
||||
alloc_once = max_data_size / block_size;
|
||||
while (remain_count > 0)
|
||||
{
|
||||
current_count = (remain_count > alloc_once) ? \
|
||||
alloc_once : remain_count;
|
||||
current_alloc_size = block_size * current_count;
|
||||
mpool = malloc_mpool(block_size, current_alloc_size);
|
||||
if (mpool == NULL)
|
||||
{
|
||||
free_queue_destroy();
|
||||
return errno != 0 ? errno : ENOMEM;
|
||||
}
|
||||
|
||||
if (previous_mpool == NULL)
|
||||
{
|
||||
g_mpool = mpool;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_mpool->next = mpool;
|
||||
previous_mpool->last_block->next = mpool->blocks;
|
||||
}
|
||||
previous_mpool = mpool;
|
||||
|
||||
remain_count -= current_count;
|
||||
loop_count++;
|
||||
}
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"alloc_once: %d", __LINE__, alloc_once);
|
||||
}
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"malloc task info as whole: %d, malloc loop count: %d", \
|
||||
__LINE__, g_free_queue.malloc_whole_block, loop_count);
|
||||
|
||||
if (g_mpool != NULL)
|
||||
{
|
||||
g_free_queue.head = g_mpool->blocks;
|
||||
g_free_queue.tail = mpool->last_block;
|
||||
|
||||
/*
|
||||
struct fast_task_info *pTask;
|
||||
int task_count = 0;
|
||||
|
||||
pTask = g_free_queue.head;
|
||||
while (pTask != NULL)
|
||||
{
|
||||
task_count++;
|
||||
pTask = pTask->next;
|
||||
}
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"task count: %d", __LINE__, task_count);
|
||||
*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_queue_destroy()
|
||||
{
|
||||
struct mpool_chain *mpool;
|
||||
struct mpool_chain *mp;
|
||||
|
||||
if (g_mpool == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_free_queue.malloc_whole_block)
|
||||
{
|
||||
char *p;
|
||||
char *pCharEnd;
|
||||
int block_size;
|
||||
struct fast_task_info *pTask;
|
||||
|
||||
block_size = ALIGNED_TASK_INFO_SIZE + g_free_queue.arg_size;
|
||||
pCharEnd = ((char *)g_mpool->blocks) + block_size * \
|
||||
g_free_queue.max_connections;
|
||||
for (p=(char *)g_mpool->blocks; p<pCharEnd; p += block_size)
|
||||
{
|
||||
pTask = (struct fast_task_info *)p;
|
||||
if (pTask->data != NULL)
|
||||
{
|
||||
free(pTask->data);
|
||||
pTask->data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mpool = g_mpool;
|
||||
while (mpool != NULL)
|
||||
{
|
||||
mp = mpool;
|
||||
mpool = mpool->next;
|
||||
|
||||
free(mp->blocks);
|
||||
free(mp);
|
||||
}
|
||||
g_mpool = NULL;
|
||||
|
||||
pthread_mutex_destroy(&(g_free_queue.lock));
|
||||
}
|
||||
|
||||
struct fast_task_info *free_queue_pop()
|
||||
{
|
||||
return task_queue_pop(&g_free_queue);;
|
||||
}
|
||||
|
||||
int free_queue_push(struct fast_task_info *pTask)
|
||||
{
|
||||
char *new_buff;
|
||||
int result;
|
||||
|
||||
*(pTask->client_ip) = '\0';
|
||||
pTask->length = 0;
|
||||
pTask->offset = 0;
|
||||
pTask->req_count = 0;
|
||||
|
||||
if (pTask->size > g_free_queue.min_buff_size) //need thrink
|
||||
{
|
||||
new_buff = (char *)malloc(g_free_queue.min_buff_size);
|
||||
if (new_buff == NULL)
|
||||
{
|
||||
logWarning("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, g_free_queue.min_buff_size, \
|
||||
errno, STRERROR(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
free(pTask->data);
|
||||
pTask->size = g_free_queue.min_buff_size;
|
||||
pTask->data = new_buff;
|
||||
}
|
||||
}
|
||||
|
||||
if ((result=pthread_mutex_lock(&g_free_queue.lock)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_lock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
pTask->next = g_free_queue.head;
|
||||
g_free_queue.head = pTask;
|
||||
if (g_free_queue.tail == NULL)
|
||||
{
|
||||
g_free_queue.tail = pTask;
|
||||
}
|
||||
|
||||
if ((result=pthread_mutex_unlock(&g_free_queue.lock)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_unlock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int free_queue_count()
|
||||
{
|
||||
return task_queue_count(&g_free_queue);
|
||||
}
|
||||
|
||||
int task_queue_push(struct fast_task_queue *pQueue, \
|
||||
struct fast_task_info *pTask)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_lock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
pTask->next = NULL;
|
||||
if (pQueue->tail == NULL)
|
||||
{
|
||||
pQueue->head = pTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
pQueue->tail->next = pTask;
|
||||
}
|
||||
pQueue->tail = pTask;
|
||||
|
||||
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_unlock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue)
|
||||
{
|
||||
struct fast_task_info *pTask;
|
||||
int result;
|
||||
|
||||
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_lock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pTask = pQueue->head;
|
||||
if (pTask != NULL)
|
||||
{
|
||||
pQueue->head = pTask->next;
|
||||
if (pQueue->head == NULL)
|
||||
{
|
||||
pQueue->tail = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_unlock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
return pTask;
|
||||
}
|
||||
|
||||
int task_queue_count(struct fast_task_queue *pQueue)
|
||||
{
|
||||
struct fast_task_info *pTask;
|
||||
int count;
|
||||
int result;
|
||||
|
||||
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_lock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
pTask = pQueue->head;
|
||||
while (pTask != NULL)
|
||||
{
|
||||
pTask = pTask->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_unlock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//fast_task_queue.h
|
||||
|
||||
#ifndef _FAST_TASK_QUEUE_H
|
||||
#define _FAST_TASK_QUEUE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "common_define.h"
|
||||
#include "ioevent.h"
|
||||
#include "fast_timer.h"
|
||||
|
||||
struct nio_thread_data;
|
||||
struct fast_task_info;
|
||||
|
||||
typedef int (*ThreadLoopCallback) (struct nio_thread_data *pThreadData);
|
||||
typedef int (*TaskFinishCallback) (struct fast_task_info *pTask);
|
||||
typedef void (*TaskCleanUpCallback) (struct fast_task_info *pTask);
|
||||
|
||||
typedef void (*IOEventCallback) (int sock, short event, void *arg);
|
||||
|
||||
typedef struct ioevent_entry
|
||||
{
|
||||
int fd;
|
||||
FastTimerEntry timer;
|
||||
IOEventCallback callback;
|
||||
} IOEventEntry;
|
||||
|
||||
struct nio_thread_data
|
||||
{
|
||||
struct ioevent_puller ev_puller;
|
||||
struct fast_timer timer;
|
||||
int pipe_fds[2];
|
||||
struct fast_task_info *deleted_list;
|
||||
ThreadLoopCallback thread_loop_callback;
|
||||
void *arg; //extra argument pointer
|
||||
};
|
||||
|
||||
struct fast_task_info
|
||||
{
|
||||
IOEventEntry event; //must first
|
||||
char client_ip[IP_ADDRESS_SIZE];
|
||||
void *arg; //extra argument pointer
|
||||
char *data; //buffer for write or recv
|
||||
int size; //alloc size
|
||||
int length; //data length
|
||||
int offset; //current offset
|
||||
int64_t req_count; //request count
|
||||
TaskFinishCallback finish_callback;
|
||||
struct nio_thread_data *thread_data;
|
||||
struct fast_task_info *next;
|
||||
};
|
||||
|
||||
struct fast_task_queue
|
||||
{
|
||||
struct fast_task_info *head;
|
||||
struct fast_task_info *tail;
|
||||
pthread_mutex_t lock;
|
||||
int max_connections;
|
||||
int min_buff_size;
|
||||
int max_buff_size;
|
||||
int arg_size;
|
||||
bool malloc_whole_block;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int free_queue_init(const int max_connections, const int min_buff_size, \
|
||||
const int max_buff_size, const int arg_size);
|
||||
|
||||
void free_queue_destroy();
|
||||
|
||||
int free_queue_push(struct fast_task_info *pTask);
|
||||
struct fast_task_info *free_queue_pop();
|
||||
int free_queue_count();
|
||||
|
||||
|
||||
int task_queue_init(struct fast_task_queue *pQueue);
|
||||
int task_queue_push(struct fast_task_queue *pQueue, \
|
||||
struct fast_task_info *pTask);
|
||||
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue);
|
||||
int task_queue_count(struct fast_task_queue *pQueue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "logger.h"
|
||||
#include "fast_timer.h"
|
||||
|
||||
int fast_timer_init(FastTimer *timer, const int slot_count,
|
||||
const int64_t current_time)
|
||||
{
|
||||
int bytes;
|
||||
if (slot_count <= 0 || current_time <= 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
timer->slot_count = slot_count;
|
||||
timer->base_time = current_time; //base time for slot 0
|
||||
timer->current_time = current_time;
|
||||
bytes = sizeof(FastTimerSlot) * slot_count;
|
||||
timer->slots = (FastTimerSlot *)malloc(bytes);
|
||||
if (timer->slots == NULL) {
|
||||
return errno != 0 ? errno : ENOMEM;
|
||||
}
|
||||
memset(timer->slots, 0, bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fast_timer_destroy(FastTimer *timer)
|
||||
{
|
||||
if (timer->slots != NULL) {
|
||||
free(timer->slots);
|
||||
timer->slots = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define TIMER_GET_SLOT_INDEX(timer, expires) \
|
||||
(((expires) - timer->base_time) % timer->slot_count)
|
||||
|
||||
#define TIMER_GET_SLOT_POINTER(timer, expires) \
|
||||
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
|
||||
|
||||
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry)
|
||||
{
|
||||
FastTimerSlot *slot;
|
||||
|
||||
slot = TIMER_GET_SLOT_POINTER(timer, entry->expires >
|
||||
timer->current_time ? entry->expires : timer->current_time);
|
||||
entry->next = slot->head.next;
|
||||
if (slot->head.next != NULL) {
|
||||
slot->head.next->prev = entry;
|
||||
}
|
||||
entry->prev = &slot->head;
|
||||
slot->head.next = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||
const int64_t new_expires)
|
||||
{
|
||||
if (new_expires == entry->expires) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (new_expires < entry->expires) {
|
||||
fast_timer_remove(timer, entry);
|
||||
entry->expires = new_expires;
|
||||
return fast_timer_add(timer, entry);
|
||||
}
|
||||
|
||||
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) !=
|
||||
TIMER_GET_SLOT_INDEX(timer, entry->expires);
|
||||
entry->expires = new_expires; //lazy move
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
|
||||
{
|
||||
if (entry->prev == NULL) {
|
||||
return ENOENT; //already removed
|
||||
}
|
||||
|
||||
if (entry->next != NULL) {
|
||||
entry->next->prev = entry->prev;
|
||||
entry->prev->next = entry->next;
|
||||
entry->next = NULL;
|
||||
}
|
||||
else {
|
||||
entry->prev->next = NULL;
|
||||
}
|
||||
|
||||
entry->prev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time)
|
||||
{
|
||||
if (timer->current_time >= current_time) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
||||
}
|
||||
|
||||
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
||||
FastTimerEntry *head)
|
||||
{
|
||||
FastTimerSlot *slot;
|
||||
FastTimerEntry *entry;
|
||||
FastTimerEntry *first;
|
||||
FastTimerEntry *last;
|
||||
FastTimerEntry *tail;
|
||||
int count;
|
||||
|
||||
head->prev = NULL;
|
||||
head->next = NULL;
|
||||
if (timer->current_time >= current_time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
first = NULL;
|
||||
last = NULL;
|
||||
tail = head;
|
||||
count = 0;
|
||||
while (timer->current_time < current_time) {
|
||||
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
||||
entry = slot->head.next;
|
||||
while (entry != NULL) {
|
||||
if (entry->expires >= current_time) { //not expired
|
||||
if (first != NULL) {
|
||||
first->prev->next = entry;
|
||||
entry->prev = first->prev;
|
||||
|
||||
tail->next = first;
|
||||
first->prev = tail;
|
||||
tail = last;
|
||||
first = NULL;
|
||||
}
|
||||
if (entry->rehash) {
|
||||
last = entry;
|
||||
entry = entry->next;
|
||||
|
||||
last->rehash = false;
|
||||
fast_timer_remove(timer, last);
|
||||
fast_timer_add(timer, last);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
count++;
|
||||
if (first == NULL) {
|
||||
first = entry;
|
||||
}
|
||||
}
|
||||
last = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
if (first != NULL) {
|
||||
first->prev->next = NULL;
|
||||
|
||||
tail->next = first;
|
||||
first->prev = tail;
|
||||
tail = last;
|
||||
first = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
tail->next = NULL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#ifndef __FAST_TIMER_H__
|
||||
#define __FAST_TIMER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common_define.h"
|
||||
|
||||
typedef struct fast_timer_entry {
|
||||
int64_t expires;
|
||||
void *data;
|
||||
struct fast_timer_entry *prev;
|
||||
struct fast_timer_entry *next;
|
||||
bool rehash;
|
||||
} FastTimerEntry;
|
||||
|
||||
typedef struct fast_timer_slot {
|
||||
struct fast_timer_entry head;
|
||||
} FastTimerSlot;
|
||||
|
||||
typedef struct fast_timer {
|
||||
int slot_count; //time wheel slot count
|
||||
int64_t base_time; //base time for slot 0
|
||||
int64_t current_time;
|
||||
FastTimerSlot *slots;
|
||||
} FastTimer;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int fast_timer_init(FastTimer *timer, const int slot_count,
|
||||
const int64_t current_time);
|
||||
void fast_timer_destroy(FastTimer *timer);
|
||||
|
||||
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry);
|
||||
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry);
|
||||
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||
const int64_t new_expires);
|
||||
|
||||
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time);
|
||||
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
||||
FastTimerEntry *head);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
int g_fdfs_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
|
||||
int g_fdfs_network_timeout = DEFAULT_NETWORK_TIMEOUT;
|
||||
char g_fdfs_base_path[MAX_PATH_SIZE] = {'/', 't', 'm', 'p', '\0'};
|
||||
Version g_fdfs_version = {5, 3};
|
||||
Version g_fdfs_version = {5, 4};
|
||||
bool g_use_connection_pool = false;
|
||||
ConnectionPool g_connection_pool;
|
||||
int g_connection_pool_max_idle_time = 3600;
|
||||
|
|
|
|||
1403
common/hash.c
1403
common/hash.c
File diff suppressed because it is too large
Load Diff
381
common/hash.h
381
common/hash.h
|
|
@ -1,381 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#ifndef _HASH_H_
|
||||
#define _HASH_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
#include "common_define.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CRC32_XINIT 0xFFFFFFFF /* initial value */
|
||||
#define CRC32_XOROT 0xFFFFFFFF /* final xor value */
|
||||
|
||||
typedef int (*HashFunc) (const void *key, const int key_len);
|
||||
|
||||
#ifdef HASH_STORE_HASH_CODE
|
||||
#define HASH_CODE(pHash, hash_data) hash_data->hash_code
|
||||
#else
|
||||
#define HASH_CODE(pHash, hash_data) ((unsigned int)pHash->hash_func( \
|
||||
hash_data->key, hash_data->key_len))
|
||||
#endif
|
||||
|
||||
#define CALC_NODE_MALLOC_BYTES(key_len, value_size) \
|
||||
sizeof(HashData) + key_len + value_size
|
||||
|
||||
#define FREE_HASH_DATA(pHash, hash_data) \
|
||||
pHash->item_count--; \
|
||||
pHash->bytes_used -= CALC_NODE_MALLOC_BYTES(hash_data->key_len, \
|
||||
hash_data->malloc_value_size); \
|
||||
free(hash_data);
|
||||
|
||||
|
||||
typedef struct tagHashData
|
||||
{
|
||||
int key_len;
|
||||
int value_len;
|
||||
int malloc_value_size;
|
||||
|
||||
#ifdef HASH_STORE_HASH_CODE
|
||||
unsigned int hash_code;
|
||||
#endif
|
||||
|
||||
char *value;
|
||||
struct tagHashData *next;
|
||||
char key[0];
|
||||
} HashData;
|
||||
|
||||
typedef int64_t (*ConvertValueFunc)(const HashData *old_data, const int inc,
|
||||
char *new_value, int *new_value_len, void *arg);
|
||||
|
||||
typedef struct tagHashArray
|
||||
{
|
||||
HashData **buckets;
|
||||
HashFunc hash_func;
|
||||
int item_count;
|
||||
unsigned int *capacity;
|
||||
double load_factor;
|
||||
int64_t max_bytes;
|
||||
int64_t bytes_used;
|
||||
bool is_malloc_capacity;
|
||||
bool is_malloc_value;
|
||||
unsigned int lock_count;
|
||||
pthread_mutex_t *locks;
|
||||
} HashArray;
|
||||
|
||||
typedef struct tagHashStat
|
||||
{
|
||||
unsigned int capacity;
|
||||
int item_count;
|
||||
int bucket_used;
|
||||
double bucket_avg_length;
|
||||
int bucket_max_length;
|
||||
} HashStat;
|
||||
|
||||
/**
|
||||
* hash walk function
|
||||
* parameters:
|
||||
* index: item index based 0
|
||||
* data: hash data, including key and value
|
||||
* args: passed by hash_walk function
|
||||
* return 0 for success, != 0 for error
|
||||
*/
|
||||
typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
|
||||
|
||||
#define hash_init(pHash, hash_func, capacity, load_factor) \
|
||||
hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false)
|
||||
|
||||
#define hash_insert(pHash, key, key_len, value) \
|
||||
hash_insert_ex(pHash, key, key_len, value, 0, true)
|
||||
|
||||
/**
|
||||
* hash init function
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* hash_func: hash function
|
||||
* capacity: init capacity
|
||||
* load_factor: hash load factor, such as 0.75
|
||||
* max_bytes: max memory can be used (bytes)
|
||||
* bMallocValue: if need malloc value buffer
|
||||
* return 0 for success, != 0 for error
|
||||
*/
|
||||
int hash_init_ex(HashArray *pHash, HashFunc hash_func, \
|
||||
const unsigned int capacity, const double load_factor, \
|
||||
const int64_t max_bytes, const bool bMallocValue);
|
||||
|
||||
/**
|
||||
* set hash locks function
|
||||
* parameters:
|
||||
* lock_count: the lock count
|
||||
* return 0 for success, != 0 for error
|
||||
*/
|
||||
int hash_set_locks(HashArray *pHash, const int lock_count);
|
||||
|
||||
/**
|
||||
* convert the value
|
||||
* parameters:
|
||||
* HashData: the old hash data
|
||||
* inc: the increasement value
|
||||
* new_value: return the new value
|
||||
* new_value_len: return the length of the new value
|
||||
* arg: the user data
|
||||
* return the number after increasement
|
||||
*/
|
||||
int64_t hash_inc_value(const HashData *old_data, const int inc,
|
||||
char *new_value, int *new_value_len, void *arg);
|
||||
|
||||
#define hash_inc(pHash, key, key_len, inc, value, value_len) \
|
||||
hash_inc_ex(pHash, key, key_len, inc, value, value_len, \
|
||||
hash_inc_value, NULL)
|
||||
|
||||
/**
|
||||
* atomic increase value
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* key: the key to insert
|
||||
* key_len: length of th key
|
||||
* inc: the increasement value
|
||||
* value: return the new value
|
||||
* value_len: return the length of the new value
|
||||
* convert_func: the convert function
|
||||
* arg: the arg to convert function
|
||||
* return 0 for success, != 0 for error (errno)
|
||||
*
|
||||
*/
|
||||
int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
|
||||
const int inc, char *value, int *value_len,
|
||||
ConvertValueFunc convert_func, void *arg);
|
||||
|
||||
/**
|
||||
* hash destroy function
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* return none
|
||||
*/
|
||||
void hash_destroy(HashArray *pHash);
|
||||
|
||||
/**
|
||||
* hash insert key
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* key: the key to insert
|
||||
* key_len: length of th key
|
||||
* value: the value
|
||||
* value_len: length of the value
|
||||
* needLock: if need lock
|
||||
* return >= 0 for success, 0 for key already exist (update),
|
||||
* 1 for new key (insert), < 0 for error
|
||||
*/
|
||||
int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
|
||||
void *value, const int value_len, const bool needLock);
|
||||
|
||||
/**
|
||||
* hash find key
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* key: the key to find
|
||||
* key_len: length of th key
|
||||
* return user data, return NULL when the key not exist
|
||||
*/
|
||||
void *hash_find(HashArray *pHash, const void *key, const int key_len);
|
||||
|
||||
/**
|
||||
* hash find key
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* key: the key to find
|
||||
* key_len: length of th key
|
||||
* return hash data, return NULL when the key not exist
|
||||
*/
|
||||
HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len);
|
||||
|
||||
|
||||
/**
|
||||
* hash get the value of the key
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* key: the key to find
|
||||
* key_len: length of th key
|
||||
* value: store the value
|
||||
* value_len: input for the max size of the value
|
||||
* output for the length fo the value
|
||||
* return 0 for success, != 0 fail (errno)
|
||||
*/
|
||||
int hash_get(HashArray *pHash, const void *key, const int key_len,
|
||||
void *value, int *value_len);
|
||||
|
||||
|
||||
/**
|
||||
* hash partial set
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* key: the key to insert
|
||||
* key_len: length of th key
|
||||
* value: the value
|
||||
* offset: the offset of existed value
|
||||
* value_len: length of the value
|
||||
* return 0 for success, != 0 fail (errno)
|
||||
*/
|
||||
int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
||||
const char *value, const int offset, const int value_len);
|
||||
|
||||
/**
|
||||
* hash delete key
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* key: the key to delete
|
||||
* key_len: length of th key
|
||||
* return 0 for success, != 0 fail (errno)
|
||||
*/
|
||||
int hash_delete(HashArray *pHash, const void *key, const int key_len);
|
||||
|
||||
/**
|
||||
* hash walk (iterator)
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* walkFunc: walk (interator) function
|
||||
* args: extra args which will be passed to walkFunc
|
||||
* return 0 for success, != 0 fail (errno)
|
||||
*/
|
||||
int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
|
||||
|
||||
/**
|
||||
* get hash item count
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* return item count
|
||||
*/
|
||||
int hash_count(HashArray *pHash);
|
||||
|
||||
/**
|
||||
* hash best optimize
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* suggest_capacity: suggest init capacity for speed
|
||||
* return >0 for success, < 0 fail (errno)
|
||||
*/
|
||||
int hash_best_op(HashArray *pHash, const int suggest_capacity);
|
||||
|
||||
/**
|
||||
* hash stat
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* pStat: return stat info
|
||||
* stat_by_lens: return stats array by bucket length
|
||||
* stat_by_lens[0] empty buckets count
|
||||
* stat_by_lens[1] contain 1 key buckets count
|
||||
* stat_by_lens[2] contain 2 key buckets count, etc
|
||||
* stat_size: stats array size (contain max elments)
|
||||
* return 0 for success, != 0 fail (errno)
|
||||
*/
|
||||
int hash_stat(HashArray *pHash, HashStat *pStat, \
|
||||
int *stat_by_lens, const int stat_size);
|
||||
|
||||
/**
|
||||
* print hash stat info
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* return none
|
||||
*/
|
||||
void hash_stat_print(HashArray *pHash);
|
||||
|
||||
/**
|
||||
* lock the bucket of hash table
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* bucket_index: the index of bucket
|
||||
* return 0 for success, != 0 fail (errno)
|
||||
*/
|
||||
int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
|
||||
|
||||
/**
|
||||
* unlock the bucket of hash table
|
||||
* parameters:
|
||||
* pHash: the hash table
|
||||
* bucket_index: the index of bucket
|
||||
* return 0 for success, != 0 fail (errno)
|
||||
*/
|
||||
int hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index);
|
||||
|
||||
int RSHash(const void *key, const int key_len);
|
||||
|
||||
int JSHash(const void *key, const int key_len);
|
||||
int JSHash_ex(const void *key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int PJWHash(const void *key, const int key_len);
|
||||
int PJWHash_ex(const void *key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int ELFHash(const void *key, const int key_len);
|
||||
int ELFHash_ex(const void *key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int BKDRHash(const void *key, const int key_len);
|
||||
int BKDRHash_ex(const void *key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int SDBMHash(const void *key, const int key_len);
|
||||
int SDBMHash_ex(const void *key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int Time33Hash(const void *key, const int key_len);
|
||||
int Time33Hash_ex(const void *key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int DJBHash(const void *key, const int key_len);
|
||||
int DJBHash_ex(const void *key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int APHash(const void *key, const int key_len);
|
||||
int APHash_ex(const void *key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int calc_hashnr (const void* key, const int key_len);
|
||||
|
||||
int calc_hashnr1(const void* key, const int key_len);
|
||||
int calc_hashnr1_ex(const void* key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int simple_hash(const void* key, const int key_len);
|
||||
int simple_hash_ex(const void* key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
int CRC32(void *key, const int key_len);
|
||||
int CRC32_ex(void *key, const int key_len, \
|
||||
const int init_value);
|
||||
|
||||
#define CRC32_FINAL(crc) (crc ^ CRC32_XOROT)
|
||||
|
||||
#define INIT_HASH_CODES4(hash_codes) \
|
||||
hash_codes[0] = CRC32_XINIT; \
|
||||
hash_codes[1] = 0; \
|
||||
hash_codes[2] = 0; \
|
||||
hash_codes[3] = 0; \
|
||||
|
||||
#define CALC_HASH_CODES4(buff, buff_len, hash_codes) \
|
||||
hash_codes[0] = CRC32_ex(buff, buff_len, hash_codes[0]); \
|
||||
hash_codes[1] = ELFHash_ex(buff, buff_len, hash_codes[1]); \
|
||||
hash_codes[2] = simple_hash_ex(buff, buff_len, hash_codes[2]); \
|
||||
hash_codes[3] = Time33Hash_ex(buff, buff_len, hash_codes[3]); \
|
||||
|
||||
|
||||
#define FINISH_HASH_CODES4(hash_codes) \
|
||||
hash_codes[0] = CRC32_FINAL(hash_codes[0]); \
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,331 +0,0 @@
|
|||
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include "sockopt.h"
|
||||
#include "logger.h"
|
||||
#include "shared_func.h"
|
||||
|
||||
int get_url_content_ex(const char *url, const int url_len,
|
||||
const int connect_timeout, const int network_timeout,
|
||||
int *http_status, char **content, int *content_len, char *error_info)
|
||||
{
|
||||
char domain_name[256];
|
||||
char ip_addr[IP_ADDRESS_SIZE];
|
||||
char out_buff[4096];
|
||||
int domain_len;
|
||||
int out_len;
|
||||
int alloc_size;
|
||||
int recv_bytes;
|
||||
int result;
|
||||
int sock;
|
||||
int port;
|
||||
bool bNeedAlloc;
|
||||
const char *pDomain;
|
||||
const char *pContent;
|
||||
const char *pURI;
|
||||
char *pPort;
|
||||
char *pSpace;
|
||||
|
||||
*http_status = 0;
|
||||
if (*content == NULL)
|
||||
{
|
||||
bNeedAlloc = true;
|
||||
alloc_size = 64 * 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
bNeedAlloc = false;
|
||||
alloc_size = *content_len - 1;
|
||||
}
|
||||
*content_len = 0;
|
||||
|
||||
if (url_len <= 7 || strncasecmp(url, "http://", 7) != 0)
|
||||
{
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"invalid url.", __LINE__);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
pDomain = url + 7;
|
||||
pURI = strchr(pDomain, '/');
|
||||
if (pURI == NULL)
|
||||
{
|
||||
domain_len = url_len - 7;
|
||||
pURI = "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
domain_len = pURI - pDomain;
|
||||
}
|
||||
|
||||
if (domain_len >= sizeof(domain_name))
|
||||
{
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"domain is too large, exceed %d.", \
|
||||
__LINE__, (int)sizeof(domain_name));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
memcpy(domain_name, pDomain, domain_len);
|
||||
*(domain_name + domain_len) = '\0';
|
||||
pPort = strchr(domain_name, ':');
|
||||
if (pPort == NULL)
|
||||
{
|
||||
port = 80;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pPort = '\0';
|
||||
port = atoi(pPort + 1);
|
||||
}
|
||||
|
||||
if (getIpaddrByName(domain_name, ip_addr, \
|
||||
sizeof(ip_addr)) == INADDR_NONE)
|
||||
{
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"resolve domain \"%s\" fail.", \
|
||||
__LINE__, domain_name);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(sock < 0)
|
||||
{
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"socket create failed, errno: %d, " \
|
||||
"error info: %s", __LINE__, \
|
||||
errno, STRERROR(errno));
|
||||
return errno != 0 ? errno : EPERM;
|
||||
}
|
||||
|
||||
if ((result=connectserverbyip_nb_auto(sock, ip_addr, port, \
|
||||
connect_timeout)) != 0)
|
||||
{
|
||||
close(sock);
|
||||
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"connect to %s:%d fail, errno: %d, " \
|
||||
"error info: %s", __LINE__, domain_name, \
|
||||
port, result, STRERROR(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
out_len = snprintf(out_buff, sizeof(out_buff), \
|
||||
"GET %s HTTP/1.0\r\n" \
|
||||
"Host: %s:%d\r\n" \
|
||||
"Connection: close\r\n" \
|
||||
"\r\n", pURI, domain_name, port);
|
||||
if ((result=tcpsenddata(sock, out_buff, out_len, network_timeout)) != 0)
|
||||
{
|
||||
close(sock);
|
||||
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"send data to %s:%d fail, errno: %d, " \
|
||||
"error info: %s", __LINE__, domain_name, \
|
||||
port, result, STRERROR(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (bNeedAlloc)
|
||||
{
|
||||
*content = (char *)malloc(alloc_size + 1);
|
||||
if (*content == NULL)
|
||||
{
|
||||
close(sock);
|
||||
result = errno != 0 ? errno : ENOMEM;
|
||||
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes fail, errno: %d, " \
|
||||
"error info: %s", __LINE__, alloc_size + 1, \
|
||||
result, STRERROR(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
recv_bytes = alloc_size - *content_len;
|
||||
if (recv_bytes <= 0)
|
||||
{
|
||||
if (bNeedAlloc)
|
||||
{
|
||||
alloc_size *= 2;
|
||||
*content = (char *)realloc(*content, alloc_size + 1);
|
||||
if (*content == NULL)
|
||||
{
|
||||
*content_len = 0;
|
||||
close(sock);
|
||||
result = errno != 0 ? errno : ENOMEM;
|
||||
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"realloc %d bytes fail, errno: %d, " \
|
||||
"error info: %s", __LINE__, \
|
||||
alloc_size + 1, \
|
||||
result, STRERROR(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
recv_bytes = alloc_size - *content_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"buffer size: %d is too small", \
|
||||
__LINE__, alloc_size);
|
||||
return ENOSPC;
|
||||
}
|
||||
}
|
||||
|
||||
result = tcprecvdata_ex(sock, *content + *content_len, \
|
||||
recv_bytes, network_timeout, &recv_bytes);
|
||||
|
||||
*content_len += recv_bytes;
|
||||
} while (result == 0);
|
||||
|
||||
do
|
||||
{
|
||||
if (result == ENOTCONN)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
else {
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"recv data from %s:%d fail, errno: %d, " \
|
||||
"error info: %s", __LINE__, domain_name, \
|
||||
port, result, STRERROR(result));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
*(*content + *content_len) = '\0';
|
||||
pContent = strstr(*content, "\r\n\r\n");
|
||||
if (pContent == NULL)
|
||||
{
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"response data from %s:%d is invalid", \
|
||||
__LINE__, domain_name, port);
|
||||
|
||||
result = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
pContent += 4;
|
||||
pSpace = strchr(*content, ' ');
|
||||
if (pSpace == NULL || pSpace >= pContent)
|
||||
{
|
||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||
"response data from %s:%d is invalid", \
|
||||
__LINE__, domain_name, port);
|
||||
|
||||
result = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
*http_status = atoi(pSpace + 1);
|
||||
*content_len -= pContent - *content;
|
||||
memcpy(*content, pContent, *content_len);
|
||||
*(*content + *content_len) = '\0';
|
||||
*error_info = '\0';
|
||||
} while (0);
|
||||
|
||||
close(sock);
|
||||
if (result != 0 && bNeedAlloc)
|
||||
{
|
||||
free(*content);
|
||||
*content = NULL;
|
||||
*content_len = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int get_url_content(const char *url, const int connect_timeout, \
|
||||
const int network_timeout, int *http_status, \
|
||||
char **content, int *content_len, char *error_info)
|
||||
{
|
||||
*content = NULL;
|
||||
return get_url_content_ex(url, strlen(url), connect_timeout, network_timeout,
|
||||
http_status, content, content_len, error_info);
|
||||
}
|
||||
|
||||
int http_parse_query(char *url, KeyValuePair *params, const int max_count)
|
||||
{
|
||||
KeyValuePair *pCurrent;
|
||||
KeyValuePair *pEnd;
|
||||
char *pParamStart;
|
||||
char *p;
|
||||
char *pStrEnd;
|
||||
int value_len;
|
||||
|
||||
pParamStart = strchr(url, '?');
|
||||
if (pParamStart == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pParamStart = '\0';
|
||||
|
||||
pEnd = params + max_count;
|
||||
pCurrent = params;
|
||||
p = pParamStart + 1;
|
||||
while (p != NULL && *p != '\0')
|
||||
{
|
||||
if (pCurrent >= pEnd)
|
||||
{
|
||||
return pCurrent - params;
|
||||
}
|
||||
|
||||
pCurrent->key = p;
|
||||
pStrEnd = strchr(p, '&');
|
||||
if (pStrEnd == NULL)
|
||||
{
|
||||
p = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pStrEnd = '\0';
|
||||
p = pStrEnd + 1;
|
||||
}
|
||||
|
||||
pStrEnd = strchr(pCurrent->key, '=');
|
||||
if (pStrEnd == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
*pStrEnd = '\0';
|
||||
pCurrent->value = pStrEnd + 1;
|
||||
if (*pCurrent->key == '\0')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
urldecode(pCurrent->value, strlen(pCurrent->value), \
|
||||
pCurrent->value, &value_len);
|
||||
pCurrent++;
|
||||
}
|
||||
|
||||
return pCurrent - params;
|
||||
}
|
||||
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#ifndef _HTTP_FUNC_H
|
||||
#define _HTTP_FUNC_H
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "common_define.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
get content from url
|
||||
params:
|
||||
url: the url to fetch, must start as: "http://"
|
||||
connect_timeout: connect timeout in seconds
|
||||
network_timeout: network timeout in seconds
|
||||
http_status: return http status code, 200 for Ok
|
||||
content: return the content (HTTP body only, not including HTTP header),
|
||||
*content should be freed by caller when input *content is NULL for auto malloc
|
||||
content_len: input for *content buffer size when *content is NOT NULL,
|
||||
output for content length (bytes)
|
||||
return: 0 for success, != 0 for error
|
||||
**/
|
||||
int get_url_content_ex(const char *url, const int url_len,
|
||||
const int connect_timeout, const int network_timeout,
|
||||
int *http_status, char **content, int *content_len, char *error_info);
|
||||
|
||||
|
||||
/**
|
||||
get content from url
|
||||
params:
|
||||
url: the url to fetch, must start as: "http://"
|
||||
connect_timeout: connect timeout in seconds
|
||||
network_timeout: network timeout in seconds
|
||||
http_status: return http status code, 200 for Ok
|
||||
content: return the content (HTTP body only, not including HTTP header),
|
||||
*content should be freed by caller
|
||||
content_len: return content length (bytes)
|
||||
return: 0 for success, != 0 for error
|
||||
**/
|
||||
int get_url_content(const char *url, const int connect_timeout, \
|
||||
const int network_timeout, int *http_status, \
|
||||
char **content, int *content_len, char *error_info);
|
||||
|
||||
/**
|
||||
parse url
|
||||
params:
|
||||
url: the url to parse
|
||||
params: params array to store param and it's value
|
||||
max_count: max param count
|
||||
return: param count
|
||||
**/
|
||||
int http_parse_query(char *url, KeyValuePair *params, const int max_count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,785 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//ini_file_reader.c
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include "shared_func.h"
|
||||
#include "logger.h"
|
||||
#include "http_func.h"
|
||||
#include "ini_file_reader.h"
|
||||
|
||||
#define _LINE_BUFFER_SIZE 512
|
||||
#define _ALLOC_ITEMS_ONCE 8
|
||||
|
||||
static int iniDoLoadFromFile(const char *szFilename, \
|
||||
IniContext *pContext);
|
||||
static int iniDoLoadItemsFromBuffer(char *content, \
|
||||
IniContext *pContext);
|
||||
|
||||
static int iniCompareByItemName(const void *p1, const void *p2)
|
||||
{
|
||||
return strcmp(((IniItem *)p1)->name, ((IniItem *)p2)->name);
|
||||
}
|
||||
|
||||
static int iniInitContext(IniContext *pContext)
|
||||
{
|
||||
int result;
|
||||
|
||||
memset(pContext, 0, sizeof(IniContext));
|
||||
pContext->current_section = &pContext->global;
|
||||
if ((result=hash_init(&pContext->sections, PJWHash, 10, 0.75)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"hash_init fail, errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int iniSortHashData(const int index, const HashData *data, void *args)
|
||||
{
|
||||
IniSection *pSection;
|
||||
|
||||
pSection = (IniSection *)data->value;
|
||||
if (pSection->count > 1)
|
||||
{
|
||||
qsort(pSection->items, pSection->count, \
|
||||
sizeof(IniItem), iniCompareByItemName);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iniSortItems(IniContext *pContext)
|
||||
{
|
||||
if (pContext->global.count > 1)
|
||||
{
|
||||
qsort(pContext->global.items, pContext->global.count, \
|
||||
sizeof(IniItem), iniCompareByItemName);
|
||||
}
|
||||
|
||||
hash_walk(&pContext->sections, iniSortHashData, NULL);
|
||||
}
|
||||
|
||||
int iniLoadFromFile(const char *szFilename, IniContext *pContext)
|
||||
{
|
||||
int result;
|
||||
int len;
|
||||
char *pLast;
|
||||
char full_filename[MAX_PATH_SIZE];
|
||||
|
||||
if ((result=iniInitContext(pContext)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (strncasecmp(szFilename, "http://", 7) == 0)
|
||||
{
|
||||
*pContext->config_path = '\0';
|
||||
snprintf(full_filename, sizeof(full_filename),"%s",szFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*szFilename == '/')
|
||||
{
|
||||
pLast = strrchr(szFilename, '/');
|
||||
len = pLast - szFilename;
|
||||
if (len >= sizeof(pContext->config_path))
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, "\
|
||||
"the path of the config file: %s is " \
|
||||
"too long!", __LINE__, szFilename);
|
||||
return ENOSPC;
|
||||
}
|
||||
|
||||
memcpy(pContext->config_path, szFilename, len);
|
||||
*(pContext->config_path + len) = '\0';
|
||||
snprintf(full_filename, sizeof(full_filename), \
|
||||
"%s", szFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(pContext->config_path, 0, \
|
||||
sizeof(pContext->config_path));
|
||||
if (getcwd(pContext->config_path, sizeof( \
|
||||
pContext->config_path)) == NULL)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"getcwd fail, errno: %d, " \
|
||||
"error info: %s", \
|
||||
__LINE__, errno, STRERROR(errno));
|
||||
return errno != 0 ? errno : EPERM;
|
||||
}
|
||||
|
||||
len = strlen(pContext->config_path);
|
||||
if (len > 0 && pContext->config_path[len - 1] == '/')
|
||||
{
|
||||
len--;
|
||||
*(pContext->config_path + len) = '\0';
|
||||
}
|
||||
|
||||
snprintf(full_filename, sizeof(full_filename), \
|
||||
"%s/%s", pContext->config_path, szFilename);
|
||||
|
||||
pLast = strrchr(szFilename, '/');
|
||||
if (pLast != NULL)
|
||||
{
|
||||
int tail_len;
|
||||
|
||||
tail_len = pLast - szFilename;
|
||||
if (len + 1 + tail_len >= sizeof( \
|
||||
pContext->config_path))
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, "\
|
||||
"the path of the config " \
|
||||
"file: %s is too long!", \
|
||||
__LINE__, szFilename);
|
||||
return ENOSPC;
|
||||
}
|
||||
|
||||
*(pContext->config_path + len++) = '/';
|
||||
memcpy(pContext->config_path + len, \
|
||||
szFilename, tail_len);
|
||||
len += tail_len;
|
||||
*(pContext->config_path + len) = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = iniDoLoadFromFile(full_filename, pContext);
|
||||
if (result == 0)
|
||||
{
|
||||
iniSortItems(pContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
iniFreeContext(pContext);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int iniDoLoadFromFile(const char *szFilename, \
|
||||
IniContext *pContext)
|
||||
{
|
||||
char *content;
|
||||
int result;
|
||||
int http_status;
|
||||
int content_len;
|
||||
int64_t file_size;
|
||||
char error_info[512];
|
||||
|
||||
if (strncasecmp(szFilename, "http://", 7) == 0)
|
||||
{
|
||||
if ((result=get_url_content(szFilename, 10, 60, &http_status, \
|
||||
&content, &content_len, error_info)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"get_url_content fail, " \
|
||||
"url: %s, error info: %s", \
|
||||
__LINE__, szFilename, error_info);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (http_status != 200)
|
||||
{
|
||||
free(content);
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"HTTP status code: %d != 200, url: %s", \
|
||||
__LINE__, http_status, szFilename);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((result=getFileContent(szFilename, &content, \
|
||||
&file_size)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result = iniDoLoadItemsFromBuffer(content, pContext);
|
||||
free(content);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int iniLoadFromBuffer(char *content, IniContext *pContext)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result=iniInitContext(pContext)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = iniDoLoadItemsFromBuffer(content, pContext);
|
||||
if (result == 0)
|
||||
{
|
||||
iniSortItems(pContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
iniFreeContext(pContext);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
|
||||
{
|
||||
IniSection *pSection;
|
||||
IniItem *pItem;
|
||||
char *pLine;
|
||||
char *pLastEnd;
|
||||
char *pEqualChar;
|
||||
char *pIncludeFilename;
|
||||
char full_filename[MAX_PATH_SIZE];
|
||||
int nLineLen;
|
||||
int nNameLen;
|
||||
int nValueLen;
|
||||
int result;
|
||||
|
||||
result = 0;
|
||||
pLastEnd = content - 1;
|
||||
pSection = pContext->current_section;
|
||||
if (pSection->count > 0)
|
||||
{
|
||||
pItem = pSection->items + pSection->count;
|
||||
}
|
||||
else
|
||||
{
|
||||
pItem = pSection->items;
|
||||
}
|
||||
|
||||
while (pLastEnd != NULL)
|
||||
{
|
||||
pLine = pLastEnd + 1;
|
||||
pLastEnd = strchr(pLine, '\n');
|
||||
if (pLastEnd != NULL)
|
||||
{
|
||||
*pLastEnd = '\0';
|
||||
}
|
||||
|
||||
if (*pLine == '#' && \
|
||||
strncasecmp(pLine+1, "include", 7) == 0 && \
|
||||
(*(pLine+8) == ' ' || *(pLine+8) == '\t'))
|
||||
{
|
||||
pIncludeFilename = strdup(pLine + 9);
|
||||
if (pIncludeFilename == NULL)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"strdup %d bytes fail", __LINE__, \
|
||||
(int)strlen(pLine + 9) + 1);
|
||||
result = errno != 0 ? errno : ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
trim(pIncludeFilename);
|
||||
if (strncasecmp(pIncludeFilename, "http://", 7) == 0)
|
||||
{
|
||||
snprintf(full_filename, sizeof(full_filename),\
|
||||
"%s", pIncludeFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*pIncludeFilename == '/')
|
||||
{
|
||||
snprintf(full_filename, sizeof(full_filename), \
|
||||
"%s", pIncludeFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(full_filename, sizeof(full_filename), \
|
||||
"%s/%s", pContext->config_path, \
|
||||
pIncludeFilename);
|
||||
}
|
||||
|
||||
if (!fileExists(full_filename))
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"include file \"%s\" not exists, " \
|
||||
"line: \"%s\"", __LINE__, \
|
||||
pIncludeFilename, pLine);
|
||||
free(pIncludeFilename);
|
||||
result = ENOENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = iniDoLoadFromFile(full_filename, pContext);
|
||||
if (result != 0)
|
||||
{
|
||||
free(pIncludeFilename);
|
||||
break;
|
||||
}
|
||||
|
||||
pSection = pContext->current_section;
|
||||
if (pSection->count > 0)
|
||||
{
|
||||
pItem = pSection->items + pSection->count; //must re-asign
|
||||
}
|
||||
else
|
||||
{
|
||||
pItem = pSection->items;
|
||||
}
|
||||
|
||||
free(pIncludeFilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
trim(pLine);
|
||||
if (*pLine == '#' || *pLine == '\0')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
nLineLen = strlen(pLine);
|
||||
if (*pLine == '[' && *(pLine + (nLineLen - 1)) == ']') //section
|
||||
{
|
||||
char *section_name;
|
||||
int section_len;
|
||||
|
||||
*(pLine + (nLineLen - 1)) = '\0';
|
||||
section_name = pLine + 1; //skip [
|
||||
|
||||
trim(section_name);
|
||||
if (*section_name == '\0') //global section
|
||||
{
|
||||
pContext->current_section = &pContext->global;
|
||||
pSection = pContext->current_section;
|
||||
if (pSection->count > 0)
|
||||
{
|
||||
pItem = pSection->items + pSection->count;
|
||||
}
|
||||
else
|
||||
{
|
||||
pItem = pSection->items;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
section_len = strlen(section_name);
|
||||
pSection = (IniSection *)hash_find(&pContext->sections,\
|
||||
section_name, section_len);
|
||||
if (pSection == NULL)
|
||||
{
|
||||
pSection = (IniSection *)malloc(sizeof(IniSection));
|
||||
if (pSection == NULL)
|
||||
{
|
||||
result = errno != 0 ? errno : ENOMEM;
|
||||
logError("file: "__FILE__", line: %d, "\
|
||||
"malloc %d bytes fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, \
|
||||
(int)sizeof(IniSection), \
|
||||
result, STRERROR(result));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
memset(pSection, 0, sizeof(IniSection));
|
||||
result = hash_insert(&pContext->sections, \
|
||||
section_name, section_len, pSection);
|
||||
if (result < 0)
|
||||
{
|
||||
result *= -1;
|
||||
logError("file: "__FILE__", line: %d, "\
|
||||
"insert into hash table fail, "\
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, \
|
||||
STRERROR(result));
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pContext->current_section = pSection;
|
||||
if (pSection->count > 0)
|
||||
{
|
||||
pItem = pSection->items + pSection->count;
|
||||
}
|
||||
else
|
||||
{
|
||||
pItem = pSection->items;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
pEqualChar = strchr(pLine, '=');
|
||||
if (pEqualChar == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
nNameLen = pEqualChar - pLine;
|
||||
nValueLen = strlen(pLine) - (nNameLen + 1);
|
||||
if (nNameLen > FAST_INI_ITEM_NAME_LEN)
|
||||
{
|
||||
nNameLen = FAST_INI_ITEM_NAME_LEN;
|
||||
}
|
||||
|
||||
if (nValueLen > FAST_INI_ITEM_VALUE_LEN)
|
||||
{
|
||||
nValueLen = FAST_INI_ITEM_VALUE_LEN;
|
||||
}
|
||||
|
||||
if (pSection->count >= pSection->alloc_count)
|
||||
{
|
||||
pSection->alloc_count += _ALLOC_ITEMS_ONCE;
|
||||
pSection->items=(IniItem *)realloc(pSection->items,
|
||||
sizeof(IniItem) * pSection->alloc_count);
|
||||
if (pSection->items == NULL)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"realloc %d bytes fail", __LINE__, \
|
||||
(int)sizeof(IniItem) * \
|
||||
pSection->alloc_count);
|
||||
result = errno != 0 ? errno : ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
pItem = pSection->items + pSection->count;
|
||||
memset(pItem, 0, sizeof(IniItem) * \
|
||||
(pSection->alloc_count - pSection->count));
|
||||
}
|
||||
|
||||
memcpy(pItem->name, pLine, nNameLen);
|
||||
memcpy(pItem->value, pEqualChar + 1, nValueLen);
|
||||
|
||||
trim(pItem->name);
|
||||
trim(pItem->value);
|
||||
|
||||
pSection->count++;
|
||||
pItem++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int iniFreeHashData(const int index, const HashData *data, void *args)
|
||||
{
|
||||
IniSection *pSection;
|
||||
|
||||
pSection = (IniSection *)data->value;
|
||||
if (pSection == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pSection->items != NULL)
|
||||
{
|
||||
free(pSection->items);
|
||||
memset(pSection, 0, sizeof(IniSection));
|
||||
}
|
||||
|
||||
free(pSection);
|
||||
((HashData *)data)->value = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iniFreeContext(IniContext *pContext)
|
||||
{
|
||||
if (pContext == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pContext->global.items != NULL)
|
||||
{
|
||||
free(pContext->global.items);
|
||||
memset(&pContext->global, 0, sizeof(IniSection));
|
||||
}
|
||||
|
||||
hash_walk(&pContext->sections, iniFreeHashData, NULL);
|
||||
hash_destroy(&pContext->sections);
|
||||
}
|
||||
|
||||
|
||||
#define INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
|
||||
targetItem, pItem, return_val) \
|
||||
if (szSectionName == NULL || *szSectionName == '\0') \
|
||||
{ \
|
||||
pSection = &pContext->global; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
pSection = (IniSection *)hash_find(&pContext->sections, \
|
||||
szSectionName, strlen(szSectionName)); \
|
||||
if (pSection == NULL) \
|
||||
{ \
|
||||
return return_val; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (pSection->count <= 0) \
|
||||
{ \
|
||||
return return_val; \
|
||||
} \
|
||||
\
|
||||
snprintf(targetItem.name, sizeof(targetItem.name), "%s", szItemName); \
|
||||
pItem = (IniItem *)bsearch(&targetItem, pSection->items, \
|
||||
pSection->count, sizeof(IniItem), iniCompareByItemName);
|
||||
|
||||
|
||||
char *iniGetStrValue(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext)
|
||||
{
|
||||
IniItem targetItem;
|
||||
IniSection *pSection;
|
||||
IniItem *pItem;
|
||||
|
||||
INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
|
||||
targetItem, pItem, NULL)
|
||||
|
||||
if (pItem == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pItem->value;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t iniGetInt64Value(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, const int64_t nDefaultValue)
|
||||
{
|
||||
char *pValue;
|
||||
|
||||
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
|
||||
if (pValue == NULL)
|
||||
{
|
||||
return nDefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return strtoll(pValue, NULL, 10);
|
||||
}
|
||||
}
|
||||
|
||||
int iniGetIntValue(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, const int nDefaultValue)
|
||||
{
|
||||
char *pValue;
|
||||
|
||||
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
|
||||
if (pValue == NULL)
|
||||
{
|
||||
return nDefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return atoi(pValue);
|
||||
}
|
||||
}
|
||||
|
||||
double iniGetDoubleValue(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, const double dbDefaultValue)
|
||||
{
|
||||
char *pValue;
|
||||
|
||||
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
|
||||
if (pValue == NULL)
|
||||
{
|
||||
return dbDefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return strtod(pValue, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool iniGetBoolValue(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, const bool bDefaultValue)
|
||||
{
|
||||
char *pValue;
|
||||
|
||||
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
|
||||
if (pValue == NULL)
|
||||
{
|
||||
return bDefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return strcasecmp(pValue, "true") == 0 ||
|
||||
strcasecmp(pValue, "yes") == 0 ||
|
||||
strcasecmp(pValue, "on") == 0 ||
|
||||
strcmp(pValue, "1") == 0;
|
||||
}
|
||||
}
|
||||
|
||||
int iniGetValues(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, char **szValues, const int max_values)
|
||||
{
|
||||
IniItem targetItem;
|
||||
IniSection *pSection;
|
||||
IniItem *pFound;
|
||||
IniItem *pItem;
|
||||
IniItem *pItemEnd;
|
||||
char **ppValues;
|
||||
|
||||
if (max_values <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
|
||||
targetItem, pFound, 0)
|
||||
if (pFound == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ppValues = szValues;
|
||||
*ppValues++ = pFound->value;
|
||||
for (pItem=pFound-1; pItem>=pSection->items; pItem--)
|
||||
{
|
||||
if (strcmp(pItem->name, szItemName) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ppValues - szValues < max_values)
|
||||
{
|
||||
*ppValues++ = pItem->value;
|
||||
}
|
||||
}
|
||||
|
||||
pItemEnd = pSection->items + pSection->count;
|
||||
for (pItem=pFound+1; pItem<pItemEnd; pItem++)
|
||||
{
|
||||
if (strcmp(pItem->name, szItemName) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ppValues - szValues < max_values)
|
||||
{
|
||||
*ppValues++ = pItem->value;
|
||||
}
|
||||
}
|
||||
|
||||
return ppValues - szValues;
|
||||
}
|
||||
|
||||
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, int *nTargetCount)
|
||||
{
|
||||
IniItem targetItem;
|
||||
IniSection *pSection;
|
||||
IniItem *pFound;
|
||||
IniItem *pItem;
|
||||
IniItem *pItemEnd;
|
||||
IniItem *pItemStart;
|
||||
|
||||
*nTargetCount = 0;
|
||||
INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
|
||||
targetItem, pFound, NULL)
|
||||
if (pFound == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*nTargetCount = 1;
|
||||
for (pItem=pFound-1; pItem>=pSection->items; pItem--)
|
||||
{
|
||||
if (strcmp(pItem->name, szItemName) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
(*nTargetCount)++;
|
||||
}
|
||||
pItemStart = pFound - (*nTargetCount) + 1;
|
||||
|
||||
pItemEnd = pSection->items + pSection->count;
|
||||
for (pItem=pFound+1; pItem<pItemEnd; pItem++)
|
||||
{
|
||||
if (strcmp(pItem->name, szItemName) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
(*nTargetCount)++;
|
||||
}
|
||||
|
||||
return pItemStart;
|
||||
}
|
||||
|
||||
static int iniPrintHashData(const int index, const HashData *data, void *args)
|
||||
{
|
||||
IniSection *pSection;
|
||||
IniItem *pItem;
|
||||
IniItem *pItemEnd;
|
||||
char section_name[256];
|
||||
int section_len;
|
||||
int i;
|
||||
|
||||
pSection = (IniSection *)data->value;
|
||||
if (pSection == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
section_len = data->key_len;
|
||||
if (section_len >= sizeof(section_name))
|
||||
{
|
||||
section_len = sizeof(section_name) - 1;
|
||||
}
|
||||
|
||||
memcpy(section_name, data->key, section_len);
|
||||
*(section_name + section_len) = '\0';
|
||||
|
||||
printf("section: %s, item count: %d\n", section_name, pSection->count);
|
||||
if (pSection->count > 0)
|
||||
{
|
||||
i = 0;
|
||||
pItemEnd = pSection->items + pSection->count;
|
||||
for (pItem=pSection->items; pItem<pItemEnd; pItem++)
|
||||
{
|
||||
printf("%d. %s=%s\n", ++i, pItem->name, pItem->value);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iniPrintItems(IniContext *pContext)
|
||||
{
|
||||
IniItem *pItem;
|
||||
IniItem *pItemEnd;
|
||||
int i;
|
||||
|
||||
printf("global section, item count: %d\n", pContext->global.count);
|
||||
if (pContext->global.count > 0)
|
||||
{
|
||||
i = 0;
|
||||
pItemEnd = pContext->global.items + pContext->global.count;
|
||||
for (pItem=pContext->global.items; pItem<pItemEnd; pItem++)
|
||||
{
|
||||
printf("%d. %s=%s\n", ++i, pItem->name, pItem->value);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
hash_walk(&pContext->sections, iniPrintHashData, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//ini_file_reader.h
|
||||
#ifndef INI_FILE_READER_H
|
||||
#define INI_FILE_READER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "common_define.h"
|
||||
#include "hash.h"
|
||||
|
||||
#define FAST_INI_ITEM_NAME_LEN 64
|
||||
#define FAST_INI_ITEM_VALUE_LEN 256
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[FAST_INI_ITEM_NAME_LEN + 1];
|
||||
char value[FAST_INI_ITEM_VALUE_LEN + 1];
|
||||
} IniItem;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IniItem *items;
|
||||
int count; //item count
|
||||
int alloc_count;
|
||||
} IniSection;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IniSection global;
|
||||
HashArray sections; //key is session name, and value is IniSection
|
||||
IniSection *current_section; //for load from ini file
|
||||
char config_path[MAX_PATH_SIZE]; //save the config filepath
|
||||
} IniContext;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** load ini items from file
|
||||
* parameters:
|
||||
* szFilename: the filename, can be an URL
|
||||
* pContext: the ini context
|
||||
* return: error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int iniLoadFromFile(const char *szFilename, IniContext *pContext);
|
||||
|
||||
/** load ini items from string buffer
|
||||
* parameters:
|
||||
* content: the string buffer to parse
|
||||
* pContext: the ini context
|
||||
* return: error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int iniLoadFromBuffer(char *content, IniContext *pContext);
|
||||
|
||||
/** free ini context
|
||||
* parameters:
|
||||
* pContext: the ini context
|
||||
* return: none
|
||||
*/
|
||||
void iniFreeContext(IniContext *pContext);
|
||||
|
||||
/** get item string value
|
||||
* parameters:
|
||||
* szSectionName: the section name, NULL or empty string for
|
||||
* global section
|
||||
* szItemName: the item name
|
||||
* pContext: the ini context
|
||||
* return: item value, return NULL when the item not exist
|
||||
*/
|
||||
char *iniGetStrValue(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext);
|
||||
|
||||
/** get item string value
|
||||
* parameters:
|
||||
* szSectionName: the section name, NULL or empty string for
|
||||
* global section
|
||||
* szItemName: the item name
|
||||
* pContext: the ini context
|
||||
* szValues: string array to store the values
|
||||
* max_values: max string array elements
|
||||
* return: item value count
|
||||
*/
|
||||
int iniGetValues(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, char **szValues, const int max_values);
|
||||
|
||||
/** get item int value (32 bits)
|
||||
* parameters:
|
||||
* szSectionName: the section name, NULL or empty string for
|
||||
* global section
|
||||
* szItemName: the item name
|
||||
* pContext: the ini context
|
||||
* nDefaultValue: the default value
|
||||
* return: item value, return nDefaultValue when the item not exist
|
||||
*/
|
||||
int iniGetIntValue(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, const int nDefaultValue);
|
||||
|
||||
/** get item string value array
|
||||
* parameters:
|
||||
* szSectionName: the section name, NULL or empty string for
|
||||
* global section
|
||||
* szItemName: the item name
|
||||
* pContext: the ini context
|
||||
* nTargetCount: store the item value count
|
||||
* return: item value array, return NULL when the item not exist
|
||||
*/
|
||||
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, int *nTargetCount);
|
||||
|
||||
/** get item int64 value (64 bits)
|
||||
* parameters:
|
||||
* szSectionName: the section name, NULL or empty string for
|
||||
* global section
|
||||
* szItemName: the item name
|
||||
* pContext: the ini context
|
||||
* nDefaultValue: the default value
|
||||
* return: int64 value, return nDefaultValue when the item not exist
|
||||
*/
|
||||
int64_t iniGetInt64Value(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, const int64_t nDefaultValue);
|
||||
|
||||
/** get item boolean value
|
||||
* parameters:
|
||||
* szSectionName: the section name, NULL or empty string for
|
||||
* global section
|
||||
* szItemName: the item name
|
||||
* pContext: the ini context
|
||||
* bDefaultValue: the default value
|
||||
* return: item boolean value, return bDefaultValue when the item not exist
|
||||
*/
|
||||
bool iniGetBoolValue(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, const bool bDefaultValue);
|
||||
|
||||
/** get item double value
|
||||
* parameters:
|
||||
* szSectionName: the section name, NULL or empty string for
|
||||
* global section
|
||||
* szItemName: the item name
|
||||
* pContext: the ini context
|
||||
* dbDefaultValue: the default value
|
||||
* return: item value, return dbDefaultValue when the item not exist
|
||||
*/
|
||||
double iniGetDoubleValue(const char *szSectionName, const char *szItemName, \
|
||||
IniContext *pContext, const double dbDefaultValue);
|
||||
|
||||
/** print all items
|
||||
* parameters:
|
||||
* pContext: the ini context
|
||||
* return: none
|
||||
*/
|
||||
void iniPrintItems(IniContext *pContext);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
179
common/ioevent.c
179
common/ioevent.c
|
|
@ -1,179 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "ioevent.h"
|
||||
|
||||
#if IOEVENT_USE_KQUEUE
|
||||
/* we define these here as numbers, because for kqueue mapping them to a combination of
|
||||
* filters / flags is hard to do. */
|
||||
int kqueue_ev_convert(int16_t event, uint16_t flags)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (event == EVFILT_READ) {
|
||||
r = KPOLLIN;
|
||||
}
|
||||
else if (event == EVFILT_WRITE) {
|
||||
r = KPOLLOUT;
|
||||
}
|
||||
else {
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (flags & EV_EOF) {
|
||||
r |= KPOLLHUP;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ioevent_init(IOEventPoller *ioevent, const int size,
|
||||
const int timeout, const int extra_events)
|
||||
{
|
||||
int bytes;
|
||||
|
||||
ioevent->size = size;
|
||||
ioevent->extra_events = extra_events;
|
||||
|
||||
#if IOEVENT_USE_EPOLL
|
||||
ioevent->timeout = timeout;
|
||||
ioevent->poll_fd = epoll_create(ioevent->size);
|
||||
bytes = sizeof(struct epoll_event) * size;
|
||||
ioevent->events = (struct epoll_event *)malloc(bytes);
|
||||
#elif IOEVENT_USE_KQUEUE
|
||||
ioevent->timeout.tv_sec = timeout / 1000;
|
||||
ioevent->timeout.tv_nsec = 1000000 * (timeout % 1000);
|
||||
ioevent->poll_fd = kqueue();
|
||||
bytes = sizeof(struct kevent) * size;
|
||||
ioevent->events = (struct kevent *)malloc(bytes);
|
||||
#elif IOEVENT_USE_PORT
|
||||
ioevent->timeout.tv_sec = timeout / 1000;
|
||||
ioevent->timeout.tv_nsec = 1000000 * (timeout % 1000);
|
||||
ioevent->poll_fd = port_create();
|
||||
bytes = sizeof(port_event_t) * size;
|
||||
ioevent->events = (port_event_t *)malloc(bytes);
|
||||
#endif
|
||||
if (ioevent->events == NULL) {
|
||||
return errno != 0 ? errno : ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ioevent_destroy(IOEventPoller *ioevent)
|
||||
{
|
||||
if (ioevent->events != NULL) {
|
||||
free(ioevent->events);
|
||||
ioevent->events = NULL;
|
||||
}
|
||||
|
||||
if (ioevent->poll_fd >=0) {
|
||||
close(ioevent->poll_fd);
|
||||
ioevent->poll_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
|
||||
void *data)
|
||||
{
|
||||
#if IOEVENT_USE_EPOLL
|
||||
struct epoll_event ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.events = e | ioevent->extra_events;
|
||||
ev.data.ptr = data;
|
||||
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_ADD, fd, &ev);
|
||||
#elif IOEVENT_USE_KQUEUE
|
||||
struct kevent ev[2];
|
||||
int n = 0;
|
||||
if (e & IOEVENT_READ) {
|
||||
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | ioevent->extra_events, 0, 0, data);
|
||||
}
|
||||
if (e & IOEVENT_WRITE) {
|
||||
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
|
||||
}
|
||||
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
|
||||
#elif IOEVENT_USE_PORT
|
||||
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
|
||||
void *data)
|
||||
{
|
||||
#if IOEVENT_USE_EPOLL
|
||||
struct epoll_event ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.events = e | ioevent->extra_events;
|
||||
ev.data.ptr = data;
|
||||
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_MOD, fd, &ev);
|
||||
#elif IOEVENT_USE_KQUEUE
|
||||
struct kevent ev[2];
|
||||
int n = 0;
|
||||
if (e & IOEVENT_READ) {
|
||||
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | ioevent->extra_events, 0, 0, data);
|
||||
}
|
||||
else {
|
||||
EV_SET(&ev[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, data);
|
||||
}
|
||||
|
||||
if (e & IOEVENT_WRITE) {
|
||||
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
|
||||
}
|
||||
else {
|
||||
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, data);
|
||||
}
|
||||
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
|
||||
#elif IOEVENT_USE_PORT
|
||||
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ioevent_detach(IOEventPoller *ioevent, const int fd)
|
||||
{
|
||||
#if IOEVENT_USE_EPOLL
|
||||
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL);
|
||||
#elif IOEVENT_USE_PORT
|
||||
return port_dissociate(ioevent->poll_fd, PORT_SOURCE_FD, fd);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ioevent_poll(IOEventPoller *ioevent)
|
||||
{
|
||||
#if IOEVENT_USE_EPOLL
|
||||
return epoll_wait(ioevent->poll_fd, ioevent->events, ioevent->size, ioevent->timeout);
|
||||
#elif IOEVENT_USE_KQUEUE
|
||||
return kevent(ioevent->poll_fd, NULL, 0, ioevent->events, ioevent->size, &ioevent->timeout);
|
||||
#elif IOEVENT_USE_PORT
|
||||
int result;
|
||||
int retval;
|
||||
unsigned int nget = 1;
|
||||
if((retval = port_getn(ioevent->poll_fd, ioevent->events,
|
||||
ioevent->size, &nget, &ioevent->timeout)) == 0)
|
||||
{
|
||||
result = (int)nget;
|
||||
} else {
|
||||
switch(errno) {
|
||||
case EINTR:
|
||||
case EAGAIN:
|
||||
case ETIME:
|
||||
if (nget > 0) {
|
||||
result = (int)nget;
|
||||
}
|
||||
else {
|
||||
result = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
#error port me
|
||||
#endif
|
||||
}
|
||||
|
||||
113
common/ioevent.h
113
common/ioevent.h
|
|
@ -1,113 +0,0 @@
|
|||
#ifndef __IOEVENT_H__
|
||||
#define __IOEVENT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <poll.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define IOEVENT_TIMEOUT 0x8000
|
||||
|
||||
#if IOEVENT_USE_EPOLL
|
||||
#include <sys/epoll.h>
|
||||
#define IOEVENT_EDGE_TRIGGER EPOLLET
|
||||
|
||||
#define IOEVENT_READ EPOLLIN
|
||||
#define IOEVENT_WRITE EPOLLOUT
|
||||
#define IOEVENT_ERROR (EPOLLERR | EPOLLPRI | EPOLLHUP)
|
||||
|
||||
#elif IOEVENT_USE_KQUEUE
|
||||
#include <sys/event.h>
|
||||
#define IOEVENT_EDGE_TRIGGER EV_CLEAR
|
||||
|
||||
#define KPOLLIN 0x001
|
||||
#define KPOLLPRI 0x002
|
||||
#define KPOLLOUT 0x004
|
||||
#define KPOLLERR 0x010
|
||||
#define KPOLLHUP 0x020
|
||||
#define IOEVENT_READ KPOLLIN
|
||||
#define IOEVENT_WRITE KPOLLOUT
|
||||
#define IOEVENT_ERROR (KPOLLHUP | KPOLLPRI | KPOLLHUP)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int kqueue_ev_convert(int16_t event, uint16_t flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif IOEVENT_USE_PORT
|
||||
#include <port.h>
|
||||
#define IOEVENT_EDGE_TRIGGER 0
|
||||
|
||||
#define IOEVENT_READ POLLIN
|
||||
#define IOEVENT_WRITE POLLOUT
|
||||
#define IOEVENT_ERROR (POLLERR | POLLPRI | POLLHUP)
|
||||
#endif
|
||||
|
||||
typedef struct ioevent_puller {
|
||||
int size; //max events (fd)
|
||||
int extra_events;
|
||||
int poll_fd;
|
||||
|
||||
#if IOEVENT_USE_EPOLL
|
||||
struct epoll_event *events;
|
||||
int timeout;
|
||||
#elif IOEVENT_USE_KQUEUE
|
||||
struct kevent *events;
|
||||
struct timespec timeout;
|
||||
#elif IOEVENT_USE_PORT
|
||||
port_event_t *events;
|
||||
timespec_t timeout;
|
||||
#endif
|
||||
} IOEventPoller;
|
||||
|
||||
#if IOEVENT_USE_EPOLL
|
||||
#define IOEVENT_GET_EVENTS(ioevent, index) \
|
||||
ioevent->events[index].events
|
||||
#elif IOEVENT_USE_KQUEUE
|
||||
#define IOEVENT_GET_EVENTS(ioevent, index) kqueue_ev_convert( \
|
||||
ioevent->events[index].filter, ioevent->events[index].flags)
|
||||
#elif IOEVENT_USE_PORT
|
||||
#define IOEVENT_GET_EVENTS(ioevent, index) \
|
||||
ioevent->events[index].portev_events
|
||||
#else
|
||||
#error port me
|
||||
#endif
|
||||
|
||||
#if IOEVENT_USE_EPOLL
|
||||
#define IOEVENT_GET_DATA(ioevent, index) \
|
||||
ioevent->events[index].data.ptr
|
||||
#elif IOEVENT_USE_KQUEUE
|
||||
#define IOEVENT_GET_DATA(ioevent, index) \
|
||||
ioevent->events[index].udata
|
||||
#elif IOEVENT_USE_PORT
|
||||
#define IOEVENT_GET_DATA(ioevent, index) \
|
||||
ioevent->events[index].portev_user
|
||||
#else
|
||||
#error port me
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ioevent_init(IOEventPoller *ioevent, const int size,
|
||||
const int timeout, const int extra_events);
|
||||
void ioevent_destroy(IOEventPoller *ioevent);
|
||||
|
||||
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
|
||||
void *data);
|
||||
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
|
||||
void *data);
|
||||
int ioevent_detach(IOEventPoller *ioevent, const int fd);
|
||||
int ioevent_poll(IOEventPoller *ioevent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
#include "sched_thread.h"
|
||||
#include "logger.h"
|
||||
#include "ioevent_loop.h"
|
||||
|
||||
static void deal_ioevents(IOEventPoller *ioevent, const int count)
|
||||
{
|
||||
int i;
|
||||
int event;
|
||||
IOEventEntry *pEntry;
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
event = IOEVENT_GET_EVENTS(ioevent, i);
|
||||
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent, i);
|
||||
|
||||
pEntry->callback(pEntry->fd, event, pEntry->timer.data);
|
||||
}
|
||||
}
|
||||
|
||||
static void deal_timeouts(FastTimerEntry *head)
|
||||
{
|
||||
FastTimerEntry *entry;
|
||||
FastTimerEntry *current;
|
||||
IOEventEntry *pEventEntry;
|
||||
|
||||
entry = head->next;
|
||||
while (entry != NULL)
|
||||
{
|
||||
current = entry;
|
||||
entry = entry->next;
|
||||
|
||||
pEventEntry = (IOEventEntry *)current->data;
|
||||
if (pEventEntry != NULL)
|
||||
{
|
||||
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT,
|
||||
current->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ioevent_loop(struct nio_thread_data *pThreadData,
|
||||
IOEventCallback recv_notify_callback, TaskCleanUpCallback
|
||||
clean_up_callback, volatile bool *continue_flag)
|
||||
{
|
||||
int result;
|
||||
IOEventEntry ev_notify;
|
||||
FastTimerEntry head;
|
||||
struct fast_task_info *pTask;
|
||||
time_t last_check_time;
|
||||
int count;
|
||||
|
||||
memset(&ev_notify, 0, sizeof(ev_notify));
|
||||
ev_notify.fd = pThreadData->pipe_fds[0];
|
||||
ev_notify.callback = recv_notify_callback;
|
||||
if (ioevent_attach(&pThreadData->ev_puller,
|
||||
pThreadData->pipe_fds[0], IOEVENT_READ,
|
||||
&ev_notify) != 0)
|
||||
{
|
||||
result = errno != 0 ? errno : ENOMEM;
|
||||
logCrit("file: "__FILE__", line: %d, " \
|
||||
"ioevent_attach fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
last_check_time = g_current_time;
|
||||
while (*continue_flag)
|
||||
{
|
||||
pThreadData->deleted_list = NULL;
|
||||
count = ioevent_poll(&pThreadData->ev_puller);
|
||||
if (count > 0)
|
||||
{
|
||||
deal_ioevents(&pThreadData->ev_puller, count);
|
||||
}
|
||||
else if (count < 0)
|
||||
{
|
||||
result = errno != 0 ? errno : EINVAL;
|
||||
if (result != EINTR)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"ioevent_poll fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (pThreadData->deleted_list != NULL)
|
||||
{
|
||||
count = 0;
|
||||
while (pThreadData->deleted_list != NULL)
|
||||
{
|
||||
pTask = pThreadData->deleted_list;
|
||||
pThreadData->deleted_list = pTask->next;
|
||||
|
||||
clean_up_callback(pTask);
|
||||
count++;
|
||||
}
|
||||
logInfo("cleanup task count: %d", count);
|
||||
}
|
||||
|
||||
if (g_current_time - last_check_time > 0)
|
||||
{
|
||||
last_check_time = g_current_time;
|
||||
count = fast_timer_timeouts_get(
|
||||
&pThreadData->timer, g_current_time, &head);
|
||||
if (count > 0)
|
||||
{
|
||||
deal_timeouts(&head);
|
||||
}
|
||||
}
|
||||
|
||||
if (pThreadData->thread_loop_callback != NULL) {
|
||||
pThreadData->thread_loop_callback(pThreadData);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
|
||||
int sock, short event, IOEventCallback callback, const int timeout)
|
||||
{
|
||||
int result;
|
||||
|
||||
pTask->thread_data = pThread;
|
||||
pTask->event.fd = sock;
|
||||
pTask->event.callback = callback;
|
||||
if (ioevent_attach(&pThread->ev_puller,
|
||||
sock, event, pTask) < 0)
|
||||
{
|
||||
result = errno != 0 ? errno : ENOENT;
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"ioevent_attach fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
pTask->event.timer.data = pTask;
|
||||
pTask->event.timer.expires = g_current_time + timeout;
|
||||
result = fast_timer_add(&pThread->timer, &pTask->event.timer);
|
||||
if (result != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"fast_timer_add fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#ifndef _IOEVENT_LOOP_H
|
||||
#define _IOEVENT_LOOP_H
|
||||
|
||||
#include "fast_task_queue.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ioevent_loop(struct nio_thread_data *pThreadData,
|
||||
IOEventCallback recv_notify_callback, TaskCleanUpCallback
|
||||
clean_up_callback, volatile bool *continue_flag);
|
||||
|
||||
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
|
||||
int sock, short event, IOEventCallback callback, const int timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "logger.h"
|
||||
#include "sockopt.h"
|
||||
#include "shared_func.h"
|
||||
#include "local_ip_func.h"
|
||||
|
||||
int g_local_host_ip_count = 0;
|
||||
char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS * \
|
||||
IP_ADDRESS_SIZE];
|
||||
char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE] = {0};
|
||||
|
||||
bool is_local_host_ip(const char *client_ip)
|
||||
{
|
||||
char *p;
|
||||
char *pEnd;
|
||||
|
||||
pEnd = g_local_host_ip_addrs + \
|
||||
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
||||
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
||||
{
|
||||
if (strcmp(client_ip, p) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int insert_into_local_host_ip(const char *client_ip)
|
||||
{
|
||||
if (is_local_host_ip(client_ip))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (g_local_host_ip_count >= FAST_MAX_LOCAL_IP_ADDRS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(g_local_host_ip_addrs + \
|
||||
IP_ADDRESS_SIZE * g_local_host_ip_count, \
|
||||
client_ip);
|
||||
g_local_host_ip_count++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void log_local_host_ip_addrs()
|
||||
{
|
||||
char *p;
|
||||
char *pEnd;
|
||||
char buff[512];
|
||||
int len;
|
||||
|
||||
len = sprintf(buff, "local_host_ip_count: %d,", g_local_host_ip_count);
|
||||
pEnd = g_local_host_ip_addrs + \
|
||||
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
||||
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
||||
{
|
||||
len += sprintf(buff + len, " %s", p);
|
||||
}
|
||||
|
||||
logInfo("%s", buff);
|
||||
}
|
||||
|
||||
void load_local_host_ip_addrs()
|
||||
{
|
||||
#define STORAGE_MAX_ALIAS_PREFIX_COUNT 4
|
||||
char ip_addresses[FAST_MAX_LOCAL_IP_ADDRS][IP_ADDRESS_SIZE];
|
||||
int count;
|
||||
int k;
|
||||
char *if_alias_prefixes[STORAGE_MAX_ALIAS_PREFIX_COUNT];
|
||||
int alias_count;
|
||||
|
||||
insert_into_local_host_ip("127.0.0.1");
|
||||
|
||||
memset(if_alias_prefixes, 0, sizeof(if_alias_prefixes));
|
||||
if (*g_if_alias_prefix == '\0')
|
||||
{
|
||||
alias_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
alias_count = splitEx(g_if_alias_prefix, ',', \
|
||||
if_alias_prefixes, STORAGE_MAX_ALIAS_PREFIX_COUNT);
|
||||
for (k=0; k<alias_count; k++)
|
||||
{
|
||||
trim(if_alias_prefixes[k]);
|
||||
}
|
||||
}
|
||||
|
||||
if (gethostaddrs(if_alias_prefixes, alias_count, ip_addresses, \
|
||||
FAST_MAX_LOCAL_IP_ADDRS, &count) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (k=0; k<count; k++)
|
||||
{
|
||||
insert_into_local_host_ip(ip_addresses[k]);
|
||||
}
|
||||
|
||||
log_local_host_ip_addrs();
|
||||
//print_local_host_ip_addrs();
|
||||
}
|
||||
|
||||
void print_local_host_ip_addrs()
|
||||
{
|
||||
char *p;
|
||||
char *pEnd;
|
||||
|
||||
printf("local_host_ip_count=%d\n", g_local_host_ip_count);
|
||||
pEnd = g_local_host_ip_addrs + \
|
||||
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
||||
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
||||
{
|
||||
printf("%d. %s\n", (int)((p-g_local_host_ip_addrs)/ \
|
||||
IP_ADDRESS_SIZE)+1, p);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//local_ip_func.h
|
||||
|
||||
#ifndef _LOCAL_IP_FUNC_H
|
||||
#define _LOCAL_IP_FUNC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "common_define.h"
|
||||
|
||||
#define FAST_IF_ALIAS_PREFIX_MAX_SIZE 32
|
||||
#define FAST_MAX_LOCAL_IP_ADDRS 16
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int g_local_host_ip_count;
|
||||
extern char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS * \
|
||||
IP_ADDRESS_SIZE];
|
||||
extern char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE];
|
||||
|
||||
void load_local_host_ip_addrs();
|
||||
bool is_local_host_ip(const char *client_ip);
|
||||
int insert_into_local_host_ip(const char *client_ip);
|
||||
void print_local_host_ip_addrs();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
801
common/logger.c
801
common/logger.c
|
|
@ -1,801 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <pthread.h>
|
||||
#include "shared_func.h"
|
||||
#include "pthread_func.h"
|
||||
#include "sched_thread.h"
|
||||
#include "logger.h"
|
||||
|
||||
#ifndef LINE_MAX
|
||||
#define LINE_MAX 2048
|
||||
#endif
|
||||
|
||||
#define LOG_BUFF_SIZE 64 * 1024
|
||||
|
||||
LogContext g_log_context = {LOG_INFO, STDERR_FILENO, NULL};
|
||||
|
||||
static int log_fsync(LogContext *pContext, const bool bNeedLock);
|
||||
|
||||
static int check_and_mk_log_dir(const char *base_path)
|
||||
{
|
||||
char data_path[MAX_PATH_SIZE];
|
||||
|
||||
snprintf(data_path, sizeof(data_path), "%s/logs", base_path);
|
||||
if (!fileExists(data_path))
|
||||
{
|
||||
if (mkdir(data_path, 0755) != 0)
|
||||
{
|
||||
fprintf(stderr, "mkdir \"%s\" fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
data_path, errno, STRERROR(errno));
|
||||
return errno != 0 ? errno : EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int log_init()
|
||||
{
|
||||
if (g_log_context.log_buff != NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return log_init_ex(&g_log_context);
|
||||
}
|
||||
|
||||
int log_init2()
|
||||
{
|
||||
int result;
|
||||
if ((result=log_init()) != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
log_take_over_stderr();
|
||||
log_take_over_stdout();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int log_init_ex(LogContext *pContext)
|
||||
{
|
||||
int result;
|
||||
|
||||
memset(pContext, 0, sizeof(LogContext));
|
||||
pContext->log_level = LOG_INFO;
|
||||
pContext->log_fd = STDERR_FILENO;
|
||||
pContext->time_precision = LOG_TIME_PRECISION_SECOND;
|
||||
strcpy(pContext->rotate_time_format, "%Y%m%d_%H%M%S");
|
||||
|
||||
pContext->log_buff = (char *)malloc(LOG_BUFF_SIZE);
|
||||
if (pContext->log_buff == NULL)
|
||||
{
|
||||
fprintf(stderr, "malloc %d bytes fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
LOG_BUFF_SIZE, errno, STRERROR(errno));
|
||||
return errno != 0 ? errno : ENOMEM;
|
||||
}
|
||||
pContext->pcurrent_buff = pContext->log_buff;
|
||||
|
||||
if ((result=init_pthread_lock(&(pContext->log_thread_lock))) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int log_open(LogContext *pContext)
|
||||
{
|
||||
if ((pContext->log_fd = open(pContext->log_filename, O_WRONLY | \
|
||||
O_CREAT | O_APPEND, 0644)) < 0)
|
||||
{
|
||||
fprintf(stderr, "open log file \"%s\" to write fail, " \
|
||||
"errno: %d, error info: %s\n", \
|
||||
pContext->log_filename, errno, STRERROR(errno));
|
||||
pContext->log_fd = STDERR_FILENO;
|
||||
return errno != 0 ? errno : EACCES;
|
||||
}
|
||||
|
||||
if (pContext->take_over_stderr) {
|
||||
if (dup2(pContext->log_fd, STDERR_FILENO) < 0) {
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, "
|
||||
"call dup2 fail, errno: %d, error info: %s\n",
|
||||
__LINE__, errno, STRERROR(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (pContext->take_over_stdout) {
|
||||
if (dup2(pContext->log_fd, STDOUT_FILENO) < 0) {
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, "
|
||||
"call dup2 fail, errno: %d, error info: %s\n",
|
||||
__LINE__, errno, STRERROR(errno));
|
||||
}
|
||||
}
|
||||
|
||||
pContext->current_size = lseek(pContext->log_fd, 0, SEEK_END);
|
||||
if (pContext->current_size < 0)
|
||||
{
|
||||
fprintf(stderr, "lseek file \"%s\" fail, " \
|
||||
"errno: %d, error info: %s\n", \
|
||||
pContext->log_filename, errno, STRERROR(errno));
|
||||
return errno != 0 ? errno : EACCES;
|
||||
}
|
||||
if (pContext->current_size == 0 && pContext->print_header_callback != NULL)
|
||||
{
|
||||
pContext->print_header_callback(pContext);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int log_set_prefix_ex(LogContext *pContext, const char *base_path, \
|
||||
const char *filename_prefix)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result=check_and_mk_log_dir(base_path)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s/logs/%s.log", \
|
||||
base_path, filename_prefix);
|
||||
|
||||
return log_open(pContext);
|
||||
}
|
||||
|
||||
int log_set_filename_ex(LogContext *pContext, const char *log_filename)
|
||||
{
|
||||
if (log_filename == NULL) {
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"log_filename is NULL!\n", __LINE__);
|
||||
return EINVAL;
|
||||
}
|
||||
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s", log_filename);
|
||||
return log_open(pContext);
|
||||
}
|
||||
|
||||
void log_set_cache_ex(LogContext *pContext, const bool bLogCache)
|
||||
{
|
||||
pContext->log_to_cache = bLogCache;
|
||||
}
|
||||
|
||||
void log_set_time_precision(LogContext *pContext, const int time_precision)
|
||||
{
|
||||
pContext->time_precision = time_precision;
|
||||
}
|
||||
|
||||
void log_set_rotate_time_format(LogContext *pContext, const char *time_format)
|
||||
{
|
||||
snprintf(pContext->rotate_time_format,
|
||||
sizeof(pContext->rotate_time_format),
|
||||
"%s", time_format);
|
||||
}
|
||||
|
||||
void log_set_keep_days(LogContext *pContext, const int keep_days)
|
||||
{
|
||||
pContext->keep_days = keep_days;
|
||||
}
|
||||
|
||||
void log_set_header_callback(LogContext *pContext, LogHeaderCallback header_callback)
|
||||
{
|
||||
pContext->print_header_callback = header_callback;
|
||||
if (pContext->print_header_callback != NULL)
|
||||
{
|
||||
pthread_mutex_lock(&(pContext->log_thread_lock));
|
||||
if (pContext->current_size == 0)
|
||||
{
|
||||
pContext->print_header_callback(pContext);
|
||||
}
|
||||
pthread_mutex_unlock(&(pContext->log_thread_lock));
|
||||
}
|
||||
}
|
||||
|
||||
void log_take_over_stderr_ex(LogContext *pContext)
|
||||
{
|
||||
pContext->take_over_stderr = true;
|
||||
}
|
||||
|
||||
void log_take_over_stdout_ex(LogContext *pContext)
|
||||
{
|
||||
pContext->take_over_stdout = true;
|
||||
}
|
||||
|
||||
void log_destroy_ex(LogContext *pContext)
|
||||
{
|
||||
if (pContext->log_fd >= 0 && pContext->log_fd != STDERR_FILENO)
|
||||
{
|
||||
log_fsync(pContext, true);
|
||||
|
||||
close(pContext->log_fd);
|
||||
pContext->log_fd = STDERR_FILENO;
|
||||
|
||||
pthread_mutex_destroy(&pContext->log_thread_lock);
|
||||
}
|
||||
|
||||
if (pContext->log_buff != NULL)
|
||||
{
|
||||
free(pContext->log_buff);
|
||||
pContext->log_buff = NULL;
|
||||
pContext->pcurrent_buff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int log_sync_func(void *args)
|
||||
{
|
||||
if (args == NULL)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return log_fsync((LogContext *)args, true);
|
||||
}
|
||||
|
||||
int log_notify_rotate(void *args)
|
||||
{
|
||||
if (args == NULL)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
((LogContext *)args)->rotate_immediately = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int log_delete_old_files(void *args)
|
||||
{
|
||||
LogContext *pContext;
|
||||
char old_filename[MAX_PATH_SIZE + 32];
|
||||
int len;
|
||||
struct tm tm;
|
||||
time_t the_time;
|
||||
|
||||
if (args == NULL)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
pContext = (LogContext *)args;
|
||||
if (*(pContext->log_filename) == '\0' || \
|
||||
*(pContext->rotate_time_format) == '\0')
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (pContext->keep_days <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
the_time = get_current_time() - pContext->keep_days * 86400;
|
||||
while (1) {
|
||||
the_time -= 86400;
|
||||
localtime_r(&the_time, &tm);
|
||||
memset(old_filename, 0, sizeof(old_filename));
|
||||
len = sprintf(old_filename, "%s.", pContext->log_filename);
|
||||
strftime(old_filename + len, sizeof(old_filename) - len,
|
||||
pContext->rotate_time_format, &tm);
|
||||
if (unlink(old_filename) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"unlink %s fail, errno: %d, error info: %s\n", \
|
||||
__LINE__, old_filename, errno, STRERROR(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int log_rotate(LogContext *pContext)
|
||||
{
|
||||
struct tm tm;
|
||||
time_t current_time;
|
||||
int len;
|
||||
char old_filename[MAX_PATH_SIZE + 32];
|
||||
|
||||
if (*(pContext->log_filename) == '\0')
|
||||
{
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
close(pContext->log_fd);
|
||||
|
||||
current_time = get_current_time();
|
||||
localtime_r(¤t_time, &tm);
|
||||
|
||||
memset(old_filename, 0, sizeof(old_filename));
|
||||
len = sprintf(old_filename, "%s.", pContext->log_filename);
|
||||
strftime(old_filename + len, sizeof(old_filename) - len,
|
||||
pContext->rotate_time_format, &tm);
|
||||
if (access(old_filename, F_OK) == 0)
|
||||
{
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"file: %s already exist, rotate file fail\n",
|
||||
__LINE__, old_filename);
|
||||
}
|
||||
else if (rename(pContext->log_filename, old_filename) != 0)
|
||||
{
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"rename %s to %s fail, errno: %d, error info: %s\n", \
|
||||
__LINE__, pContext->log_filename, old_filename, \
|
||||
errno, STRERROR(errno));
|
||||
}
|
||||
|
||||
return log_open(pContext);
|
||||
}
|
||||
|
||||
static int log_check_rotate(LogContext *pContext, const bool bNeedLock)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (pContext->log_fd == STDERR_FILENO)
|
||||
{
|
||||
if (pContext->current_size > 0)
|
||||
{
|
||||
pContext->current_size = 0;
|
||||
}
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
if (bNeedLock)
|
||||
{
|
||||
pthread_mutex_lock(&(pContext->log_thread_lock));
|
||||
}
|
||||
|
||||
if (pContext->rotate_immediately)
|
||||
{
|
||||
result = log_rotate(pContext);
|
||||
pContext->rotate_immediately = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
|
||||
if (bNeedLock)
|
||||
{
|
||||
pthread_mutex_unlock(&(pContext->log_thread_lock));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int log_fsync(LogContext *pContext, const bool bNeedLock)
|
||||
{
|
||||
int result;
|
||||
int lock_res;
|
||||
int write_bytes;
|
||||
|
||||
write_bytes = pContext->pcurrent_buff - pContext->log_buff;
|
||||
if (write_bytes == 0)
|
||||
{
|
||||
if (!pContext->rotate_immediately)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return log_check_rotate(pContext, bNeedLock);
|
||||
}
|
||||
}
|
||||
|
||||
if (bNeedLock && ((lock_res=pthread_mutex_lock( \
|
||||
&(pContext->log_thread_lock))) != 0))
|
||||
{
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_lock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, lock_res, STRERROR(lock_res));
|
||||
}
|
||||
|
||||
if (pContext->rotate_size > 0)
|
||||
{
|
||||
pContext->current_size += write_bytes;
|
||||
if (pContext->current_size > pContext->rotate_size)
|
||||
{
|
||||
pContext->rotate_immediately = true;
|
||||
log_check_rotate(pContext, false);
|
||||
}
|
||||
}
|
||||
|
||||
result = 0;
|
||||
do
|
||||
{
|
||||
write_bytes = pContext->pcurrent_buff - pContext->log_buff;
|
||||
if (write(pContext->log_fd, pContext->log_buff, write_bytes) != \
|
||||
write_bytes)
|
||||
{
|
||||
result = errno != 0 ? errno : EIO;
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"call write fail, errno: %d, error info: %s\n",\
|
||||
__LINE__, result, STRERROR(result));
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
if (pContext->log_fd != STDERR_FILENO)
|
||||
{
|
||||
if (fsync(pContext->log_fd) != 0)
|
||||
{
|
||||
result = errno != 0 ? errno : EIO;
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"call fsync fail, errno: %d, error info: %s\n",\
|
||||
__LINE__, result, STRERROR(result));
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (pContext->rotate_immediately)
|
||||
{
|
||||
result = log_check_rotate(pContext, false);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
pContext->pcurrent_buff = pContext->log_buff;
|
||||
if (bNeedLock && ((lock_res=pthread_mutex_unlock( \
|
||||
&(pContext->log_thread_lock))) != 0))
|
||||
{
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_unlock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, lock_res, STRERROR(lock_res));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void doLogEx(LogContext *pContext, struct timeval *tv, \
|
||||
const char *caption, const char *text, const int text_len, \
|
||||
const bool bNeedSync, const bool bNeedLock)
|
||||
{
|
||||
struct tm tm;
|
||||
int time_fragment;
|
||||
int buff_len;
|
||||
int result;
|
||||
|
||||
if (pContext->time_precision == LOG_TIME_PRECISION_SECOND)
|
||||
{
|
||||
time_fragment = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pContext->time_precision == LOG_TIME_PRECISION_MSECOND)
|
||||
{
|
||||
time_fragment = tv->tv_usec / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
time_fragment = tv->tv_usec;
|
||||
}
|
||||
}
|
||||
|
||||
localtime_r(&tv->tv_sec, &tm);
|
||||
if (bNeedLock && (result=pthread_mutex_lock(&pContext->log_thread_lock)) != 0)
|
||||
{
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_lock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
if (text_len + 64 > LOG_BUFF_SIZE)
|
||||
{
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"log buff size: %d < log text length: %d ", \
|
||||
__LINE__, LOG_BUFF_SIZE, text_len + 64);
|
||||
if (bNeedLock)
|
||||
{
|
||||
pthread_mutex_unlock(&(pContext->log_thread_lock));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pContext->pcurrent_buff - pContext->log_buff) + text_len + 64 \
|
||||
> LOG_BUFF_SIZE)
|
||||
{
|
||||
log_fsync(pContext, false);
|
||||
}
|
||||
|
||||
if (pContext->time_precision == LOG_TIME_PRECISION_SECOND)
|
||||
{
|
||||
buff_len = sprintf(pContext->pcurrent_buff, \
|
||||
"[%04d-%02d-%02d %02d:%02d:%02d] ", \
|
||||
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
buff_len = sprintf(pContext->pcurrent_buff, \
|
||||
"[%04d-%02d-%02d %02d:%02d:%02d.%03d] ", \
|
||||
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec, time_fragment);
|
||||
}
|
||||
pContext->pcurrent_buff += buff_len;
|
||||
|
||||
if (caption != NULL)
|
||||
{
|
||||
buff_len = sprintf(pContext->pcurrent_buff, "%s - ", caption);
|
||||
pContext->pcurrent_buff += buff_len;
|
||||
}
|
||||
memcpy(pContext->pcurrent_buff, text, text_len);
|
||||
pContext->pcurrent_buff += text_len;
|
||||
*pContext->pcurrent_buff++ = '\n';
|
||||
|
||||
if (!pContext->log_to_cache || bNeedSync)
|
||||
{
|
||||
log_fsync(pContext, false);
|
||||
}
|
||||
|
||||
if (bNeedLock && (result=pthread_mutex_unlock(&(pContext->log_thread_lock))) != 0)
|
||||
{
|
||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_unlock fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
}
|
||||
|
||||
void log_it_ex2(LogContext *pContext, const char *caption, \
|
||||
const char *text, const int text_len, \
|
||||
const bool bNeedSync, const bool bNeedLock)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
if (pContext->time_precision == LOG_TIME_PRECISION_SECOND)
|
||||
{
|
||||
tv.tv_sec = get_current_time();
|
||||
tv.tv_usec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gettimeofday(&tv, NULL);
|
||||
}
|
||||
|
||||
doLogEx(pContext, &tv, caption, text, text_len, bNeedSync, bNeedLock);
|
||||
}
|
||||
|
||||
void log_it_ex1(LogContext *pContext, const int priority, \
|
||||
const char *text, const int text_len)
|
||||
{
|
||||
bool bNeedSync;
|
||||
char *caption;
|
||||
|
||||
switch(priority)
|
||||
{
|
||||
case LOG_DEBUG:
|
||||
bNeedSync = true;
|
||||
caption = "DEBUG";
|
||||
break;
|
||||
case LOG_INFO:
|
||||
bNeedSync = true;
|
||||
caption = "INFO";
|
||||
break;
|
||||
case LOG_NOTICE:
|
||||
bNeedSync = false;
|
||||
caption = "NOTICE";
|
||||
break;
|
||||
case LOG_WARNING:
|
||||
bNeedSync = false;
|
||||
caption = "WARNING";
|
||||
break;
|
||||
case LOG_ERR:
|
||||
bNeedSync = false;
|
||||
caption = "ERROR";
|
||||
break;
|
||||
case LOG_CRIT:
|
||||
bNeedSync = true;
|
||||
caption = "CRIT";
|
||||
break;
|
||||
case LOG_ALERT:
|
||||
bNeedSync = true;
|
||||
caption = "ALERT";
|
||||
break;
|
||||
case LOG_EMERG:
|
||||
bNeedSync = true;
|
||||
caption = "EMERG";
|
||||
break;
|
||||
default:
|
||||
bNeedSync = false;
|
||||
caption = "UNKOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
log_it_ex2(pContext, caption, text, text_len, bNeedSync, true);
|
||||
}
|
||||
|
||||
void log_it_ex(LogContext *pContext, const int priority, const char *format, ...)
|
||||
{
|
||||
bool bNeedSync;
|
||||
char text[LINE_MAX];
|
||||
char *caption;
|
||||
int len;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
len = vsnprintf(text, sizeof(text), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
switch(priority)
|
||||
{
|
||||
case LOG_DEBUG:
|
||||
bNeedSync = true;
|
||||
caption = "DEBUG";
|
||||
break;
|
||||
case LOG_INFO:
|
||||
bNeedSync = true;
|
||||
caption = "INFO";
|
||||
break;
|
||||
case LOG_NOTICE:
|
||||
bNeedSync = false;
|
||||
caption = "NOTICE";
|
||||
break;
|
||||
case LOG_WARNING:
|
||||
bNeedSync = false;
|
||||
caption = "WARNING";
|
||||
break;
|
||||
case LOG_ERR:
|
||||
bNeedSync = false;
|
||||
caption = "ERROR";
|
||||
break;
|
||||
case LOG_CRIT:
|
||||
bNeedSync = true;
|
||||
caption = "CRIT";
|
||||
break;
|
||||
case LOG_ALERT:
|
||||
bNeedSync = true;
|
||||
caption = "ALERT";
|
||||
break;
|
||||
case LOG_EMERG:
|
||||
bNeedSync = true;
|
||||
caption = "EMERG";
|
||||
break;
|
||||
default:
|
||||
bNeedSync = false;
|
||||
caption = "UNKOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
log_it_ex2(pContext, caption, text, len, bNeedSync, true);
|
||||
}
|
||||
|
||||
|
||||
#define _DO_LOG(pContext, priority, caption, bNeedSync) \
|
||||
char text[LINE_MAX]; \
|
||||
int len; \
|
||||
\
|
||||
if (pContext->log_level < priority) \
|
||||
{ \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
{ \
|
||||
va_list ap; \
|
||||
va_start(ap, format); \
|
||||
len = vsnprintf(text, sizeof(text), format, ap); \
|
||||
va_end(ap); \
|
||||
} \
|
||||
\
|
||||
log_it_ex2(pContext, caption, text, len, bNeedSync, true); \
|
||||
|
||||
|
||||
void logEmergEx(LogContext *pContext, const char *format, ...)
|
||||
{
|
||||
_DO_LOG(pContext, LOG_EMERG, "EMERG", true)
|
||||
}
|
||||
|
||||
void logAlertEx(LogContext *pContext, const char *format, ...)
|
||||
{
|
||||
_DO_LOG(pContext, LOG_ALERT, "ALERT", true)
|
||||
}
|
||||
|
||||
void logCritEx(LogContext *pContext, const char *format, ...)
|
||||
{
|
||||
_DO_LOG(pContext, LOG_CRIT, "CRIT", true)
|
||||
}
|
||||
|
||||
void logErrorEx(LogContext *pContext, const char *format, ...)
|
||||
{
|
||||
_DO_LOG(pContext, LOG_ERR, "ERROR", false)
|
||||
}
|
||||
|
||||
void logWarningEx(LogContext *pContext, const char *format, ...)
|
||||
{
|
||||
_DO_LOG(pContext, LOG_WARNING, "WARNING", false)
|
||||
}
|
||||
|
||||
void logNoticeEx(LogContext *pContext, const char *format, ...)
|
||||
{
|
||||
_DO_LOG(pContext, LOG_NOTICE, "NOTICE", false)
|
||||
}
|
||||
|
||||
void logInfoEx(LogContext *pContext, const char *format, ...)
|
||||
{
|
||||
_DO_LOG(pContext, LOG_INFO, "INFO", false)
|
||||
}
|
||||
|
||||
void logDebugEx(LogContext *pContext, const char *format, ...)
|
||||
{
|
||||
_DO_LOG(pContext, LOG_DEBUG, "DEBUG", false)
|
||||
}
|
||||
|
||||
void logAccess(LogContext *pContext, struct timeval *tvStart, \
|
||||
const char *format, ...)
|
||||
{
|
||||
char text[LINE_MAX];
|
||||
int len;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
len = vsnprintf(text, sizeof(text), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
doLogEx(pContext, tvStart, NULL, text, len, false, true);
|
||||
}
|
||||
|
||||
#ifndef LOG_FORMAT_CHECK
|
||||
|
||||
void logEmerg(const char *format, ...)
|
||||
{
|
||||
_DO_LOG((&g_log_context), LOG_EMERG, "EMERG", true)
|
||||
}
|
||||
|
||||
void logAlert(const char *format, ...)
|
||||
{
|
||||
_DO_LOG((&g_log_context), LOG_ALERT, "ALERT", true)
|
||||
}
|
||||
|
||||
void logCrit(const char *format, ...)
|
||||
{
|
||||
_DO_LOG((&g_log_context), LOG_CRIT, "CRIT", true)
|
||||
}
|
||||
|
||||
void logError(const char *format, ...)
|
||||
{
|
||||
_DO_LOG((&g_log_context), LOG_ERR, "ERROR", false)
|
||||
}
|
||||
|
||||
void logWarning(const char *format, ...)
|
||||
{
|
||||
_DO_LOG((&g_log_context), LOG_WARNING, "WARNING", false)
|
||||
}
|
||||
|
||||
void logNotice(const char *format, ...)
|
||||
{
|
||||
_DO_LOG((&g_log_context), LOG_NOTICE, "NOTICE", false)
|
||||
}
|
||||
|
||||
void logInfo(const char *format, ...)
|
||||
{
|
||||
_DO_LOG((&g_log_context), LOG_INFO, "INFO", true)
|
||||
}
|
||||
|
||||
void logDebug(const char *format, ...)
|
||||
{
|
||||
_DO_LOG((&g_log_context), LOG_DEBUG, "DEBUG", true)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
299
common/logger.h
299
common/logger.h
|
|
@ -1,299 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//logger.h
|
||||
#ifndef LOGGER_H
|
||||
#define LOGGER_H
|
||||
|
||||
#include <syslog.h>
|
||||
#include <sys/time.h>
|
||||
#include "common_define.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LOG_TIME_PRECISION_SECOND 's' //second
|
||||
#define LOG_TIME_PRECISION_MSECOND 'm' //millisecond
|
||||
#define LOG_TIME_PRECISION_USSECOND 'u' //microsecond
|
||||
|
||||
struct log_context;
|
||||
|
||||
//log header line callback
|
||||
typedef void (*LogHeaderCallback)(struct log_context *pContext);
|
||||
|
||||
typedef struct log_context
|
||||
{
|
||||
/* log level value please see: sys/syslog.h
|
||||
default value is LOG_INFO */
|
||||
int log_level;
|
||||
|
||||
/* default value is STDERR_FILENO */
|
||||
int log_fd;
|
||||
|
||||
/* cache buffer */
|
||||
char *log_buff;
|
||||
|
||||
/* string end in the cache buffer for next sprintf */
|
||||
char *pcurrent_buff;
|
||||
|
||||
/* mutext lock */
|
||||
pthread_mutex_t log_thread_lock;
|
||||
|
||||
/*
|
||||
rotate the log when the log file exceeds this parameter
|
||||
rotate_size > 0 means need rotate log by log file size
|
||||
*/
|
||||
int64_t rotate_size;
|
||||
|
||||
/* log file current size */
|
||||
int64_t current_size;
|
||||
|
||||
/* if write to buffer firstly, then sync to disk.
|
||||
default value is false (no cache) */
|
||||
bool log_to_cache;
|
||||
|
||||
/* if rotate the access log */
|
||||
bool rotate_immediately;
|
||||
|
||||
/* if stderr to the log file */
|
||||
bool take_over_stderr;
|
||||
|
||||
/* if stdout to the log file */
|
||||
bool take_over_stdout;
|
||||
|
||||
/* time precision */
|
||||
char time_precision;
|
||||
|
||||
/* save the log filename */
|
||||
char log_filename[MAX_PATH_SIZE];
|
||||
|
||||
/* the time format for rotated filename,
|
||||
* default: %Y%m%d_%H%M%S
|
||||
* */
|
||||
char rotate_time_format[32];
|
||||
|
||||
/* keep days for rotated log files */
|
||||
int keep_days;
|
||||
|
||||
/*
|
||||
* log the header (title line) callback
|
||||
* */
|
||||
LogHeaderCallback print_header_callback;
|
||||
} LogContext;
|
||||
|
||||
extern LogContext g_log_context;
|
||||
|
||||
/** init function using global log context
|
||||
* return: 0 for success, != 0 fail
|
||||
*/
|
||||
int log_init();
|
||||
|
||||
/** init function using global log context, take over stderr and stdout
|
||||
* return: 0 for success, != 0 fail
|
||||
*/
|
||||
int log_init2();
|
||||
|
||||
#define log_set_prefix(base_path, filename_prefix) \
|
||||
log_set_prefix_ex(&g_log_context, base_path, filename_prefix)
|
||||
|
||||
#define log_set_filename(log_filename) \
|
||||
log_set_filename_ex(&g_log_context, log_filename)
|
||||
|
||||
#define log_set_cache(bLogCache) log_set_cache_ex(&g_log_context, bLogCache)
|
||||
|
||||
#define log_take_over_stderr() log_take_over_stderr_ex(&g_log_context)
|
||||
#define log_take_over_stdout() log_take_over_stdout_ex(&g_log_context)
|
||||
|
||||
#define log_destroy() log_destroy_ex(&g_log_context)
|
||||
|
||||
/** init function, use stderr for output by default
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* return: 0 for success, != 0 fail
|
||||
*/
|
||||
int log_init_ex(LogContext *pContext);
|
||||
|
||||
/** set log filename prefix, such as "tracker", the log filename will be
|
||||
* ${base_path}/logs/tracker.log
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* base_path: base path
|
||||
* filename_prefix: log filename prefix
|
||||
* return: 0 for success, != 0 fail
|
||||
*/
|
||||
int log_set_prefix_ex(LogContext *pContext, const char *base_path, \
|
||||
const char *filename_prefix);
|
||||
|
||||
/** set log filename
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* log_filename: log filename
|
||||
* return: 0 for success, != 0 fail
|
||||
*/
|
||||
int log_set_filename_ex(LogContext *pContext, const char *log_filename);
|
||||
|
||||
/** set if use log cache
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* bLogCache: true for cache in buffer, false directly write to disk
|
||||
* return: none
|
||||
*/
|
||||
void log_set_cache_ex(LogContext *pContext, const bool bLogCache);
|
||||
|
||||
/** set time precision
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* time_precision: the time precision
|
||||
* return: none
|
||||
*/
|
||||
void log_set_time_precision(LogContext *pContext, const int time_precision);
|
||||
|
||||
/** set rotate time format, the time format same as function strftime
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* time_format: rotate time format
|
||||
* return: none
|
||||
*/
|
||||
void log_set_rotate_time_format(LogContext *pContext, const char *time_format);
|
||||
|
||||
/** set keep days
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* keep_days: the keep days
|
||||
* return: none
|
||||
*/
|
||||
void log_set_keep_days(LogContext *pContext, const int keep_days);
|
||||
|
||||
/** set print header callback
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* header_callback: the callback
|
||||
* return: none
|
||||
*/
|
||||
void log_set_header_callback(LogContext *pContext, LogHeaderCallback header_callback);
|
||||
|
||||
/** set take_over_stderr to true
|
||||
* return: none
|
||||
*/
|
||||
void log_take_over_stderr_ex(LogContext *pContext);
|
||||
|
||||
/** set take_over_stdout to true
|
||||
* return: none
|
||||
*/
|
||||
void log_take_over_stdout_ex(LogContext *pContext);
|
||||
|
||||
/** destroy function
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* bLogCache: true for cache in buffer, false directly write to disk
|
||||
* return: none
|
||||
*/
|
||||
void log_destroy_ex(LogContext *pContext);
|
||||
|
||||
/** log to file
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* priority: unix priority
|
||||
* format: printf format
|
||||
* ...: arguments for printf format
|
||||
* return: none
|
||||
*/
|
||||
void log_it_ex(LogContext *pContext, const int priority, \
|
||||
const char *format, ...);
|
||||
|
||||
/** log to file
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* priority: unix priority
|
||||
* text: text string to log
|
||||
* text_len: text string length (bytes)
|
||||
* return: none
|
||||
*/
|
||||
void log_it_ex1(LogContext *pContext, const int priority, \
|
||||
const char *text, const int text_len);
|
||||
|
||||
/** log to file
|
||||
* parameters:
|
||||
* pContext: the log context
|
||||
* caption: such as INFO, ERROR, NULL for no caption
|
||||
* text: text string to log
|
||||
* text_len: text string length (bytes)
|
||||
* bNeedSync: if sync to file immediatelly
|
||||
* return: none
|
||||
*/
|
||||
void log_it_ex2(LogContext *pContext, const char *caption, \
|
||||
const char *text, const int text_len, \
|
||||
const bool bNeedSync, const bool bNeedLock);
|
||||
|
||||
|
||||
/** sync log buffer to log file
|
||||
* parameters:
|
||||
* args: should be (LogContext *)
|
||||
* return: error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int log_sync_func(void *args);
|
||||
|
||||
/** set rotate flag to true
|
||||
* parameters:
|
||||
* args: should be (LogContext *)
|
||||
* return: error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int log_notify_rotate(void *args);
|
||||
|
||||
/** delete old log files
|
||||
* parameters:
|
||||
* args: should be (LogContext *)
|
||||
* return: error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int log_delete_old_files(void *args);
|
||||
|
||||
void logEmergEx(LogContext *pContext, const char *format, ...);
|
||||
void logCritEx(LogContext *pContext, const char *format, ...);
|
||||
void logAlertEx(LogContext *pContext, const char *format, ...);
|
||||
void logErrorEx(LogContext *pContext, const char *format, ...);
|
||||
void logWarningEx(LogContext *pContext, const char *format, ...);
|
||||
void logNoticeEx(LogContext *pContext, const char *format, ...);
|
||||
void logInfoEx(LogContext *pContext, const char *format, ...);
|
||||
void logDebugEx(LogContext *pContext, const char *format, ...);
|
||||
void logAccess(LogContext *pContext, struct timeval *tvStart, \
|
||||
const char *format, ...);
|
||||
|
||||
//#define LOG_FORMAT_CHECK
|
||||
|
||||
#ifdef LOG_FORMAT_CHECK /*only for format check*/
|
||||
|
||||
#define logEmerg printf
|
||||
#define logCrit printf
|
||||
#define logAlert printf
|
||||
#define logError printf
|
||||
#define logWarning printf
|
||||
#define logNotice printf
|
||||
#define logInfo printf
|
||||
#define logDebug printf
|
||||
|
||||
#else
|
||||
|
||||
/* following functions use global log context: g_log_context */
|
||||
void logEmerg(const char *format, ...);
|
||||
void logCrit(const char *format, ...);
|
||||
void logAlert(const char *format, ...);
|
||||
void logError(const char *format, ...);
|
||||
void logWarning(const char *format, ...);
|
||||
void logNotice(const char *format, ...);
|
||||
void logInfo(const char *format, ...);
|
||||
void logDebug(const char *format, ...);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
356
common/md5.c
356
common/md5.c
|
|
@ -1,356 +0,0 @@
|
|||
#include "md5.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
static void MD5Transform (UINT4[4], unsigned char[64]);
|
||||
static void Encode (unsigned char *, UINT4 *, unsigned int);
|
||||
static void Decode (UINT4 *, unsigned char *, unsigned int);
|
||||
static void MD5_memcpy (POINTER, POINTER, unsigned int);
|
||||
static void MD5_memset (POINTER, int, unsigned int);
|
||||
|
||||
static unsigned char PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* F, G, H and I are basic MD5 functions.
|
||||
*/
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/*
|
||||
* ROTATE_LEFT rotates x left n bits.
|
||||
*/
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
/*
|
||||
* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is
|
||||
* separate from addition to prevent recomputation.
|
||||
*/
|
||||
#define FF(a, b, c, d, x, s, ac) { \
|
||||
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) { \
|
||||
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) { \
|
||||
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) { \
|
||||
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 initialization. Begins an MD5 operation, writing a new context.
|
||||
*/
|
||||
void
|
||||
my_md5_init(MD5_CTX *context)
|
||||
{
|
||||
context->count[0] = context->count[1] = 0;
|
||||
/*
|
||||
* Load magic initialization constants.
|
||||
*/
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xefcdab89;
|
||||
context->state[2] = 0x98badcfe;
|
||||
context->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 block update operation. Continues an MD5 message-digest operation,
|
||||
* processing another message block, and updating the context.
|
||||
*/
|
||||
void
|
||||
my_md5_update(MD5_CTX *context, unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
unsigned int i, index, partLen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
|
||||
|
||||
/* Update number of bits */
|
||||
if ((context->count[0] += ((UINT4) inputLen << 3)) < ((UINT4) inputLen << 3))
|
||||
context->count[1]++;
|
||||
context->count[1] += ((UINT4) inputLen >> 29);
|
||||
|
||||
partLen = 64 - index;
|
||||
|
||||
/*
|
||||
* Transform as many times as possible.
|
||||
*/
|
||||
if (inputLen >= partLen) {
|
||||
MD5_memcpy
|
||||
((POINTER) & context->buffer[index], (POINTER) input, partLen);
|
||||
MD5Transform(context->state, context->buffer);
|
||||
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
MD5Transform(context->state, &input[i]);
|
||||
|
||||
index = 0;
|
||||
} else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining input */
|
||||
MD5_memcpy
|
||||
((POINTER) & context->buffer[index], (POINTER) & input[i],
|
||||
inputLen - i);
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 finalization. Ends an MD5 message-digest operation, writing the the
|
||||
* message digest and zeroizing the context.
|
||||
*/
|
||||
void
|
||||
my_md5_final(unsigned char digest[16], MD5_CTX *context)
|
||||
{
|
||||
unsigned char bits[8];
|
||||
unsigned int index, padLen;
|
||||
|
||||
/* Save number of bits */
|
||||
Encode(bits, context->count, 8);
|
||||
|
||||
/*
|
||||
* Pad out to 56 mod 64.
|
||||
*/
|
||||
index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
my_md5_update(context, PADDING, padLen);
|
||||
|
||||
/* Append length (before padding) */
|
||||
my_md5_update(context, bits, 8);
|
||||
/* Store state in digest */
|
||||
Encode(digest, context->state, 16);
|
||||
|
||||
/*
|
||||
* Zeroize sensitive information.
|
||||
*/
|
||||
MD5_memset((POINTER) context, 0, sizeof(*context));
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 basic transformation. Transforms state based on block.
|
||||
*/
|
||||
static void
|
||||
MD5Transform(UINT4 state[4], unsigned char block[64])
|
||||
{
|
||||
UINT4 a = state[0], b = state[1], c = state[2], d = state[3],
|
||||
x[16];
|
||||
|
||||
Decode(x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
|
||||
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
|
||||
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
|
||||
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
|
||||
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
|
||||
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
|
||||
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
|
||||
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
|
||||
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
|
||||
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
|
||||
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
|
||||
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
|
||||
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
|
||||
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
|
||||
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
|
||||
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
|
||||
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
|
||||
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
|
||||
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
|
||||
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
|
||||
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
|
||||
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
|
||||
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
|
||||
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
|
||||
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
|
||||
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
|
||||
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
|
||||
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
|
||||
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
|
||||
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
|
||||
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
|
||||
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
|
||||
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
/*
|
||||
* Zeroize sensitive information.
|
||||
*
|
||||
*/
|
||||
MD5_memset((POINTER) x, 0, sizeof(x));
|
||||
}
|
||||
|
||||
/*
|
||||
* Encodes input (UINT4) into output (unsigned char). Assumes len is a
|
||||
* multiple of 4.
|
||||
*/
|
||||
static void
|
||||
Encode(unsigned char *output, UINT4 *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (unsigned char) (input[i] & 0xff);
|
||||
output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
|
||||
output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
|
||||
output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes input (unsigned char) into output (UINT4). Assumes len is a
|
||||
* multiple of 4.
|
||||
*/
|
||||
static void
|
||||
Decode(UINT4 *output, unsigned char *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
|
||||
(((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: Replace "for loop" with standard memcpy if possible.
|
||||
*/
|
||||
|
||||
static void
|
||||
MD5_memcpy(POINTER output, POINTER input, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = input[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: Replace "for loop" with standard memset if possible.
|
||||
*/
|
||||
static void
|
||||
MD5_memset(POINTER output, int value, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
((char *) output)[i] = (char) value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Digests a string
|
||||
*/
|
||||
int my_md5_string(char *string,unsigned char digest[16])
|
||||
{
|
||||
MD5_CTX context;
|
||||
unsigned int len = strlen(string);
|
||||
|
||||
my_md5_init(&context);
|
||||
my_md5_update(&context, (unsigned char *)string, len);
|
||||
my_md5_final(digest, &context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16])
|
||||
{
|
||||
MD5_CTX context;
|
||||
|
||||
my_md5_init(&context);
|
||||
my_md5_update(&context, (unsigned char *)buffer, len);
|
||||
my_md5_final(digest, &context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int my_md5_file(char *filename,unsigned char digest[16])
|
||||
{
|
||||
FILE *file;
|
||||
MD5_CTX context;
|
||||
int len;
|
||||
unsigned char buffer[1024];
|
||||
|
||||
if ((file = fopen(filename, "rb")) == NULL)
|
||||
return -1;
|
||||
else {
|
||||
my_md5_init(&context);
|
||||
while ((len = fread(buffer, 1, 1024, file)) > 0)
|
||||
{
|
||||
my_md5_update(&context, buffer, len);
|
||||
}
|
||||
my_md5_final(digest, &context);
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
55
common/md5.h
55
common/md5.h
|
|
@ -1,55 +0,0 @@
|
|||
#ifndef MCL_MD5_H
|
||||
#define MCL_MD5_H
|
||||
#include <stdio.h>
|
||||
|
||||
typedef unsigned char *POINTER;
|
||||
typedef unsigned short int UINT2;
|
||||
typedef unsigned int UINT4;
|
||||
|
||||
typedef struct {
|
||||
UINT4 state[4]; /* state (ABCD) */
|
||||
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
} MD5_CTX;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** md5 for string
|
||||
* parameters:
|
||||
* string: the string to md5
|
||||
* digest: store the md5 digest
|
||||
* return: 0 for success, != 0 fail
|
||||
*/
|
||||
int my_md5_string(char *string, unsigned char digest[16]);
|
||||
|
||||
/** md5 for file
|
||||
* parameters:
|
||||
* filename: the filename whose content to md5
|
||||
* digest: store the md5 digest
|
||||
* return: 0 for success, != 0 fail
|
||||
*/
|
||||
int my_md5_file(char *filename, unsigned char digest[16]);
|
||||
|
||||
/** md5 for buffer
|
||||
* parameters:
|
||||
* buffer: the buffer to md5
|
||||
* len: the buffer length
|
||||
* digest: store the md5 digest
|
||||
* return: 0 for success, != 0 fail
|
||||
*/
|
||||
int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16]);
|
||||
|
||||
void my_md5_init (MD5_CTX *);
|
||||
|
||||
void my_md5_update (MD5_CTX *, unsigned char *, unsigned int);
|
||||
|
||||
void my_md5_final (unsigned char [16], MD5_CTX *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "shared_func.h"
|
||||
#include "logger.h"
|
||||
#include "process_ctrl.h"
|
||||
|
||||
int get_pid_from_file(const char *pidFilename, pid_t *pid)
|
||||
{
|
||||
char buff[32];
|
||||
int64_t file_size;
|
||||
int result;
|
||||
|
||||
if (access(pidFilename, F_OK) != 0) {
|
||||
return errno != 0 ? errno : EPERM;
|
||||
}
|
||||
|
||||
file_size = sizeof(buff) - 1;
|
||||
if ((result=getFileContentEx(pidFilename, buff, 0, &file_size)) != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
*(buff + file_size) = '\0';
|
||||
*pid = strtol(buff, NULL, 10);
|
||||
if (*pid == 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_to_pid_file(const char *pidFilename)
|
||||
{
|
||||
char buff[32];
|
||||
int len;
|
||||
|
||||
len = sprintf(buff, "%d", (int)getpid());
|
||||
return writeToFile(pidFilename, buff, len);
|
||||
}
|
||||
|
||||
int delete_pid_file(const char *pidFilename)
|
||||
{
|
||||
if (unlink(pidFilename) == 0) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return errno != 0 ? errno : ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_stop(const char *pidFilename, const bool bShowError, pid_t *pid)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result=get_pid_from_file(pidFilename, pid)) != 0) {
|
||||
if (bShowError) {
|
||||
if (result == ENOENT) {
|
||||
fprintf(stderr, "pid file: %s not exist!\n", pidFilename);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "get pid from file: %s fail, " \
|
||||
"errno: %d, error info: %s\n",
|
||||
pidFilename, result, strerror(result));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (kill(*pid, SIGTERM) == 0) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
result = errno != 0 ? errno : EPERM;
|
||||
if (bShowError || result != ESRCH) {
|
||||
fprintf(stderr, "kill pid: %d fail, errno: %d, error info: %s\n",
|
||||
(int)*pid, result, strerror(result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
int process_stop(const char *pidFilename)
|
||||
{
|
||||
pid_t pid;
|
||||
int result;
|
||||
|
||||
result = do_stop(pidFilename, true, &pid);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
|
||||
do {
|
||||
sleep(1);
|
||||
} while (kill(pid, SIGTERM) == 0);
|
||||
fprintf(stderr, "pid [%d] exit.\n", (int)pid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int process_restart(const char *pidFilename)
|
||||
{
|
||||
int result;
|
||||
pid_t pid;
|
||||
|
||||
result = do_stop(pidFilename, false, &pid);
|
||||
if (result == 0) {
|
||||
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
|
||||
do {
|
||||
sleep(1);
|
||||
} while (kill(pid, SIGTERM) == 0);
|
||||
fprintf(stderr, "starting ...\n");
|
||||
}
|
||||
|
||||
if (result == ENOENT || result == ESRCH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int process_exist(const char *pidFilename)
|
||||
{
|
||||
pid_t pid;
|
||||
int result;
|
||||
|
||||
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
|
||||
if (result == ENOENT) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "get pid from file: %s fail, " \
|
||||
"errno: %d, error info: %s\n",
|
||||
pidFilename, result, strerror(result));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (kill(pid, 0) == 0) {
|
||||
return true;
|
||||
}
|
||||
else if (errno == ENOENT || errno == ESRCH) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "kill pid: %d fail, errno: %d, error info: %s\n",
|
||||
(int)pid, errno, strerror(errno));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int get_base_path_from_conf_file(const char *filename, char *base_path,
|
||||
const int path_size)
|
||||
{
|
||||
char *pBasePath;
|
||||
IniContext iniContext;
|
||||
int result;
|
||||
|
||||
memset(&iniContext, 0, sizeof(IniContext));
|
||||
if ((result=iniLoadFromFile(filename, &iniContext)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"load conf file \"%s\" fail, ret code: %d", \
|
||||
__LINE__, filename, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
pBasePath = iniGetStrValue(NULL, "base_path", &iniContext);
|
||||
if (pBasePath == NULL)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"conf file \"%s\" must have item " \
|
||||
"\"base_path\"!", __LINE__, filename);
|
||||
result = ENOENT;
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(base_path, path_size, "%s", pBasePath);
|
||||
chopPath(base_path);
|
||||
if (!fileExists(base_path))
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"\"%s\" can't be accessed, error info: %s", \
|
||||
__LINE__, base_path, STRERROR(errno));
|
||||
result = errno != 0 ? errno : ENOENT;
|
||||
break;
|
||||
}
|
||||
if (!isDir(base_path))
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"\"%s\" is not a directory!", \
|
||||
__LINE__, base_path);
|
||||
result = ENOTDIR;
|
||||
break;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
iniFreeContext(&iniContext);
|
||||
return result;
|
||||
}
|
||||
|
||||
int process_action(const char *pidFilename, const char *action, bool *stop)
|
||||
{
|
||||
*stop = false;
|
||||
if (action == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(action, "stop") == 0)
|
||||
{
|
||||
*stop = true;
|
||||
return process_stop(pidFilename);
|
||||
}
|
||||
else if (strcmp(action, "restart") == 0)
|
||||
{
|
||||
return process_restart(pidFilename);
|
||||
}
|
||||
else if (strcmp(action, "start") == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "invalid action: %s\n", action);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
|
||||
#ifndef PROCESS_CTRL_H
|
||||
#define PROCESS_CTRL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int get_base_path_from_conf_file(const char *filename, char *base_path,
|
||||
const int path_size);
|
||||
|
||||
int get_pid_from_file(const char *pidFilename, pid_t *pid);
|
||||
|
||||
int write_to_pid_file(const char *pidFilename);
|
||||
|
||||
int delete_pid_file(const char *pidFilename);
|
||||
|
||||
int process_stop(const char *pidFilename);
|
||||
|
||||
int process_restart(const char *pidFilename);
|
||||
|
||||
int process_exist(const char *pidFilename);
|
||||
|
||||
int process_action(const char *pidFilename, const char *action, bool *stop);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/file.h>
|
||||
#include <dirent.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include "pthread_func.h"
|
||||
#include "logger.h"
|
||||
|
||||
int init_pthread_lock(pthread_mutex_t *pthread_lock)
|
||||
{
|
||||
pthread_mutexattr_t mat;
|
||||
int result;
|
||||
|
||||
if ((result=pthread_mutexattr_init(&mat)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutexattr_init fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
if ((result=pthread_mutexattr_settype(&mat, \
|
||||
PTHREAD_MUTEX_ERRORCHECK)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutexattr_settype fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
if ((result=pthread_mutex_init(pthread_lock, &mat)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_mutex_init fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
if ((result=pthread_mutexattr_destroy(&mat)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call thread_mutexattr_destroy fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size)
|
||||
{
|
||||
size_t old_stack_size;
|
||||
size_t new_stack_size;
|
||||
int result;
|
||||
|
||||
if ((result=pthread_attr_init(pattr)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_attr_init fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result=pthread_attr_getstacksize(pattr, &old_stack_size)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_attr_getstacksize fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (stack_size > 0)
|
||||
{
|
||||
if (old_stack_size != stack_size)
|
||||
{
|
||||
new_stack_size = stack_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_stack_size = 0;
|
||||
}
|
||||
}
|
||||
else if (old_stack_size < 1 * 1024 * 1024)
|
||||
{
|
||||
new_stack_size = 1 * 1024 * 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_stack_size = 0;
|
||||
}
|
||||
|
||||
if (new_stack_size > 0)
|
||||
{
|
||||
if ((result=pthread_attr_setstacksize(pattr, \
|
||||
new_stack_size)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_attr_setstacksize fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if ((result=pthread_attr_setdetachstate(pattr, \
|
||||
PTHREAD_CREATE_DETACHED)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"call pthread_attr_setdetachstate fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_work_threads(int *count, void *(*start_func)(void *), \
|
||||
void *arg, pthread_t *tids, const int stack_size)
|
||||
{
|
||||
int result;
|
||||
pthread_attr_t thread_attr;
|
||||
pthread_t *ptid;
|
||||
pthread_t *ptid_end;
|
||||
|
||||
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
ptid_end = tids + (*count);
|
||||
for (ptid=tids; ptid<ptid_end; ptid++)
|
||||
{
|
||||
if ((result=pthread_create(ptid, &thread_attr, \
|
||||
start_func, arg)) != 0)
|
||||
{
|
||||
*count = ptid - tids;
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"create thread failed, startup threads: %d, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, *count, \
|
||||
result, STRERROR(result));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&thread_attr);
|
||||
return result;
|
||||
}
|
||||
|
||||
int kill_work_threads(pthread_t *tids, const int count)
|
||||
{
|
||||
int result;
|
||||
pthread_t *ptid;
|
||||
pthread_t *ptid_end;
|
||||
|
||||
ptid_end = tids + count;
|
||||
for (ptid=tids; ptid<ptid_end; ptid++)
|
||||
{
|
||||
if ((result=pthread_kill(*ptid, SIGINT)) != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"kill thread failed, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#ifndef PTHREAD_FUNC_H
|
||||
#define PTHREAD_FUNC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include "common_define.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int init_pthread_lock(pthread_mutex_t *pthread_lock);
|
||||
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size);
|
||||
|
||||
int create_work_threads(int *count, void *(*start_func)(void *), \
|
||||
void *arg, pthread_t *tids, const int stack_size);
|
||||
int kill_work_threads(pthread_t *tids, const int count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,508 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "sched_thread.h"
|
||||
#include "shared_func.h"
|
||||
#include "pthread_func.h"
|
||||
#include "logger.h"
|
||||
|
||||
volatile bool g_schedule_flag = false;
|
||||
volatile time_t g_current_time = 0;
|
||||
|
||||
static ScheduleArray waiting_schedule_array = {NULL, 0};
|
||||
static int waiting_del_id = -1;
|
||||
|
||||
static int sched_cmp_by_next_call_time(const void *p1, const void *p2)
|
||||
{
|
||||
return ((ScheduleEntry *)p1)->next_call_time - \
|
||||
((ScheduleEntry *)p2)->next_call_time;
|
||||
}
|
||||
|
||||
static int sched_init_entries(ScheduleArray *pScheduleArray)
|
||||
{
|
||||
ScheduleEntry *pEntry;
|
||||
ScheduleEntry *pEnd;
|
||||
time_t time_base;
|
||||
struct tm tm_current;
|
||||
struct tm tm_base;
|
||||
|
||||
if (pScheduleArray->count < 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"schedule count %d < 0", \
|
||||
__LINE__, pScheduleArray->count);
|
||||
return EINVAL;
|
||||
}
|
||||
if (pScheduleArray->count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_current_time = time(NULL);
|
||||
localtime_r((time_t *)&g_current_time, &tm_current);
|
||||
pEnd = pScheduleArray->entries + pScheduleArray->count;
|
||||
for (pEntry=pScheduleArray->entries; pEntry<pEnd; pEntry++)
|
||||
{
|
||||
if (pEntry->interval <= 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"shedule interval %d <= 0", \
|
||||
__LINE__, pEntry->interval);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (pEntry->time_base.hour == TIME_NONE)
|
||||
{
|
||||
pEntry->next_call_time = g_current_time + \
|
||||
pEntry->interval;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tm_current.tm_hour > pEntry->time_base.hour || \
|
||||
(tm_current.tm_hour == pEntry->time_base.hour \
|
||||
&& tm_current.tm_min >= pEntry->time_base.minute))
|
||||
{
|
||||
memcpy(&tm_base, &tm_current, sizeof(struct tm));
|
||||
}
|
||||
else
|
||||
{
|
||||
time_base = g_current_time - 24 * 3600;
|
||||
localtime_r(&time_base, &tm_base);
|
||||
}
|
||||
|
||||
tm_base.tm_hour = pEntry->time_base.hour;
|
||||
tm_base.tm_min = pEntry->time_base.minute;
|
||||
tm_base.tm_sec = 0;
|
||||
time_base = mktime(&tm_base);
|
||||
|
||||
pEntry->next_call_time = g_current_time + \
|
||||
pEntry->interval - (g_current_time - \
|
||||
time_base) % pEntry->interval;
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
char buff1[32];
|
||||
char buff2[32];
|
||||
logInfo("id=%d, current time=%s, first call time=%s\n", \
|
||||
pEntry->id, formatDatetime(g_current_time, \
|
||||
"%Y-%m-%d %H:%M:%S", buff1, sizeof(buff1)), \
|
||||
formatDatetime(pEntry->next_call_time, \
|
||||
"%Y-%m-%d %H:%M:%S", buff2, sizeof(buff2)));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sched_make_chain(ScheduleContext *pContext)
|
||||
{
|
||||
ScheduleArray *pScheduleArray;
|
||||
ScheduleEntry *pEntry;
|
||||
|
||||
pScheduleArray = &(pContext->scheduleArray);
|
||||
if (pScheduleArray->count == 0)
|
||||
{
|
||||
pContext->head = NULL;
|
||||
pContext->tail = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
qsort(pScheduleArray->entries, pScheduleArray->count, \
|
||||
sizeof(ScheduleEntry), sched_cmp_by_next_call_time);
|
||||
|
||||
pContext->head = pScheduleArray->entries;
|
||||
pContext->tail = pScheduleArray->entries + (pScheduleArray->count - 1);
|
||||
for (pEntry=pScheduleArray->entries; pEntry<pContext->tail; pEntry++)
|
||||
{
|
||||
pEntry->next = pEntry + 1;
|
||||
}
|
||||
pContext->tail->next = NULL;
|
||||
}
|
||||
|
||||
static int sched_check_waiting(ScheduleContext *pContext)
|
||||
{
|
||||
ScheduleArray *pScheduleArray;
|
||||
ScheduleEntry *newEntries;
|
||||
ScheduleEntry *pWaitingEntry;
|
||||
ScheduleEntry *pWaitingEnd;
|
||||
ScheduleEntry *pSchedEntry;
|
||||
ScheduleEntry *pSchedEnd;
|
||||
int allocCount;
|
||||
int newCount;
|
||||
int result;
|
||||
int deleteCount;
|
||||
|
||||
pScheduleArray = &(pContext->scheduleArray);
|
||||
deleteCount = 0;
|
||||
if (waiting_del_id >= 0)
|
||||
{
|
||||
pSchedEnd = pScheduleArray->entries + pScheduleArray->count;
|
||||
for (pSchedEntry=pScheduleArray->entries; \
|
||||
pSchedEntry<pSchedEnd; pSchedEntry++)
|
||||
{
|
||||
if (pSchedEntry->id == waiting_del_id)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSchedEntry < pSchedEnd)
|
||||
{
|
||||
pSchedEntry++;
|
||||
while (pSchedEntry < pSchedEnd)
|
||||
{
|
||||
memcpy(pSchedEntry - 1, pSchedEntry, \
|
||||
sizeof(ScheduleEntry));
|
||||
pSchedEntry++;
|
||||
}
|
||||
|
||||
deleteCount++;
|
||||
pScheduleArray->count--;
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"delete task id: %d, " \
|
||||
"current schedule count: %d", __LINE__, \
|
||||
waiting_del_id, pScheduleArray->count);
|
||||
}
|
||||
|
||||
waiting_del_id = -1;
|
||||
}
|
||||
|
||||
if (waiting_schedule_array.count == 0)
|
||||
{
|
||||
if (deleteCount > 0)
|
||||
{
|
||||
sched_make_chain(pContext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
allocCount = pScheduleArray->count + waiting_schedule_array.count;
|
||||
newEntries = (ScheduleEntry *)malloc(sizeof(ScheduleEntry) * allocCount);
|
||||
if (newEntries == NULL)
|
||||
{
|
||||
result = errno != 0 ? errno : ENOMEM;
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes failed, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, (int)sizeof(ScheduleEntry) * allocCount, \
|
||||
result, STRERROR(result));
|
||||
|
||||
if (deleteCount > 0)
|
||||
{
|
||||
sched_make_chain(pContext);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (pScheduleArray->count > 0)
|
||||
{
|
||||
memcpy(newEntries, pScheduleArray->entries, \
|
||||
sizeof(ScheduleEntry) * pScheduleArray->count);
|
||||
}
|
||||
newCount = pScheduleArray->count;
|
||||
pWaitingEnd = waiting_schedule_array.entries + waiting_schedule_array.count;
|
||||
for (pWaitingEntry=waiting_schedule_array.entries; \
|
||||
pWaitingEntry<pWaitingEnd; pWaitingEntry++)
|
||||
{
|
||||
pSchedEnd = newEntries + newCount;
|
||||
for (pSchedEntry=newEntries; pSchedEntry<pSchedEnd; \
|
||||
pSchedEntry++)
|
||||
{
|
||||
if (pWaitingEntry->id == pSchedEntry->id)
|
||||
{
|
||||
memcpy(pSchedEntry, pWaitingEntry, \
|
||||
sizeof(ScheduleEntry));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSchedEntry == pSchedEnd)
|
||||
{
|
||||
memcpy(pSchedEntry, pWaitingEntry, \
|
||||
sizeof(ScheduleEntry));
|
||||
newCount++;
|
||||
}
|
||||
}
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"schedule add entries: %d, replace entries: %d",
|
||||
__LINE__, newCount - pScheduleArray->count, \
|
||||
waiting_schedule_array.count - (newCount - pScheduleArray->count));
|
||||
|
||||
if (pScheduleArray->entries != NULL)
|
||||
{
|
||||
free(pScheduleArray->entries);
|
||||
}
|
||||
pScheduleArray->entries = newEntries;
|
||||
pScheduleArray->count = newCount;
|
||||
|
||||
free(waiting_schedule_array.entries);
|
||||
waiting_schedule_array.count = 0;
|
||||
waiting_schedule_array.entries = NULL;
|
||||
|
||||
sched_make_chain(pContext);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *sched_thread_entrance(void *args)
|
||||
{
|
||||
ScheduleContext *pContext;
|
||||
ScheduleEntry *pPrevious;
|
||||
ScheduleEntry *pCurrent;
|
||||
ScheduleEntry *pSaveNext;
|
||||
ScheduleEntry *pNode;
|
||||
ScheduleEntry *pUntil;
|
||||
int exec_count;
|
||||
int i;
|
||||
int sleep_time;
|
||||
|
||||
pContext = (ScheduleContext *)args;
|
||||
if (sched_init_entries(&(pContext->scheduleArray)) != 0)
|
||||
{
|
||||
free(pContext);
|
||||
return NULL;
|
||||
}
|
||||
sched_make_chain(pContext);
|
||||
|
||||
g_schedule_flag = true;
|
||||
while (*(pContext->pcontinue_flag))
|
||||
{
|
||||
sched_check_waiting(pContext);
|
||||
if (pContext->scheduleArray.count == 0) //no schedule entry
|
||||
{
|
||||
sleep(1);
|
||||
g_current_time = time(NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_current_time = time(NULL);
|
||||
sleep_time = pContext->head->next_call_time - g_current_time;
|
||||
|
||||
/*
|
||||
//fprintf(stderr, "count=%d, sleep_time=%d\n", \
|
||||
pContext->scheduleArray.count, sleep_time);
|
||||
*/
|
||||
while (sleep_time > 0 && *(pContext->pcontinue_flag))
|
||||
{
|
||||
sleep(1);
|
||||
g_current_time = time(NULL);
|
||||
if (sched_check_waiting(pContext) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
sleep_time--;
|
||||
}
|
||||
|
||||
if (!(*(pContext->pcontinue_flag)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
exec_count = 0;
|
||||
pCurrent = pContext->head;
|
||||
while (*(pContext->pcontinue_flag) && (pCurrent != NULL \
|
||||
&& pCurrent->next_call_time <= g_current_time))
|
||||
{
|
||||
//fprintf(stderr, "exec task id=%d\n", pCurrent->id);
|
||||
pCurrent->task_func(pCurrent->func_args);
|
||||
pCurrent->next_call_time = g_current_time + \
|
||||
pCurrent->interval;
|
||||
pCurrent = pCurrent->next;
|
||||
exec_count++;
|
||||
}
|
||||
|
||||
if (exec_count == 0 || pContext->scheduleArray.count == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (exec_count > pContext->scheduleArray.count / 2)
|
||||
{
|
||||
sched_make_chain(pContext);
|
||||
continue;
|
||||
}
|
||||
|
||||
pNode = pContext->head;
|
||||
pContext->head = pCurrent; //new chain head
|
||||
for (i=0; i<exec_count; i++)
|
||||
{
|
||||
if (pNode->next_call_time >= pContext->tail->next_call_time)
|
||||
{
|
||||
pContext->tail->next = pNode;
|
||||
pContext->tail = pNode;
|
||||
pNode = pNode->next;
|
||||
pContext->tail->next = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
pPrevious = NULL;
|
||||
pUntil = pContext->head;
|
||||
while (pUntil != NULL && \
|
||||
pNode->next_call_time > pUntil->next_call_time)
|
||||
{
|
||||
pPrevious = pUntil;
|
||||
pUntil = pUntil->next;
|
||||
}
|
||||
|
||||
pSaveNext = pNode->next;
|
||||
if (pPrevious == NULL)
|
||||
{
|
||||
pContext->head = pNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrevious->next = pNode;
|
||||
}
|
||||
pNode->next = pUntil;
|
||||
|
||||
pNode = pSaveNext;
|
||||
}
|
||||
}
|
||||
|
||||
g_schedule_flag = false;
|
||||
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"schedule thread exit", __LINE__);
|
||||
|
||||
free(pContext);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sched_dup_array(const ScheduleArray *pSrcArray, \
|
||||
ScheduleArray *pDestArray)
|
||||
{
|
||||
int result;
|
||||
int bytes;
|
||||
|
||||
if (pSrcArray->count == 0)
|
||||
{
|
||||
pDestArray->entries = NULL;
|
||||
pDestArray->count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytes = sizeof(ScheduleEntry) * pSrcArray->count;
|
||||
pDestArray->entries = (ScheduleEntry *)malloc(bytes);
|
||||
if (pDestArray->entries == NULL)
|
||||
{
|
||||
result = errno != 0 ? errno : ENOMEM;
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes failed, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, bytes, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
memcpy(pDestArray->entries, pSrcArray->entries, bytes);
|
||||
pDestArray->count = pSrcArray->count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sched_add_entries(const ScheduleArray *pScheduleArray)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (pScheduleArray->count == 0)
|
||||
{
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"no schedule entry", __LINE__);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
while (waiting_schedule_array.entries != NULL)
|
||||
{
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"waiting for schedule array ready ...", __LINE__);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if ((result=sched_dup_array(pScheduleArray, &waiting_schedule_array))!=0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return sched_init_entries(&waiting_schedule_array);
|
||||
}
|
||||
|
||||
int sched_del_entry(const int id)
|
||||
{
|
||||
if (id < 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"id: %d is invalid!", __LINE__, id);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
while (waiting_del_id >= 0)
|
||||
{
|
||||
logDebug("file: "__FILE__", line: %d, " \
|
||||
"waiting for delete ready ...", __LINE__);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
waiting_del_id = id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sched_start(ScheduleArray *pScheduleArray, pthread_t *ptid, \
|
||||
const int stack_size, bool * volatile pcontinue_flag)
|
||||
{
|
||||
int result;
|
||||
pthread_attr_t thread_attr;
|
||||
ScheduleContext *pContext;
|
||||
|
||||
pContext = (ScheduleContext *)malloc(sizeof(ScheduleContext));
|
||||
if (pContext == NULL)
|
||||
{
|
||||
result = errno != 0 ? errno : ENOMEM;
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"malloc %d bytes failed, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, (int)sizeof(ScheduleContext), \
|
||||
result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0)
|
||||
{
|
||||
free(pContext);
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result=sched_dup_array(pScheduleArray, \
|
||||
&(pContext->scheduleArray))) != 0)
|
||||
{
|
||||
free(pContext);
|
||||
return result;
|
||||
}
|
||||
|
||||
pContext->pcontinue_flag = pcontinue_flag;
|
||||
if ((result=pthread_create(ptid, &thread_attr, \
|
||||
sched_thread_entrance, pContext)) != 0)
|
||||
{
|
||||
free(pContext);
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"create thread failed, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&thread_attr);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#ifndef _SCHED_THREAD_H_
|
||||
#define _SCHED_THREAD_H_
|
||||
|
||||
#include <time.h>
|
||||
#include "common_define.h"
|
||||
|
||||
typedef int (*TaskFunc) (void *args);
|
||||
|
||||
typedef struct tagScheduleEntry
|
||||
{
|
||||
int id; //the task id
|
||||
|
||||
/* the time base to execute task, such as 00:00, interval is 3600,
|
||||
means execute the task every hour as 1:00, 2:00, 3:00 etc. */
|
||||
TimeInfo time_base;
|
||||
|
||||
int interval; //the interval for execute task, unit is second
|
||||
|
||||
TaskFunc task_func; //callback function
|
||||
void *func_args; //arguments pass to callback function
|
||||
|
||||
/* following are internal fields, do not set manually! */
|
||||
time_t next_call_time;
|
||||
struct tagScheduleEntry *next;
|
||||
} ScheduleEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ScheduleEntry *entries;
|
||||
int count;
|
||||
} ScheduleArray;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ScheduleArray scheduleArray;
|
||||
ScheduleEntry *head; //schedule chain head
|
||||
ScheduleEntry *tail; //schedule chain tail
|
||||
bool *pcontinue_flag;
|
||||
} ScheduleContext;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern volatile bool g_schedule_flag; //schedule continue running flag
|
||||
extern volatile time_t g_current_time; //the current time
|
||||
|
||||
|
||||
#define get_current_time() (g_schedule_flag ? g_current_time: time(NULL))
|
||||
|
||||
int sched_add_entries(const ScheduleArray *pScheduleArray);
|
||||
int sched_del_entry(const int id);
|
||||
|
||||
/** execute the schedule thread
|
||||
* parameters:
|
||||
* pScheduleArray: schedule task
|
||||
* ptid: store the schedule thread id
|
||||
* stack_size: set thread stack size (byes)
|
||||
* pcontinue_flag: main process continue running flag
|
||||
* return: error no, 0 for success, != 0 fail
|
||||
*/
|
||||
int sched_start(ScheduleArray *pScheduleArray, pthread_t *ptid, \
|
||||
const int stack_size, bool * volatile pcontinue_flag);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
2083
common/shared_func.c
2083
common/shared_func.c
File diff suppressed because it is too large
Load Diff
|
|
@ -1,510 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
#ifndef SHARED_FUNC_H
|
||||
#define SHARED_FUNC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include "common_define.h"
|
||||
#include "ini_file_reader.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** lowercase the string
|
||||
* parameters:
|
||||
* src: input string, will be changed
|
||||
* return: lowercased string
|
||||
*/
|
||||
char *toLowercase(char *src);
|
||||
|
||||
/** uppercase the string
|
||||
* parameters:
|
||||
* src: input string, will be changed
|
||||
* return: uppercased string
|
||||
*/
|
||||
char *toUppercase(char *src);
|
||||
|
||||
|
||||
/** date format to string
|
||||
* parameters:
|
||||
* nTime: unix timestamp
|
||||
* szDateFormat: date format, more detail man strftime
|
||||
* buff: store the formated result, can be NULL
|
||||
* buff_size: buffer size, max bytes can contain
|
||||
* return: formated date string
|
||||
*/
|
||||
char *formatDatetime(const time_t nTime, \
|
||||
const char *szDateFormat, \
|
||||
char *buff, const int buff_size);
|
||||
|
||||
/** get character count, only support GB charset
|
||||
* parameters:
|
||||
* s: the string
|
||||
* return: character count
|
||||
*/
|
||||
int getCharLen(const char *s);
|
||||
|
||||
/** replace \r and \n to space
|
||||
* parameters:
|
||||
* s: the string
|
||||
* return: replaced string
|
||||
*/
|
||||
char *replaceCRLF2Space(char *s);
|
||||
|
||||
/** get the filename absolute path
|
||||
* parameters:
|
||||
* fileame: the filename
|
||||
* szAbsPath: store the absolute path
|
||||
* pathSize: max bytes to contain
|
||||
* return: absolute path, NULL for fail
|
||||
*/
|
||||
char *getAbsolutePath(const char *fileame, char *szAbsPath, \
|
||||
const int pathSize);
|
||||
|
||||
/** get the executable file absolute filename
|
||||
* parameters:
|
||||
* exeFilename: the executable filename
|
||||
* szAbsFilename: store the absolute filename
|
||||
* maxSize: max bytes to contain
|
||||
* return: absolute filename, NULL for fail
|
||||
*/
|
||||
char *getExeAbsoluteFilename(const char *exeFilename, char *szAbsFilename, \
|
||||
const int maxSize);
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
/** get running process count by program name such as fdfs_trackerd
|
||||
* parameters:
|
||||
* progName: the program name
|
||||
* bAllOwners: false for only get my proccess count
|
||||
* return: proccess count, >= 0 success, < 0 fail
|
||||
*/
|
||||
int getProccessCount(const char *progName, const bool bAllOwners);
|
||||
|
||||
/** get running process ids by program name such as fdfs_trackerd
|
||||
* parameters:
|
||||
* progName: the program name
|
||||
* bAllOwners: false for only get my proccess count
|
||||
* pids: store the pids
|
||||
* arrSize: max pids
|
||||
* return: proccess count, >= 0 success, < 0 fail
|
||||
*/
|
||||
int getUserProcIds(const char *progName, const bool bAllOwners, \
|
||||
int pids[], const int arrSize);
|
||||
|
||||
/** execute program, get it's output
|
||||
* parameters:
|
||||
* command: the program
|
||||
* output: store ouput result
|
||||
* buff_size: output max size (bytes)
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int getExecResult(const char *command, char *output, const int buff_size);
|
||||
|
||||
#endif
|
||||
|
||||
/** daemon init
|
||||
* parameters:
|
||||
* bCloseFiles: if close the stdin, stdout and stderr
|
||||
* return: none
|
||||
*/
|
||||
void daemon_init(bool bCloseFiles);
|
||||
|
||||
/** convert buffer content to hex string such as 0B82A1
|
||||
* parameters:
|
||||
* s: the buffer
|
||||
* len: the buffer length
|
||||
* szHexBuff: store the hex string (must have enough space)
|
||||
* return: hex string (szHexBuff)
|
||||
*/
|
||||
char *bin2hex(const char *s, const int len, char *szHexBuff);
|
||||
|
||||
/** parse hex string to binary content
|
||||
* parameters:
|
||||
* s: the hex string such as 8B04CD
|
||||
* szBinBuff: store the converted binary content(must have enough space)
|
||||
* nDestLen: store the converted content length
|
||||
* return: converted binary content (szBinBuff)
|
||||
*/
|
||||
char *hex2bin(const char *s, char *szBinBuff, int *nDestLen);
|
||||
|
||||
/** print binary buffer as hex string
|
||||
* parameters:
|
||||
* s: the buffer
|
||||
* len: the buffer length
|
||||
* return: none
|
||||
*/
|
||||
void printBuffHex(const char *s, const int len);
|
||||
|
||||
/** 16 bits int convert to buffer (big-endian)
|
||||
* parameters:
|
||||
* n: 16 bits int value
|
||||
* buff: the buffer, at least 2 bytes space, no tail \0
|
||||
* return: none
|
||||
*/
|
||||
void short2buff(const short n, char *buff);
|
||||
|
||||
/** buffer convert to 16 bits int
|
||||
* parameters:
|
||||
* buff: big-endian 2 bytes buffer
|
||||
* return: 16 bits int value
|
||||
*/
|
||||
short buff2short(const char *buff);
|
||||
|
||||
/** 32 bits int convert to buffer (big-endian)
|
||||
* parameters:
|
||||
* n: 32 bits int value
|
||||
* buff: the buffer, at least 4 bytes space, no tail \0
|
||||
* return: none
|
||||
*/
|
||||
void int2buff(const int n, char *buff);
|
||||
|
||||
/** buffer convert to 32 bits int
|
||||
* parameters:
|
||||
* buff: big-endian 4 bytes buffer
|
||||
* return: 32 bits int value
|
||||
*/
|
||||
int buff2int(const char *buff);
|
||||
|
||||
/** long (64 bits) convert to buffer (big-endian)
|
||||
* parameters:
|
||||
* n: 64 bits int value
|
||||
* buff: the buffer, at least 8 bytes space, no tail \0
|
||||
* return: none
|
||||
*/
|
||||
void long2buff(int64_t n, char *buff);
|
||||
|
||||
/** buffer convert to 64 bits int
|
||||
* parameters:
|
||||
* buff: big-endian 8 bytes buffer
|
||||
* return: 64 bits int value
|
||||
*/
|
||||
int64_t buff2long(const char *buff);
|
||||
|
||||
/** trim leading spaces ( \t\r\n)
|
||||
* parameters:
|
||||
* pStr: the string to trim
|
||||
* return: trimed string porinter as pStr
|
||||
*/
|
||||
char *trim_left(char *pStr);
|
||||
|
||||
/** trim tail spaces ( \t\r\n)
|
||||
* parameters:
|
||||
* pStr: the string to trim
|
||||
* return: trimed string porinter as pStr
|
||||
*/
|
||||
char *trim_right(char *pStr);
|
||||
|
||||
/** trim leading and tail spaces ( \t\r\n)
|
||||
* parameters:
|
||||
* pStr: the string to trim
|
||||
* return: trimed string porinter as pStr
|
||||
*/
|
||||
char *trim(char *pStr);
|
||||
|
||||
/** copy string to BufferInfo
|
||||
* parameters:
|
||||
* pBuff: the dest buffer
|
||||
* str: source string
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int buffer_strcpy(BufferInfo *pBuff, const char *str);
|
||||
|
||||
/** copy binary buffer to BufferInfo
|
||||
* parameters:
|
||||
* pBuff: the dest buffer
|
||||
* buff: source buffer
|
||||
* len: source buffer length
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int buffer_memcpy(BufferInfo *pBuff, const char *buff, const int len);
|
||||
|
||||
/** url encode
|
||||
* parameters:
|
||||
* src: the source string to encode
|
||||
* src_len: source string length
|
||||
* dest: store dest string
|
||||
* dest_len: store the dest string length
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
char *urlencode(const char *src, const int src_len, char *dest, int *dest_len);
|
||||
|
||||
/** url decode
|
||||
* parameters:
|
||||
* src: the source string to decode
|
||||
* src_len: source string length
|
||||
* dest: store dest string
|
||||
* dest_len: store the dest string length
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
char *urldecode(const char *src, const int src_len, char *dest, int *dest_len);
|
||||
|
||||
/** get char occurs count
|
||||
* parameters:
|
||||
* src: the source string
|
||||
* seperator: find this char occurs times
|
||||
* return: char occurs count
|
||||
*/
|
||||
int getOccurCount(const char *src, const char seperator);
|
||||
|
||||
/** split string
|
||||
* parameters:
|
||||
* src: the source string, will be modified by this function
|
||||
* seperator: seperator char
|
||||
* nMaxCols: max columns (max split count)
|
||||
* nColCount: store the columns (array elements) count
|
||||
* return: string array, should call freeSplit to free, return NULL when fail
|
||||
*/
|
||||
char **split(char *src, const char seperator, const int nMaxCols, \
|
||||
int *nColCount);
|
||||
|
||||
/** free split results
|
||||
* parameters:
|
||||
* p: return by function split
|
||||
* return: none
|
||||
*/
|
||||
void freeSplit(char **p);
|
||||
|
||||
|
||||
/** split string
|
||||
* parameters:
|
||||
* src: the source string, will be modified by this function
|
||||
* seperator: seperator char
|
||||
* pCols: store split strings
|
||||
* nMaxCols: max columns (max split count)
|
||||
* return: string array / column count
|
||||
*/
|
||||
int splitEx(char *src, const char seperator, char **pCols, const int nMaxCols);
|
||||
|
||||
/** split string
|
||||
* parameters:
|
||||
* src: the source string, will be modified by this function
|
||||
* seperator: seperator char
|
||||
* pCols: store split strings
|
||||
* nMaxCols: max columns (max split count)
|
||||
* return: string array / column count
|
||||
*/
|
||||
int my_strtok(char *src, const char *delim, char **pCols, const int nMaxCols);
|
||||
|
||||
/** check file exist
|
||||
* parameters:
|
||||
* filename: the filename
|
||||
* return: true if file exists, otherwise false
|
||||
*/
|
||||
bool fileExists(const char *filename);
|
||||
|
||||
/** check if a directory
|
||||
* parameters:
|
||||
* filename: the filename
|
||||
* return: true for directory
|
||||
*/
|
||||
bool isDir(const char *filename);
|
||||
|
||||
/** check if a regular file
|
||||
* parameters:
|
||||
* filename: the filename
|
||||
* return: true for regular file
|
||||
*/
|
||||
bool isFile(const char *filename);
|
||||
|
||||
/** check if filename securty, /../ ocur in filename not allowed
|
||||
* parameters:
|
||||
* filename: the filename
|
||||
* len: filename length
|
||||
* return: true for regular file
|
||||
*/
|
||||
bool is_filename_secure(const char *filename, const int len);
|
||||
|
||||
/** load log_level from config context
|
||||
* parameters:
|
||||
* pIniContext: the config context
|
||||
* return: none
|
||||
*/
|
||||
void load_log_level(IniContext *pIniContext);
|
||||
|
||||
/** load log_level from config file
|
||||
* parameters:
|
||||
* conf_filename: the config filename
|
||||
* return: none
|
||||
*/
|
||||
int load_log_level_ex(const char *conf_filename);
|
||||
|
||||
/** set global log level
|
||||
* parameters:
|
||||
* pLogLevel: log level string value
|
||||
* return: none
|
||||
*/
|
||||
void set_log_level(char *pLogLevel);
|
||||
|
||||
/** load allow hosts from config context
|
||||
* parameters:
|
||||
* pIniContext: the config context
|
||||
* allow_ip_addrs: store allow ip addresses
|
||||
* allow_ip_count: store allow ip address count
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int load_allow_hosts(IniContext *pIniContext, \
|
||||
in_addr_t **allow_ip_addrs, int *allow_ip_count);
|
||||
|
||||
/** get time item from config context
|
||||
* parameters:
|
||||
* pIniContext: the config context
|
||||
* item_name: item name in config file, time format: hour:minute, such as 15:25
|
||||
* pTimeInfo: store time info
|
||||
* default_hour: default hour value
|
||||
* default_minute: default minute value
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int get_time_item_from_conf(IniContext *pIniContext, \
|
||||
const char *item_name, TimeInfo *pTimeInfo, \
|
||||
const byte default_hour, const byte default_minute);
|
||||
|
||||
/** trim path tail char /
|
||||
* parameters:
|
||||
* filePath: the file path to chop
|
||||
* return: none
|
||||
*/
|
||||
void chopPath(char *filePath);
|
||||
|
||||
/** get file content
|
||||
* parameters:
|
||||
* filename: the filename
|
||||
* buff: return the buff, must be freed
|
||||
* file_size: store the file size
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int getFileContent(const char *filename, char **buff, int64_t *file_size);
|
||||
|
||||
/** get file content
|
||||
* parameters:
|
||||
* filename: the filename
|
||||
* buff: the buff to store file content
|
||||
* offset: the start offset
|
||||
* size: specify the size to fetch and return the fetched size
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int getFileContentEx(const char *filename, char *buff, \
|
||||
int64_t offset, int64_t *size);
|
||||
|
||||
/** write to file
|
||||
* parameters:
|
||||
* filename: the filename to write
|
||||
* buff: the buffer to write
|
||||
* file_size: the file size
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int writeToFile(const char *filename, const char *buff, const int file_size);
|
||||
|
||||
/** safe write to file, first write to tmp file, then rename to true filename
|
||||
* parameters:
|
||||
* filename: the filename to write
|
||||
* buff: the buffer to write
|
||||
* file_size: the file size
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int safeWriteToFile(const char *filename, const char *buff, \
|
||||
const int file_size);
|
||||
|
||||
/** get a line from file
|
||||
* parameters:
|
||||
* fd: the fd to read
|
||||
* buff: the buffer to store the line
|
||||
* size: the buffer max size
|
||||
* once_bytes: the bytes per read
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int fd_gets(int fd, char *buff, const int size, int once_bytes);
|
||||
|
||||
/** set unix rlimit
|
||||
* parameters:
|
||||
* resource: resource id, please see sys/resource.h
|
||||
* value: the value to set
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int set_rlimit(int resource, const rlim_t value);
|
||||
|
||||
/** set non block mode
|
||||
* parameters:
|
||||
* fd: the fd to set
|
||||
* adding_flags: the flags to add
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int fd_add_flags(int fd, int adding_flags);
|
||||
|
||||
/** set non block mode
|
||||
* parameters:
|
||||
* fd: the fd to set
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
#define set_nonblock(fd) fd_add_flags(fd, O_NONBLOCK)
|
||||
|
||||
/** set run by group and user
|
||||
* parameters:
|
||||
* group_name: the group name, can be NULL or empty
|
||||
* username: the username, can be NULL or empty
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int set_run_by(const char *group_name, const char *username);
|
||||
|
||||
/** compare ip address, type is (in_addr_t *)
|
||||
* parameters:
|
||||
* p1: the first ip address
|
||||
* p2: the second ip address
|
||||
* return: > 0 when p1 > p2, 0 when p1 == p2, < 0 when p1 < p2
|
||||
*/
|
||||
int cmp_by_ip_addr_t(const void *p1, const void *p2);
|
||||
|
||||
/** parse bytes
|
||||
* parameters:
|
||||
* pStr: the string to parse
|
||||
* default_unit_bytes: default unit if not specified the unit like MB etc.
|
||||
* bytes: store the parsed bytes
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int parse_bytes(char *pStr, const int default_unit_bytes, int64_t *bytes);
|
||||
|
||||
/** set rand seed
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int set_rand_seed();
|
||||
|
||||
/** set timer wrapper
|
||||
* parameters:
|
||||
* first_remain_seconds: remain time for first time, in seconds
|
||||
* interval: the interval
|
||||
* sighandler: handler function
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int set_timer(const int first_remain_seconds, const int interval, \
|
||||
void (*sighandler)(int));
|
||||
|
||||
/** set file access and modified times
|
||||
* parameters:
|
||||
* filename: the file to modify times
|
||||
* new_time: the time to set
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int set_file_utimes(const char *filename, const time_t new_time);
|
||||
|
||||
/** ignore singal pipe (SIGPIPE)
|
||||
* return: error no , 0 success, != 0 fail
|
||||
*/
|
||||
int ignore_signal_pipe();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
1799
common/sockopt.c
1799
common/sockopt.c
File diff suppressed because it is too large
Load Diff
347
common/sockopt.h
347
common/sockopt.h
|
|
@ -1,347 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS 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.
|
||||
**/
|
||||
|
||||
//socketopt.h
|
||||
|
||||
#ifndef _SOCKETOPT_H_
|
||||
#define _SOCKETOPT_H_
|
||||
|
||||
#include "common_define.h"
|
||||
|
||||
#define FDFS_WRITE_BUFF_SIZE 256 * 1024
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int (*getnamefunc)(int socket, struct sockaddr *address, \
|
||||
socklen_t *address_len);
|
||||
|
||||
typedef int (*tcpsenddatafunc)(int sock, void* data, const int size, \
|
||||
const int timeout);
|
||||
|
||||
typedef int (*tcprecvdata_exfunc)(int sock, void *data, const int size, \
|
||||
const int timeout, int *count);
|
||||
|
||||
#define getSockIpaddr(sock, buff, bufferSize) \
|
||||
getIpaddr(getsockname, sock, buff, bufferSize)
|
||||
|
||||
#define getPeerIpaddr(sock, buff, bufferSize) \
|
||||
getIpaddr(getpeername, sock, buff, bufferSize)
|
||||
|
||||
/** get a line from socket
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* s: the buffer
|
||||
* size: buffer size (max bytes can receive)
|
||||
* timeout: read timeout
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpgets(int sock, char *s, const int size, const int timeout);
|
||||
|
||||
/** recv data (block mode)
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* data: the buffer
|
||||
* size: buffer size (max bytes can receive)
|
||||
* timeout: read timeout
|
||||
* count: store the bytes recveived
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcprecvdata_ex(int sock, void *data, const int size, \
|
||||
const int timeout, int *count);
|
||||
|
||||
/** recv data (non-block mode)
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* data: the buffer
|
||||
* size: buffer size (max bytes can receive)
|
||||
* timeout: read timeout in seconds
|
||||
* count: store the bytes recveived
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcprecvdata_nb_ex(int sock, void *data, const int size, \
|
||||
const int timeout, int *count);
|
||||
|
||||
/** recv data (non-block mode) in ms
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* data: the buffer
|
||||
* size: buffer size (max bytes can receive)
|
||||
* timeout: read timeout in milliseconds
|
||||
* count: store the bytes recveived
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcprecvdata_nb_ms(int sock, void *data, const int size, \
|
||||
const int timeout_ms, int *count);
|
||||
|
||||
/** send data (block mode)
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* data: the buffer to send
|
||||
* size: buffer size
|
||||
* timeout: write timeout
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpsenddata(int sock, void* data, const int size, const int timeout);
|
||||
|
||||
/** send data (non-block mode)
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* data: the buffer to send
|
||||
* size: buffer size
|
||||
* timeout: write timeout
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpsenddata_nb(int sock, void* data, const int size, const int timeout);
|
||||
|
||||
/** connect to server by block mode
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* server_ip: ip address of the server
|
||||
* server_port: port of the server
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int connectserverbyip(int sock, const char *server_ip, const short server_port);
|
||||
|
||||
/** connect to server by non-block mode
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* server_ip: ip address of the server
|
||||
* server_port: port of the server
|
||||
* timeout: connect timeout in seconds
|
||||
* auto_detect: if detect and adjust the block mode of the socket
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int connectserverbyip_nb_ex(int sock, const char *server_ip, \
|
||||
const short server_port, const int timeout, \
|
||||
const bool auto_detect);
|
||||
|
||||
/** connect to server by non-block mode, the socket must be set to non-block
|
||||
* parameters:
|
||||
* sock: the socket, must be set to non-block
|
||||
* server_ip: ip address of the server
|
||||
* server_port: port of the server
|
||||
* timeout: connect timeout in seconds
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
#define connectserverbyip_nb(sock, server_ip, server_port, timeout) \
|
||||
connectserverbyip_nb_ex(sock, server_ip, server_port, timeout, false)
|
||||
|
||||
/** connect to server by non-block mode, auto detect socket block mode
|
||||
* parameters:
|
||||
* sock: the socket, can be block mode
|
||||
* server_ip: ip address of the server
|
||||
* server_port: port of the server
|
||||
* timeout: connect timeout in seconds
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
#define connectserverbyip_nb_auto(sock, server_ip, server_port, timeout) \
|
||||
connectserverbyip_nb_ex(sock, server_ip, server_port, timeout, true)
|
||||
|
||||
/** accept client connect request
|
||||
* parameters:
|
||||
* sock: the server socket
|
||||
* timeout: read timeout
|
||||
* err_no: store the error no, 0 for success
|
||||
* return: client socket, < 0 for error
|
||||
*/
|
||||
int nbaccept(int sock, const int timeout, int *err_no);
|
||||
|
||||
/** set socket options
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* timeout: read & write timeout
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpsetserveropt(int fd, const int timeout);
|
||||
|
||||
/** set socket non-block options
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpsetnonblockopt(int fd);
|
||||
|
||||
/** set socket no delay on send data
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* timeout: read & write timeout
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpsetnodelay(int fd, const int timeout);
|
||||
|
||||
/** set socket keep-alive
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* idleSeconds: max idle time (seconds)
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpsetkeepalive(int fd, const int idleSeconds);
|
||||
|
||||
/** print keep-alive related parameters
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpprintkeepalive(int fd);
|
||||
|
||||
/** get ip address
|
||||
* parameters:
|
||||
* getname: the function name, should be getpeername or getsockname
|
||||
* sock: the socket
|
||||
* buff: buffer to store the ip address
|
||||
* bufferSize: the buffer size (max bytes)
|
||||
* return: in_addr_t, INADDR_NONE for fail
|
||||
*/
|
||||
in_addr_t getIpaddr(getnamefunc getname, int sock, \
|
||||
char *buff, const int bufferSize);
|
||||
|
||||
/** get hostname by it's ip address
|
||||
* parameters:
|
||||
* szIpAddr: the ip address
|
||||
* buff: buffer to store the hostname
|
||||
* bufferSize: the buffer size (max bytes)
|
||||
* return: hostname, empty buffer for error
|
||||
*/
|
||||
char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize);
|
||||
|
||||
/** get by ip address by it's hostname
|
||||
* parameters:
|
||||
* name: the hostname
|
||||
* buff: buffer to store the ip address
|
||||
* bufferSize: the buffer size (max bytes)
|
||||
* return: in_addr_t, INADDR_NONE for fail
|
||||
*/
|
||||
in_addr_t getIpaddrByName(const char *name, char *buff, const int bufferSize);
|
||||
|
||||
/** bind wrapper
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* bind_ipaddr: the ip address to bind
|
||||
* port: the port to bind
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int socketBind(int sock, const char *bind_ipaddr, const int port);
|
||||
|
||||
/** start a socket server (socket, bind and listen)
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* bind_ipaddr: the ip address to bind
|
||||
* port: the port to bind
|
||||
* err_no: store the error no
|
||||
* return: >= 0 server socket, < 0 fail
|
||||
*/
|
||||
int socketServer(const char *bind_ipaddr, const int port, int *err_no);
|
||||
|
||||
#define tcprecvdata(sock, data, size, timeout) \
|
||||
tcprecvdata_ex(sock, data, size, timeout, NULL)
|
||||
|
||||
#define tcpsendfile(sock, filename, file_bytes, timeout, total_send_bytes) \
|
||||
tcpsendfile_ex(sock, filename, 0, file_bytes, timeout, total_send_bytes)
|
||||
|
||||
#define tcprecvdata_nb(sock, data, size, timeout) \
|
||||
tcprecvdata_nb_ex(sock, data, size, timeout, NULL)
|
||||
|
||||
/** send a file
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* filename: the file to send
|
||||
* file_offset: file offset, start position
|
||||
* file_bytes: send file length
|
||||
* timeout: write timeout
|
||||
* total_send_bytes: store the send bytes
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpsendfile_ex(int sock, const char *filename, const int64_t file_offset, \
|
||||
const int64_t file_bytes, const int timeout, int64_t *total_send_bytes);
|
||||
|
||||
/** receive data to a file
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* filename: the file to write
|
||||
* file_bytes: file size (bytes)
|
||||
* fsync_after_written_bytes: call fsync every x bytes
|
||||
* timeout: read/recv timeout
|
||||
* true_file_bytes: store the true file bytes
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcprecvfile(int sock, const char *filename, const int64_t file_bytes, \
|
||||
const int fsync_after_written_bytes, const int timeout, \
|
||||
int64_t *true_file_bytes);
|
||||
|
||||
|
||||
#define tcprecvinfinitefile(sock, filename, fsync_after_written_bytes, \
|
||||
timeout, file_bytes) \
|
||||
tcprecvfile(sock, filename, INFINITE_FILE_SIZE, \
|
||||
fsync_after_written_bytes, timeout, file_bytes)
|
||||
|
||||
|
||||
/** receive data to a file
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* filename: the file to write
|
||||
* file_bytes: file size (bytes)
|
||||
* fsync_after_written_bytes: call fsync every x bytes
|
||||
* hash_codes: return hash code of file content
|
||||
* timeout: read/recv timeout
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcprecvfile_ex(int sock, const char *filename, const int64_t file_bytes, \
|
||||
const int fsync_after_written_bytes, \
|
||||
unsigned int *hash_codes, const int timeout);
|
||||
|
||||
/** receive specified data and discard
|
||||
* parameters:
|
||||
* sock: the socket
|
||||
* bytes: data bytes to discard
|
||||
* timeout: read timeout
|
||||
* total_recv_bytes: store the total recv bytes
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int tcpdiscard(int sock, const int bytes, const int timeout, \
|
||||
int64_t *total_recv_bytes);
|
||||
|
||||
/** get local host ip addresses
|
||||
* parameters:
|
||||
* ip_addrs: store the ip addresses
|
||||
* max_count: max ip address (max ip_addrs elements)
|
||||
* count: store the ip address count
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
|
||||
const int max_count, int *count);
|
||||
|
||||
/** get local host ip addresses
|
||||
* parameters:
|
||||
* ip_addrs: store the ip addresses
|
||||
* max_count: max ip address (max ip_addrs elements)
|
||||
* count: store the ip address count
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int getlocaladdrs1(char ip_addrs[][IP_ADDRESS_SIZE], \
|
||||
const int max_count, int *count);
|
||||
|
||||
/** get local host ip addresses by if alias prefix
|
||||
* parameters:
|
||||
* if_alias_prefixes: if alias prefixes, such as eth, bond etc.
|
||||
* prefix_count: if alias prefix count
|
||||
* ip_addrs: store the ip addresses
|
||||
* max_count: max ip address (max ip_addrs elements)
|
||||
* count: store the ip address count
|
||||
* return: error no, 0 success, != 0 fail
|
||||
*/
|
||||
int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
|
||||
char ip_addrs[][IP_ADDRESS_SIZE], const int max_count, int *count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
47
fastdfs.spec
47
fastdfs.spec
|
|
@ -1,13 +1,13 @@
|
|||
%define FastDFS fastdfs
|
||||
%define FastdfsServer fastdfs-server
|
||||
%define ClientName libfdfsclient
|
||||
%define FastTool fastdfs-tool
|
||||
%define FastVersion 5.0.3
|
||||
%define FastDFS fastdfs
|
||||
%define FDFSServer fastdfs-server
|
||||
%define FDFSClient libfdfsclient
|
||||
%define FDFSTool fastdfs-tool
|
||||
%define FDFSVersion 5.0.4
|
||||
|
||||
Name: %{FastDFS}
|
||||
Version: %{FastVersion}
|
||||
Version: %{FDFSVersion}
|
||||
Release: 1%{?dist}
|
||||
Summary: The fastdfs manager
|
||||
Summary: FastDFS server and client
|
||||
License: GPL
|
||||
Group: Arch/Tech
|
||||
URL: http://perso.orange.fr/sebastien.godard/
|
||||
|
|
@ -20,31 +20,32 @@ Requires: %__cp %__mv %__chmod %__grep %__mkdir %__install %__id
|
|||
%description
|
||||
This package provides tracker & storage of fastdfs
|
||||
|
||||
%package -n %{FastdfsServer}
|
||||
%package -n %{FDFSServer}
|
||||
Requires: libfastcommon
|
||||
Summary: fastdfs tracker & storage
|
||||
|
||||
%package -n %{FastTool}
|
||||
%package -n %{FDFSTool}
|
||||
Requires: libfastcommon
|
||||
Summary: fastdfs tools
|
||||
|
||||
%package -n %{ClientName}
|
||||
%package -n %{FDFSClient}
|
||||
Requires: libfastcommon
|
||||
Summary: The client dynamic library of fastdfs
|
||||
|
||||
%package -n %{ClientName}-devel
|
||||
Requires: %{ClientName}
|
||||
%package -n %{FDFSClient}-devel
|
||||
Requires: %{FDFSClient}
|
||||
Summary: The client header of fastdfs
|
||||
|
||||
%description -n %{FastdfsServer}
|
||||
%description -n %{FDFSServer}
|
||||
This package provides tracker & storage of fastdfs
|
||||
|
||||
%description -n %{ClientName}
|
||||
%description -n %{FDFSClient}
|
||||
This package is client dynamic library of fastdfs
|
||||
|
||||
%description -n %{ClientName}-devel
|
||||
This package is client header of fastdfs
|
||||
%description -n %{FDFSClient}-devel
|
||||
This package is client header of fastdfs client
|
||||
|
||||
%description -n %{FastTool}
|
||||
%description -n %{FDFSTool}
|
||||
This package is tools for fastdfs
|
||||
|
||||
%prep
|
||||
|
|
@ -65,11 +66,11 @@ DESTDIR=$RPM_BUILD_ROOT ./make.sh install
|
|||
|
||||
#%find_lang %{name}
|
||||
|
||||
%post -n %{FastdfsServer}
|
||||
%post -n %{FDFSServer}
|
||||
/sbin/chkconfig --add fdfs_trackerd
|
||||
/sbin/chkconfig --add fdfs_storaged
|
||||
|
||||
%preun -n %{FastdfsServer}
|
||||
%preun -n %{FDFSServer}
|
||||
/sbin/chkconfig --del fdfs_trackerd
|
||||
/sbin/chkconfig --del fdfs_storaged
|
||||
|
||||
|
|
@ -83,7 +84,7 @@ DESTDIR=$RPM_BUILD_ROOT ./make.sh install
|
|||
#/usr/local/bin/*
|
||||
#/usr/local/include/*
|
||||
|
||||
%files -n %{FastdfsServer}
|
||||
%files -n %{FDFSServer}
|
||||
%defattr(-,root,root,-)
|
||||
/usr/bin/fdfs_trackerd
|
||||
/usr/bin/fdfs_storaged
|
||||
|
|
@ -93,15 +94,15 @@ DESTDIR=$RPM_BUILD_ROOT ./make.sh install
|
|||
/etc/fdfs/tracker.conf.sample
|
||||
/etc/fdfs/storage.conf.sample
|
||||
|
||||
%files -n %{ClientName}
|
||||
%files -n %{FDFSClient}
|
||||
/usr/lib64/libfdfsclient*
|
||||
/etc/fdfs/client.conf.sample
|
||||
|
||||
%files -n %{ClientName}-devel
|
||||
%files -n %{FDFSClient}-devel
|
||||
%defattr(-,root,root,-)
|
||||
/usr/include/fastdfs/*
|
||||
|
||||
%files -n %{FastTool}
|
||||
%files -n %{FDFSTool}
|
||||
/usr/bin/fdfs_monitor
|
||||
/usr/bin/fdfs_test
|
||||
/usr/bin/fdfs_test1
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ if test "$PHP_FASTDFS_CLIENT" != "no"; then
|
|||
PHP_SUBST(FASTDFS_CLIENT_SHARED_LIBADD)
|
||||
|
||||
if test -z "$ROOT"; then
|
||||
ROOT=/usr/local
|
||||
ROOT=/usr
|
||||
fi
|
||||
|
||||
PHP_ADD_INCLUDE($ROOT/include/fastcommon)
|
||||
|
|
|
|||
|
|
@ -1,21 +1,12 @@
|
|||
.SUFFIXES: .c .o
|
||||
|
||||
COMPILE = $(CC) $(CFLAGS)
|
||||
INC_PATH = -I. -Itrunk_mgr -I../common -I../tracker -I../client -Ifdht_client -I/usr/local/include
|
||||
LIB_PATH = -L/usr/local/lib $(LIBS)
|
||||
INC_PATH = -I. -Itrunk_mgr -I../common -I../tracker -I../client -Ifdht_client -I/usr/include/fastcommon
|
||||
LIB_PATH = -L/usr/local/lib $(LIBS) -lfastcommon
|
||||
TARGET_PATH = $(TARGET_PREFIX)/bin
|
||||
CONFIG_PATH = $(TARGET_CONF_PATH)
|
||||
|
||||
SHARED_OBJS = ../common/hash.o ../common/chain.o \
|
||||
../common/shared_func.o ../common/ini_file_reader.o \
|
||||
../common/logger.o ../common/sockopt.o ../common/fdfs_global.o \
|
||||
../common/base64.o ../common/sched_thread.o \
|
||||
../common/local_ip_func.o ../common/http_func.o \
|
||||
../common/md5.o ../common/pthread_func.o \
|
||||
../common/fast_mblock.o ../common/avl_tree.o \
|
||||
../common/connection_pool.o ../common/process_ctrl.o \
|
||||
../common/ioevent.o ../common/fast_timer.o \
|
||||
../common/fast_task_queue.o ../common/ioevent_loop.o \
|
||||
SHARED_OBJS = ../common/fdfs_global.o \
|
||||
../tracker/fdfs_shared_func.o ../tracker/tracker_proto.o \
|
||||
tracker_client_thread.o storage_global.o storage_func.o \
|
||||
storage_service.o storage_sync.o storage_nio.o storage_dio.o \
|
||||
|
|
@ -44,6 +35,6 @@ install:
|
|||
mkdir -p $(TARGET_PATH)
|
||||
mkdir -p $(CONFIG_PATH)
|
||||
cp -f $(ALL_PRGS) $(TARGET_PATH)
|
||||
if [ ! -f $(CONFIG_PATH)/storage.conf ]; then cp -f ../conf/storage.conf $(CONFIG_PATH)/storage.conf.sample; fi
|
||||
if [ ! -f $(CONFIG_PATH)/storage.conf.sample ]; then cp -f ../conf/storage.conf $(CONFIG_PATH)/storage.conf.sample; fi
|
||||
clean:
|
||||
rm -f $(ALL_OBJS) $(ALL_PRGS)
|
||||
|
|
|
|||
|
|
@ -1,19 +1,12 @@
|
|||
.SUFFIXES: .c .o
|
||||
|
||||
COMPILE = $(CC) $(CFLAGS)
|
||||
INC_PATH = -I../common -I/usr/local/include
|
||||
LIB_PATH = -L/usr/local/lib $(LIBS)
|
||||
INC_PATH = -I../common -I/usr/include/fastcommon
|
||||
LIB_PATH = -L/usr/local/lib $(LIBS) -lfastcommon
|
||||
TARGET_PATH = $(TARGET_PREFIX)/bin
|
||||
CONFIG_PATH = $(TARGET_CONF_PATH)
|
||||
|
||||
SHARED_OBJS = ../common/hash.o ../common/chain.o ../common/base64.o \
|
||||
../common/shared_func.o ../common/ini_file_reader.o \
|
||||
../common/logger.o ../common/sockopt.o ../common/fdfs_global.o \
|
||||
../common/sched_thread.o ../common/http_func.o ../common/md5.o \
|
||||
../common/pthread_func.o ../common/local_ip_func.o \
|
||||
../common/connection_pool.o ../common/process_ctrl.o \
|
||||
../common/ioevent.o ../common/fast_timer.o \
|
||||
../common/fast_task_queue.o ../common/ioevent_loop.o \
|
||||
SHARED_OBJS = ../common/fdfs_global.o \
|
||||
tracker_proto.o tracker_mem.o tracker_service.o tracker_status.o \
|
||||
tracker_global.o tracker_func.o \
|
||||
fdfs_shared_func.o tracker_nio.o tracker_relationship.o \
|
||||
|
|
@ -21,7 +14,7 @@ SHARED_OBJS = ../common/hash.o ../common/chain.o ../common/base64.o \
|
|||
|
||||
ALL_OBJS = $(SHARED_OBJS)
|
||||
|
||||
ALL_PRGS = fdfs_trackerd
|
||||
ALL_PRGS = fdfs_trackerd
|
||||
|
||||
all: $(ALL_OBJS) $(ALL_PRGS)
|
||||
.o:
|
||||
|
|
@ -34,6 +27,6 @@ install:
|
|||
mkdir -p $(TARGET_PATH)
|
||||
mkdir -p $(CONFIG_PATH)
|
||||
cp -f $(ALL_PRGS) $(TARGET_PATH)
|
||||
if [ ! -f $(CONFIG_PATH)/tracker.conf ]; then cp -f ../conf/tracker.conf $(CONFIG_PATH)/tracker.conf.sample; fi
|
||||
if [ ! -f $(CONFIG_PATH)/tracker.conf.sample ]; then cp -f ../conf/tracker.conf $(CONFIG_PATH)/tracker.conf.sample; fi
|
||||
clean:
|
||||
rm -f $(ALL_OBJS) $(ALL_PRGS)
|
||||
|
|
|
|||
Loading…
Reference in New Issue