Commit 45a68310 authored by yuqing's avatar yuqing
Browse files

first commit based v2.00

No related merge requests found
Showing with 3399 additions and 0 deletions
+3399 -0
HISTORY 0 → 100644
Version 2.00 2014-02-02
* discard libevent, use epoll in Linux, kqueue in FreeBSD, port in SunOS directly
* mpool use hash table's multi locks
* fdhtd support start, stop and restart command
Version 1.23 2013-03-20
* bug fixed: mp_do_set unlock before call mp_clear_expired_keys
* fdhtd.conf add parameter: need_clear_expired_data
* support multi accept threads
* add common/connection_pool.h and common/connection_pool.c
Version 1.22 2012-12-31
* support rotate log by file size
* add common/avl_tree.h and common/avl_tree.c
* common/ini_file_reader.c does NOT call chdir
* use g_current_time instead of call time function
Version 1.21 2012-07-08
* another method to get local ip addresses
* logger support access log
* set pipe reading fd with attribute O_NOATIME
Version 1.20 2012-07-01
* bug fixed: client/fdht_client.c get_connection set err_no correctly
* common/logger.c: function log_init can be called more than once
* php extension logInfo change to logDebug
* c client logInfo change to logDebug
Version 1.19 2012-05-13
* md5 function name changed to avoid conflict
* sync.c: binlog_write_cache_buff dynamic malloc intead of static char array
* sync.c: function fdht_binlog_read optimization
* remove compile warnings
* get local ip addresses enhancement
* php extension compile passed in PHP 5.4.0
Version 1.18 2011-08-08
* use hash function: Time33Hash instead of PJWHash
Version 1.17 2011-04-28
* maintain object's key list
* add tools: client/fdht_set, client/fdht_get and client/fdht_delete
Version 1.16 2011-02-17
* cp fdht_client.conf to /etc/fdht/
* init.d/fdhtd correct config file name
* bug fixed: write_to_binlog_index then increase g_binlog_index
Version 1.15 2011-01-31
* strerror change to STRERROR macro
* bug fixed: server/func.c: load_group_servers type mismatched
* update common files from FastDFS V2.08
* macro DEFAULT_SYNC_MARK_FILE_FREQ change to FDHT_DEFAULT_SYNC_MARK_FILE_FREQ
Version 1.14 2010-11-18
* sockopt.h add non-block connect function connectserverbyip_nb
* log_init set log to cache to false (no cache)
* connect server support timeout, adding connect_timeout parameter in
config file
* local ip functions move to common/local_ip_func.c
* do not catch signal SIGABRT
* bug fixed: when fdhtd quit, maybe write to binlog file fail,
the error info is "Bad file descriptor"
Version 1.13 2010-06-06
* logger support context (multi instance)
* add files: common/pthread_func.h and common/pthread_func.c
* common/sched_thread.h, remove statement: extern bool g_continue_flag;
* global variables: g_base_path, g_network_timeout, g_version change to
g_fdht_base_path, g_fdht_network_timeout, g_fdht_version
* client add libfastcommon
* common/fdfs_base64.h/c change name to common/base64.h/c
* sync mark file and stat file to disk properly
* make.sh use TARGET_PREFIX instead of TARGET_PATH
Version 1.12 2010-04-11
* copy common files from FastDFS/common
* remove compile warning info of logError
* ini file reader supoort section
* redirect stdout and stderr to log file
* storage.conf: add if_alias_prefix parameter to get the ip address of the
local host
* make.sh compile use debug mode
* make.sh: default not install FastDHT services in Linux server
Version 1.11 2009-10-13
* bug fixed: http_func.c logError parameter mismatched
* base64 use context, functions changed
* common/ini_file_reader.c: fix memory leak
* omit 64 bits OS compile warning
* shared_func.c add functions: buffer_strcpy and buffer_memcpy
* add thread_stack_size in config file, default value is 1MB
* server use setsockopt to keep alive
* client persistent connection use setsockopt to keep alive
* bug fixed: common/shared_func.c allow_hosts array maybe overflow in some case
* common/sockopt.c: setsockopt level SOL_TCP only supported in Linux
* common/http_func.c: do not use function strsep because strsep is not portable
* server index exchanged hash code change type from unsigned int to int
Version 1.10 2009-07-19
* ini reader support HTTP protocol, conf file can be an url
* hash does not use macro: HASH_MALLOC_VALUE, add member is_malloc_value
* sockopt.c sendfile and recvfile support non-block socket
* sync.c call tcpsetnonblock after connect
* bug fix: sockopt.c do not set non-block in function tcpsetserveropt
* fdht_compress.c: change global static variable names to avoid conflict
Version 1.09 2009-07-01
* correct php extension error info
* fdht_compress.c: make sure syncing is done
* add shell script: stop.sh, restart.sh modified
* add fdhtd as service in Linux platform
* correct get local ip addresses
* common files do not use global vars like g_network_timeout and g_base_path
* fdht_compress.c: use {base_path}/tmp as sort temporary path instead of /tmp
* sync.c: check binlog file format when reading
* client can use proxy for FastDHT
* cache size not division by g_db_count
* protocol add stat cmd
* client retry connect when connection is not connected and keep_alive is true
* multi db use only one env
* support MPOOL (memory only cache as memcached)
* when max_threads set 1, use process instead of thread
* client use non-block socket to increase performance
* hash.c use chain impl by self
* bugfix: never expired / persistent keys not be cleared when clear expired keys
* inc use thread lock for atomicity
* mpool use rwlock, support multi-threads
* change work thread mode
* stat cmd add more info
Version 1.08 2009-04-12
* common/shared_func.c: rindex change to strrchr, add #include <netinet/in.h>
* use scheduling thread to sync binlog buff / cache to disk, add parameter
"sync_binlog_buff_interval" to conf file fdhtd.conf
* add restart daemon shell script: restart.sh
* add compress binlog tool
* hash_walk change return type from void to int
* compress binlog tool can be run by scheduler, fdhtd.conf add parameters:
compress_binlog_time_base and compress_binlog_interval
Version 1.07 2009-03-13
* fastdht_client.ini: add parameter fastdht_client.log_filename
* a header can be recv more than one time (recv header particially)
* for compatible with other language such as Java, change hash function
return type from unsigned int to int
Version 1.06 2009-02-26
* in config file conf/fdhtd.conf: add item "min_buff_size"
* add batch get, can get multi keys once
* add batch set, can set multi keys once
* add batch delete, can delete multi keys once
* php extension add class version, see sub dir php_client/
* performance enhancement: in function get, delay expires (timeout)
use partial set
* php extension support multi config file
* bug fix: fdht_client_init can be called more than once
* move global config parameters to fastdht_client.ini
Version 1.05 2009-02-04
* only start one dead_lock_detect thread to save resource
* in file php_client/README: add function description
* in file client/fdht_client.h: add function description / remark
Version 1.04 2009-01-29
* sync.c: when call socket fail, continue deal (do not exit)
* client: share a same sock when the ip and port of servers are same
* client: thread-safe and add muti-thread test program fdht_test_thread.c
* sync.c: fdht_sync_del return 0 when key not exists (errno: ENOENT)
Version 1.03 2009-01-25
* BDB env->open add DB_INIT_LOCK flag and add BDB dead_lock_detect thread
* shared_func.c add urlencode and urldecode functions
* clear expired keys every interval seconds
* php_client directory: add test_fastdht.php
Version 1.02 2009-01-18
* protocol header add field: keep_alive to support persistent connection
* fdhtd.conf add item: write_to_binlog to enable or disable replication
* return ENOENT (key not exist) when the key expires
* client auto reconnect when connection is reset and keep_alive is true
* add php client extension
* add README file in sub directories: client and php_client
Version 1.01 2008-12-15
* fdhtd.conf add parameter: sync_db_time_base, change the default value of
sync_db_interval to 86400 (one day)
* remove fdht_global.h dependency of client codes
Version 1.00 2008-12-08
* fix memory leak in sync.c
* function enhancement: db recovery when the daemon starts
* pass (void *)1 to memp_trickle before exit
Version 0.90 2008-12-02
* use memp_trickle to sync data to BDB file periodically
* fix bug: mod(%) result maybe < 0
* sockopt.h / .c add function tcpsetnodelay
* bug fixed: realloc size and reasign
* add client set test program: fdht_test_set.c
* add Makefile.in and make.sh
* pipe read more bytes once
Version 0.80 2008-11-24
* add namespace and object ID
* add expires (timeout)
* add binlog write buff to increase performance
Version 0.50 2008-10-22
* support data sync
Version 0.20 2008-09-27
* framework is done:
# implement db functions such as get, set, inc and del
# implement asynchronous IO use libevent
Version 0.10 2008-09-08
* first version, only implement queue management
INSTALL 0 → 100644
Copy right 2009 Happy Fish / YuQing
FastDHT may be copied only under the terms of the GNU General
Public License V3, which may be found in the FastDHT source kit.
Please visit the FastDHT Home Page for more detail.
Google code: http://code.google.com/p/fastdht/
Chinese language: http://fastdht.csource.com/
#step 1. install libevent
# download libevent-1.4.8-stable.tar.gz from website
# http://monkey.org/~provos/libevent/
tar xzf libevent-1.4.8-stable.tar.gz
cd libevent-1.4.8-stable
./configure --prefix=/usr
make; make install
#step 2. install Berkeley DB
# download db-4.7.25.tar.gz from website
# http://www.oracle.com/technology/software/products/berkeley-db/index.html
tar xzf db-4.7.25.tar.gz
cd db-4.7.25/build_unix
../dist/configure --prefix=/usr
make; make install
#step 3. install FastDHT
# download FastDHT from website
# http://code.google.com/p/fastdht/downloads/list
# then unpack the source package as:
# tar xzf FastDHT_v1.xx.tar.gz
tar xzf FastDHT_v1.09.tar.gz
cd FastDHT
./make.sh; ./make.sh install
#step 4. edit/modify the config file
#step 5. run server program
/usr/local/bin/fdhtd <conf_filename>
#step 6. run test program
#run the client test program:
/usr/local/bin/fdht_test <conf_filename>
#for example
/usr/local/bin/fdht_test conf/fdht_client.conf
server config file sample:
###start of server config###
disabled=false
bind_addr=
port=11411
network_timeout=60
base_path=/home/yuqing/fastdht
# max concurrent connect count
# default value is 256
max_connections=256
# work thread count, should <= max_connections
# default value is 32
max_threads=32
# max communication package size
# bytes unit can be one of follows:
### G or g for gigabyte(GB)
### M or m for megabyte(MB)
### K or k for kilobyte(KB)
### no unit for byte(B)
# default value is 64KB
max_pkg_size=64KB
# min buff size, the task queue size at least: max_connections * min_buff_size,
# you can set the value of min_buff_size to that of max_pkg_size to avoid
# memory re-alloc if memory is enough.
# bytes unit can be one of follows:
### G or g for gigabyte(GB)
### M or m for megabyte(MB)
### K or k for kilobyte(KB)
### no unit for byte(B)
# default value is 64KB
min_buff_size=64KB
# store type
### BDB for Berkeley DB
### MPOOL for memory pool
store_type = BDB
# cache size
# bytes unit can be one of follows:
### G or g for gigabyte(GB)
### M or m for megabyte(MB)
### K or k for kilobyte(KB)
### no unit for byte(B)
# default value is 64MB
cache_size = 32MB
# the BDB db filename prefix
db_prefix = db
# BDB page size. The minimum page size is 512 bytes, the maximum page size is
# 64KB, and the page size must be a power-of-two
# bytes unit can be one of follows:
### K or k for kilobyte(KB)
### no unit for byte(B)
# default value is 4KB
page_size = 4096
# DBD DB type, case insensitive, value can be:
# btree: BTREE type (default)
# hash: HASH table
db_type = btree
# MPOOL hash table init capacity
# default value is 10000
mpool_init_capacity = 10000
# MPOOL hash table load factor
# should >= 0.1 and <= 1.0
# default value is 0.75
mpool_load_factor = 0.75
# MPOOL hash table clear expired key min interval (seconds)
mpool_clear_min_interval = 30
#standard log level as syslog, case insensitive, value list:
### emerg for emergency
### alert
### crit for critical
### error
### warn for warning
### notice
### info (default)
### debug
log_level=info
# unix group name to run this program,
# not set (empty) means run by the group of current user
run_by_group=
# unix username to run this program,
# not set (empty) means run by current user
run_by_user=
# allow_hosts can ocur more than once, host can be hostname or ip address,
# "*" means match all ip addresses, can use range like this: 10.0.1.[1-15,20] or
# host[01-08,20-25].domain.com, for example:
# allow_hosts=10.0.1.[1-15,20]
# allow_hosts=host[01-08,20-25].domain.com
allow_hosts=*
# sync log buff to disk every interval seconds
# default value is 10 seconds
sync_log_buff_interval=10
# the base time for syncing db to disk, time format: HH:MM
# empty for the current time when the program starts
# default value is 00:00
sync_db_time_base=00:00
# sync db to disk every interval seconds
# default value is 86400 seconds (sync every day)
# <= 0 for never sync
sync_db_interval=86400
# if write to binlog file, set to 0 to disable replication
# default value is 1
write_to_binlog=1
# sync binlog buff / cache to disk every interval seconds
# this parameter is valid when write_to_binlog set to 1
# default value is 60 seconds
sync_binlog_buff_interval=60
# the base time for clear expired keys, time format: HH:MM
# empty for the current time when the program starts
# default value is 04:00
clear_expired_time_base=04:00
# clear expired keys every interval seconds
# default value is 86400 seconds (clear every day)
# <= 0 for never clear
clear_expired_interval=86400
# detect Berkeley DB dead lock every interval milliseconds
# default value is 1000 milliseconds
# <= 0 for never detect
db_dead_lock_detect_interval=1000
# the base time for compressing binlog file, time format: HH:MM
# empty for the current time when the program starts
# default value is 02:00
compress_binlog_time_base=02:00
# try to compress binlog file every interval seconds
# default value is 86400 seconds (try to compress every day)
# <= 0 for never compress
compress_binlog_interval=86400
# if write to binlog file, set to 0 to disable replication
# use "#include filename" (not include double quotes) directive to load
# FastDHT server list when the filename is a relative path such as pure
# filename, the base path is the base path of current/this config file
#include fdht_servers.conf
###end of server config###
Item detail
1. common items
----------------------------------------------------
| item name | type | default | Must |
----------------------------------------------------
| group_count | int | | Y |
----------------------------------------------------
| group# | string | | Y |
----------------------------------------------------
| network_timeout | int | 30(s) | N |
----------------------------------------------------
| log_level | string | info | N |
----------------------------------------------------
memo:
* group#: # based 0, from 0 to group_count - 1,
value format: hostname:port
each group can have more than one value(host:port)
2. server items
----------------------------------------------------
| item name | type | default | Must |
----------------------------------------------------
| base_path | string | | Y |
----------------------------------------------------
| store_type | string | | Y |
----------------------------------------------------
| db_prefix | string | | Y |
----------------------------------------------------
| disabled | boolean| false | N |
----------------------------------------------------
| bind_addr | string | | N |
----------------------------------------------------
| port | int | 24000 | N |
----------------------------------------------------
| max_connections | int | 256 | N |
----------------------------------------------------
| max_threads | int | 32 | N |
----------------------------------------------------
| max_pkg_size | string | 64KB | N |
----------------------------------------------------
| min_buff_size | string | 64KB | N |
----------------------------------------------------
| cache_size | string | 64MB | N |
----------------------------------------------------
| page_size | string | 4KB | N |
----------------------------------------------------
| db_type | string | btree | N |
----------------------------------------------------
| mpool_init_capacity | int | 10000 | N |
----------------------------------------------------
| mpool_load_factor | double | 0.75 | N |
----------------------------------------------------
| mpool_clear_min_interval| int | 30 (s) | N |
----------------------------------------------------
| run_by_group | string | | N |
----------------------------------------------------
| run_by_user | string | | N |
----------------------------------------------------
| allow_hosts | string | * | N |
----------------------------------------------------
| sync_log_buff_interval | int | 10(s) | N |
----------------------------------------------------
| sync_db_time_base | string | 00:00 | N |
----------------------------------------------------
| sync_db_interval | int | 86400(s)| N |
----------------------------------------------------
| clear_expired_time_base| string | 04:00 | N |
----------------------------------------------------
| expired_time_interval | int | 0(s) | N |
----------------------------------------------------
| db_dead_lock_detect_interval| int|1000(ms)| N |
----------------------------------------------------
| write_to_binlog | boolean| 1 | N |
----------------------------------------------------
| sync_binlog_buff_interval| int | 60(s) | N |
----------------------------------------------------
| compress_binlog_time_base| string| 02:00 | N |
----------------------------------------------------
| compress_binlog_interval | int |86400(s)| N |
----------------------------------------------------
memo:
* base_path is the base path of sub dirs:
data and logs. base_path must exist and it's sub dirs will
be automatically created if not exist.
$base_path/data: store data files
$base_path/logs: store log files
* log_level is the standard log level as syslog, case insensitive
# emerg: for emergency
# alert
# crit: for critical
# error
# warn: for warning
# notice
# info
# debug
* allow_hosts can ocur more than once, host can be hostname or ip address,
"*" means match all ip addresses, can use range like this: 10.0.1.[1-15,20]
or host[01-08,20-25].domain.com, for example:
allow_hosts=10.0.1.[1-15,20]
allow_hosts=host[01-08,20-25].domain.com
3. client items
---------------------------------------------------
| item name | type | default | Must |
---------------------------------------------------
| base_path | string | | Y |
---------------------------------------------------
| keep_alive | boolean| 0 | N |
---------------------------------------------------
memo:
* base_path is the base path of sub dirs: logs.
base_path must exist.
* set keep_alive to true to make persistent connection
README 0 → 100644
Copyright (C) 2008 Happy Fish / YuQing
FastDHT may be copied only under the terms of the GNU General
Public License V3, which may be found in the FastDHT source kit.
Please visit the FastDHT Home Page for more detail.
Google code (English language): http://code.google.com/p/fastdht/
Chinese language: http://fastdht.csource.com/
FastDHT is a high-performance distributed hash system (DHT) which based key
value pairs. It can store mass key value pairs such as filename mapping,
session data and user related data.
FastDHT uses the Berkeley DB as data storage to support mass data and libevent
as network IO to support huge connections. FastDHT implements data replication
by it's binlog file, so it only uses the basic storage function of the
Berkeley DB.
FastDHT cluster composes of one or many groups and a group contains one or more
servers. The data on a group is same and data is synchronized only among the
servers of the same group. The servers of a group are coordinative, so which
server is selected to access according to the key's hash code. The source server
pushes the data to other servers in the group.
The client of FastDHT decides which server to be selected. When select which
server to access, we use the key's hash code to avoid lookuping the constrast
table. The step of the algorithm is:
1. calculate the hash code of the key
2. group_index = hash_code % group_count
3. new_hash_code = (hash_code << 16) | (hash_code >> 16)
4. server_index = new_hash_code % server_count_in_the_group
In FastDHT, the key contains three fields: namespace, object ID and key name.
These three concepts are like those of the database system:
namespace vs database name, object ID vs table name and key name vs field name.
The purpose of namespace is resolving the probable data conflict between
multiple users such as the different applications or products.
The purpose of object ID is convenient for organization and management of
object related data such as user's data and increasing the whole performance.
The sytem is more flexible as namespace and object ID are imported. These two
fields can be empty in some cases.
The input of the hash function (it's result is hash code) is: If namespace and
object ID are not empty, the concatenation of these two fields, or the key name.
FastDHT imports the concept of logic group which is used to avoid re-hashing
when the system scales. A physical group is composed of one or more real
servers. It can contains one or more logic groups.
A FastDHT server supports several logic groups and the data of a logic group is
stored to a single Berkeley DB file. This design provides more convenience for
scaling. We can use a larger number of logic groups at the beginning. When
system scaled, one or more logic groups are migrated to the new physical
group(s). All things we need to do are:
1. copy the Berkeley DB data file to the new servers
2. change the config file
3. restart the programs of the FastDHT servers
4. restart the programs of the FastDHT clients if necessary
FastDHT supports timeout and every key has timeout attribute. FastDHT can be
used to store session data which is more efficient and more simple than
the traditional database.
.SUFFIXES: .c .o .lo
COMPILE = $(CC) $(CFLAGS)
INC_PATH = -I../common -I/usr/local/include
LIB_PATH = -L/usr/local/lib $(LIBS)
TARGET_PATH = $(TARGET_PREFIX)/bin
CONFIG_PATH = $(TARGET_CONF_PATH)
TARGET_LIB = $(TARGET_PREFIX)/lib
TARGET_INC = $(TARGET_PREFIX)/include
STATIC_OBJS = ../common/hash.o ../common/chain.o ../common/pthread_func.o \
../common/shared_func.o ../common/ini_file_reader.o \
../common/logger.o ../common/sockopt.o \
../common/base64.o ../common/http_func.o \
../common/fdht_global.o ../common/fdht_proto.o \
../common/fdht_func.o fdht_client.o
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
FDHT_SHARED_OBJS = ../common/fdht_global.lo ../common/fdht_proto.lo \
../common/fdht_func.lo fdht_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
FDHT_HEADER_FILES = ../common/fdht_define.h ../common/fdht_func.h \
../common/fdht_global.h ../common/fdht_proto.h \
../common/fdht_proto_types.h ../common/fdht_types.h \
fdht_client.h
ALL_OBJS = $(STATIC_OBJS) $(FAST_SHARED_OBJS) $(FDHT_SHARED_OBJS)
ALL_PRGS = fdht_test fdht_batch_test fdht_test_thread fdht_test_set \
fdht_test_get fdht_set fdht_get fdht_delete
ALL_LIBS = libfastcommon.so.1 libfdhtclient.so.1
all: $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
libfastcommon.so.1:
$(COMPILE) -o $@ $< -shared $(FAST_SHARED_OBJS) $(LIB_PATH)
ln -fs libfastcommon.so.1 libfastcommon.so
libfdhtclient.so.1:
$(COMPILE) -o $@ $< -shared $(FDHT_SHARED_OBJS) $(LIB_PATH) -L. -lfastcommon
ln -fs libfdhtclient.so.1 libfdhtclient.so
.o:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c.o:
$(COMPILE) -c -o $@ $< $(INC_PATH)
.c.lo:
$(COMPILE) -c -fPIC -o $@ $< $(INC_PATH)
install:
mkdir -p $(TARGET_PATH)
mkdir -p $(CONFIG_PATH)
mkdir -p $(TARGET_LIB)
cp -f $(ALL_PRGS) $(TARGET_PATH)
cp -f $(ALL_LIBS) $(TARGET_LIB)
if [ ! -f $(CONFIG_PATH)/fdht_client.conf ]; then cp -f ../conf/fdht_client.conf ../conf/fdht_servers.conf $(CONFIG_PATH); fi
mkdir -p $(TARGET_INC)
mkdir -p $(TARGET_INC)/fastcommon
mkdir -p $(TARGET_INC)/fastdht
cp -f $(FAST_HEADER_FILES) $(TARGET_INC)/fastcommon
cp -f $(FDHT_HEADER_FILES) $(TARGET_INC)/fastdht
ln -fs $(TARGET_LIB)/libfastcommon.so.1 $(TARGET_LIB)/libfastcommon.so
ln -fs $(TARGET_LIB)/libfdhtclient.so.1 $(TARGET_LIB)/libfdhtclient.so
ln -fs $(TARGET_LIB)/libfastcommon.so.1 /usr/lib/libfastcommon.so
ln -fs $(TARGET_LIB)/libfdhtclient.so.1 /usr/lib/libfdhtclient.so
clean:
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
Copyright (C) 2008 Happy Fish / YuQing
FastDHT client library may be copied only under the terms of
the Less GNU General Public License (LGPL).
Please visit the FastDHT Home Page for more detail.
Google code (English language): http://code.google.com/p/fastdht/
Chinese language: http://fastdht.csource.com/
Please read INSTALL file to know about how to config FastDHT client.
/**
* 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 <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include "fdht_global.h"
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
#include "fdht_types.h"
#include "fdht_proto.h"
#include "fdht_client.h"
#include "fdht_func.h"
int main(int argc, char *argv[])
{
char *conf_filename;
int result;
int expires;
FDHTObjectInfo object_info;
FDHTKeyValuePair key_list[32];
char sub_keys[16 * 1024];
char *keys[FDHT_KEY_LIST_MAX_COUNT];
int key_count;
int success_count;
int i;
int conn_success_count;
int conn_fail_count;
int sub_key_count;
printf("This is FastDHT client test program v%d.%d\n" \
"\nCopyright (C) 2008, Happy Fish / YuQing\n" \
"\nFastDHT may be copied only under the terms of the GNU General\n" \
"Public License V3, which may be found in the FastDHT source kit.\n" \
"Please visit the FastDHT Home Page http://www.csource.org/ \n" \
"for more detail.\n\n" \
, g_fdht_version.major, g_fdht_version.minor);
if (argc < 2)
{
printf("Usage: %s <config_file>\n", argv[0]);
return 1;
}
log_init();
conf_filename = argv[1];
g_log_context.log_level = LOG_DEBUG;
if ((result=fdht_client_init(conf_filename)) != 0)
{
return result;
}
//g_keep_alive = true;
if (g_keep_alive)
{
if ((result=fdht_connect_all_servers(&g_group_array, true, \
&conn_success_count, &conn_fail_count)) != 0)
{
printf("fdht_connect_all_servers fail, " \
"error code: %d, error info: %s\n", \
result, STRERROR(result));
return result;
}
}
srand(time(NULL));
expires = FDHT_EXPIRES_NEVER;
//expires = time(NULL) + 3600;
memset(&object_info, 0, sizeof(object_info));
object_info.namespace_len = sprintf(object_info.szNameSpace, "user");
object_info.obj_id_len = sprintf(object_info.szObjectId, "happy_fish");
memset(key_list, 0, sizeof(key_list));
key_count = 4;
key_list[0].key_len = sprintf(key_list[0].szKey, "login");
key_list[1].key_len = sprintf(key_list[1].szKey, "reg");
key_list[2].key_len = sprintf(key_list[2].szKey, "intl");
key_list[3].key_len = sprintf(key_list[3].szKey, "co");
do
{
key_list[0].pValue = "happyfish";
key_list[0].value_len = strlen(key_list[0].pValue);
key_list[1].pValue = "1235277184";
key_list[1].value_len = strlen(key_list[1].pValue);
key_list[2].pValue = "zh";
key_list[2].value_len = strlen(key_list[2].pValue);
key_list[3].pValue = "cn";
key_list[3].value_len = strlen(key_list[3].pValue);
if ((result=fdht_batch_set(&object_info, key_list, \
key_count, expires, &success_count)) != 0)
{
printf("fdht_batch_set result=%d\n", result);
break;
}
printf("fdht_batch_set success count: %d\n", success_count);
for (i=0; i<key_count; i++)
{
key_list[i].pValue = NULL;
key_list[i].value_len = 0;
}
if ((result=fdht_batch_get_ex(&object_info, key_list, \
key_count, expires, &success_count)) != 0)
{
printf("fdht_batch_get_ex result=%d\n", result);
break;
}
printf("fdht_batch_get_ex success count: %d\n", success_count);
for (i=0; i<key_count; i++)
{
if (key_list[i].status == 0)
{
printf("key=%s, value=%s(%d)\n", \
key_list[i].szKey, key_list[i].pValue, \
key_list[i].value_len);
}
else
{
printf("key=%s, status=%d\n", \
key_list[i].szKey, key_list[i].status);
}
}
for (i=0; i<key_count; i++)
{
if (key_list[i].pValue != NULL)
{
free(key_list[i].pValue);
}
}
if ((result=fdht_get_sub_keys(&object_info, sub_keys, \
sizeof(sub_keys))) != 0)
{
printf("fdht_get_sub_keys fail, " \
"errno: %d, error info: %s\n", \
result, STRERROR(result));
}
else
{
sub_key_count = splitEx(sub_keys, \
FDHT_FULL_KEY_SEPERATOR, keys, \
FDHT_KEY_LIST_MAX_COUNT);
printf("sub keys after batch set: ");
for (i=0; i<sub_key_count; i++)
{
if (i > 0)
{
printf(", ");
}
printf("%s", keys[i]);
}
printf("\n");
}
/*
if ((result=fdht_batch_delete(&object_info, key_list, \
key_count, &success_count)) != 0)
{
printf("fdht_batch_delete result=%d\n", result);
break;
}
printf("fdht_batch_delete success count: %d\n", success_count);
*/
if ((result=fdht_get_sub_keys(&object_info, sub_keys, \
sizeof(sub_keys))) != 0)
{
printf("fdht_get_sub_keys fail, " \
"errno: %d, error info: %s\n", \
result, STRERROR(result));
}
else
{
printf("sub keys after batch delete: %s\n", sub_keys);
}
} while(0);
if (g_keep_alive)
{
fdht_disconnect_all_servers(&g_group_array);
}
fdht_client_destroy();
return result;
}
This diff is collapsed.
/**
* 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.
**/
//fdht_client.h
#ifndef _FDHT_CLIENT_H
#define _FDHT_CLIENT_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fdht_define.h"
#include "fdht_types.h"
#include "fdht_proto.h"
#include "fdht_func.h"
#ifdef __cplusplus
extern "C" {
#endif
extern GroupArray g_group_array; //group info, including server list
extern bool g_keep_alive; //persistent connection flag
/*
init function
param:
filename: client config filename
return: 0 for success, != 0 for fail (errno)
*/
int fdht_client_init(const char *filename);
/*
init function
param:
filename: client config filename
pGroupArray: return server list
bKeepAlive: return keep alive flag
return: 0 for success, != 0 for fail (errno)
*/
int fdht_load_conf(const char *filename, GroupArray *pGroupArray, \
bool *bKeepAlive);
int fdht_connect_all_servers(GroupArray *pGroupArray, const bool bKeepAlive, \
int *success_count, int *fail_count);
void fdht_disconnect_all_servers(GroupArray *pGroupArray);
/*
destroy function, free resource
param:
return: none
*/
void fdht_client_destroy();
#define fdht_get(pKeyInfo, ppValue, value_len) \
fdht_get_ex1((&g_group_array), g_keep_alive, pKeyInfo, \
FDHT_EXPIRES_NONE, ppValue, value_len, malloc)
#define fdht_get_ex(pKeyInfo, expires, ppValue, value_len) \
fdht_get_ex1((&g_group_array), g_keep_alive, pKeyInfo, expires, \
ppValue, value_len, malloc)
#define fdht_batch_get(pObjectInfo, key_list, key_count, success_count) \
fdht_batch_get_ex1((&g_group_array), g_keep_alive, pObjectInfo, \
key_list, key_count, FDHT_EXPIRES_NONE, \
malloc, success_count)
#define fdht_batch_get_ex(pObjectInfo, key_list, key_count, \
expires, success_count) \
fdht_batch_get_ex1((&g_group_array), g_keep_alive, pObjectInfo, \
key_list, key_count, expires, malloc, success_count)
#define fdht_set(pKeyInfo, expires, pValue, value_len) \
fdht_set_ex((&g_group_array), g_keep_alive, pKeyInfo, expires, \
pValue, value_len)
#define fdht_batch_set(pObjectInfo, key_list, key_count, \
expires, success_count) \
fdht_batch_set_ex((&g_group_array), g_keep_alive, pObjectInfo, \
key_list, key_count, expires, success_count)
#define fdht_inc(pKeyInfo, expires, increase, pValue, value_len) \
fdht_inc_ex((&g_group_array), g_keep_alive, pKeyInfo, expires, \
increase, pValue, value_len)
#define fdht_delete(pKeyInfo) \
fdht_delete_ex((&g_group_array), g_keep_alive, pKeyInfo)
#define fdht_batch_delete(pObjectInfo, key_list, key_count, success_count) \
fdht_batch_delete_ex((&g_group_array), g_keep_alive, pObjectInfo, \
key_list, key_count, success_count)
#define fdht_stat(server_index, buff, size) \
fdht_stat_ex((&g_group_array), g_keep_alive, server_index, buff, size)
#define fdht_get_sub_keys(pObjectInfo, key_list, key_size) \
fdht_get_sub_keys_ex((&g_group_array), g_keep_alive, \
pObjectInfo, key_list, key_size)
/*
get value of the key
param:
pGroupArray: group info, can use &g_group_array
bKeepAlive: persistent connection flag, true for persistent connection
pKeyInfo: the key to fetch
expires: expire time (unix timestamp)
FDHT_EXPIRES_NONE - do not change the expire time of the key
FDHT_EXPIRES_NEVER- set the expire time to forever(never expired)
ppValue: return the value of the key
value_len: return the length of the value (bytes)
malloc_func: malloc function, can be standard function named malloc
return: 0 for success, != 0 for fail (errno)
*/
int fdht_get_ex1(GroupArray *pGroupArray, const bool bKeepAlive, \
FDHTKeyInfo *pKeyInfo, const time_t expires, \
char **ppValue, int *value_len, MallocFunc malloc_func);
/*
get values of the key list
param:
pGroupArray: group info, can use &g_group_array
bKeepAlive: persistent connection flag, true for persistent connection
pObjectInfo: the object to fetch, namespace and object id can't be empty
key_list: key list, return the value of the key
key_count: key count
expires: expire time (unix timestamp)
FDHT_EXPIRES_NONE - do not change the expire time of the keys
FDHT_EXPIRES_NEVER- set the expire time to forever(never expired)
malloc_func: malloc function, can be standard function named malloc
return: 0 for success, != 0 for fail (errno)
*/
int fdht_batch_get_ex1(GroupArray *pGroupArray, const bool bKeepAlive, \
FDHTObjectInfo *pObjectInfo, FDHTKeyValuePair *key_list, \
const int key_count, const time_t expires, \
MallocFunc malloc_func, int *success_count);
/*
set value of the key
param:
pGroupArray: group info, can use &g_group_array
bKeepAlive: persistent connection flag, true for persistent connection
pKeyInfo: the key to set
expires: expire time (unix timestamp)
FDHT_EXPIRES_NEVER- set the expire time to forever(never expired)
pValue: the value of the key
value_len: the length of the value (bytes)
return: 0 for success, != 0 for fail (errno)
*/
int fdht_set_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
FDHTKeyInfo *pKeyInfo, const time_t expires, \
const char *pValue, const int value_len);
/*
set values of the key list
param:
pGroupArray: group info, can use &g_group_array
bKeepAlive: persistent connection flag, true for persistent connection
pObjectInfo: the object to fetch, namespace and object id can't be empty
key_list: key list, return the value of the key
key_count: key count
expires: expire time (unix timestamp)
FDHT_EXPIRES_NEVER- set the expire time to forever(never expired)
return: 0 for success, != 0 for fail (errno)
*/
int fdht_batch_set_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
FDHTObjectInfo *pObjectInfo, FDHTKeyValuePair *key_list, \
const int key_count, const time_t expires, int *success_count);
/*
increase value of the key, if the key does not exist,
set the value to increment value (param named "increase")
param:
pGroupArray: group info, can use &g_group_array
bKeepAlive: persistent connection flag, true for persistent connection
pKeyInfo: the key to increase
expires: expire time (unix timestamp)
FDHT_EXPIRES_NEVER- set the expire time to forever(never expired)
increase: the increment value, can be negative, eg. 1 or -1
pValue: return the value after increment
value_len: return the length of the value (bytes)
return: 0 for success, != 0 for fail (errno)
*/
int fdht_inc_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
FDHTKeyInfo *pKeyInfo, const time_t expires, \
const int increase, char *pValue, int *value_len);
/*
delete the key
param:
pGroupArray: group info, can use &g_group_array
bKeepAlive: persistent connection flag, true for persistent connection
pKeyInfo: the key to delete
return: 0 for success, != 0 for fail (errno)
*/
int fdht_delete_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
FDHTKeyInfo *pKeyInfo);
/*
delete key list
param:
pGroupArray: group info, can use &g_group_array
bKeepAlive: persistent connection flag, true for persistent connection
pObjectInfo: the object to fetch, namespace and object id can't be empty
key_list: key list, return the value of the key
key_count: key count
return: 0 for success, != 0 for fail (errno)
*/
int fdht_batch_delete_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
FDHTObjectInfo *pObjectInfo, FDHTKeyValuePair *key_list, \
const int key_count, int *success_count);
/*
query stat of server
param:
pGroupArray: group info, can use &g_group_array
server_index: index of server, based 0
buff: return stat buff, key value pair as key=value, row seperated by \n
size: buff size
return: 0 for success, != 0 for fail (errno)
*/
int fdht_stat_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
const int server_index, char *buff, const int size);
/*
get sub keys of an object
param:
pGroupArray: group info, can use &g_group_array
bKeepAlive: persistent connection flag, true for persistent connection
pObjectInfo: the object to fetch, namespace and object id can't be empty
key_list: store the sub keys
key_size: the key buff size
return: 0 for success, != 0 for fail (errno)
*/
int fdht_get_sub_keys_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
FDHTObjectInfo *pObjectInfo, char *key_list, \
const int key_size);
#ifdef __cplusplus
}
#endif
#endif
/**
* 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 <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include "fdht_global.h"
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
#include "fdht_types.h"
#include "fdht_proto.h"
#include "fdht_func.h"
#include "fdht_client.h"
void usage(const char *program)
{
printf("Usage: %s <config_file> [namespace:][object id] " \
"<key list split by comma>\n" \
"\tsuch as: %s /etc/fdht/fdht_client.conf " \
"bbs:happyfish name,sex,mail\n", \
program, program);
}
int main(int argc, char *argv[])
{
char *conf_filename;
char *keys_arg;
char *keys_buff;
char *parts2[2];
char **keys;
FDHTKeyValuePair *key_list;
FDHTKeyValuePair *pKeyValuePair;
char object_buff[FDHT_MAX_NAMESPACE_LEN + FDHT_MAX_OBJECT_ID_LEN + 2];
int result;
int expires;
int key_count;
int success_count;
int fail_count;
int count;
int i;
FDHTObjectInfo object_info;
FDHTKeyInfo key_info;
printf("This is FastDHT client test program v%d.%02d\n" \
"\nCopyright (C) 2008, Happy Fish / YuQing\n" \
"\nFastDHT may be copied only under the terms of the GNU General\n" \
"Public License V3, which may be found in the FastDHT source kit.\n" \
"Please visit the FastDHT Home Page http://www.csource.org/ \n" \
"for more detail.\n\n" \
, g_fdht_version.major, g_fdht_version.minor);
if (argc < 3)
{
usage(argv[0]);
return EINVAL;
}
conf_filename = argv[1];
memset(&object_info, 0, sizeof(FDHTObjectInfo));
if (argc == 3)
{
keys_arg = argv[2];
}
else
{
keys_arg = argv[3];
snprintf(object_buff, sizeof(object_buff), "%s", argv[2]);
if (splitEx(object_buff, ':', parts2, 2) != 2)
{
usage(argv[0]);
return EINVAL;
}
object_info.namespace_len = strlen(parts2[0]);
object_info.obj_id_len = strlen(parts2[1]);
if (object_info.namespace_len == 0)
{
printf("invalid empty namespace!\n");
return EINVAL;
}
if (object_info.namespace_len > FDHT_MAX_NAMESPACE_LEN)
{
printf("namespace: %s is too long, exceed %d!\n", \
parts2[0], FDHT_MAX_NAMESPACE_LEN);
return EINVAL;
}
if (object_info.obj_id_len == 0)
{
printf("invalid empty object Id!\n");
return EINVAL;
}
if (object_info.obj_id_len > FDHT_MAX_OBJECT_ID_LEN)
{
printf("object id: %s is too long, exceed %d!\n", \
parts2[1], FDHT_MAX_OBJECT_ID_LEN);
return EINVAL;
}
memcpy(object_info.szNameSpace, parts2[0], \
object_info.namespace_len);
memcpy(object_info.szObjectId, parts2[1], \
object_info.obj_id_len);
}
if (*keys_arg == '\0')
{
printf("invalid empty keys!\n");
return EINVAL;
}
log_init();
g_log_context.log_level = LOG_DEBUG;
if ((result=fdht_client_init(conf_filename)) != 0)
{
return result;
}
log_set_cache(false);
keys_buff = strdup(keys_arg);
if (keys_buff == NULL)
{
printf("strdup %d bytes fail!\n", (int)strlen(keys_arg));
return ENOMEM;
}
expires = FDHT_EXPIRES_NEVER;
memset(&key_info, 0, sizeof(key_info));
keys = split(keys_buff, ',', 0, &key_count);
key_list = (FDHTKeyValuePair *)malloc(sizeof(FDHTKeyValuePair) \
* key_count);
if (key_list == NULL)
{
printf("malloc %d bytes fail!\n", \
(int)sizeof(FDHTKeyValuePair) * key_count);
return ENOMEM;
}
memset(key_list, 0, sizeof(FDHTKeyValuePair) * key_count);
success_count = 0;
fail_count = 0;
pKeyValuePair = key_list;
for (i=0; i<key_count; i++)
{
pKeyValuePair->key_len = snprintf(pKeyValuePair->szKey, \
sizeof(pKeyValuePair->szKey), "%s", keys[i]);
if (object_info.namespace_len == 0)
{
key_info.key_len = snprintf(key_info.szKey, \
sizeof(key_info.szKey), "%s", keys[i]);
if ((pKeyValuePair->status=fdht_delete(&key_info)) != 0)
{
fail_count++;
}
else
{
success_count++;
}
}
pKeyValuePair++;
}
if (object_info.namespace_len > 0)
{
result = fdht_batch_delete(&object_info, key_list, \
pKeyValuePair - key_list, &success_count);
if (result != 0)
{
fail_count = pKeyValuePair - key_list;
printf("delete keys fail, " \
"error code: %d, error info: %s\n", \
result, STRERROR(result));
fdht_client_destroy();
return result;
}
else
{
fail_count = (pKeyValuePair - key_list) - success_count;
}
}
if (fail_count > 0)
{
pKeyValuePair = key_list;
for (i=0; i<key_count; i++)
{
if (pKeyValuePair->status == 0)
{
pKeyValuePair++;
continue;
}
printf("delete key: %s fail, " \
"error code: %d, error info: %s\n", \
pKeyValuePair->szKey, pKeyValuePair->status, \
STRERROR(pKeyValuePair->status));
pKeyValuePair++;
}
printf("\n");
}
if (success_count > 0)
{
printf("success delete keys: ");
count = 0;
pKeyValuePair = key_list;
for (i=0; i<key_count; i++)
{
if (pKeyValuePair->status != 0)
{
pKeyValuePair++;
continue;
}
if (count > 0)
{
printf(", ");
}
printf("%s", pKeyValuePair->szKey);
pKeyValuePair++;
count++;
}
printf("\n");
}
printf("\n");
printf("success delete key count: %d, fail count: %d\n", \
success_count, fail_count);
free(keys_buff);
free(key_list);
freeSplit(keys);
fdht_client_destroy();
return result;
}
/**
* 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 <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include "fdht_global.h"
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
#include "fdht_types.h"
#include "fdht_proto.h"
#include "fdht_func.h"
#include "fdht_client.h"
void usage(const char *program)
{
printf("Usage: %s <config_file> [namespace:][object id] " \
"<key list split by comma>\n" \
"\tkey is * means get all keys of the object\n"
"\tsuch as: %s /etc/fdht/fdht_client.conf " \
"bbs:happyfish name,sex,mail\n", \
program, program);
}
int main(int argc, char *argv[])
{
char *conf_filename;
char *keys_arg;
char *keys_buff;
char *parts2[2];
char **keys;
FDHTKeyValuePair *key_list;
FDHTKeyValuePair *pKeyValuePair;
char sub_keys[FDHT_KEY_LIST_MAX_SIZE];
char object_buff[FDHT_MAX_NAMESPACE_LEN + FDHT_MAX_OBJECT_ID_LEN + 2];
char key_seperator;
int result;
int expires;
int key_count;
int success_count;
int fail_count;
int i;
FDHTObjectInfo object_info;
FDHTKeyInfo key_info;
printf("This is FastDHT client test program v%d.%02d\n" \
"\nCopyright (C) 2008, Happy Fish / YuQing\n" \
"\nFastDHT may be copied only under the terms of the GNU General\n" \
"Public License V3, which may be found in the FastDHT source kit.\n" \
"Please visit the FastDHT Home Page http://www.csource.org/ \n" \
"for more detail.\n\n" \
, g_fdht_version.major, g_fdht_version.minor);
if (argc < 3)
{
usage(argv[0]);
return EINVAL;
}
conf_filename = argv[1];
memset(&object_info, 0, sizeof(FDHTObjectInfo));
if (argc == 3)
{
keys_arg = argv[2];
}
else
{
keys_arg = argv[3];
snprintf(object_buff, sizeof(object_buff), "%s", argv[2]);
if (splitEx(object_buff, ':', parts2, 2) != 2)
{
usage(argv[0]);
return EINVAL;
}
object_info.namespace_len = strlen(parts2[0]);
object_info.obj_id_len = strlen(parts2[1]);
if (object_info.namespace_len == 0)
{
printf("invalid empty namespace!\n");
return EINVAL;
}
if (object_info.namespace_len > FDHT_MAX_NAMESPACE_LEN)
{
printf("namespace: %s is too long, exceed %d!\n", \
parts2[0], FDHT_MAX_NAMESPACE_LEN);
return EINVAL;
}
if (object_info.obj_id_len == 0)
{
printf("invalid empty object Id!\n");
return EINVAL;
}
if (object_info.obj_id_len > FDHT_MAX_OBJECT_ID_LEN)
{
printf("object id: %s is too long, exceed %d!\n", \
parts2[1], FDHT_MAX_OBJECT_ID_LEN);
return EINVAL;
}
memcpy(object_info.szNameSpace, parts2[0], \
object_info.namespace_len);
memcpy(object_info.szObjectId, parts2[1], \
object_info.obj_id_len);
}
if (*keys_arg == '\0')
{
printf("invalid empty keys!\n");
return EINVAL;
}
log_init();
g_log_context.log_level = LOG_DEBUG;
if ((result=fdht_client_init(conf_filename)) != 0)
{
return result;
}
log_set_cache(false);
if (strcmp(keys_arg, "*") == 0)
{
if (object_info.namespace_len == 0)
{
printf("use must specify namespace and object Id!\n");
return EINVAL;
}
result = fdht_get_sub_keys(&object_info, sub_keys, \
sizeof(sub_keys));
if (result != 0)
{
printf("get sub key of %s:%s fail, " \
"errno: %d, error info: %s\n", \
object_info.szNameSpace, \
object_info.szObjectId, \
result, STRERROR(result));
return result;
}
keys_arg = sub_keys;
key_seperator = FDHT_FULL_KEY_SEPERATOR;
}
else
{
key_seperator = ',';
}
keys_buff = strdup(keys_arg);
if (keys_buff == NULL)
{
printf("strdup %d bytes fail!\n", (int)strlen(keys_arg));
return ENOMEM;
}
expires = FDHT_EXPIRES_NEVER;
memset(&key_info, 0, sizeof(key_info));
keys = split(keys_buff, key_seperator, 0, &key_count);
key_list = (FDHTKeyValuePair *)malloc(sizeof(FDHTKeyValuePair) \
* key_count);
if (key_list == NULL)
{
printf("malloc %d bytes fail!\n", \
(int)sizeof(FDHTKeyValuePair) * key_count);
return ENOMEM;
}
memset(key_list, 0, sizeof(FDHTKeyValuePair) * key_count);
success_count = 0;
fail_count = 0;
pKeyValuePair = key_list;
for (i=0; i<key_count; i++)
{
pKeyValuePair->key_len = snprintf(pKeyValuePair->szKey, \
sizeof(pKeyValuePair->szKey), "%s", keys[i]);
if (object_info.namespace_len == 0)
{
key_info.key_len = snprintf(key_info.szKey, \
sizeof(key_info.szKey), "%s", keys[i]);
if ((pKeyValuePair->status=fdht_get(&key_info, \
&pKeyValuePair->pValue, \
&pKeyValuePair->value_len)) != 0)
{
fail_count++;
}
else
{
success_count++;
}
}
pKeyValuePair++;
}
if (object_info.namespace_len > 0)
{
result = fdht_batch_get(&object_info, key_list, \
pKeyValuePair - key_list, &success_count);
if (result != 0)
{
fail_count = pKeyValuePair - key_list;
printf("get all keys fail, " \
"error code: %d, error info: %s\n", \
result, STRERROR(result));
fdht_client_destroy();
return result;
}
else
{
fail_count = (pKeyValuePair - key_list) - success_count;
}
}
if (fail_count > 0)
{
pKeyValuePair = key_list;
for (i=0; i<key_count; i++)
{
if (pKeyValuePair->status == 0)
{
pKeyValuePair++;
continue;
}
printf("get key: %s fail, " \
"error code: %d, error info: %s\n", \
pKeyValuePair->szKey, pKeyValuePair->status, \
STRERROR(pKeyValuePair->status));
pKeyValuePair++;
}
printf("\n");
}
if (success_count > 0)
{
pKeyValuePair = key_list;
for (i=0; i<key_count; i++)
{
if (pKeyValuePair->status != 0)
{
pKeyValuePair++;
continue;
}
printf("%s=%s\n", pKeyValuePair->szKey, \
pKeyValuePair->pValue);
pKeyValuePair++;
}
}
printf("\n");
printf("success get key count: %d, fail count: %d\n", \
success_count, fail_count);
free(keys_buff);
free(key_list);
freeSplit(keys);
pKeyValuePair = key_list;
for (i=0; i<key_count; i++)
{
if (pKeyValuePair->pValue != NULL)
{
free(pKeyValuePair->pValue);
}
pKeyValuePair++;
}
fdht_client_destroy();
return result;
}
/**
* 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 <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include "fdht_global.h"
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
#include "fdht_types.h"
#include "fdht_proto.h"
#include "fdht_func.h"
#include "fdht_client.h"
void usage(const char *program)
{
printf("Usage: %s <config_file> [namespace:][object id] " \
"<key value pairs, split by comma>\n" \
"\tsuch as: %s /etc/fdht/fdht_client.conf " \
"bbs:happyfish name=yq,sex=M,mail=xxx@domain.com\n", \
program, program);
}
int main(int argc, char *argv[])
{
char *conf_filename;
char *kv_arg;
char *kv_buff;
char *parts2[2];
char **kv_pairs;
char **key_value;
FDHTKeyValuePair *key_list;
FDHTKeyValuePair *pKeyValuePair;
char object_buff[FDHT_MAX_NAMESPACE_LEN + FDHT_MAX_OBJECT_ID_LEN + 2];
int result;
int expires;
int kv_len;
int key_count;
int success_count;
int fail_count;
int count;
int i;
FDHTObjectInfo object_info;
FDHTKeyInfo key_info;
printf("This is FastDHT client test program v%d.%02d\n" \
"\nCopyright (C) 2008, Happy Fish / YuQing\n" \
"\nFastDHT may be copied only under the terms of the GNU General\n" \
"Public License V3, which may be found in the FastDHT source kit.\n" \
"Please visit the FastDHT Home Page http://www.csource.org/ \n" \
"for more detail.\n\n" \
, g_fdht_version.major, g_fdht_version.minor);
if (argc < 3)
{
usage(argv[0]);
return EINVAL;
}
conf_filename = argv[1];
memset(&object_info, 0, sizeof(FDHTObjectInfo));
if (argc == 3)
{
kv_arg = argv[2];
}
else
{
kv_arg = argv[3];
snprintf(object_buff, sizeof(object_buff), "%s", argv[2]);
if (splitEx(object_buff, ':', parts2, 2) != 2)
{
usage(argv[0]);
return EINVAL;
}
object_info.namespace_len = strlen(parts2[0]);
object_info.obj_id_len = strlen(parts2[1]);
if (object_info.namespace_len == 0)
{
printf("invalid empty namespace!\n");
return EINVAL;
}
if (object_info.namespace_len > FDHT_MAX_NAMESPACE_LEN)
{
printf("namespace: %s is too long, exceed %d!\n", \
parts2[0], FDHT_MAX_NAMESPACE_LEN);
return EINVAL;
}
if (object_info.obj_id_len == 0)
{
printf("invalid empty object Id!\n");
return EINVAL;
}
if (object_info.obj_id_len > FDHT_MAX_OBJECT_ID_LEN)
{
printf("object id: %s is too long, exceed %d!\n", \
parts2[1], FDHT_MAX_OBJECT_ID_LEN);
return EINVAL;
}
memcpy(object_info.szNameSpace, parts2[0], \
object_info.namespace_len);
memcpy(object_info.szObjectId, parts2[1], \
object_info.obj_id_len);
}
kv_len = strlen(kv_arg);
if (kv_len == 0)
{
printf("invalid empty key value pair!\n");
return EINVAL;
}
kv_buff = strdup(kv_arg);
if (kv_buff == NULL)
{
printf("strdup %d bytes fail!\n", (int)strlen(kv_arg));
return ENOMEM;
}
log_init();
g_log_context.log_level = LOG_DEBUG;
if ((result=fdht_client_init(conf_filename)) != 0)
{
return result;
}
log_set_cache(false);
expires = FDHT_EXPIRES_NEVER;
memset(&key_info, 0, sizeof(key_info));
kv_pairs = split(kv_buff, ',', 0, &key_count);
if (object_info.namespace_len > 0)
{
key_list = (FDHTKeyValuePair *)malloc(sizeof(FDHTKeyValuePair) \
* key_count);
if (key_list == NULL)
{
printf("malloc %d bytes fail!\n", \
(int)sizeof(FDHTKeyValuePair) * key_count);
return ENOMEM;
}
memset(key_list, 0, sizeof(FDHTKeyValuePair) * key_count);
}
else
{
key_list = NULL;
}
success_count = 0;
fail_count = 0;
pKeyValuePair = key_list;
for (i=0; i<key_count; i++)
{
key_value = split(kv_pairs[i], '=', 0, &count);
if (count != 2)
{
freeSplit(key_value);
fail_count++;
printf("invalid key value pair: %s\n", kv_pairs[i]);
continue;
}
if (object_info.namespace_len > 0)
{
pKeyValuePair->key_len = snprintf(pKeyValuePair->szKey, \
sizeof(pKeyValuePair->szKey), "%s", key_value[0]);
pKeyValuePair->value_len = strlen(key_value[1]);
pKeyValuePair->pValue = key_value[1];
pKeyValuePair++;
}
else
{
key_info.key_len = snprintf(key_info.szKey, \
sizeof(key_info.szKey), "%s", key_value[0]);
if ((result=fdht_set(&key_info, expires, key_value[1], \
strlen(key_value[1]))) != 0)
{
printf("set key value pair: %s=%s fail, " \
"error code: %d\n", key_value[0], \
key_value[1], result);
fail_count++;
}
else
{
success_count++;
}
}
freeSplit(key_value);
}
if (object_info.namespace_len > 0)
{
result = fdht_batch_set(&object_info, key_list, \
pKeyValuePair - key_list, expires, &success_count);
if (result != 0)
{
fail_count = pKeyValuePair - key_list;
printf("set keys fail, error code: %d\n", result);
}
else
{
fail_count = (pKeyValuePair - key_list) - success_count;
}
}
free(kv_buff);
if (key_list != NULL)
{
free(key_list);
}
freeSplit(kv_pairs);
printf("success set key count: %d, fail count: %d\n", \
success_count, fail_count);
fdht_client_destroy();
return result;
}
/**
* 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 <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include "fdht_global.h"
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
#include "fdht_types.h"
#include "fdht_proto.h"
#include "fdht_client.h"
#include "fdht_func.h"
int main(int argc, char *argv[])
{
char *conf_filename;
int result;
int expires;
FDHTKeyInfo key_info;
FDHTObjectInfo object_info;
char szValue[256];
char sub_keys[16 * 1024];
int value_len;
int i;
char stat_buff[1024];
printf("This is FastDHT client test program v%d.%02d\n" \
"\nCopyright (C) 2008, Happy Fish / YuQing\n" \
"\nFastDHT may be copied only under the terms of the GNU General\n" \
"Public License V3, which may be found in the FastDHT source kit.\n" \
"Please visit the FastDHT Home Page http://www.csource.org/ \n" \
"for more detail.\n\n" \
, g_fdht_version.major, g_fdht_version.minor);
if (argc < 2)
{
printf("Usage: %s <config_file>\n", argv[0]);
return 1;
}
log_init();
conf_filename = argv[1];
g_log_context.log_level = LOG_DEBUG;
if ((result=fdht_client_init(conf_filename)) != 0)
{
return result;
}
srand(time(NULL));
//expires = time(NULL) + 3600;
expires = FDHT_EXPIRES_NEVER;
memset(&key_info, 0, sizeof(key_info));
key_info.namespace_len = sprintf(key_info.szNameSpace, "user");
key_info.obj_id_len = sprintf(key_info.szObjectId, "happy_fish");
key_info.key_len = sprintf(key_info.szKey, "reg");
memset(&object_info, 0, sizeof(object_info));
object_info.namespace_len = key_info.namespace_len;
object_info.obj_id_len = key_info.obj_id_len;
memcpy(object_info.szNameSpace, key_info.szNameSpace, \
key_info.namespace_len);
memcpy(object_info.szObjectId, key_info.szObjectId, \
key_info.obj_id_len);
if ((result=fdht_get_sub_keys(&object_info, sub_keys, \
sizeof(sub_keys))) != 0)
{
printf("fdht_get_sub_keys fail, errno: %d, error info: %s\n", \
result, STRERROR(result));
}
else
{
printf("sub keys: %s\n", sub_keys);
}
//key_info.obj_id_len = sprintf(key_info.szObjectId, "o%d", 1234567);
//key_info.key_len = sprintf(key_info.szKey, "k%d", 97865432);
while (1)
{
char *value;
//memset(szValue, '1', sizeof(szValue));
value_len = sprintf(szValue, "%d", rand());
printf("original value=%s(%d)\n", szValue, value_len);
if ((result=fdht_set(&key_info, expires, szValue, value_len)) != 0)
{
break;
}
value_len = sizeof(szValue);
if ((result=fdht_inc(&key_info, expires, 100, \
szValue, &value_len)) != 0)
{
break;
}
printf("value_len: %d\n", value_len);
printf("value: %s\n", szValue);
value = szValue;
value_len = sizeof(szValue);
if ((result=fdht_get_ex(&key_info, expires, &value, &value_len)) != 0)
{
printf("fdht_get_ex result=%d\n", result);
break;
}
printf("value_len: %d\n", value_len);
printf("value: %s\n", value);
/*
if ((result=fdht_delete(&key_info)) != 0)
{
break;
}
*/
break;
}
printf("\n");
for (i=0; i<g_group_array.server_count; i++)
{
if ((result=fdht_stat(i, stat_buff, sizeof(stat_buff))) != 0)
{
printf("fdht_stat server %s:%d fail, errno: %d\n",
g_group_array.servers[i].ip_addr,
g_group_array.servers[i].port, result);
}
else
{
printf("server %s:%d\n", g_group_array.servers[i].ip_addr, \
g_group_array.servers[i].port);
printf("%s\n", stat_buff);
}
}
if ((result=fdht_get_sub_keys(&object_info, sub_keys, \
sizeof(sub_keys))) != 0)
{
printf("fdht_get_sub_keys fail, errno: %d, error info: %s\n", \
result, STRERROR(result));
}
else
{
printf("sub keys: %s\n", sub_keys);
}
if (g_keep_alive)
{
fdht_disconnect_all_servers(&g_group_array);
}
fdht_client_destroy();
return result;
}
/**
* 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 <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include "fdht_global.h"
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
#include "fdht_types.h"
#include "fdht_proto.h"
#include "fdht_func.h"
#include "fdht_client.h"
int main(int argc, char *argv[])
{
char *conf_filename;
int result;
int success_count;
int fail_count;
int expires;
FDHTKeyInfo key_info;
char szValue[101];
char *pValue;
int value_len;
struct sigaction act;
int i;
printf("This is FastDHT client test program v%d.%02d\n" \
"\nCopyright (C) 2008, Happy Fish / YuQing\n" \
"\nFastDHT may be copied only under the terms of the GNU General\n" \
"Public License V3, which may be found in the FastDHT source kit.\n" \
"Please visit the FastDHT Home Page http://www.csource.org/ \n" \
"for more detail.\n\n" \
, g_fdht_version.major, g_fdht_version.minor);
if (argc < 2)
{
printf("Usage: %s <config_file>\n", argv[0]);
return 1;
}
log_init();
conf_filename = argv[1];
g_log_context.log_level = LOG_DEBUG;
if ((result=fdht_client_init(conf_filename)) != 0)
{
return result;
}
log_set_prefix(g_fdht_base_path, "fdht_test_get");
log_set_cache(false);
memset(&act, 0, sizeof(act));
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_IGN;
if(sigaction(SIGPIPE, &act, NULL) < 0)
{
logError("file: "__FILE__", line: %d, " \
"call sigaction fail, errno: %d, error info: %s", \
__LINE__, errno, STRERROR(errno));
return errno;
}
srand(time(NULL));
expires = 0;
memset(&key_info, 0, sizeof(key_info));
value_len = sizeof(szValue) - 1;
for (i=0; i<value_len; i++)
{
szValue[i] = (char)rand();
}
g_keep_alive = true;
if (g_keep_alive)
{
if ((result=fdht_connect_all_servers(&g_group_array, true, \
&success_count, &fail_count)) != 0)
{
printf("fdht_connect_all_servers fail, " \
"error code: %d, error info: %s\n", \
result, STRERROR(result));
return result;
}
}
key_info.key_len = sprintf(key_info.szKey, "k%015d", rand());
if ((result=fdht_set(&key_info, expires, szValue, value_len)) != 0)
{
return result;
}
pValue = szValue;
success_count = 0;
fail_count = 0;
for (i=1; i<=100000; i++)
{
if (i % 10000 == 0)
{
printf("current: %d\n", i);
fflush(stdout);
}
value_len = sizeof(szValue);
if ((result=fdht_get(&key_info, &pValue, &value_len)) != 0)
{
logError("fdht_get return %d", result);
fail_count++;
}
else
{
success_count++;
}
}
if (g_keep_alive)
{
fdht_disconnect_all_servers(&g_group_array);
}
fdht_client_destroy();
printf("success count=%d, fail count=%d\n", success_count, fail_count);
return result;
}
/**
* 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 <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include "fdht_global.h"
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
#include "fdht_types.h"
#include "fdht_proto.h"
#include "fdht_func.h"
#include "fdht_client.h"
int main(int argc, char *argv[])
{
char *conf_filename;
int result;
int success_count;
int fail_count;
int expires;
FDHTKeyInfo key_info;
char szValue[100];
int value_len;
struct sigaction act;
int i;
printf("This is FastDHT client test program v%d.%02d\n" \
"\nCopyright (C) 2008, Happy Fish / YuQing\n" \
"\nFastDHT may be copied only under the terms of the GNU General\n" \
"Public License V3, which may be found in the FastDHT source kit.\n" \
"Please visit the FastDHT Home Page http://www.csource.org/ \n" \
"for more detail.\n\n" \
, g_fdht_version.major, g_fdht_version.minor);
if (argc < 2)
{
printf("Usage: %s <config_file>\n", argv[0]);
return 1;
}
log_init();
conf_filename = argv[1];
g_log_context.log_level = LOG_DEBUG;
if ((result=fdht_client_init(conf_filename)) != 0)
{
return result;
}
log_set_prefix(g_fdht_base_path, "fdht_test_set");
log_set_cache(false);
memset(&act, 0, sizeof(act));
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_IGN;
if(sigaction(SIGPIPE, &act, NULL) < 0)
{
logError("file: "__FILE__", line: %d, " \
"call sigaction fail, errno: %d, error info: %s", \
__LINE__, errno, STRERROR(errno));
return errno;
}
srand(time(NULL));
expires = time(NULL) + 5 * 86400;
memset(&key_info, 0, sizeof(key_info));
value_len = sizeof(szValue);
for (i=0; i<value_len; i++)
{
szValue[i] = (char)rand();
}
g_keep_alive = true;
if (g_keep_alive)
{
if ((result=fdht_connect_all_servers(&g_group_array, true, \
&success_count, &fail_count)) != 0)
{
printf("fdht_connect_all_servers fail, " \
"error code: %d, error info: %s\n", \
result, STRERROR(result));
return result;
}
}
printf("g_keep_alive=%d\n", g_keep_alive);
success_count = 0;
fail_count = 0;
for (i=1; i<=100000; i++)
{
if (i % 10000 == 0)
{
printf("current: %d\n", i);
fflush(stdout);
}
key_info.key_len = sprintf(key_info.szKey, "k%d", rand());
if ((result=fdht_set(&key_info, expires, szValue, value_len)) != 0)
{
printf("%d. result=%d\n", i, result);
fail_count++;
}
else
{
success_count++;
}
}
if (g_keep_alive)
{
fdht_disconnect_all_servers(&g_group_array);
}
fdht_client_destroy();
printf("success count=%d, fail count=%d\n", success_count, fail_count);
return result;
}
/**
* 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 <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include "fdht_global.h"
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
#include "fdht_types.h"
#include "fdht_proto.h"
#include "fdht_client.h"
#include "fdht_func.h"
int main(int argc, char *argv[])
{
char *conf_filename;
int result;
int expires;
FDHTKeyInfo key_info;
int conn_success_count;
int conn_fail_count;
char szValue[256];
int value_len;
GroupArray group_array;
bool bKeepAlive;
printf("This is FastDHT client test program v%d.%d\n" \
"\nCopyright (C) 2008, Happy Fish / YuQing\n" \
"\nFastDHT may be copied only under the terms of the GNU General\n" \
"Public License V3, which may be found in the FastDHT source kit.\n" \
"Please visit the FastDHT Home Page http://www.csource.org/ \n" \
"for more detail.\n\n" \
, g_fdht_version.major, g_fdht_version.minor);
if (argc < 2)
{
printf("Usage: %s <config_file>\n", argv[0]);
return 1;
}
log_init();
conf_filename = argv[1];
g_log_context.log_level = LOG_DEBUG;
if ((result=fdht_client_init(conf_filename)) != 0)
{
return result;
}
if ((result=fdht_copy_group_array(&group_array, &g_group_array)) != 0)
{
return result;
}
bKeepAlive = true;
if (bKeepAlive)
{
if ((result=fdht_connect_all_servers(&group_array, true, \
&conn_success_count, &conn_fail_count)) != 0)
{
printf("fdht_connect_all_servers fail, " \
"error code: %d, error info: %s\n", \
result, STRERROR(result));
}
}
srand(time(NULL));
expires = time(NULL) + 3600;
memset(&key_info, 0, sizeof(key_info));
key_info.namespace_len = sprintf(key_info.szNameSpace, "bbs");
key_info.obj_id_len = sprintf(key_info.szObjectId, "o%d", rand());
key_info.key_len = sprintf(key_info.szKey, "k%d", rand());
/*
key_info.obj_id_len = sprintf(key_info.szObjectId, "o%d", 12345678);
key_info.key_len = sprintf(key_info.szKey, "k%d", 978654);
*/
while (1)
{
char *value;
//memset(szValue, '1', sizeof(szValue));
value_len = sprintf(szValue, "%d", rand());
printf("original value=%s(%d)\n", szValue, value_len);
if ((result=fdht_set_ex(&group_array, bKeepAlive, &key_info, \
expires, szValue, value_len)) != 0)
{
break;
}
value_len = sizeof(szValue);
if ((result=fdht_inc_ex(&group_array, bKeepAlive, &key_info, \
expires, 100, szValue, &value_len)) != 0)
{
break;
}
printf("value_len: %d\n", value_len);
printf("value: %s\n", szValue);
value = szValue;
value_len = sizeof(szValue);
if ((result=fdht_get_ex1(&group_array, bKeepAlive, &key_info, \
expires, &value, &value_len, malloc)) != 0)
{
printf("result=%d\n", result);
break;
}
printf("value_len: %d\n", value_len);
printf("value: %s\n", value);
if ((result=fdht_delete_ex(&group_array, bKeepAlive, \
&key_info)) != 0)
{
break;
}
break;
}
if (bKeepAlive)
{
fdht_disconnect_all_servers(&group_array);
}
fdht_free_group_array(&group_array);
fdht_client_destroy();
return result;
}
#ifndef _OS_BITS_H
#define _OS_BITS_H
#define OS_BITS 32
#endif
#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);
}
*/
#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
This diff is collapsed.
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment