caopei11 2 år sedan
förälder
incheckning
b75e808089
100 ändrade filer med 22581 tillägg och 0 borttagningar
  1. 43 0
      src/core/Makefile
  2. 21 0
      src/daemons/Makefile
  3. 89 0
      src/daemons/base.cc
  4. 41 0
      src/daemons/base.h
  5. 118 0
      src/daemons/daemon_listener.cc
  6. 55 0
      src/daemons/daemon_listener.h
  7. 125 0
      src/daemons/daemons.cc
  8. 53 0
      src/daemons/daemons.h
  9. 104 0
      src/daemons/fault.cc
  10. 32 0
      src/daemons/fault.h
  11. 75 0
      src/daemons/fork.cc
  12. 202 0
      src/daemons/gdb.cc
  13. 21 0
      src/daemons/gdb.h
  14. 67 0
      src/daemons/gdb_srv.cc
  15. 110 0
      src/daemons/helper.cc
  16. 39 0
      src/daemons/helper.h
  17. 120 0
      src/daemons/logger.cc
  18. 19 0
      src/daemons/logger.h
  19. 99 0
      src/daemons/main.cc
  20. 41 0
      src/daemons/main.h
  21. 100 0
      src/daemons/run.cc
  22. 46 0
      src/daemons/stattool.cc
  23. 32 0
      src/daemons/stattool.h
  24. 174 0
      src/daemons/unit.cc
  25. 76 0
      src/daemons/unit.h
  26. 5 0
      src/devel/Makefile
  27. 43 0
      src/devel/cpp/Makefile
  28. 100 0
      src/devel/cpp/container_api.cc
  29. 1076 0
      src/devel/cpp/dtcapi.h
  30. 12 0
      src/devel/cpp/dtcapi.lst
  31. 592 0
      src/devel/cpp/dtcint.h
  32. 1009 0
      src/devel/cpp/dtcpool.cc
  33. 275 0
      src/devel/cpp/dtcpool.h
  34. 734 0
      src/devel/cpp/dtcqossvr.cc
  35. 111 0
      src/devel/cpp/dtcqossvr.h
  36. 1040 0
      src/devel/cpp/dtcreq.cc
  37. 1296 0
      src/devel/cpp/dtcsvr.cc
  38. 1381 0
      src/devel/cpp/dtcwrap.cc
  39. 231 0
      src/devel/cpp/dtcwrapp.cc
  40. 34 0
      src/devel/cpp/example/deletetest.cpp
  41. 77 0
      src/devel/cpp/example/inserttest.cpp
  42. 91 0
      src/devel/cpp/example/selecttest.cpp
  43. 889 0
      src/devel/cpp/example/ttcapi.h
  44. 84 0
      src/devel/cpp/example/updatetest.cpp
  45. 32 0
      src/devel/cpp/examples/cache.conf
  46. 39 0
      src/devel/cpp/examples/delete/Makefile
  47. 34 0
      src/devel/cpp/examples/delete/deletetest.cpp
  48. 1020 0
      src/devel/cpp/examples/delete/dtcapi.h
  49. 38 0
      src/devel/cpp/examples/insert/Makefile
  50. 1020 0
      src/devel/cpp/examples/insert/dtcapi.h
  51. 163 0
      src/devel/cpp/examples/insert/inserttest.cpp
  52. 47 0
      src/devel/cpp/examples/select/Makefile
  53. 118 0
      src/devel/cpp/examples/select/TestServerPool.cpp
  54. 1020 0
      src/devel/cpp/examples/select/dtcapi.h
  55. 91 0
      src/devel/cpp/examples/select/selecttest.cpp
  56. 46 0
      src/devel/cpp/examples/table.conf
  57. 38 0
      src/devel/cpp/examples/update/Makefile
  58. 1019 0
      src/devel/cpp/examples/update/dtcapi.h
  59. 84 0
      src/devel/cpp/examples/update/updatetest.cpp
  60. 149 0
      src/devel/cpp/key_list.cc
  61. 90 0
      src/devel/cpp/key_list.h
  62. 11 0
      src/devel/cpp/log_client.cc
  63. 3 0
      src/devel/cpp/readme.txt
  64. 34 0
      src/devel/cpp/somain.c
  65. 201 0
      src/devel/cpp/udppool.cc
  66. 65 0
      src/devel/cpp/udppool.h
  67. 5 0
      src/libs/Makefile
  68. 750 0
      src/libs/cJSON/cJSON.c
  69. 150 0
      src/libs/cJSON/cJSON.h
  70. 96 0
      src/libs/common/Condition.h
  71. 44 0
      src/libs/common/Makefile
  72. 354 0
      src/libs/common/agent/agent_client.cc
  73. 95 0
      src/libs/common/agent/agent_client.h
  74. 192 0
      src/libs/common/agent/agent_listen_pool.cc
  75. 50 0
      src/libs/common/agent/agent_listen_pool.h
  76. 86 0
      src/libs/common/agent/agent_listener.cc
  77. 40 0
      src/libs/common/agent/agent_listener.h
  78. 161 0
      src/libs/common/agent/agent_multi_request.cc
  79. 74 0
      src/libs/common/agent/agent_multi_request.h
  80. 279 0
      src/libs/common/agent/agent_receiver.cc
  81. 59 0
      src/libs/common/agent/agent_receiver.h
  82. 163 0
      src/libs/common/agent/agent_sender.cc
  83. 69 0
      src/libs/common/agent/agent_sender.h
  84. 58 0
      src/libs/common/agent/agent_unit.cc
  85. 47 0
      src/libs/common/agent/agent_unit.h
  86. 45 0
      src/libs/common/algorithm/bitsop.cc
  87. 98 0
      src/libs/common/algorithm/bitsop.h
  88. 107 0
      src/libs/common/algorithm/chash.cc
  89. 25 0
      src/libs/common/algorithm/chash.h
  90. 94 0
      src/libs/common/algorithm/compress.cc
  91. 54 0
      src/libs/common/algorithm/compress.h
  92. 1908 0
      src/libs/common/algorithm/markup_stl.cc
  93. 384 0
      src/libs/common/algorithm/markup_stl.h
  94. 354 0
      src/libs/common/algorithm/md5.cc
  95. 54 0
      src/libs/common/algorithm/md5.h
  96. 107 0
      src/libs/common/algorithm/new_hash.cc
  97. 23 0
      src/libs/common/algorithm/new_hash.h
  98. 39 0
      src/libs/common/algorithm/non_copyable.h
  99. 74 0
      src/libs/common/algorithm/relative_hour_calculator.h
  100. 99 0
      src/libs/common/algorithm/singleton.h

+ 43 - 0
src/core/Makefile

@@ -0,0 +1,43 @@
+include ../Make.conf
+
+SRC_FOLDER := $(shell find . -maxdepth 1 -type d)
+VPATH :=../libs/stat $(basename $(patsubst ./%, %/, $(SRC_FOLDER)))
+
+####################compile#################
+CFLAGS += -D_GLIBCXX_USE_CXX11_ABI=0 -std=gnu++11
+CFLAGS += -I./ -I../libs/common -I../devel/cpp -I../libs/stat -I../daemons -I../connector $(LOG4CPLUS_INC)  $(YAML_CPP_INC)
+CFLAGS += $(basename $(patsubst ./%, -I%, $(SRC_FOLDER)))
+
+LIBPATH := -L. -L../libs/common -L../daemons -L../libs/stat -L../devel $(LOG4CPLUS_LIB) $(YAML_CPP_LIB)
+DB%.o tmp.DB%.o:CFLAGS += $(MYSQLINC)
+ifneq ($(findstring x86_64,$(PLATFORM)),)
+BITS=64
+else
+BITS=32
+endif
+
+LIBDTCAPI := -L../devel  -lpthread -Wl,-rpath,\$$ORIGIN/../lib/ -Wl,-rpath,\$$ORIGIN  -Wl,-rpath,\$$ORIGIN/../devel/  -Wl,-rpath,\$$ORIGIN/../ -z origin
+
+target = libdtcd.a dtcd
+target_external = ../devel/cpp/libdtc.a ../libs/stat/libstat.a ../libs/common/libcommon.a 
+
+$(filterout libdtcd.a,$(target)): libdtcd.a;
+
+filelist := feature hash ng_info node_set node_index barrier_ask_answer_chain buffer_bypass_answer_chain buffer_bypass_ask_chain buffer_pond\
+		pt_malloc sys_malloc raw_data raw_data_process buffer_process_answer_chain buffer_process_ask_chain buffer_flush\
+		job_procedure empty_filter black_hole_ask_chain logger task_pendlist lru_bit hb_log\
+		hb_feature container_dtcd col_expand t_tree tree_data\
+		tree_data_process expire_time main_supply main hot_backup_ask_chain system_command_ask_chain 
+libdtcd_objs:= $(sort $(filelist:%=%.o))
+
+#dtcd
+dtcd: CFLAGS += -export-dynamic
+dtcd: LDFLAGS += -Wl,--version-script,dtcd.export.lst
+dtcd_objs:= main.o system_command_ask_chain.o stat_client.o expire_time.o hot_backup_ask_chain.o 
+dtcd_libs:= -lstat -ldaemons  -ldtcd -lcommon -lpthread -ldl $(Z_LIB) -rdynamic
+
+#####################install############
+target_install = dtcd
+install_dir = ../../bin
+
+include ../Make.rules

+ 21 - 0
src/daemons/Makefile

@@ -0,0 +1,21 @@
+include ../Make.conf
+
+target = libdaemons.a faultlogger
+
+CFLAGS+=-I../libs/common -I../libs/stat -std=gnu++11 -fPIC $(LOG4CPLUS_INC)  $(YAML_CPP_INC)
+VPATH := ../libs/stat
+filelist := daemons base fork helper daemon_listener main run stattool unit logger fault gdb gdb_srv stat_alarm_reporter
+libdaemons_objs := $(filelist:%=%.o) $(LOG4CPLUS_LIB) $(YAML_CPP_LIB) 
+
+faultlogger: LDFLAGS += -shared -e _so_start
+
+faultlogger_objs = fault.pic.o
+
+fault.pic.o fault.o: CFLAGS += -O0
+
+target_install = faultlogger
+
+install_dir = ../../bin
+
+include ../Make.rules
+

+ 89 - 0
src/daemons/base.cc

@@ -0,0 +1,89 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <fcntl.h>
+#include <errno.h>
+
+#include "base.h"
+#include "log/log.h"
+
+WatchDogDaemon::WatchDogDaemon(WatchDog *watchdog, int sec)
+	: WatchDogObject(watchdog)
+{
+	if (watchdog)
+		timer_list_ = watchdog->get_timer_list(sec);
+}
+
+WatchDogDaemon::~WatchDogDaemon(void)
+{
+}
+
+int WatchDogDaemon::dtc_fork()
+{
+	/* an error detection pipe */
+	// int err, fd[2];
+	// fd[0] = 0;
+	// fd[1] = 0;
+	// int unused = 0;
+	int err, fd[2];
+	int unused;
+
+	unused = pipe(fd);
+	/* fork child process */
+	watchdog_object_pid_ = fork();
+	if (watchdog_object_pid_ == -1)
+		return watchdog_object_pid_;
+	if (watchdog_object_pid_ == 0) {
+		/* close pipe if exec succ */
+		close(fd[0]);
+		fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+		exec();
+		err = errno;
+		log4cplus_error("%s: exec(): %m", watchdog_object_name_);
+		unused = write(fd[1], &err, sizeof(err));
+		exit(-1);
+	}
+	close(fd[1]);
+	if (read(fd[0], &err, sizeof(err)) == sizeof(err)) {
+		errno = err;
+		return -1;
+	}
+	close(fd[0]);
+	attach_watch_dog();
+	return watchdog_object_pid_;
+}
+
+void WatchDogDaemon::job_timer_procedure()
+{
+	log4cplus_debug("enter timer procedure");
+	if (dtc_fork() < 0)
+		if (timer_list_)
+			attach_timer(timer_list_);
+	log4cplus_debug("leave timer procedure");
+}
+
+void WatchDogDaemon::killed_notify(int signo, int coredumped)
+{
+	if (timer_list_)
+		attach_timer(timer_list_);
+	report_kill_alarm(signo, coredumped);
+}
+
+void WatchDogDaemon::exited_notify(int retval)
+{
+	if (timer_list_)
+		attach_timer(timer_list_);
+}

+ 41 - 0
src/daemons/base.h

@@ -0,0 +1,41 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#ifndef __H_WATCHDOG_DAEMON_H__
+#define __H_WATCHDOG_DAEMON_H__
+
+#include "daemons.h"
+
+class WatchDogDaemon : public WatchDogObject,
+					   private TimerObject
+{
+private:
+	TimerList *timer_list_;
+
+private:
+	virtual void killed_notify(int signo, int coredumped);
+	virtual void exited_notify(int retval);
+	virtual void job_timer_procedure();
+
+public:
+	WatchDogDaemon(WatchDog *watchdog, int sec);
+	~WatchDogDaemon();
+
+	virtual int dtc_fork();
+	virtual void exec() = 0;
+};
+
+#endif

+ 118 - 0
src/daemons/daemon_listener.cc

@@ -0,0 +1,118 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "daemon_listener.h"
+#include "helper.h"
+#include "config/dbconfig.h"
+#include "log/log.h"
+
+WatchDogListener::WatchDogListener(WatchDog *watchdog, int sec) : owner_(watchdog), peerfd_(-1), delay_(sec){};
+
+WatchDogListener::~WatchDogListener()
+{
+	if (peerfd_ > 0) {
+		log4cplus_debug("daemons listener fd: %d closed", peerfd_);
+		close(peerfd_);
+	}
+};
+
+/* 建socket */
+int WatchDogListener::attach_watch_dog()
+{
+	int fd[2];
+	socketpair(AF_UNIX, SOCK_DGRAM, 0, fd);
+	netfd = fd[0];
+	peerfd_ = fd[1];
+
+	char buf[30];
+	snprintf(buf, sizeof(buf), "%d", peerfd_);
+	setenv(ENV_WATCHDOG_SOCKET_FD, buf, 1);
+
+	int no;
+	setsockopt(netfd, SOL_SOCKET, SO_PASSCRED, (no = 1, &no), sizeof(int));
+	fcntl(netfd, F_SETFD, FD_CLOEXEC);
+	enable_input();
+	owner_->set_listener(this);
+	return 0;
+}
+
+void WatchDogListener::input_notify()
+{
+	char buf[16];
+	int n;
+	struct msghdr msg = {0};
+	char ucbuf[CMSG_SPACE(sizeof(struct ucred))];
+	struct iovec iov[1];
+
+	iov[0].iov_base = (void *)&buf;
+	iov[0].iov_len = sizeof(buf);
+	msg.msg_control = ucbuf;
+	msg.msg_controllen = sizeof ucbuf;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+	msg.msg_flags = 0;
+
+	while ((n = recvmsg(netfd, &msg, MSG_TRUNC | MSG_DONTWAIT)) > 0) {
+		struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+		struct ucred *uc;
+		if (msg.msg_controllen < sizeof(ucbuf) ||
+			cmsg->cmsg_level != SOL_SOCKET ||
+			cmsg->cmsg_type != SCM_CREDENTIALS ||
+			cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)) ||
+			msg.msg_controllen < cmsg->cmsg_len)
+			continue;
+		uc = (struct ucred *)CMSG_DATA(cmsg);
+		if (n != sizeof(buf))
+			continue;
+
+		log4cplus_debug("new daemons object: %p, %d, %d, %s", owner_, buf[0], uc->pid, buf + 1);
+		WatchDogObject *obj = NULL;
+		if (buf[0] == WATCHDOG_INPUT_OBJECT) {
+			obj = new WatchDogObject(owner_, buf, uc->pid);
+			if (obj == NULL) {
+				log4cplus_error("new WatchDogObject error");
+				return;
+			}
+		} else if (buf[0] == WATCHDOG_INPUT_HELPER) {
+			StartHelperPara *para = (StartHelperPara *)(buf + 1);
+			char path[32];
+			if (!DbConfig::build_path(path, 32, getpid(), para->mach, para->role, para->type)) {
+				log4cplus_error("build helper listen path error");
+				return;
+			}
+			NEW(WatchDogHelper(owner_, delay_, path, para->mach, para->role, para->backlog, para->type, para->conf, para->num), obj);
+			if (obj == NULL) {
+				log4cplus_error("new daemons helper error");
+				return;
+			}
+			WatchDogHelper *helper = (WatchDogHelper *)obj;
+			if (helper->dtc_fork() < 0 || helper->verify() < 0) {
+				log4cplus_error("fork helper error");
+				return;
+			}
+		} else {
+			log4cplus_error("unknown daemons input type: %d, %s", buf[0], buf + 1);
+			return;
+		}
+		obj->attach_watch_dog();
+	}
+}

+ 55 - 0
src/daemons/daemon_listener.h

@@ -0,0 +1,55 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#ifndef __H_WATCHDOG_LISTENER_H__
+#define __H_WATCHDOG_LISTENER_H__
+
+#include "daemons.h"
+
+#define ENV_WATCHDOG_SOCKET_FD "WATCHDOG_SOCKET_FD"
+
+#define WATCHDOG_INPUT_OBJECT 0
+#define WATCHDOG_INPUT_HELPER 1
+
+#define DBHELPER_TABLE_ORIGIN 0
+#define DBHELPER_TABLE_NEW 1
+
+struct StartHelperPara
+{
+	uint8_t type;
+	uint8_t mach;
+	uint8_t role;
+	uint8_t conf;
+	uint16_t num;
+	uint16_t backlog;
+};
+
+class WatchDogListener : public EpollBase
+{
+private:
+	WatchDog *owner_;
+	int peerfd_;
+	int delay_;
+
+public:
+	WatchDogListener(WatchDog *watchdog, int sec);
+	virtual ~WatchDogListener(void);
+	int attach_watch_dog();
+	virtual void input_notify();
+};
+
+extern int watch_dog_fork(const char *name, int (*entry)(void *), void *args);
+#endif

+ 125 - 0
src/daemons/daemons.cc

@@ -0,0 +1,125 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+
+#include "daemons.h"
+#include "daemon/daemon.h"
+#include "log/log.h"
+
+WatchDogPipe::WatchDogPipe()
+{
+	int fd[2];
+	netfd = fd[0];
+	peerfd_ = fd[1];
+	fcntl(netfd, F_SETFL, O_NONBLOCK);
+	fcntl(peerfd_, F_SETFL, O_NONBLOCK);
+	fcntl(netfd, F_SETFD, FD_CLOEXEC);
+	fcntl(peerfd_, F_SETFD, FD_CLOEXEC);
+	enable_input();
+}
+
+WatchDogPipe::~WatchDogPipe()
+{
+	if (peerfd_ >= 0)
+		close(peerfd_);
+}
+
+void WatchDogPipe::input_notify()
+{
+	char buf[100];
+	while (read(netfd, buf, sizeof(buf)) == sizeof(buf))
+		;
+}
+
+void WatchDogPipe::wake()
+{
+	char c = 0;
+	c = write(peerfd_, &c, 1);
+}
+
+static WatchDogPipe *notifier;
+static void sighdlr(int signo) 
+{ 
+	notifier->wake(); 
+}
+
+WatchDog::WatchDog()
+{
+	/* 立马注册进程退出处理函数,解决启动时创建太多进程导致部分进程退出没有收到信号linjinming 2014-06-14*/
+	notifier = new WatchDogPipe;
+	signal(SIGCHLD, sighdlr);
+}
+
+WatchDog::~WatchDog(void)
+{
+}
+
+void WatchDog::run_loop()
+{
+	struct pollfd pfd[2];
+	notifier->init_poll_fd(&pfd[0]);
+
+	if (listener_) {
+		listener_->init_poll_fd(&pfd[1]);
+	} else {
+		pfd[1].fd = -1;
+		pfd[1].events = 0;
+		pfd[1].revents = 0;
+	}
+
+	while (!stop) {
+		int timeout = expire_micro_seconds(3600 * 1000, 1);
+		int interrupted = poll(pfd, 2, timeout);
+		update_now_time(timeout, interrupted);
+		if (stop)
+			break;
+
+		if (pfd[0].revents & POLLIN)
+			notifier->input_notify();
+		if (pfd[1].revents & POLLIN)
+			listener_->input_notify();
+
+		check_watchdog();
+		check_expired();
+		check_ready();
+	}
+	log4cplus_debug("prepare stopping");
+	//kill_allwatchdog();
+	force_kill_allwatchdog();
+	check_watchdog();
+	time_t stoptimer = time(NULL) + 5;
+	int stopretry = 0;
+	while (stopretry < 6 && get_process_count() > 0) {
+		time_t now = time(NULL);
+		if (stoptimer <= now) {
+			stopretry++;
+			stoptimer = now + 5;
+			log4cplus_debug("notify all children again");
+			kill_allwatchdog();
+		}
+		poll(pfd, 1, 1000);
+		if (pfd[0].revents & POLLIN)
+			notifier->input_notify();
+		check_watchdog();
+	}
+	delete notifier;
+	force_kill_allwatchdog();
+	log4cplus_info("all children stopped, daemons ended");
+	exit(0);
+}

+ 53 - 0
src/daemons/daemons.h

@@ -0,0 +1,53 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#ifndef __H_WATCHDOG__H__
+#define __H_WATCHDOG__H__
+
+#include "unit.h"
+#include "poll/poller.h"
+#include "timer/timer_list.h"
+
+class WatchDogPipe : public EpollBase
+{
+private:
+	int peerfd_;
+
+public:
+	WatchDogPipe();
+	virtual ~WatchDogPipe();
+
+public:
+	void wake();
+	virtual void input_notify();
+};
+
+class WatchDog : public WatchDogUnit,
+				 public TimerUnit
+{
+private:
+	EpollBase *listener_;
+
+public:
+	WatchDog();
+	virtual ~WatchDog();
+
+	void set_listener(EpollBase *listener) { listener_ = listener; }
+	void run_loop();
+};
+
+extern int start_watch_dog(int (*entry)(void *), void *);
+#endif

+ 104 - 0
src/daemons/fault.cc

@@ -0,0 +1,104 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <version.h>
+#include <asm/unistd.h>
+
+#include "compiler.h"
+#include "fault.h"
+
+__HIDDEN
+int FaultHandler::dogpid_ = 0;
+
+__HIDDEN
+FaultHandler FaultHandler::instance_;
+
+extern "C"
+	__attribute__((__weak__)) void
+	crash_hook(int signo);
+
+extern "C"
+{
+	__EXPORT volatile int g_crash_continue;
+};
+
+static int g_crash_hook = 0;
+
+__HIDDEN
+void FaultHandler::handler(int signo, siginfo_t *dummy_first, void *dummy_second)
+{
+	signal(signo, SIG_DFL);
+	if (dogpid_ > 1) {
+		sigval tid;
+		tid.sival_int = syscall(__NR_gettid);
+		sigqueue(dogpid_, SIGWINCH, tid);
+		for (int i = 0; i < 50 && !g_crash_continue; i++)
+			usleep(100 * 1000);
+		if ((g_crash_hook != 0) && (&crash_hook != 0))
+			crash_hook(signo);
+	}
+}
+
+__HIDDEN
+FaultHandler::FaultHandler(void)
+{
+	initialize(1);
+}
+
+__HIDDEN
+void FaultHandler::initialize(int protect)
+{
+	char *p = getenv(ENV_FAULT_LOGGER_PID);
+	if (p && (dogpid_ = atoi(p)) > 1) {
+		struct sigaction sa;
+		memset(&sa, 0, sizeof(sa));
+		sa.sa_sigaction = FaultHandler::handler;
+		sa.sa_flags = SA_RESTART | SA_SIGINFO;
+		sigaction(SIGSEGV, &sa, NULL);
+		sigaction(SIGBUS, &sa, NULL);
+		sigaction(SIGILL, &sa, NULL);
+		sigaction(SIGABRT, &sa, NULL);
+		sigaction(SIGFPE, &sa, NULL);
+		if (protect)
+			g_crash_hook = 1;
+	}
+}
+
+#if __pic__ || __PIC__
+extern "C" const char __invoke_dynamic_linker__[]
+	__attribute__((section(".interp")))
+	__HIDDEN =
+#if __x86_64__
+		"/lib64/ld-linux-x86-64.so.2"
+#else
+		"/lib/ld-linux.so.2"
+#endif
+	;
+
+extern "C" __HIDDEN int _so_start(void)
+{
+#define BANNER "DTC FaultLogger v" DTC_VERSION_DETAIL "\n" \
+			   "  - USED BY DTCD INTERNAL ONLY!!!\n"
+	int unused;
+	unused = write(1, BANNER, sizeof(BANNER) - 1);
+	_exit(0);
+}
+#endif

+ 32 - 0
src/daemons/fault.h

@@ -0,0 +1,32 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <signal.h>
+
+#define ENV_FAULT_LOGGER_PID "__FAULT_LOGGER_PID"
+class FaultHandler
+{
+private:
+    static FaultHandler instance_;
+	static int dogpid_;
+
+private:
+	static void handler(int signo, siginfo_t *dummy_first, void *dummy_second);
+	FaultHandler();
+
+public:
+	static void initialize(int protect);
+};

+ 75 - 0
src/daemons/fork.cc

@@ -0,0 +1,75 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <string.h>
+#include <signal.h>
+
+#ifndef CLONE_PARENT
+#define CLONE_PARENT 0x00008000
+#endif
+
+#include "daemon_listener.h"
+#include "log/log.h"
+
+struct ForkInfo
+{
+	char name[16];
+	int fd;
+	int (*entry)(void *);
+	void *args;
+};
+
+static int CloneEntry(void *arg)
+{
+	struct ForkInfo *info = (ForkInfo *)arg;
+	send(info->fd, info->name, sizeof(info->name), 0);
+	exit(info->entry(info->args));
+}
+
+int watch_dog_fork(const char *name, int (*entry)(void *), void *args)
+{
+	/* 4K stack is enough for CloneEntry */
+	char stack[4096]; 
+	struct ForkInfo info;
+	char *env = getenv(ENV_WATCHDOG_SOCKET_FD);
+
+	info.fd = env == NULL ? -1 : atoi(env);
+	log4cplus_debug("daemons fork, fd: %d, name: %s, args: %p", info.fd, name, args);
+	if (info.fd <= 0) {
+		int pid = fork();
+		if (pid == 0) 
+			exit(entry(args));
+		return pid;
+	}
+
+	strncpy(info.name, name, sizeof(info.name));
+	info.entry = entry;
+	info.args = args;
+
+	return clone(
+		/* entry */
+		CloneEntry, 
+		stack + sizeof(stack) - 16,
+		/* flag */
+		CLONE_PARENT | SIGCHLD,
+		/* data */ 
+		&info					
+	);
+};

+ 202 - 0
src/daemons/gdb.cc

@@ -0,0 +1,202 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "gdb.h"
+#include "log/log.h"
+
+#define printf(fmt, args...) log4cplus_bare(2, fmt, ##args)
+
+struct frame_t
+{
+	int index;
+	/* 0 normal, 1 *this, 2 signal */
+	int ftype; 
+};
+
+static void wait_prompt(FILE *outfp)
+{
+	char buf[1024];
+	while (fgets(buf, sizeof(buf) - 1, outfp)) {
+		if (!strncmp(buf, "GDB>", 4))
+			break;
+	}
+}
+
+static void dump_result(FILE *outfp)
+{
+	char buf[1024];
+	while (fgets(buf, sizeof(buf) - 1, outfp)) {
+		if (!strncmp(buf, "GDB>", 4))
+			break;
+		printf("%s", buf);
+	}
+}
+
+static void parse_frame(FILE *outfp, std::vector<frame_t> &frame)
+{
+	char buf[1024];
+	int first = 1;
+	while (fgets(buf, sizeof(buf) - 1, outfp)) {
+		if (!strncmp(buf, "GDB>", 4))
+			break;
+		printf("%s", buf);
+		if (buf[0] == '#') {
+			struct frame_t f;
+			char *p = strstr(buf, "this");
+			f.index = atoi(buf + 1);
+			f.ftype = p && (!isalnum(p[-1] && !isalnum(p[4])));
+			if (first && strstr(buf, "signal handler called") != NULL) {
+				first = 0;
+				frame.clear();
+				f.ftype = 2;
+			}
+			frame.push_back(f);
+		}
+	}
+}
+
+static void dump_info(int pid)
+{
+	char fn[64];
+	char buf[1024];
+	int rv;
+
+	printf("Process/Thread %d Crashed\n", pid);
+	snprintf(fn, sizeof(fn), "/proc/%d/exe", pid);
+	rv = readlink(fn, buf, sizeof(buf) - 1);
+	if (rv > 0) {
+		buf[rv] = 0;
+		printf("Executable: %s\n", buf);
+	}
+
+	snprintf(fn, sizeof(fn), "/proc/%d/cwd", pid);
+	rv = readlink(fn, buf, sizeof(buf) - 1);
+	if (rv > 0) {
+		buf[rv] = 0;
+		printf("Working Directory: %s\n", buf);
+	}
+
+	snprintf(fn, sizeof(fn), "/proc/%d/cmdline", pid);
+	FILE *fp = fopen(fn, "r");
+	if (fp) {
+		if (fgets(buf, sizeof(buf), fp))
+			printf("Command Line: %s\n", buf);
+		fclose(fp);
+	}
+
+	snprintf(fn, sizeof(fn), "/proc/%d/maps", pid);
+	fp = fopen(fn, "r");
+	if (fp) {
+		printf("Dump memory maps:\n");
+		while (fgets(buf, sizeof(buf), fp)) {
+			printf("    %s", buf);
+		}
+		fclose(fp);
+	}
+}
+
+void gdb_dump(int pid)
+{
+	std::vector<frame_t> frame;
+	int pcmd[2] = {0,0};
+	int pout[2] = {0,0};
+	int ret = 0;
+	if(ret == 0) {
+		ret = pipe(pcmd);
+		ret = pipe(pout);
+	}
+	if (fork() == 0) {
+		dup2(pcmd[0], 0);
+		dup2(pout[1], 1);
+		dup2(pout[1], 2);
+		close(pcmd[0]);
+		close(pcmd[1]);
+		close(pout[0]);
+		close(pout[1]);
+		execlp("gdb", "gdb", NULL);
+		exit(1);
+	}
+
+	close(pcmd[0]);
+	close(pout[1]);
+
+	/* always succ because the fd is valid */
+	FILE *cmdfp = fdopen(pcmd[1], "w");
+	FILE *outfp = fdopen(pout[0], "r");
+
+	setbuf(cmdfp, NULL);
+	setbuf(outfp, NULL);
+
+	fprintf(cmdfp, "set prompt GDB>\\n\n\n");
+	fflush(cmdfp);
+	wait_prompt(outfp);
+	fprintf(cmdfp, "attach %d\n", pid);
+	dump_info(pid);
+	dump_result(outfp);
+	printf("(gdb) backtrace\n");
+	fprintf(cmdfp, "backtrace\n");
+	parse_frame(outfp, frame);
+
+#define DUMP(fmt, args...)                 \
+	do                                     \
+	{                                      \
+		printf("(gdb) " fmt "\n", ##args); \
+		fprintf(cmdfp, fmt "\n", ##args);  \
+		dump_result(outfp);                \
+	} while (0)
+
+	for (unsigned int i = 0; i < frame.size(); i++) {
+		DUMP("frame %d", frame[i].index);
+		if (frame[i].ftype <= 1)
+			DUMP("info locals");
+		if (frame[i].ftype == 1)
+			DUMP("print *this");
+		if (frame[i].ftype == 2)
+			DUMP("info registers");
+	}
+
+	fprintf(cmdfp, "set variable crash_continue = 1\n");
+	dump_result(outfp);
+	fprintf(cmdfp, "quit\n");
+	fclose(cmdfp);
+	fclose(outfp);
+}
+
+void gdb_attach(int pid, const char *fn)
+{
+	int ret;
+	if (fn == NULL)
+		fn = getenv("DISPLAY");
+	char buf[256];
+	if (fn == NULL || !fn[0] || !strcmp(fn, "screen")) {
+		snprintf(buf, sizeof(buf), "screen -X -S gdb screen -t gdb.%d gdb /proc/%d/exe %d", pid, pid, pid);
+		ret = system(buf);
+		if (ret != 0) {
+			snprintf(buf, sizeof(buf), "screen -S gdb -t gdb.%d -d -m gdb /proc/%d/exe %d", pid, pid, pid);
+			ret = system(buf);
+		}
+	} else {
+		snprintf(buf, sizeof(buf), "xterm -T gdb.%d -e gdb /proc/%d/exe %d &", pid, pid, pid);
+		ret = system(buf);
+	}
+	dump_info(pid);
+}

+ 21 - 0
src/daemons/gdb.h

@@ -0,0 +1,21 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <vector>
+
+void gdb_dump(int pid);
+void gdb_attach(int pid, const char *fn);
+void gdb_server(int debug, const char *display);

+ 67 - 0
src/daemons/gdb_srv.cc

@@ -0,0 +1,67 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "gdb.h"
+
+static volatile int g_stop;
+static void sigusr1(int signo) {}
+static void sigstop(int signo) { g_stop = 1; }
+
+void gdb_server(int debug, const char *display)
+{
+	signal(SIGINT, sigstop);
+	signal(SIGTERM, sigstop);
+	signal(SIGQUIT, sigstop);
+	signal(SIGHUP, sigstop);
+	signal(SIGPIPE, SIG_IGN);
+	signal(SIGCHLD, SIG_DFL);
+	signal(SIGWINCH, sigusr1);
+	signal(SIGPIPE, SIG_IGN);
+	signal(SIGCHLD, SIG_IGN);
+
+	sigset_t sset;
+	sigemptyset(&sset);
+	sigaddset(&sset, SIGWINCH);
+	sigprocmask(SIG_BLOCK, &sset, NULL);
+
+	const struct timespec timeout = {5, 0};
+	siginfo_t info;
+	while (!g_stop) {
+		if (getppid() == 1)
+			break;
+		int signo = sigtimedwait(&sset, &info, &timeout);
+		if (signo == -1 && errno == -EAGAIN)
+			continue;
+		if (signo <= 0) {
+			usleep(100 * 1000);
+			continue;
+		}
+		if (info.si_code != SI_QUEUE)
+			continue;
+
+		int tid = info.si_int;
+		if (debug == 0) {
+			gdb_dump(tid);
+		} else {
+			gdb_attach(tid, display);
+		}
+	}
+}

+ 110 - 0
src/daemons/helper.cc

@@ -0,0 +1,110 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <sys/un.h>
+#include "socket/unix_socket.h"
+
+#include "config/dbconfig.h"
+#include "thread/thread.h"
+#include "helper.h"
+#include "daemon/daemon.h"
+#include "log/log.h"
+#include "dtc_global.h"
+#include <sstream>
+
+WatchDogHelper::WatchDogHelper(WatchDog *watchdog, int sec, const char *path, int machine_conf, int role, int backlog, int type, int conf, int num)
+	: WatchDogDaemon(watchdog, sec)
+{
+	std::stringstream oss;
+	oss << "helper" << machine_conf << MACHINEROLESTRING[role];
+	memcpy(watchdog_object_name_, oss.str().c_str(), oss.str().length());
+	path_ = path;
+	backlog_ = backlog;
+	type_ = type;
+	conf_ = conf;
+	num_ = num;
+}
+
+WatchDogHelper::~WatchDogHelper(void)
+{
+}
+
+const char *HelperName[] =
+{
+		NULL,
+		NULL,
+		"rocksdb_connector",
+		"tdb_connector",
+		"custom_connector",
+};
+
+void WatchDogHelper::exec()
+{
+	struct sockaddr_un unaddr;
+	int len = init_unix_socket_address(&unaddr, path_);
+	int listenfd = socket(unaddr.sun_family, SOCK_STREAM, 0);
+	bind(listenfd, (sockaddr *)&unaddr, len);
+	listen(listenfd, backlog_);
+
+	/* relocate listenfd to stdin */
+	dup2(listenfd, 0);
+	close(listenfd);
+
+	char *argv[9];
+	int argc = 0;
+
+	argv[argc++] = NULL;
+	argv[argc++] = (char *)"-d";
+	if (strcmp(cache_file, CACHE_CONF_NAME)) {
+		argv[argc++] = (char *)"-f";
+		argv[argc++] = cache_file;
+	}
+	if (conf_ == DBHELPER_TABLE_NEW) {
+		argv[argc++] = (char *)"-t";
+		char tableName[64];
+		snprintf(tableName, 64, "../conf/table%d.conf", num_);
+		argv[argc++] = tableName;
+	} else if (conf_ == DBHELPER_TABLE_ORIGIN && strcmp(table_file, TABLE_CONF_NAME)) {
+		argv[argc++] = (char *)"-t";
+		argv[argc++] = table_file;
+	}
+	argv[argc++] = watchdog_object_name_ + 6;
+	argv[argc++] = (char *)"-";
+	argv[argc++] = NULL;
+
+	Thread *helperThread = new Thread(watchdog_object_name_, Thread::ThreadTypeProcess);
+	helperThread->initialize_thread();
+	argv[0] = (char *)HelperName[type_];
+	execv(argv[0], argv);
+	log4cplus_error("helper[%s] execv error: %m", argv[0]);
+}
+
+int WatchDogHelper::verify()
+{
+	struct sockaddr_un unaddr;
+	int len = init_unix_socket_address(&unaddr, path_);
+
+	/* delay 100ms and verify socket */
+	usleep(100 * 1000);
+	int s = socket(unaddr.sun_family, SOCK_STREAM, 0);
+	if (connect(s, (sockaddr *)&unaddr, len) < 0) {
+		close(s);
+		log4cplus_error("verify connect: %m");
+		return -1;
+	}
+	close(s);
+	return watchdog_object_pid_;
+}

+ 39 - 0
src/daemons/helper.h

@@ -0,0 +1,39 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#ifndef __H_WATCHDOG_HELPER_H__
+#define __H_WATCHDOG_HELPER_H__
+
+#include "base.h"
+#include "daemon_listener.h"
+
+class WatchDogHelper : public WatchDogDaemon
+{
+private:
+	const char *path_;
+	int backlog_;
+	int type_;
+	int conf_;
+	int num_;
+
+public:
+	WatchDogHelper(WatchDog *watchdog, int sec, const char *path, int machine_conf, int role, int backlog, int type, int conf = DBHELPER_TABLE_ORIGIN, int num = -1);
+	virtual ~WatchDogHelper();
+	virtual void exec();
+	int verify();
+};
+
+#endif

+ 120 - 0
src/daemons/logger.cc

@@ -0,0 +1,120 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <string.h>
+#include "daemon/daemon.h"
+#include "proc_title.h"
+#include "config/config.h"
+#include "gdb.h"
+#include "log/log.h"
+#include "daemons.h"
+#include "unit.h"
+#include "fault.h"
+#include "thread/thread.h"
+
+#define HOOKSO "../bin/faultlogger"
+
+/* 设置环境变量LD_PRELOAD */
+static void set_ld_preload()
+{
+	if (access(HOOKSO, R_OK) == 0) {
+		char *preload = canonicalize_file_name(HOOKSO);
+		char *p = getenv("LD_PRELOAD");
+		if (p == NULL) {
+			setenv("LD_PRELOAD", preload, 1);
+		} else {
+			char *concat = NULL;
+			int unused = 0;
+			if(unused == 0)
+				unused = asprintf(&concat, "%s:%s", p, preload);
+			setenv("LD_PRELOAD", concat, 1);
+		}
+	}
+}
+
+/* 启动默认日志线程 */
+int start_fault_logger(WatchDog *watchdog)
+{
+	/**
+	 * CarshProtect/CrashLog mode:
+	 * 0 -- disabled
+	 * 1 -- log-only
+	 * 2 -- protect
+	 * 3 -- screen
+	 * 4 -- xterm
+	 */
+	/* default protect */
+	int mode = 2; 
+	const char *display;
+
+	display = g_dtc_config->get_str_val("cache", "FaultLoggerMode");
+	if (display == NULL || !display[0]) {
+		/* protect */
+		mode = 2; 
+	} else if (!strcmp(display, "log")) {
+		/* log */
+		mode = 1; 
+	} else if (!strcmp(display, "dump")) {
+		/* log */
+		mode = 1; 
+	} else if (!strcmp(display, "protect")) {
+		/* protect */
+		mode = 2; 
+	} else if (!strcmp(display, "screen")) {
+		/* screen */
+		mode = 3; 
+	} else if (!strcmp(display, "xterm")) {
+		if (getenv("DISPLAY")) {
+			/* xterm */
+			mode = 4; 
+			display = NULL;
+		} else {
+			log4cplus_warning("FaultLoggerTarget set to \"xterm\", but no DISPLAY found");
+			/* screen */
+			mode = 2; 
+		}
+	} else if (!strncmp(display, "xterm:", 6)) {
+		mode = 4; // xterm
+		display += 6;
+	} else if (!strcasecmp(display, "disable")) {
+		mode = 0;
+	} else if (!strcasecmp(display, "disabled")) {
+		mode = 0;
+	} else {
+		log4cplus_warning("unknown FaultLoggerMode \"%s\"", display);
+	}
+	log4cplus_info("FaultLoggerMode is %s\n", ((const char *[]){"disable", "log", "protect", "screen", "xterm"})[mode]);
+	if (mode == 0)
+		return 0;
+	int pid = fork();
+	if (pid < 0)
+		return -1;
+	if (pid == 0) {
+		set_proc_title("FaultLogger");
+		Thread *loggerThread = new Thread("faultlogger", Thread::ThreadTypeProcess);
+		loggerThread->initialize_thread();
+		gdb_server(mode >= 3, display);
+		exit(0);
+	}
+	char buf[20];
+	snprintf(buf, sizeof(buf), "%d", pid);
+	setenv(ENV_FAULT_LOGGER_PID, buf, 1);
+	FaultHandler::initialize(mode >= 2);
+	set_ld_preload();
+	WatchDogObject *obj = new WatchDogObject(watchdog, "FaultLogger", pid);
+	obj->attach_watch_dog();
+	return 0;
+}

+ 19 - 0
src/daemons/logger.h

@@ -0,0 +1,19 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+
+class WatchDog;
+int start_fault_logger(WatchDog *watchdog);

+ 99 - 0
src/daemons/main.cc

@@ -0,0 +1,99 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <signal.h>
+#include <string.h>
+#include "main.h"
+#include "daemon/daemon.h"
+#include "log/log.h"
+#include "proc_title.h"
+
+
+/**
+  * recovery_ value:
+  *    0 -- don't refork
+  *    1 -- fork again if crashed
+  *    2 -- fork & enable core dump if crashed
+  *    3 -- fork if killed
+  *    4 -- fork again if exit != 0
+  *    5 -- always fork again
+  */
+static const char *recovery_Info_str[] = {
+	"None", "Crash", "CrashDebug", "Killed", "Error", "Always"};
+
+
+WatchDogEntry::WatchDogEntry(WatchDogUnit *watchdog, int (*e)(void *), void *args, int recovery)
+	: WatchDogObject(watchdog), entry(e), args_(args), recovery_(recovery), core_count_(0)
+{
+	strncpy(watchdog_object_name_, "main", sizeof(watchdog_object_name_));
+	if (recovery_ > 3) {
+		char comm[24] = "wdog-";
+		get_proc_name(comm + 5);
+		set_proc_name(comm);
+	}
+	log4cplus_info("Main Process Recovery Mode: %s", recovery_Info_str[recovery_]);
+}
+
+WatchDogEntry::~WatchDogEntry(void)
+{
+}
+
+int WatchDogEntry::dtc_fork(int enCoreDump)
+{
+	if ((watchdog_object_pid_ = fork()) == 0) {
+		if (enCoreDump)
+			init_core_dump();
+		exit(entry(args_));
+	}
+    /* cann't fork main process */
+	if (watchdog_object_pid_ < 0)
+		return -1; 
+	attach_watch_dog();
+	return watchdog_object_pid_;
+}
+
+void WatchDogEntry::killed_notify(int signo, int coredumped)
+{
+	int corenable = 0;
+
+	if (recovery_ == 0 || ((recovery_ <= 2 && signo == SIGKILL) || signo == SIGTERM))
+		/* main cache exited, stopping all children */
+		stop = 1;
+	else {
+		++core_count_;
+		if (core_count_ == 1 && recovery_ >= 2)
+			corenable = 1;
+		sleep(2);
+		if (dtc_fork(corenable) < 0)
+			/* main fork error, stopping all children */
+			stop = 1;
+	}
+	report_kill_alarm(signo, coredumped);
+}
+
+void WatchDogEntry::exited_notify(int retval)
+{
+	if (recovery_ < 4 || retval == 0)
+		/* main cache exited, stopping all children */
+		stop = 1;
+	else {
+		/* sync sleep */
+		sleep(2); 
+		if (dtc_fork() < 0)
+			/* main fork error, stopping all children */
+			stop = 1;
+	}
+}

+ 41 - 0
src/daemons/main.h

@@ -0,0 +1,41 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#ifndef __H_WATCHDOG_MAIN_H__
+#define __H_WATCHDOG_MAIN_H__
+
+#include "daemons.h"
+
+class WatchDogEntry : private WatchDogObject
+{
+private:
+	int (*entry)(void *);
+	void *args_;
+	int recovery_;
+	int core_count_;
+
+private:
+	virtual void killed_notify(int signo, int coredumped);
+	virtual void exited_notify(int retval);
+
+public:
+	WatchDogEntry(WatchDogUnit *watchdog, int (*entry)(void *), void *args_, int recovery);  
+	virtual ~WatchDogEntry();
+	
+	int dtc_fork(int enCoreDump = 0);
+};
+
+#endif

+ 100 - 0
src/daemons/run.cc

@@ -0,0 +1,100 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <signal.h>
+
+#include "daemons.h"
+#include "main.h"
+#include "stattool.h"
+#include "listener/listener.h"
+#include "helper.h"
+#include "logger.h"
+#include "config/dbconfig.h"
+#include "log/log.h"
+#include "daemon/daemon.h"
+/* 打开看门狗 */
+int start_watch_dog(int (*entry)(void *), void *args)
+{
+    int delay = 5;
+    dbConfig->set_helper_path(getpid());
+    WatchDog *wdog = NULL;
+    WatchDogListener *srv = NULL;
+
+    if (g_dtc_config->get_int_val("cache", "DisableWatchDog", 0) == 0) {
+        signal(SIGCHLD, SIG_DFL);
+        delay = g_dtc_config->get_int_val("cache", "WatchDogTime", 30);
+        if (delay < 5)
+            delay = 5;
+        wdog = new WatchDog;
+        srv = new WatchDogListener(wdog, delay);
+        srv->attach_watch_dog();
+        start_fault_logger(wdog);
+        if (g_dtc_config->get_int_val("cache", "StartStatReporter", 0) > 0) {
+            WatchDogStatTool *stat_tool = new WatchDogStatTool(wdog, delay);
+            if (stat_tool->dtc_fork() < 0)
+                /* cann't fork reporter */
+                return -1; 
+            log4cplus_info("fork stat reporter");
+        }
+    }
+    if (g_dtc_config->get_int_val("cache", "DisableDataSource", 0) == 0) {
+        int nh = 0;
+        /* starting master helper */
+        for (int g = 0; g < dbConfig->machineCnt; ++g) {
+            for (int r = 0; r < ROLES_PER_MACHINE; ++r) {
+                HELPERTYPE t = dbConfig->mach[g].helperType;
+                log4cplus_debug("helper type = %d", t);
+                /* check helper type is dtc */
+                if (DTC_HELPER >= t)
+                    break;
+                int i, n = 0;
+                for (i = 0; i < GROUPS_PER_ROLE && (r * GROUPS_PER_ROLE + i) < GROUPS_PER_MACHINE; i++) {
+                    n += dbConfig->mach[g].gprocs[r * GROUPS_PER_ROLE + i];
+                }
+                if (n <= 0)
+                    continue;
+                WatchDogHelper *h = NULL;
+                NEW(WatchDogHelper(wdog, delay, dbConfig->mach[g].role[r].path, g, r, n + 1, t), h);
+                if (NULL == h) {
+                    log4cplus_error("create WatchDogHelper object failed, msg:%m");
+                    return -1;
+                }
+                if (h->dtc_fork() < 0 || h->verify() < 0)
+                    return -1;
+                nh++;
+            }
+        }
+        log4cplus_info("fork %d helper groups", nh);
+    }
+    if (wdog) {
+        const int recovery = g_dtc_config->get_idx_val("cache", "ServerRecovery",
+                                                ((const char *const[]){
+                                                    "none",
+                                                    "crash",
+                                                    "crashdebug",
+                                                    "killed",
+                                                    "error",
+                                                    "always",
+                                                    NULL}),
+                                                2);                                
+        WatchDogEntry *dtc = new WatchDogEntry(wdog, entry, args, recovery);
+        if (dtc->dtc_fork() < 0)
+            return -1;
+        wdog->run_loop();
+        exit(0);
+    }
+    return 0;
+}

+ 46 - 0
src/daemons/stattool.cc

@@ -0,0 +1,46 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <unistd.h>
+
+#include "stattool.h"
+
+WatchDogStatTool::WatchDogStatTool(WatchDog *watchdog, int sec)
+	: WatchDogDaemon(watchdog, sec)
+{
+	strncpy(watchdog_object_name_, "stattool", sizeof(watchdog_object_name_));
+}
+
+WatchDogStatTool::~WatchDogStatTool(void)
+{
+}
+
+void WatchDogStatTool::exec()
+{
+	char *argv[3];
+
+	argv[1] = (char *)"reporter";
+	argv[2] = NULL;
+
+	argv[0] = (char *)"stattool32";
+	execv(argv[0], argv);
+	argv[0] = (char *)"../bin/stattool32";
+	execv(argv[0], argv);
+	argv[0] = (char *)"stattool";
+	execv(argv[0], argv);
+	argv[0] = (char *)"../bin/stattool";
+	execv(argv[0], argv);
+}

+ 32 - 0
src/daemons/stattool.h

@@ -0,0 +1,32 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#ifndef __H_WATCHDOG_STATTOOL_H__
+#define __H_WATCHDOG_STATTOOL_H__
+
+#include "daemon/daemon.h"
+#include "base.h"
+
+class WatchDogStatTool : public WatchDogDaemon
+{
+public:
+	WatchDogStatTool(WatchDog *watchdog, int sec);
+	virtual ~WatchDogStatTool();
+
+	virtual void exec();
+};
+
+#endif

+ 174 - 0
src/daemons/unit.cc

@@ -0,0 +1,174 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#include <sys/wait.h>
+#include <errno.h>
+
+#include "config/config.h"
+#include "unit.h"
+#include "log/log.h"
+#include "stat_alarm_reporter.h"
+#include <sstream>
+#include <dtc_global.h>
+
+WatchDogObject::~WatchDogObject()
+{
+}
+
+int WatchDogObject::attach_watch_dog(WatchDogUnit *u)
+{
+	if (u && watchdog_object_owner_ == NULL)
+		watchdog_object_owner_ = u;
+	return watchdog_object_owner_ ? watchdog_object_owner_->attach_process(this) : -1;
+}
+
+void WatchDogObject::exited_notify(int retval)
+{
+	delete this;
+}
+
+void WatchDogObject::killed_notify(int signo, int coredumped)
+{
+	report_kill_alarm(signo, coredumped);
+	delete this;
+}
+
+void WatchDogObject::report_kill_alarm(int signo, int coredumped)
+{
+
+	if (!ALARM_REPORTER->init_alarm_cfg(std::string(ALARM_CONF_FILE), true)) {
+		log4cplus_error("init alarm conf file fail");
+		return;
+	}
+	ALARM_REPORTER->set_time_out(1);
+	std::stringstream oss;
+	oss << "child process[" << watchdog_object_pid_ << "][ " << watchdog_object_name_ << " ]killed by signal " << signo;
+	if (coredumped) 
+		oss << " core dumped";
+	ALARM_REPORTER->report_alarm(oss.str());
+}
+
+WatchDogUnit::WatchDogUnit()
+	: pid_count_(0){};
+
+WatchDogUnit::~WatchDogUnit()
+{
+	pidmap_t::iterator i;
+	for (i = pid_map_watchdog_object_.begin(); i != pid_map_watchdog_object_.end(); i++) {
+		WatchDogObject *obj = i->second;
+		delete obj;
+	}
+};
+
+int WatchDogUnit::check_watchdog()
+{
+	while (1) {
+		int status;
+		int pid = waitpid(-1, &status, WNOHANG);
+		int err = errno;
+		if (pid < 0) {
+			switch (err) {
+			case EINTR:
+			case ECHILD:
+				break;
+			default:
+				log4cplus_info("wait() return pid %d errno %d", pid, err);
+				break;
+			}
+			break;
+		} else if (pid == 0) {
+			break;
+		} else {
+			pidmap_t::iterator itr = pid_map_watchdog_object_.find(pid);
+			if (itr == pid_map_watchdog_object_.end()) {
+				log4cplus_info("wait() return unknown pid %d status 0x%x", pid, status);
+			} else {
+				WatchDogObject *obj = itr->second;
+				const char *const name = obj->Name();
+				pid_map_watchdog_object_.erase(itr);
+				/* special exit value return-ed by CrashProtector */
+				if (WIFEXITED(status) && WEXITSTATUS(status) == 85 && strncmp(name, "main", 5) == 0) {   
+					/* treat it as a fake SIGSEGV */
+					status = W_STOPCODE(SIGSEGV);
+				}
+				if (WIFSIGNALED(status)) {
+					const int sig = WTERMSIG(status);
+					const int core = WCOREDUMP(status);
+					log4cplus_fatal("%s: killed by signal %d", name, sig);
+					log4cplus_error("child %.16s pid %d killed by signal %d%s",
+							  name, pid, sig,
+							  core ? " (core dumped)" : "");
+					pid_count_--;
+					obj->killed_notify(sig, core);
+				} else if (WIFEXITED(status)) {
+					const int retval = (signed char)WEXITSTATUS(status);
+					if (retval == 0)
+						log4cplus_debug("child %.16s pid %d exit status %d",
+								  name, pid, retval);
+					else
+						log4cplus_info("child %.16s pid %d exit status %d",
+								 name, pid, retval);
+					pid_count_--;
+					obj->exited_notify(retval);
+				}
+			}
+		}
+	}
+	return pid_count_;
+}
+
+int WatchDogUnit::attach_process(WatchDogObject *obj)
+{
+	const int pid = obj->watchdog_object_pid_;
+	pidmap_t::iterator itr = pid_map_watchdog_object_.find(pid);
+	if (itr != pid_map_watchdog_object_.end() || pid <= 1)
+		return -1;
+	pid_map_watchdog_object_[pid] = obj;
+	pid_count_++;
+	return 0;
+}
+
+int WatchDogUnit::kill_allwatchdog()
+{
+	pidmap_t::iterator i;
+	int n = 0;
+	for (i = pid_map_watchdog_object_.begin(); i != pid_map_watchdog_object_.end(); i++) {
+		WatchDogObject *obj = i->second;
+		if (obj->get_watchdog_pid() > 1) {
+			log4cplus_debug("killing child %.16s pid %d SIGTERM",
+					  obj->Name(), obj->get_watchdog_pid());
+			kill(obj->get_watchdog_pid(), SIGTERM);
+			n++;
+		}
+	}
+	return n;
+}
+
+int WatchDogUnit::force_kill_allwatchdog()
+{
+	pidmap_t::iterator i;
+	int n = 0;
+	for (i = pid_map_watchdog_object_.begin(); i != pid_map_watchdog_object_.end(); i++) {
+		WatchDogObject *obj = i->second;
+		if (obj->get_watchdog_pid() > 1) {
+			log4cplus_error("child %.16s pid %d didn't exit in timely, sending SIGKILL.",
+					  obj->Name(), obj->get_watchdog_pid());
+			kill(obj->get_watchdog_pid(), SIGKILL);
+			n++;
+		}
+	}
+	return n;
+}

+ 76 - 0
src/daemons/unit.h

@@ -0,0 +1,76 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+*/
+#ifndef __H_WATCHDOG_UNIT_H__
+#define __H_WATCHDOG_UNIT_H__
+#include <stdlib.h>
+#include <string.h>
+#include <map>
+
+class WatchDogUnit;
+
+class WatchDogObject
+{
+protected:
+	friend class WatchDogUnit;
+	WatchDogUnit *watchdog_object_owner_;
+	int watchdog_object_pid_;
+	char watchdog_object_name_[16];
+
+public:
+	WatchDogObject(void) : watchdog_object_owner_(NULL), watchdog_object_pid_(0) { watchdog_object_name_[0] = '0'; }
+	WatchDogObject(WatchDogUnit *u) : watchdog_object_owner_(u), watchdog_object_pid_(0) { watchdog_object_name_[0] = '0'; }
+	WatchDogObject(WatchDogUnit *u, const char *n) : watchdog_object_owner_(u), watchdog_object_pid_(0)
+	{
+		strncpy(watchdog_object_name_, n, sizeof(watchdog_object_name_));
+	}
+	WatchDogObject(WatchDogUnit *u, const char *n, int i) : watchdog_object_owner_(u), watchdog_object_pid_(i)
+	{
+		strncpy(watchdog_object_name_, n, sizeof(watchdog_object_name_));
+	}
+	virtual ~WatchDogObject();
+	virtual void exited_notify(int retval);
+	virtual void killed_notify(int signo, int coredumped);
+	const char *Name() const { return watchdog_object_name_; }
+	int get_watchdog_pid() const { return watchdog_object_pid_; }
+	int attach_watch_dog(WatchDogUnit *o = 0);
+	void report_kill_alarm(int signo, int coredumped);
+};
+
+
+
+class WatchDogUnit
+{
+private:
+	friend class WatchDogObject;
+	typedef std::map<int, WatchDogObject *> pidmap_t;
+	int pid_count_;
+	pidmap_t pid_map_watchdog_object_;
+
+private:
+	int attach_process(WatchDogObject *);
+
+public:
+	WatchDogUnit();
+	virtual ~WatchDogUnit();
+	/* return #pid monitored */
+	int check_watchdog(); 
+	int kill_allwatchdog();
+	int force_kill_allwatchdog();
+	int get_process_count() const { return pid_count_; }
+};
+
+#endif

+ 5 - 0
src/devel/Makefile

@@ -0,0 +1,5 @@
+include ../Make.conf
+
+SUBDIRS := cpp
+
+include ../Make.rules

+ 43 - 0
src/devel/cpp/Makefile

@@ -0,0 +1,43 @@
+LIB_PATH = ../..
+
+include ../../Make.conf
+
+GIT_VERSION=$(shell git log . | head -n 4 | grep "commit" | cut -d " " -f 2 | cut -c 1-7)
+SVN_REVISION = $(shell test -d .svn && (svn info | grep "Last Changed Rev" | cut -d " " -f 4))
+ifeq "$(SVN_REVISION)a" "a"
+	SVN_REVISION = "(unknown)"
+endif
+
+SRC_FOLDER := $(shell find ../../libs/common -maxdepth 1 -type d)
+VPATH = ../../libs/common ../../configcenter/ca_api/ $(basename $(patsubst ./%, %/, $(SRC_FOLDER)))
+################compile#############
+target = libdtc.a container_api.pic.o version.pic.o somain.pic.o libdtc.so libdtc.pic.a 
+
+# CLIENTAPI macro use for scope test only
+CFLAGS += -DCLIENTAPI
+CFLAGS += -D_GLIBCXX_USE_CXX11_ABI=0 -std=gnu++11
+CFLAGS += -pthread -I../../libs/common -I../../stat -I../../configcenter/ca_api/ $(LOG4CPLUS_INC) $(ZINC) $(YAML_CPP_INC)
+LIBS = ${Z_LIB} -ldl -lpthread  $(LOG4CPLUS_LIB) $(CA_API_LIB) -L../../libs/common -lcommon $(YAML_CPP_LIB)
+
+filelist := dtcreq value dtcsvr dtcpool dtcwrap dtcwrapp dtcqossvr \
+	poller timer_list key_list table_def log_client mem_check \
+	md5 section decode encode field_api packet_base \
+	packet_client task_base task_const socket_addr udppool compress buffer thread
+#filelist := dtcreq
+
+#lidttc.so: container_api.pic.o version.pic.o
+
+# for auto ln -sf
+libdtc_objs := $(patsubst %,%.o,$(filelist))
+libdtc.so: LDFLAGS += -Wl,--version-script,dtcapi.lst -e _so_start container_api.pic.o version.pic.o somain.pic.o
+libdtc_filename := libdtc-gcc-$(GCCVER)-r$(GIT_VERSION).so
+libdtc_soname := libdtc.so.1
+
+###############install##############
+target_install = libdtc.a libdtc.pic.a libdtc.so dtcapi.h 
+install_dir = ../../../bin
+%.a: install_dir = ../../../lib
+%.h: install_dir = ../../../include
+
+include ../../Make.rules
+

+ 100 - 0
src/devel/cpp/container_api.cc

@@ -0,0 +1,100 @@
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include "container.h"
+#include "version.h"
+#include "dtcint.h"
+
+typedef IInternalService *(*QueryInternalServiceFunctionType)(const char *name, const char *instance);
+
+IInternalService *query_internal_service(const char *name, const char *instance)
+{
+	QueryInternalServiceFunctionType entry = NULL;
+	entry = (QueryInternalServiceFunctionType)dlsym(RTLD_DEFAULT, "_QueryInternalService");
+	if(entry == NULL)
+		return NULL;
+	return entry(name, instance);
+}
+
+static inline int fieldtype_keytype(int t)
+{
+	switch(t) {
+		case DField::Signed:
+		case DField::Unsigned:
+			return DField::Signed;
+
+		case DField::String:
+		case DField::Binary:
+			return DField::String;
+	}
+	return DField::None;
+}
+
+void NCServer::check_internal_service(void)
+{
+	if(NCResultInternal::verify_class()==0)
+		return;
+
+	IInternalService *inst = query_internal_service("dtcd", this->tablename_);
+
+	/* not inside dtcd or tablename not found */
+	if(inst == NULL)
+		return;
+
+	/* version mismatch, internal service is unusable */
+	const char *version = inst->query_version_string();
+	if(version==NULL || strcasecmp(version_detail, version) != 0)
+		return;
+
+	/* cast to DTC service */
+	IDTCService *inst1 = static_cast<IDTCService *>(inst);
+
+	DTCTableDefinition *tdef = inst1->query_table_definition();
+
+	/* verify tablename etc */
+	if(tdef->is_same_table(tablename_)==0)
+		return;
+
+	/* verify and save key type */
+	int kt = fieldtype_keytype(tdef->key_type());
+	if(kt == DField::None)
+		/* bad key type */
+		return;
+
+	if(keytype_ == DField::None) {
+		keytype_ = kt;
+	} else if(keytype_ != kt) {
+		badkey_ = 1;
+		error_str_ = "Key Type Mismatch";
+		return;
+	}
+	if(keyinfo_.get_key_fields_count()!=0) {
+		/* FIXME: checking keyinfo */
+
+		/* ZAP key info, use ordered name from server */
+		keyinfo_.clear_key();
+	}
+	/* add NCKeyInfo */
+	for(int i=0; i<tdef->key_fields(); i++) {
+		kt = fieldtype_keytype(tdef->field_type(i));
+		if(kt == DField::None)
+			// bad key type
+			return;
+		keyinfo_.add_key(tdef->field_name(i), kt);
+	}
+
+    /**
+     * OK, save it.
+     * OK, save it.
+     */
+	this->table_definition_ = tdef;
+	this->admin_tdef = inst1->query_admin_table_definition();
+	/* useless here, internal DTCTableDefinition don't maintent a usage count */
+	tdef->increase();
+	this->service_ = inst1;
+	this->completed_ = 1;
+	if(get_address() && service_->match_listening_ports(get_address(), NULL)) {
+		executor_ = service_->query_task_executor();
+	}
+}
+

+ 1076 - 0
src/devel/cpp/dtcapi.h

@@ -0,0 +1,1076 @@
+#ifndef __DTC_API_H__
+#define __DTC_API_H__
+
+#include <stdlib.h>
+#include <vector>
+#include <string>
+#include <stdint.h>
+
+#define IP_LENGHT 16
+
+namespace DTC 
+{
+
+	typedef struct route_node
+	{
+		int bid;
+		int port;
+		int status;
+		int weight;
+		char ip[IP_LENGHT];
+	}ROUTE_NODE;
+
+	class Server;
+	class ServerPool;
+	class Request;
+	class Result;
+
+	const int kRequestSvrAdmin 	= 3;
+	const int kRequestGet 		= 4;
+	const int kRequestPurge 		= 5;
+	const int kRequestInsert 	= 6;
+	const int kRequestUpdate 	= 7;
+	const int kRequestDelete 	= 8;
+	const int kRequestReplace 	= 12;
+	const int kRequestFlush 		= 13;
+	const int kRequestInvalidate	= 14;
+
+	/* mem monior Request;2014/06/6;by seanzheng */
+	const int kRequestMonitor    = 15;
+
+	/* sub-code of admin cmd */
+	const int RegisterHB		= 1;
+	const int LogoutHB		= 2;
+	const int GetKeyList		= 3;
+	const int GetUpdateKey		= 4;
+	const int GetRawData		= 5;
+	const int ReplaceRawData	= 6;
+	const int AdjustLRU        	= 7;
+	const int VerifyHBT		= 8;
+	const int GetHBTime		= 9;
+	const int kSetReadOnly	= 10;
+	const int kSetReadWrite	= 11;
+	const int kQueryBinlogID		= 12;
+	const int kNodeHandleChange  = 13;
+	const int Migrate = 14;
+    const int kReloadClusterNodeList = 15;
+    const int kSetClusterNodeState  = 16;
+    const int kChangeNodeAddress  = 17;
+    const int kGetClusterState  = 18;
+    const int kPurgeForHit    = 19;
+	const int ClearCache = 21;
+	const int ColExpandStatus = 24;
+	const int kColExpand = 25;
+	const int ColExpandDone = 26;
+	const int ColExpandKey = 27;
+	 
+	/* undefined */
+	const int kKeyTypeNone		= 0;	
+	/* Signed Integer */
+	const int kKeyTypeInt		= 1;	
+	/* String, case insensitive, null ended */
+	const int kKeyTypeString		= 4;	
+	/* undefined */
+	const int kFieldTypeNone		= 0;    
+	/* Signed Integer */
+	const int kFieldTypeSigned	= 1;
+	/* Unsigned Integer */
+	const int kFieldTypeUnsigned	= 2;	
+	/* float */
+	const int kFieldTypeFloat	= 3;	
+	/* String, case insensitive, null ended */
+	const int kFieldTypeString	= 4;	
+	/* binary */
+	const int kFieldTypeBinary	= 5;	
+
+	void init_log (const char *app, const char *dir = NULL);
+	void set_log_level(int n);
+	/* 设置批量操作一次最多多少个key(默认最多32个) */
+	int  set_key_value_max(unsigned int count); 
+
+	class Result;
+	class Server 
+	{
+	private:
+		void *addr_;
+		long check;
+	public:
+		friend class Request;
+		friend class Result;
+		friend class ServerPool;
+		friend class QOSServerPool;
+
+		Server(void);
+		~Server(void);
+		Server(const Server &);
+		void clone_table_define(const Server& source);
+		int set_address(const char *host, const char *port=0);
+		int set_table_name(const char *);
+		/* for compress */
+		void set_compress_level(int);
+		/* get address and tablename set by user */
+		const char * get_address(void) const;
+		const char * get_table_name(void) const;
+		/* get address and tablename set by dtc frame,for plugin only; */
+		const char * get_server_address(void) const;
+		const char * get_server_table_name(void) const;
+		int int_key(void);
+		int binary_key(void);
+		int string_key(void);
+		int add_key(const char* name, int type);
+		int get_field_type(const char* name);
+		const char *get_error_message(void) const;
+		void SetTimeout(int);
+		void set_timeout(int);
+		int Connect(void);
+		void Close(void);
+		int ping(void);
+		void auto_ping(void);
+		/* UNSUPPORTED API */
+		void set_fd(int); 
+		void set_auto_Update_table(bool autoUpdate);
+		void set_auto_reconnect(int auto_reconnect);
+		int decode_packet(Result &, const char *, int);
+		int check_packet_size(const char *, int);
+
+		void set_accesskey(const char *token);
+
+	public:
+		void increase_error_count_();
+		uint64_t get_error_count();
+		void clear_error_count();
+		
+		void increase_remove_count();
+		int get_remove_count();
+		void clear_remove_count();
+
+		void increase_total_request();
+		uint64_t get_total_request();
+		void clear_total_request();
+
+		void add_total_elaps(uint64_t iElaps);
+		uint64_t get_total_elaps();
+		void clear_total_elaps();
+	};
+
+	class DTCQosServer;
+
+	class DTCServers
+	{
+		public:
+			DTCServers();
+			~DTCServers();
+
+		private:
+			DTCServers(const DTCServers&);
+			DTCServers& operator=(const DTCServers&);
+
+		public:
+			int set_route_list(std::vector<ROUTE_NODE>& ip_list);
+			void set_idc_no(int IDCNo);
+			Server* get_server();
+
+			int set_accesskey(const char *token);
+			int set_table_name(const char *tableName);
+		    /**
+			 * Signed=1,  Signed Integer
+			 * String=4,  String, case insensitive, null ended
+			 * Binary=5,  opaque binary data
+			 */
+			int set_key_type(int type);
+			void set_agenttime(int t);
+			void set_timeout(int n);
+			std::string get_error_msg();
+
+		private:
+			int is_server_has_existed(ROUTE_NODE& ip);
+			int construct_servers();
+			int construct_servers2(std::vector<ROUTE_NODE>& IPList);
+			void disorder_list(int *tmpBuckets, int size);
+			int construct_balance_buckets();
+			int refresh_balance_buckets(uint64_t );			
+			void remove_server_from_buckets(uint64_t );
+			Server* get_one_server_from_buckets();
+			void set_error_msg(int err, std::string from, std::string msg);
+
+		private:
+			int m_time_out;
+			int m_agent_time; 
+			int m_key_type;
+			char* m_table_name;
+			std::string m_access_token;
+			std::string m_err_msg;
+
+		private:
+			bool m_set_route;	
+			bool m_constructed_by_set_i_ps;
+			int m_bid;
+			int m_idc_no;
+			int m_buckets_pos;
+			int m_balance_bucket_size;
+			uint64_t m_bid_version;
+			uint64_t m_last_get_ca_time;
+			uint64_t m_refresh_buckets_time;
+			uint64_t m_remove_buckets_time;
+			int* m_load_balance_buckets;
+			DTCQosServer* m_qos_severs;
+			std::vector<ROUTE_NODE> m_ip_list;
+	};
+
+	class Request 
+	{
+		private:
+			void *addr_;
+			long check;
+			Request(const Request &);
+		public:
+			friend class Server;
+			friend class Result;
+			friend class ServerPool;
+
+			Request(Server *srv, int op);
+			Request(void);
+			~Request(void);
+			void Reset(void);
+			void Reset(int);
+			int attach_server(Server *srv);
+
+			void set_admin_code(int code);
+			void set_hotbackup_id(long long);
+			void set_master_hotbackup_timestamp(long long);
+			void set_slave_hotbackup_timestamp(long long);
+
+#define _API_DEFINE_LONG_(op, t) int op(const char *n, t a) { return op(n, (long long)a); }
+#define _API_DEFINE_FLOAT_(op, t) int op(const char *n, t a) { return op(n, (double)a); }
+			int need(const char *);
+			int need(const char *, int);
+			int get_field_type(const char*);
+			void no_cache(void);
+			void no_next_server(void);
+			void limit(unsigned int, unsigned int);
+			int EQ(const char *, long long);
+			int NE(const char *, long long);
+			int LT(const char *, long long);
+			int LE(const char *, long long);
+			int GT(const char *, long long);
+			int GE(const char *, long long);
+			int EQ(const char *, const char *);
+			int NE(const char *, const char *);
+			int EQ(const char *, const char *, int);
+			int NE(const char *, const char *, int);
+
+			_API_DEFINE_LONG_(EQ, unsigned long long);
+			_API_DEFINE_LONG_(EQ, long);
+			_API_DEFINE_LONG_(EQ, unsigned long);
+			_API_DEFINE_LONG_(EQ, int);
+			_API_DEFINE_LONG_(EQ, unsigned int);
+			_API_DEFINE_LONG_(EQ, short);
+			_API_DEFINE_LONG_(EQ, unsigned short);
+			_API_DEFINE_LONG_(EQ, char);
+			_API_DEFINE_LONG_(EQ, unsigned char);
+
+			_API_DEFINE_LONG_(NE, unsigned long long);
+			_API_DEFINE_LONG_(NE, long);
+			_API_DEFINE_LONG_(NE, unsigned long);
+			_API_DEFINE_LONG_(NE, int);
+			_API_DEFINE_LONG_(NE, unsigned int);
+			_API_DEFINE_LONG_(NE, short);
+			_API_DEFINE_LONG_(NE, unsigned short);
+			_API_DEFINE_LONG_(NE, char);
+			_API_DEFINE_LONG_(NE, unsigned char);
+
+			_API_DEFINE_LONG_(GT, unsigned long long);
+			_API_DEFINE_LONG_(GT, long);
+			_API_DEFINE_LONG_(GT, unsigned long);
+			_API_DEFINE_LONG_(GT, int);
+			_API_DEFINE_LONG_(GT, unsigned int);
+			_API_DEFINE_LONG_(GT, short);
+			_API_DEFINE_LONG_(GT, unsigned short);
+			_API_DEFINE_LONG_(GT, char);
+			_API_DEFINE_LONG_(GT, unsigned char);
+
+			_API_DEFINE_LONG_(GE, unsigned long long);
+			_API_DEFINE_LONG_(GE, long);
+			_API_DEFINE_LONG_(GE, unsigned long);
+			_API_DEFINE_LONG_(GE, int);
+			_API_DEFINE_LONG_(GE, unsigned int);
+			_API_DEFINE_LONG_(GE, short);
+			_API_DEFINE_LONG_(GE, unsigned short);
+			_API_DEFINE_LONG_(GE, char);
+			_API_DEFINE_LONG_(GE, unsigned char);
+
+			_API_DEFINE_LONG_(LT, unsigned long long);
+			_API_DEFINE_LONG_(LT, long);
+			_API_DEFINE_LONG_(LT, unsigned long);
+			_API_DEFINE_LONG_(LT, int);
+			_API_DEFINE_LONG_(LT, unsigned int);
+			_API_DEFINE_LONG_(LT, short);
+			_API_DEFINE_LONG_(LT, unsigned short);
+			_API_DEFINE_LONG_(LT, char);
+			_API_DEFINE_LONG_(LT, unsigned char);
+
+			_API_DEFINE_LONG_(LE, unsigned long long);
+			_API_DEFINE_LONG_(LE, long);
+			_API_DEFINE_LONG_(LE, unsigned long);
+			_API_DEFINE_LONG_(LE, int);
+			_API_DEFINE_LONG_(LE, unsigned int);
+			_API_DEFINE_LONG_(LE, short);
+			_API_DEFINE_LONG_(LE, unsigned short);
+			_API_DEFINE_LONG_(LE, char);
+			_API_DEFINE_LONG_(LE, unsigned char);
+
+			int Set(const char *, long long);
+			int OR(const char *, long long);
+			int Add(const char *, long long);
+			int Sub(const char *, long long);
+			int Set(const char *, double);
+			int Add(const char *, double);
+			int Sub(const char *, double);
+			int Set(const char *, const char *);
+			int Set(const char *, const char *, int);
+
+			/* just for compress,only support binary field */
+			int compress_set(const char *, const char *, int);
+			/* just compress and set. Don't need compressflag */
+			int compress_set_force(const char *, const char *, int);
+			/* bits op */
+			int set_multi_bits(const char *, int, int, unsigned int);
+			int set_bit  (const char *f, int o) { return set_multi_bits(f, o, 1, 1);}
+			int clear_bit(const char *f, int o) { return set_multi_bits(f, o, 1, 0);}
+
+			_API_DEFINE_LONG_(Set, unsigned long long);
+			_API_DEFINE_LONG_(Set, long);
+			_API_DEFINE_LONG_(Set, unsigned long);
+			_API_DEFINE_LONG_(Set, int);
+			_API_DEFINE_LONG_(Set, unsigned int);
+			_API_DEFINE_LONG_(Set, short);
+			_API_DEFINE_LONG_(Set, unsigned short);
+			_API_DEFINE_LONG_(Set, char);
+			_API_DEFINE_LONG_(Set, unsigned char);
+			_API_DEFINE_FLOAT_(Set, float);
+			_API_DEFINE_FLOAT_(Set, long double);
+
+			_API_DEFINE_LONG_(OR, unsigned long long);
+			_API_DEFINE_LONG_(OR, long);
+			_API_DEFINE_LONG_(OR, unsigned long);
+			_API_DEFINE_LONG_(OR, int);
+			_API_DEFINE_LONG_(OR, unsigned int);
+			_API_DEFINE_LONG_(OR, short);
+			_API_DEFINE_LONG_(OR, unsigned short);
+
+			_API_DEFINE_LONG_(Add, unsigned long long);
+			_API_DEFINE_LONG_(Add, long);
+			_API_DEFINE_LONG_(Add, unsigned long);
+			_API_DEFINE_LONG_(Add, int);
+			_API_DEFINE_LONG_(Add, unsigned int);
+			_API_DEFINE_LONG_(Add, short);
+			_API_DEFINE_LONG_(Add, unsigned short);
+			_API_DEFINE_LONG_(Add, char);
+			_API_DEFINE_LONG_(Add, unsigned char);
+			_API_DEFINE_FLOAT_(Add, float);
+			_API_DEFINE_FLOAT_(Add, long double);
+
+			_API_DEFINE_LONG_(Sub, unsigned long long);
+			_API_DEFINE_LONG_(Sub, long);
+			_API_DEFINE_LONG_(Sub, unsigned long);
+			_API_DEFINE_LONG_(Sub, int);
+			_API_DEFINE_LONG_(Sub, unsigned int);
+			_API_DEFINE_LONG_(Sub, short);
+			_API_DEFINE_LONG_(Sub, unsigned short);
+			_API_DEFINE_LONG_(Sub, char);
+			_API_DEFINE_LONG_(Sub, unsigned char);
+			_API_DEFINE_FLOAT_(Sub, float);
+			_API_DEFINE_FLOAT_(Sub, long double);
+#undef _API_DEFINE_LONG_
+
+			void unset_key(void);
+			int set_key(long long);
+			int set_key(const char *);
+			int set_key(const char *, int);
+#define _API_DEFINE_LONG_(t) int set_key(t a) { return set_key((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int add_key_value(const char* name, long long v);
+			int add_key_value(const char* name, const char *str);
+			int add_key_value(const char* name, const char *ptr, int len);
+#define _API_DEFINE_LONG_(t) int add_key_value(const char* name, t a) { return add_key_value(name, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			Result *do_execute(void);
+			Result *do_execute(long long);
+			Result *do_execute(const char *);
+			Result *do_execute(const char *, int);
+
+#define _API_DEFINE_LONG_(t) Result *do_execute(t a) { return do_execute((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int do_execute(Result&);
+			int do_execute(Result&, long long);
+			int do_execute(Result&, const char *);
+			int do_execute(Result&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int do_execute(Result &r, t a) { return do_execute(r, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int encode_packet(char *&, int&, long long&);
+			int encode_packet(char *&, int&, long long&, long long);
+			int encode_packet(char *&, int&, long long&, const char *);
+			int encode_packet(char *&, int&, long long&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int encode_packet(char *&p, int &l, long long &m, t a) { return encode_packet(p,l,m,(long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int set_cache_id(long long);
+#define _API_DEFINE_LONG_(t) int set_cache_id(t a) {return set_cache_id((long long)a);}
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+            const char *get_error_message(void) const;
+			/* 无源模式超时时间 */
+			int set_expire_time(const char* key, int time);
+			int get_expire_time(const char* key);
+	};
+
+	class GetRequest : public Request 
+	{
+	public:
+		GetRequest(Server *srv): Request(srv, kRequestGet) {}
+		GetRequest(): Request((Server *)0, kRequestGet) {}
+	};
+
+	class InsertRequest : public Request 
+	{
+	public:
+		InsertRequest(Server *srv) : Request(srv, kRequestInsert) {}
+		InsertRequest() : Request((Server *)0, kRequestInsert) {}
+	};
+
+	class DeleteRequest : public Request 
+	{
+	public:
+		DeleteRequest(Server *srv) : Request(srv, kRequestDelete) {}
+		DeleteRequest() : Request((Server *)0, kRequestDelete) {}
+	};
+
+	class UpdateRequest : public Request 
+	{
+	public:
+		UpdateRequest(Server *srv) : Request(srv, kRequestUpdate) {}
+		UpdateRequest() : Request((Server *)0, kRequestUpdate) {}
+	};
+
+	class PurgeRequest : public Request 
+	{
+	public:
+		PurgeRequest(Server *srv) : Request(srv, kRequestPurge) {}
+		PurgeRequest() : Request((Server *)0, kRequestPurge) {}
+	};
+
+	class ReplaceRequest:public Request 
+	{
+	public:
+		ReplaceRequest(Server *srv) : Request(srv, kRequestReplace) {}
+		ReplaceRequest() : Request((Server *)0, kRequestReplace) {}
+	};
+
+	class FlushRequest : public Request 
+	{
+	public:
+		FlushRequest(Server *srv) : Request(srv, kRequestFlush) {}
+		FlushRequest(void) : Request((Server *)0, kRequestFlush) {}
+	};
+
+	class InvalidateRequest: public Request 
+	{
+	public:
+		InvalidateRequest(Server *srv) : Request(srv, kRequestInvalidate) {}
+	};
+
+	class SvrAdminRequest: public Request 
+	{
+	public:
+		SvrAdminRequest(Server *srv) : Request(srv, kRequestSvrAdmin) {}
+	};
+
+	class MonitorRequest: public Request 
+	{
+	public:
+		MonitorRequest(Server *srv) : Request(srv, kRequestMonitor){}
+	};
+
+	class Result 
+	{
+	private:
+		void *addr_;
+		long check;
+		Result(const Result &);
+		char *ServerInfo() const;
+	public:
+		friend class Server;
+		friend class Request;
+		friend class ServerPool;
+
+		Result(void);
+		~Result(void);
+		void Reset(void);
+
+		/* from will not dupped */
+		void set_error(int errcode, const char *from, const char *detail); 
+		int get_result_code(void) const;
+		const char *get_error_message(void) const;
+		const char *get_error_from(void) const;
+		long long get_hotbackup_id() const;
+		long long get_master_hotbackup_timestamp() const;
+		long long slave_hotbackup_timestamp() const;
+		long long get_binlog_id() const;
+		long long get_binlog_offset() const;
+		long long get_mem_size() const;
+		long long get_datd_size() const;
+		int get_num_row_size(void) const;
+		int get_total_rows_size(void) const;
+		int get_affected_rows_size(void) const;
+		int get_num_fields_size(void) const;
+		const char* get_field_name(int n) const;
+		int get_field_present(const char* name) const;
+		int get_field_type(int n) const;
+		long long get_tag(void) const;
+		void *get_tag_ptr(void) const;
+		long long magic(void) const;
+		long long get_server_timestamp(void) const;
+		long long get_insert_id(void) const;
+		long long int_key(void) const;
+		const char *binary_key(void) const;
+		const char *binary_key(int *) const;
+		const char *binary_key(int &) const;
+		const char *string_key(void) const;
+		const char *string_key(int *) const;
+		const char *string_key(int &) const;
+		long long int_value(const char *) const;
+		double float_value(const char *) const;
+		const char *string_value(const char *) const;
+		const char *string_value(const char *, int*) const;
+		const char *string_value(const char *, int&) const;
+		const char *binary_value(const char *) const;
+		const char *binary_value(const char *, int*) const;
+		const char *binary_value(const char *, int&) const;
+		int uncompress_binary_value(const char *name,char **buf,int *lenp);
+		/* Uncompress Binary Value without check compressflag */
+		int uncompress_binary_value_force(const char *name,char **buf,int *lenp);
+		const char * uncompress_error_message() const;
+		long long int_value(int) const;
+		double float_value(int) const;
+		const char *string_value(int) const;
+		const char *string_value(int, int*) const;
+		const char *string_value(int, int&) const;
+		const char *binary_value(int) const;
+		const char *binary_value(int, int*) const;
+		const char *binary_value(int, int&) const;
+		int fetch_row(void);
+		int rewind(void);
+	};
+
+	class ServerPool 
+	{
+	private:
+		void *addr_;
+		long check;
+		ServerPool(ServerPool &);
+	public:
+		friend class Server;
+		friend class Request;
+		friend class Result;
+
+		ServerPool(int max_servers, int max_requests);
+		~ServerPool(void);
+
+		int get_epoll_fd(int size);
+		int add_server(Server *srv, int mReq=1, int mConn=0);
+		int add_request(Request *, long long);
+		int add_request(Request *, long long, long long);
+		int add_request(Request *, long long, const char *);
+		int add_request(Request *, long long, const char *, int);
+		int add_request(Request *, void *);
+		int add_request(Request *, void *, long long);
+		int add_request(Request *, void *, const char *);
+		int add_request(Request *, void *, const char *, int);
+		int do_execute(int msec);
+		int execute_all(int msec);
+		int cancel_request(int);
+		int cancel_all_request(int type);
+		int abort_request(int);
+		int abort_all_request(int type);
+		Result *get_result(void);
+		Result *get_result(int);
+		int get_result(Result&);
+		int get_result(Result&, int);
+
+		int server_count(void) const;
+		int request_count(int type) const;
+		int request_state(int reqId) const;
+	};
+
+	const int WAIT = 1;
+	const int SEND = 2;
+	const int RECV = 4;
+	const int DONE = 8;
+	const int ALL_STATE = WAIT|SEND|RECV|DONE;
+
+	enum 
+	{
+		EC_ERROR_BASE = 2000,
+		/* unsupported command */
+		EC_BAD_COMMAND,		
+		/* missing mandatory section */
+		EC_MISSING_SECTION,	
+		/* incompatible section present */
+		EC_EXTRA_SECTION,	
+		/* same tag appear twice */
+		EC_DUPLICATE_TAG,
+
+		/* 5: same field appear twice in .need() */
+		EC_DUPLICATE_FIELD,	
+		/* section length too short */
+		EC_BAD_SECTION_LENGTH,	
+		/* value length not allow */
+		EC_BAD_VALUE_LENGTH,	
+		/* string value w/o NULL */
+		EC_BAD_STRING_VALUE,	
+		/* invalid float format */
+		EC_BAD_FLOAT_VALUE,	
+        /* 10: invalid total field */
+		EC_BAD_FIELD_NUM,	
+		/* section length too large */
+		EC_EXTRA_SECTION_DATA,	
+		/* incompatible value type */
+		EC_BAD_VALUE_TYPE,	
+		/* incompatible operator/comparison */
+		EC_BAD_OPERATOR,	
+		/* invalid field ID */
+		EC_BAD_FIELD_ID,	
+
+        /* 15: invalud field name */
+		EC_BAD_FIELD_NAME,	
+		/* invalid field type */
+		EC_BAD_FIELD_TYPE,	
+		/* invalid field size */
+		EC_BAD_FIELD_SIZE,	
+		/* table defined twice */
+		EC_TABLE_REDEFINED,	
+		/* request table != server table */
+		EC_TABLE_MISMATCH,	
+        
+		/* 20: unsupported protocol version */
+		EC_VERSION_MISMATCH,	
+		/* table hash not equal */
+		EC_CHECKSUM_MISMATCH,	
+		/* End of Result */
+		EC_NO_MORE_DATA,	
+		/* only full field set accepted by helper */
+		EC_NEED_FULL_FIELDSET,	
+		/* key type incompatible */
+		EC_BAD_KEY_TYPE,	
+
+        /* 25: key size incompatible */
+		EC_BAD_KEY_SIZE,
+		/* server error */
+		EC_SERVER_BUSY,		
+		/* network failed */
+		EC_BAD_SOCKET,		
+		/* object didn't initialized */
+		EC_NOT_INITIALIZED,	
+		EC_BAD_HOST_STRING,
+        
+		/* 30 */
+		EC_BAD_TABLE_NAME,	
+		EC_TASK_NEED_DELETE,
+		EC_KEY_NEEDED,
+		EC_SERVER_ERROR,
+		EC_UPSTREAM_ERROR,
+        
+		/* 35 */
+		EC_KEY_OVERFLOW,	
+		EC_BAD_MULTIKEY,
+		EC_READONLY_FIELD,
+		EC_BAD_ASYNC_CMD,
+		EC_OUT_OF_KEY_RANGE,
+
+        /* 40 */
+		EC_REQUEST_ABORTED,     
+		EC_PARALLEL_MODE,
+		EC_KEY_NOTEXIST,
+		EC_SERVER_READONLY,
+		EC_BAD_INVALID_FIELD,
+        
+		/* 45 */
+		EC_DUPLICATE_KEY,    	
+		EC_TOO_MANY_KEY_VALUE,
+		EC_BAD_KEY_NAME,
+		EC_BAD_RAW_DATA,
+		EC_BAD_HOTBACKUP_JID,
+        
+		/* 50 */
+		EC_FULL_SYNC_COMPLETE,  
+		EC_FULL_SYNC_STAGE,
+		EC_INC_SYNC_STAGE,
+        EC_ERR_SYNC_STAGE,
+        EC_NOT_ALLOWED_INSERT,
+        
+		/* 55 */
+        EC_COMPRESS_ERROR,  
+        EC_UNCOMPRESS_ERROR,
+        EC_TASKPOOL,
+        EC_STATE_ERROR,
+        EC_DATA_NEEDED,
+
+    	EC_TASK_TIMEOUT,
+        
+		/* 62 */
+        EC_BUSINESS_WITHOUT_EXPIRETIME, 
+        EC_EMPTY_TBDEF, 
+    	EC_INVALID_KEY_VALUE, 
+    	EC_INVALID_EXPIRETIME, 
+
+    	EC_GET_EXPIRETIME_END_OF_RESULT, 
+	};
+
+	enum 
+	{
+		ER_HASHCHK=1000,
+		ER_NISAMCHK=1001,
+		ER_NO=1002,
+		ER_YES=1003,
+		ER_CANT_CREATE_FILE=1004,
+		ER_CANT_CREATE_TABLE=1005,
+		ER_CANT_CREATE_DB=1006,
+		ER_DB_CREATE_EXISTS=1007,
+		ER_DB_DROP_EXISTS=1008,
+		ER_DB_DROP_DELETE=1009,
+		ER_DB_DROP_RMDIR=1010,
+		ER_CANT_DELETE_FILE=1011,
+		ER_CANT_FIND_SYSTEM_REC=1012,
+		ER_CANT_GET_STAT=1013,
+		ER_CANT_GET_WD=1014,
+		ER_CANT_LOCK=1015,
+		ER_CANT_OPEN_FILE=1016,
+		ER_FILE_NOT_FOUND=1017,
+		ER_CANT_READ_DIR=1018,
+		ER_CANT_SET_WD=1019,
+		ER_CHECKREAD=1020,
+		ER_DISK_FULL=1021,
+		ER_DUP_KEY=1022,
+		ER_ERROR_ON_CLOSE=1023,
+		ER_ERROR_ON_READ=1024,
+		ER_ERROR_ON_RENAME=1025,
+		ER_ERROR_ON_WRITE=1026,
+		ER_FILE_USED=1027,
+		ER_FILSORT_ABORT=1028,
+		ER_FORM_NOT_FOUND=1029,
+		ER_GET_ERRNO=1030,
+		ER_ILLEGAL_HA=1031,
+		ER_KEY_NOT_FOUND=1032,
+		ER_NOT_FORM_FILE=1033,
+		ER_NOT_KEYFILE=1034,
+		ER_OLD_KEYFILE=1035,
+		ER_OPEN_AS_READONLY=1036,
+		ER_OUTOFMEMORY=1037,
+		ER_OUT_OF_SORTMEMORY=1038,
+		ER_UNEXPECTED_EOF=1039,
+		ER_CON_COUNT_ERROR=1040,
+		ER_OUT_OF_RESOURCES=1041,
+		ER_BAD_HOST_ERROR=1042,
+		ER_HANDSHAKE_ERROR=1043,
+		ER_DBACCESS_DENIED_ERROR=1044,
+		ER_ACCESS_DENIED_ERROR=1045,
+		ER_NO_DB_ERROR=1046,
+		ER_UNKNOWN_COM_ERROR=1047,
+		ER_BAD_NULL_ERROR=1048,
+		ER_BAD_DB_ERROR=1049,
+		ER_TABLE_EXISTS_ERROR=1050,
+		ER_BAD_TABLE_ERROR=1051,
+		ER_NON_UNIQ_ERROR=1052,
+		ER_SERVER_SHUTDOWN=1053,
+		ER_BAD_FIELD_ERROR=1054,
+		ER_WRONG_FIELD_WITH_GROUP=1055,
+		ER_WRONG_GROUP_FIELD=1056,
+		ER_WRONG_SUM_SELECT=1057,
+		ER_WRONG_VALUE_COUNT=1058,
+		ER_TOO_LONG_IDENT=1059,
+		ER_DUP_FIELDNAME=1060,
+		ER_DUP_KEYNAME=1061,
+		ER_DUP_ENTRY=1062,
+		ER_WRONG_FIELD_SPEC=1063,
+		ER_PARSE_ERROR=1064,
+		ER_EMPTY_QUERY=1065,
+		ER_NONUNIQ_TABLE=1066,
+		ER_INVALID_DEFAULT=1067,
+		ER_MULTIPLE_PRI_KEY=1068,
+		ER_TOO_MANY_KEYS=1069,
+		ER_TOO_MANY_KEY_PARTS=1070,
+		ER_TOO_LONG_KEY=1071,
+		ER_KEY_COLUMN_DOES_NOT_EXITS=1072,
+		ER_BLOB_USED_AS_KEY=1073,
+		ER_TOO_BIG_FIELDLENGTH=1074,
+		ER_WRONG_AUTO_KEY=1075,
+		ER_READY=1076,
+		ER_NORMAL_SHUTDOWN=1077,
+		ER_GOT_SIGNAL=1078,
+		ER_SHUTDOWN_COMPLETE=1079,
+		ER_FORCING_CLOSE=1080,
+		ER_IPSOCK_ERROR=1081,
+		ER_NO_SUCH_INDEX=1082,
+		ER_WRONG_FIELD_TERMINATORS=1083,
+		ER_BLOBS_AND_NO_TERMINATED=1084,
+		ER_TEXTFILE_NOT_READABLE=1085,
+		ER_FILE_EXISTS_ERROR=1086,
+		ER_LOAD_INFO=1087,
+		ER_ALTER_INFO=1088,
+		ER_WRONG_SUB_KEY=1089,
+		ER_CANT_REMOVE_ALL_FIELDS=1090,
+		ER_CANT_DROP_FIELD_OR_KEY=1091,
+		ER_INSERT_INFO=1092,
+		ER_INSERT_TABLE_USED=1093,
+		ER_NO_SUCH_THREAD=1094,
+		ER_KILL_DENIED_ERROR=1095,
+		ER_NO_TABLES_USED=1096,
+		ER_TOO_BIG_SET=1097,
+		ER_NO_UNIQUE_LOGFILE=1098,
+		ER_TABLE_NOT_LOCKED_FOR_WRITE=1099,
+		ER_TABLE_NOT_LOCKED=1100,
+		ER_BLOB_CANT_HAVE_DEFAULT=1101,
+		ER_WRONG_DB_NAME=1102,
+		ER_WRONG_TABLE_NAME=1103,
+		ER_TOO_BIG_SELECT=1104,
+		ER_UNKNOWN_ERROR=1105,
+		ER_UNKNOWN_PROCEDURE=1106,
+		ER_WRONG_PARAMCOUNT_TO_PROCEDURE=1107,
+		ER_WRONG_PARAMETERS_TO_PROCEDURE=1108,
+		ER_UNKNOWN_TABLE=1109,
+		ER_FIELD_SPECIFIED_TWICE=1110,
+		ER_INVALID_GROUP_FUNC_USE=1111,
+		ER_UNSUPPORTED_EXTENSION=1112,
+		ER_TABLE_MUST_HAVE_COLUMNS=1113,
+		ER_RECORD_FILE_FULL=1114,
+		ER_UNKNOWN_CHARACTER_SET=1115,
+		ER_TOO_MANY_TABLES=1116,
+		ER_TOO_MANY_FIELDS=1117,
+		ER_TOO_BIG_ROWSIZE=1118,
+		ER_STACK_OVERRUN=1119,
+		ER_WRONG_OUTER_JOIN=1120,
+		ER_NULL_COLUMN_IN_INDEX=1121,
+		ER_CANT_FIND_UDF=1122,
+		ER_CANT_INITIALIZE_UDF=1123,
+		ER_UDF_NO_PATHS=1124,
+		ER_UDF_EXISTS=1125,
+		ER_CANT_OPEN_LIBRARY=1126,
+		ER_CANT_FIND_DL_ENTRY=1127,
+		ER_FUNCTION_NOT_DEFINED=1128,
+		ER_HOST_IS_BLOCKED=1129,
+		ER_HOST_NOT_PRIVILEGED=1130,
+		ER_PASSWORD_ANONYMOUS_USER=1131,
+		ER_PASSWORD_NOT_ALLOWED=1132,
+		ER_PASSWORD_NO_MATCH=1133,
+		ER_UPDATE_INFO=1134,
+		ER_CANT_CREATE_THREAD=1135,
+		ER_WRONG_VALUE_COUNT_ON_ROW=1136,
+		ER_CANT_REOPEN_TABLE=1137,
+		ER_INVALID_USE_OF_NULL=1138,
+		ER_REGEXP_ERROR=1139,
+		ER_MIX_OF_GROUP_FUNC_AND_FIELDS=1140,
+		ER_NONEXISTING_GRANT=1141,
+		ER_TABLEACCESS_DENIED_ERROR=1142,
+		ER_COLUMNACCESS_DENIED_ERROR=1143,
+		ER_ILLEGAL_GRANT_FOR_TABLE=1144,
+		ER_GRANT_WRONG_HOST_OR_USER=1145,
+		ER_NO_SUCH_TABLE=1146,
+		ER_NONEXISTING_TABLE_GRANT=1147,
+		ER_NOT_ALLOWED_COMMAND=1148,
+		ER_SYNTAX_ERROR=1149,
+		ER_DELAYED_CANT_CHANGE_LOCK=1150,
+		ER_TOO_MANY_DELAYED_THREADS=1151,
+		ER_ABORTING_CONNECTION=1152,
+		ER_NET_PACKET_TOO_LARGE=1153,
+		ER_NET_READ_ERROR_FROM_PIPE=1154,
+		ER_NET_FCNTL_ERROR=1155,
+		ER_NET_PACKETS_OUT_OF_ORDER=1156,
+		ER_NET_UNCOMPRESS_ERROR=1157,
+		ER_NET_READ_ERROR=1158,
+		ER_NET_READ_INTERRUPTED=1159,
+		ER_NET_ERROR_ON_WRITE=1160,
+		ER_NET_WRITE_INTERRUPTED=1161,
+		ER_TOO_LONG_STRING=1162,
+		ER_TABLE_CANT_HANDLE_BLOB=1163,
+		ER_TABLE_CANT_HANDLE_AUTO_INCREMENT=1164,
+		ER_DELAYED_INSERT_TABLE_LOCKED=1165,
+		ER_WRONG_COLUMN_NAME=1166,
+		ER_WRONG_KEY_COLUMN=1167,
+		ER_WRONG_MRG_TABLE=1168,
+		ER_DUP_UNIQUE=1169,
+		ER_BLOB_KEY_WITHOUT_LENGTH=1170,
+		ER_PRIMARY_CANT_HAVE_NULL=1171,
+		ER_TOO_MANY_ROWS=1172,
+		ER_REQUIRES_PRIMARY_KEY=1173,
+		ER_NO_RAID_COMPILED=1174,
+		ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE=1175,
+		ER_KEY_DOES_NOT_EXITS=1176,
+		ER_CHECK_NO_SUCH_TABLE=1177,
+		ER_CHECK_NOT_IMPLEMENTED=1178,
+		ER_CANT_DO_THIS_DURING_AN_TRANSACTION=1179,
+		ER_ERROR_DURING_COMMIT=1180,
+		ER_ERROR_DURING_ROLLBACK=1181,
+		ER_ERROR_DURING_FLUSH_LOGS=1182,
+		ER_ERROR_DURING_CHECKPOINT=1183,
+		ER_NEW_ABORTING_CONNECTION=1184,
+		ER_DUMP_NOT_IMPLEMENTED=   1185,
+		ER_FLUSH_MASTER_BINLOG_CLOSED=1186,
+		ER_INDEX_REBUILD= 1187,
+		ER_MASTER=1188,
+		ER_MASTER_NET_READ=1189,
+		ER_MASTER_NET_WRITE=1190,
+		ER_FT_MATCHING_KEY_NOT_FOUND=1191,
+		ER_LOCK_OR_ACTIVE_TRANSACTION=1192,
+		ER_UNKNOWN_SYSTEM_VARIABLE=1193,
+		ER_CRASHED_ON_USAGE=1194,
+		ER_CRASHED_ON_REPAIR=1195,
+		ER_WARNING_NOT_COMPLETE_ROLLBACK=1196,
+		ER_TRANS_CACHE_FULL=1197,
+		ER_SLAVE_MUST_STOP=1198,
+		ER_SLAVE_NOT_RUNNING=1199,
+		ER_BAD_SLAVE=1200,
+		ER_MASTER_INFO=1201,
+		ER_SLAVE_THREAD=1202,
+		ER_TOO_MANY_USER_CONNECTIONS=1203,
+		ER_SET_CONSTANTS_ONLY=1204,
+		ER_LOCK_WAIT_TIMEOUT=1205,
+		ER_LOCK_TABLE_FULL=1206,
+		ER_READ_ONLY_TRANSACTION=1207,
+		ER_DROP_DB_WITH_READ_LOCK=1208,
+		ER_CREATE_DB_WITH_READ_LOCK=1209,
+		ER_WRONG_ARGUMENTS=1210,
+		ER_NO_PERMISSION_TO_CREATE_USER=1211,
+		ER_UNION_TABLES_IN_DIFFERENT_DIR=1212,
+		ER_LOCK_DEADLOCK=1213,
+		ER_TABLE_CANT_HANDLE_FULLTEXT=1214,
+		ER_CANNOT_ADD_FOREIGN=1215,
+		ER_NO_REFERENCED_ROW=1216,
+		ER_ROW_IS_REFERENCED=1217,
+		ER_CONNECT_TO_MASTER=1218,
+		ER_QUERY_ON_MASTER=1219,
+		ER_ERROR_WHEN_EXECUTING_COMMAND=1220,
+		ER_WRONG_USAGE=1221,
+		ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT=1222,
+		ER_CANT_UPDATE_WITH_READLOCK=1223,
+		ER_MIXING_NOT_ALLOWED=1224,
+		ER_DUP_ARGUMENT=1225,
+		ER_USER_LIMIT_REACHED=1226,
+		ER_SPECIFIC_ACCESS_DENIED_ERROR=1227,
+		ER_LOCAL_VARIABLE=1228,
+		ER_GLOBAL_VARIABLE=1229,
+		ER_NO_DEFAULT=1230,
+		ER_WRONG_VALUE_FOR_VAR=1231,
+		ER_WRONG_TYPE_FOR_VAR=1232,
+		ER_VAR_CANT_BE_READ=1233,
+		ER_CANT_USE_OPTION_HERE=1234,
+		ER_NOT_SUPPORTED_YET=1235,
+		ER_MASTER_FATAL_ERROR_READING_BINLOG=1236,
+		ER_SLAVE_IGNORED_TABLE=1237,
+		ER_INCORRECT_GLOBAL_LOCAL_VAR=1238,
+		CR_UNKNOWN_ERROR=1900,
+		CR_SOCKET_CREATE_ERROR=1901,
+		CR_CONNECTION_ERROR=1902,
+		CR_CONN_HOST_ERROR=1903,
+		CR_IPSOCK_ERROR	=1904,
+		CR_UNKNOWN_HOST	=1905,
+		CR_SERVER_GONE_ERROR=1906,
+		CR_VERSION_ERROR=1907,
+		CR_OUT_OF_MEMORY=1908,
+		CR_WRONG_HOST_INFO=1909,
+		CR_LOCALHOST_CONNECTION=1910,
+		CR_TCP_CONNECTION=1911,
+		CR_SERVER_HANDSHAKE_ERR=1912,
+		CR_SERVER_LOST=1913,
+		CR_COMMANDS_OUT_OF_SYNC=1914,
+		CR_NAMEDPIPE_CONNECTION=1915,
+		CR_NAMEDPIPEWAIT_ERROR=1916,
+		CR_NAMEDPIPEOPEN_ERROR=1917,
+		CR_NAMEDPIPESETSTATE_ERROR=1918,
+		CR_CANT_READ_CHARSET=1919,
+		CR_NET_PACKET_TOO_LARGE=1920,
+		CR_EMBEDDED_CONNECTION=1921,
+		CR_PROBE_SLAVE_STATUS=1922,
+		CR_PROBE_SLAVE_HOSTS=1923,
+		CR_PROBE_SLAVE_CONNECT=1924,
+		CR_PROBE_MASTER_CONNECT=1925,
+		CR_SSL_CONNECTION_ERROR=1926,
+		CR_MALFORMED_PACKET=1927,
+		CR_WRONG_LICENSE=1928,
+	};
+
+	enum
+	{
+		ER_SET_IPLIST_NULL = 20001,
+		ER_SET_INSTANCE_PROPERTIES_ERR,
+		ER_KEY_TYPE,
+		ER_CC_VERSION_ERR,
+		ER_ROUTE_INFO_NULL,
+		ER_BID_VERSION_ERR,
+		ER_PORT_OUT_RANGE,
+		ER_STATUS_ERROR_VALUE,
+		ER_WEIGHT_ERROR_VALUE,
+		ER_IP_ERROR_VALUE,
+	};
+
+};
+
+#endif

+ 12 - 0
src/devel/cpp/dtcapi.lst

@@ -0,0 +1,12 @@
+{
+    global:
+	*DTC*;
+	__invoke_dynamic_linker__;
+	set_network_mode;
+    set_server_address;
+    set_server_tablename;
+
+    local:
+	*;
+};
+

+ 592 - 0
src/devel/cpp/dtcint.h

@@ -0,0 +1,592 @@
+#ifndef __CHC_CLI_H
+#define __CHC_CLI_H
+
+#include <table/table_def.h>
+#include <field/field_api.h>
+#include <packet/packet.h>
+#include <unistd.h>
+#include <dtc_error_code.h>
+#include <log/log.h>
+#include "key_list.h"
+#include <task/task_request.h>
+#include <container.h>
+#include <socket/socket_addr.h>
+#include "udppool.h"
+#include "algorithm/compress.h"
+#include "poll/poller_base.h"
+#include "lock/lock.h"
+#include <map>
+
+/*
+ * Goal:
+ * 	single transaction (*)
+ * 	batch transaction (*)
+ * 	async transaction
+ */
+
+
+#define HUNDRED 100
+#define THOUSAND 1000
+#define TENTHOUSAND 10000
+#define HUNDREDTHOUSAND 100000
+#define MILLION 1000000
+
+
+enum E_REPORT_TYPE
+{
+	RT_MIN,
+	RT_SHARDING,
+	RT_ALL,
+	RT_MAX
+};
+
+/* tp99 统计区间,单位us */
+static const uint32_t kpi_sample_count[] =
+{
+	200, 500, 1000,
+	2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000,
+	20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000, 100000,
+	200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000,
+	2000000, 500000, 10000000
+};
+
+
+class DtcJob;
+class Packet;
+
+class NCResult;
+class NCResultInternal;
+class NCPool;
+struct NCTransaction;
+class IDTCTaskExecutor;
+class IDTCService;
+
+class NCBase 
+{
+private:
+	AtomicU32 count_;
+
+public:
+	NCBase(void) {}
+	~NCBase(void) {}
+
+public:
+	int increase(void) { return ++count_; }
+	int decrease(void) { return --count_; }
+	int count(void) { return count_.get(); };
+};
+
+class NCRequest;
+class DataConnector;
+
+class NCServer: public NCBase  
+{
+public:
+    /* base settings */
+	SocketAddress addr_;
+	char *tablename_;
+	char *appname_;
+
+	/* dtc set server_address_ and server_tablename_ for plugin */
+    static char * server_address_;
+    static char * server_tablename_;
+
+	int keytype_;
+	int auto_update_table_;
+	int uto_reconnect_;
+    static int network_mode_;
+	NCKeyInfo keyinfo_;
+
+	static DataConnector *data_connector_;
+
+	/* error state */
+	unsigned completed_:1;
+	unsigned badkey_:1;
+	unsigned badname_:1;
+	unsigned autoping_:1;
+	const char *error_str_;
+
+	/* table definition */
+	DTCTableDefinition *table_definition_;
+	DTCTableDefinition *admin_tdef;  //==================================================================================================
+
+	std::string access_token_;
+	NCPool *owner_pool_;
+	int owner_id_;
+private: 
+    /* serialNr manupulation */
+	uint64_t last_serialnr_;
+	/* timeout settings */
+	int timeout_;
+	int realtmo_;
+	int compress_level_;
+	
+    /* sync execution */
+	IDTCService         *service_;
+	IDTCTaskExecutor    *executor_;
+	int                 netfd;                                 
+	time_t              last_action_;
+	NCRequest           *ping_request_;
+
+	uint64_t agent_time_;
+
+	/* add by neolv to QOS */
+	/* 原有的不变增加三个参数用于做QOS */
+	uint64_t error_count_;
+	/* 用于统计请求总数, 请求总数只对一个周期有效 */
+	uint64_t total_count_;
+	/* 用于统计请求总耗时, 请求总数只对一个周期有效 */
+	uint64_t total_elaps_;
+	/* 被摘次数 */
+	int remove_count_;
+public:	
+	NCServer();
+	NCServer(const NCServer &);
+	~NCServer(void);
+
+public:
+    /* for compress */
+    void set_compress_level(int level){compress_level_=level;}   
+    int get_compress_level(void){return compress_level_;}   
+
+	void clone_table_define(const NCServer& source);  
+	int set_address(const char *h, const char *p=NULL);  
+	int set_table_name(const char *);  
+	/* this addres is set by user */
+	const char * get_address(void) const { return addr_.Name(); }  
+	/* this address is set by dtc */
+	const char * get_server_address(void) const { return server_address_; }  
+	const char * get_server_table_name(void) const { return server_tablename_;}
+	int is_dgram(void) const { return addr_.socket_type()==SOCK_DGRAM; }  
+	int is_udp(void) const { return addr_.socket_type()==SOCK_DGRAM && addr_.socket_family()==AF_INET; }  
+	const char * get_table_name(void) const { return tablename_; }  
+	int int_key(void); 
+	int string_key(void); 
+	int get_field_type(const char*);
+	int is_completed(void) const { return completed_; } 
+	int add_key(const char* name, uint8_t type);  
+	int get_key_fields_count(void) const { return keyinfo_.get_key_fields_count() ? : keytype_ != DField::None ? 1 : 0; }  
+	int allow_batch_key(void) const { return keyinfo_.get_key_fields_count(); }
+	int simple_batch_key(void) const { return keyinfo_.get_key_fields_count()==1 && keytype_ == keyinfo_.get_key_type(0); }
+
+	void set_auto_Update_table(bool autoUpdate){ auto_update_table_ = autoUpdate?1:0; }  
+	void set_auto_reconnect(int reconnect){ uto_reconnect_ = reconnect; }  
+	
+	const char *get_error_message(void) const { return error_str_; }  
+
+	void save_definition(NCResult *);  
+	DTCTableDefinition* get_table_definition(int cmd) const;  
+	int set_accesskey(const char *token);  
+
+	uint64_t get_next_serialnr(void) { ++last_serialnr_; if(last_serialnr_==0) last_serialnr_++; return last_serialnr_; }  
+	uint64_t get_last_serialnr(void) { return last_serialnr_; } 
+
+	void set_timeout(int n); 
+	int get_timeout(void) const { return timeout_; }  
+
+	void set_agenttime(int t){agent_time_=t;}  
+	uint64_t get_agenttime(void){return agent_time_;}  
+
+	int Connect(void);  
+	int reconnect(void); 
+	void Close(void);   
+	void set_fd(int fd) {  Close(); netfd = fd; update_timeout(); }  
+	/* stream, connected */
+	int send_packet_stream(Packet &);  
+	int decode_result_stream(NCResult &); 
+	/* dgram, connected or connectless */
+	int send_packet_dgram(SocketAddress *peer, Packet &);
+	int decode_result_dgram(SocketAddress *peer, NCResult &);
+	/* connectless */
+	NCUdpPort *get_global_port(void);  
+	void put_global_port(NCUdpPort *);  
+
+	void try_ping(void);
+	int ping(void);
+	void auto_ping(void) { if(!is_dgram()) autoping_ = 1; }
+	NCResultInternal *execute_internal(NCRequest &rq, const DTCValue *kptr) { return executor_->task_execute(rq, kptr); }
+	int has_internal_executor(void) const { return executor_ != 0; }  
+
+	/* transaction manager, impl at dtcpool.cc */
+	int async_connect(int &);  
+	void set_owner(NCPool *, int);
+	NCResult *decode_buffer(const char *, int);
+	static int check_packet_size(const char *, int);
+
+	void increase_error_count_() { ++error_count_; }  
+	uint64_t get_error_count() { return error_count_; }  
+	void clear_error_count() { error_count_ = 0; } 
+    void increase_remove_count() { ++remove_count_; }  
+	int get_remove_count() { return remove_count_; }
+	void clear_remove_count() { remove_count_ = 0; }  
+    void increase_total_request() { ++total_count_; }  
+	uint64_t get_total_request() { return  total_count_; } 
+	void clear_total_request() { total_count_ = 0; }
+	void add_total_elaps(uint64_t iElaps) { total_elaps_ += iElaps; }  
+	uint64_t get_total_elaps() { return total_elaps_; }  
+	void clear_total_elaps() { total_elaps_ = 0; }  
+private:
+	int bind_temp_unix_socket(void);  
+	void update_timeout(void);  
+	void update_timeout_anyway(void);  
+	/* this method is weak, and don't exist in libdtc.a */
+	__attribute__((__weak__)) void check_internal_service(void);  
+};
+
+
+
+class NCRequest 
+{
+public:
+	NCServer *server;
+	uint8_t cmd;
+	uint8_t haskey;
+	uint8_t flags;
+	int err;
+	DTCValue key;
+	NCKeyValueList key_value_list_;
+	FieldValueByName ui;
+	FieldValueByName ci;
+	FieldSetByName fs;
+	
+	DTCTableDefinition *table_definition_;
+	char *tablename_;
+	int keytype_;
+
+	unsigned int limitStart;
+	unsigned int limitCount;
+	int adminCode;
+
+	uint64_t hotbackup_id;
+	uint64_t master_hotbackup_timestamp_;
+	uint64_t slave_hotbackup_timestamp_;
+
+private:
+	/* field flag */
+	uint64_t compressFlag;
+	DTCCompress *gzip;
+	int init_compress(void);
+	char errmsg_[1024];
+
+public:
+	NCRequest(NCServer *, int op);
+	~NCRequest(void);
+	
+public:
+	int attach_server(NCServer *);  
+
+	void enable_no_cache(void) { flags |= DRequest::Flag::no_cache; }  
+	void enable_no_next_server(void) { flags |= DRequest::Flag::no_next_server; } 
+	void add_condition(void) { flags |= DRequest::Flag::NoResult; }  
+	int add_condition(const char *n, uint8_t op, uint8_t t, const DTCValue &v);  
+	int add_operation(const char *n, uint8_t op, uint8_t t, const DTCValue &v);
+    int compress_set(const char *n,const char * v,int len);
+    int compress_set_force(const char *n,const char * v,int len);
+	int add_value(const char *n, uint8_t t, const DTCValue &v);  
+	int need(const char *n, int);
+	void limit(unsigned int st, unsigned int cnt) 
+	{
+		if(cnt==0)
+			st = 0;
+		limitStart = st;
+		limitCount = cnt;
+	}
+	
+	int set_key(int64_t);
+	int set_key(const char *, int);
+	int unset_key(void);
+	int unset_key_value(void);
+	int get_field_type(const char* name){ return server?server->get_field_type(name):DField::None; }
+	int add_key_value(const char* name, const DTCValue &v, uint8_t type);
+	int set_cache_id(int dummy) { return err = -EINVAL; }
+	void set_admin_code(int code){ adminCode = code; }
+	void set_hotbackup_id(uint64_t v){ hotbackup_id=v; }
+	void set_master_hotbackup_timestamp(uint64_t t){ master_hotbackup_timestamp_=t; }
+	void set_slave_hotbackup_timestamp(uint64_t t){ slave_hotbackup_timestamp_=t; }
+	
+	/* never return NULL */
+	NCResult *do_execute(const DTCValue *key=NULL);  
+	NCResult *execute_stream(const DTCValue *key=NULL);
+	NCResult *execute_dgram(SocketAddress *peer, const DTCValue *key = NULL);
+	NCResult *execute_network(const DTCValue *key=NULL);
+	NCResult *execute_internal(const DTCValue *key=NULL);
+	NCResult *do_execute(int64_t);
+	NCResult *do_execute(const char *, int);
+	/* sync execution */
+	NCResult *precheck(const DTCValue *key); 
+	/* need compress flag for read,or set compressFlag for write */
+    int set_compress_field_name(void);
+	int encode(const DTCValue *key, Packet *);
+	/* return 1 if tdef changed... */
+	int set_table_definition(void);
+
+	int encode_buffer(char *&ptr, int&len, int64_t &magic, const DTCValue *key=NULL);
+	int encode_buffer(char *&ptr, int&len, int64_t &magic, int64_t);
+	int encode_buffer(char *&ptr, int&len, int64_t &magic, const char *, int);
+    const char* get_error_message(void) const { return errmsg_; }
+
+    int set_expire_time(const char* key, int t);
+    int get_expire_time(const char* key);
+
+private:
+		int check_key(const DTCValue *kptr);
+        int set_compress_flag(const char * name)
+        {
+            if (table_definition_==NULL)
+                return -EC_NOT_INITIALIZED;
+            if (table_definition_->field_id(name) >= 64) {
+                snprintf(errmsg_, sizeof(errmsg_), "compress error:field id must less than 64"); 
+                return -EC_COMPRESS_ERROR;
+            }
+            compressFlag|=(1<<table_definition_->field_id(name));
+            return 0;
+        }
+};
+
+
+class NCResultLocal 
+{
+public:
+	const uint8_t *vidmap;
+	long long apiTag;
+	int maxvid;
+	DTCCompress *gzip;
+
+private:
+	DTCTableDefinition* _tdef;
+	uint64_t compressid;
+
+public:
+	NCResultLocal(DTCTableDefinition* tdef) :
+		vidmap(NULL),
+		apiTag(0),
+		maxvid(0),
+		gzip (NULL),
+		_tdef(tdef),
+	compressid(-1) {}
+
+	virtual ~NCResultLocal(void) 
+	{
+		FREE_CLEAR(vidmap);
+		DELETE (gzip);
+	}
+
+	virtual int field_id_virtual(int id) const { return id > 0 && id <= maxvid ? vidmap[id-1] : 0; } 
+
+	virtual void set_api_tag(long long t) { apiTag = t; } 
+	virtual long long get_api_tag(void) const { return apiTag; } 
+
+	void set_virtual_map(FieldSetByName &fs) 
+	{
+		if(fs.max_virtual_id()) {
+			fs.Resolve(_tdef, 0);
+			vidmap = fs.virtual_map();
+			maxvid = fs.max_virtual_id();
+		}
+	}
+
+	virtual int init_compress()   
+	{
+		if(NULL == _tdef)
+			return -EC_CHECKSUM_MISMATCH;
+
+		int iret = 0;
+		compressid = _tdef->compress_field_id();
+		if(compressid<0) return 0;
+		if(gzip == NULL)
+			NEW(DTCCompress,gzip);
+		if (gzip == NULL)
+			return -ENOMEM;
+		iret = gzip->set_buffer_len(_tdef->max_field_size());
+		if(iret) 
+			return iret;
+		return 0;
+	}
+	virtual const int compress_id (void)const { return compressid; } 
+};
+
+class NCResult: public NCResultLocal, public DtcJob
+{
+public:
+	NCResult(DTCTableDefinition *tdef) : NCResultLocal(tdef), DtcJob(tdef, TaskRoleClient, 0) 
+	{
+		if(tdef) tdef->increase();
+		mark_allow_remote_table();
+	}
+
+	NCResult(int err, const char *from, const char *msg) : NCResultLocal(NULL), DtcJob(NULL, TaskRoleClient, 1) 
+	{
+		resultInfo.set_error_dup(err, from, msg);
+	}
+	virtual ~NCResult() 
+	{
+		DTCTableDefinition *tdef = table_definition();
+		DEC_DELETE(tdef);
+	}
+};
+
+
+class NCResultInternal: public NCResultLocal, public DTCJobOperation
+{
+public:
+	NCResultInternal(DTCTableDefinition* tdef=NULL) : NCResultLocal (tdef){}
+
+	virtual ~NCResultInternal() {}
+
+	static inline int verify_class(void)  
+	{
+		NCResultInternal *ir = 0;
+		NCResult *er = reinterpret_cast<NCResult *>(ir);
+
+		NCResultLocal *il = (NCResultLocal *) ir;
+		NCResultLocal *el = (NCResultLocal *) er;
+
+		DtcJob *it = (DtcJob *) ir;
+		DtcJob *et = (DtcJob *) er;
+
+		long dl = reinterpret_cast<char *>(il) - reinterpret_cast<char *>(el);
+		long dt = reinterpret_cast<char *>(it) - reinterpret_cast<char *>(et);
+		return dl==0 && dt==0;
+	}
+};
+
+
+/* 模调上报 */
+class DataConnector
+{
+private:
+	struct businessStatistics
+	{
+		/* 10s内请求总耗时 */
+		uint64_t TotalTime;		
+		/* 10s内请求总次数 */
+		uint32_t TotalRequests;		
+	public:
+		businessStatistics(){ TotalTime = 0; TotalRequests = 0; }
+	};
+	struct bidCurve
+	{
+		uint32_t bid;
+		uint32_t curve;
+        bool operator < (const bidCurve &that) const
+		{
+			int sum1 = bid * 10 + curve;
+			int sum2 = that.bid * 10 + that.curve;
+			return sum1 < sum2;
+        }
+	};
+	struct top_percentile_statistics
+	{
+		uint32_t uiBid;
+		uint32_t uiAgentIP;
+		uint16_t uiAgentPort;
+		/* 10s内请求总次数 */
+		uint32_t uiTotalRequests;	
+		/* 10s内请求总耗时 */
+		uint64_t uiTotalTime;		
+		/* 10s内错误次数 */
+		uint32_t uiFailCount;	
+		/* 10s内的最大执行时间 */	
+		uint64_t uiMaxTime;	
+		/* 10s内的最小执行时间 */	
+		uint64_t uiMinTime;	
+		/* 统计值 */		
+		uint32_t statArr[sizeof(kpi_sample_count) / sizeof(kpi_sample_count[0])];	
+		
+		public:
+		top_percentile_statistics()
+		{
+			uiBid = 0;
+			uiAgentIP = 0;
+			uiAgentPort = 0;
+			uiTotalRequests = 0;
+			uiTotalTime = 0;
+			uiFailCount = 0;
+			uiMaxTime = 0;
+			uiMinTime = 0;
+			memset(statArr, 0, sizeof(statArr));
+		}
+		top_percentile_statistics(const top_percentile_statistics &that)
+		{
+			this->uiBid = that.uiBid;
+			this->uiAgentIP = that.uiAgentIP;
+			this->uiAgentPort = that.uiAgentPort;
+			this->uiTotalRequests = that.uiTotalRequests;
+			this->uiTotalTime = that.uiTotalTime;
+			this->uiFailCount = that.uiFailCount;
+			this->uiMaxTime = that.uiMaxTime;
+			this->uiMinTime = that.uiMinTime;
+			memcpy(this->statArr, that.statArr, sizeof(this->statArr));
+		}
+		top_percentile_statistics &operator =(const top_percentile_statistics &that)
+		{
+			this->uiBid = that.uiBid;
+			this->uiAgentIP = that.uiAgentIP;
+			this->uiAgentPort = that.uiAgentPort;
+			this->uiTotalRequests = that.uiTotalRequests;
+			this->uiTotalTime = that.uiTotalTime;
+			this->uiFailCount = that.uiFailCount;
+			this->uiMaxTime = that.uiMaxTime;
+			this->uiMinTime = that.uiMinTime;
+			memcpy(this->statArr, that.statArr, sizeof(this->statArr));
+
+			return *this;
+		}
+	};
+
+private:
+	std::map<bidCurve, businessStatistics> mapBi;
+	/* 读写  TotalTime、TotalRequests时,加锁,防止脏数据 */
+	Mutex lock_;			
+	std::map<uint64_t, top_percentile_statistics> map_tp_stat_;
+	/* 读写 tp99 数据时,加锁,防止脏数据 */
+	Mutex m_tp_lock;	
+	static DataConnector *pDataConnector;
+	pthread_t thread_id_;
+	DataConnector();
+	~DataConnector();
+
+public:
+    static DataConnector* getInstance()  
+	{
+		if( pDataConnector == NULL)
+			pDataConnector = new DataConnector();
+		return pDataConnector;
+	};
+
+	int send_data();
+	int set_report_info(const std::string str, const uint32_t curve, const uint64_t t);   
+	void get_report_info(std::map<bidCurve, businessStatistics> &mapData); 
+	int set_bussiness_id(std::string str);
+	
+	int send_top_percentile_data(); 
+	int set_top_percentile_data(const std::string strAccessKey, const std::string strAgentAddr, const uint64_t elapse, const int status);
+	void get_top_percentile_data(std::map<uint64_t, top_percentile_statistics> &mapStat);  
+	int set_top_percentile_config(std::string strAccessKey, const std::string strAgentAddr);
+		
+private:
+	int parse_address(const std::string strAddr, uint64_t *uipIP = NULL, uint64_t *uipPort = NULL); 
+};
+
+
+class CTopPercentileSection
+{
+private:
+	/* 执行时间小于1000us的 */
+	static int16_t get_little_thousand(uint64_t elapse); 
+	/* 执行时间大于等于1000us 小于 10000us的 */
+	static int16_t get_between_thousand_and_tenthousand(uint64_t elapse);
+	/* 执行时间大于等于10000us 小于 100000us的 */
+	static int16_t get_between_tenthousand_and_hundredthousand(uint64_t elapse);
+	/* 执行时间大于等于100000us 小于 1000000us的 */
+	static int16_t get_between_hundredthousand_and_million(uint64_t elapse);
+	/* 执行时间大于等于1000000us的 */
+	static int16_t get_exceed_million(uint64_t elapse);
+	
+public:
+	static int16_t get_tp_section(uint64_t elapse);
+};
+#endif
+
+
+

+ 1009 - 0
src/devel/cpp/dtcpool.cc

@@ -0,0 +1,1009 @@
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <linux/sockios.h>
+
+#include "socket/unix_socket.h"
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include "poll/myepoll.h"
+
+#include "dtcpool.h"
+
+// must be bitwise
+enum {
+	RS_IDLE = 0,
+	RS_WAIT = 1,
+	RS_SEND = 2,
+	RS_RECV = 4,
+	RS_DONE = 8,
+};
+
+enum {
+	SS_CONNECTED = 0,
+	SS_LINGER = 1,
+	SS_CLOSED = 1,
+	SS_CONNECTING = 2,
+};
+
+#define MAXREQID 2147483646L
+
+NCPool::NCPool(int ms, int mr)
+	:
+	EpollOperation(1024+16)
+{
+	int i;
+
+	if(ms > (1<<20))
+		ms = 1<<20;
+	if(mr > (1<<20))
+		mr = 1<<20;
+
+	max_servers = ms;
+	max_requests = mr;
+	max_request_id = MAXREQID / max_requests;
+
+	server_list = new NCServerInfo[max_servers];
+	// needn't zero init
+	num_servers = 0;
+
+	trans_list = new NCTransaction[max_requests];
+	for(i=0; i<max_requests; i++)
+	{
+		trans_list[i].ListAdd(&free_list);;
+	}
+	num_requests = 0;
+
+	done_requests = 0;
+
+	init_flag = -1;
+	buf = NULL;
+}
+
+NCPool::~NCPool()
+{
+	int i;
+
+	DELETE_ARRAY(server_list);
+	if(trans_list)
+	{
+		for(i=0; i<max_requests; i++)
+		{
+		}
+
+		DELETE_ARRAY(trans_list);
+	}
+	DELETE_ARRAY(buf);
+}
+
+/* add server to pool */
+int NCPool::add_server(NCServer *server, int mReq, int mConn)
+{
+	if(server->owner_pool_ != NULL)
+		return -EINVAL;
+
+	if(num_servers >= max_servers)
+		return -E2BIG;
+
+	if(server->is_dgram())
+	{
+		if(mConn == 0)
+			mConn = 1;
+		else if(mConn != 1)
+			return -EINVAL;
+	} else {
+		if(mConn == 0)
+			mConn = mReq;
+		else if(mConn > mReq)
+			return -EINVAL;
+	}
+
+	server->set_owner(this, num_servers);
+	server_list[num_servers].do_init(server, mReq, mConn);
+	num_servers++;
+	return 0;
+}
+
+/* switch basic server to async mode */
+void NCServer::set_owner(NCPool *owner, int id)
+{
+	Close();
+	owner_id_ = id;;
+	owner_pool_ = owner;
+	increase();
+}
+
+/* async connect, high level */
+int NCServer::async_connect(int &netfd)
+{
+	int err = -EC_NOT_INITIALIZED;
+	netfd = -1;
+
+	if(addr_.socket_family() != 0) {
+		netfd = addr_.create_socket();
+		if(netfd < 0) {
+			err = -errno;
+		} else if(addr_.socket_family()==AF_UNIX && is_dgram() && bind_temp_unix_socket() < 0) {
+			err = -errno;
+			close(netfd);
+			netfd = -1;
+		} else {
+			fcntl(netfd, F_SETFL, O_RDWR|O_NONBLOCK);
+			if(addr_.connect_socket(netfd)==0)
+				return 0;
+			err = -errno;
+			if(err!=-EINPROGRESS) 
+			{
+				close(netfd);
+				netfd = -1;
+			}
+		}
+	}
+	return err;
+}
+
+NCConnection::NCConnection(NCPool *owner, NCServerInfo *si)
+	:
+	EpollBase(owner),
+	timer(this)
+{
+	server_info = si;
+	sreq = NULL;
+	state = SS_CLOSED;
+	result = NULL;
+}
+
+NCConnection::~NCConnection(void)
+{
+	if(state==SS_CONNECTING)
+		/* decrease connecting count */
+		server_info->connecting_done();
+	/* remove partial result */
+	DELETE(result);
+	/* remove from all connection queue */
+	list_del();
+	/* abort all associated requests */
+	abort_requests(-EC_REQUEST_ABORTED);
+	server_info->more_closed_connection_and_ready();
+}
+
+/* connection is idle again */
+void NCConnection::switch_to_idle(void)
+{
+	if(state==SS_CONNECTING)
+		/* decrease connecting count */
+		server_info->connecting_done();
+	ListMove(&server_info->idle_list);
+	server_info->connection_idle_and_ready();
+	state = SS_CONNECTED;
+	disable_output();
+	enable_input();
+	timer.disable_timer();
+	/* ApplyEvnets by caller */
+}
+
+/* prepare connecting state, wait for EPOLLOUT */
+void NCConnection::switch_to_connecting(void)
+{
+	state = SS_CONNECTING;
+	timer.attach_timer(server_info->timerList);
+	ListMove(&server_info->busy_list);
+	disable_input();
+	enable_output();
+	// no apply events, following AttachPoller will do it */
+}
+
+/* try async connecting */
+int NCConnection::Connect(void)
+{
+	int err = server_info->info->async_connect(netfd);
+	if(err == 0) {
+		switch_to_idle();
+		/* treat epollsize overflow as fd overflow */
+		if(attach_poller() < 0)
+			return -EMFILE;
+		/* AttachPoller will ApplyEvents automatically */
+	} else if(err == -EINPROGRESS) {
+		switch_to_connecting();
+		/* treat epollsize overflow as fd overflow */
+		if(attach_poller() < 0)
+			return -EMFILE;
+		/* AttachPoller will ApplyEvents automatically */
+	}
+
+	return err;
+}
+
+/* Link connection & transaction */
+void NCConnection::process_request(NCTransaction *r)
+{
+	/* linkage between connection & transaction */
+	sreq = r;
+	sreq->attach_connection(this);
+
+	/* adjust server connection statistics */
+	list_move_tail(&server_info->busy_list);
+	server_info->request_scheduled();
+
+	/* initial timing and flushing */
+	timer.attach_timer(server_info->timerList);
+	send_request();
+}
+
+/* abort all requests associated transaction */
+void NCConnection::abort_requests(int err)
+{
+	if(sreq)
+	{
+		sreq->Abort(err);
+		sreq = NULL;
+	}
+	while(req_list.ListEmpty()==0)
+	{
+		NCTransaction *req = req_list.NextOwner();
+		req->Abort(err);
+	}
+}
+
+/* abort sending transaction, linger connection for RECV request */
+void NCConnection::abort_send_side(int err)
+{
+	if(sreq)
+	{
+		sreq->Abort(err);
+		sreq = NULL;
+	}
+	if(!is_async() || req_list.ListEmpty())
+		Close(err);
+	else
+	{
+		// async connection, lingering
+		ListMove(&server_info->busy_list);
+		state = SS_LINGER;
+		timer.attach_timer(server_info->timerList);
+	}
+}
+
+/* close a connection */
+void NCConnection::Close(int err)
+{
+	abort_requests(err);
+	if(is_dgram()==0)
+		delete this;
+	/* UDP has not connection close */
+}
+
+/* a valid result received */
+void NCConnection::done_result(void)
+{
+	if(result)
+	{
+		/* searching SN */
+		ListObject<NCTransaction> *reqPtr = req_list.ListNext();
+		while(reqPtr != &req_list)
+		{
+			NCTransaction *req = reqPtr->ListOwner();
+			if(req->MatchSN(result))
+			{
+				/* SN matched, transaction is dont */
+				req->done(result);
+				result = NULL;
+				break;
+			}
+			reqPtr = reqPtr->ListNext();
+		}
+		DELETE(result);
+	}
+	if(is_async()==0) {
+		/*
+		 * SYNC server, switch to idle state,
+		 * ASYNC server always idle, no switch needed
+		 */
+		switch_to_idle();
+		apply_events();
+	} else if(state == SS_LINGER) {
+		/* close LINGER connection if all result done */
+		if(req_list.ListEmpty())
+			delete this;
+	}
+	/*
+	// disabled because async server should trigger by req->done
+	else
+		server_info->mark_as_ready();
+		*/
+}
+
+/* hangup by recv zero bytes */
+int NCConnection::check_hangup(void)
+{
+	if(is_async())
+		return 0;
+	char buf[1];
+	int n = recv(netfd, buf, sizeof(buf), MSG_DONTWAIT|MSG_PEEK);
+	return n >= 0;
+}
+
+/*
+ * sending result, may called by other component
+ * apply events is required
+ */
+void NCConnection::send_request(void)
+{
+	int ret = sreq->Send(netfd);
+	timer.disable_timer();
+	switch (ret)
+	{
+		case SendResultMoreData:
+			/* more data to send, enable EPOLLOUT and timer */
+			enable_output();
+			apply_events();
+			timer.attach_timer(server_info->timerList);
+			break;
+
+		case SendResultDone:
+			/* send OK, disable output and enable receiving */
+			disable_output();
+			enable_input();
+			sreq->send_ok(&req_list);
+			sreq = NULL;
+			server_info->request_sent();
+			/* fire up receiving timer */
+			timer.attach_timer(server_info->timerList);
+			if(is_async())
+			{
+				list_move_tail(&server_info->idle_list); 
+				server_info->connection_idle_and_ready();
+			}
+#if 0
+			else {
+				/* fire up receiving logic */
+				recv_result();
+			}
+#endif
+			apply_events();
+			break;
+
+		default:
+			abort_send_side(-ECONNRESET);
+			break;
+	}
+}
+
+int NCConnection::recv_result(void)
+{
+	int ret;
+	if(result==NULL)
+	{
+		result = new NCResult(server_info->info->table_definition_);
+		receiver.attach(netfd);
+		receiver.erase();
+	}
+	if(is_dgram())
+	{
+		if(server_info->owner->buf==NULL)
+			server_info->owner->buf = new char[65536];
+		ret = recv(netfd, server_info->owner->buf, 65536, 0);
+		if(ret <= 0)
+			ret = DecodeFatalError;
+		else
+			ret = result->do_decode(server_info->owner->buf, ret);
+	} else
+		ret = result->do_decode(receiver);
+	timer.disable_timer();
+	switch (ret)
+	{
+		default:
+		case DecodeFatalError:
+			Close(-ECONNRESET);
+			return -1; // connection bad
+			break;
+
+		case DecodeDataError:
+			done_result();
+			// more result maybe available
+			ret = 1;
+			break;
+
+		case DecodeIdle:
+		case DecodeWaitData:
+			// partial or no result available yet
+			ret = 0;
+			break;
+			
+		case DecodeDone:
+			server_info->info->save_definition(result);
+			done_result();
+			// more result maybe available
+			ret = 1;
+			break;
+	}
+	if(sreq || !req_list.ListEmpty())
+		timer.attach_timer(server_info->timerList);
+	return ret;
+}
+
+void NCConnection::input_procedure(void)
+{
+	switch(state) {
+		case SS_CONNECTED:
+			while(1) {
+				if(recv_result() <= 0)
+					break;
+			}
+			break;
+		case SS_LINGER:
+			while(req_list.ListEmpty()==0) {
+				if(recv_result() <= 0)
+					break;
+			}
+		default:
+			break;
+	}
+}
+
+void NCConnection::output_procedure(void)
+{
+	switch(state)
+	{
+	case SS_CONNECTING:
+		switch_to_idle();
+		break;
+	case SS_CONNECTED:
+		send_request();
+		break;
+	default:
+		disable_output();
+		break;
+	}
+}
+
+void NCConnection::hang_procedure(void)
+{
+	if(state==SS_CONNECTING) {
+		server_info->connecting_failed();
+	}
+	abort_requests(-ECONNRESET);
+	delete this;
+}
+
+void NCConnection::job_timer_procedure(void)
+{
+	if(sreq || !req_list.ListEmpty())
+	{
+		Close(-ETIMEDOUT);
+	}
+}
+
+NCServerInfo::NCServerInfo(void)
+{
+	info = NULL;
+}
+
+NCServerInfo::~NCServerInfo(void)
+{
+	while(!idle_list.ListEmpty())
+	{
+		NCConnection *conn = idle_list.NextOwner();
+		delete conn;
+	}
+
+	while(!busy_list.ListEmpty())
+	{
+		NCConnection *conn = busy_list.NextOwner();
+		delete conn;
+	}
+
+	while(!req_list.ListEmpty())
+	{
+		NCTransaction *trans = req_list.NextOwner();
+		trans->Abort(-EC_REQUEST_ABORTED);
+	}
+
+	if(info && info->decrease()==0)
+		delete info;
+}
+
+void NCServerInfo::do_init(NCServer *server, int maxReq, int maxConn)
+{
+	info = server;
+	req_list.ResetList();
+	idle_list.ResetList();
+	busy_list.ResetList();
+
+	req_wait = 0;
+	req_send = 0;
+	req_recv = 0;
+	req_remain = maxReq;
+
+	conn_remain = maxConn;
+	connTotal = maxConn;
+	conn_connecting = 0;
+	conn_error = 0;
+	owner = server->owner_pool_;
+	int to = server->get_timeout();
+	if(to <= 0) to = 3600 * 1000; // 1 hour
+	timerList = owner->get_timer_list_by_m_seconds( to );
+
+	mode = server->is_dgram() ? 2 : maxReq==maxConn ? 0 : 1;
+}
+
+int NCServerInfo::Connect(void)
+{
+	NCConnection *conn = new NCConnection(owner, this);
+	conn_remain--;
+	int err = conn->Connect();
+	if(err==0) {
+		/* pass */;
+	} else if(err==-EINPROGRESS) {
+		conn_connecting++;
+		err = 0; /* NOT a ERROR */
+	} else {
+		conn_remain++;
+		delete conn;
+		conn_error++;
+	}
+	return err;
+}
+
+void NCServerInfo::abort_wait_queue(int err)
+{
+	while(!req_list.ListEmpty())
+	{
+		NCTransaction *trans = req_list.NextOwner();
+		trans->Abort(err);
+	}
+}
+
+void NCServerInfo::job_timer_procedure()
+{
+	while(req_remain>0 && !req_list.ListEmpty())
+	{
+		if(!idle_list.ListEmpty())
+		{
+			// has something to do
+			NCConnection *conn = idle_list.NextOwner();
+
+			conn->process_request(get_request_from_queue());
+		} else {
+			// NO connection available
+			if(conn_remain == 0)
+				break;
+			// need more connection to process
+			if(conn_connecting >= req_wait)
+				break;
+
+			int err;
+			// connect error, abort processing
+			if((err=Connect()) != 0)
+			{
+				if(conn_remain>=connTotal)
+					abort_wait_queue(err);
+				break;
+			}
+		}
+	}
+	/* no more work, clear bogus ready timer */
+	TimerObject::disable_timer();
+	/* reset connect error count */
+	conn_error = 0;
+}
+
+void NCServerInfo::request_done_and_ready(int state) {
+	switch(state) {
+		case RS_WAIT:
+			req_wait--; // Abort a queued not really ready
+			break;
+		case RS_SEND:
+			req_send--;
+			req_remain++;
+			mark_as_ready();
+			break;
+		case RS_RECV:
+			req_recv--;
+			req_remain++;
+			mark_as_ready();
+			break;
+	}
+}
+
+NCTransaction::NCTransaction(void)
+{
+}
+
+NCTransaction::~NCTransaction(void)
+{
+	DELETE(packet);
+	DELETE(result);
+}
+
+/* clear transaction state */
+void NCTransaction::Clear(void)
+{
+	/* detach from list, mostly free_list */
+	ListObject<NCTransaction>::ResetList();
+
+	/* increase reqId */
+	genId++;
+
+	/* reset local state */
+	state = RS_IDLE;
+	reqTag = 0;;
+	server = NULL;
+	packet = NULL;
+	result = NULL;
+}
+
+/* get transaction result */
+NCResult * NCTransaction::get_result(void) {
+	NCResult *ret = result;
+	ret->set_api_tag(reqTag);
+	DELETE(packet);
+	Clear();
+	return ret;
+}
+
+/* attach new request to transaction slot */
+int NCTransaction::attach_request(NCServerInfo *info, long long tag, NCRequest *req, DTCValue *key) {
+	state = RS_WAIT;
+	reqTag = tag;
+	server = info;
+	packet = new Packet;
+	int ret = req->encode(key, packet);
+	if(ret < 0) {
+		/* encode error */
+		result = new NCResult(ret, "API::encoding", "client encode packet error");
+	} else {
+		SN = server->info->get_last_serialnr();
+	}
+	return ret;
+}
+
+extern inline void NCTransaction::attach_connection(NCConnection *c) {
+	state = RS_SEND;
+	conn = c;
+}
+
+extern inline void NCTransaction::send_ok(ListObject<NCTransaction> *queue) {
+	state = RS_RECV;
+	ListAddTail(queue);
+}
+
+extern inline void NCTransaction::recv_ok(ListObject<NCTransaction> *queue) {
+	state = RS_DONE;
+	ListAddTail(queue);
+}
+
+/* abort current transaction, zero means succ */
+void NCTransaction::Abort(int err)
+{
+	if(server == NULL) // empty slot or done
+		return;
+
+	//Don't reverse abort connection, just clear linkage
+	//NCConnection *c = conn;
+	//DELETE(c);
+	conn = NULL;
+
+	NCPool *owner = server->owner;
+	list_del();
+
+	server->request_done_and_ready(state);
+	server = NULL;
+
+	if(err)
+	{
+		result = new NCResult(err, "API::aborted", "client abort request");
+	}
+	
+	owner->transaction_finished(this);
+}
+
+NCResult *NCPool::get_transaction_result(NCTransaction *req)
+{
+	NCResult *ret = req->get_result();
+	done_requests--;
+	num_requests--;
+	req->ListAdd(&free_list);
+	return ret;
+}
+
+/* get transaction slot for new request */
+NCTransaction * NCPool::get_transaction_slot(void)
+{
+	NCTransaction *trans = free_list.NextOwner();
+	trans->Clear();
+	trans->round_gen_id(max_request_id);
+	num_requests ++;
+	return trans;
+}
+
+void NCPool::transaction_finished(NCTransaction *trans)
+{
+	trans->recv_ok(&done_list);
+	done_requests++;
+}
+
+int NCPool::add_request(NCRequest *req, long long tag, DTCValue *key)
+{
+	int ret;
+	if(num_requests >= max_requests)
+	{
+		return -E2BIG;
+	}
+
+	if(req->server == NULL)
+	{
+	    return -EC_NOT_INITIALIZED;
+	}
+
+	NCServer *server = req->server;
+	if(server->owner_pool_ == NULL)
+	{
+		ret = add_server(server, 1);
+		if(ret < 0)
+			return ret;
+	}
+
+	if(server->owner_pool_ != this)
+	{
+		return -EINVAL;
+	}
+
+	if(key==NULL && req->haskey) key = &req->key;
+
+	NCTransaction *trans = get_transaction_slot();
+	NCServerInfo *info = &server_list[server->owner_id_];
+
+	if(trans->attach_request(info, tag, req, key) < 0)
+	{
+		// attach error, result already prepared */
+		transaction_finished(trans);
+	} else {
+		info->queue_request(trans);
+	}
+
+	return (trans-trans_list) + trans->GenId() * max_requests + 1;
+}
+
+void NCPool::execute_one_loop(int timeout)
+{
+	wait_poller_events(timeout);
+	uint64_t now = GET_TIMESTAMP();
+	process_poller_events();
+	check_expired(now);
+	check_ready();
+}
+
+int NCPool::do_execute(int timeout)
+{
+	if(timeout > 3600000) timeout = 3600000;
+	initialize_poller_unit();
+	execute_one_loop(0);
+	if(done_requests > 0)
+		return done_requests;
+	int64_t till = GET_TIMESTAMP() + timeout * TIMESTAMP_PRECISION / 1000;
+	while(done_requests <= 0)
+	{
+		int64_t exp = till - GET_TIMESTAMP();
+		if(exp < 0)
+			break;
+		int msec;
+#if TIMESTAMP_PRECISION > 1000
+		msec = exp / (TIMESTAMP_PRECISION/1000);
+#else
+		msec = exp * 1000/TIMESTAMP_PRECISION;
+#endif
+		execute_one_loop(expire_micro_seconds(msec, 1));
+	}
+	return done_requests;
+}
+
+int NCPool::execute_all(int timeout)
+{
+	if(timeout > 3600000) timeout = 3600000;
+	initialize_poller_unit();
+	execute_one_loop(0);
+	if(num_requests <= done_requests)
+		return done_requests;
+	int64_t till = GET_TIMESTAMP() + timeout * TIMESTAMP_PRECISION / 1000;
+	while(num_requests > done_requests)
+	{
+		int64_t exp = till - GET_TIMESTAMP();
+		if(exp < 0)
+			break;
+		int msec;
+#if TIMESTAMP_PRECISION > 1000
+		msec = exp / (TIMESTAMP_PRECISION/1000);
+#else
+		msec = exp * 1000/TIMESTAMP_PRECISION;
+#endif
+		execute_one_loop(expire_micro_seconds(msec, 1));
+	}
+	return done_requests;
+}
+
+int NCPool::initialize_poller_unit(void)
+{
+	if(init_flag==-1)
+	{
+		init_flag = EpollOperation::initialize_poller_unit() >= 0;
+	}
+	return init_flag;
+}
+
+int NCPool::get_epoll_fd(int mp)
+{
+	if(init_flag == -1 && mp > EpollOperation::get_max_pollers())
+		EpollOperation::set_max_pollers(mp);
+	initialize_poller_unit();
+	return EpollOperation::get_fd();
+}
+
+NCTransaction * NCPool::Id2Req(int reqId) const
+{
+	if(reqId <= 0 || reqId > MAXREQID)
+		return NULL;
+	reqId--;
+	NCTransaction *req = &trans_list[reqId % max_requests];
+	if(reqId / max_requests != req->GenId())
+		return NULL;
+	return req;
+}
+
+
+int NCPool::abort_request(NCTransaction *req)
+{
+	if(req->conn)
+	{
+		/* send or recv state */
+		if(req->server->mode==0)
+		{	// SYNC, always close connecction
+			req->conn->Close(-EC_REQUEST_ABORTED);
+		} else if(req->server->mode==1)
+		{	// ASYNC, linger connection for other result, abort send side
+			if(req->State()==RS_SEND)
+				req->conn->abort_send_side(-EC_REQUEST_ABORTED);
+			else 
+				req->Abort(-EC_REQUEST_ABORTED);
+		} else { // UDP, abort request only
+			req->Abort(-EC_REQUEST_ABORTED);
+		}
+		return 1;
+	}
+	else if(req->server)
+	{
+		/* waiting state, abort request only */
+		req->Abort(-EC_REQUEST_ABORTED);
+		return 1;
+	}
+	return 0;
+}
+
+int NCPool::cancel_request(int reqId)
+{
+	NCTransaction *req = Id2Req(reqId);
+	if(req==NULL)
+		return -EINVAL;
+
+	abort_request(req);
+	NCResult *res = get_transaction_result(req);
+	DELETE(res);
+	return 1;
+}
+
+int NCPool::cancel_all_request(int type)
+{
+	int n = 0;
+	if((type & ~0xf) != 0)
+		return -EINVAL;
+	for(int i=0; i<max_requests; i++)
+	{
+		NCTransaction *req = &trans_list[i];
+		if((type & req->State()))
+		{
+			abort_request(req);
+			NCResult *res = get_transaction_result(req);
+			DELETE(res);
+			n++;
+		}
+	}
+	return n;
+}
+
+int NCPool::abort_request(int reqId)
+{
+	NCTransaction *req = Id2Req(reqId);
+	if(req==NULL)
+		return -EINVAL;
+
+	return abort_request(req);
+}
+
+int NCPool::abort_all_request(int type)
+{
+	int n = 0;
+	if((type & ~0xf) != 0)
+		return -EINVAL;
+	type &= ~RS_DONE;
+	for(int i=0; i<max_requests; i++)
+	{
+		NCTransaction *req = &trans_list[i];
+		if((type & req->State()))
+		{
+			abort_request(req);
+			n++;
+		}
+	}
+	return n;
+}
+
+NCResult *NCPool::get_result(int reqId)
+{
+	NCTransaction *req;
+	if(reqId==0)
+	{
+		if(done_list.ListEmpty())
+			return (NCResult *)-EAGAIN;
+		req = done_list.NextOwner();
+	} else {
+		req = Id2Req(reqId);
+		if(req==NULL) return (NCResult *)-EINVAL;
+
+		if(req->State() != RS_DONE)
+			return (NCResult *)((long)req->State());
+	}
+	return get_transaction_result(req);
+}
+
+int NCServerInfo::count_request_state(int type) const
+{
+	int n = 0;
+	if((type & RS_WAIT))
+		n += req_wait;
+	if((type & RS_SEND))
+		n += req_send;
+	if((type & RS_RECV))
+		n += req_recv;
+	return n;
+}
+
+int NCPool::count_request_state(int type) const
+{
+	int n = 0;
+#if 0
+	for(int i=0; i<max_requests; i++)
+	{
+		if((type & trans_list[i].State()))
+			n++;
+	}
+#else
+	for(int i=0; i<max_servers; i++)
+	{
+		if(server_list[i].info==NULL)
+			continue;
+		n += server_list[i].count_request_state(type);
+	}
+	if((type & RS_DONE))
+		n += done_requests;
+#endif
+	return n;
+}
+
+int NCPool::request_state(int reqId) const
+{
+	NCTransaction *req = Id2Req(reqId);
+	if(req==NULL)
+		return -EINVAL;
+
+	return req->State();
+}
+

+ 275 - 0
src/devel/cpp/dtcpool.h

@@ -0,0 +1,275 @@
+#ifndef __CHC_CLI_POOL_H
+#define __CHC_CLI_POOL_H
+
+#include <sys/poll.h>
+
+#include "list/list.h"
+#include "poll/poller.h"
+#include "timer/timer_list.h"
+#include "dtcint.h"
+#include "dtc_error_code.h"
+
+class NCServerInfo;
+class NCPool;
+class NCConnection;
+
+// transaction is a internal async request
+class NCTransaction :
+	public ListObject<NCTransaction>
+{
+public:
+	// constructor/destructor equiv
+	NCTransaction(void);
+	~NCTransaction(void);
+	/* clear transaction state */
+	void Clear(void);
+	/* abort current transaction, zero means succ */
+	void Abort(int);
+	/* transaction succ with result */
+	void done(NCResult *res) { result = res; Abort(0); }
+	/* get transaction result */
+	NCResult * get_result(void);
+	/* adjust generation id */
+	void round_gen_id(int m) { if(genId >= m) genId = 0; }
+
+	/* state & info management */
+	int State(void) const { return state; }
+	int GenId(void) const { return genId; }
+	int MatchSN(NCResult *res) const { return SN == res->versionInfo.serial_nr(); }
+	/* send packet management */
+	int Send(int fd) { return packet->Send(fd); }
+	int attach_request(NCServerInfo *s, long long tag, NCRequest *req, DTCValue *key);
+	void attach_connection(NCConnection *c);
+	void send_ok(ListObject<NCTransaction>*);
+	void recv_ok(ListObject<NCTransaction>*);
+
+public: // constant member declare as static
+	// owner info, associated server
+	NCServerInfo *server;
+	// attached connection, SEND, RECV
+	NCConnection *conn;
+
+private:// transient members is private
+	// current transaction state, WAIT, SEND, RECV, DONE
+	int state;
+	// internal transaction generation id
+	int genId;
+	// associated request tag
+	long long reqTag;
+	// associated request SN, state SEND, RECV
+	uint64_t SN;
+
+	// sending packet
+	Packet *packet;
+
+	// do_execute result
+	NCResult *result;
+};
+
+class NCConnection :
+	public ListObject<NCConnection>,
+	public EpollBase
+{
+public:
+	NCConnection(NCPool *, NCServerInfo *);
+	~NCConnection(void);
+
+	int is_dgram(void) const;
+	int is_async(void) const;
+	/* starting state machine, by NCServerInfo::connect */
+	int Connect(void);
+	/* attach transaction to connection */
+	void process_request(NCTransaction *);
+	/* flush send channel */
+	void send_request(void);
+	/* flush recv channel */
+	int recv_result(void);
+	/* check connection hangup, recv zero bytes */
+	int check_hangup(void);
+
+	/* abort all associated request */
+	void abort_requests(int err);
+	/* close connection */
+	void Close(int err);
+	/* abort current sending request, linger recv channel */
+	void abort_send_side(int err);
+	/* a valid result received */
+	void done_result(void);
+	/* connection is idle, usable for transaction */
+	void switch_to_idle(void);
+	/* connection is async connecting */
+	void switch_to_connecting(void);
+
+	virtual void input_procedure(void);
+	virtual void output_procedure(void);
+	virtual void hang_procedure(void);
+	virtual void job_timer_procedure(void);
+
+private:
+	/* associated server */
+	NCServerInfo *server_info;
+	/* queued transaction in RECV state */
+	ListObject<NCTransaction> req_list;
+	/* sending transaction */
+	NCTransaction *sreq;
+	/* decoding/decoded result */
+	NCResult *result;
+	/* connection state */
+	int state;
+
+	int NETFD(void) const { return netfd; }
+
+private:
+	TimerMember<NCConnection> timer;
+	SimpleReceiver receiver;
+};
+
+typedef ListObject<NCConnection> NCConnectionList;
+
+class NCPool :
+	public EpollOperation,
+	public TimerUnit
+{
+public:
+	NCPool(int max_servers, int max_requests);
+	~NCPool();
+
+	int initialize_poller_unit(void);
+
+	int get_epoll_fd(int maxpoller);
+	int add_server(NCServer *srv, int maxReq=1, int maxConn=0);
+	int add_request(NCRequest *req, long long tag, DTCValue *key=0);
+
+	void execute_one_loop(int timeout);
+	int do_execute(int timeout);
+	int execute_all(int timeout);
+	
+	NCTransaction *Id2Req(int) const;
+	int cancel_request(int);
+	int cancel_all_request(int);
+	int abort_request(NCTransaction *);
+	int abort_request(int);
+	int abort_all_request(int);
+	NCResult *get_result(void);
+	NCResult *get_result(int);
+
+	int count_request_state(int) const;
+	int request_state(int) const;
+public:
+	NCTransaction * get_transaction_slot(void);
+	void transaction_finished(NCTransaction *);
+	NCResult * get_transaction_result(NCTransaction *);
+	int get_transaction_state(NCTransaction *);
+
+	int server_count(void) const { return num_servers; }
+	int request_count(void) const { return num_requests; }
+	int done_request_count(void) const { return done_requests; }
+private:
+	int init_flag;
+	int max_servers;
+	int max_requests;
+	int num_servers;
+	int num_requests;
+	int max_request_id;
+	int done_requests;
+	ListObject<NCTransaction> free_list;
+	ListObject<NCTransaction> done_list;
+	NCServerInfo *server_list;
+	NCTransaction *trans_list;
+public:
+	char *buf;
+};
+
+class NCServerInfo :
+	private TimerObject
+{
+public:
+	NCServerInfo(void);
+	~NCServerInfo(void);
+	void do_init(NCServer *, int, int);
+
+	/* prepare wake TimerNotify */
+	void mark_as_ready() { attach_ready_timer(owner); }
+	virtual void job_timer_procedure(void);
+	/* four reason server has more work to do */
+	/* more transaction attached */
+	void more_request_and_ready(void) { req_wait++; mark_as_ready(); }
+	/* more close connection, should reconnecting */
+	void more_closed_connection_and_ready(void) { conn_remain++; mark_as_ready(); }
+	/* more idle connection available */
+	void connection_idle_and_ready(void) { mark_as_ready(); }
+	/* more request can assign to idle pool */
+	void request_done_and_ready(int oldstate);
+
+	/* one request scheduled to SEND state */
+	void request_scheduled(void) { req_remain--; req_send++; }
+	void request_sent(void) { req_send--; req_recv++; }
+
+	/* queue transaction to this server */
+	void queue_request(NCTransaction *req)
+	{
+		req->ListAddTail(&req_list);
+		more_request_and_ready();
+	}
+	/* one connecting aborted */
+	void connecting_failed(void) { conn_error++; }
+	void connecting_done(void) { conn_connecting--; }
+
+	/* abort all waiting transactions */
+	void abort_wait_queue(int err);
+
+	int count_request_state(int type) const;
+
+	/* get a waiting transaction */
+	NCTransaction * get_request_from_queue(void)
+	{
+		NCTransaction *trans = req_list.NextOwner();
+		trans->list_del();
+		req_wait--;
+		return trans;
+	}
+
+private:
+	int Connect(void);
+	ListObject<NCTransaction> req_list;
+
+public: // constant member declare as public
+	/* associated ServerPool */
+	NCPool *owner;
+	/* basic server info */
+	NCServer *info;
+	TimerList *timerList;
+	int mode; // 0--TCP 1--ASYNC 2--UDP
+	/* total connection */
+	int connTotal;
+
+private:// transient member is private
+
+	/* transaction in state WAIT */
+	int req_wait;
+	/* transaction in state SEND */
+	int req_send;
+	/* transaction in state RECV */
+	int req_recv;
+	/* remain requests can assign to connection pool */
+	int req_remain;
+
+	/* remain connections can connect */
+	int conn_remain;
+	/* number connections in connecting state */
+	int conn_connecting;
+	/* number of connect error this round */
+	int conn_error;
+	/* busy connection count */
+	inline int conn_working(void) const { return connTotal - conn_connecting - conn_remain; }
+public: //except idle_list for code conventional
+	/* idle connection list */
+	NCConnectionList idle_list;
+	/* busy connection list SEND,RECV,LINGER */
+	NCConnectionList busy_list;
+};
+
+inline int NCConnection::is_dgram(void) const { return server_info->mode==2; }
+inline int NCConnection::is_async(void) const { return server_info->mode; }
+
+#endif

+ 734 - 0
src/devel/cpp/dtcqossvr.cc

@@ -0,0 +1,734 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>  
+#include <sys/stat.h>
+#include <time.h>
+#include <fcntl.h>
+
+#include "protocol.h"
+
+#include "dtcapi.h"
+#include "dtcint.h"
+#include "dtcqossvr.h"
+
+using namespace DTC;
+
+/* linux-2.6.38.8/include/linux/compiler.h */
+//# define likely(x)	__builtin_expect(!!(x), 1)
+//# define unlikely(x)	__builtin_expect(!!(x), 0)
+
+#define random(x) (rand()%x)
+
+const uint32_t ACCESS_KEY_LEN = 40;
+
+DTCQosServer::DTCQosServer():m_status(0), m_weight(0), m_remove_time_stamp(0), 
+								m_last_remove_time(0), m_max_time_stamp(0), m_server(NULL)
+{
+}
+
+DTCQosServer::~DTCQosServer()
+{
+	if (this->m_server != NULL){
+		delete this->m_server;
+		this->m_server = NULL;
+	}
+} 
+
+DTCServers::DTCServers()
+	:m_time_out(50), m_agent_time(0), m_key_type(0), m_table_name(NULL),
+	m_set_route(false), m_constructed_by_set_i_ps(false), m_bid(0),
+	m_idc_no(0), m_buckets_pos(0), m_balance_bucket_size(0), m_bid_version(0),
+	m_last_get_ca_time(0), m_refresh_buckets_time(0), m_remove_buckets_time(0),
+	m_load_balance_buckets(NULL), m_qos_severs(NULL)
+{
+}
+
+DTCServers::~DTCServers()
+{
+	if(this->m_table_name) {
+		free(this->m_table_name);
+		this->m_table_name = NULL;
+	}
+
+	if(this->m_load_balance_buckets) {
+		free(this->m_load_balance_buckets);
+		this->m_load_balance_buckets = NULL;
+	}
+
+	if(this->m_qos_severs) {
+		delete[] this->m_qos_severs;
+		this->m_qos_severs = NULL;
+	}
+}
+
+void print_ip_node(ROUTE_NODE RouteNode)
+{
+	printf("\n");
+	printf("\t bid = %d \n", RouteNode.bid);
+	printf("\t ip = %s \n", RouteNode.ip);
+	printf("\t port = %d \n", RouteNode.port);
+	printf("\t weight = %d \n", RouteNode.weight);
+	printf("\t status = %d \n", RouteNode.status);
+	printf("\n");
+}
+
+void DTCServers::set_error_msg(int err, std::string from, std::string msg)
+{
+	char buffer[1000];
+	memset(buffer, 0, 1000);
+	sprintf(buffer, "ERROR CODE %d, FROM %s ERRMSG %s", err, from.c_str(), msg.c_str());
+	std::string ErrMsg(buffer);
+	this->m_err_msg.clear();
+	this->m_err_msg = ErrMsg;
+}
+
+std::string DTCServers::get_error_msg()
+{
+	return this->m_err_msg;
+}
+
+int InvalidIpaddr(char *str)
+{
+   if(str == NULL || *str == '\0')
+      return 1;
+
+   union
+   {
+      struct sockaddr addr;
+      struct sockaddr_in6 addr6;
+      struct sockaddr_in addr4;
+   } a;
+   memset(&a, 0, sizeof(a));
+   if(1 == inet_pton(AF_INET, str, &a.addr4.sin_addr))
+      return 0;
+   else if(1 == inet_pton(AF_INET6, str, &a.addr6.sin6_addr))
+      return 0;
+   return 1;
+}
+
+int DTCServers::set_route_list(std::vector<ROUTE_NODE>& IPList)
+{
+	if(IPList.empty())
+		return -ER_SET_IPLIST_NULL;
+	std::vector<ROUTE_NODE>().swap(this->m_ip_list);	
+	std::vector<ROUTE_NODE>::iterator it = IPList.begin();
+	for(; it != IPList.end(); ++it) {
+		ROUTE_NODE ip;
+		ip.bid = it->bid;
+		if(it->port > 0 && it->port <= 65535) {
+			ip.port = it->port;
+		} else {
+			set_error_msg(ER_PORT_OUT_RANGE, "DTCServers::set_route_list", "port is out of range!");
+			return -ER_PORT_OUT_RANGE;
+		}
+		if(it->status == 0 || it->status == 1) {
+			ip.status = it->status;
+		} else {
+			set_error_msg(ER_STATUS_ERROR_VALUE, "DTCServers::set_route_list", "status is error value!");
+			return -ER_STATUS_ERROR_VALUE;
+		}
+		if(it->weight > 0) {
+			ip.weight = it->weight;
+		} else {
+			set_error_msg(ER_WEIGHT_ERROR_VALUE, "DTCServers::set_route_list", "weight is error value!");
+			return -ER_WEIGHT_ERROR_VALUE;
+		}
+		if(InvalidIpaddr(it->ip) == 0) {
+			memcpy(ip.ip, it->ip, IP_LEN);
+		} else {
+			set_error_msg(ER_IP_ERROR_VALUE, "DTCServers::set_accesskey", "ip is error value!");
+			return -ER_IP_ERROR_VALUE;
+		}
+#ifdef DEBUG_INFO
+		print_ip_node(ip);	
+#endif
+		this->m_ip_list.push_back(ip);
+	}
+	this->m_set_route = true;
+
+	return 0;
+}
+
+void DTCServers::set_idc_no(int IDCNo)
+{
+	this->m_idc_no = IDCNo;
+}
+
+int DTCServers::set_accesskey(const char *token)
+{
+	std::string str;
+	if(token == NULL)
+		return -EC_BAD_ACCESS_KEY;
+	else
+		str = token;                                                     
+	if(str.length() != ACCESS_KEY_LEN) {
+		log4cplus_error("Invalid accessKey!");
+		this->m_access_token = "";
+		set_error_msg(EC_BAD_ACCESS_KEY, "DTCServers::set_accesskey", "Invalid accessKey!");
+		return -EC_BAD_ACCESS_KEY;
+	} else
+		this->m_access_token = str;
+
+	std::string stemp = str.substr(0, 8);
+	sscanf(stemp.c_str(), "%d", &(this->m_bid));
+	return 0;
+}
+
+int DTCServers::set_table_name(const char *tableName)
+{
+	if(tableName==NULL) return -DTC::EC_BAD_TABLE_NAME;
+
+	if(this->m_table_name)
+		return mystrcmp(tableName, this->m_table_name, 256)==0 ? 0 : -DTC::EC_BAD_TABLE_NAME; 
+
+	this->m_table_name = STRDUP(tableName);
+
+	return 0;
+}
+
+int DTCServers::set_key_type(int type)
+{
+	switch(type) {
+		case DField::Signed:
+		case DField::Unsigned:
+		case DField::Float:
+		case DField::String:
+		case DField::Binary:
+			this->m_key_type = type;
+			break;
+		default:
+			return -DTC::EC_BAD_KEY_TYPE;
+			break; 
+	}
+	return 0;
+}
+
+void DTCServers::set_agenttime(int t)
+{
+	this->m_agent_time = t;
+}
+
+void DTCServers::set_timeout(int n)
+{
+	this->m_time_out = n<=0 ? 5000 : n;
+}
+
+int DTCServers::construct_servers()
+{
+	if(this->m_ip_list.empty()) {
+		log4cplus_error("ip list is empty!");
+		set_error_msg(ER_SET_IPLIST_NULL, "DTCServers::construct_servers", "ip list is empty!");
+		return -ER_SET_IPLIST_NULL;
+	}
+	
+	if(this->m_access_token.empty() || (this->m_table_name == NULL) || (this->m_key_type == 0)) {
+		log4cplus_error("m_access_token m_table_name or m_key_type is unset");
+		set_error_msg(ER_SET_INSTANCE_PROPERTIES_ERR, "DTCServers::construct_servers", "m_access_token m_table_name or m_key_type is unset!");
+		return -ER_SET_INSTANCE_PROPERTIES_ERR;
+	}
+
+	int i = 0;
+	int ret = 0;
+	char tmpPort[7];
+	memset(tmpPort, 0, sizeof(tmpPort));	
+	
+	if(this->m_qos_severs) {
+		delete[] this->m_qos_severs;
+		this->m_qos_severs = NULL;
+	}
+ 	int IPCount = this->m_ip_list.size();
+	this->m_qos_severs = new DTCQosServer[IPCount];
+	for( ; i < IPCount; ++i) {
+		this->m_qos_severs[i].create_dtc_server();
+		Server *server = this->m_qos_severs[i].get_dtc_server();
+		sprintf(tmpPort, "%d", this->m_ip_list[i].port);
+		ret = server->set_address(this->m_ip_list[i].ip, tmpPort);
+		if(ret < 0) {
+			if(this->m_qos_severs) {
+				delete[] this->m_qos_severs;
+				this->m_qos_severs = NULL;  
+			}                      
+			return -ret;
+		}
+		
+		this->m_qos_severs[i].set_weight(this->m_ip_list[i].weight);
+		this->m_qos_severs[i].set_status(this->m_ip_list[i].status);
+		ret = server->set_table_name(this->m_table_name);
+		if(ret < 0) {
+			if(this->m_qos_severs) {
+				delete[] this->m_qos_severs;
+				this->m_qos_severs = NULL;  
+			}                      
+			return -ret;
+		}
+		server->set_accesskey(this->m_access_token.c_str());	
+		switch(this->m_key_type) {
+			case DField::Signed:
+			case DField::Unsigned:
+				server->int_key();
+				break;
+			case DField::String:
+				server->string_key();
+				break;
+			case DField::Binary:
+				server->string_key();
+				break;
+			case DField::Float:
+			default:
+				{
+					log4cplus_error("key type is wrong!");
+					if(this->m_qos_severs) {
+						delete[] this->m_qos_severs;
+						this->m_qos_severs = NULL;  
+					}                      
+					set_error_msg(ER_KEY_TYPE, "DTCServers::construct_servers", "key type is wrong!");
+					return -ER_KEY_TYPE;
+				}
+				break;
+		}	
+		if(this->m_time_out > 0)
+			server->set_timeout(this->m_time_out);
+	}
+	return 0;
+}
+
+int DTCServers::is_server_has_existed(ROUTE_NODE& ip)
+{
+	unsigned int i;
+	for (i = 0; i < this->m_ip_list.size(); i++) {
+		if((ip.port == this->m_ip_list[i].port) && (strncmp(ip.ip, this->m_ip_list[i].ip, IP_LENGHT) == 0))
+			return i;
+	}
+	return -1;
+}
+
+int DTCServers::construct_servers2(std::vector<ROUTE_NODE>& IPList)
+{
+	if(IPList.empty()) {
+		log4cplus_error("ip list is empty!");
+		set_error_msg(ER_SET_IPLIST_NULL, "DTCServers::construct_servers2", "ip list is empty!");
+		return -ER_SET_IPLIST_NULL;
+	}
+	if(this->m_access_token.empty() || (this->m_table_name == NULL) || (this->m_key_type == 0)) {
+		log4cplus_error("m_access_token m_table_name or m_key_type is unset");
+		set_error_msg(ER_SET_INSTANCE_PROPERTIES_ERR, "DTCServers::construct_servers2", "m_access_token m_table_name or m_key_type is unset!");
+		return -ER_SET_INSTANCE_PROPERTIES_ERR;
+	}
+
+	int i = 0;
+	int ret = 0;
+	char tmpPort[7];
+	memset(tmpPort, 0, sizeof(tmpPort));
+
+	int IPCount = IPList.size();
+	DTCQosServer* tmpQosServer = new DTCQosServer[IPCount];
+	for ( ; i < IPCount; i++) {
+		int idx = is_server_has_existed(IPList[i]);
+		if (idx >= 0) {
+			tmpQosServer[i].set_weight(IPList[i].weight);
+			tmpQosServer[i].set_status(IPList[i].status);
+			tmpQosServer[i].set_remove_time_stamp(this->m_qos_severs[idx].get_remove_time_stamp());
+			tmpQosServer[i].set_last_remove_time(this->m_qos_severs[idx].get_last_remove_time());
+			tmpQosServer[i].set_max_time_stamp(this->m_qos_severs[idx].get_max_time_stamp());
+			tmpQosServer[i].set_dtc_server(this->m_qos_severs[idx].get_dtc_server());
+			this->m_qos_severs[idx].reset_dtc_server();
+		} else {
+			tmpQosServer[i].create_dtc_server();
+			Server *server = tmpQosServer[i].get_dtc_server();
+			sprintf(tmpPort, "%d", IPList[i].port);
+			ret = server->set_address(IPList[i].ip, tmpPort);
+			if(ret < 0) {
+				if(this->m_qos_severs)
+				{
+					delete[] this->m_qos_severs;
+					this->m_qos_severs = NULL;  
+				}   
+				delete[] tmpQosServer;                  
+				return -ret;
+			}
+			tmpQosServer[i].set_weight(IPList[i].weight);
+			tmpQosServer[i].set_status(IPList[i].status);
+			ret = server->set_table_name(this->m_table_name);
+			if(ret < 0) {
+				if(this->m_qos_severs) {
+					delete[] this->m_qos_severs;
+					this->m_qos_severs = NULL;  
+				}
+				delete[] tmpQosServer;                 
+				return -ret;
+			}
+			server->set_accesskey(this->m_access_token.c_str());
+			switch(this->m_key_type) {
+				case DField::Signed:
+				case DField::Unsigned:
+					server->int_key();
+					break;
+				case DField::String:
+					server->string_key();
+					break;
+				case DField::Binary:
+					server->string_key();
+					break;
+				case DField::Float:
+				default:
+					{
+						log4cplus_error("key type is wrong!");
+						if(this->m_qos_severs) {
+							delete[] this->m_qos_severs;
+							this->m_qos_severs = NULL;  
+						}
+						delete[] tmpQosServer;
+						set_error_msg(ER_KEY_TYPE, "DTCServers::construct_servers2", "key type is wrong!");
+						return -ER_KEY_TYPE;
+					}
+					break;
+			}
+			if(this->m_time_out > 0)
+				server->set_timeout(this->m_time_out);
+		}
+	}
+	std::vector<ROUTE_NODE>().swap(this->m_ip_list);
+	if(this->m_qos_severs) {
+		delete[] this->m_qos_severs;
+		this->m_qos_severs = NULL;
+	}
+	this->m_qos_severs = tmpQosServer;
+	tmpQosServer = NULL;
+	return 0;
+}
+
+void init_random()
+{
+	uint64_t ticks;
+	struct timeval tv;
+	int fd;
+	gettimeofday(&tv, NULL);
+	ticks = tv.tv_sec + tv.tv_usec;
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd > 0) {
+		uint64_t r;
+		int i;
+		for (i = 0; i <100 ; i++) {
+			read(fd, &r, sizeof(r));
+			ticks += r;
+		}
+		close(fd);
+	}
+	srand(ticks);
+}
+
+unsigned int new_rand()
+{
+	int fd;
+	unsigned int n = 0;
+	fd = open("/dev/urandom", O_RDONLY);
+	if(fd > 0)
+		read(fd, &n, sizeof(n));
+	close (fd);
+	return n;
+}
+
+void DTCServers::disorder_list(int *tmpBuckets, int size)
+{
+    int randCount = 0;// 索引
+    unsigned int position = 0;// 位置
+    int k = 0;
+//    srand((int)time(0));
+    do{
+        int r = size - randCount;
+//        position = random(r);
+		init_random();
+		unsigned int tmp = new_rand();
+        position = tmp%r;
+        this->m_load_balance_buckets[k++] = tmpBuckets[position];
+        randCount++; 
+		 // 将最后一位数值赋值给已经被使用的position
+        tmpBuckets[position] = tmpBuckets[r - 1];   
+    }while(randCount < size);  
+    return ; 
+}
+
+int DTCServers::construct_balance_buckets()
+{
+	if(!this->m_qos_severs || this->m_ip_list.empty()) {
+		log4cplus_error("QOSSevers is null or ip count <0 ");
+		set_error_msg(ER_ROUTE_INFO_NULL, "DTCServers::construct_balance_buckets", "QOSSevers is null or ip count <0!");
+		return -ER_ROUTE_INFO_NULL;
+	}
+
+	int i = 0;
+	int totalCount = 0;
+	int IPCount = this->m_ip_list.size();
+	for( ; i < IPCount; ++i) {
+		totalCount += this->m_qos_severs[i].m_weight;	
+	}
+	FREE_IF(this->m_load_balance_buckets);
+	this->m_load_balance_buckets = (int *)malloc(sizeof(int) * totalCount);
+	this->m_balance_bucket_size = totalCount;
+	int* tmpBuckets = (int *)malloc(sizeof(int) * totalCount);
+	int j = 0;
+	int pos = 0;
+	for( ; j < IPCount; ++j) {
+		int k = 0;
+		for( ; k < this->m_qos_severs[j].m_weight; ++k) {
+			tmpBuckets[pos] = j; 
+			pos ++;
+		}
+	}
+	this->m_buckets_pos = 0;
+	disorder_list(tmpBuckets, totalCount);
+//	FREE_IF(tmpBuckets);
+	FREE_CLEAR(tmpBuckets);
+	return 0;
+} 
+
+void DTCServers::remove_server_from_buckets(uint64_t now)
+{
+	int i = 0;
+	int IPCount = this->m_ip_list.size();
+	for( ; i < IPCount; ++i) {
+		if(0 == this->m_qos_severs[i].get_status())
+			continue;
+		uint64_t errorCount = this->m_qos_severs[i].get_dtc_server()->get_error_count();
+		if(errorCount >= DEFAULT_REMOVE_ERROR_COUNT) {
+			this->m_qos_severs[i].get_dtc_server()->increase_remove_count();
+			uint64_t removeTime = this->m_qos_severs[i].get_dtc_server()->get_remove_count() * DEFAULT_ROUTE_INTERVAL_TIME;
+			if(removeTime >= DEFAULT_MAX_REMOVE_THRESHOLD_TIME)
+				removeTime = DEFAULT_MAX_REMOVE_THRESHOLD_TIME;
+			this->m_qos_severs[i].set_remove_time_stamp(removeTime);
+			this->m_qos_severs[i].set_last_remove_time(now);
+			this->m_qos_severs[i].set_status(0);
+			log4cplus_debug("bid=[%d], remove time=[%lu], now=[%lu], address=[%s], pos=[%d]!", \
+					this->m_bid, removeTime, now, this->m_qos_severs[i].get_dtc_server()->get_address(), i);
+#ifdef DEBUG_INFO 
+			printf("remove bid=[%d],now=[%lu],remvoe timeStamp=[%lu],remove count=[%d],address=[%s]!\n", \
+					this->m_bid, now, removeTime, this->m_qos_severs[i].get_dtc_server()->get_remove_count(), \
+					this->m_qos_severs[i].get_dtc_server()->get_address()); 
+#endif
+		}
+	}
+}
+
+int DTCServers::refresh_balance_buckets(uint64_t now)
+{
+	int i = 0;
+	int IPCount = this->m_ip_list.size();
+	for( ; i < IPCount; ++i) {
+		if(this->m_qos_severs[i].get_status() == 0) {
+			if(this->m_qos_severs[i].get_last_remove_time() != 0) {
+				if(now - this->m_qos_severs[i].get_last_remove_time() > this->m_qos_severs[i].get_remove_time_stamp()) {
+					this->m_qos_severs[i].set_status(1);
+					this->m_qos_severs[i].set_remove_time_stamp(0);
+					this->m_qos_severs[i].set_last_remove_time(0);
+					this->m_qos_severs[i].get_dtc_server()->clear_error_count();
+					log4cplus_debug("bid=[%d], address=[%s], pos=[%d]!", \
+							this->m_bid, this->m_qos_severs[i].get_dtc_server()->get_address(), i); 
+#ifdef DEBUG_INFO 
+					printf("refresh bid=[%d],address=[%s],now=[%lu]!\n", \
+							this->m_bid, this->m_qos_severs[i].get_dtc_server()->get_address(), now);
+#endif 
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+DTC::Server* DTCServers::get_one_server_from_buckets()
+{
+	int serverPos = 0;
+	int lastBucketsPos = this->m_buckets_pos;
+	do{
+		++this->m_buckets_pos;
+		if(this->m_buckets_pos >= this->m_balance_bucket_size)
+			this->m_buckets_pos = 0;
+		
+		if(unlikely(!this->m_load_balance_buckets))
+			return NULL;
+		serverPos = this->m_load_balance_buckets[this->m_buckets_pos];
+		if(this->m_qos_severs[serverPos].get_status()) {
+#ifdef DEBUG_INFO 
+			printf("get server address=[%s]\n", this->m_qos_severs[serverPos].get_dtc_server()->get_address());
+#endif
+			return this->m_qos_severs[serverPos].get_dtc_server();
+		} else {
+			/* 整租服务皆不可用,返回默认位置的server */
+			if(lastBucketsPos == this->m_buckets_pos) {
+				int tmpPos = this->m_load_balance_buckets[DEFAULT_SERVER_POS];
+				return this->m_qos_severs[tmpPos].get_dtc_server();
+			}
+		}
+	}while(1);
+}
+
+DTC::Server* DTCServers::get_server()
+{
+	int ret = 0;
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	uint64_t now = tv.tv_sec; 
+	if(this->m_set_route && (!this->m_ip_list.empty()) && (!this->m_constructed_by_set_i_ps)) {
+#ifdef DEBUG_INFO 
+		printf("construct server by set route\n");
+#endif
+		ret = construct_servers();
+		if(ret < 0) {
+			log4cplus_error("construct servers by set route failed! error code=[%d]", ret);
+			set_error_msg(ret, "DTCServers::get_server", "construct servers by set route failed!");
+			return NULL;
+		}
+		ret = construct_balance_buckets();
+		if(ret < 0) {
+			log4cplus_error("construct balance bucket failed! error code=[%d]", ret);
+			set_error_msg(ret, "DTCServers::get_server", "construct balance bucket failed");
+			return NULL;
+		}
+		this->m_constructed_by_set_i_ps = true;
+#ifdef DEBUG_INFO 
+		printf("get one server from set route\n");
+#endif
+		goto GetOneServer;
+	}
+	
+	if(this->m_set_route && (!this->m_ip_list.empty()) && this->m_constructed_by_set_i_ps) {
+#ifdef DEBUG_INFO 
+		printf("get one server from set route\n");
+#endif
+		goto GetOneServer;
+	}
+
+	if(0 == this->m_bid_version) {
+		uint64_t BidVersion = 0;
+		int ret = get_version(&BidVersion);
+		if(BidVersion <= 0) {
+			log4cplus_info("get version from CC error!");
+//			set_error_msg(ER_BID_VERSION_ERR, "DTCServers::get_server", "get version from CC error!");
+			set_error_msg(ret, "DTCServers::get_server", "get version from CC error!");
+			return NULL;
+		}
+		IP_ROUTE IPRoute;
+		memset(&IPRoute, 0, sizeof(IP_ROUTE));
+		ret = get_ip_route(this->m_bid, &IPRoute);
+		if(ret < 0 || IPRoute.ip_num <= 0 || IPRoute.ip_list == NULL) {
+			log4cplus_error("get ip list by bid failed! ip list is null!");
+			set_error_msg(0, "DTCServers::get_server", "get ip list by bid failed! ip list is null!");
+			free_ip_route(&IPRoute);
+			return NULL;
+		}
+		int i = 0;
+		std::vector<ROUTE_NODE>().swap(this->m_ip_list);
+		for(; i < IPRoute.ip_num; ++i) {
+			ROUTE_NODE RouteNode;
+			RouteNode.bid = IPRoute.ip_list[i].bid;
+			memcpy(RouteNode.ip, IPRoute.ip_list[i].ip, IP_LEN);
+			RouteNode.port = IPRoute.ip_list[i].port;
+			RouteNode.status = IPRoute.ip_list[i].status;
+			RouteNode.weight = IPRoute.ip_list[i].weight;
+#ifdef DEBUG_INFO
+			print_ip_node(RouteNode);
+#endif
+			this->m_ip_list.push_back(RouteNode);	
+		}
+		free_ip_route(&IPRoute);
+
+#ifdef DEBUG_INFO 
+		printf("construct server by cc\n");
+#endif
+		ret = construct_servers();
+		if(ret < 0) {
+			log4cplus_error("construct servers failed!");
+			set_error_msg(ret, "DTCServers::get_server", "construct servers failed!!");
+			return NULL;
+		}
+		/* TODO cc version管理 */
+		ret = construct_balance_buckets();
+		if(ret < 0) {
+			log4cplus_error("construct balance bucket failed! error code=[%d]", ret);
+			set_error_msg(ret, "DTCServers::get_server", "construct balance bucket failed!");
+			return NULL;
+		}
+#ifdef DEBUG_INFO 
+		printf("get one server from cc\n");
+#endif
+		this->m_last_get_ca_time = now; 
+		this->m_bid_version = BidVersion;
+		goto GetOneServer;
+	}
+	
+	if(now - this->m_last_get_ca_time >= DEFAULT_ROUTE_EXPIRE_TIME) {
+		uint64_t BidVersion = 0;
+		get_version(&BidVersion);
+		this->m_last_get_ca_time = now;
+		if(this->m_bid_version >= BidVersion) {
+			log4cplus_info("the version is lastest!");
+#ifdef DEBUG_INFO 
+			printf("get one server from cc\n");
+#endif
+			goto GetOneServer;
+		}
+		IP_ROUTE IPRoute;
+		memset(&IPRoute, 0, sizeof(IP_ROUTE));
+		ret = get_ip_route(this->m_bid, &IPRoute); 
+		if(ret < 0 || IPRoute.ip_num <= 0 || IPRoute.ip_list == NULL) {
+			log4cplus_error("get ip list by bid failed! ip list is null!");
+			set_error_msg(0, "DTCServers::get_server", "get ip list by bid failed! ip list is null!");
+			free_ip_route(&IPRoute);
+			return NULL;
+		}
+
+		int i = 0;
+		std::vector<ROUTE_NODE> IPList;
+
+		for(; i < IPRoute.ip_num; ++i) {
+			ROUTE_NODE RouteNode;
+			RouteNode.bid = IPRoute.ip_list[i].bid;
+			memcpy(RouteNode.ip, IPRoute.ip_list[i].ip, IP_LEN);
+			RouteNode.port = IPRoute.ip_list[i].port;
+			RouteNode.status = IPRoute.ip_list[i].status;
+			RouteNode.weight = IPRoute.ip_list[i].weight;
+#ifdef DEBUG_INFO
+			print_ip_node(RouteNode);
+#endif
+			IPList.push_back(RouteNode);	
+		}
+		free_ip_route(&IPRoute);
+
+#ifdef DEBUG_INFO
+		printf("construct server by cc\n");
+#endif
+		ret = construct_servers2(IPList);
+		if(ret < 0) {
+			std::vector<ROUTE_NODE>().swap(this->m_ip_list);
+			this->m_ip_list = IPList;
+			log4cplus_error("construct servers failed!");
+			set_error_msg(ret, "DTCServers::get_server", "construct servers failed!");
+			return NULL;
+		}
+		this->m_ip_list = IPList;
+		ret = construct_balance_buckets();
+		if(ret < 0) {
+			log4cplus_error("construct balance bucket failed! error code=[%d]", ret);
+			set_error_msg(ret, "DTCServers::get_server", "construct balance bucket failed!");
+			return NULL;
+		}
+		this->m_bid_version = BidVersion;
+#ifdef DEBUG_INFO
+		printf("get one server from cc\n");
+#endif
+		goto GetOneServer;
+	} else {
+#ifdef DEBUG_INFO
+		printf("get one server from cc\n");
+#endif
+		goto GetOneServer;
+	}
+	log4cplus_error("Exception process!");
+	set_error_msg(0, "DTCServers::get_server", "Exception process!");
+	return NULL;
+
+GetOneServer:
+	refresh_balance_buckets(now);
+	remove_server_from_buckets(now);
+	return get_one_server_from_buckets();
+}

+ 111 - 0
src/devel/cpp/dtcqossvr.h

@@ -0,0 +1,111 @@
+#ifndef __CHC_CLI_SERVERS_H
+#define __CHC_CLI_SERVERS_H
+
+#include "dtcint.h"
+
+extern "C"
+{
+#include "app_client_set.h"
+}
+
+#define DEFAULT_ROUTE_EXPIRE_TIME 120
+#define DEFAULT_MAX_REMOVE_THRESHOLD_TIME 1800
+#define DEFAULT_REMOVE_ERROR_COUNT 3
+#define DEFAULT_ROUTE_INTERVAL_TIME 5
+#define DEFAULT_SERVER_POS 0
+
+namespace DTC 
+{
+	class DTCQosServer
+	{
+	public:
+		friend class DTCServers;
+
+	private:
+		int m_status;
+		int m_weight;
+		/* 需要被摘除的时间 */
+		uint64_t m_remove_time_stamp;
+		/* 上次被移除的时间点 */
+		uint64_t m_last_remove_time; 
+		/* 最大指数阀值 */
+		uint64_t m_max_time_stamp;
+		Server *m_server;
+
+    private:
+		DTCQosServer(const DTCQosServer& qosServer);
+		DTCQosServer& operator=(const DTCQosServer& qosServer);
+	public:
+		DTCQosServer();
+		~DTCQosServer(void);
+
+	public:
+		int get_status()
+		{
+			return this->m_status;
+		}
+		void set_status(int iFlag)
+		{
+			this->m_status = iFlag;
+		}
+
+		int get_weight()
+		{
+			return this->m_weight;
+		}
+		void set_weight(int iFlag)
+		{
+			this->m_weight = iFlag;
+		}
+
+		uint64_t get_remove_time_stamp()
+		{
+			return this->m_remove_time_stamp;
+		}	
+		void set_remove_time_stamp(uint64_t iFlag)
+		{
+			this->m_remove_time_stamp = iFlag;
+		}
+
+		uint64_t get_last_remove_time()
+		{
+			return this->m_last_remove_time;
+		}	
+		void set_last_remove_time(uint64_t iFlag)
+		{
+			this->m_last_remove_time = iFlag;
+		}
+
+		uint64_t get_max_time_stamp()
+		{
+			return this->m_max_time_stamp;
+		}	
+		void set_max_time_stamp(uint64_t iFlag)
+		{
+			this->m_max_time_stamp = iFlag;
+		}
+
+		Server* get_dtc_server()
+		{
+			return this->m_server;
+		}
+
+		void set_dtc_server(Server* ser)
+		{
+			this->m_server = ser;
+		}
+
+		void reset_dtc_server()
+		{
+			this->m_server = NULL;
+		}
+
+		void create_dtc_server()
+		{
+			this->m_server = new Server();
+		}
+	};
+
+};
+
+#endif 

+ 1040 - 0
src/devel/cpp/dtcreq.cc

@@ -0,0 +1,1040 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <new>
+
+#include "dtcapi.h"
+#include "dtcint.h"
+
+/**
+ * NCRequest's methods always assign and return
+ * cache the logical error code
+ */
+#define return_err(x)	return err = (x)
+#define return_err_res(x,y,z)   return new NCResult(x,y,z)
+#define MAX_EXPIRETIME 30*24*3600
+#define CLIENT_CURVE 5
+#define AGENT_CURVE 8
+
+NCRequest::NCRequest(NCServer *s, int op)
+{
+    compressFlag = 0;
+	/* MonitorRequest need not table check */
+	if( op != DRequest::Monitor && (s && s->is_completed()==0) )
+		s = NULL;
+	server = s;
+	if(server) server->increase();
+	table_definition_ = NULL;
+	tablename_ = NULL;
+	keytype_ = 0;
+
+	switch(op) {
+		case DRequest::TYPE_PASS:
+		case DRequest::Get:
+		case DRequest::Purge:
+		case DRequest::Flush:
+		case DRequest::Insert:
+		case DRequest::Update:
+		case DRequest::Delete:
+		case DRequest::Replace:
+			if(server) {
+				table_definition_ = server->table_definition_;
+				tablename_ = server->tablename_;
+				keytype_ = server->keytype_;
+			}
+			break;
+		/* 跨IDC分布支持 */
+		case DRequest::TYPE_SYSTEM_COMMAND:
+		case DRequest::Invalidate:
+			if(server) {
+				table_definition_ = server->admin_tdef;
+				tablename_ =(char *) "@HOT_BACKUP";
+				keytype_ = DField::Unsigned;
+			}
+			break;
+		case DRequest::Monitor:
+			break;
+		default:
+			op = DRequest::result_code;
+	}
+	cmd = op;
+	err = 0;
+	haskey = 0;
+	flags = 0;
+	key.u64 = 0;
+	key.bin.ptr = NULL;
+	key.bin.len = 0;
+
+	limitStart = 0;
+	limitCount = 0;
+	adminCode = 0;
+	hotbackup_id = 0;
+	master_hotbackup_timestamp_ = 0;
+	slave_hotbackup_timestamp_ = 0;
+	if(server)
+		key_value_list_.keyinfo_ = &server->keyinfo_;
+    gzip = NULL;
+}
+
+NCRequest::~NCRequest(void){
+	unset_key_value();
+	unset_key();
+	if(server) DEC_DELETE(server);
+    if(gzip) DELETE(gzip);
+}
+
+/* attach_server() error is transient, don't cache it */
+int NCRequest::attach_server(NCServer *s)
+{
+	/* NO-OP */
+	if(s==server)
+		return 0;
+
+	switch(cmd) {
+		case DRequest::TYPE_PASS:
+		case DRequest::Get:
+		case DRequest::Purge:
+		case DRequest::Flush:
+		case DRequest::Insert:
+		case DRequest::Update:
+		case DRequest::Delete:
+		case DRequest::Replace:
+			break;
+		default:
+			/* don't allow change admin target server */
+			return -EPERM;
+	}
+
+	/* new server must be initialized */
+	if(s==NULL || s->is_completed()==0)
+		return -EC_NOT_INITIALIZED;
+
+	/* precheck same table */
+	if(server) {
+		if(keytype_ != s->keytype_)
+			return -EC_BAD_KEY_TYPE;
+		if(!server->keyinfo_.equal_key_name(s->keyinfo_))
+			return -EC_BAD_KEY_TYPE;
+		if(strcmp(tablename_, s->tablename_) != 0)
+			return -EC_BAD_TABLE_NAME;
+		if(table_definition_==NULL) {
+			/* no current tabledef */
+		} else if(table_definition_ == server->table_definition_) {
+			/* same tabledef */
+		} else if(table_definition_->is_same_table(server->table_definition_)) {
+			/* hash equal */
+		} else {
+			/* force re-resolve fieldnames */
+			ui.Unresolve();
+			ci.Unresolve();
+			fs.Unresolve();
+		}
+		/* release old server */
+		DEC_DELETE(server);
+	}
+	/* switch to new server */
+	server = s;
+	server->increase();
+	table_definition_ = server->table_definition_;
+	tablename_ = server->tablename_;
+	keytype_ = server->keytype_;
+	key_value_list_.keyinfo_ = &server->keyinfo_;
+	return 0;
+}
+
+int NCRequest::need(const char *n, int vid)
+{
+	if(server==NULL)
+		return_err(-EC_NOT_INITIALIZED);
+	if(cmd!=DRequest::Get && cmd!=DRequest::TYPE_SYSTEM_COMMAND)
+		return_err(-EC_BAD_OPERATOR);
+	int ret = fs.add_field(n, vid);
+	if(ret)
+		err = ret;
+	return ret;
+}
+
+int NCRequest::add_condition(const char *n, uint8_t op, uint8_t t, const DTCValue &v)
+{
+	if(server==NULL)
+		return_err(-EC_NOT_INITIALIZED);
+	if(cmd==DRequest::Insert || cmd==DRequest::Replace)
+		return_err(-EC_BAD_OPERATOR);
+	switch(t) {
+		case DField::Signed:
+		case DField::Unsigned:
+			if(op >= DField::TotalComparison)
+				return_err(-EC_BAD_OPERATOR);
+			break;
+		case DField::String:
+		case DField::Binary:
+			if(op != DField::EQ && op != DField::NE)
+				return_err(-EC_BAD_OPERATOR);
+			break;
+		default:
+			return_err(-EC_BAD_FIELD_TYPE);
+	}
+	int ret = ci.add_value(n, op, t, v);
+	if(ret) err = ret;
+	return ret;
+}
+
+int NCRequest::add_operation(const char *n, uint8_t op, uint8_t t, const DTCValue &v)
+{
+	if(server==NULL) return_err(-EC_NOT_INITIALIZED);
+	switch(cmd) {
+		case DRequest::Insert:
+		case DRequest::Replace:
+		case DRequest::TYPE_SYSTEM_COMMAND:
+			if(op != DField::Set)
+				return_err(-EC_BAD_OPERATOR);
+			break;
+		case DRequest::Update:
+			break;
+		default:
+			return_err(-EC_BAD_OPERATOR);
+			break;
+	}
+	switch(t) {
+		case DField::Signed:
+		case DField::Unsigned:
+			if(op >= DField::TotalOperation)
+				return_err(-EC_BAD_OPERATOR);
+			break;
+
+		case DField::String:
+		case DField::Binary:
+			if(op == DField::Add||op == DField::OR) return_err(-EC_BAD_OPERATOR);
+			break;
+
+		case DField::Float:
+			if(op == DField::SetBits || op == DField::OR)
+				return_err(-EC_BAD_OPERATOR);
+			break;
+		default:
+			return_err(-EC_BAD_FIELD_TYPE);
+	}
+	int ret = ui.add_value(n, op, t, v);
+	if(ret) err = ret;
+	return ret;
+}
+
+int NCRequest::init_compress()
+{
+    int iret = 0;
+    if (server==NULL)
+        return -EC_NOT_INITIALIZED;
+    if (table_definition_==NULL) {
+		/* ping and get tabledef */
+        iret = server->ping();
+        table_definition_ = server->table_definition_;
+    }
+    if (iret)
+        return iret;
+    if (gzip==NULL)
+        NEW(DTCCompress,gzip);
+    if (gzip==NULL)
+        return -ENOMEM;
+    if (table_definition_==NULL)
+        return -EC_CHECKSUM_MISMATCH;
+    if (server->get_compress_level())
+        gzip->set_compress_level(server->get_compress_level());
+    return gzip->set_buffer_len(table_definition_->max_field_size());
+}
+
+int NCRequest::compress_set(const char *n,const char * v,int len)
+{
+    int iret = 0;
+    if (len < 0) {
+        snprintf(errmsg_, sizeof(errmsg_), "compress error:fieldlen is invalid");
+        return -EC_COMPRESS_ERROR;
+    }
+
+    if (n == NULL) {
+        snprintf(errmsg_, sizeof(errmsg_), "compress error:fieldname is invalid");
+        return -EC_COMPRESS_ERROR;
+    }
+
+    if (v == NULL) {
+        snprintf(errmsg_, sizeof(errmsg_), "compress error:fieldvalue is invalid");
+        return -EC_COMPRESS_ERROR;
+    }
+
+    if (gzip==NULL) {
+        iret = init_compress();
+        if (iret) return iret;
+    }
+    if (table_definition_->compress_field_id() <= 0) {
+        snprintf(errmsg_, sizeof(errmsg_), "compress error:DTC must add a field for compress(get_field_type=2,FieldSize=8,DefaultValue=compressflag)");
+        return -EC_COMPRESS_ERROR;
+    }
+
+    if (table_definition_->field_type(table_definition_->field_id(n)) != DField::Binary) {
+        snprintf(errmsg_, sizeof(errmsg_), "compress error:compress just support binary field");
+        return - EC_BAD_VALUE_TYPE;
+    }
+
+    iret = gzip->compress(v,len);
+    if (iret) {
+        if (iret==-111111)
+             snprintf(errmsg_, sizeof(errmsg_), "compress error:compress buff is null,sth sucks happend");
+        else
+             snprintf(errmsg_, sizeof(errmsg_), "compress error:zlib return code is %d.",iret);
+             return -EC_COMPRESS_ERROR ;
+    }
+    iret = set_compress_flag(n);
+    if (iret)
+		return iret;
+    return add_operation(n,DField::Set,DField::String,DTCValue::Make(gzip->get_buf(),gzip->get_len()));
+}
+
+int NCRequest::compress_set_force(const char *n,const char * v,int len)
+{
+    int iret = 0;
+    if (len < 0) {
+        snprintf(errmsg_, sizeof(errmsg_), "compress error:fieldlen is invalid");
+        return -EC_COMPRESS_ERROR;
+    }
+
+    if (n == NULL) {
+        snprintf(errmsg_, sizeof(errmsg_), "compress error:fieldname is invalid");
+        return -EC_COMPRESS_ERROR;
+    }
+
+    if (v == NULL) {
+        snprintf(errmsg_, sizeof(errmsg_), "compress error:fieldvalue is invalid");
+        return -EC_COMPRESS_ERROR;
+    }
+
+    if (gzip==NULL) {
+        iret = init_compress();
+        if (iret) return iret;
+    }
+
+    if (table_definition_->field_type(table_definition_->field_id(n)) != DField::Binary) {
+        snprintf(errmsg_, sizeof(errmsg_), "compress error:compress just support binary field");
+        return - EC_BAD_VALUE_TYPE;
+    }
+
+    iret = gzip->compress(v,len);
+    if (iret) {
+        if (iret==-111111)
+             snprintf(errmsg_, sizeof(errmsg_), "compress error:compress buff is null,sth sucks happend");
+        else
+             snprintf(errmsg_, sizeof(errmsg_), "compress error:zlib return code is %d.",iret);
+             return -EC_COMPRESS_ERROR ;
+    }
+    if (iret) 
+		return iret;
+
+    return add_operation(n,DField::Set,DField::String,DTCValue::Make(gzip->get_buf(),gzip->get_len()));
+}
+
+int NCRequest::add_value(const char *n, uint8_t t, const DTCValue &v)
+{
+	if(server==NULL) 
+		return_err(-EC_NOT_INITIALIZED);
+	if(cmd!=DRequest::Insert && cmd!=DRequest::Replace) 
+		return_err(-EC_BAD_COMMAND);
+	int ret = ui.add_value(n, DField::Set, t, v);
+	if(ret) 
+		err = ret;
+	return ret;
+}
+
+int NCRequest::unset_key(void) 
+{
+	if(haskey) {
+		if(server && server->keytype_ == DField::String) {
+			DELETE_ARRAY(key.bin.ptr);
+			key.Set(NULL, 0);
+		}
+		haskey = 0;
+	}
+	return 0;
+}
+
+int NCRequest::unset_key_value(void) 
+{
+	key_value_list_.unset_key();
+	flags &= ~DRequest::Flag::MultiKeyValue;
+	return 0;
+}
+
+int NCRequest::set_key(int64_t k) 
+{
+	if(server==NULL)
+		return_err(-EC_NOT_INITIALIZED);
+	if(server->keytype_ != DField::Signed)
+		return_err(-EC_BAD_KEY_TYPE);
+	key = k;
+	haskey = 1;
+	unset_key_value();
+	return 0;
+}
+
+int NCRequest::set_key(const char *name, int l) 
+{
+	if(server==NULL)
+		return_err(-EC_NOT_INITIALIZED);
+	if(server->keytype_ != DField::String)
+		return_err(-EC_BAD_KEY_TYPE);
+	char *a = new char[l];
+	memcpy(a, name, l);
+	DELETE_ARRAY(key.bin.ptr);
+	haskey = 1;
+	key.Set(a, l);
+	unset_key_value();
+	return 0;
+}
+
+int NCRequest::add_key_value(const char* name, const DTCValue &v, uint8_t type)
+{
+	if(server==NULL)
+		return_err(-EC_NOT_INITIALIZED);
+	if(server->allow_batch_key()==0)
+		return_err(-EC_NOT_INITIALIZED);
+
+	int ret = key_value_list_.add_value(name, v, type);
+	if(ret < 0)
+		return err = ret;
+
+	flags |= DRequest::Flag::MultiKeyValue;
+	unset_key();
+	return 0;
+}
+
+int NCRequest::set_table_definition(void)
+{
+	int ret = 0;
+	if(server) {
+		switch(cmd) {
+			case DRequest::TYPE_PASS:
+			case DRequest::Get:
+			case DRequest::Purge:
+			case DRequest::Flush:
+			case DRequest::Insert:
+			case DRequest::Update:
+			case DRequest::Delete:
+			case DRequest::Replace:
+				ret = table_definition_ != server->table_definition_;
+				table_definition_ = server->table_definition_;
+				tablename_ = server->tablename_;
+				keytype_ = server->keytype_;
+				break;
+			/* 跨IDC分布支持 */
+			case DRequest::TYPE_SYSTEM_COMMAND:
+			case DRequest::Invalidate:
+				ret = table_definition_ != server->admin_tdef;
+				table_definition_ = server->admin_tdef;
+				tablename_ = (char *)"@HOT_BACKUP";
+				keytype_ = DField::Unsigned;
+				break;
+			default:
+				break;
+		}
+	}
+	return ret;
+}
+
+int NCRequest::check_key(const DTCValue *kptr)
+{
+	int keyType = table_definition_->key_type();
+	int keySize = table_definition_->key_size();
+	/* 多key查询时 kptr为空 */
+	if(kptr) {
+		if(keyType == 1 || keyType == 2) {
+			return check_int_value( *kptr, keyType, keySize);
+		} else if(keyType == 4 || keyType == 5) {
+			if(keySize <  kptr->str.len)
+				return -EC_BAD_FIELD_SIZE_ON_CHECKKEY;
+		} else {
+			return -EC_EXCEPTION_ON_CHECKKEY;	
+		}
+	}
+	return 0;
+}
+
+int NCRequest::encode(const DTCValue *kptr, Packet *pkt)
+{
+	int err;
+	int force = set_table_definition();
+
+	if(table_definition_ &&(	(err = check_key(kptr)) ||
+				(err = ui.Resolve(table_definition_, force)) ||
+				(err = ci.Resolve(table_definition_, force)) ||
+				(err = fs.Resolve(table_definition_, force)) 
+			  ))
+		return err;
+	if((err = pkt->encode_request(*this, kptr)) != 0) 
+		return err;
+	return 0;
+}
+
+NCResult *NCRequest::execute_stream(const DTCValue *kptr)
+{
+	int resend = 1;
+	int nrecv = 0;
+	int nsent = 0;
+
+	while(1) {
+		int err;
+		if(resend) {
+			Packet pk;
+			if((err=encode(kptr, &pk)) < 0)
+				return_err_res(err, "API::encoding", "client api encode error");
+			if((err = server->Connect()) != 0) {
+				server->increase_error_count_();
+				if(err==-EAGAIN) {
+					/* unix socket return EAGAIN if listen queue overflow */
+					err = -EC_SERVER_BUSY;
+				}
+				log4cplus_error("dtc connect error %d\n", err);
+				return_err_res(err, "API::connecting", "client api connect server error");
+			}
+			nsent++;
+			if((err = server->send_packet_stream(pk)) != 0) {
+				if(server->uto_reconnect_ && nsent <= 1 && (err==-ECONNRESET || err==-EPIPE)) {
+					resend = 1;
+					continue;
+				}
+				return_err_res(err, "API::sending", "client api send packet error");
+			}
+		}
+		NCResult *res = new NCResult(table_definition_);
+		res->versionInfo.set_serial_nr(server->get_last_serialnr());
+		err = server->decode_result_stream(*res);
+		if(err < 0) {
+			if(cmd!=DRequest::TYPE_PASS && err==-EAGAIN && nsent<=1) {
+				resend = 1;
+				delete res;
+				continue;
+			}
+			/* network error always aborted */
+			return res;
+		}
+		nrecv++;
+		if(res->versionInfo.serial_nr() != server->get_last_serialnr()) {
+			log4cplus_debug("SN different, receive again. my SN: %lu, result SN: %lu",
+					(unsigned long)server->get_last_serialnr(),
+					(unsigned long)res->versionInfo.serial_nr());
+			/* receive again */
+			resend = 0;
+		} else if(res->result_code() == -EC_CHECKSUM_MISMATCH && nrecv <= 1) {
+			resend = 1;
+			/* tabledef changed, resend,agent restart reconnect */
+			if(res->versionInfo.ReConnect()) {
+				server->Close();	
+			}
+		} else {
+			/* got valid result */
+			if(res->result_code() >= 0 && cmd == DRequest::Get)
+				res->set_virtual_map(fs);
+			if(0 != server->get_remove_count())
+				server->clear_remove_count();
+			uint64_t time = 0;
+			if(res->resultInfo.tag_present(7)) {
+				char *t = res->resultInfo.time_info();
+				if(t) {
+					DTCTimeInfo *t_info = (DTCTimeInfo *)t;
+					time = (t_info->time)>0 ? (t_info->time):0;
+					server->set_agenttime(time);
+				}
+			}
+			/* agent restart reconnect */
+			if(res->versionInfo.ReConnect()) {
+				server->Close();	
+			}	
+			return res;
+		}
+		/* delete invalid result and loop */
+		delete res; 
+	}
+	/* UNREACHABLE */
+	return NULL;
+}
+
+NCResult *NCRequest::execute_dgram(SocketAddress *peer, const DTCValue *kptr)
+{
+	int resend = 1;
+	int nrecv = 0;
+	int nsent = 0;
+	while (1) {
+		int err;
+		if(resend) {
+			Packet pk;
+			if ((err = encode(kptr, &pk)) < 0)
+				return_err_res(err, "API::encoding", "client api encode error");
+			nsent++;
+			if ((err = server->send_packet_dgram(peer, pk)) != 0)
+			{
+				if (peer==NULL && server->uto_reconnect_ && nsent <= 1 &&
+						(err==-ECONNRESET || err==-EPIPE || err==-ECONNREFUSED || err==-ENOTCONN)) {
+					if((err = server->reconnect()) != 0) {
+						if(err==-EAGAIN) {
+							/* unix socket return EAGAIN if listen queue overflow */
+							err = -EC_SERVER_BUSY;
+						}
+						return_err_res(err, "API::connecting", "client api connect server error");
+					}
+					resend = 1;
+					continue;
+				}
+				return_err_res(err, "API::sending", "client api send packet error");
+			}
+		}
+
+		NCResult *res = new NCResult(table_definition_);
+		res->versionInfo.set_serial_nr(server->get_last_serialnr());
+		err = server->decode_result_dgram(peer, *res);
+		if(err < 0) {
+			/* network error encountered */
+			return res;
+		}
+		nrecv++;
+
+		if (res->versionInfo.serial_nr() != server->get_last_serialnr()) {
+			log4cplus_debug("SN different, receive again. my SN: %lu, result SN: %lu",
+					(unsigned long)server->get_last_serialnr(),
+					(unsigned long)res->versionInfo.serial_nr());
+			/* receive again */
+			resend = 0;
+		} else if (res->result_code() == -EC_CHECKSUM_MISMATCH && nrecv <= 1) {
+			resend = 1;
+			/* tabledef changed, resend */
+		} else {
+			/* got valid result */
+			if (res->result_code() >= 0 && cmd == DRequest::Get)
+				res->set_virtual_map(fs);
+			uint64_t time = 0;
+			if(res->resultInfo.tag_present(7)) {
+				char *t = res->resultInfo.time_info();
+				if(t) {
+					DTCTimeInfo *t_info = (DTCTimeInfo *)t;
+					time = (t_info->time)>0 ? (t_info->time):0;
+					server->set_agenttime(time);
+				}
+			}
+			return res;
+		}
+		/* delete invalid result and loop */
+		delete res; 
+	}
+	/* UNREACHABLE */
+	return NULL;
+}
+
+NCResult *NCRequest::execute_network(const DTCValue *kptr) 
+{
+	NCResult *res = NULL;
+	if(!server->is_dgram()) {
+		res = execute_stream(kptr);
+	} else if(server->is_dgram()) {
+		NCUdpPort *port = server->get_global_port();
+		/* get UDPPORT{SN,fd} from udp pool */
+		if (port  == NULL)
+			return_err_res(err, "API::do_execute", "get udp port error.udp port may exhaust");
+		res = execute_dgram(&server->addr_, kptr);
+		server->put_global_port(port);
+	} else {
+		int err;
+		if((err = server->Connect()) != 0) {
+			if(err==-EAGAIN)
+				/* unix socket return EAGAIN if listen queue overflow */
+				err = -EC_SERVER_BUSY;
+			return_err_res(err, "API::connecting", "client api connect server error");
+		}
+		res = execute_dgram(NULL, kptr);
+	}
+	return res;
+}
+
+NCResult *NCRequest::execute_internal(const DTCValue *kptr)
+{
+	if(table_definition_ == NULL) {
+		return_err_res(err, "API::encoding", "internal error: request has no tdef");
+	int force = set_table_definition();
+	int err;
+	if(
+			(err = ui.Resolve(table_definition_, force)) ||
+			(err = ci.Resolve(table_definition_, force)) ||
+			(err = fs.Resolve(table_definition_, force))
+	  ) {
+		return_err_res(err, "API::encoding", "client api encode error");
+	}
+
+	NCResultInternal *res = server->execute_internal(*this, kptr);
+	if(res == NULL) {
+		return_err_res(err, "API::sending", "internal client api do_execute error");
+	}
+	if(res->result_code() >= 0 && cmd==DRequest::Get)
+		res->set_virtual_map(fs);
+
+	return reinterpret_cast<NCResult *>(res);
+	}
+}
+
+NCResult *NCRequest::precheck(const DTCValue *kptr) 
+{
+
+	if(cmd == DRequest::Monitor) {
+		/**
+		 * MonitorRequest is a stub of kRequestSvrAdmin.Agent should add MonitorRequest type later
+		 * Monitor Request need not check
+		 */
+		cmd = DRequest::TYPE_SYSTEM_COMMAND;
+		return 	NULL;
+	}
+	if(err)
+		return_err_res(err, "API::encoding", "do_init Operation Error");
+	if(server==NULL)
+		return_err_res(-EC_NOT_INITIALIZED, "API::encoding", "Server Not Initialized");
+	if(cmd==DRequest::result_code)
+		return_err_res(-EC_BAD_COMMAND, "API::encoding", "Unknown Request Type");
+	if(server->badkey_)
+		return_err_res(-EC_BAD_KEY_TYPE, "API::encoding", "Key Type Mismatch");
+	if(server->badname_)
+		return_err_res(-EC_BAD_TABLE_NAME, "API::encoding", "Table Name Mismatch");
+	if(cmd!=DRequest::Insert && cmd!=DRequest::TYPE_SYSTEM_COMMAND &&
+			!(flags & DRequest::Flag::MultiKeyValue) && kptr==NULL)
+		return_err_res(-EINVAL, "API::encoding", "Missing Key");
+	if((flags & DRequest::Flag::MultiKeyValue) && key_value_list_.is_key_flat()==0)
+		return_err_res(-EINVAL, "API::encoding", "Missing Key Value");
+	if (table_definition_==NULL) {
+		int ret = 0;
+		uint64_t time_before = GET_TIMESTAMP();
+		/* ping and get tabledef */
+		ret = server->ping();
+		uint64_t time_after = GET_TIMESTAMP();
+		table_definition_ = server->table_definition_;
+
+		uint64_t timeInterval = 0;
+		if(time_after > time_before)
+			timeInterval = time_after - time_before;
+		
+		/* log4cplus_info("timeInterval: %lu", timeInterval); */
+		std::string accessKey = server->access_token_;
+		if(ret == -ETIMEDOUT) {
+			//server->data_connector_->set_report_info(accessKey, CLIENT_CURVE, server->get_timeout());
+			server->data_connector_->set_report_info(accessKey, AGENT_CURVE, server->get_timeout());
+		} else {
+			//server->data_connector_->set_report_info(accessKey, CLIENT_CURVE, timeInterval);
+			server->data_connector_->set_report_info(accessKey, AGENT_CURVE, (server->get_agenttime() != 0)?server->get_agenttime():timeInterval);
+		}
+		server->data_connector_->set_report_info(accessKey, CLIENT_CURVE, timeInterval);
+		
+		//top_percentile_report(accessKey, server->get_address(), timeInterval, ret, RT_SHARDING);
+		//top_percentile_report(accessKey, "", timeInterval, ret, RT_ALL);
+		server->data_connector_->set_top_percentile_data(accessKey, server->get_address(), timeInterval, ret);
+		
+		log4cplus_info("NCRequest::precheck,seq:%lu, clientTime:%lu, agentTime:%lu", server->get_last_serialnr(), timeInterval, server->get_agenttime());
+		/* 清除  ping 之后获取的 agent-dtc 响应耗时 */
+		server->set_agenttime(0);
+	}
+	return NULL;
+}
+
+int NCRequest::set_compress_field_name()
+{
+    int iret = 0;
+	/* 启用压缩必定有这个字段 */
+    if (table_definition_ && table_definition_->compress_field_id()>0) {
+		/* 读请求需要need字段 */
+        if (gzip==NULL) {
+            if (cmd != DRequest::Get)
+                return 0;
+            iret = need(table_definition_->field_name(table_definition_->compress_field_id()),0);
+            if (iret) {
+                snprintf(errmsg_, sizeof(errmsg_), "need CompressField error,errorcode is %d",iret);
+                return -1;
+            }
+        } else {
+			/* 写请求 */
+			if  (cmd == DRequest::Insert||cmd == DRequest::Replace) {
+				iret = add_operation(table_definition_->field_name(table_definition_->compress_field_id()),//name
+						DField::Set,DField::Signed,DTCValue::Make(compressFlag));
+			} else if (cmd == DRequest::Update) {
+				iret = add_operation(table_definition_->field_name(table_definition_->compress_field_id()),//name
+						DField::OR,DField::Signed,DTCValue::Make(compressFlag));
+			} else {
+				 snprintf(errmsg_, sizeof(errmsg_), "Request type[%d] not support compressset",cmd);
+				 return -1;
+			}
+            if (iret) {
+                snprintf(errmsg_, sizeof(errmsg_), "set CompressField error,errorcode is %d",iret);
+                return -1;
+            }
+        }
+    }
+    return 0;
+}
+/* if get,need compressfield,if write set compressfield; */
+NCResult *NCRequest::do_execute(const DTCValue *kptr) 
+{
+	NCResult *ret = NULL;
+	if(kptr==NULL && haskey) kptr = &key;
+	ret = precheck(kptr);
+	if(ret==NULL) {
+        if (set_compress_field_name())
+            return_err_res(-EC_COMPRESS_ERROR, "API::do_execute", "set_compress_field_name error. please check request.get_error_message");;
+        /*date:2014/06/09, author:xuxinxin 模调上报 */
+        uint64_t time_before = GET_TIMESTAMP();
+        if(server->has_internal_executor())
+			ret = execute_internal(kptr);
+		else
+			ret = execute_network(kptr);
+        uint64_t time_after = GET_TIMESTAMP();
+
+		uint64_t timeInterval = 0;
+		if(time_after > time_before)
+			timeInterval = time_after - time_before;
+        
+        std::string accessKey = server->access_token_;
+
+        if(ret != NULL && ret->resultInfo.result_code() == -ETIMEDOUT) {
+        	server->data_connector_->set_report_info(accessKey, AGENT_CURVE, server->get_timeout());
+        } else {
+        	server->data_connector_->set_report_info(accessKey, AGENT_CURVE, (server->get_agenttime() != 0)?server->get_agenttime():timeInterval);
+        }
+		server->data_connector_->set_report_info(accessKey, CLIENT_CURVE, timeInterval);
+		
+		server->data_connector_->set_top_percentile_data(accessKey, server->get_address(), timeInterval, ret ? ret->resultInfo.result_code() : 1);
+		
+		std::string stemp = accessKey.substr(0, 8);
+		uint32_t bid = 0;
+		sscanf(stemp.c_str(), "%u", &bid);
+		log4cplus_info("NCRequest::do_execute,seq:%lu, clientTime:%lu, agentTime:%lu, bid:%u", server->get_last_serialnr(), timeInterval, server->get_agenttime(), bid);
+		/* 清除  解包 之后获取的 agent-dtc 响应耗时 */
+		server->set_agenttime(0);
+	} else {
+		if(NULL != server)
+			log4cplus_info("NCRequest::do_execute,seq:%lu, precheck return NULL", server->get_last_serialnr());
+	}
+	return ret;
+}
+
+NCResult *NCRequest::do_execute(int64_t k) 
+{
+	if(server == NULL)
+	    return_err_res(-EC_NOT_INITIALIZED, "API::encoding", "Server Not Initialized");
+	if(server->keytype_ != DField::Signed)
+	    return_err_res(-EC_BAD_KEY_TYPE, "API::encoding", "Key Type Mismatch");
+	DTCValue v(k);
+	return do_execute(&v);
+}
+
+NCResult *NCRequest::do_execute(const char *k, int l) 
+{
+	if(server == NULL)
+	    return_err_res(-EC_NOT_INITIALIZED, "API::encoding", "Server Not Initialized");
+	if(server->keytype_ != DField::String)
+	    return_err_res(-EC_BAD_KEY_TYPE, "API::encoding", "Key Type Mismatch");
+	DTCValue v(k, l);
+	return do_execute(&v);
+}
+
+/* packet encoding don't cache error code */
+int NCRequest::encode_buffer(char *&ptr, int &len, int64_t &magic, const DTCValue *kptr) 
+{
+	if(kptr==NULL && haskey) kptr = &key;
+	int err = 0;
+	NCResult *ret = precheck(kptr);
+	if(ret!=NULL) {
+		err = ret->result_code();
+		delete ret;
+		return err;
+	}
+
+	set_table_definition();
+	if(table_definition_ &&(
+				(err = ui.Resolve(table_definition_, 0)) ||
+				(err = ci.Resolve(table_definition_, 0)) ||
+				(err = fs.Resolve(table_definition_, 0))
+			  ))
+		return err;
+	if((err = Packet::encode_simple_request(*this, kptr, ptr, len)) != 0)
+		return err;
+	magic = server->get_last_serialnr();
+	return 0;
+}
+
+int NCRequest::encode_buffer(char *&ptr, int &len, int64_t &magic, int64_t k) 
+{
+	if(server == NULL)
+	    return -EC_NOT_INITIALIZED;
+	if(server->keytype_ != DField::Signed)
+	    return -EC_BAD_KEY_TYPE;
+	if(cmd==DRequest::TYPE_SYSTEM_COMMAND)
+	    return -EC_BAD_COMMAND;
+	DTCValue v(k);
+	return encode_buffer(ptr, len, magic, &v);
+}
+
+int NCRequest::encode_buffer(char *&ptr, int &len, int64_t &magic, const char *k, int l) 
+{
+	if(server == NULL)
+	    return -EC_NOT_INITIALIZED;
+	if(server->keytype_ != DField::String)
+	    return -EC_BAD_KEY_TYPE;
+	DTCValue v(k, l);
+	return encode_buffer(ptr, len, magic, &v);
+}
+/*
+ * @descr: 无源模式设置超时时间
+ * @param: key, dtc key value
+ * @param: t, 超时时间,相对时间
+ * add by xuxinxin
+ * date: 2014/12/09
+ */
+int NCRequest::set_expire_time(const char* key, int t)
+{
+	int ret = 0;
+	if(key == NULL) {
+		log4cplus_error("invalid key value! key is null");
+		return -EC_INVALID_KEY_VALUE;
+	}
+	if(t <= 0) {
+		log4cplus_error("invalid expireTime! expireTime:%d", t);
+		return -EC_INVALID_EXPIRETIME;
+	}
+	if(cmd != DRequest::Update) {
+		log4cplus_error("invalid requset must be request!");  
+		return -EC_BAD_OPERATOR;
+	}
+
+	switch(server->keytype_) {
+		case DField::Signed:
+		case DField::Unsigned:
+			ret = set_key(atoll(key));
+			break;
+		case DField::String:
+		case DField::Binary:
+			ret = set_key(key, strlen(key));
+			break;
+		default:
+			break;
+	}
+	if(ret != 0) return ret; 
+
+	ret = add_operation("_dtc_sys_expiretime", DField::Set, DField::Signed, DTCValue::Make(t));
+	if(ret != 0) return ret;
+	NCResult * rst = do_execute(); //rst 不会为空
+	ret = rst->result_code();
+	if(ret != 0) {
+		log4cplus_error("set expireTime fail, errmsg:%s, errfrom:%s",  rst->resultInfo.error_message(),  rst->resultInfo.error_from());
+	}
+	delete rst;
+	rst = NULL;
+	return ret;
+}
+
+/*
+ * @descr: 无源模式获取超时时间
+ * @param: key, dtc key value
+ * add by xuxinxin
+ * date: 2014/12/11
+ */
+int NCRequest::get_expire_time(const char* key)
+{
+	int ret = 0;
+	if(key == NULL) {
+		log4cplus_error("invalid key value! key is null");
+		return -EC_INVALID_KEY_VALUE;
+	}
+
+	if(cmd != DRequest::Get) {
+		log4cplus_error("invalid requset must be request!");  
+		return -EC_BAD_OPERATOR;
+	}
+
+	switch(server->keytype_) {
+		case DField::Signed:
+		case DField::Unsigned:
+			ret = set_key(atoll(key));
+			break;
+		case DField::String:
+		case DField::Binary:
+			ret = set_key(key, strlen(key));
+			break;
+		default:
+			break;
+	}
+
+	ret = need("_dtc_sys_expiretime", 0);
+	if(ret != 0) {
+		log4cplus_error("get expireTime fail, need error, errcode: %d", ret);
+		return ret;
+	}
+	/* rst 不会为空 */
+	NCResult * rst = do_execute(); 
+	ret = rst->result_code();
+	if(ret < 0) {
+		log4cplus_error("get expireTime fail, errmsg:%s, errfrom:%s", rst->resultInfo.error_message(), rst->resultInfo.error_from());
+		delete rst;
+		rst = NULL;
+		return ret;
+	}
+	if(rst->result==NULL) {
+		log4cplus_error("result is null [rst->result==NULL]");
+		delete rst;
+		rst = NULL;
+		return -EC_GET_EXPIRETIME_RESULT_NULL;
+	}
+	if(rst->result->total_rows() <= 0) {
+		log4cplus_error("get expireTime fail, no data exist in dtc for key:%s", key);
+		delete rst;
+		rst = NULL;
+		return -EC_GET_EXPIRETIME_END_OF_RESULT;
+	}
+	ret = rst->result->decode_row();
+	if(ret < 0) {
+		log4cplus_error("get expireTime fail, fetch_row error, errmsg:%s, errfrom:%s", rst->resultInfo.error_message(), rst->resultInfo.error_from());
+		delete rst;
+		rst = NULL;
+		return ret;
+	}
+	int expiretime = 0;
+	int id = rst->field_id("_dtc_sys_expiretime");
+	if(id >= 0) {
+		const DTCValue *v;
+		if(id==0 && !(rst->result->field_present(0)))
+			v = rst->result_key();
+		else
+			v = rst->result->field_value(id);
+
+		if(v) {
+			switch(rst->field_type(id)) {
+				case DField::Signed:
+				case DField::Unsigned:
+					{
+						expiretime =  v->s64;
+						break;
+					}
+				case DField::Float:
+					{
+						expiretime =  llround(v->flt);
+						//return (int64_t)(v->flt);
+						break;
+					}
+				case DField::String:
+					{
+						if(v->str.ptr)
+							expiretime =  atoll(v->str.ptr);
+						break;
+					}
+			}
+		}
+	} else {
+		log4cplus_error("can not find field expiretime");
+		delete rst;
+		rst = NULL;
+		return -EC_GET_EXPIRETIME_FIELD_EXPIRETIME_NULL;
+	}
+	delete rst;
+	rst = NULL;
+	return expiretime;
+}

+ 1296 - 0
src/devel/cpp/dtcsvr.cc

@@ -0,0 +1,1296 @@
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <linux/sockios.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <netinet/tcp.h>
+
+#include "socket/unix_socket.h"
+#include "dtcint.h"
+#include <algorithm/timestamp.h>
+#include <container.h>
+
+using namespace std;
+
+const uint32_t ACCESS_KEY_LEN = 40;
+#define CLIENT_CURVE 5
+#define AGENT_CURVE 8
+
+const char* dtc_api_ver="dtc-api-ver:4.3.4"; 
+const char* dtc_api_complite="dtc-api-complite-date:" __DATE__ " " __TIME__;
+
+int NCServer::network_mode_ = 0;
+char * NCServer::server_address_ = NULL;
+char * NCServer::server_tablename_ = NULL;
+extern "C" void set_network_mode(void)
+{
+    NCServer::network_mode_ = 1;
+}
+
+extern "C" void set_server_address(const char * address)
+{
+    NCServer::server_address_ = strdup(address);
+}
+
+extern "C" void set_server_tablename(const char * tablename)
+{
+    NCServer::server_tablename_ = strdup(tablename);
+}
+
+NCServer::NCServer(void)
+{
+	keytype_ = DField::None;
+
+	tablename_ = NULL;
+	appname_ = NULL;
+
+	auto_update_table_ = 1;
+	uto_reconnect_ = 1;
+	table_definition_ = NULL;
+	admin_tdef = NULL;
+	
+	unsigned int a = time(NULL);
+	a = rand_r(&a) + (long)this;
+	last_serialnr_ = rand_r(&a);
+
+	completed_ = 0;
+	badkey_ = 0;
+	badname_ = 0;
+	autoping_ = 0;
+	error_str_ = NULL;
+
+	timeout_ = 5000;
+	realtmo_ = 0;
+
+	service_ = NULL;
+	executor_ = NULL;
+	netfd = -1;
+	last_action_ = 0;
+	ping_request_ = NULL;
+
+	owner_pool_ = NULL;
+	owner_id_ = 0;
+	data_connector_ = DataConnector::getInstance();
+
+	error_count_ = 0;
+	total_count_ = 0;
+	total_elaps_ = 0;
+	remove_count_ = 0;
+}
+
+
+// copy most members, zero connection state
+// copy address if use generic address
+NCServer::NCServer(const NCServer &that) :
+	addr_(that.addr_),
+	keyinfo_(that.keyinfo_)
+{
+#define _MCOPY(x) this->x = that.x
+#define _MZERO(x) this->x = 0
+#define _MNEG(x) this->x = -1
+#define _MDUP(x)	this->x = that.x ? STRDUP(that.x) : NULL
+
+	_MDUP(tablename_);
+	_MDUP(appname_);
+	_MCOPY(keytype_);
+	_MCOPY(auto_update_table_);
+	_MCOPY(uto_reconnect_);
+
+	_MCOPY(completed_);
+	_MCOPY(badkey_);
+	_MCOPY(badname_);
+	_MCOPY(autoping_);
+	// errstr always compile time const string
+	_MCOPY(error_str_);
+
+	_MCOPY(table_definition_);
+	_MCOPY(admin_tdef);
+	if(table_definition_) table_definition_->increase();
+	if(admin_tdef) admin_tdef->increase();
+
+	last_action_ = time(NULL);
+	_MCOPY(timeout_);
+	_MZERO(realtmo_); // this is sockopt set to real netfd
+	_MCOPY(service_);
+	_MCOPY(executor_);
+	_MNEG(netfd);	// real socket fd, cleared
+	_MZERO(ping_request_); // cached ping request object
+
+	unsigned int a = last_action_;
+	a = rand_r(&a) + (long)this;
+	last_serialnr_ = rand_r(&a);
+
+
+	_MZERO(owner_pool_); // serverpool linkage
+	_MZERO(owner_id_); // serverpool linkage
+
+#undef _MCOPY
+#undef _MZERO
+#undef _MNEG
+#undef _MDUP
+}
+
+NCServer::~NCServer(void) 
+{
+	DELETE(ping_request_);
+	Close();
+	FREE_IF(tablename_);
+	FREE_IF(appname_);
+	DEC_DELETE(table_definition_);
+	DEC_DELETE(admin_tdef);
+	DataConnector::getInstance()->send_data();		// 防止10s 间隔时间未到,程序先结束了少报一次
+	DataConnector::getInstance()->send_top_percentile_data();
+}
+
+DataConnector*  NCServer::data_connector_ = NULL;//DataConnector::getInstance();
+
+void NCServer::clone_table_define(const NCServer& source)
+{
+	DEC_DELETE(table_definition_);
+	table_definition_ = source.table_definition_;
+	table_definition_->increase();
+	if(tablename_ != NULL)
+		FREE(tablename_);
+	tablename_ = STRDUP(source.tablename_);
+	keytype_ = source.keytype_;
+	completed_ = 1;
+}
+
+int NCServer::set_address(const char *h, const char *p) {
+	if(h==NULL) {
+		error_str_ = "No Host Specified";
+		return -EC_BAD_HOST_STRING;
+	}
+
+	char *oldhost = NULL;
+	if(addr_.Name() != NULL) {
+		// dup string put on stack
+		oldhost = strdupa(addr_.Name());
+	}
+
+	const char *err = addr_.set_address(h, p);
+	if(err) {
+		this->error_str_ = err;
+		return -EC_BAD_HOST_STRING;
+	}
+
+	// un-changed
+	if(oldhost!=NULL && !strcmp(addr_.Name(), oldhost)) 
+		return 0;
+
+	Close();
+
+    //set network model
+	executor_ = NULL;
+    if(!network_mode_&&service_ && service_->match_listening_ports(addr_.Name(), NULL)) {
+        executor_ = service_->query_task_executor();
+        DTCTableDefinition *t1 = service_->query_table_definition();
+        if(t1 != this->table_definition_) {
+            DEC_DELETE(this->table_definition_);
+            this->table_definition_ = t1;
+        }
+        DTCTableDefinition *t2 = service_->query_admin_table_definition();
+        if(t2 != this->table_definition_) {
+            DEC_DELETE(this->admin_tdef);
+            this->admin_tdef = t2;
+        }
+    }
+
+	return 0;
+}
+
+int NCServer::int_key(void) {
+	if(keytype_ != DField::None && keytype_ != DField::Signed)
+	    return -EC_BAD_KEY_TYPE;
+	keytype_ = DField::Signed;
+	if(tablename_ != NULL) completed_ = 1;
+	return 0;
+}
+
+int NCServer::string_key(void) {
+	if(keytype_ != DField::None && keytype_ != DField::String)
+	    return -EC_BAD_KEY_TYPE;
+	keytype_ = DField::String;
+	if(tablename_ != NULL) completed_ = 1;
+	return 0;
+}
+
+int NCServer::add_key(const char* name, uint8_t type)
+{
+	int ret = keyinfo_.add_key(name, type);
+	// TODO verify tabledef
+	if(ret==0) {
+		if(tablename_ != NULL) completed_ = 1;
+		if(keytype_ == DField::None)
+			keytype_ = type;
+	}
+	return 0;
+}
+
+int NCServer::set_table_name(const char *name) {
+	if(name==NULL) return -EC_BAD_TABLE_NAME;
+
+	if(tablename_)
+		return mystrcmp(name, tablename_, 256)==0 ? 0 : -EC_BAD_TABLE_NAME;
+
+	tablename_ = STRDUP(name);
+
+    if(&NCServer::check_internal_service != 0 && !network_mode_) {
+        check_internal_service();
+    }
+
+	if(keytype_ != DField::None) completed_ = 1;
+
+	return 0;
+}
+
+int NCServer::get_field_type(const char *name) {
+	if(table_definition_ == NULL)
+		ping();
+
+	if(table_definition_ != NULL){
+		int id = table_definition_->field_id(name);
+		if(id >= 0)
+			return table_definition_->field_type(id);
+	}
+	
+	return DField::None;
+}
+
+//fixed, sec --> msec
+void NCServer::set_timeout(int n) {
+	timeout_ = n<=0 ? 5000 : n;
+	update_timeout();
+}
+
+void NCServer::update_timeout(void) {
+	if(netfd >= 0 && realtmo_ != timeout_) {
+		struct timeval tv = { timeout_/1000, (timeout_%1000)*1000 };
+		setsockopt(netfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+		if(timeout_) {
+			if(tv.tv_usec > 1000000)
+			{
+				tv.tv_usec += 100000; // add more 100ms
+			}else {
+				tv.tv_usec += 100; // add more 100us
+			}
+			if(tv.tv_usec >= 1000000)
+			{
+				tv.tv_usec -= 1000000;
+				tv.tv_sec  +=1;
+			}
+		}
+		setsockopt(netfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+		realtmo_ = timeout_;
+	}
+}
+
+void NCServer::update_timeout_anyway(void){
+	if(netfd >= 0) {
+		struct timeval tv = { timeout_/1000, (timeout_%1000)*1000 };
+		setsockopt(netfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+		if(timeout_) {
+			if(tv.tv_usec > 1000000)
+			{
+				tv.tv_usec += 100000; // add more 100ms
+			}else {
+				tv.tv_usec += 100; // add more 100us
+			}
+			if(tv.tv_usec >= 1000000)
+			{
+				tv.tv_usec -= 1000000;
+				tv.tv_sec  +=1;
+			}
+		}
+		setsockopt(netfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+		realtmo_ = timeout_;
+	}
+}
+
+void NCServer::Close(void){
+	if(netfd>=0) {
+		close(netfd);
+		netfd = -1;
+		realtmo_=0;
+	}
+}
+
+int NCServer::bind_temp_unix_socket(void) {
+	struct sockaddr_un tempaddr;
+	tempaddr.sun_family = AF_UNIX;
+	snprintf(tempaddr.sun_path, sizeof(tempaddr.sun_path),
+			"@dtcapi-%d-%d-%d", getpid(), netfd, (int)time(NULL));
+	socklen_t len = SUN_LEN(&tempaddr);
+	tempaddr.sun_path[0] = 0;
+	return bind(netfd, (const sockaddr *)&tempaddr, len);
+}
+
+int NCServer::Connect(void) {
+	if(owner_pool_ != NULL)
+		return -EC_PARALLEL_MODE;
+	if(executor_ != NULL)
+		return 0;
+	if(netfd >= 0)
+		return 0;
+
+	int err = -EC_NOT_INITIALIZED;
+
+	if(addr_.socket_family() != 0) {
+		netfd = addr_.create_socket();
+		if(netfd < 0) {
+			log4cplus_error("create socket error: %d, %m", errno);
+			err = -errno;
+		} else if(addr_.socket_family()==AF_UNIX && is_dgram() && bind_temp_unix_socket() < 0) {
+			log4cplus_error("bind unix socket error: %d, %m", errno);
+			err = -errno;
+			Close();
+		} else {
+			int iRes = -1;
+			//先将netfd设置为非阻塞模式,然后进行connect,返回0,则建立连接成功;返回其它失败
+			fcntl(netfd, F_SETFL, fcntl(netfd, F_GETFL, 0) | O_NONBLOCK);
+			if(addr_.connect_socket(netfd)==0) {
+				iRes = 0;
+			}
+			else{
+				int iTimeout = timeout_<=0 ? 5000 : timeout_;
+				//struct pollfd *pollfds = (struct pollfd *) calloc(1, sizeof(struct pollfd));
+				struct pollfd pollfds[1];
+						
+				pollfds[0].fd = netfd;
+				pollfds[0].events = POLLIN | POLLOUT | POLLERR;
+				int ready_num = poll(pollfds, 1, iTimeout);
+				if (ready_num < 0) {
+					log4cplus_error("network error in connect, errno [%d], errmsg [%s]", errno, strerror(errno));
+				}
+				else if (ready_num == 0) {
+					log4cplus_error("connect time out, errno [%d], errmsg [%s]", errno, strerror(errno));
+				}
+				else {
+					if (pollfds[0].revents & POLLERR) {
+						log4cplus_error("network error in connect, errno [%d], errmsg [%s]", errno, strerror(errno));
+					}
+					else if (pollfds[0].revents & POLLOUT || pollfds[0].revents & POLLIN) {
+						iRes = 0;
+					}
+
+				}
+			}
+			//将netfd恢复为阻塞模式
+			fcntl(netfd, F_SETFL, fcntl(netfd, F_GETFL, 0) & ~O_NONBLOCK);
+			int keepalive = 1; //开启keepalive属性
+			int keepidle = 60; //如该连接在60秒内没有任何数据往来,则进行探测
+			int keepinterval = 5; //探测时发包的时间间隔为5 秒
+			int keepcount = 3; //探测尝试的次数。如果第1次探测包就收到响应了,则后2次的不再发。
+			setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive , sizeof(keepalive ));
+			setsockopt(netfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle ));
+			setsockopt(netfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval ));
+			setsockopt(netfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount ));
+			update_timeout_anyway();
+			
+			if(0 == iRes)
+				return 0;
+			log4cplus_error("connect dtc server error: %d,%m", errno);
+			err = -errno;
+			if(err==-EINPROGRESS) err = -ETIMEDOUT;
+			Close();
+		}
+	}
+	return err;
+}
+
+int NCServer::reconnect(void) {
+	if(owner_pool_ != NULL)
+		return -EC_PARALLEL_MODE;
+	if(executor_ != NULL)
+		return 0;
+	if(netfd < 0)
+		return -ENOTCONN;
+
+	if(addr_.connect_socket(netfd)==0) {
+		return 0;
+	}
+	log4cplus_error("connect dtc server error: %d,%m", errno);
+	int err = -errno;
+	if(err==-EINPROGRESS) err = -ETIMEDOUT;
+	Close();
+	return err;
+}
+
+int NCServer::send_packet_stream(Packet &pk) 
+{
+	int err;
+#ifndef SIOCOUTQ
+	if(1) {
+		char tmp[1];
+		err = recv(netfd, tmp, sizeof(tmp), MSG_PEEK|MSG_DONTWAIT);
+		if(err==0 || (err<0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
+			if(!uto_reconnect_) {
+				log4cplus_error("dtc server close connection: %d,%m", err);
+				return err;
+			} else {
+				log4cplus_debug("%s", "dtc server close connection, re-connect now.");
+				Close();
+				err = Connect();
+				if(err) return err;
+			}
+		}
+	}
+#endif
+
+	while((err = pk.Send(netfd)) == SendResultMoreData)
+	{
+	    if(errno==EINPROGRESS)
+	    {
+			log4cplus_error("socket[%d] send data timeout: %d,%m", netfd, errno);
+	    	// timeout
+			if(1) 
+				Close();
+			return -ETIMEDOUT;
+	    }
+	}
+	if(err != SendResultDone)
+	{
+		log4cplus_error("socket[%d] send data error: %d,%m", netfd, err);
+	    err = -errno;
+	    if(1) 
+		    Close();
+	    return err;
+	}
+	return 0;
+}
+
+// always return network error code
+// EAGAIN must re-sent
+int NCServer::decode_result_stream(NCResult &tk) 
+{
+	if(netfd < 0) 
+	{
+		tk.set_error(-ENOTCONN, "API::recving", "connection is closed");
+		return -ENOTCONN;
+	}
+
+	int err;
+	SimpleReceiver receiver(netfd);
+
+	uint64_t beginTime = 0;
+	
+	while(1)
+	{
+		errno = 0;
+		err = tk.do_decode(receiver);
+
+		if(err == DecodeFatalError) 
+		{
+			log4cplus_error("socket[%d] decode data error: %d, %m", netfd, errno);
+			
+			err = -errno;
+			if(err==0)
+				err = -ECONNRESET;
+#ifdef SIOCOUTQ
+			int value = 0;
+			ioctl(netfd, SIOCOUTQ, &value);
+			// unsent bytes
+			if(value > 0) {
+				err = -EAGAIN;
+				tk.set_error(err, "API::sending", "client send packet error");
+				Close();
+				return err;
+			}
+#endif
+			Close();
+			// EAGAIN never return FatalError, should be DecodeWaitData
+			tk.set_error(err, "API::recving", "client recv packet error");
+			return err;
+		}
+
+		if(err == DecodeDataError)
+		{
+			log4cplus_error("socket[%d] decode data error: %d, %m", netfd, errno);
+			
+			// packet is valid
+			return 0;
+		}
+
+		if(err == DecodeDone)
+		{
+			break;
+		}
+
+		if(errno == EINPROGRESS || errno == EAGAIN)
+		{
+			log4cplus_error("socket[%d] decode data error: %d, %m", netfd, errno);
+			log4cplus_debug("use time %ldms", (long)((GET_TIMESTAMP()-beginTime)/1000));
+			
+			Close();
+			tk.set_error(-ETIMEDOUT, "API::recving", "client recv packet timedout");
+			return -ETIMEDOUT;
+		}
+	}
+
+	save_definition(&tk);
+	if(autoping_) {
+		time(&last_action_);
+		err = tk.versionInfo.keep_alive_timeout();
+		if(err<15) err = 15;
+		last_action_ += err - 1;
+	}
+	return 0;
+}
+
+int NCServer::send_packet_dgram(SocketAddress *peer, Packet &pk)
+{
+	int err = 0;
+
+	while ((err = pk.send_to(netfd, peer)) == SendResultMoreData)
+	{
+		if (errno == EINPROGRESS)
+		{
+			log4cplus_error("socket[%d] send data timeout: %d,%m", netfd, errno);
+			// timeout
+			return -ETIMEDOUT;
+		}
+	}
+
+	if (err != SendResultDone)
+	{
+		log4cplus_error("socket[%d] send data error: %d,%m", netfd, err);
+		err = -errno;
+		return err;
+	}
+	return 0;
+}
+
+static inline char *RecvFromFixedSize(int fd, int len, int &err, struct sockaddr *peeraddr, socklen_t *addrlen)
+{
+	int blen = len <= 0 ? 1 : len;
+	char *buf = (char *)MALLOC(blen);
+	blen = recvfrom(fd, buf, blen, 0, peeraddr, addrlen);
+	if(blen < 0) {
+		err = errno;
+		free(buf);
+		buf = NULL;
+	} else if(blen != len) {
+		err = EIO;
+		free(buf);
+		buf = NULL;
+	} else {
+		err = 0;
+	}
+
+	return buf;
+}
+
+static char *RecvPacketPeek(int fd, int &len, int &err)
+{
+	// MSG_PEEK + MSG_TRUNC get next packet size
+	char dummy[1];
+	len = recv(fd, dummy, 1, MSG_PEEK|MSG_TRUNC);
+	if(len < 0) {
+		err = errno;
+		return NULL;
+	}
+
+	return RecvFromFixedSize(fd, len, err, NULL, NULL);
+}
+
+static char *RecvPacketPeekPeer(int fd, SocketAddress *peer, int &len, int &err)
+{
+	struct sockaddr peeraddr;
+	socklen_t sock_len;
+
+	for (int n=0; n<10; n++) {
+		char dummy[1];
+
+		sock_len = sizeof(peeraddr);
+		len = recvfrom(fd, dummy, 1, MSG_PEEK|MSG_TRUNC, &peeraddr, &sock_len);
+		if(len < 0) {
+			err = errno;
+			return NULL;
+		}
+
+		if(peer->Equal(&peeraddr, sock_len, SOCK_DGRAM))
+			break;
+	}
+
+	return RecvFromFixedSize(fd, len, err, &peeraddr, &sock_len);
+}
+
+static char *RecvPacketPoll(int fd, int msec, int &len, int &err)
+{
+	struct pollfd pfd;
+	pfd.fd = fd;
+	pfd.events = POLLIN;
+	int n;
+	
+	while( (n = poll(&pfd, 1, msec)) < 0 && errno == EINTR)
+		/* LOOP IF EINTR */;
+
+	if(n == 0) {
+		err = EAGAIN;
+		return NULL;
+	}
+	if(n < 0) {
+		err = errno;
+		return NULL;
+	}
+
+	len = 0;
+	ioctl(fd, SIOCINQ, &len);
+
+	return RecvFromFixedSize(fd, len, err, NULL, NULL);
+}
+
+// always return network error code
+// EAGAIN must re-sent
+int NCServer::decode_result_dgram(SocketAddress *peer, NCResult &tk) 
+{
+	if(netfd < 0) 
+	{
+		tk.set_error(-ENOTCONN, "API::recving", "connection is closed");
+		return -ENOTCONN;
+	}
+
+	int saved_errno; // saved errno
+	int len; // recv len
+	char *buf; // packet buffer
+	uint64_t beginTime = 0;
+
+	log4cplus_debug("wait response time stamp = %lld", (long long)(beginTime = GET_TIMESTAMP()));
+	
+	if(addr_.socket_family() == AF_UNIX) {
+		if(peer == NULL) {
+			buf = RecvPacketPoll(netfd, timeout_,  len, saved_errno);
+		} else {
+			if(peer->connect_socket(netfd) < 0) {
+				saved_errno = errno;
+				log4cplus_error("connect dtc server error: %d,%m", saved_errno);
+				if(saved_errno == EAGAIN) {
+					// unix socket return EAGAIN if listen queue overflow
+					saved_errno = EC_SERVER_BUSY;
+				}
+				tk.set_error(-saved_errno, "API::connecting", "client api connect server error");
+				return -saved_errno;
+			}
+
+			buf = RecvPacketPoll(netfd, timeout_, len, saved_errno);
+
+			// Un-connect
+			struct sockaddr addr;
+			addr.sa_family = AF_UNSPEC;
+			connect(netfd, &addr, sizeof(addr));
+		}
+	} else {
+		if(peer == NULL) {
+			buf = RecvPacketPeek(netfd, len, saved_errno);
+		} else {
+			buf = RecvPacketPeekPeer(netfd, peer, len, saved_errno);
+		}
+	}
+	log4cplus_debug("receive result use time: %ldms", (long)((GET_TIMESTAMP()-beginTime)/1000));
+
+	if(buf == NULL)
+	{
+		errno = saved_errno;
+		log4cplus_error("socket[%d] recv udp data error: %d,%m", netfd, saved_errno);
+
+		if(saved_errno == EAGAIN) {
+			// change errcode to TIMEDOUT;
+			saved_errno = ETIMEDOUT;
+			tk.set_error(-ETIMEDOUT, "API::recving", "client recv packet timedout");
+		} else {
+			if(saved_errno==0)
+				saved_errno = ECONNRESET;
+			tk.set_error(-saved_errno, "API::recving", "connection reset by peer");
+		}
+		return -saved_errno;
+	}
+
+	int err = tk.do_decode(buf, len, 1 /*eat buf*/);
+
+	switch(err) {
+	case DecodeFatalError:
+		log4cplus_error("socket[%d] decode udp data error: invalid packet content", netfd);
+		tk.set_error(-ECONNRESET, "API::recving", "invalid packet content");
+		FREE_IF(buf); // buf not eaten
+		return -ECONNRESET;
+
+	case DecodeWaitData:
+	default:
+		// UNREACHABLE, decode_packet never return these code
+		log4cplus_error("socket[%d] decode udp data error: %d, %m", netfd, errno);
+		tk.set_error(-ETIMEDOUT, "API::recving", "client recv packet timedout");
+		return -ETIMEDOUT;
+
+	case DecodeDataError:
+		// packet maybe valid
+		break;
+
+	case DecodeDone:
+		save_definition(&tk);
+		break;
+
+	}
+
+	return 0;
+}
+
+//Get udpport form udppool
+NCUdpPort *NCServer::get_global_port()
+{
+    NCUdpPort *udpport = NCUdpPort::get_family_port(addr_.socket_family());
+
+    if (udpport)
+    {
+	    netfd = udpport->fd;
+	    last_serialnr_ = udpport->sn;
+	    realtmo_ = udpport->timeout; 
+	    update_timeout();
+    }
+
+    return udpport;
+}
+
+//Put the udpport to the udppool
+void NCServer::put_global_port(NCUdpPort *udpport)
+{
+	if (udpport)
+	{
+		if (netfd > 0)
+		{
+			udpport->sn = last_serialnr_;
+			udpport->timeout = realtmo_;
+			netfd = -1;
+			udpport->put_list_node();
+		}
+		else
+		{
+			//if fd error, delete this udpport object
+			udpport->delete_port();
+		}
+	}
+}
+
+void NCServer::save_definition(NCResult *tk)
+{
+	if(strcmp("*", tablename_)!=0 && tk->result_code()==-EC_TABLE_MISMATCH) {
+		badname_ = 1;
+		error_str_ = "Table Name Mismatch";
+		return;
+	}
+	if(strcmp("*", tablename_)!=0 && tk->result_code()==-EC_BAD_KEY_TYPE) {
+		badkey_ = 1;
+		error_str_ = "Key Type Mismatch";
+		return;
+	}
+	
+	DTCTableDefinition *t = tk->remote_table_definition();
+	if(t == NULL) return;
+
+	if(t->is_admin_table()){
+		if(admin_tdef)
+		{
+			if(admin_tdef->is_same_table(t)) return;
+			if(!auto_update_table_){
+				badname_ = 1;
+				error_str_ = "Table Mismatch";
+				tk->set_error(-EC_TABLE_MISMATCH, "API::executed", "AdminTable Mismatch");
+				return;
+			}
+			DEC_DELETE(admin_tdef);
+		}
+		admin_tdef = t;
+		admin_tdef->increase();
+	}
+	else{
+		if(table_definition_)
+		{
+			if(table_definition_->is_same_table(t)) return;
+			if(!auto_update_table_){
+				badname_ = 1;
+				error_str_ = "Table Mismatch";
+				tk->set_error(-EC_TABLE_MISMATCH, "API::executed", "Table Mismatch");
+				return;
+			}
+			DEC_DELETE(table_definition_);
+		}
+		table_definition_ = t;
+		table_definition_->increase();
+		
+		FREE(tablename_);
+		tablename_ = STRDUP(table_definition_->table_name());
+		keytype_ = table_definition_->key_type();
+
+	    //bugfix, by ada
+	    if(keytype_ == DField::Unsigned)
+	        keytype_ = DField::Signed;
+
+	    if(keytype_ == DField::Binary)
+	        keytype_ = DField::String;
+	}
+}
+
+void NCServer::try_ping(void) {
+	if(autoping_ && netfd >= 0) {
+		time_t now;
+		time(&now);
+		if(now >= last_action_)
+			ping();
+	}
+}
+
+int NCServer::ping(void) {
+	if(owner_pool_ != NULL)
+		return -EC_PARALLEL_MODE;
+	if(executor_ != NULL)
+		return 0;
+		NCRequest r(this, DRequest::TYPE_PASS);
+	NCResult *t = r.execute_network();
+	int ret = t->result_code();
+	delete t;
+	return ret;
+}
+
+NCResult *NCServer::decode_buffer(const char *buf, int len)
+{
+	NCResult *res = new NCResult(table_definition_);
+
+	switch(len <= (int)sizeof(PacketHeader) ? DecodeFatalError : res->do_decode(buf, len))
+	{
+		default:
+			res->set_error(-EINVAL, "API::decoding", "invalid packet content");
+			break;
+		case DecodeDataError:
+		case DecodeDone:
+			break;
+	}
+	return res;
+}
+
+int NCServer::check_packet_size(const char *buf, int len)
+{
+	return NCResult::check_packet_size(buf, len);
+}
+
+/*date:2014/06/04, author:xuxinxin*/
+int NCServer::set_accesskey(const char *token)
+{
+	int ret = 0;
+	std::string str;
+	if(token == NULL)
+		return -EC_BAD_ACCESS_KEY;
+	else
+		str = token;
+	if(str.length() != ACCESS_KEY_LEN)
+	{
+		log4cplus_error("Invalid accessKey!");
+		access_token_ = "";
+		return -EC_BAD_ACCESS_KEY;
+	}
+	else
+		access_token_ = str;
+
+	/* 截取  AccessKey中前32位以后的bid, 以便上报至数据采集 dtchttpd */
+	ret = data_connector_->set_bussiness_id(access_token_);
+	ret = data_connector_->set_top_percentile_config(access_token_, this->get_address());
+	if(ret ==0)
+		return -EC_BAD_ACCESS_KEY;
+	return 0;
+}
+
+DataConnector* DataConnector::pDataConnector = NULL;
+
+pthread_mutex_t wakeLock;
+static void *do_process(void *p)
+{
+	sigset_t sset;
+	sigfillset(&sset);
+	sigdelset(&sset, SIGSEGV);
+	sigdelset(&sset, SIGBUS);
+	sigdelset(&sset, SIGABRT);
+	sigdelset(&sset, SIGILL);
+	sigdelset(&sset, SIGCHLD);
+	sigdelset(&sset, SIGFPE);
+	pthread_sigmask(SIG_BLOCK, &sset, &sset);
+
+//	int ret = 0;
+	time_t next = 0;
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	int offset = random() % 10;
+	next = (tv.tv_sec / 10) * 10 + 10 + offset;
+	struct timespec ts;
+	ts.tv_sec = next;
+	ts.tv_nsec = 0;
+
+	while(pthread_mutex_timedlock(&wakeLock, &ts)!=0)
+	{
+		gettimeofday(&tv, NULL);
+		if(tv.tv_sec >= next)
+		{
+//			ret = DataConnector::getInstance()->send_data();
+//			ret = DataConnector::getInstance()->send_top_percentile_data();
+			gettimeofday(&tv, NULL);
+			next = (tv.tv_sec / 10) * 10 + 10 + offset;
+		}
+		ts.tv_sec = next;
+		ts.tv_nsec = 0;
+	}
+	pthread_mutex_unlock(&wakeLock);
+	return NULL;
+}
+
+/* date:2014/06/09, author:xuxinxin */
+DataConnector::DataConnector()
+{
+}
+
+DataConnector::~DataConnector()
+{
+}
+
+int DataConnector::send_data()
+{
+	return 0;
+}
+
+int DataConnector::set_report_info(const std::string str, const uint32_t curve, const uint64_t t)
+{
+	uint32_t bid = 0;
+	std::string stemp = str.substr(0,8);
+	sscanf(stemp.c_str(), "%u", &bid);
+	struct bidCurve bc;
+	bc.bid = bid;
+	bc.curve = curve;
+
+	if(mapBi.find(bc) != mapBi.end())
+	{
+		do
+		{
+			ScopedLock lock(lock_);
+			mapBi[bc].TotalTime += t;
+			mapBi[bc].TotalRequests += 1;
+		}while(0);
+	}
+	return 0;
+}
+
+void DataConnector::get_report_info(std::map<bidCurve, businessStatistics> &map)
+{
+	ScopedLock lock(lock_);
+	for(std::map<bidCurve, businessStatistics>::iterator it = mapBi.begin(); it != mapBi.end(); ++it)
+	{
+		struct businessStatistics bs;
+		map[it->first] = it->second;
+		/*  mapBi 取出来之后,不管后面是否上报成功,该bid对应的数据都丢弃,重置为0  */
+		mapBi[it->first] = bs;
+	}
+}
+
+int DataConnector::set_bussiness_id(std::string str)
+{
+	ScopedLock lock(lock_);
+	if(mapBi.size() == 0)
+	{
+		pthread_mutex_init(&wakeLock, NULL);
+		if(pthread_mutex_trylock(&wakeLock) == 0)
+		{
+			int ret = pthread_create(&thread_id_, 0, do_process, (void *)NULL);
+			if(ret != 0)
+			{
+				errno = ret;
+				return -1;
+			}
+		}
+	}
+	std::string stemp = str.substr(0, 8);
+	uint32_t bid = 0;
+	sscanf(stemp.c_str(), "%u", &bid);
+
+	struct businessStatistics bs;
+	struct bidCurve bclient, bagent;
+	bclient.bid = bid;
+	bclient.curve = CLIENT_CURVE;
+
+	bagent.bid = bid;
+	bagent.curve = AGENT_CURVE;
+	mapBi.insert(std::make_pair(bclient, bs));
+	mapBi.insert(std::make_pair(bagent, bs));
+	return 0;
+}
+
+int DataConnector::send_top_percentile_data()
+{
+	return 0;
+}
+
+int DataConnector::set_top_percentile_data(const std::string strAccessKey, const std::string strAgentAddr, const uint64_t elapse, const int status)
+{
+	if(strAccessKey.empty())
+		return -1;
+	if(strAgentAddr.empty())
+		return -1;
+	if(!isdigit(strAgentAddr[0]))
+		return -1;
+
+	uint32_t uiBid = 0;
+	std::string stemp = strAccessKey.substr(0,8);
+	sscanf(stemp.c_str(), "%u", &uiBid);
+	
+	uint64_t uiIP;
+	uint64_t uiPort;
+	if(parse_address(strAgentAddr, &uiIP, &uiPort) < 0)
+		return -1;
+
+	uint16_t iRealSite = CTopPercentileSection::get_tp_section(elapse);
+	if(iRealSite < 0 || iRealSite >= sizeof(kpi_sample_count) / sizeof(kpi_sample_count[0]))
+		return -1;
+
+	uint64_t uiKey = (uiIP << 32) | (uiPort << 16) | (uint64_t)uiBid;
+	std::map<uint64_t, DataConnector::top_percentile_statistics>::iterator it;
+	ScopedLock lock(m_tp_lock);
+	if((it = map_tp_stat_.find(uiKey)) == map_tp_stat_.end())
+	{
+		DataConnector::top_percentile_statistics tpStat;
+		tpStat.uiBid = uiBid;
+		tpStat.uiAgentIP = uiIP;
+		tpStat.uiAgentPort = uiPort;
+		std::pair<std::map<uint64_t, DataConnector::top_percentile_statistics>::iterator, bool> pairRet;
+		pairRet = map_tp_stat_.insert(std::make_pair(uiKey, tpStat));
+		if(!pairRet.second)
+			return -1;
+		it = pairRet.first;
+	}
+
+	if(it->second.uiMaxTime < elapse)
+		it->second.uiMaxTime = elapse;
+	if(0 == it->second.uiMinTime)
+		it->second.uiMinTime = elapse;
+	else if(it->second.uiMinTime > elapse)
+		it->second.uiMinTime = elapse;
+	if(0 != status)
+		it->second.uiFailCount ++;
+	it->second.uiTotalRequests ++;
+	it->second.uiTotalTime += elapse;
+	it->second.statArr[iRealSite] ++;
+	
+	return 0;
+}
+
+void DataConnector::get_top_percentile_data(std::map<uint64_t, top_percentile_statistics> &mapStat)
+{
+	ScopedLock lock(m_tp_lock);
+	std::swap(map_tp_stat_, mapStat);
+}
+
+/*
+ *@strAccessKey:00001460ccea307caad065107c936c88bc59b1a4
+ *@strAgentAddr:192.168.145.135:20024/tcp
+ */
+int DataConnector::set_top_percentile_config(const std::string strAccessKey, const std::string strAgentAddr)
+{
+	if(strAccessKey.empty())
+		return -1;
+	if(strAgentAddr.empty())
+		return -1;
+	if(!isdigit(strAgentAddr[0]))
+		return -1;
+	uint64_t uiIP = 0;
+	uint64_t uiPort = 0;
+	if(parse_address(strAgentAddr, &uiIP, &uiPort) < 0)
+		return -1;
+	uint32_t uiBid = 0;
+	std::string strTemp = strAccessKey.substr(0,8);
+	sscanf(strTemp.c_str(), "%u", &uiBid);
+	struct top_percentile_statistics tpStat;
+	tpStat.uiBid = uiBid;
+	tpStat.uiAgentIP = (uint32_t)uiIP;
+	tpStat.uiAgentPort = (uint16_t)uiPort;
+	map_tp_stat_.insert(std::make_pair((uiIP << 32) | (uiPort << 16) | uiBid, tpStat));
+	return 0;
+}
+
+/*
+ *@strAddr:192.168.145.135:20024/tcp
+ */
+int DataConnector::parse_address(const std::string strAddr, uint64_t *uipIP /* = NULL */, uint64_t *uipPort /* = NULL */)
+{
+	if(strAddr.empty())
+		return -1;
+	if(!isdigit(strAddr[0]))
+		return -1;
+	const char *szAgentAddr = strAddr.c_str();
+	const char *szPortProtocol = strchr(strAddr.c_str(), ':');
+	if(NULL == szPortProtocol)
+		return -1;
+	//":"后面必然需要有端口,若是长度小于2,则数据有问题
+	if(strlen((char *)szPortProtocol) < 2)
+		return -1;
+	if(!isdigit(szPortProtocol[1]))
+		return -1;
+	struct in_addr addr;
+	uint32_t uiLen = szPortProtocol - szAgentAddr;
+	char szIP[uiLen + 1];
+	memcpy(szIP, szAgentAddr, uiLen);
+	szIP[uiLen] = 0;
+	if(1 != inet_pton(AF_INET, szIP, &addr))
+		return -1;
+	*uipIP = 0;
+	*uipPort = 0;
+	*uipIP = (uint64_t)ntohl(addr.s_addr);
+	*uipPort = (uint64_t)atoi(szPortProtocol + 1);
+	if(0 == *uipIP || 0 == *uipPort)
+		return -1;
+	return 0;
+}
+
+/*
+ *以下数组中的值对应的为kpi_sample_count数组的下标,即跟随在其后注释中的数值所在的位置
+ */
+int16_t CTopPercentileSection::get_tp_section(uint64_t elapse)
+{
+	if(elapse < THOUSAND)
+		return get_little_thousand(elapse);
+	else if(THOUSAND <= elapse && elapse < TENTHOUSAND)
+		return get_between_thousand_and_tenthousand(elapse);
+	else if(TENTHOUSAND <= elapse && elapse < HUNDREDTHOUSAND)
+		return get_between_tenthousand_and_hundredthousand(elapse);
+	else if(HUNDREDTHOUSAND <= elapse && elapse < MILLION)
+		return get_between_hundredthousand_and_million(elapse);
+	else
+		return get_exceed_million(elapse);
+
+	return -1;
+}
+
+int16_t CTopPercentileSection::get_little_thousand(uint64_t elapse)
+{
+	if(elapse < THOUSAND)
+	{
+		static int16_t iSiteArr[] =
+		{
+			0,/*200us下标*/
+			0,/*200us下标*/
+			1,/*500us下标*/
+			1,/*500us下标*/
+			1,/*500us下标*/
+			2,/*1000us下标*/
+			2,/*1000us下标*/
+			2,/*1000us下标*/
+			2,/*1000us下标*/
+			2/*1000us下标*/
+		};
+		int16_t iSite = elapse / HUNDRED;
+		if(iSite < 0 || iSite >= int16_t(sizeof(iSiteArr) / sizeof(iSiteArr[0])))
+			return -1;
+		return iSiteArr[iSite];
+	}
+	return -1;
+}
+
+int16_t CTopPercentileSection::get_between_thousand_and_tenthousand(uint64_t elapse)
+{
+	if(THOUSAND <= elapse && elapse < TENTHOUSAND)
+	{
+		static int16_t iSiteArr[] =
+		{
+			3,/*2000us下标*/
+			4,/*3000us下标*/
+			5,/*4000us下标*/
+			6,/*5000us下标*/
+			7,/*6000us下标*/
+			8,/*7000us下标*/
+			9,/*8000us下标*/
+			10,/*9000us下标*/
+			11/*10000us下标*/
+		};
+		int16_t iSite = elapse / THOUSAND - 1;
+		if(iSite < 0 || iSite >= int16_t(sizeof(iSiteArr) / sizeof(iSiteArr[0])))
+			return -1;
+		return iSiteArr[iSite];
+	}
+	return -1;
+}
+
+int16_t CTopPercentileSection::get_between_tenthousand_and_hundredthousand(uint64_t elapse)
+{
+	if(TENTHOUSAND <= elapse && elapse < HUNDREDTHOUSAND)
+	{
+		static int16_t iSiteArr[] =
+		{
+			12,/*20000us下标*/
+			13,/*30000us下标*/
+			14,/*40000us下标*/
+			15,/*50000us下标*/
+			16,/*60000us下标*/
+			17,/*70000us下标*/
+			18,/*80000us下标*/
+			19,/*90000us下标*/
+			20/*100000us下标*/
+		};
+		int16_t iSite = elapse / TENTHOUSAND - 1;
+		if(iSite < 0 || iSite >= int16_t(sizeof(iSiteArr) / sizeof(iSiteArr[0])))
+			return -1;
+		return iSiteArr[iSite];
+	}
+	return -1;
+}
+
+int16_t CTopPercentileSection::get_between_hundredthousand_and_million(uint64_t elapse)
+{
+	if(HUNDREDTHOUSAND <= elapse && elapse < MILLION)
+	{
+		static int16_t iSiteArr[] =
+		{
+			21,/*200000us下标*/
+			22,/*300000us下标*/
+			23,/*400000us下标*/
+			24,/*500000us下标*/
+			25,/*600000us下标*/
+			26,/*700000us下标*/
+			27,/*800000us下标*/
+			28,/*900000us下标*/
+			29/*1000000us下标*/
+		};
+		int16_t iSite = elapse / HUNDREDTHOUSAND - 1;
+		if(iSite < 0 || iSite >= int16_t(sizeof(iSiteArr) / sizeof(iSiteArr[0])))
+			return -1;
+		return iSiteArr[iSite];
+	}
+	return -1;
+}
+
+int16_t CTopPercentileSection::get_exceed_million(uint64_t elapse)
+{
+	if(elapse >= MILLION)
+	{
+		static int16_t iSiteArr[] =
+		{
+			30,/*2000000us下标*/
+			31,/*5000000us下标*/
+			31,/*5000000us下标*/
+			31,/*5000000us下标*/
+			32,/*10000000us下标*/
+			32,/*10000000us下标*/
+			32,/*10000000us下标*/
+			32,/*10000000us下标*/
+			32,/*10000000us下标*/
+			32/*10000000us下标*/
+		};
+		int16_t iSite = elapse / MILLION - 1;
+		int16_t iArrLen = int16_t(sizeof(iSiteArr) / sizeof(iSiteArr[0]));
+		iSite = (iSite >= iArrLen) ? (iArrLen - 1) : iSite;
+		if(iSite < 0)
+			return -1;
+		return iSiteArr[iSite];
+	}
+	return -1;
+}

+ 1381 - 0
src/devel/cpp/dtcwrap.cc

@@ -0,0 +1,1381 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <new>
+
+#include "dtcapi.h"
+#include "dtcint.h"
+#include <string.h>
+#include <protocol.h>
+#include "compiler.h"
+
+
+using namespace DTC;
+
+#define CAST(type, var) type *var = (type *)addr_
+#define CAST2(type, var, src) type *var = (type *)src->addr_
+#define CAST2Z(type, var, src) type *var = (type *)((src)?(src)->addr_:0)
+#define CAST3(type, var, src) type *var = (type *)src.addr_
+
+
+
+__EXPORT
+int DTC::set_key_value_max(unsigned int count)
+{
+	if(count >= 8 && count <= 10000) {
+		NCKeyValueList::key_value_max_ = count;
+	} else  {
+		return -EINVAL;
+	}
+	return 0;
+};
+
+/* WRAPPER for Server */
+__EXPORT
+Server::Server(void) 
+{
+	NCServer *srv = new NCServer;
+	srv->increase();
+	addr_ = srv;
+}
+
+__EXPORT
+Server::Server(const Server &that) 
+{
+	CAST3(NCServer, old, that);
+	NCServer *srv = new NCServer(*old);
+	srv->increase();
+	addr_ = srv;
+}
+
+__EXPORT
+Server::~Server(void) 
+{
+	CAST(NCServer, srv);  
+	DEC_DELETE(srv);
+}
+
+__EXPORT
+int Server::set_address(const char *host, const char *port) 
+{
+	CAST(NCServer, srv);
+	return srv->set_address(host, port);
+}
+
+__EXPORT
+int Server::set_table_name(const char *name) 
+{
+	CAST(NCServer, srv);
+	return srv->set_table_name(name);
+}
+
+__EXPORT
+void Server::set_compress_level(int level) 
+{
+	CAST(NCServer, srv);
+	srv->set_compress_level(level);
+}
+
+__EXPORT
+const char * Server::get_address(void) const
+{
+	CAST(NCServer, srv);
+	return srv ? srv->get_address() : NULL;
+}
+
+__EXPORT
+const char * Server::get_table_name(void) const 
+{
+	CAST(NCServer, srv);
+	return srv ? srv->get_table_name() : NULL;
+}
+
+__EXPORT
+const char * Server::get_server_address(void) const 
+{
+	CAST(NCServer, srv);
+	return srv ? srv->get_server_address() : NULL;
+}
+
+__EXPORT
+const char * Server::get_server_table_name(void) const 
+{
+	CAST(NCServer, srv);
+	return srv ? srv->get_server_table_name() : NULL;
+}
+__EXPORT
+void Server::clone_table_define(const Server& source)
+{
+	CAST(NCServer, srv);
+	CAST3(NCServer, ssrv, source);
+	srv->clone_table_define(*ssrv);
+}
+
+__EXPORT
+int Server::int_key(void) 
+{
+	CAST(NCServer, srv);
+	return srv->int_key();
+}
+
+__EXPORT
+int Server::string_key(void) 
+{
+	CAST(NCServer, srv);
+	return srv->string_key();
+}
+
+__EXPORT
+int Server::binary_key(void) 
+{
+	CAST(NCServer, srv);
+	return srv->string_key();
+}
+
+__EXPORT
+int Server::add_key(const char* name, int type) 
+{
+	CAST(NCServer, srv);
+	return srv->add_key(name, (uint8_t)type);
+}
+
+__EXPORT
+int Server::get_field_type(const char* name) 
+{
+	CAST(NCServer, srv);
+	return srv->get_field_type(name);
+}
+
+__EXPORT
+const char * Server::get_error_message(void) const 
+{
+	CAST(NCServer, srv);
+	return srv->get_error_message();
+}
+
+/* fixed, sec ---> msec */
+__EXPORT
+void Server::set_timeout(int n) 
+{
+	CAST(NCServer, srv);
+	return srv->set_timeout(n);
+}
+
+__EXPORT
+void Server::SetTimeout(int n) 
+{
+	CAST(NCServer, srv);
+	return srv->set_timeout(n*1000);
+}
+
+__EXPORT
+int Server::Connect(void) 
+{
+	CAST(NCServer, srv);
+	return srv->Connect();
+}
+
+__EXPORT
+void Server::Close(void) 
+{
+	CAST(NCServer, srv);
+	return srv->Close();
+}
+
+__EXPORT
+int Server::ping(void) 
+{
+	CAST(NCServer, srv);
+	return srv->ping();
+}
+
+__EXPORT
+void Server::auto_ping(void) 
+{
+	CAST(NCServer, srv);
+	return srv->auto_ping();
+}
+
+__EXPORT
+void Server::set_fd(int fd) 
+{
+	CAST(NCServer, srv);
+	srv->set_fd(fd);
+}
+
+__EXPORT
+void Server::set_auto_Update_table(bool autoUpdate)
+{
+	CAST(NCServer, srv);
+	srv->set_auto_Update_table(autoUpdate);
+}
+
+__EXPORT
+void Server::set_auto_reconnect(int auto_reconnect)
+{
+	CAST(NCServer, srv);
+	srv->set_auto_reconnect(auto_reconnect);
+}
+
+__EXPORT
+void Server::set_accesskey(const char *token)
+{
+	CAST(NCServer, srv);
+	srv->set_accesskey(token);
+}
+
+/* QOS ADD BY NEOLV */
+__EXPORT
+void Server::increase_error_count_()
+{
+	CAST(NCServer, srv);
+	srv->increase_error_count_();
+}
+
+__EXPORT
+uint64_t Server::get_error_count()
+{
+	CAST(NCServer, srv);
+	return srv->get_error_count();
+}
+__EXPORT
+void Server::clear_error_count()
+{
+	CAST(NCServer, srv);
+	srv->clear_error_count();
+}
+
+__EXPORT
+void Server::increase_remove_count()
+{
+	CAST(NCServer, srv);
+	srv->increase_remove_count();
+}
+
+__EXPORT
+int Server::get_remove_count()
+{
+	CAST(NCServer, srv);
+	return srv->get_remove_count();
+}
+
+__EXPORT
+void Server::clear_remove_count()
+{
+	CAST(NCServer, srv);
+	srv->clear_remove_count();
+}
+__EXPORT
+void Server::increase_total_request()
+{
+	CAST(NCServer, srv);
+	srv->increase_total_request();
+}
+__EXPORT
+uint64_t Server::get_total_request()
+{
+	CAST(NCServer, srv);
+	return srv->get_total_request();
+}
+__EXPORT
+void Server::clear_total_request()
+{
+	CAST(NCServer, srv);
+	srv->clear_total_request();
+}
+
+__EXPORT
+void Server::add_total_elaps(uint64_t iElaps)
+{
+	CAST(NCServer, srv);
+	srv->add_total_elaps(iElaps);
+}
+__EXPORT
+uint64_t Server::get_total_elaps()
+{
+	CAST(NCServer, srv);
+	return srv->get_total_elaps();
+}
+__EXPORT
+void Server::clear_total_elaps()
+{
+	CAST(NCServer, srv);
+	srv->clear_total_elaps();
+}
+
+/* WRAPER for Request */
+
+__EXPORT
+Request::Request(Server *srv0, int op) {
+	CAST2Z(NCServer, srv, srv0);
+	NCRequest *req = new NCRequest(srv, op);
+	addr_ = (void *)req;
+}
+
+Request::Request()
+{
+	NCRequest *req = new NCRequest(NULL, 0);
+	addr_ = (void *)req;
+}
+
+__EXPORT
+Request::~Request(void) 
+{
+	CAST(NCRequest, req);
+	delete req;
+}
+
+__EXPORT
+int Request::attach_server(Server *srv0) 
+{
+	CAST2Z(NCServer, srv, srv0);
+	CAST(NCRequest, r);
+	return r->attach_server(srv);
+}
+
+__EXPORT
+void Request::Reset(void) 
+{
+	CAST(NCRequest, old);
+	if(old) {
+		int op = old->cmd;
+		NCServer *srv = old->server;
+		srv->increase();
+		old->~NCRequest();
+		memset(old, 0, sizeof(NCRequest));
+		new(addr_) NCRequest(srv, op);
+		srv->decrease();
+	}
+}
+
+__EXPORT
+void Request::Reset(int op)
+{
+	CAST(NCRequest, old);
+	if (old) {
+		NCServer *srv = old->server;
+		srv->increase();
+		old->~NCRequest();
+		memset(old, 0, sizeof(NCRequest));
+		new(addr_) NCRequest(srv, op);
+		srv->decrease();
+	}
+}
+
+__EXPORT
+void Request::set_admin_code(int code) 
+{
+	CAST(NCRequest, r);
+	r->set_admin_code(code);
+}
+
+__EXPORT
+void Request::set_hotbackup_id(long long v) 
+{
+	CAST(NCRequest, r);
+	r->set_hotbackup_id(v);
+}
+
+__EXPORT
+void Request::set_master_hotbackup_timestamp(long long t) 
+{
+	CAST(NCRequest, r);
+	r->set_master_hotbackup_timestamp(t);
+}
+
+__EXPORT
+void Request::set_slave_hotbackup_timestamp(long long t) 
+{
+	CAST(NCRequest, r);
+	r->set_slave_hotbackup_timestamp(t);
+}
+
+__EXPORT
+void Request::no_cache(void) 
+{
+	CAST(NCRequest, r); return r->enable_no_cache();
+}
+
+__EXPORT
+void Request::no_next_server(void) 
+{
+	CAST(NCRequest, r); return r->enable_no_next_server();
+}
+
+__EXPORT
+int Request::need(const char *name) 
+{
+	CAST(NCRequest, r); return r->need(name, 0);
+}
+
+__EXPORT
+int Request::need(const char *name, int vid) 
+{
+	CAST(NCRequest, r); return r->need(name, vid);
+}
+
+__EXPORT
+int Request::get_field_type(const char *name) 
+{
+	CAST(NCRequest, r); return r->get_field_type(name);
+}
+
+__EXPORT
+void Request::limit(unsigned int st, unsigned int cnt) 
+{
+	CAST(NCRequest, r); return r->limit(st, cnt);
+}
+
+__EXPORT
+void Request::unset_key(void) 
+{
+	CAST(NCRequest, r);
+	r->unset_key();
+	r->unset_key_value();
+}
+
+__EXPORT
+int Request::set_key(long long key) 
+{
+	CAST(NCRequest, r); return r->set_key((int64_t)key);
+}
+
+__EXPORT
+int Request::set_key(const char *key) 
+{
+	CAST(NCRequest, r); return r->set_key(key, strlen(key));
+}
+
+__EXPORT
+int Request::set_key(const char *key, int len) 
+{
+	CAST(NCRequest, r); return r->set_key(key, len);
+}
+
+__EXPORT
+int Request::add_key_value(const char* name, long long v) 
+{
+	CAST(NCRequest, r);
+	DTCValue key(v);
+	return r->add_key_value(name, key, kKeyTypeInt);
+}
+
+__EXPORT
+int Request::add_key_value(const char* name, const char *v) 
+{
+	CAST(NCRequest, r);
+	DTCValue key(v);
+	return r->add_key_value(name, key, kKeyTypeString);
+}
+
+__EXPORT
+int Request::add_key_value(const char* name, const char *v, int len) 
+{
+	CAST(NCRequest, r);
+	DTCValue key(v, len);
+	return r->add_key_value(name, key, kKeyTypeString);
+}
+
+__EXPORT
+int Request::set_cache_id(long long id)
+{
+    CAST(NCRequest, r); return r->set_cache_id(id);
+}
+
+__EXPORT
+Result *Request::do_execute(void) 
+{
+	Result *s = new Result();
+	CAST(NCRequest, r);
+	s->addr_ = r->do_execute();
+	return s;
+}
+
+__EXPORT
+Result *Request::do_execute(long long k) 
+{
+	Result *s = new Result();
+	CAST(NCRequest, r);
+	s->addr_ = r->do_execute((int64_t)k);
+	return s;
+}
+
+__EXPORT
+Result *Request::do_execute(const char *k) 
+{
+	Result *s = new Result();
+	CAST(NCRequest, r);
+	s->addr_ = r->do_execute(k, k?strlen(k):0);
+	return s;
+}
+
+__EXPORT
+Result *Request::do_execute(const char *k, int l) 
+{
+	Result *s = new Result();
+	CAST(NCRequest, r);
+	s->addr_ = r->do_execute(k, l);
+	return s;
+}
+
+__EXPORT
+int Request::do_execute(Result &s) 
+{
+	CAST(NCRequest, r);
+	s.Reset();
+	s.addr_ = r->do_execute();
+	return s.get_result_code();
+}
+
+__EXPORT
+int Request::do_execute(Result &s, long long k) 
+{
+	CAST(NCRequest, r);
+	s.Reset();
+	s.addr_ = r->do_execute((int64_t)k);
+	return s.get_result_code();
+}
+
+__EXPORT
+int Request::do_execute(Result &s, const char *k) 
+{
+	CAST(NCRequest, r);
+	s.Reset();
+	s.addr_ = r->do_execute(k, k?strlen(k):0);
+	return s.get_result_code();
+}
+
+__EXPORT
+int Request::do_execute(Result &s, const char *k, int l) 
+{
+	CAST(NCRequest, r);
+	s.Reset();
+	s.addr_ = r->do_execute(k, l);
+	return s.get_result_code();
+}
+
+/* 增加错误信息,方便以后问题定位. add by foryzhou */
+__EXPORT
+const char * Request::get_error_message(void) const 
+{
+	CAST(NCRequest, r);
+	if(r==NULL) return NULL;
+	return r->get_error_message();
+}
+
+#define _DECLACT_(f0,t0,f1,f2,t1) \
+    __EXPORT \
+    int Request::f0(const char *n, t0 v) { \
+	CAST(NCRequest, r); \
+	return r->f1(n, DField::f2, DField::t1, DTCValue::Make(v)); \
+    }
+#define _DECLACT2_(f0,t0,f1,f2,t1) \
+    __EXPORT \
+    int Request::f0(const char *n, t0 v, int l) { \
+	CAST(NCRequest, r); \
+	return r->f1(n, DField::f2, DField::t1, DTCValue::Make(v,l)); \
+    }
+
+
+
+_DECLACT_(EQ, long long, add_condition, EQ, Signed);
+_DECLACT_(NE, long long, add_condition, NE, Signed);
+_DECLACT_(GT, long long, add_condition, GT, Signed);
+_DECLACT_(GE, long long, add_condition, GE, Signed);
+_DECLACT_(LT, long long, add_condition, LT, Signed);
+_DECLACT_(LE, long long, add_condition, LE, Signed);
+_DECLACT_(EQ, const char *, add_condition, EQ, String);
+_DECLACT_(NE, const char *, add_condition, NE, String);
+_DECLACT2_(EQ, const char *, add_condition, EQ, String);
+_DECLACT2_(NE, const char *, add_condition, NE, String);
+_DECLACT_(Set, long long, add_operation, Set, Signed);
+_DECLACT_(OR, long long, add_operation, OR, Signed);
+_DECLACT_(Add, long long, add_operation, Add, Signed);
+
+__EXPORT
+int Request::Sub(const char *n, long long v) 
+{
+    CAST(NCRequest, r);
+    return r->add_operation(n, DField::Add, DField::Signed, DTCValue::Make(-(int64_t)v));
+}
+
+_DECLACT_(Set, double, add_operation, Set, Float);
+_DECLACT_(Add, double, add_operation, Add, Float);
+
+__EXPORT
+int Request::Sub(const char *n, double v) 
+{
+    CAST(NCRequest, r);
+    return r->add_operation(n, DField::Add, DField::Signed, DTCValue::Make(-v));
+}
+
+_DECLACT_(Set, const char *, add_operation, Set, String);
+_DECLACT2_(Set, const char *, add_operation, Set, String);
+#undef _DECLACT_
+#undef _DECLACT2_
+
+__EXPORT
+int Request::compress_set(const char *n,const char * v,int len)
+{
+    CAST(NCRequest, r);
+    return r->compress_set(n,v,len);
+}
+
+__EXPORT
+int Request::compress_set_force(const char *n,const char * v,int len)
+{
+    CAST(NCRequest, r);
+    return r->compress_set_force(n,v,len);
+}
+
+__EXPORT
+int Request::set_multi_bits(const char *n, int o, int s, unsigned int v) 
+{
+    if(s <=0 || o >= (1 << 24) || o < 0)
+		return 0;
+    if(s >= 32)
+		s = 32;
+
+    CAST(NCRequest, r);
+    /**
+     * 1 byte 3 byte 4 byte
+	 * s     o      v
+     */
+    uint64_t t = ((uint64_t)s << 56)+ ((uint64_t)o << 32) + v;
+    return r->add_operation(n, DField::SetBits, DField::Unsigned, DTCValue::Make(t));
+}
+
+__EXPORT
+int Request::set_expire_time(const char* key, int time)
+{
+	CAST(NCRequest, r);
+	return r->set_expire_time(key, time);
+}
+
+__EXPORT
+int Request::get_expire_time(const char* key)
+{
+	CAST(NCRequest, r);
+	return r->get_expire_time(key);
+}
+
+
+/* WRAPER for Result */
+__EXPORT
+Result::Result(void) 
+{
+	addr_ = NULL;
+}
+
+__EXPORT
+Result::~Result(void) 
+{
+	Reset();
+}
+
+__EXPORT
+void Result::set_error(int err, const char *via, const char *msg) 
+{
+	Reset();
+	addr_ = new NCResult(err, via, msg);
+}
+
+__EXPORT
+void Result::Reset(void) 
+{
+	if(addr_ != NULL) {
+		CAST(NCResult, job);
+		CAST(NCResultInternal, itask);
+		if(job->Role()==TaskRoleClient)
+			delete job;
+		else
+			delete itask;
+	}
+	addr_ = NULL;
+}
+
+__EXPORT
+int Result::fetch_row(void) 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return -EC_NO_MORE_DATA;
+	if(r->result_code()<0) return r->result_code();
+	if(r->result==NULL) return -EC_NO_MORE_DATA;
+	return r->result->decode_row();
+}
+
+__EXPORT
+int Result::rewind(void) 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return -EC_NO_MORE_DATA;
+	if(r->result_code()<0) return r->result_code();
+	if(r->result==NULL)  return -EC_NO_MORE_DATA;
+	return r->result->rewind();
+}
+
+__EXPORT
+int Result::get_result_code(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return 0;
+	return r->result_code();
+}
+
+__EXPORT
+const char * Result::get_error_message(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return NULL;
+	int code = r->result_code();
+	const char *msg = r->resultInfo.error_message();
+	if(msg==NULL && code < 0) {
+		char a[1];
+		msg = strerror_r(-code, a, 1);
+		if(msg==a) msg = NULL;
+	}
+	return msg;
+}
+
+__EXPORT
+const char * Result::get_error_from(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return NULL;
+	return r->resultInfo.error_from();
+}
+
+__EXPORT
+long long Result::get_hotbackup_id() const 
+{
+    CAST(NCResult, r);
+    return r->versionInfo.hot_backup_id();
+}
+
+__EXPORT
+long long Result::get_master_hotbackup_timestamp() const 
+{
+    CAST(NCResult, r);
+    return r->versionInfo.master_hb_timestamp();
+}
+
+__EXPORT
+long long Result::slave_hotbackup_timestamp() const 
+{
+    CAST(NCResult, r);
+    return r->versionInfo.slave_hb_timestamp();
+}
+
+__EXPORT
+char* Result::ServerInfo() const 
+{
+    CAST(NCResult, r);
+    return r->resultInfo.server_info();
+}
+
+__EXPORT
+long long Result::get_binlog_id() const 
+{
+	DTCServerInfo *p = (DTCServerInfo *)ServerInfo();
+	return p ? p->binlog_id : 0;
+}
+
+__EXPORT
+long long Result::get_binlog_offset() const 
+{
+	DTCServerInfo *p = (DTCServerInfo *)ServerInfo();
+	return p ? p->binlog_off : 0;
+}
+
+__EXPORT
+long long Result::get_mem_size() const
+{
+	DTCServerInfo *p = (DTCServerInfo *)ServerInfo();
+	return p ? p->memsize : 0;
+}
+__EXPORT
+long long Result::get_datd_size() const
+{
+	DTCServerInfo *p = (DTCServerInfo *)ServerInfo();
+	return p ? p->datasize : 0;
+}
+
+__EXPORT
+int Result::get_num_row_size(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL || r->result==NULL) return 0;
+	return r->result->total_rows();
+}
+
+__EXPORT
+int Result::get_total_rows_size(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return 0;
+	return r->resultInfo.total_rows();
+}
+
+__EXPORT
+long long Result::get_insert_id(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return 0;
+	return r->resultInfo.insert_id();
+}
+
+__EXPORT
+int Result::get_num_fields_size(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL || r->result==NULL) return 0;
+	return r->result->num_fields();
+}
+
+__EXPORT
+const char* Result::get_field_name(int n) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL || r->result==NULL) return NULL;
+	if(n<0 || n>=r->result->num_fields()) return NULL;
+	return r->field_name(r->result->field_id(n));
+}
+
+__EXPORT
+int Result::get_field_present(const char* name) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL || r->result==NULL) return 0;
+	int id = r->field_id(name);
+	if(id < 0) return 0;
+	return r->result->field_present(id);
+}
+
+__EXPORT
+int Result::get_field_type(int n) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL || r->result==NULL) return kFieldTypeNone;
+	if(n<0 || n>=r->result->num_fields()) return kFieldTypeNone;
+	return r->field_type(r->result->field_id(n));
+}
+
+__EXPORT
+int Result::get_affected_rows_size(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return 0;
+	return r->resultInfo.affected_rows();
+}
+
+__EXPORT
+long long Result::int_key(void) const 
+{
+	CAST(NCResult, r);
+	const DTCValue *v = NULL;
+	if(r && r->flag_multi_key_result() && r->result) {
+		v = r->result->field_value(0);
+	}
+	else if(r && r->result_key()) {
+		v = r->result_key();
+	}
+	if(v != NULL) {
+		switch(r->field_type(0)) {
+		case DField::Signed:
+		case DField::Unsigned:
+		    return v->s64;
+	    }
+	}
+	return 0;
+}
+
+__EXPORT
+const char *Result::string_key(void) const 
+{
+	CAST(NCResult, r);
+	const DTCValue *v = NULL;
+	if(r && r->flag_multi_key_result() && r->result) {
+		v = r->result->field_value(0);
+	} else if(r && r->result_key()) {
+		v = r->result_key();
+	}
+	if(v != NULL) {
+		  switch(r->field_type(0)) {
+			case DField::Binary:
+			case DField::String:
+				return v->bin.ptr;
+		}
+	}
+	return NULL;
+}
+
+__EXPORT
+const char *Result::string_key(int *lp) const 
+{
+	CAST(NCResult, r);
+	const DTCValue *v = NULL;
+	if(r && r->flag_multi_key_result() && r->result) {
+		v = r->result->field_value(0);
+	} else if(r && r->result_key()) {
+		v = r->result_key();
+	}
+	if(v != NULL) {
+		switch(r->field_type(0)) {
+			case DField::Binary:
+		    case DField::String:
+			     if(lp) *lp = v->bin.len;
+		        return v->bin.ptr;
+	    }
+	}	
+	return NULL;
+}
+
+const char *Result::string_key(int &l) const 
+{
+	CAST(NCResult, r);
+	const DTCValue *v = NULL;
+	if(r && r->flag_multi_key_result() && r->result) {
+		v = r->result->field_value(0);
+	} else if(r && r->result_key()) {
+		v = r->result_key();
+	}
+	if(v != NULL) {
+		switch(r->field_type(0)) {
+		case DField::Binary:
+		case DField::String:
+			 l = v->bin.len;
+		    return v->bin.ptr;
+	    }
+	}		
+	return NULL;
+}
+
+__EXPORT
+const char *Result::binary_key(void) const 
+{
+	return string_key();
+}
+
+__EXPORT
+const char *Result::binary_key(int *lp) const 
+{
+	return string_key(lp);
+}
+
+__EXPORT
+const char *Result::binary_key(int &l) const 
+{
+	return string_key(l);
+}
+
+static inline int64_t GetIntValue(NCResult *r, int id) 
+{
+	if(id >= 0) {
+		const DTCValue *v;
+		if(id==0 && !(r->result->field_present(0)))
+			v = r->result_key();
+		else
+			v = r->result->field_value(id);
+		if(v) {
+			switch(r->field_type(id)) {
+				case DField::Signed:
+				case DField::Unsigned:
+					return v->s64;
+				case DField::Float:
+					return llround(v->flt);
+					//return (int64_t)(v->flt);
+				case DField::String:
+					if(v->str.ptr)
+						return atoll(v->str.ptr);
+			}
+		}
+	}
+	return 0;
+}
+
+static inline double GetFloatValue(NCResult *r, int id) 
+{
+	if(id >= 0) {
+		const DTCValue *v;
+		if(id==0 && !(r->result->field_present(0)))
+			v = r->result_key();
+		else
+			v = r->result->field_value(id);
+
+		if(v) {
+			switch(r->field_type(id)) {
+				case DField::Signed:
+					return (double)v->s64;
+				case DField::Unsigned:
+					return (double)v->u64;
+				case DField::Float:
+					return v->flt;
+				case DField::String:
+					if(v->str.ptr)
+						return atof(v->str.ptr);
+			}
+		}
+	}
+	return NAN;
+}
+
+static inline const char *GetStringValue(NCResult *r, int id, int *lenp) 
+{
+	if(id >= 0) {
+		const DTCValue *v;
+		if(id==0 && !(r->result->field_present(0)))
+			v = r->result_key();
+		else
+			v = r->result->field_value(id);
+
+		if(v) {
+			switch(r->field_type(id)) {
+				case DField::String:
+					if(lenp) *lenp = v->bin.len;
+					return v->str.ptr;
+			}
+		}
+	}
+	return NULL;
+}
+
+static inline const char *GetBinaryValue(NCResult *r, int id, int *lenp) 
+{
+	if(id >= 0) {
+		const DTCValue *v;
+		if(id==0 && !(r->result->field_present(0)))
+			v = r->result_key();
+		else
+			v = r->result->field_value(id);
+
+		if(v) {
+			switch(r->field_type(id)) {
+				case DField::String:
+				case DField::Binary:
+					if(lenp) *lenp = v->bin.len;
+					return v->str.ptr;
+			}
+		}
+	}
+	return NULL;
+}
+
+__EXPORT
+long long Result::int_value(const char *name) const 
+{
+	CAST(NCResult, r);
+	if(r && r->result)
+	    return GetIntValue(r, r->field_id(name));
+	return 0;
+}
+
+__EXPORT
+long long Result::int_value(int id) const 
+{
+	CAST(NCResult, r);
+	if(r && r->result)
+	    return GetIntValue(r, r->field_id_virtual(id));
+	return 0;
+}
+
+__EXPORT
+double Result::float_value(const char *name) const 
+{
+	CAST(NCResult, r);
+	if(r && r->result)
+	    return GetFloatValue(r, r->field_id(name));
+	return NAN;
+}
+
+__EXPORT
+double Result::float_value(int id) const 
+{
+	CAST(NCResult, r);
+	if(r && r->result)
+	    return GetFloatValue(r, r->field_id_virtual(id));
+	return NAN;
+}
+
+__EXPORT
+const char *Result::string_value(const char *name, int *lenp) const 
+{
+	if(lenp) *lenp = 0;
+	CAST(NCResult, r);
+	if(r && r->result)
+	    return GetStringValue(r, r->field_id(name), lenp);
+	return NULL;
+}
+
+__EXPORT
+const char *Result::string_value(int id, int *lenp) const 
+{
+	if(lenp) *lenp = 0;
+	CAST(NCResult, r);
+	if(r && r->result)
+	    return GetStringValue(r, r->field_id_virtual(id), lenp);
+	return NULL;
+}
+
+__EXPORT
+const char *Result::string_value(const char *name, int &len) const 
+{
+	return string_value(name, &len);
+}
+
+__EXPORT
+const char *Result::string_value(int id, int &len) const 
+{
+	return string_value(id, &len);
+}
+
+__EXPORT
+const char *Result::string_value(const char *name) const 
+{
+	return string_value(name, NULL);
+}
+
+__EXPORT
+const char *Result::string_value(int id) const 
+{
+	return string_value(id, NULL);
+}
+
+__EXPORT
+const char *Result::binary_value(const char *name, int *lenp) const {
+	if(lenp) *lenp = 0;
+	CAST(NCResult, r);
+	if(r && r->result)
+	    return GetBinaryValue(r, r->field_id(name), lenp);
+	return NULL;
+}
+
+/* 所以UnCompressBinaryValue接口的调用均会复制一份buffer,用户得到数据后需要手动释放 */
+__EXPORT
+int Result::uncompress_binary_value(const char *name,char **buf,int *lenp)
+{
+    if(buf==NULL||lenp==NULL)
+        return -EC_UNCOMPRESS_ERROR;
+
+    int iret = 0;
+	*lenp = 0;
+    *buf = NULL;
+    const char * buf_dup = NULL;
+    uint64_t compressflag = 0;
+
+	CAST(NCResult, r);
+	if(r && r->result) {
+		iret = r->init_compress();
+		if (iret) return iret;
+		if (name == NULL) {
+			snprintf(r->gzip->errmsg_, sizeof(r->gzip->errmsg_), "field name is null");
+			return -EC_UNCOMPRESS_ERROR;
+		}
+		int fieldId = r->field_id(name);
+		/* fieldid must less than 64,because compressflag is 8 bytes uint */
+		if (fieldId >63) {
+			snprintf(r->gzip->errmsg_, sizeof(r->gzip->errmsg_), "fieldid must less than 64,because compressflag is 8 bytes uint");
+			return -EC_UNCOMPRESS_ERROR;
+		}
+		buf_dup = GetBinaryValue(r, fieldId, lenp);
+		if (buf_dup==NULL) {
+			snprintf(r->gzip->errmsg_, sizeof(r->gzip->errmsg_), "binary_value of this field is NULL,please check fieldname and fieldtype is binary or not");
+			return -EC_UNCOMPRESS_ERROR;
+		}
+        /* 没启用压缩 */
+		if (r->compress_id() < 0) {
+			*buf = (char *)MALLOC(*lenp);
+			if (*buf==NULL)
+				return -ENOMEM;
+			memcpy(*buf,buf_dup,*lenp);
+			return 0;
+		}
+		compressflag = GetIntValue(r,r->compress_id());
+		/* 启用了压缩,但是该字段没有被压缩 */
+		if (!(compressflag&(0x1<<fieldId)))
+		{
+			*buf = (char *)MALLOC(*lenp);
+			if (*buf==NULL)
+				return -ENOMEM;
+			memcpy(*buf,buf_dup,*lenp);
+			return 0;
+        }
+
+        /* 需要解压 */
+        iret = r->gzip->UnCompress(buf,lenp,buf_dup,*lenp);
+        if (iret == -111111)
+            return -EC_UNCOMPRESS_ERROR;
+        return iret;
+    }
+    return  -EC_UNCOMPRESS_ERROR;
+}
+
+/** 
+ * 所以UnCompressBinaryValue接口的调用均会复制一份buffer,用户得到数据后需要手动释放
+ * 忽略compressflag
+ */
+__EXPORT
+int Result::uncompress_binary_value_force(const char *name,char **buf,int *lenp)
+{
+    if(buf==NULL||lenp==NULL)
+        return -EC_UNCOMPRESS_ERROR;
+
+    int iret = 0;
+	*lenp = 0;
+    *buf = NULL;
+    const char * buf_dup = NULL;
+
+	CAST(NCResult, r);
+	if(r && r->result) {
+		if (name == NULL) {
+			snprintf(r->gzip->errmsg_, sizeof(r->gzip->errmsg_), "field name is null");
+			return -EC_UNCOMPRESS_ERROR;
+		}
+		iret = r->init_compress();
+		if (iret) return iret;
+		int fieldId = r->field_id(name);
+		buf_dup = GetBinaryValue(r, fieldId, lenp);
+		if (buf_dup==NULL) {
+			snprintf(r->gzip->errmsg_, sizeof(r->gzip->errmsg_), "binary_value of this field is NULL,please check fieldname and fieldtype is binary or not");
+			return -EC_UNCOMPRESS_ERROR;
+		}
+        /* 需要解压 */
+        iret = r->gzip->UnCompress(buf,lenp,buf_dup,*lenp);
+        if (iret == -111111)
+            return -EC_UNCOMPRESS_ERROR;
+        return iret;
+    }
+    return  -EC_UNCOMPRESS_ERROR;
+}
+
+__EXPORT
+const char *Result::uncompress_error_message() const
+{
+	CAST(NCResult, r);
+	if(r && r->gzip)
+        return  r->gzip->error_message();
+    return NULL;
+}
+
+__EXPORT
+const char *Result::binary_value(int id, int *lenp) const 
+{
+	if(lenp) *lenp = 0;
+	CAST(NCResult, r);
+	if(r && r->result)
+	    return GetBinaryValue(r, r->field_id_virtual(id), lenp);
+	return NULL;
+}
+
+__EXPORT
+const char *Result::binary_value(const char *name, int &len) const 
+{
+	return binary_value(name, &len);
+}
+
+__EXPORT
+const char *Result::binary_value(int id, int &len) const 
+{
+	return binary_value(id, &len);
+}
+
+__EXPORT
+const char *Result::binary_value(const char *name) const 
+{
+	return binary_value(name, NULL);
+}
+
+__EXPORT
+const char *Result::binary_value(int id) const 
+{
+	return binary_value(id, NULL);
+}
+
+__EXPORT
+long long Result::get_tag(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return 0;
+	return r->get_api_tag();
+};
+
+__EXPORT
+void *Result::get_tag_ptr(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return NULL;
+	return (void *)(long)r->get_api_tag();
+};
+
+__EXPORT
+long long Result::magic(void) const 
+{
+	CAST(NCResult, r);
+	if(r==NULL) return 0;
+	return r->versionInfo.serial_nr();
+};
+
+__EXPORT
+long long Result::get_server_timestamp(void) const
+{
+	CAST(NCResult, r);
+
+	if (r == NULL) {
+		return 0;
+	}
+
+	return r->resultInfo.Timestamp();
+};
+
+__EXPORT
+int Server::decode_packet(Result &s, const char *buf, int len)
+{
+	CAST(NCServer, srv);
+	s.Reset();
+	s.addr_ = srv->decode_buffer(buf, len);
+	return s.get_result_code();
+}
+
+__EXPORT
+int Server::check_packet_size(const char *buf, int len)
+{
+	return NCServer::check_packet_size(buf, len);
+}
+
+__EXPORT
+int Request::encode_packet(char *&ptr, int &len, long long &m) {
+	CAST(NCRequest, r);
+	int64_t mm;
+	int ret = r->encode_buffer(ptr, len, mm);
+	m = mm;
+	return ret;
+}
+
+__EXPORT
+int Request::encode_packet(char *&ptr, int &len, long long &m, long long k) 
+{
+	CAST(NCRequest, r);
+	int64_t mm;
+	int ret = r->encode_buffer(ptr, len, mm, (int64_t)k);
+	m = mm;
+	return ret;
+}
+
+__EXPORT
+int Request::encode_packet(char *&ptr, int &len, long long &m, const char *k) 
+{
+	CAST(NCRequest, r);
+	int64_t mm;
+	int ret = r->encode_buffer(ptr, len, mm, k, k?strlen(k):0);
+	m = mm;
+	return ret;
+}
+
+__EXPORT
+int Request::encode_packet(char *&ptr, int &len, long long &m, const char *k, int l) 
+{
+	CAST(NCRequest, r);
+	int64_t mm;
+	int ret = r->encode_buffer(ptr, len, mm, k, l);
+	m = mm;
+	return ret;
+}
+

+ 231 - 0
src/devel/cpp/dtcwrapp.cc

@@ -0,0 +1,231 @@
+#include <inttypes.h>
+#include <value.h>
+#include <compiler.h>
+
+#include "dtcapi.h"
+#include "dtcpool.h"
+
+using namespace DTC;
+
+#define CAST(type, var) type *var = (type *)addr_
+#define CAST2(type, var, src) type *var = (type *)src->addr_
+#define CAST3(type, var, src) type *var = (type *)src.addr_
+
+// WRAPPER for Server
+__EXPORT
+ServerPool::ServerPool(int ms, int mr) {
+	NCPool *pl = new NCPool(ms, mr);
+	addr_ = pl;
+}
+
+__EXPORT
+ServerPool::~ServerPool(void) {
+	CAST(NCPool, pl);
+	delete pl;
+}
+
+__EXPORT
+int ServerPool::add_server(Server *srv, int mreq, int mconn)
+{
+	CAST(NCPool, pl);
+	CAST2(NCServer, s, srv);
+
+	return pl->add_server(s, mreq, mconn);
+}
+
+__EXPORT
+int ServerPool::add_request(Request *req, long long tag)
+{
+	CAST(NCPool, pl);
+	CAST2(NCRequest, r, req);
+
+	if(r->server == NULL)
+	    return -EC_NOT_INITIALIZED;
+
+	return pl->add_request(r, tag, NULL);
+}
+
+__EXPORT
+int ServerPool::add_request(Request *req, void *tag)
+{
+	return add_request(req, (long long)(long)tag);
+}
+
+__EXPORT
+int ServerPool::add_request(Request *req, long long tag, long long k)
+{
+	CAST(NCPool, pl);
+	CAST2(NCRequest, r, req);
+
+	if(r->server == NULL)
+	    return -EC_NOT_INITIALIZED;
+	if(r->server->keytype_ != DField::Signed)
+	    return -EC_BAD_KEY_TYPE;
+
+	DTCValue v(k);
+	return pl->add_request(r, tag, &v);
+}
+
+__EXPORT
+int ServerPool::add_request(Request *req, void *tag, long long k)
+{
+	return add_request(req, (long long)(long)tag, k);
+}
+
+__EXPORT
+int ServerPool::add_request(Request *req, long long tag, const char *k)
+{
+	CAST(NCPool, pl);
+	CAST2(NCRequest, r, req);
+
+	if(r->server == NULL)
+	    return -EC_NOT_INITIALIZED;
+	if(r->server->keytype_ != DField::String)
+	    return -EC_BAD_KEY_TYPE;
+
+	DTCValue v(k);
+	return pl->add_request(r, tag, &v);
+}
+
+__EXPORT
+int ServerPool::add_request(Request *req, void *tag, const char *k)
+{
+	return add_request(req, (long long)(long)tag, k);
+}
+
+__EXPORT
+int ServerPool::add_request(Request *req, long long tag, const char *k, int l)
+{
+	CAST(NCPool, pl);
+	CAST2(NCRequest, r, req);
+
+	if(r->server == NULL)
+	    return -EC_NOT_INITIALIZED;
+	if(r->server->keytype_ != DField::String)
+	    return -EC_BAD_KEY_TYPE;
+
+	DTCValue v(k, l);
+	return pl->add_request(r, tag, &v);
+}
+
+__EXPORT
+int ServerPool::add_request(Request *req, void *tag, const char *k, int l)
+{
+	return add_request(req, (long long)(long)tag, k, l);
+}
+
+__EXPORT
+int ServerPool::do_execute(int msec)
+{
+	CAST(NCPool, pl);
+	return pl->do_execute(msec);
+}
+
+__EXPORT
+int ServerPool::execute_all(int msec)
+{
+	CAST(NCPool, pl);
+	return pl->execute_all(msec);
+}
+
+__EXPORT
+int ServerPool::cancel_request(int id)
+{
+	CAST(NCPool, pl);
+	return pl->cancel_request(id);
+}
+
+__EXPORT
+int ServerPool::cancel_all_request(int type)
+{
+	CAST(NCPool, pl);
+	return pl->cancel_all_request(type);
+}
+
+__EXPORT
+int ServerPool::abort_request(int id)
+{
+	CAST(NCPool, pl);
+	return pl->abort_request(id);
+}
+
+__EXPORT
+int ServerPool::abort_all_request(int type)
+{
+	CAST(NCPool, pl);
+	return pl->abort_all_request(type);
+}
+
+__EXPORT
+Result * ServerPool::get_result(void)
+{
+	return get_result(0);
+}
+
+__EXPORT
+Result * ServerPool::get_result(int id)
+{
+	CAST(NCPool, pl);
+	NCResult *a = pl->get_result(id);
+	if( (long)a  < 4096 && (long)a > -4095)
+		return NULL;
+	Result *s = new Result();
+	s->addr_ = (void *)a;
+	return s;
+}
+
+__EXPORT
+int ServerPool::get_result(Result &s)
+{
+	return get_result(s, 0);
+}
+
+__EXPORT
+int ServerPool::get_result(Result &s, int id)
+{
+	CAST(NCPool, pl);
+	s.Reset();
+	NCResult *a = pl->get_result(id);
+	long iv = (long)a;
+	if( iv  < 4096 && iv > -4095)
+	{
+		s.addr_ = (void *)(new NCResult(iv, "API::executing", iv>0 ? "Request not completed" : id ? "Invalid request" : "No more result"));
+		return iv;
+	}
+	s.addr_ = (void *)a;
+	return 0;
+}
+
+__EXPORT
+int ServerPool::server_count(void) const
+{
+	CAST(NCPool, pl);
+	return pl->server_count();
+}
+
+__EXPORT
+int ServerPool::request_count(int type) const
+{
+	CAST(NCPool, pl);
+	if(type == DONE)
+		return pl->done_request_count();
+	if(type == (WAIT|SEND|RECV|DONE))
+		return pl->request_count();
+	return pl->count_request_state(type);
+}
+
+__EXPORT
+int ServerPool::request_state(int reqId) const
+{
+	CAST(NCPool, pl);
+	return pl->request_state(reqId);
+}
+
+__EXPORT
+int ServerPool::get_epoll_fd(int size)
+{
+    CAST(NCPool, pl);
+    return pl->get_epoll_fd(size);
+}
+
+const int ALL_STATE = WAIT|SEND|RECV|DONE;

+ 34 - 0
src/devel/cpp/example/deletetest.cpp

@@ -0,0 +1,34 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string>
+#include<stdint.h>
+#include<unistd.h>
+
+#include "dtcapi.h"
+
+int main(int argc,char* argv[])
+{
+	int retCode = 0;
+	unsigned int uid;
+
+	DTC::Server stServer; // 只要server不析构,后台会保持长连接
+	stServer.int_key(); // 声明key类型
+	stServer.set_table_name("t_dtc_example");//设置dtc的表名,与table.conf中tablename应该一样
+	stServer.set_address("192.168.214.62", "10009");//设置的dtc的ip和端口
+	stServer.SetTimeout(5); // 设置网络超时时间
+	stServer.set_accesskey("0000010284d9cfc2f395ce883a41d7ffc1bbcf4e"); // 设置访问码 AccessToken,在申请dtc实例的时候网站端会生成
+
+	DTC::DeleteRequest deleteReq(&stServer);
+	uid = atoi(argv[1]);
+	deleteReq.set_key(uid);
+
+	DTC::Result stResult;
+	retCode = deleteReq.do_execute(stResult);
+	printf("retCode:%d\n", retCode);
+	if(retCode == 0)
+	{
+		printf("delete success!\n");
+	}
+
+	return 0;  
+}  

+ 77 - 0
src/devel/cpp/example/inserttest.cpp

@@ -0,0 +1,77 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string>
+#include<stdint.h>
+#include<unistd.h>
+
+#include "dtcapi.h"
+
+int main(int argc,char* argv[])
+{
+	int retCode = 0;
+	unsigned int uid;
+	unsigned int age;
+	std::string name;
+	std::string city;
+	std::string descr;
+
+	DTC::Server stServer; // 只要server不析构,后台会保持长连接
+	stServer.int_key(); // 声明key类型
+	stServer.set_table_name("t_dtc_example");//设置dtc的表名,与table.conf中tablename应该一样
+	stServer.set_address("192.168.214.62", "10109");//设置的dtc的ip和端口
+	stServer.SetTimeout(5); // 设置网络超时时间
+	stServer.set_accesskey("0000010284d9cfc2f395ce883a41d7ffc1bbcf4e"); // 设置访问码 AccessToken,在申请dtc实例的时候网站端会生成
+
+	DTC::InsertRequest insertReq(&stServer);
+	//retCode = insertReq.set_key(key);
+
+	uid = atoi(argv[1]);
+	name = std::string(argv[2]);
+	city = std::string(argv[3]);
+	descr = std::string(argv[4]);
+	age = atoi(argv[5]);
+
+	insertReq.set_key(uid);
+	//insertReq.Set("key", 100003);
+	insertReq.Set("uid", uid);
+	insertReq.Set("name", name.c_str());
+	insertReq.Set("city", city.c_str());
+	insertReq.Set("descr", descr.c_str());
+	insertReq.Set("age", age);
+
+	DTC::Result stResult;
+	retCode = insertReq.do_execute(stResult);
+	printf("retCode:%d\n", retCode);
+	if(retCode == 0)
+	{
+		DTC::GetRequest getReq(&stServer);
+		getReq.set_key(uid);
+		if(retCode == 0)
+			retCode = getReq.need("uid");//设置需要select的字段,注意第一个key字段不能在这里出现
+		if(retCode == 0)
+			retCode = getReq.need("name");
+		if(retCode == 0)
+			retCode = getReq.need("city");
+		if(retCode == 0)
+			retCode = getReq.need("descr");
+		if(retCode == 0)
+			retCode = getReq.need("age");
+		if(retCode != 0)
+		{
+			printf("get-req set key or need error: %d", retCode);
+			fflush(stdout);
+			return(-1);
+		}
+
+		// do_execute & get result
+		retCode = getReq.do_execute(stResult);
+		retCode = stResult.fetch_row();//开始获取数据
+		printf("uid:%d\n", stResult.int_value("uid"));
+	    printf("name: %s\n", stResult.string_value("name"));//输出binary类型的数据
+		printf("city: %s\n", stResult.string_value("city"));
+		printf("descr: %s\n", stResult.binary_value("descr"));
+	    printf("age: %d\n", stResult.int_value("age"));//输出int类型的数据
+	}
+
+	return 0;  
+}  

+ 91 - 0
src/devel/cpp/example/selecttest.cpp

@@ -0,0 +1,91 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string>
+#include<stdint.h>
+#include<unistd.h>
+ 
+#include "dtcapi.h"
+
+int main(int argc,char* argv[])
+{
+	int iRet;
+	unsigned int uid;
+	DTC::Server stServer; // 只要server不析构,后台会保持长连接
+	stServer.int_key(); // 声明key类型
+	stServer.set_table_name("t_dtc_example");//设置dtc的表名,与在dtc.jd.com网站上申请dtc时指定的表名即tablename应该一样
+	stServer.set_address("192.168.214.62", "10109");//设置的dtc的ip和端口
+	stServer.SetTimeout(5); // 设置网络超时时间
+	stServer.set_accesskey("0000010284d9cfc2f395ce883a41d7ffc1bbcf4e"); // 设置访问码 AccessToken,在申请dtc实例的时候网站端会生成
+	//下面三行代码是Get数据
+	unsigned int  age;
+	std::string name;
+	std::string city;
+	std::string descr;
+ 
+    DTC::GetRequest stGetReq(&stServer);
+    uid = atoi(argv[1]);
+    iRet = stGetReq.set_key(uid);
+ 
+	if(iRet == 0)
+		iRet = stGetReq.need("uid");//设置需要select的字段,注意第一个key字段不能在这里出现
+    if(iRet == 0)
+    	iRet = stGetReq.need("name");
+    if(iRet == 0)
+    	iRet = stGetReq.need("city");
+    if(iRet == 0)
+    	iRet = stGetReq.need("descr");
+    if(iRet == 0)
+    	iRet = stGetReq.need("age");
+    if(iRet == 0)
+    	iRet = stGetReq.GT("age", 24);
+		//iRet = stGetReq.OR("age", 27);
+
+    if(iRet != 0)
+    { 
+		printf("get-req set key or need error: %d", iRet);
+		fflush(stdout); 
+		return(-1); 
+    } 
+ 
+    // do_execute & get result
+    DTC::Result stResult; 
+    iRet = stGetReq.do_execute(stResult);
+    if(iRet != 0)
+	//如果出错,则输出错误码、错误阶段,错误信息,stResult.get_error_from(), stResult.get_error_message() 这两个错误信息很重要,一定要打印出来,方便定位问题
+    { 
+		printf ("uin[%u] dtc do_execute get error: %d, error_from:%s, msg:%s\n",
+			uid,//出错的key是多少
+			iRet,//错误码为多少
+			stResult.get_error_from(),//返回错误阶段
+			stResult.get_error_message()//返回错误信息
+			);
+		fflush(stdout);
+		return(-2); 
+    } 
+ 
+    if(stResult.get_num_row_size() <= 0)
+	{ 
+		// 数据不存在
+		printf("uin[%u] data not exist.\n", uid);
+		return(0); 
+    } 
+ 
+	printf("nubrow:%d\n", stResult.get_num_row_size());
+	for(int i=0;i<=stResult.get_num_row_size();++i)
+	{
+		iRet = stResult.fetch_row();//开始获取数据
+		if(iRet < 0)
+		{
+			printf ("uid[%lu] dtc fetch row error: %d\n", uid, iRet);
+			fflush(stdout);
+			return(-3);
+		}
+		//如果一切正确,则可以输出数据了
+		printf("uid: %d\n", stResult.int_value("uid"));//输出int类型的数据
+		printf("name: %s\n", stResult.string_value("name"));//输出string类型的数据
+		printf("city: %s\n", stResult.string_value("city"));//输出string类型的数据
+		printf("descr: %s\n", stResult.binary_value("descr"));//输出binary类型的数据
+		printf("age:%d\n",stResult.int_value("age"));
+	}
+    return(0);
+}  

+ 889 - 0
src/devel/cpp/example/ttcapi.h

@@ -0,0 +1,889 @@
+#ifndef __DTC_API_H__
+#define __DTC_API_H__
+
+#include <stdlib.h>
+
+namespace DTC {
+	class Server;
+	class ServerPool;
+	class Request;
+	class Result;
+
+	const int kRequestSvrAdmin 	= 3;
+	const int kRequestGet 		= 4;
+	const int kRequestPurge 		= 5;
+	const int kRequestInsert 	= 6;
+	const int kRequestUpdate 	= 7;
+	const int kRequestDelete 	= 8;
+	const int kRequestReplace 	= 12;
+	const int kRequestFlush 		= 13;
+	const int kRequestInvalidate	= 14;
+
+	//mem monior Request;2014/06/6;by seanzheng
+	const int kRequestMonitor    = 15;
+
+	// sub-code of admin cmd
+	const int RegisterHB		= 1;
+	const int LogoutHB		= 2;
+	const int GetKeyList		= 3;
+	const int GetUpdateKey		= 4;
+	const int GetRawData		= 5;
+	const int ReplaceRawData	= 6;
+	const int AdjustLRU        	= 7;
+	const int VerifyHBT		= 8;
+	const int GetHBTime		= 9;
+	const int kSetReadOnly	= 10;
+	const int kSetReadWrite	= 11;
+	const int kQueryBinlogID		= 12;
+	const int kNodeHandleChange  = 13;
+	const int Migrate = 14;
+    const int kReloadClusterNodeList = 15;
+    const int kSetClusterNodeState  = 16;
+    const int kChangeNodeAddress  = 17;
+    const int kGetClusterState  = 18;
+    const int kPurgeForHit    = 19;
+	
+	const int kKeyTypeNone		= 0;	// undefined
+	const int kKeyTypeInt		= 1;	// Signed Integer
+	const int kKeyTypeString		= 4;	// String, case insensitive, null ended
+
+	const int kFieldTypeNone		= 0;    // undefined
+	const int kFieldTypeSigned	= 1;	// Signed Integer
+	const int kFieldTypeUnsigned	= 2;	// Unsigned Integer
+	const int kFieldTypeFloat	= 3;	// float
+	const int kFieldTypeString	= 4;	// String, case insensitive, null ended
+	const int kFieldTypeBinary	= 5;	// binary
+
+	void set_log_level(int n);
+	int  set_key_value_max(unsigned int count); // 设置批量操作一次最多多少个key(默认最多32个)
+	// void write_log (int level,
+	// 		const char*file, const char *func, int lineno,
+	// 		const char *fmt, ...)
+	// 	__attribute__((format(printf,5,6)));
+
+	class Result;
+	class Server {
+		private:
+			void *addr_;
+			long check;
+		public:
+			friend class Request;
+			friend class Result;
+			friend class ServerPool;
+
+			Server(void);
+			~Server(void);
+			Server(const Server &);
+			void clone_table_define(const Server& source);
+			int set_address(const char *host, const char *port=0);
+			int set_table_name(const char *);
+            //for compress
+            void set_compress_level(int);
+            //get address and tablename set by user
+			const char * get_address(void) const;
+			const char * get_table_name(void) const;
+            //get address and tablename set by dtc frame,for plugin only;
+			const char * get_server_address(void) const;
+			const char * get_server_table_name(void) const;
+			int int_key(void);
+			int binary_key(void);
+			int string_key(void);
+			int add_key(const char* name, int type);
+			int get_field_type(const char* name);
+			const char *get_error_message(void) const;
+			void SetTimeout(int);
+			void set_timeout(int);
+			int connect(void);
+			void close(void);
+			int ping(void);
+			void auto_ping(void);
+			void set_fd(int); // UNSUPPORTED API
+			void set_auto_Update_table(bool autoUpdate);
+			void set_auto_reconnect(int auto_reconnect);
+			int decode_packet(Result &, const char *, int);
+			int check_packet_size(const char *, int);
+
+			void set_accesskey(const char *token);
+	};
+
+	class Request {
+		private:
+			void *addr_;
+			long check;
+			Request(const Request &);
+		public:
+			friend class Server;
+			friend class Result;
+			friend class ServerPool;
+
+			Request(Server *srv, int op);
+			Request(void);
+			~Request(void);
+			void Reset(void);
+			void Reset(int);
+			int attach_server(Server *srv);
+
+			void set_admin_code(int code);
+			void set_hotbackup_id(long long);
+			void set_master_hotbackup_timestamp(long long);
+			void set_slave_hotbackup_timestamp(long long);
+
+#define _API_DEFINE_LONG_(op, t) int op(const char *n, t a) { return op(n, (long long)a); }
+#define _API_DEFINE_FLOAT_(op, t) int op(const char *n, t a) { return op(n, (double)a); }
+			int need(const char *);
+			int need(const char *, int);
+			int get_field_type(const char*);
+			void no_cache(void);
+			void no_next_server(void);
+			void limit(unsigned int, unsigned int);
+			int EQ(const char *, long long);
+			int NE(const char *, long long);
+			int LT(const char *, long long);
+			int LE(const char *, long long);
+			int GT(const char *, long long);
+			int GE(const char *, long long);
+			int EQ(const char *, const char *);
+			int NE(const char *, const char *);
+			int EQ(const char *, const char *, int);
+			int NE(const char *, const char *, int);
+
+			_API_DEFINE_LONG_(EQ, unsigned long long);
+			_API_DEFINE_LONG_(EQ, long);
+			_API_DEFINE_LONG_(EQ, unsigned long);
+			_API_DEFINE_LONG_(EQ, int);
+			_API_DEFINE_LONG_(EQ, unsigned int);
+			_API_DEFINE_LONG_(EQ, short);
+			_API_DEFINE_LONG_(EQ, unsigned short);
+			_API_DEFINE_LONG_(EQ, char);
+			_API_DEFINE_LONG_(EQ, unsigned char);
+
+			_API_DEFINE_LONG_(NE, unsigned long long);
+			_API_DEFINE_LONG_(NE, long);
+			_API_DEFINE_LONG_(NE, unsigned long);
+			_API_DEFINE_LONG_(NE, int);
+			_API_DEFINE_LONG_(NE, unsigned int);
+			_API_DEFINE_LONG_(NE, short);
+			_API_DEFINE_LONG_(NE, unsigned short);
+			_API_DEFINE_LONG_(NE, char);
+			_API_DEFINE_LONG_(NE, unsigned char);
+
+			_API_DEFINE_LONG_(GT, unsigned long long);
+			_API_DEFINE_LONG_(GT, long);
+			_API_DEFINE_LONG_(GT, unsigned long);
+			_API_DEFINE_LONG_(GT, int);
+			_API_DEFINE_LONG_(GT, unsigned int);
+			_API_DEFINE_LONG_(GT, short);
+			_API_DEFINE_LONG_(GT, unsigned short);
+			_API_DEFINE_LONG_(GT, char);
+			_API_DEFINE_LONG_(GT, unsigned char);
+
+			_API_DEFINE_LONG_(GE, unsigned long long);
+			_API_DEFINE_LONG_(GE, long);
+			_API_DEFINE_LONG_(GE, unsigned long);
+			_API_DEFINE_LONG_(GE, int);
+			_API_DEFINE_LONG_(GE, unsigned int);
+			_API_DEFINE_LONG_(GE, short);
+			_API_DEFINE_LONG_(GE, unsigned short);
+			_API_DEFINE_LONG_(GE, char);
+			_API_DEFINE_LONG_(GE, unsigned char);
+
+			_API_DEFINE_LONG_(LT, unsigned long long);
+			_API_DEFINE_LONG_(LT, long);
+			_API_DEFINE_LONG_(LT, unsigned long);
+			_API_DEFINE_LONG_(LT, int);
+			_API_DEFINE_LONG_(LT, unsigned int);
+			_API_DEFINE_LONG_(LT, short);
+			_API_DEFINE_LONG_(LT, unsigned short);
+			_API_DEFINE_LONG_(LT, char);
+			_API_DEFINE_LONG_(LT, unsigned char);
+
+			_API_DEFINE_LONG_(LE, unsigned long long);
+			_API_DEFINE_LONG_(LE, long);
+			_API_DEFINE_LONG_(LE, unsigned long);
+			_API_DEFINE_LONG_(LE, int);
+			_API_DEFINE_LONG_(LE, unsigned int);
+			_API_DEFINE_LONG_(LE, short);
+			_API_DEFINE_LONG_(LE, unsigned short);
+			_API_DEFINE_LONG_(LE, char);
+			_API_DEFINE_LONG_(LE, unsigned char);
+
+			int Set(const char *, long long);
+			int OR(const char *, long long);
+			int Add(const char *, long long);
+			int Sub(const char *, long long);
+			int Set(const char *, double);
+			int Add(const char *, double);
+			int Sub(const char *, double);
+			int Set(const char *, const char *);
+			int Set(const char *, const char *, int);
+
+            //just for compress,only support binary field
+			int compress_set(const char *, const char *, int);
+			//just compress and set. Don't need compressflag
+			int compress_set_force(const char *, const char *, int);
+
+			//bits op
+			int set_multi_bits(const char *, int, int, unsigned int);
+			int set_bit  (const char *f, int o) { return set_multi_bits(f, o, 1, 1);}
+			int clear_bit(const char *f, int o) { return set_multi_bits(f, o, 1, 0);}
+
+			_API_DEFINE_LONG_(Set, unsigned long long);
+			_API_DEFINE_LONG_(Set, long);
+			_API_DEFINE_LONG_(Set, unsigned long);
+			_API_DEFINE_LONG_(Set, int);
+			_API_DEFINE_LONG_(Set, unsigned int);
+			_API_DEFINE_LONG_(Set, short);
+			_API_DEFINE_LONG_(Set, unsigned short);
+			_API_DEFINE_LONG_(Set, char);
+			_API_DEFINE_LONG_(Set, unsigned char);
+			_API_DEFINE_FLOAT_(Set, float);
+			_API_DEFINE_FLOAT_(Set, long double);
+
+			_API_DEFINE_LONG_(OR, unsigned long long);
+			_API_DEFINE_LONG_(OR, long);
+			_API_DEFINE_LONG_(OR, unsigned long);
+			_API_DEFINE_LONG_(OR, int);
+			_API_DEFINE_LONG_(OR, unsigned int);
+			_API_DEFINE_LONG_(OR, short);
+			_API_DEFINE_LONG_(OR, unsigned short);
+
+			_API_DEFINE_LONG_(Add, unsigned long long);
+			_API_DEFINE_LONG_(Add, long);
+			_API_DEFINE_LONG_(Add, unsigned long);
+			_API_DEFINE_LONG_(Add, int);
+			_API_DEFINE_LONG_(Add, unsigned int);
+			_API_DEFINE_LONG_(Add, short);
+			_API_DEFINE_LONG_(Add, unsigned short);
+			_API_DEFINE_LONG_(Add, char);
+			_API_DEFINE_LONG_(Add, unsigned char);
+			_API_DEFINE_FLOAT_(Add, float);
+			_API_DEFINE_FLOAT_(Add, long double);
+
+			_API_DEFINE_LONG_(Sub, unsigned long long);
+			_API_DEFINE_LONG_(Sub, long);
+			_API_DEFINE_LONG_(Sub, unsigned long);
+			_API_DEFINE_LONG_(Sub, int);
+			_API_DEFINE_LONG_(Sub, unsigned int);
+			_API_DEFINE_LONG_(Sub, short);
+			_API_DEFINE_LONG_(Sub, unsigned short);
+			_API_DEFINE_LONG_(Sub, char);
+			_API_DEFINE_LONG_(Sub, unsigned char);
+			_API_DEFINE_FLOAT_(Sub, float);
+			_API_DEFINE_FLOAT_(Sub, long double);
+#undef _API_DEFINE_LONG_
+
+			void unset_key(void);
+			int set_key(long long);
+			int set_key(const char *);
+			int set_key(const char *, int);
+#define _API_DEFINE_LONG_(t) int set_key(t a) { return set_key((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int add_key_value(const char* name, long long v);
+			int add_key_value(const char* name, const char *str);
+			int add_key_value(const char* name, const char *ptr, int len);
+#define _API_DEFINE_LONG_(t) int add_key_value(const char* name, t a) { return add_key_value(name, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			Result *do_execute(void);
+			Result *do_execute(long long);
+			Result *do_execute(const char *);
+			Result *do_execute(const char *, int);
+
+#define _API_DEFINE_LONG_(t) Result *do_execute(t a) { return do_execute((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int do_execute(Result&);
+			int do_execute(Result&, long long);
+			int do_execute(Result&, const char *);
+			int do_execute(Result&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int do_execute(Result &r, t a) { return do_execute(r, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int encode_packet(char *&, int&, long long&);
+			int encode_packet(char *&, int&, long long&, long long);
+			int encode_packet(char *&, int&, long long&, const char *);
+			int encode_packet(char *&, int&, long long&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int encode_packet(char *&p, int &l, long long &m, t a) { return encode_packet(p,l,m,(long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int set_cache_id(long long);
+#define _API_DEFINE_LONG_(t) int set_cache_id(t a) {return set_cache_id((long long)a);}
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+            const char *get_error_message(void) const;
+	};
+
+	class GetRequest : public Request {
+		public:
+			GetRequest(Server *srv): Request(srv, kRequestGet) {}
+			GetRequest(): Request((Server *)0, kRequestGet) {}
+	};
+
+	class InsertRequest : public Request {
+		public:
+			InsertRequest(Server *srv) : Request(srv, kRequestInsert) {}
+			InsertRequest() : Request((Server *)0, kRequestInsert) {}
+	};
+
+	class DeleteRequest : public Request {
+		public:
+			DeleteRequest(Server *srv) : Request(srv, kRequestDelete) {}
+			DeleteRequest() : Request((Server *)0, kRequestDelete) {}
+	};
+
+	class UpdateRequest : public Request {
+		public:
+			UpdateRequest(Server *srv) : Request(srv, kRequestUpdate) {}
+			UpdateRequest() : Request((Server *)0, kRequestUpdate) {}
+	};
+
+	class PurgeRequest : public Request {
+		public:
+			PurgeRequest(Server *srv) : Request(srv, kRequestPurge) {}
+			PurgeRequest() : Request((Server *)0, kRequestPurge) {}
+	};
+
+	class ReplaceRequest:public Request {
+		public:
+			ReplaceRequest(Server *srv) : Request(srv, kRequestReplace) {}
+			ReplaceRequest() : Request((Server *)0, kRequestReplace) {}
+	};
+
+	class FlushRequest : public Request {
+		public:
+			FlushRequest(Server *srv) : Request(srv, kRequestFlush) {}
+			FlushRequest(void) : Request((Server *)0, kRequestFlush) {}
+	};
+
+	class InvalidateRequest: public Request {
+		public:
+			InvalidateRequest(Server *srv) : Request(srv, kRequestInvalidate) {}
+	};
+
+	class SvrAdminRequest: public Request {
+		public:
+			SvrAdminRequest(Server *srv) : Request(srv, kRequestSvrAdmin) {}
+	};
+
+	class MonitorRequest: public Request {
+		public:
+			MonitorRequest(Server *srv) : Request(srv, kRequestMonitor){}
+	};
+
+	class Result {
+		private:
+			void *addr_;
+			long check;
+			Result(const Result &);
+			char *ServerInfo() const;
+		public:
+			friend class Server;
+			friend class Request;
+			friend class ServerPool;
+
+			Result(void);
+			~Result(void);
+			void Reset(void);
+
+			void set_error(int errcode, const char *from, const char *detail); // from will not dupped
+			int get_result_code(void) const;
+			const char *get_error_message(void) const;
+			const char *get_error_from(void) const;
+			long long get_hotbackup_id() const;
+			long long get_master_hotbackup_timestamp() const;
+			long long slave_hotbackup_timestamp() const;
+			long long get_binlog_id() const;
+			long long get_binlog_offset() const;
+			long long get_mem_size() const;
+			long long get_datd_size() const;
+			int get_num_row_size(void) const;
+			int get_total_rows_size(void) const;
+			int get_affected_rows_size(void) const;
+			int get_num_fields_size(void) const;
+			const char* get_field_name(int n) const;
+			int get_field_present(const char* name) const;
+			int get_field_type(int n) const;
+			long long get_tag(void) const;
+			void *get_tag_ptr(void) const;
+			long long magic(void) const;
+			long long get_server_timestamp(void) const;
+			long long get_insert_id(void) const;
+			long long int_key(void) const;
+			const char *binary_key(void) const;
+			const char *binary_key(int *) const;
+			const char *binary_key(int &) const;
+			const char *string_key(void) const;
+			const char *string_key(int *) const;
+			const char *string_key(int &) const;
+			long long int_value(const char *) const;
+			double float_value(const char *) const;
+			const char *string_value(const char *) const;
+			const char *string_value(const char *, int*) const;
+			const char *string_value(const char *, int&) const;
+			const char *binary_value(const char *) const;
+			const char *binary_value(const char *, int*) const;
+			const char *binary_value(const char *, int&) const;
+			int uncompress_binary_value(const char *name,char **buf,int *lenp);
+			//Uncompress Binary Value without check compressflag
+			int uncompress_binary_value_force(const char *name,char **buf,int *lenp);
+            const char * uncompress_error_message() const;
+			long long int_value(int) const;
+			double float_value(int) const;
+			const char *string_value(int) const;
+			const char *string_value(int, int*) const;
+			const char *string_value(int, int&) const;
+			const char *binary_value(int) const;
+			const char *binary_value(int, int*) const;
+			const char *binary_value(int, int&) const;
+			int fetch_row(void);
+			int rewind(void);
+	};
+
+	class ServerPool {
+		private:
+			void *addr_;
+			long check;
+			ServerPool(ServerPool &);
+		public:
+			friend class Server;
+			friend class Request;
+			friend class Result;
+
+			ServerPool(int max_servers, int max_requests);
+			~ServerPool(void);
+
+			int get_epoll_fd(int size);
+			int add_server(Server *srv, int mReq=1, int mConn=0);
+			int add_request(Request *, long long);
+			int add_request(Request *, long long, long long);
+			int add_request(Request *, long long, const char *);
+			int add_request(Request *, long long, const char *, int);
+			int add_request(Request *, void *);
+			int add_request(Request *, void *, long long);
+			int add_request(Request *, void *, const char *);
+			int add_request(Request *, void *, const char *, int);
+			int do_execute(int msec);
+			int execute_all(int msec);
+			int cancel_request(int);
+			int cancel_all_request(int type);
+			int abort_request(int);
+			int abort_all_request(int type);
+			Result *get_result(void);
+			Result *get_result(int);
+			int get_result(Result&);
+			int get_result(Result&, int);
+
+			int server_count(void) const;
+			int request_count(int type) const;
+			int request_state(int reqId) const;
+	};
+
+	const int WAIT = 1;
+	const int SEND = 2;
+	const int RECV = 4;
+	const int DONE = 8;
+	const int ALL_STATE = WAIT|SEND|RECV|DONE;
+
+	enum {
+		EC_ERROR_BASE = 2000,
+		EC_BAD_COMMAND,		// unsupported command
+		EC_MISSING_SECTION,	// missing mandatory section
+		EC_EXTRA_SECTION,	// incompatible section present
+		EC_DUPLICATE_TAG,	// same tag appear twice
+
+		EC_DUPLICATE_FIELD,	//5: same field appear twice in .need()
+		EC_BAD_SECTION_LENGTH,	// section length too short
+		EC_BAD_VALUE_LENGTH,	// value length not allow
+		EC_BAD_STRING_VALUE,	// string value w/o NULL
+		EC_BAD_FLOAT_VALUE,	// invalid float format
+
+		EC_BAD_FIELD_NUM,	//10: invalid total field#
+		EC_EXTRA_SECTION_DATA,	// section length too large
+		EC_BAD_VALUE_TYPE,	// incompatible value type
+		EC_BAD_OPERATOR,	// incompatible operator/comparison
+		EC_BAD_FIELD_ID,	// invalid field ID
+
+		EC_BAD_FIELD_NAME,	//15: invalud field name
+		EC_BAD_FIELD_TYPE,	// invalid field type
+		EC_BAD_FIELD_SIZE,	// invalid field size
+		EC_TABLE_REDEFINED,	// table defined twice
+		EC_TABLE_MISMATCH,	// request table != server table
+
+		EC_VERSION_MISMATCH,	//20: unsupported protocol version
+		EC_CHECKSUM_MISMATCH,	// table hash not equal
+		EC_NO_MORE_DATA,	// End of Result
+		EC_NEED_FULL_FIELDSET,	// only full field set accepted by helper
+		EC_BAD_KEY_TYPE,	// key type incompatible
+
+		EC_BAD_KEY_SIZE,	// 25: key size incompatible
+		EC_SERVER_BUSY,		//server error
+		EC_BAD_SOCKET,		// network failed
+		EC_NOT_INITIALIZED,	// object didn't initialized
+		EC_BAD_HOST_STRING,
+
+		EC_BAD_TABLE_NAME,	// 30
+		EC_TASK_NEED_DELETE,
+		EC_KEY_NEEDED,
+		EC_SERVER_ERROR,
+		EC_UPSTREAM_ERROR,
+
+		EC_KEY_OVERFLOW,	// 35
+		EC_BAD_MULTIKEY,
+		EC_READONLY_FIELD,
+		EC_BAD_ASYNC_CMD,
+		EC_OUT_OF_KEY_RANGE,
+
+		EC_REQUEST_ABORTED,     // 40
+		EC_PARALLEL_MODE,
+		EC_KEY_NOTEXIST,
+		EC_SERVER_READONLY,
+		EC_BAD_INVALID_FIELD,
+
+		EC_DUPLICATE_KEY,    	// 45
+		EC_TOO_MANY_KEY_VALUE,
+		EC_BAD_KEY_NAME,
+		EC_BAD_RAW_DATA,
+		EC_BAD_HOTBACKUP_JID,
+
+		EC_FULL_SYNC_COMPLETE,  //50
+		EC_FULL_SYNC_STAGE,
+		EC_INC_SYNC_STAGE,
+        EC_ERR_SYNC_STAGE,
+        EC_NOT_ALLOWED_INSERT,
+
+        EC_COMPRESS_ERROR,  //55
+        EC_UNCOMPRESS_ERROR,
+	EC_TASKPOOL,
+	EC_STATE_ERROR,
+        EC_DATA_NEEDED,
+	};
+
+	enum {
+		ER_HASHCHK=1000,
+		ER_NISAMCHK=1001,
+		ER_NO=1002,
+		ER_YES=1003,
+		ER_CANT_CREATE_FILE=1004,
+		ER_CANT_CREATE_TABLE=1005,
+		ER_CANT_CREATE_DB=1006,
+		ER_DB_CREATE_EXISTS=1007,
+		ER_DB_DROP_EXISTS=1008,
+		ER_DB_DROP_DELETE=1009,
+		ER_DB_DROP_RMDIR=1010,
+		ER_CANT_DELETE_FILE=1011,
+		ER_CANT_FIND_SYSTEM_REC=1012,
+		ER_CANT_GET_STAT=1013,
+		ER_CANT_GET_WD=1014,
+		ER_CANT_LOCK=1015,
+		ER_CANT_OPEN_FILE=1016,
+		ER_FILE_NOT_FOUND=1017,
+		ER_CANT_READ_DIR=1018,
+		ER_CANT_SET_WD=1019,
+		ER_CHECKREAD=1020,
+		ER_DISK_FULL=1021,
+		ER_DUP_KEY=1022,
+		ER_ERROR_ON_CLOSE=1023,
+		ER_ERROR_ON_READ=1024,
+		ER_ERROR_ON_RENAME=1025,
+		ER_ERROR_ON_WRITE=1026,
+		ER_FILE_USED=1027,
+		ER_FILSORT_ABORT=1028,
+		ER_FORM_NOT_FOUND=1029,
+		ER_GET_ERRNO=1030,
+		ER_ILLEGAL_HA=1031,
+		ER_KEY_NOT_FOUND=1032,
+		ER_NOT_FORM_FILE=1033,
+		ER_NOT_KEYFILE=1034,
+		ER_OLD_KEYFILE=1035,
+		ER_OPEN_AS_READONLY=1036,
+		ER_OUTOFMEMORY=1037,
+		ER_OUT_OF_SORTMEMORY=1038,
+		ER_UNEXPECTED_EOF=1039,
+		ER_CON_COUNT_ERROR=1040,
+		ER_OUT_OF_RESOURCES=1041,
+		ER_BAD_HOST_ERROR=1042,
+		ER_HANDSHAKE_ERROR=1043,
+		ER_DBACCESS_DENIED_ERROR=1044,
+		ER_ACCESS_DENIED_ERROR=1045,
+		ER_NO_DB_ERROR=1046,
+		ER_UNKNOWN_COM_ERROR=1047,
+		ER_BAD_NULL_ERROR=1048,
+		ER_BAD_DB_ERROR=1049,
+		ER_TABLE_EXISTS_ERROR=1050,
+		ER_BAD_TABLE_ERROR=1051,
+		ER_NON_UNIQ_ERROR=1052,
+		ER_SERVER_SHUTDOWN=1053,
+		ER_BAD_FIELD_ERROR=1054,
+		ER_WRONG_FIELD_WITH_GROUP=1055,
+		ER_WRONG_GROUP_FIELD=1056,
+		ER_WRONG_SUM_SELECT=1057,
+		ER_WRONG_VALUE_COUNT=1058,
+		ER_TOO_LONG_IDENT=1059,
+		ER_DUP_FIELDNAME=1060,
+		ER_DUP_KEYNAME=1061,
+		ER_DUP_ENTRY=1062,
+		ER_WRONG_FIELD_SPEC=1063,
+		ER_PARSE_ERROR=1064,
+		ER_EMPTY_QUERY=1065,
+		ER_NONUNIQ_TABLE=1066,
+		ER_INVALID_DEFAULT=1067,
+		ER_MULTIPLE_PRI_KEY=1068,
+		ER_TOO_MANY_KEYS=1069,
+		ER_TOO_MANY_KEY_PARTS=1070,
+		ER_TOO_LONG_KEY=1071,
+		ER_KEY_COLUMN_DOES_NOT_EXITS=1072,
+		ER_BLOB_USED_AS_KEY=1073,
+		ER_TOO_BIG_FIELDLENGTH=1074,
+		ER_WRONG_AUTO_KEY=1075,
+		ER_READY=1076,
+		ER_NORMAL_SHUTDOWN=1077,
+		ER_GOT_SIGNAL=1078,
+		ER_SHUTDOWN_COMPLETE=1079,
+		ER_FORCING_CLOSE=1080,
+		ER_IPSOCK_ERROR=1081,
+		ER_NO_SUCH_INDEX=1082,
+		ER_WRONG_FIELD_TERMINATORS=1083,
+		ER_BLOBS_AND_NO_TERMINATED=1084,
+		ER_TEXTFILE_NOT_READABLE=1085,
+		ER_FILE_EXISTS_ERROR=1086,
+		ER_LOAD_INFO=1087,
+		ER_ALTER_INFO=1088,
+		ER_WRONG_SUB_KEY=1089,
+		ER_CANT_REMOVE_ALL_FIELDS=1090,
+		ER_CANT_DROP_FIELD_OR_KEY=1091,
+		ER_INSERT_INFO=1092,
+		ER_INSERT_TABLE_USED=1093,
+		ER_NO_SUCH_THREAD=1094,
+		ER_KILL_DENIED_ERROR=1095,
+		ER_NO_TABLES_USED=1096,
+		ER_TOO_BIG_SET=1097,
+		ER_NO_UNIQUE_LOGFILE=1098,
+		ER_TABLE_NOT_LOCKED_FOR_WRITE=1099,
+		ER_TABLE_NOT_LOCKED=1100,
+		ER_BLOB_CANT_HAVE_DEFAULT=1101,
+		ER_WRONG_DB_NAME=1102,
+		ER_WRONG_TABLE_NAME=1103,
+		ER_TOO_BIG_SELECT=1104,
+		ER_UNKNOWN_ERROR=1105,
+		ER_UNKNOWN_PROCEDURE=1106,
+		ER_WRONG_PARAMCOUNT_TO_PROCEDURE=1107,
+		ER_WRONG_PARAMETERS_TO_PROCEDURE=1108,
+		ER_UNKNOWN_TABLE=1109,
+		ER_FIELD_SPECIFIED_TWICE=1110,
+		ER_INVALID_GROUP_FUNC_USE=1111,
+		ER_UNSUPPORTED_EXTENSION=1112,
+		ER_TABLE_MUST_HAVE_COLUMNS=1113,
+		ER_RECORD_FILE_FULL=1114,
+		ER_UNKNOWN_CHARACTER_SET=1115,
+		ER_TOO_MANY_TABLES=1116,
+		ER_TOO_MANY_FIELDS=1117,
+		ER_TOO_BIG_ROWSIZE=1118,
+		ER_STACK_OVERRUN=1119,
+		ER_WRONG_OUTER_JOIN=1120,
+		ER_NULL_COLUMN_IN_INDEX=1121,
+		ER_CANT_FIND_UDF=1122,
+		ER_CANT_INITIALIZE_UDF=1123,
+		ER_UDF_NO_PATHS=1124,
+		ER_UDF_EXISTS=1125,
+		ER_CANT_OPEN_LIBRARY=1126,
+		ER_CANT_FIND_DL_ENTRY=1127,
+		ER_FUNCTION_NOT_DEFINED=1128,
+		ER_HOST_IS_BLOCKED=1129,
+		ER_HOST_NOT_PRIVILEGED=1130,
+		ER_PASSWORD_ANONYMOUS_USER=1131,
+		ER_PASSWORD_NOT_ALLOWED=1132,
+		ER_PASSWORD_NO_MATCH=1133,
+		ER_UPDATE_INFO=1134,
+		ER_CANT_CREATE_THREAD=1135,
+		ER_WRONG_VALUE_COUNT_ON_ROW=1136,
+		ER_CANT_REOPEN_TABLE=1137,
+		ER_INVALID_USE_OF_NULL=1138,
+		ER_REGEXP_ERROR=1139,
+		ER_MIX_OF_GROUP_FUNC_AND_FIELDS=1140,
+		ER_NONEXISTING_GRANT=1141,
+		ER_TABLEACCESS_DENIED_ERROR=1142,
+		ER_COLUMNACCESS_DENIED_ERROR=1143,
+		ER_ILLEGAL_GRANT_FOR_TABLE=1144,
+		ER_GRANT_WRONG_HOST_OR_USER=1145,
+		ER_NO_SUCH_TABLE=1146,
+		ER_NONEXISTING_TABLE_GRANT=1147,
+		ER_NOT_ALLOWED_COMMAND=1148,
+		ER_SYNTAX_ERROR=1149,
+		ER_DELAYED_CANT_CHANGE_LOCK=1150,
+		ER_TOO_MANY_DELAYED_THREADS=1151,
+		ER_ABORTING_CONNECTION=1152,
+		ER_NET_PACKET_TOO_LARGE=1153,
+		ER_NET_READ_ERROR_FROM_PIPE=1154,
+		ER_NET_FCNTL_ERROR=1155,
+		ER_NET_PACKETS_OUT_OF_ORDER=1156,
+		ER_NET_UNCOMPRESS_ERROR=1157,
+		ER_NET_READ_ERROR=1158,
+		ER_NET_READ_INTERRUPTED=1159,
+		ER_NET_ERROR_ON_WRITE=1160,
+		ER_NET_WRITE_INTERRUPTED=1161,
+		ER_TOO_LONG_STRING=1162,
+		ER_TABLE_CANT_HANDLE_BLOB=1163,
+		ER_TABLE_CANT_HANDLE_AUTO_INCREMENT=1164,
+		ER_DELAYED_INSERT_TABLE_LOCKED=1165,
+		ER_WRONG_COLUMN_NAME=1166,
+		ER_WRONG_KEY_COLUMN=1167,
+		ER_WRONG_MRG_TABLE=1168,
+		ER_DUP_UNIQUE=1169,
+		ER_BLOB_KEY_WITHOUT_LENGTH=1170,
+		ER_PRIMARY_CANT_HAVE_NULL=1171,
+		ER_TOO_MANY_ROWS=1172,
+		ER_REQUIRES_PRIMARY_KEY=1173,
+		ER_NO_RAID_COMPILED=1174,
+		ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE=1175,
+		ER_KEY_DOES_NOT_EXITS=1176,
+		ER_CHECK_NO_SUCH_TABLE=1177,
+		ER_CHECK_NOT_IMPLEMENTED=1178,
+		ER_CANT_DO_THIS_DURING_AN_TRANSACTION=1179,
+		ER_ERROR_DURING_COMMIT=1180,
+		ER_ERROR_DURING_ROLLBACK=1181,
+		ER_ERROR_DURING_FLUSH_LOGS=1182,
+		ER_ERROR_DURING_CHECKPOINT=1183,
+		ER_NEW_ABORTING_CONNECTION=1184,
+		ER_DUMP_NOT_IMPLEMENTED=   1185,
+		ER_FLUSH_MASTER_BINLOG_CLOSED=1186,
+		ER_INDEX_REBUILD= 1187,
+		ER_MASTER=1188,
+		ER_MASTER_NET_READ=1189,
+		ER_MASTER_NET_WRITE=1190,
+		ER_FT_MATCHING_KEY_NOT_FOUND=1191,
+		ER_LOCK_OR_ACTIVE_TRANSACTION=1192,
+		ER_UNKNOWN_SYSTEM_VARIABLE=1193,
+		ER_CRASHED_ON_USAGE=1194,
+		ER_CRASHED_ON_REPAIR=1195,
+		ER_WARNING_NOT_COMPLETE_ROLLBACK=1196,
+		ER_TRANS_CACHE_FULL=1197,
+		ER_SLAVE_MUST_STOP=1198,
+		ER_SLAVE_NOT_RUNNING=1199,
+		ER_BAD_SLAVE=1200,
+		ER_MASTER_INFO=1201,
+		ER_SLAVE_THREAD=1202,
+		ER_TOO_MANY_USER_CONNECTIONS=1203,
+		ER_SET_CONSTANTS_ONLY=1204,
+		ER_LOCK_WAIT_TIMEOUT=1205,
+		ER_LOCK_TABLE_FULL=1206,
+		ER_READ_ONLY_TRANSACTION=1207,
+		ER_DROP_DB_WITH_READ_LOCK=1208,
+		ER_CREATE_DB_WITH_READ_LOCK=1209,
+		ER_WRONG_ARGUMENTS=1210,
+		ER_NO_PERMISSION_TO_CREATE_USER=1211,
+		ER_UNION_TABLES_IN_DIFFERENT_DIR=1212,
+		ER_LOCK_DEADLOCK=1213,
+		ER_TABLE_CANT_HANDLE_FULLTEXT=1214,
+		ER_CANNOT_ADD_FOREIGN=1215,
+		ER_NO_REFERENCED_ROW=1216,
+		ER_ROW_IS_REFERENCED=1217,
+		ER_CONNECT_TO_MASTER=1218,
+		ER_QUERY_ON_MASTER=1219,
+		ER_ERROR_WHEN_EXECUTING_COMMAND=1220,
+		ER_WRONG_USAGE=1221,
+		ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT=1222,
+		ER_CANT_UPDATE_WITH_READLOCK=1223,
+		ER_MIXING_NOT_ALLOWED=1224,
+		ER_DUP_ARGUMENT=1225,
+		ER_USER_LIMIT_REACHED=1226,
+		ER_SPECIFIC_ACCESS_DENIED_ERROR=1227,
+		ER_LOCAL_VARIABLE=1228,
+		ER_GLOBAL_VARIABLE=1229,
+		ER_NO_DEFAULT=1230,
+		ER_WRONG_VALUE_FOR_VAR=1231,
+		ER_WRONG_TYPE_FOR_VAR=1232,
+		ER_VAR_CANT_BE_READ=1233,
+		ER_CANT_USE_OPTION_HERE=1234,
+		ER_NOT_SUPPORTED_YET=1235,
+		ER_MASTER_FATAL_ERROR_READING_BINLOG=1236,
+		ER_SLAVE_IGNORED_TABLE=1237,
+		ER_INCORRECT_GLOBAL_LOCAL_VAR=1238,
+		CR_UNKNOWN_ERROR=1900,
+		CR_SOCKET_CREATE_ERROR=1901,
+		CR_CONNECTION_ERROR=1902,
+		CR_CONN_HOST_ERROR=1903,
+		CR_IPSOCK_ERROR	=1904,
+		CR_UNKNOWN_HOST	=1905,
+		CR_SERVER_GONE_ERROR=1906,
+		CR_VERSION_ERROR=1907,
+		CR_OUT_OF_MEMORY=1908,
+		CR_WRONG_HOST_INFO=1909,
+		CR_LOCALHOST_CONNECTION=1910,
+		CR_TCP_CONNECTION=1911,
+		CR_SERVER_HANDSHAKE_ERR=1912,
+		CR_SERVER_LOST=1913,
+		CR_COMMANDS_OUT_OF_SYNC=1914,
+		CR_NAMEDPIPE_CONNECTION=1915,
+		CR_NAMEDPIPEWAIT_ERROR=1916,
+		CR_NAMEDPIPEOPEN_ERROR=1917,
+		CR_NAMEDPIPESETSTATE_ERROR=1918,
+		CR_CANT_READ_CHARSET=1919,
+		CR_NET_PACKET_TOO_LARGE=1920,
+		CR_EMBEDDED_CONNECTION=1921,
+		CR_PROBE_SLAVE_STATUS=1922,
+		CR_PROBE_SLAVE_HOSTS=1923,
+		CR_PROBE_SLAVE_CONNECT=1924,
+		CR_PROBE_MASTER_CONNECT=1925,
+		CR_SSL_CONNECTION_ERROR=1926,
+		CR_MALFORMED_PACKET=1927,
+		CR_WRONG_LICENSE=1928,
+	};
+};
+
+#endif

+ 84 - 0
src/devel/cpp/example/updatetest.cpp

@@ -0,0 +1,84 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string>
+#include<stdint.h>
+#include<unistd.h>
+
+#include "dtcapi.h"
+
+int main(int argc,char* argv[])
+{
+	int retCode = 0;
+	unsigned int uid;
+	unsigned int age;
+	std::string name;
+	std::string city;
+	std::string descr;
+
+	DTC::Server stServer; // 只要server不析构,后台会保持长连接
+	stServer.int_key(); // 声明key类型
+	stServer.set_table_name("t_dtc_example");//设置dtc的表名,与table.conf中tablename应该一样
+	stServer.set_address("192.168.214.62", "10009");//设置的dtc的ip和端口
+	stServer.SetTimeout(5); // 设置网络超时时间
+	stServer.set_accesskey("0000010284d9cfc2f395ce883a41d7ffc1bbcf4e"); // 设置访问码 AccessToken,在申请dtc实例的时候网站端会生成
+	
+	uid = atoi(argv[1]);
+	name = std::string(argv[2]);
+	city = std::string(argv[3]);
+	descr = std::string(argv[4]);
+	age = atoi(argv[5]);
+	DTC::UpdateRequest UpdateReq(&stServer);
+	retCode = UpdateReq.set_key(uid);
+	if(retCode != 0)
+	{
+		printf("update-req set key error: %d", retCode);
+		fflush(stdout);
+		return(-1);
+	}
+	retCode = UpdateReq.Set("name", name.c_str());
+	retCode = UpdateReq.Set("city", city.c_str());
+	retCode = UpdateReq.Set("descr", descr.c_str());
+	retCode = UpdateReq.Set("age", age);
+	if(retCode != 0)
+	{
+		printf("update-req set field error: %d", retCode);
+		fflush(stdout);
+		return(-1);
+	}
+
+	// do_execute & get result
+	DTC::Result stResult;
+	retCode = UpdateReq.do_execute(stResult);
+	printf("retCode:%d\n", retCode);
+	if(retCode == 0)
+	{
+		DTC::GetRequest getReq(&stServer);
+		getReq.set_key(uid);
+		if(retCode == 0)
+			retCode = getReq.need("uid");//设置需要select的字段,注意第一个key字段不能在这里出现
+		if(retCode == 0)
+			retCode = getReq.need("name");
+		if(retCode == 0)
+			retCode = getReq.need("city");
+		if(retCode == 0)
+			retCode = getReq.need("descr");
+		if(retCode == 0)
+			retCode = getReq.need("age");
+		if(retCode != 0)
+		{
+			printf("get-req set key or need error: %d", retCode);
+			fflush(stdout);
+			return(-1);
+		}
+
+		// do_execute & get result
+		retCode = getReq.do_execute(stResult);
+		retCode = stResult.fetch_row();//开始获取数据
+		printf("uid:%d\n", stResult.int_value("uid"));
+	    printf("name: %s\n", stResult.string_value("name"));//输出binary类型的数据
+		printf("city: %s\n", stResult.string_value("city"));
+		printf("descr: %s\n", stResult.binary_value("descr"));
+	    printf("age: %d\n", stResult.int_value("age"));//输出int类型的数据
+	}
+	return 0;
+}  

+ 32 - 0
src/devel/cpp/examples/cache.conf

@@ -0,0 +1,32 @@
+LogLevel	    	= debug 
+BindAddr	    	= 127.0.0.1:9898/tcp
+
+IdleTimeout		= 30
+HelperTimeout		= 30
+
+CacheShmKey 		= 892123 
+CacheMemorySize		= 100M
+CacheAverageDataSize	= 50
+
+MaxFlushSpeed		= 1
+MinDirtyNode		= 40
+MaxDirtyNode		= 60
+MinDirtyTime		= 3600
+MaxDirtyTime		= 43200
+
+DisableDataSource 	= 0 
+DelayUpdate 		= 0
+
+#opening file descritor overflow warning.
+OpenningFDAttrID	= 41784
+
+StartStatReporter	= 1 
+EnableCoreDump		= 1
+DisableWatchDog     	= 0
+ 
+#ServerRecovery		= crash
+#[LogApi]
+#MessageId =
+#CallerId =
+#TargetId =
+#InterfaceId =

+ 39 - 0
src/devel/cpp/examples/delete/Makefile

@@ -0,0 +1,39 @@
+LIB = ../../libdtc.so
+
+OUTPUT = delete
+
+SOURCES =  deletetest.cpp 
+								   		
+
+OBJECTS= deletetest.o
+	CPPFLAGS = -g -O -Wall -fPIC -DMACROFOR64BIT -Wl,--no-undefined -Xlinker -zmuldefs
+	CFLAGS = $(CPPFLAGS)
+
+all:$(OUTPUT)
+
+.SUFFIXES: .o .cpp
+	.cpp.o:
+		$(CXX) $(CPPFLAGS) $(INCLUDE) -c $(filter %.cpp, $^) 
+
+.o:
+		$(CXX) $(CPPFLAGS) $(INCLUDE) -o $@ $^ 
+
+$(OUTPUT): $(OBJECTS)
+		$(CXX) $(CFLAGS) -fPIC  -o $@ $^ $(LIB)
+
+
+clean:
+		rm -f *.o *.so *.~ *.bak
+		rm -f $(OUTPUT1)
+		rm -f $(OUTPUT2)
+
+install:
+		cp -f $(OUTPUT) $(INSTALL_PATH)
+
+dep:
+		mkdep -p$(VPATH) $(INCLUDE) $(SOURCES) > .depend
+
+ifneq ($(wildcard .depend),)
+	include .depend
+endif
+

+ 34 - 0
src/devel/cpp/examples/delete/deletetest.cpp

@@ -0,0 +1,34 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string>
+#include<stdint.h>
+#include<unistd.h>
+
+#include "dtcapi.h"
+
+int main(int argc,char* argv[])
+{
+	int retCode = 0;
+	unsigned int uid;
+
+	DTC::Server stServer; // 只要server不析构,后台会保持长连接
+	stServer.int_key(); // 声明key类型
+	stServer.set_table_name("t_dtc_example");//设置dtc的表名,与table.conf中tablename应该一样
+	stServer.set_address("192.168.214.62", "10009");//设置的dtc的ip和端口
+	stServer.SetTimeout(5); // 设置网络超时时间
+	stServer.set_accesskey("0000010284d9cfc2f395ce883a41d7ffc1bbcf4e"); // 设置访问码 AccessToken,在申请dtc实例的时候网站端会生成
+
+	DTC::DeleteRequest deleteReq(&stServer);
+	uid = atoi(argv[1]);
+	deleteReq.set_key(uid);
+
+	DTC::Result stResult;
+	retCode = deleteReq.do_execute(stResult);
+	printf("retCode:%d\n", retCode);
+	if(retCode == 0)
+	{
+		printf("delete success!\n");
+	}
+
+	return 0;  
+}  

+ 1020 - 0
src/devel/cpp/examples/delete/dtcapi.h

@@ -0,0 +1,1020 @@
+#ifndef __DTC_API_H__
+#define __DTC_API_H__
+
+#include <stdlib.h>
+#include <vector>
+#include <string>
+#include <stdint.h>
+
+#define IP_LENGHT 16
+
+namespace DTC {
+
+	typedef struct route_node
+	{
+		int bid;
+		int port;
+		int status;
+		int weight;
+		char ip[IP_LENGHT];
+	}ROUTE_NODE;
+
+	class Server;
+	class ServerPool;
+	class Request;
+	class Result;
+
+	const int kRequestSvrAdmin 	= 3;
+	const int kRequestGet 		= 4;
+	const int kRequestPurge 		= 5;
+	const int kRequestInsert 	= 6;
+	const int kRequestUpdate 	= 7;
+	const int kRequestDelete 	= 8;
+	const int kRequestReplace 	= 12;
+	const int kRequestFlush 		= 13;
+	const int kRequestInvalidate	= 14;
+
+	//mem monior Request;2014/06/6;by seanzheng
+	const int kRequestMonitor    = 15;
+
+	// sub-code of admin cmd
+	const int RegisterHB		= 1;
+	const int LogoutHB		= 2;
+	const int GetKeyList		= 3;
+	const int GetUpdateKey		= 4;
+	const int GetRawData		= 5;
+	const int ReplaceRawData	= 6;
+	const int AdjustLRU        	= 7;
+	const int VerifyHBT		= 8;
+	const int GetHBTime		= 9;
+	const int kSetReadOnly	= 10;
+	const int kSetReadWrite	= 11;
+	const int kQueryBinlogID		= 12;
+	const int kNodeHandleChange  = 13;
+	const int Migrate = 14;
+    const int kReloadClusterNodeList = 15;
+    const int kSetClusterNodeState  = 16;
+    const int kChangeNodeAddress  = 17;
+    const int kGetClusterState  = 18;
+    const int kPurgeForHit    = 19;
+	const int ClearCache = 21;
+	const int ColExpandStatus = 24;
+	const int kColExpand = 25;
+	const int ColExpandDone = 26;
+	const int ColExpandKey = 27;
+	
+	const int kKeyTypeNone		= 0;	// undefined
+	const int kKeyTypeInt		= 1;	// Signed Integer
+	const int kKeyTypeString		= 4;	// String, case insensitive, null ended
+
+	const int kFieldTypeNone		= 0;    // undefined
+	const int kFieldTypeSigned	= 1;	// Signed Integer
+	const int kFieldTypeUnsigned	= 2;	// Unsigned Integer
+	const int kFieldTypeFloat	= 3;	// float
+	const int kFieldTypeString	= 4;	// String, case insensitive, null ended
+	const int kFieldTypeBinary	= 5;	// binary
+
+
+	int  set_key_value_max(unsigned int count); // 设置批量操作一次最多多少个key(默认最多32个)
+#ifndef WIN32
+	void write_log (int level,
+			const char*file, const char *func, int lineno,
+			const char *fmt, ...)
+		__attribute__((format(printf,5,6)));
+#endif
+
+	class Result;
+	class Server {
+		private:
+			void *addr_;
+			long check;
+		public:
+			friend class Request;
+			friend class Result;
+			friend class ServerPool;
+			friend class QOSServerPool;
+
+			Server(void);
+			~Server(void);
+			Server(const Server &);
+			void clone_table_define(const Server& source);
+			int set_address(const char *host, const char *port=0);
+			int set_table_name(const char *);
+            //for compress
+            void set_compress_level(int);
+            //get address and tablename set by user
+			const char * get_address(void) const;
+			const char * get_table_name(void) const;
+            //get address and tablename set by dtc frame,for plugin only;
+			const char * get_server_address(void) const;
+			const char * get_server_table_name(void) const;
+			int int_key(void);
+			int binary_key(void);
+			int string_key(void);
+			int add_key(const char* name, int type);
+			int get_field_type(const char* name);
+			const char *get_error_message(void) const;
+			void SetTimeout(int);
+			void set_timeout(int);
+			int connect(void);
+			void close(void);
+			int ping(void);
+			void auto_ping(void);
+			void set_fd(int); // UNSUPPORTED API
+			void set_auto_Update_table(bool autoUpdate);
+			void set_auto_reconnect(int auto_reconnect);
+			int decode_packet(Result &, const char *, int);
+			int check_packet_size(const char *, int);
+
+			void set_accesskey(const char *token);
+
+		public:
+			void increase_error_count_();
+			uint64_t get_error_count();
+			void clear_error_count();
+			
+			void increase_remove_count();
+			int get_remove_count();
+			void clear_remove_count();
+
+			void increase_total_request();
+			uint64_t get_total_request();
+			void clear_total_request();
+
+			void add_total_elaps(uint64_t iElaps);
+			uint64_t get_total_elaps();
+			void clear_total_elaps();
+	};
+
+	class DTCQosServer;
+
+	class DTCServers
+	{
+		public:
+			DTCServers();
+			~DTCServers();
+
+		private:
+			DTCServers(const DTCServers&);
+			DTCServers& operator=(const DTCServers&);
+
+		public:
+			int set_route_list(std::vector<ROUTE_NODE>& ip_list);
+			void set_idc_no(int IDCNo);
+			Server* get_server();
+
+			int set_accesskey(const char *token);
+			int set_table_name(const char *tableName);
+			/*
+				Signed=1,   // Signed Integer
+				String=4,   // String, case insensitive, null ended
+				Binary=5,   // opaque binary data
+			*/
+			int set_key_type(int type);
+			void set_agenttime(int t);
+			voidset_timeout(int n);
+			std::string get_error_msg();
+
+		private:
+			int is_server_has_existed(ROUTE_NODE& ip);
+			int construct_servers();
+			int construct_servers2(std::vector<ROUTE_NODE>& IPList);
+			void disorder_list(int *tmpBuckets, int size);
+			int construct_balance_buckets();
+			int refresh_balance_buckets(uint64_t );			
+			void remove_server_from_buckets(uint64_t );
+			Server* get_one_server_from_buckets();
+			void set_error_msg(int err, std::string from, std::string msg);
+
+		private:
+			int m_time_out;
+			int m_agent_time; 
+			int m_key_type;
+			char* m_table_name;
+			std::string m_access_token;
+			std::string m_err_msg;
+
+		private:
+			bool m_set_route;	
+			bool m_constructed_by_set_i_ps;
+			int m_bid;
+			int m_idc_no;
+			int m_buckets_pos;
+			int m_balance_bucket_size;
+			uint64_t m_bid_version;
+			uint64_t m_last_get_ca_time;
+			uint64_t m_refresh_buckets_time;
+			uint64_t m_remove_buckets_time;
+			int* m_load_balance_buckets;
+			DTCQosServer* m_qos_severs;
+			std::vector<ROUTE_NODE> m_ip_list;
+	};
+
+	class Request {
+		private:
+			void *addr_;
+			long check;
+			Request(const Request &);
+		public:
+			friend class Server;
+			friend class Result;
+			friend class ServerPool;
+
+			Request(Server *srv, int op);
+			Request(void);
+			~Request(void);
+			void Reset(void);
+			void Reset(int);
+			int attach_server(Server *srv);
+
+			void set_admin_code(int code);
+			void set_hotbackup_id(long long);
+			void set_master_hotbackup_timestamp(long long);
+			void set_slave_hotbackup_timestamp(long long);
+
+#define _API_DEFINE_LONG_(op, t) int op(const char *n, t a) { return op(n, (long long)a); }
+#define _API_DEFINE_FLOAT_(op, t) int op(const char *n, t a) { return op(n, (double)a); }
+			int need(const char *);
+			int need(const char *, int);
+			int get_field_type(const char*);
+			void no_cache(void);
+			void no_next_server(void);
+			void limit(unsigned int, unsigned int);
+			int EQ(const char *, long long);
+			int NE(const char *, long long);
+			int LT(const char *, long long);
+			int LE(const char *, long long);
+			int GT(const char *, long long);
+			int GE(const char *, long long);
+			int EQ(const char *, const char *);
+			int NE(const char *, const char *);
+			int EQ(const char *, const char *, int);
+			int NE(const char *, const char *, int);
+
+			_API_DEFINE_LONG_(EQ, unsigned long long);
+			_API_DEFINE_LONG_(EQ, long);
+			_API_DEFINE_LONG_(EQ, unsigned long);
+			_API_DEFINE_LONG_(EQ, int);
+			_API_DEFINE_LONG_(EQ, unsigned int);
+			_API_DEFINE_LONG_(EQ, short);
+			_API_DEFINE_LONG_(EQ, unsigned short);
+			_API_DEFINE_LONG_(EQ, char);
+			_API_DEFINE_LONG_(EQ, unsigned char);
+
+			_API_DEFINE_LONG_(NE, unsigned long long);
+			_API_DEFINE_LONG_(NE, long);
+			_API_DEFINE_LONG_(NE, unsigned long);
+			_API_DEFINE_LONG_(NE, int);
+			_API_DEFINE_LONG_(NE, unsigned int);
+			_API_DEFINE_LONG_(NE, short);
+			_API_DEFINE_LONG_(NE, unsigned short);
+			_API_DEFINE_LONG_(NE, char);
+			_API_DEFINE_LONG_(NE, unsigned char);
+
+			_API_DEFINE_LONG_(GT, unsigned long long);
+			_API_DEFINE_LONG_(GT, long);
+			_API_DEFINE_LONG_(GT, unsigned long);
+			_API_DEFINE_LONG_(GT, int);
+			_API_DEFINE_LONG_(GT, unsigned int);
+			_API_DEFINE_LONG_(GT, short);
+			_API_DEFINE_LONG_(GT, unsigned short);
+			_API_DEFINE_LONG_(GT, char);
+			_API_DEFINE_LONG_(GT, unsigned char);
+
+			_API_DEFINE_LONG_(GE, unsigned long long);
+			_API_DEFINE_LONG_(GE, long);
+			_API_DEFINE_LONG_(GE, unsigned long);
+			_API_DEFINE_LONG_(GE, int);
+			_API_DEFINE_LONG_(GE, unsigned int);
+			_API_DEFINE_LONG_(GE, short);
+			_API_DEFINE_LONG_(GE, unsigned short);
+			_API_DEFINE_LONG_(GE, char);
+			_API_DEFINE_LONG_(GE, unsigned char);
+
+			_API_DEFINE_LONG_(LT, unsigned long long);
+			_API_DEFINE_LONG_(LT, long);
+			_API_DEFINE_LONG_(LT, unsigned long);
+			_API_DEFINE_LONG_(LT, int);
+			_API_DEFINE_LONG_(LT, unsigned int);
+			_API_DEFINE_LONG_(LT, short);
+			_API_DEFINE_LONG_(LT, unsigned short);
+			_API_DEFINE_LONG_(LT, char);
+			_API_DEFINE_LONG_(LT, unsigned char);
+
+			_API_DEFINE_LONG_(LE, unsigned long long);
+			_API_DEFINE_LONG_(LE, long);
+			_API_DEFINE_LONG_(LE, unsigned long);
+			_API_DEFINE_LONG_(LE, int);
+			_API_DEFINE_LONG_(LE, unsigned int);
+			_API_DEFINE_LONG_(LE, short);
+			_API_DEFINE_LONG_(LE, unsigned short);
+			_API_DEFINE_LONG_(LE, char);
+			_API_DEFINE_LONG_(LE, unsigned char);
+
+			int Set(const char *, long long);
+			int OR(const char *, long long);
+			int Add(const char *, long long);
+			int Sub(const char *, long long);
+			int Set(const char *, double);
+			int Add(const char *, double);
+			int Sub(const char *, double);
+			int Set(const char *, const char *);
+			int Set(const char *, const char *, int);
+
+            //just for compress,only support binary field
+			int compress_set(const char *, const char *, int);
+			//just compress and set. Don't need compressflag
+			int compress_set_force(const char *, const char *, int);
+
+			//bits op
+			int set_multi_bits(const char *, int, int, unsigned int);
+			int set_bit  (const char *f, int o) { return set_multi_bits(f, o, 1, 1);}
+			int clear_bit(const char *f, int o) { return set_multi_bits(f, o, 1, 0);}
+
+			_API_DEFINE_LONG_(Set, unsigned long long);
+			_API_DEFINE_LONG_(Set, long);
+			_API_DEFINE_LONG_(Set, unsigned long);
+			_API_DEFINE_LONG_(Set, int);
+			_API_DEFINE_LONG_(Set, unsigned int);
+			_API_DEFINE_LONG_(Set, short);
+			_API_DEFINE_LONG_(Set, unsigned short);
+			_API_DEFINE_LONG_(Set, char);
+			_API_DEFINE_LONG_(Set, unsigned char);
+			_API_DEFINE_FLOAT_(Set, float);
+			_API_DEFINE_FLOAT_(Set, long double);
+
+			_API_DEFINE_LONG_(OR, unsigned long long);
+			_API_DEFINE_LONG_(OR, long);
+			_API_DEFINE_LONG_(OR, unsigned long);
+			_API_DEFINE_LONG_(OR, int);
+			_API_DEFINE_LONG_(OR, unsigned int);
+			_API_DEFINE_LONG_(OR, short);
+			_API_DEFINE_LONG_(OR, unsigned short);
+
+			_API_DEFINE_LONG_(Add, unsigned long long);
+			_API_DEFINE_LONG_(Add, long);
+			_API_DEFINE_LONG_(Add, unsigned long);
+			_API_DEFINE_LONG_(Add, int);
+			_API_DEFINE_LONG_(Add, unsigned int);
+			_API_DEFINE_LONG_(Add, short);
+			_API_DEFINE_LONG_(Add, unsigned short);
+			_API_DEFINE_LONG_(Add, char);
+			_API_DEFINE_LONG_(Add, unsigned char);
+			_API_DEFINE_FLOAT_(Add, float);
+			_API_DEFINE_FLOAT_(Add, long double);
+
+			_API_DEFINE_LONG_(Sub, unsigned long long);
+			_API_DEFINE_LONG_(Sub, long);
+			_API_DEFINE_LONG_(Sub, unsigned long);
+			_API_DEFINE_LONG_(Sub, int);
+			_API_DEFINE_LONG_(Sub, unsigned int);
+			_API_DEFINE_LONG_(Sub, short);
+			_API_DEFINE_LONG_(Sub, unsigned short);
+			_API_DEFINE_LONG_(Sub, char);
+			_API_DEFINE_LONG_(Sub, unsigned char);
+			_API_DEFINE_FLOAT_(Sub, float);
+			_API_DEFINE_FLOAT_(Sub, long double);
+#undef _API_DEFINE_LONG_
+
+			void unset_key(void);
+			int set_key(long long);
+			int set_key(const char *);
+			int set_key(const char *, int);
+#define _API_DEFINE_LONG_(t) int set_key(t a) { return set_key((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int add_key_value(const char* name, long long v);
+			int add_key_value(const char* name, const char *str);
+			int add_key_value(const char* name, const char *ptr, int len);
+#define _API_DEFINE_LONG_(t) int add_key_value(const char* name, t a) { return add_key_value(name, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			Result *do_execute(void);
+			Result *do_execute(long long);
+			Result *do_execute(const char *);
+			Result *do_execute(const char *, int);
+
+#define _API_DEFINE_LONG_(t) Result *do_execute(t a) { return do_execute((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int do_execute(Result&);
+			int do_execute(Result&, long long);
+			int do_execute(Result&, const char *);
+			int do_execute(Result&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int do_execute(Result &r, t a) { return do_execute(r, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int encode_packet(char *&, int&, long long&);
+			int encode_packet(char *&, int&, long long&, long long);
+			int encode_packet(char *&, int&, long long&, const char *);
+			int encode_packet(char *&, int&, long long&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int encode_packet(char *&p, int &l, long long &m, t a) { return encode_packet(p,l,m,(long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int set_cache_id(long long);
+#define _API_DEFINE_LONG_(t) int set_cache_id(t a) {return set_cache_id((long long)a);}
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+            const char *get_error_message(void) const;
+
+            //无源模式超时时间   add by xuxinxin, 2014/12/09
+			int set_expire_time(const char* key, int time);
+			int get_expire_time(const char* key);
+	};
+
+	class GetRequest : public Request {
+		public:
+			GetRequest(Server *srv): Request(srv, kRequestGet) {}
+			GetRequest(): Request((Server *)0, kRequestGet) {}
+	};
+
+	class InsertRequest : public Request {
+		public:
+			InsertRequest(Server *srv) : Request(srv, kRequestInsert) {}
+			InsertRequest() : Request((Server *)0, kRequestInsert) {}
+	};
+
+	class DeleteRequest : public Request {
+		public:
+			DeleteRequest(Server *srv) : Request(srv, kRequestDelete) {}
+			DeleteRequest() : Request((Server *)0, kRequestDelete) {}
+	};
+
+	class UpdateRequest : public Request {
+		public:
+			UpdateRequest(Server *srv) : Request(srv, kRequestUpdate) {}
+			UpdateRequest() : Request((Server *)0, kRequestUpdate) {}
+	};
+
+	class PurgeRequest : public Request {
+		public:
+			PurgeRequest(Server *srv) : Request(srv, kRequestPurge) {}
+			PurgeRequest() : Request((Server *)0, kRequestPurge) {}
+	};
+
+	class ReplaceRequest:public Request {
+		public:
+			ReplaceRequest(Server *srv) : Request(srv, kRequestReplace) {}
+			ReplaceRequest() : Request((Server *)0, kRequestReplace) {}
+	};
+
+	class FlushRequest : public Request {
+		public:
+			FlushRequest(Server *srv) : Request(srv, kRequestFlush) {}
+			FlushRequest(void) : Request((Server *)0, kRequestFlush) {}
+	};
+
+	class InvalidateRequest: public Request {
+		public:
+			InvalidateRequest(Server *srv) : Request(srv, kRequestInvalidate) {}
+	};
+
+	class SvrAdminRequest: public Request {
+		public:
+			SvrAdminRequest(Server *srv) : Request(srv, kRequestSvrAdmin) {}
+	};
+
+	class MonitorRequest: public Request {
+		public:
+			MonitorRequest(Server *srv) : Request(srv, kRequestMonitor){}
+	};
+
+	class Result {
+		private:
+			void *addr_;
+			long check;
+			Result(const Result &);
+			char *ServerInfo() const;
+		public:
+			friend class Server;
+			friend class Request;
+			friend class ServerPool;
+
+			Result(void);
+			~Result(void);
+			void Reset(void);
+
+			void set_error(int errcode, const char *from, const char *detail); // from will not dupped
+			int get_result_code(void) const;
+			const char *get_error_message(void) const;
+			const char *get_error_from(void) const;
+			long long get_hotbackup_id() const;
+			long long get_master_hotbackup_timestamp() const;
+			long long slave_hotbackup_timestamp() const;
+			long long get_binlog_id() const;
+			long long get_binlog_offset() const;
+			long long get_mem_size() const;
+			long long get_datd_size() const;
+			int get_num_row_size(void) const;
+			int get_total_rows_size(void) const;
+			int get_affected_rows_size(void) const;
+			int get_num_fields_size(void) const;
+			const char* get_field_name(int n) const;
+			int get_field_present(const char* name) const;
+			int get_field_type(int n) const;
+			long long get_tag(void) const;
+			void *get_tag_ptr(void) const;
+			long long magic(void) const;
+			long long get_server_timestamp(void) const;
+			long long get_insert_id(void) const;
+			long long int_key(void) const;
+			const char *binary_key(void) const;
+			const char *binary_key(int *) const;
+			const char *binary_key(int &) const;
+			const char *string_key(void) const;
+			const char *string_key(int *) const;
+			const char *string_key(int &) const;
+			long long int_value(const char *) const;
+			double float_value(const char *) const;
+			const char *string_value(const char *) const;
+			const char *string_value(const char *, int*) const;
+			const char *string_value(const char *, int&) const;
+			const char *binary_value(const char *) const;
+			const char *binary_value(const char *, int*) const;
+			const char *binary_value(const char *, int&) const;
+			int uncompress_binary_value(const char *name,char **buf,int *lenp);
+			//Uncompress Binary Value without check compressflag
+			int uncompress_binary_value_force(const char *name,char **buf,int *lenp);
+            const char * uncompress_error_message() const;
+			long long int_value(int) const;
+			double float_value(int) const;
+			const char *string_value(int) const;
+			const char *string_value(int, int*) const;
+			const char *string_value(int, int&) const;
+			const char *binary_value(int) const;
+			const char *binary_value(int, int*) const;
+			const char *binary_value(int, int&) const;
+			int fetch_row(void);
+			int rewind(void);
+	};
+
+	class ServerPool {
+		private:
+			void *addr_;
+			long check;
+			ServerPool(ServerPool &);
+		public:
+			friend class Server;
+			friend class Request;
+			friend class Result;
+
+			ServerPool(int max_servers, int max_requests);
+			~ServerPool(void);
+
+			int get_epoll_fd(int size);
+			int add_server(Server *srv, int mReq=1, int mConn=0);
+			int add_request(Request *, long long);
+			int add_request(Request *, long long, long long);
+			int add_request(Request *, long long, const char *);
+			int add_request(Request *, long long, const char *, int);
+			int add_request(Request *, void *);
+			int add_request(Request *, void *, long long);
+			int add_request(Request *, void *, const char *);
+			int add_request(Request *, void *, const char *, int);
+			int do_execute(int msec);
+			int execute_all(int msec);
+			int cancel_request(int);
+			int cancel_all_request(int type);
+			int abort_request(int);
+			int abort_all_request(int type);
+			Result *get_result(void);
+			Result *get_result(int);
+			int get_result(Result&);
+			int get_result(Result&, int);
+
+			int server_count(void) const;
+			int request_count(int type) const;
+			int request_state(int reqId) const;
+	};
+
+	const int WAIT = 1;
+	const int SEND = 2;
+	const int RECV = 4;
+	const int DONE = 8;
+	const int ALL_STATE = WAIT|SEND|RECV|DONE;
+
+	enum {
+		EC_ERROR_BASE = 2000,
+		EC_BAD_COMMAND,		// unsupported command
+		EC_MISSING_SECTION,	// missing mandatory section
+		EC_EXTRA_SECTION,	// incompatible section present
+		EC_DUPLICATE_TAG,	// same tag appear twice
+
+		EC_DUPLICATE_FIELD,	//5: same field appear twice in .need()
+		EC_BAD_SECTION_LENGTH,	// section length too short
+		EC_BAD_VALUE_LENGTH,	// value length not allow
+		EC_BAD_STRING_VALUE,	// string value w/o NULL
+		EC_BAD_FLOAT_VALUE,	// invalid float format
+
+		EC_BAD_FIELD_NUM,	//10: invalid total field#
+		EC_EXTRA_SECTION_DATA,	// section length too large
+		EC_BAD_VALUE_TYPE,	// incompatible value type
+		EC_BAD_OPERATOR,	// incompatible operator/comparison
+		EC_BAD_FIELD_ID,	// invalid field ID
+
+		EC_BAD_FIELD_NAME,	//15: invalud field name
+		EC_BAD_FIELD_TYPE,	// invalid field type
+		EC_BAD_FIELD_SIZE,	// invalid field size
+		EC_TABLE_REDEFINED,	// table defined twice
+		EC_TABLE_MISMATCH,	// request table != server table
+
+		EC_VERSION_MISMATCH,	//20: unsupported protocol version
+		EC_CHECKSUM_MISMATCH,	// table hash not equal
+		EC_NO_MORE_DATA,	// End of Result
+		EC_NEED_FULL_FIELDSET,	// only full field set accepted by helper
+		EC_BAD_KEY_TYPE,	// key type incompatible
+
+		EC_BAD_KEY_SIZE,	// 25: key size incompatible
+		EC_SERVER_BUSY,		//server error
+		EC_BAD_SOCKET,		// network failed
+		EC_NOT_INITIALIZED,	// object didn't initialized
+		EC_BAD_HOST_STRING,
+
+		EC_BAD_TABLE_NAME,	// 30
+		EC_TASK_NEED_DELETE,
+		EC_KEY_NEEDED,
+		EC_SERVER_ERROR,
+		EC_UPSTREAM_ERROR,
+
+		EC_KEY_OVERFLOW,	// 35
+		EC_BAD_MULTIKEY,
+		EC_READONLY_FIELD,
+		EC_BAD_ASYNC_CMD,
+		EC_OUT_OF_KEY_RANGE,
+
+		EC_REQUEST_ABORTED,     // 40
+		EC_PARALLEL_MODE,
+		EC_KEY_NOTEXIST,
+		EC_SERVER_READONLY,
+		EC_BAD_INVALID_FIELD,
+
+		EC_DUPLICATE_KEY,    	// 45
+		EC_TOO_MANY_KEY_VALUE,
+		EC_BAD_KEY_NAME,
+		EC_BAD_RAW_DATA,
+		EC_BAD_HOTBACKUP_JID,
+
+		EC_FULL_SYNC_COMPLETE,  //50
+		EC_FULL_SYNC_STAGE,
+		EC_INC_SYNC_STAGE,
+        EC_ERR_SYNC_STAGE,
+        EC_NOT_ALLOWED_INSERT,
+
+        EC_COMPRESS_ERROR,  //55
+        EC_UNCOMPRESS_ERROR,
+        EC_TASKPOOL,
+        EC_STATE_ERROR,
+        EC_DATA_NEEDED,
+
+    	EC_TASK_TIMEOUT,
+
+        EC_BUSINESS_WITHOUT_EXPIRETIME, //62
+        EC_EMPTY_TBDEF, //63
+    	EC_INVALID_KEY_VALUE, //64
+    	EC_INVALID_EXPIRETIME, //65
+
+    	EC_GET_EXPIRETIME_END_OF_RESULT, //66
+	};
+
+	enum {
+		ER_HASHCHK=1000,
+		ER_NISAMCHK=1001,
+		ER_NO=1002,
+		ER_YES=1003,
+		ER_CANT_CREATE_FILE=1004,
+		ER_CANT_CREATE_TABLE=1005,
+		ER_CANT_CREATE_DB=1006,
+		ER_DB_CREATE_EXISTS=1007,
+		ER_DB_DROP_EXISTS=1008,
+		ER_DB_DROP_DELETE=1009,
+		ER_DB_DROP_RMDIR=1010,
+		ER_CANT_DELETE_FILE=1011,
+		ER_CANT_FIND_SYSTEM_REC=1012,
+		ER_CANT_GET_STAT=1013,
+		ER_CANT_GET_WD=1014,
+		ER_CANT_LOCK=1015,
+		ER_CANT_OPEN_FILE=1016,
+		ER_FILE_NOT_FOUND=1017,
+		ER_CANT_READ_DIR=1018,
+		ER_CANT_SET_WD=1019,
+		ER_CHECKREAD=1020,
+		ER_DISK_FULL=1021,
+		ER_DUP_KEY=1022,
+		ER_ERROR_ON_CLOSE=1023,
+		ER_ERROR_ON_READ=1024,
+		ER_ERROR_ON_RENAME=1025,
+		ER_ERROR_ON_WRITE=1026,
+		ER_FILE_USED=1027,
+		ER_FILSORT_ABORT=1028,
+		ER_FORM_NOT_FOUND=1029,
+		ER_GET_ERRNO=1030,
+		ER_ILLEGAL_HA=1031,
+		ER_KEY_NOT_FOUND=1032,
+		ER_NOT_FORM_FILE=1033,
+		ER_NOT_KEYFILE=1034,
+		ER_OLD_KEYFILE=1035,
+		ER_OPEN_AS_READONLY=1036,
+		ER_OUTOFMEMORY=1037,
+		ER_OUT_OF_SORTMEMORY=1038,
+		ER_UNEXPECTED_EOF=1039,
+		ER_CON_COUNT_ERROR=1040,
+		ER_OUT_OF_RESOURCES=1041,
+		ER_BAD_HOST_ERROR=1042,
+		ER_HANDSHAKE_ERROR=1043,
+		ER_DBACCESS_DENIED_ERROR=1044,
+		ER_ACCESS_DENIED_ERROR=1045,
+		ER_NO_DB_ERROR=1046,
+		ER_UNKNOWN_COM_ERROR=1047,
+		ER_BAD_NULL_ERROR=1048,
+		ER_BAD_DB_ERROR=1049,
+		ER_TABLE_EXISTS_ERROR=1050,
+		ER_BAD_TABLE_ERROR=1051,
+		ER_NON_UNIQ_ERROR=1052,
+		ER_SERVER_SHUTDOWN=1053,
+		ER_BAD_FIELD_ERROR=1054,
+		ER_WRONG_FIELD_WITH_GROUP=1055,
+		ER_WRONG_GROUP_FIELD=1056,
+		ER_WRONG_SUM_SELECT=1057,
+		ER_WRONG_VALUE_COUNT=1058,
+		ER_TOO_LONG_IDENT=1059,
+		ER_DUP_FIELDNAME=1060,
+		ER_DUP_KEYNAME=1061,
+		ER_DUP_ENTRY=1062,
+		ER_WRONG_FIELD_SPEC=1063,
+		ER_PARSE_ERROR=1064,
+		ER_EMPTY_QUERY=1065,
+		ER_NONUNIQ_TABLE=1066,
+		ER_INVALID_DEFAULT=1067,
+		ER_MULTIPLE_PRI_KEY=1068,
+		ER_TOO_MANY_KEYS=1069,
+		ER_TOO_MANY_KEY_PARTS=1070,
+		ER_TOO_LONG_KEY=1071,
+		ER_KEY_COLUMN_DOES_NOT_EXITS=1072,
+		ER_BLOB_USED_AS_KEY=1073,
+		ER_TOO_BIG_FIELDLENGTH=1074,
+		ER_WRONG_AUTO_KEY=1075,
+		ER_READY=1076,
+		ER_NORMAL_SHUTDOWN=1077,
+		ER_GOT_SIGNAL=1078,
+		ER_SHUTDOWN_COMPLETE=1079,
+		ER_FORCING_CLOSE=1080,
+		ER_IPSOCK_ERROR=1081,
+		ER_NO_SUCH_INDEX=1082,
+		ER_WRONG_FIELD_TERMINATORS=1083,
+		ER_BLOBS_AND_NO_TERMINATED=1084,
+		ER_TEXTFILE_NOT_READABLE=1085,
+		ER_FILE_EXISTS_ERROR=1086,
+		ER_LOAD_INFO=1087,
+		ER_ALTER_INFO=1088,
+		ER_WRONG_SUB_KEY=1089,
+		ER_CANT_REMOVE_ALL_FIELDS=1090,
+		ER_CANT_DROP_FIELD_OR_KEY=1091,
+		ER_INSERT_INFO=1092,
+		ER_INSERT_TABLE_USED=1093,
+		ER_NO_SUCH_THREAD=1094,
+		ER_KILL_DENIED_ERROR=1095,
+		ER_NO_TABLES_USED=1096,
+		ER_TOO_BIG_SET=1097,
+		ER_NO_UNIQUE_LOGFILE=1098,
+		ER_TABLE_NOT_LOCKED_FOR_WRITE=1099,
+		ER_TABLE_NOT_LOCKED=1100,
+		ER_BLOB_CANT_HAVE_DEFAULT=1101,
+		ER_WRONG_DB_NAME=1102,
+		ER_WRONG_TABLE_NAME=1103,
+		ER_TOO_BIG_SELECT=1104,
+		ER_UNKNOWN_ERROR=1105,
+		ER_UNKNOWN_PROCEDURE=1106,
+		ER_WRONG_PARAMCOUNT_TO_PROCEDURE=1107,
+		ER_WRONG_PARAMETERS_TO_PROCEDURE=1108,
+		ER_UNKNOWN_TABLE=1109,
+		ER_FIELD_SPECIFIED_TWICE=1110,
+		ER_INVALID_GROUP_FUNC_USE=1111,
+		ER_UNSUPPORTED_EXTENSION=1112,
+		ER_TABLE_MUST_HAVE_COLUMNS=1113,
+		ER_RECORD_FILE_FULL=1114,
+		ER_UNKNOWN_CHARACTER_SET=1115,
+		ER_TOO_MANY_TABLES=1116,
+		ER_TOO_MANY_FIELDS=1117,
+		ER_TOO_BIG_ROWSIZE=1118,
+		ER_STACK_OVERRUN=1119,
+		ER_WRONG_OUTER_JOIN=1120,
+		ER_NULL_COLUMN_IN_INDEX=1121,
+		ER_CANT_FIND_UDF=1122,
+		ER_CANT_INITIALIZE_UDF=1123,
+		ER_UDF_NO_PATHS=1124,
+		ER_UDF_EXISTS=1125,
+		ER_CANT_OPEN_LIBRARY=1126,
+		ER_CANT_FIND_DL_ENTRY=1127,
+		ER_FUNCTION_NOT_DEFINED=1128,
+		ER_HOST_IS_BLOCKED=1129,
+		ER_HOST_NOT_PRIVILEGED=1130,
+		ER_PASSWORD_ANONYMOUS_USER=1131,
+		ER_PASSWORD_NOT_ALLOWED=1132,
+		ER_PASSWORD_NO_MATCH=1133,
+		ER_UPDATE_INFO=1134,
+		ER_CANT_CREATE_THREAD=1135,
+		ER_WRONG_VALUE_COUNT_ON_ROW=1136,
+		ER_CANT_REOPEN_TABLE=1137,
+		ER_INVALID_USE_OF_NULL=1138,
+		ER_REGEXP_ERROR=1139,
+		ER_MIX_OF_GROUP_FUNC_AND_FIELDS=1140,
+		ER_NONEXISTING_GRANT=1141,
+		ER_TABLEACCESS_DENIED_ERROR=1142,
+		ER_COLUMNACCESS_DENIED_ERROR=1143,
+		ER_ILLEGAL_GRANT_FOR_TABLE=1144,
+		ER_GRANT_WRONG_HOST_OR_USER=1145,
+		ER_NO_SUCH_TABLE=1146,
+		ER_NONEXISTING_TABLE_GRANT=1147,
+		ER_NOT_ALLOWED_COMMAND=1148,
+		ER_SYNTAX_ERROR=1149,
+		ER_DELAYED_CANT_CHANGE_LOCK=1150,
+		ER_TOO_MANY_DELAYED_THREADS=1151,
+		ER_ABORTING_CONNECTION=1152,
+		ER_NET_PACKET_TOO_LARGE=1153,
+		ER_NET_READ_ERROR_FROM_PIPE=1154,
+		ER_NET_FCNTL_ERROR=1155,
+		ER_NET_PACKETS_OUT_OF_ORDER=1156,
+		ER_NET_UNCOMPRESS_ERROR=1157,
+		ER_NET_READ_ERROR=1158,
+		ER_NET_READ_INTERRUPTED=1159,
+		ER_NET_ERROR_ON_WRITE=1160,
+		ER_NET_WRITE_INTERRUPTED=1161,
+		ER_TOO_LONG_STRING=1162,
+		ER_TABLE_CANT_HANDLE_BLOB=1163,
+		ER_TABLE_CANT_HANDLE_AUTO_INCREMENT=1164,
+		ER_DELAYED_INSERT_TABLE_LOCKED=1165,
+		ER_WRONG_COLUMN_NAME=1166,
+		ER_WRONG_KEY_COLUMN=1167,
+		ER_WRONG_MRG_TABLE=1168,
+		ER_DUP_UNIQUE=1169,
+		ER_BLOB_KEY_WITHOUT_LENGTH=1170,
+		ER_PRIMARY_CANT_HAVE_NULL=1171,
+		ER_TOO_MANY_ROWS=1172,
+		ER_REQUIRES_PRIMARY_KEY=1173,
+		ER_NO_RAID_COMPILED=1174,
+		ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE=1175,
+		ER_KEY_DOES_NOT_EXITS=1176,
+		ER_CHECK_NO_SUCH_TABLE=1177,
+		ER_CHECK_NOT_IMPLEMENTED=1178,
+		ER_CANT_DO_THIS_DURING_AN_TRANSACTION=1179,
+		ER_ERROR_DURING_COMMIT=1180,
+		ER_ERROR_DURING_ROLLBACK=1181,
+		ER_ERROR_DURING_FLUSH_LOGS=1182,
+		ER_ERROR_DURING_CHECKPOINT=1183,
+		ER_NEW_ABORTING_CONNECTION=1184,
+		ER_DUMP_NOT_IMPLEMENTED=   1185,
+		ER_FLUSH_MASTER_BINLOG_CLOSED=1186,
+		ER_INDEX_REBUILD= 1187,
+		ER_MASTER=1188,
+		ER_MASTER_NET_READ=1189,
+		ER_MASTER_NET_WRITE=1190,
+		ER_FT_MATCHING_KEY_NOT_FOUND=1191,
+		ER_LOCK_OR_ACTIVE_TRANSACTION=1192,
+		ER_UNKNOWN_SYSTEM_VARIABLE=1193,
+		ER_CRASHED_ON_USAGE=1194,
+		ER_CRASHED_ON_REPAIR=1195,
+		ER_WARNING_NOT_COMPLETE_ROLLBACK=1196,
+		ER_TRANS_CACHE_FULL=1197,
+		ER_SLAVE_MUST_STOP=1198,
+		ER_SLAVE_NOT_RUNNING=1199,
+		ER_BAD_SLAVE=1200,
+		ER_MASTER_INFO=1201,
+		ER_SLAVE_THREAD=1202,
+		ER_TOO_MANY_USER_CONNECTIONS=1203,
+		ER_SET_CONSTANTS_ONLY=1204,
+		ER_LOCK_WAIT_TIMEOUT=1205,
+		ER_LOCK_TABLE_FULL=1206,
+		ER_READ_ONLY_TRANSACTION=1207,
+		ER_DROP_DB_WITH_READ_LOCK=1208,
+		ER_CREATE_DB_WITH_READ_LOCK=1209,
+		ER_WRONG_ARGUMENTS=1210,
+		ER_NO_PERMISSION_TO_CREATE_USER=1211,
+		ER_UNION_TABLES_IN_DIFFERENT_DIR=1212,
+		ER_LOCK_DEADLOCK=1213,
+		ER_TABLE_CANT_HANDLE_FULLTEXT=1214,
+		ER_CANNOT_ADD_FOREIGN=1215,
+		ER_NO_REFERENCED_ROW=1216,
+		ER_ROW_IS_REFERENCED=1217,
+		ER_CONNECT_TO_MASTER=1218,
+		ER_QUERY_ON_MASTER=1219,
+		ER_ERROR_WHEN_EXECUTING_COMMAND=1220,
+		ER_WRONG_USAGE=1221,
+		ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT=1222,
+		ER_CANT_UPDATE_WITH_READLOCK=1223,
+		ER_MIXING_NOT_ALLOWED=1224,
+		ER_DUP_ARGUMENT=1225,
+		ER_USER_LIMIT_REACHED=1226,
+		ER_SPECIFIC_ACCESS_DENIED_ERROR=1227,
+		ER_LOCAL_VARIABLE=1228,
+		ER_GLOBAL_VARIABLE=1229,
+		ER_NO_DEFAULT=1230,
+		ER_WRONG_VALUE_FOR_VAR=1231,
+		ER_WRONG_TYPE_FOR_VAR=1232,
+		ER_VAR_CANT_BE_READ=1233,
+		ER_CANT_USE_OPTION_HERE=1234,
+		ER_NOT_SUPPORTED_YET=1235,
+		ER_MASTER_FATAL_ERROR_READING_BINLOG=1236,
+		ER_SLAVE_IGNORED_TABLE=1237,
+		ER_INCORRECT_GLOBAL_LOCAL_VAR=1238,
+		CR_UNKNOWN_ERROR=1900,
+		CR_SOCKET_CREATE_ERROR=1901,
+		CR_CONNECTION_ERROR=1902,
+		CR_CONN_HOST_ERROR=1903,
+		CR_IPSOCK_ERROR	=1904,
+		CR_UNKNOWN_HOST	=1905,
+		CR_SERVER_GONE_ERROR=1906,
+		CR_VERSION_ERROR=1907,
+		CR_OUT_OF_MEMORY=1908,
+		CR_WRONG_HOST_INFO=1909,
+		CR_LOCALHOST_CONNECTION=1910,
+		CR_TCP_CONNECTION=1911,
+		CR_SERVER_HANDSHAKE_ERR=1912,
+		CR_SERVER_LOST=1913,
+		CR_COMMANDS_OUT_OF_SYNC=1914,
+		CR_NAMEDPIPE_CONNECTION=1915,
+		CR_NAMEDPIPEWAIT_ERROR=1916,
+		CR_NAMEDPIPEOPEN_ERROR=1917,
+		CR_NAMEDPIPESETSTATE_ERROR=1918,
+		CR_CANT_READ_CHARSET=1919,
+		CR_NET_PACKET_TOO_LARGE=1920,
+		CR_EMBEDDED_CONNECTION=1921,
+		CR_PROBE_SLAVE_STATUS=1922,
+		CR_PROBE_SLAVE_HOSTS=1923,
+		CR_PROBE_SLAVE_CONNECT=1924,
+		CR_PROBE_MASTER_CONNECT=1925,
+		CR_SSL_CONNECTION_ERROR=1926,
+		CR_MALFORMED_PACKET=1927,
+		CR_WRONG_LICENSE=1928,
+	};
+
+	enum{
+		ER_SET_IPLIST_NULL = 20001,
+		ER_SET_INSTANCE_PROPERTIES_ERR,
+		ER_KEY_TYPE,
+		ER_CC_VERSION_ERR,
+		ER_ROUTE_INFO_NULL,
+		ER_BID_VERSION_ERR,
+		ER_PORT_OUT_RANGE,
+		ER_STATUS_ERROR_VALUE,
+		ER_WEIGHT_ERROR_VALUE,
+		ER_IP_ERROR_VALUE,
+	};
+
+};
+
+#endif

+ 38 - 0
src/devel/cpp/examples/insert/Makefile

@@ -0,0 +1,38 @@
+LIB = ../../libdtc.so
+
+OUTPUT = insert
+
+SOURCES =  inserttest.cpp 
+								   		
+
+OBJECTS= inserttest.o
+	CPPFLAGS = -g -O -Wall -fPIC -DMACROFOR64BIT -Wl,--no-undefined -Xlinker -zmuldefs
+	CFLAGS = $(CPPFLAGS)
+
+all:$(OUTPUT)
+
+.SUFFIXES: .o .cpp
+	.cpp.o:
+		$(CXX) $(CPPFLAGS) $(INCLUDE) -c $(filter %.cpp, $^) 
+
+.o:
+		$(CXX) $(CPPFLAGS) $(INCLUDE) -o $@ $^ 
+
+$(OUTPUT): $(OBJECTS)
+		$(CXX) $(CFLAGS) -fPIC  -o $@ $^ $(LIB)
+
+
+clean:
+		rm -f *.o *.so *.~ *.bak
+		rm -f $(OUTPUT)
+
+install:
+		cp -f $(OUTPUT) $(INSTALL_PATH)
+
+dep:
+		mkdep -p$(VPATH) $(INCLUDE) $(SOURCES) > .depend
+
+ifneq ($(wildcard .depend),)
+	include .depend
+endif
+

+ 1020 - 0
src/devel/cpp/examples/insert/dtcapi.h

@@ -0,0 +1,1020 @@
+#ifndef __DTC_API_H__
+#define __DTC_API_H__
+
+#include <stdlib.h>
+#include <vector>
+#include <string>
+#include <stdint.h>
+
+#define IP_LENGHT 16
+
+namespace DTC {
+
+	typedef struct route_node
+	{
+		int bid;
+		int port;
+		int status;
+		int weight;
+		char ip[IP_LENGHT];
+	}ROUTE_NODE;
+
+	class Server;
+	class ServerPool;
+	class Request;
+	class Result;
+
+	const int kRequestSvrAdmin 	= 3;
+	const int kRequestGet 		= 4;
+	const int kRequestPurge 		= 5;
+	const int kRequestInsert 	= 6;
+	const int kRequestUpdate 	= 7;
+	const int kRequestDelete 	= 8;
+	const int kRequestReplace 	= 12;
+	const int kRequestFlush 		= 13;
+	const int kRequestInvalidate	= 14;
+
+	//mem monior Request;2014/06/6;by seanzheng
+	const int kRequestMonitor    = 15;
+
+	// sub-code of admin cmd
+	const int RegisterHB		= 1;
+	const int LogoutHB		= 2;
+	const int GetKeyList		= 3;
+	const int GetUpdateKey		= 4;
+	const int GetRawData		= 5;
+	const int ReplaceRawData	= 6;
+	const int AdjustLRU        	= 7;
+	const int VerifyHBT		= 8;
+	const int GetHBTime		= 9;
+	const int kSetReadOnly	= 10;
+	const int kSetReadWrite	= 11;
+	const int kQueryBinlogID		= 12;
+	const int kNodeHandleChange  = 13;
+	const int Migrate = 14;
+    const int kReloadClusterNodeList = 15;
+    const int kSetClusterNodeState  = 16;
+    const int kChangeNodeAddress  = 17;
+    const int kGetClusterState  = 18;
+    const int kPurgeForHit    = 19;
+	const int ClearCache = 21;
+	const int ColExpandStatus = 24;
+	const int kColExpand = 25;
+	const int ColExpandDone = 26;
+	const int ColExpandKey = 27;
+	
+	const int kKeyTypeNone		= 0;	// undefined
+	const int kKeyTypeInt		= 1;	// Signed Integer
+	const int kKeyTypeString		= 4;	// String, case insensitive, null ended
+
+	const int kFieldTypeNone		= 0;    // undefined
+	const int kFieldTypeSigned	= 1;	// Signed Integer
+	const int kFieldTypeUnsigned	= 2;	// Unsigned Integer
+	const int kFieldTypeFloat	= 3;	// float
+	const int kFieldTypeString	= 4;	// String, case insensitive, null ended
+	const int kFieldTypeBinary	= 5;	// binary
+
+
+	int  set_key_value_max(unsigned int count); // 设置批量操作一次最多多少个key(默认最多32个)
+#ifndef WIN32
+	void write_log (int level,
+			const char*file, const char *func, int lineno,
+			const char *fmt, ...)
+		__attribute__((format(printf,5,6)));
+#endif
+
+	class Result;
+	class Server {
+		private:
+			void *addr_;
+			long check;
+		public:
+			friend class Request;
+			friend class Result;
+			friend class ServerPool;
+			friend class QOSServerPool;
+
+			Server(void);
+			~Server(void);
+			Server(const Server &);
+			void clone_table_define(const Server& source);
+			int set_address(const char *host, const char *port=0);
+			int set_table_name(const char *);
+            //for compress
+            void set_compress_level(int);
+            //get address and tablename set by user
+			const char * get_address(void) const;
+			const char * get_table_name(void) const;
+            //get address and tablename set by dtc frame,for plugin only;
+			const char * get_server_address(void) const;
+			const char * get_server_table_name(void) const;
+			int int_key(void);
+			int binary_key(void);
+			int string_key(void);
+			int add_key(const char* name, int type);
+			int get_field_type(const char* name);
+			const char *get_error_message(void) const;
+			void SetTimeout(int);
+			void set_timeout(int);
+			int connect(void);
+			void close(void);
+			int ping(void);
+			void auto_ping(void);
+			void set_fd(int); // UNSUPPORTED API
+			void set_auto_Update_table(bool autoUpdate);
+			void set_auto_reconnect(int auto_reconnect);
+			int decode_packet(Result &, const char *, int);
+			int check_packet_size(const char *, int);
+
+			void set_accesskey(const char *token);
+
+		public:
+			void increase_error_count_();
+			uint64_t get_error_count();
+			void clear_error_count();
+			
+			void increase_remove_count();
+			int get_remove_count();
+			void clear_remove_count();
+
+			void increase_total_request();
+			uint64_t get_total_request();
+			void clear_total_request();
+
+			void add_total_elaps(uint64_t iElaps);
+			uint64_t get_total_elaps();
+			void clear_total_elaps();
+	};
+
+	class DTCQosServer;
+
+	class DTCServers
+	{
+		public:
+			DTCServers();
+			~DTCServers();
+
+		private:
+			DTCServers(const DTCServers&);
+			DTCServers& operator=(const DTCServers&);
+
+		public:
+			int set_route_list(std::vector<ROUTE_NODE>& ip_list);
+			void set_idc_no(int IDCNo);
+			Server* get_server();
+
+			int set_accesskey(const char *token);
+			int set_table_name(const char *tableName);
+			/*
+				Signed=1,   // Signed Integer
+				String=4,   // String, case insensitive, null ended
+				Binary=5,   // opaque binary data
+			*/
+			int set_key_type(int type);
+			void set_agenttime(int t);
+			voidset_timeout(int n);
+			std::string get_error_msg();
+
+		private:
+			int is_server_has_existed(ROUTE_NODE& ip);
+			int construct_servers();
+			int construct_servers2(std::vector<ROUTE_NODE>& IPList);
+			void disorder_list(int *tmpBuckets, int size);
+			int construct_balance_buckets();
+			int refresh_balance_buckets(uint64_t );			
+			void remove_server_from_buckets(uint64_t );
+			Server* get_one_server_from_buckets();
+			void set_error_msg(int err, std::string from, std::string msg);
+
+		private:
+			int m_time_out;
+			int m_agent_time; 
+			int m_key_type;
+			char* m_table_name;
+			std::string m_access_token;
+			std::string m_err_msg;
+
+		private:
+			bool m_set_route;	
+			bool m_constructed_by_set_i_ps;
+			int m_bid;
+			int m_idc_no;
+			int m_buckets_pos;
+			int m_balance_bucket_size;
+			uint64_t m_bid_version;
+			uint64_t m_last_get_ca_time;
+			uint64_t m_refresh_buckets_time;
+			uint64_t m_remove_buckets_time;
+			int* m_load_balance_buckets;
+			DTCQosServer* m_qos_severs;
+			std::vector<ROUTE_NODE> m_ip_list;
+	};
+
+	class Request {
+		private:
+			void *addr_;
+			long check;
+			Request(const Request &);
+		public:
+			friend class Server;
+			friend class Result;
+			friend class ServerPool;
+
+			Request(Server *srv, int op);
+			Request(void);
+			~Request(void);
+			void Reset(void);
+			void Reset(int);
+			int attach_server(Server *srv);
+
+			void set_admin_code(int code);
+			void set_hotbackup_id(long long);
+			void set_master_hotbackup_timestamp(long long);
+			void set_slave_hotbackup_timestamp(long long);
+
+#define _API_DEFINE_LONG_(op, t) int op(const char *n, t a) { return op(n, (long long)a); }
+#define _API_DEFINE_FLOAT_(op, t) int op(const char *n, t a) { return op(n, (double)a); }
+			int need(const char *);
+			int need(const char *, int);
+			int get_field_type(const char*);
+			void no_cache(void);
+			void no_next_server(void);
+			void limit(unsigned int, unsigned int);
+			int EQ(const char *, long long);
+			int NE(const char *, long long);
+			int LT(const char *, long long);
+			int LE(const char *, long long);
+			int GT(const char *, long long);
+			int GE(const char *, long long);
+			int EQ(const char *, const char *);
+			int NE(const char *, const char *);
+			int EQ(const char *, const char *, int);
+			int NE(const char *, const char *, int);
+
+			_API_DEFINE_LONG_(EQ, unsigned long long);
+			_API_DEFINE_LONG_(EQ, long);
+			_API_DEFINE_LONG_(EQ, unsigned long);
+			_API_DEFINE_LONG_(EQ, int);
+			_API_DEFINE_LONG_(EQ, unsigned int);
+			_API_DEFINE_LONG_(EQ, short);
+			_API_DEFINE_LONG_(EQ, unsigned short);
+			_API_DEFINE_LONG_(EQ, char);
+			_API_DEFINE_LONG_(EQ, unsigned char);
+
+			_API_DEFINE_LONG_(NE, unsigned long long);
+			_API_DEFINE_LONG_(NE, long);
+			_API_DEFINE_LONG_(NE, unsigned long);
+			_API_DEFINE_LONG_(NE, int);
+			_API_DEFINE_LONG_(NE, unsigned int);
+			_API_DEFINE_LONG_(NE, short);
+			_API_DEFINE_LONG_(NE, unsigned short);
+			_API_DEFINE_LONG_(NE, char);
+			_API_DEFINE_LONG_(NE, unsigned char);
+
+			_API_DEFINE_LONG_(GT, unsigned long long);
+			_API_DEFINE_LONG_(GT, long);
+			_API_DEFINE_LONG_(GT, unsigned long);
+			_API_DEFINE_LONG_(GT, int);
+			_API_DEFINE_LONG_(GT, unsigned int);
+			_API_DEFINE_LONG_(GT, short);
+			_API_DEFINE_LONG_(GT, unsigned short);
+			_API_DEFINE_LONG_(GT, char);
+			_API_DEFINE_LONG_(GT, unsigned char);
+
+			_API_DEFINE_LONG_(GE, unsigned long long);
+			_API_DEFINE_LONG_(GE, long);
+			_API_DEFINE_LONG_(GE, unsigned long);
+			_API_DEFINE_LONG_(GE, int);
+			_API_DEFINE_LONG_(GE, unsigned int);
+			_API_DEFINE_LONG_(GE, short);
+			_API_DEFINE_LONG_(GE, unsigned short);
+			_API_DEFINE_LONG_(GE, char);
+			_API_DEFINE_LONG_(GE, unsigned char);
+
+			_API_DEFINE_LONG_(LT, unsigned long long);
+			_API_DEFINE_LONG_(LT, long);
+			_API_DEFINE_LONG_(LT, unsigned long);
+			_API_DEFINE_LONG_(LT, int);
+			_API_DEFINE_LONG_(LT, unsigned int);
+			_API_DEFINE_LONG_(LT, short);
+			_API_DEFINE_LONG_(LT, unsigned short);
+			_API_DEFINE_LONG_(LT, char);
+			_API_DEFINE_LONG_(LT, unsigned char);
+
+			_API_DEFINE_LONG_(LE, unsigned long long);
+			_API_DEFINE_LONG_(LE, long);
+			_API_DEFINE_LONG_(LE, unsigned long);
+			_API_DEFINE_LONG_(LE, int);
+			_API_DEFINE_LONG_(LE, unsigned int);
+			_API_DEFINE_LONG_(LE, short);
+			_API_DEFINE_LONG_(LE, unsigned short);
+			_API_DEFINE_LONG_(LE, char);
+			_API_DEFINE_LONG_(LE, unsigned char);
+
+			int Set(const char *, long long);
+			int OR(const char *, long long);
+			int Add(const char *, long long);
+			int Sub(const char *, long long);
+			int Set(const char *, double);
+			int Add(const char *, double);
+			int Sub(const char *, double);
+			int Set(const char *, const char *);
+			int Set(const char *, const char *, int);
+
+            //just for compress,only support binary field
+			int compress_set(const char *, const char *, int);
+			//just compress and set. Don't need compressflag
+			int compress_set_force(const char *, const char *, int);
+
+			//bits op
+			int set_multi_bits(const char *, int, int, unsigned int);
+			int set_bit  (const char *f, int o) { return set_multi_bits(f, o, 1, 1);}
+			int clear_bit(const char *f, int o) { return set_multi_bits(f, o, 1, 0);}
+
+			_API_DEFINE_LONG_(Set, unsigned long long);
+			_API_DEFINE_LONG_(Set, long);
+			_API_DEFINE_LONG_(Set, unsigned long);
+			_API_DEFINE_LONG_(Set, int);
+			_API_DEFINE_LONG_(Set, unsigned int);
+			_API_DEFINE_LONG_(Set, short);
+			_API_DEFINE_LONG_(Set, unsigned short);
+			_API_DEFINE_LONG_(Set, char);
+			_API_DEFINE_LONG_(Set, unsigned char);
+			_API_DEFINE_FLOAT_(Set, float);
+			_API_DEFINE_FLOAT_(Set, long double);
+
+			_API_DEFINE_LONG_(OR, unsigned long long);
+			_API_DEFINE_LONG_(OR, long);
+			_API_DEFINE_LONG_(OR, unsigned long);
+			_API_DEFINE_LONG_(OR, int);
+			_API_DEFINE_LONG_(OR, unsigned int);
+			_API_DEFINE_LONG_(OR, short);
+			_API_DEFINE_LONG_(OR, unsigned short);
+
+			_API_DEFINE_LONG_(Add, unsigned long long);
+			_API_DEFINE_LONG_(Add, long);
+			_API_DEFINE_LONG_(Add, unsigned long);
+			_API_DEFINE_LONG_(Add, int);
+			_API_DEFINE_LONG_(Add, unsigned int);
+			_API_DEFINE_LONG_(Add, short);
+			_API_DEFINE_LONG_(Add, unsigned short);
+			_API_DEFINE_LONG_(Add, char);
+			_API_DEFINE_LONG_(Add, unsigned char);
+			_API_DEFINE_FLOAT_(Add, float);
+			_API_DEFINE_FLOAT_(Add, long double);
+
+			_API_DEFINE_LONG_(Sub, unsigned long long);
+			_API_DEFINE_LONG_(Sub, long);
+			_API_DEFINE_LONG_(Sub, unsigned long);
+			_API_DEFINE_LONG_(Sub, int);
+			_API_DEFINE_LONG_(Sub, unsigned int);
+			_API_DEFINE_LONG_(Sub, short);
+			_API_DEFINE_LONG_(Sub, unsigned short);
+			_API_DEFINE_LONG_(Sub, char);
+			_API_DEFINE_LONG_(Sub, unsigned char);
+			_API_DEFINE_FLOAT_(Sub, float);
+			_API_DEFINE_FLOAT_(Sub, long double);
+#undef _API_DEFINE_LONG_
+
+			void unset_key(void);
+			int set_key(long long);
+			int set_key(const char *);
+			int set_key(const char *, int);
+#define _API_DEFINE_LONG_(t) int set_key(t a) { return set_key((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int add_key_value(const char* name, long long v);
+			int add_key_value(const char* name, const char *str);
+			int add_key_value(const char* name, const char *ptr, int len);
+#define _API_DEFINE_LONG_(t) int add_key_value(const char* name, t a) { return add_key_value(name, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			Result *do_execute(void);
+			Result *do_execute(long long);
+			Result *do_execute(const char *);
+			Result *do_execute(const char *, int);
+
+#define _API_DEFINE_LONG_(t) Result *do_execute(t a) { return do_execute((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int do_execute(Result&);
+			int do_execute(Result&, long long);
+			int do_execute(Result&, const char *);
+			int do_execute(Result&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int do_execute(Result &r, t a) { return do_execute(r, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int encode_packet(char *&, int&, long long&);
+			int encode_packet(char *&, int&, long long&, long long);
+			int encode_packet(char *&, int&, long long&, const char *);
+			int encode_packet(char *&, int&, long long&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int encode_packet(char *&p, int &l, long long &m, t a) { return encode_packet(p,l,m,(long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int set_cache_id(long long);
+#define _API_DEFINE_LONG_(t) int set_cache_id(t a) {return set_cache_id((long long)a);}
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+            const char *get_error_message(void) const;
+
+            //无源模式超时时间   add by xuxinxin, 2014/12/09
+			int set_expire_time(const char* key, int time);
+			int get_expire_time(const char* key);
+	};
+
+	class GetRequest : public Request {
+		public:
+			GetRequest(Server *srv): Request(srv, kRequestGet) {}
+			GetRequest(): Request((Server *)0, kRequestGet) {}
+	};
+
+	class InsertRequest : public Request {
+		public:
+			InsertRequest(Server *srv) : Request(srv, kRequestInsert) {}
+			InsertRequest() : Request((Server *)0, kRequestInsert) {}
+	};
+
+	class DeleteRequest : public Request {
+		public:
+			DeleteRequest(Server *srv) : Request(srv, kRequestDelete) {}
+			DeleteRequest() : Request((Server *)0, kRequestDelete) {}
+	};
+
+	class UpdateRequest : public Request {
+		public:
+			UpdateRequest(Server *srv) : Request(srv, kRequestUpdate) {}
+			UpdateRequest() : Request((Server *)0, kRequestUpdate) {}
+	};
+
+	class PurgeRequest : public Request {
+		public:
+			PurgeRequest(Server *srv) : Request(srv, kRequestPurge) {}
+			PurgeRequest() : Request((Server *)0, kRequestPurge) {}
+	};
+
+	class ReplaceRequest:public Request {
+		public:
+			ReplaceRequest(Server *srv) : Request(srv, kRequestReplace) {}
+			ReplaceRequest() : Request((Server *)0, kRequestReplace) {}
+	};
+
+	class FlushRequest : public Request {
+		public:
+			FlushRequest(Server *srv) : Request(srv, kRequestFlush) {}
+			FlushRequest(void) : Request((Server *)0, kRequestFlush) {}
+	};
+
+	class InvalidateRequest: public Request {
+		public:
+			InvalidateRequest(Server *srv) : Request(srv, kRequestInvalidate) {}
+	};
+
+	class SvrAdminRequest: public Request {
+		public:
+			SvrAdminRequest(Server *srv) : Request(srv, kRequestSvrAdmin) {}
+	};
+
+	class MonitorRequest: public Request {
+		public:
+			MonitorRequest(Server *srv) : Request(srv, kRequestMonitor){}
+	};
+
+	class Result {
+		private:
+			void *addr_;
+			long check;
+			Result(const Result &);
+			char *ServerInfo() const;
+		public:
+			friend class Server;
+			friend class Request;
+			friend class ServerPool;
+
+			Result(void);
+			~Result(void);
+			void Reset(void);
+
+			void set_error(int errcode, const char *from, const char *detail); // from will not dupped
+			int get_result_code(void) const;
+			const char *get_error_message(void) const;
+			const char *get_error_from(void) const;
+			long long get_hotbackup_id() const;
+			long long get_master_hotbackup_timestamp() const;
+			long long slave_hotbackup_timestamp() const;
+			long long get_binlog_id() const;
+			long long get_binlog_offset() const;
+			long long get_mem_size() const;
+			long long get_datd_size() const;
+			int get_num_row_size(void) const;
+			int get_total_rows_size(void) const;
+			int get_affected_rows_size(void) const;
+			int get_num_fields_size(void) const;
+			const char* get_field_name(int n) const;
+			int get_field_present(const char* name) const;
+			int get_field_type(int n) const;
+			long long get_tag(void) const;
+			void *get_tag_ptr(void) const;
+			long long magic(void) const;
+			long long get_server_timestamp(void) const;
+			long long get_insert_id(void) const;
+			long long int_key(void) const;
+			const char *binary_key(void) const;
+			const char *binary_key(int *) const;
+			const char *binary_key(int &) const;
+			const char *string_key(void) const;
+			const char *string_key(int *) const;
+			const char *string_key(int &) const;
+			long long int_value(const char *) const;
+			double float_value(const char *) const;
+			const char *string_value(const char *) const;
+			const char *string_value(const char *, int*) const;
+			const char *string_value(const char *, int&) const;
+			const char *binary_value(const char *) const;
+			const char *binary_value(const char *, int*) const;
+			const char *binary_value(const char *, int&) const;
+			int uncompress_binary_value(const char *name,char **buf,int *lenp);
+			//Uncompress Binary Value without check compressflag
+			int uncompress_binary_value_force(const char *name,char **buf,int *lenp);
+            const char * uncompress_error_message() const;
+			long long int_value(int) const;
+			double float_value(int) const;
+			const char *string_value(int) const;
+			const char *string_value(int, int*) const;
+			const char *string_value(int, int&) const;
+			const char *binary_value(int) const;
+			const char *binary_value(int, int*) const;
+			const char *binary_value(int, int&) const;
+			int fetch_row(void);
+			int rewind(void);
+	};
+
+	class ServerPool {
+		private:
+			void *addr_;
+			long check;
+			ServerPool(ServerPool &);
+		public:
+			friend class Server;
+			friend class Request;
+			friend class Result;
+
+			ServerPool(int max_servers, int max_requests);
+			~ServerPool(void);
+
+			int get_epoll_fd(int size);
+			int add_server(Server *srv, int mReq=1, int mConn=0);
+			int add_request(Request *, long long);
+			int add_request(Request *, long long, long long);
+			int add_request(Request *, long long, const char *);
+			int add_request(Request *, long long, const char *, int);
+			int add_request(Request *, void *);
+			int add_request(Request *, void *, long long);
+			int add_request(Request *, void *, const char *);
+			int add_request(Request *, void *, const char *, int);
+			int do_execute(int msec);
+			int execute_all(int msec);
+			int cancel_request(int);
+			int cancel_all_request(int type);
+			int abort_request(int);
+			int abort_all_request(int type);
+			Result *get_result(void);
+			Result *get_result(int);
+			int get_result(Result&);
+			int get_result(Result&, int);
+
+			int server_count(void) const;
+			int request_count(int type) const;
+			int request_state(int reqId) const;
+	};
+
+	const int WAIT = 1;
+	const int SEND = 2;
+	const int RECV = 4;
+	const int DONE = 8;
+	const int ALL_STATE = WAIT|SEND|RECV|DONE;
+
+	enum {
+		EC_ERROR_BASE = 2000,
+		EC_BAD_COMMAND,		// unsupported command
+		EC_MISSING_SECTION,	// missing mandatory section
+		EC_EXTRA_SECTION,	// incompatible section present
+		EC_DUPLICATE_TAG,	// same tag appear twice
+
+		EC_DUPLICATE_FIELD,	//5: same field appear twice in .need()
+		EC_BAD_SECTION_LENGTH,	// section length too short
+		EC_BAD_VALUE_LENGTH,	// value length not allow
+		EC_BAD_STRING_VALUE,	// string value w/o NULL
+		EC_BAD_FLOAT_VALUE,	// invalid float format
+
+		EC_BAD_FIELD_NUM,	//10: invalid total field#
+		EC_EXTRA_SECTION_DATA,	// section length too large
+		EC_BAD_VALUE_TYPE,	// incompatible value type
+		EC_BAD_OPERATOR,	// incompatible operator/comparison
+		EC_BAD_FIELD_ID,	// invalid field ID
+
+		EC_BAD_FIELD_NAME,	//15: invalud field name
+		EC_BAD_FIELD_TYPE,	// invalid field type
+		EC_BAD_FIELD_SIZE,	// invalid field size
+		EC_TABLE_REDEFINED,	// table defined twice
+		EC_TABLE_MISMATCH,	// request table != server table
+
+		EC_VERSION_MISMATCH,	//20: unsupported protocol version
+		EC_CHECKSUM_MISMATCH,	// table hash not equal
+		EC_NO_MORE_DATA,	// End of Result
+		EC_NEED_FULL_FIELDSET,	// only full field set accepted by helper
+		EC_BAD_KEY_TYPE,	// key type incompatible
+
+		EC_BAD_KEY_SIZE,	// 25: key size incompatible
+		EC_SERVER_BUSY,		//server error
+		EC_BAD_SOCKET,		// network failed
+		EC_NOT_INITIALIZED,	// object didn't initialized
+		EC_BAD_HOST_STRING,
+
+		EC_BAD_TABLE_NAME,	// 30
+		EC_TASK_NEED_DELETE,
+		EC_KEY_NEEDED,
+		EC_SERVER_ERROR,
+		EC_UPSTREAM_ERROR,
+
+		EC_KEY_OVERFLOW,	// 35
+		EC_BAD_MULTIKEY,
+		EC_READONLY_FIELD,
+		EC_BAD_ASYNC_CMD,
+		EC_OUT_OF_KEY_RANGE,
+
+		EC_REQUEST_ABORTED,     // 40
+		EC_PARALLEL_MODE,
+		EC_KEY_NOTEXIST,
+		EC_SERVER_READONLY,
+		EC_BAD_INVALID_FIELD,
+
+		EC_DUPLICATE_KEY,    	// 45
+		EC_TOO_MANY_KEY_VALUE,
+		EC_BAD_KEY_NAME,
+		EC_BAD_RAW_DATA,
+		EC_BAD_HOTBACKUP_JID,
+
+		EC_FULL_SYNC_COMPLETE,  //50
+		EC_FULL_SYNC_STAGE,
+		EC_INC_SYNC_STAGE,
+        EC_ERR_SYNC_STAGE,
+        EC_NOT_ALLOWED_INSERT,
+
+        EC_COMPRESS_ERROR,  //55
+        EC_UNCOMPRESS_ERROR,
+        EC_TASKPOOL,
+        EC_STATE_ERROR,
+        EC_DATA_NEEDED,
+
+    	EC_TASK_TIMEOUT,
+
+        EC_BUSINESS_WITHOUT_EXPIRETIME, //62
+        EC_EMPTY_TBDEF, //63
+    	EC_INVALID_KEY_VALUE, //64
+    	EC_INVALID_EXPIRETIME, //65
+
+    	EC_GET_EXPIRETIME_END_OF_RESULT, //66
+	};
+
+	enum {
+		ER_HASHCHK=1000,
+		ER_NISAMCHK=1001,
+		ER_NO=1002,
+		ER_YES=1003,
+		ER_CANT_CREATE_FILE=1004,
+		ER_CANT_CREATE_TABLE=1005,
+		ER_CANT_CREATE_DB=1006,
+		ER_DB_CREATE_EXISTS=1007,
+		ER_DB_DROP_EXISTS=1008,
+		ER_DB_DROP_DELETE=1009,
+		ER_DB_DROP_RMDIR=1010,
+		ER_CANT_DELETE_FILE=1011,
+		ER_CANT_FIND_SYSTEM_REC=1012,
+		ER_CANT_GET_STAT=1013,
+		ER_CANT_GET_WD=1014,
+		ER_CANT_LOCK=1015,
+		ER_CANT_OPEN_FILE=1016,
+		ER_FILE_NOT_FOUND=1017,
+		ER_CANT_READ_DIR=1018,
+		ER_CANT_SET_WD=1019,
+		ER_CHECKREAD=1020,
+		ER_DISK_FULL=1021,
+		ER_DUP_KEY=1022,
+		ER_ERROR_ON_CLOSE=1023,
+		ER_ERROR_ON_READ=1024,
+		ER_ERROR_ON_RENAME=1025,
+		ER_ERROR_ON_WRITE=1026,
+		ER_FILE_USED=1027,
+		ER_FILSORT_ABORT=1028,
+		ER_FORM_NOT_FOUND=1029,
+		ER_GET_ERRNO=1030,
+		ER_ILLEGAL_HA=1031,
+		ER_KEY_NOT_FOUND=1032,
+		ER_NOT_FORM_FILE=1033,
+		ER_NOT_KEYFILE=1034,
+		ER_OLD_KEYFILE=1035,
+		ER_OPEN_AS_READONLY=1036,
+		ER_OUTOFMEMORY=1037,
+		ER_OUT_OF_SORTMEMORY=1038,
+		ER_UNEXPECTED_EOF=1039,
+		ER_CON_COUNT_ERROR=1040,
+		ER_OUT_OF_RESOURCES=1041,
+		ER_BAD_HOST_ERROR=1042,
+		ER_HANDSHAKE_ERROR=1043,
+		ER_DBACCESS_DENIED_ERROR=1044,
+		ER_ACCESS_DENIED_ERROR=1045,
+		ER_NO_DB_ERROR=1046,
+		ER_UNKNOWN_COM_ERROR=1047,
+		ER_BAD_NULL_ERROR=1048,
+		ER_BAD_DB_ERROR=1049,
+		ER_TABLE_EXISTS_ERROR=1050,
+		ER_BAD_TABLE_ERROR=1051,
+		ER_NON_UNIQ_ERROR=1052,
+		ER_SERVER_SHUTDOWN=1053,
+		ER_BAD_FIELD_ERROR=1054,
+		ER_WRONG_FIELD_WITH_GROUP=1055,
+		ER_WRONG_GROUP_FIELD=1056,
+		ER_WRONG_SUM_SELECT=1057,
+		ER_WRONG_VALUE_COUNT=1058,
+		ER_TOO_LONG_IDENT=1059,
+		ER_DUP_FIELDNAME=1060,
+		ER_DUP_KEYNAME=1061,
+		ER_DUP_ENTRY=1062,
+		ER_WRONG_FIELD_SPEC=1063,
+		ER_PARSE_ERROR=1064,
+		ER_EMPTY_QUERY=1065,
+		ER_NONUNIQ_TABLE=1066,
+		ER_INVALID_DEFAULT=1067,
+		ER_MULTIPLE_PRI_KEY=1068,
+		ER_TOO_MANY_KEYS=1069,
+		ER_TOO_MANY_KEY_PARTS=1070,
+		ER_TOO_LONG_KEY=1071,
+		ER_KEY_COLUMN_DOES_NOT_EXITS=1072,
+		ER_BLOB_USED_AS_KEY=1073,
+		ER_TOO_BIG_FIELDLENGTH=1074,
+		ER_WRONG_AUTO_KEY=1075,
+		ER_READY=1076,
+		ER_NORMAL_SHUTDOWN=1077,
+		ER_GOT_SIGNAL=1078,
+		ER_SHUTDOWN_COMPLETE=1079,
+		ER_FORCING_CLOSE=1080,
+		ER_IPSOCK_ERROR=1081,
+		ER_NO_SUCH_INDEX=1082,
+		ER_WRONG_FIELD_TERMINATORS=1083,
+		ER_BLOBS_AND_NO_TERMINATED=1084,
+		ER_TEXTFILE_NOT_READABLE=1085,
+		ER_FILE_EXISTS_ERROR=1086,
+		ER_LOAD_INFO=1087,
+		ER_ALTER_INFO=1088,
+		ER_WRONG_SUB_KEY=1089,
+		ER_CANT_REMOVE_ALL_FIELDS=1090,
+		ER_CANT_DROP_FIELD_OR_KEY=1091,
+		ER_INSERT_INFO=1092,
+		ER_INSERT_TABLE_USED=1093,
+		ER_NO_SUCH_THREAD=1094,
+		ER_KILL_DENIED_ERROR=1095,
+		ER_NO_TABLES_USED=1096,
+		ER_TOO_BIG_SET=1097,
+		ER_NO_UNIQUE_LOGFILE=1098,
+		ER_TABLE_NOT_LOCKED_FOR_WRITE=1099,
+		ER_TABLE_NOT_LOCKED=1100,
+		ER_BLOB_CANT_HAVE_DEFAULT=1101,
+		ER_WRONG_DB_NAME=1102,
+		ER_WRONG_TABLE_NAME=1103,
+		ER_TOO_BIG_SELECT=1104,
+		ER_UNKNOWN_ERROR=1105,
+		ER_UNKNOWN_PROCEDURE=1106,
+		ER_WRONG_PARAMCOUNT_TO_PROCEDURE=1107,
+		ER_WRONG_PARAMETERS_TO_PROCEDURE=1108,
+		ER_UNKNOWN_TABLE=1109,
+		ER_FIELD_SPECIFIED_TWICE=1110,
+		ER_INVALID_GROUP_FUNC_USE=1111,
+		ER_UNSUPPORTED_EXTENSION=1112,
+		ER_TABLE_MUST_HAVE_COLUMNS=1113,
+		ER_RECORD_FILE_FULL=1114,
+		ER_UNKNOWN_CHARACTER_SET=1115,
+		ER_TOO_MANY_TABLES=1116,
+		ER_TOO_MANY_FIELDS=1117,
+		ER_TOO_BIG_ROWSIZE=1118,
+		ER_STACK_OVERRUN=1119,
+		ER_WRONG_OUTER_JOIN=1120,
+		ER_NULL_COLUMN_IN_INDEX=1121,
+		ER_CANT_FIND_UDF=1122,
+		ER_CANT_INITIALIZE_UDF=1123,
+		ER_UDF_NO_PATHS=1124,
+		ER_UDF_EXISTS=1125,
+		ER_CANT_OPEN_LIBRARY=1126,
+		ER_CANT_FIND_DL_ENTRY=1127,
+		ER_FUNCTION_NOT_DEFINED=1128,
+		ER_HOST_IS_BLOCKED=1129,
+		ER_HOST_NOT_PRIVILEGED=1130,
+		ER_PASSWORD_ANONYMOUS_USER=1131,
+		ER_PASSWORD_NOT_ALLOWED=1132,
+		ER_PASSWORD_NO_MATCH=1133,
+		ER_UPDATE_INFO=1134,
+		ER_CANT_CREATE_THREAD=1135,
+		ER_WRONG_VALUE_COUNT_ON_ROW=1136,
+		ER_CANT_REOPEN_TABLE=1137,
+		ER_INVALID_USE_OF_NULL=1138,
+		ER_REGEXP_ERROR=1139,
+		ER_MIX_OF_GROUP_FUNC_AND_FIELDS=1140,
+		ER_NONEXISTING_GRANT=1141,
+		ER_TABLEACCESS_DENIED_ERROR=1142,
+		ER_COLUMNACCESS_DENIED_ERROR=1143,
+		ER_ILLEGAL_GRANT_FOR_TABLE=1144,
+		ER_GRANT_WRONG_HOST_OR_USER=1145,
+		ER_NO_SUCH_TABLE=1146,
+		ER_NONEXISTING_TABLE_GRANT=1147,
+		ER_NOT_ALLOWED_COMMAND=1148,
+		ER_SYNTAX_ERROR=1149,
+		ER_DELAYED_CANT_CHANGE_LOCK=1150,
+		ER_TOO_MANY_DELAYED_THREADS=1151,
+		ER_ABORTING_CONNECTION=1152,
+		ER_NET_PACKET_TOO_LARGE=1153,
+		ER_NET_READ_ERROR_FROM_PIPE=1154,
+		ER_NET_FCNTL_ERROR=1155,
+		ER_NET_PACKETS_OUT_OF_ORDER=1156,
+		ER_NET_UNCOMPRESS_ERROR=1157,
+		ER_NET_READ_ERROR=1158,
+		ER_NET_READ_INTERRUPTED=1159,
+		ER_NET_ERROR_ON_WRITE=1160,
+		ER_NET_WRITE_INTERRUPTED=1161,
+		ER_TOO_LONG_STRING=1162,
+		ER_TABLE_CANT_HANDLE_BLOB=1163,
+		ER_TABLE_CANT_HANDLE_AUTO_INCREMENT=1164,
+		ER_DELAYED_INSERT_TABLE_LOCKED=1165,
+		ER_WRONG_COLUMN_NAME=1166,
+		ER_WRONG_KEY_COLUMN=1167,
+		ER_WRONG_MRG_TABLE=1168,
+		ER_DUP_UNIQUE=1169,
+		ER_BLOB_KEY_WITHOUT_LENGTH=1170,
+		ER_PRIMARY_CANT_HAVE_NULL=1171,
+		ER_TOO_MANY_ROWS=1172,
+		ER_REQUIRES_PRIMARY_KEY=1173,
+		ER_NO_RAID_COMPILED=1174,
+		ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE=1175,
+		ER_KEY_DOES_NOT_EXITS=1176,
+		ER_CHECK_NO_SUCH_TABLE=1177,
+		ER_CHECK_NOT_IMPLEMENTED=1178,
+		ER_CANT_DO_THIS_DURING_AN_TRANSACTION=1179,
+		ER_ERROR_DURING_COMMIT=1180,
+		ER_ERROR_DURING_ROLLBACK=1181,
+		ER_ERROR_DURING_FLUSH_LOGS=1182,
+		ER_ERROR_DURING_CHECKPOINT=1183,
+		ER_NEW_ABORTING_CONNECTION=1184,
+		ER_DUMP_NOT_IMPLEMENTED=   1185,
+		ER_FLUSH_MASTER_BINLOG_CLOSED=1186,
+		ER_INDEX_REBUILD= 1187,
+		ER_MASTER=1188,
+		ER_MASTER_NET_READ=1189,
+		ER_MASTER_NET_WRITE=1190,
+		ER_FT_MATCHING_KEY_NOT_FOUND=1191,
+		ER_LOCK_OR_ACTIVE_TRANSACTION=1192,
+		ER_UNKNOWN_SYSTEM_VARIABLE=1193,
+		ER_CRASHED_ON_USAGE=1194,
+		ER_CRASHED_ON_REPAIR=1195,
+		ER_WARNING_NOT_COMPLETE_ROLLBACK=1196,
+		ER_TRANS_CACHE_FULL=1197,
+		ER_SLAVE_MUST_STOP=1198,
+		ER_SLAVE_NOT_RUNNING=1199,
+		ER_BAD_SLAVE=1200,
+		ER_MASTER_INFO=1201,
+		ER_SLAVE_THREAD=1202,
+		ER_TOO_MANY_USER_CONNECTIONS=1203,
+		ER_SET_CONSTANTS_ONLY=1204,
+		ER_LOCK_WAIT_TIMEOUT=1205,
+		ER_LOCK_TABLE_FULL=1206,
+		ER_READ_ONLY_TRANSACTION=1207,
+		ER_DROP_DB_WITH_READ_LOCK=1208,
+		ER_CREATE_DB_WITH_READ_LOCK=1209,
+		ER_WRONG_ARGUMENTS=1210,
+		ER_NO_PERMISSION_TO_CREATE_USER=1211,
+		ER_UNION_TABLES_IN_DIFFERENT_DIR=1212,
+		ER_LOCK_DEADLOCK=1213,
+		ER_TABLE_CANT_HANDLE_FULLTEXT=1214,
+		ER_CANNOT_ADD_FOREIGN=1215,
+		ER_NO_REFERENCED_ROW=1216,
+		ER_ROW_IS_REFERENCED=1217,
+		ER_CONNECT_TO_MASTER=1218,
+		ER_QUERY_ON_MASTER=1219,
+		ER_ERROR_WHEN_EXECUTING_COMMAND=1220,
+		ER_WRONG_USAGE=1221,
+		ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT=1222,
+		ER_CANT_UPDATE_WITH_READLOCK=1223,
+		ER_MIXING_NOT_ALLOWED=1224,
+		ER_DUP_ARGUMENT=1225,
+		ER_USER_LIMIT_REACHED=1226,
+		ER_SPECIFIC_ACCESS_DENIED_ERROR=1227,
+		ER_LOCAL_VARIABLE=1228,
+		ER_GLOBAL_VARIABLE=1229,
+		ER_NO_DEFAULT=1230,
+		ER_WRONG_VALUE_FOR_VAR=1231,
+		ER_WRONG_TYPE_FOR_VAR=1232,
+		ER_VAR_CANT_BE_READ=1233,
+		ER_CANT_USE_OPTION_HERE=1234,
+		ER_NOT_SUPPORTED_YET=1235,
+		ER_MASTER_FATAL_ERROR_READING_BINLOG=1236,
+		ER_SLAVE_IGNORED_TABLE=1237,
+		ER_INCORRECT_GLOBAL_LOCAL_VAR=1238,
+		CR_UNKNOWN_ERROR=1900,
+		CR_SOCKET_CREATE_ERROR=1901,
+		CR_CONNECTION_ERROR=1902,
+		CR_CONN_HOST_ERROR=1903,
+		CR_IPSOCK_ERROR	=1904,
+		CR_UNKNOWN_HOST	=1905,
+		CR_SERVER_GONE_ERROR=1906,
+		CR_VERSION_ERROR=1907,
+		CR_OUT_OF_MEMORY=1908,
+		CR_WRONG_HOST_INFO=1909,
+		CR_LOCALHOST_CONNECTION=1910,
+		CR_TCP_CONNECTION=1911,
+		CR_SERVER_HANDSHAKE_ERR=1912,
+		CR_SERVER_LOST=1913,
+		CR_COMMANDS_OUT_OF_SYNC=1914,
+		CR_NAMEDPIPE_CONNECTION=1915,
+		CR_NAMEDPIPEWAIT_ERROR=1916,
+		CR_NAMEDPIPEOPEN_ERROR=1917,
+		CR_NAMEDPIPESETSTATE_ERROR=1918,
+		CR_CANT_READ_CHARSET=1919,
+		CR_NET_PACKET_TOO_LARGE=1920,
+		CR_EMBEDDED_CONNECTION=1921,
+		CR_PROBE_SLAVE_STATUS=1922,
+		CR_PROBE_SLAVE_HOSTS=1923,
+		CR_PROBE_SLAVE_CONNECT=1924,
+		CR_PROBE_MASTER_CONNECT=1925,
+		CR_SSL_CONNECTION_ERROR=1926,
+		CR_MALFORMED_PACKET=1927,
+		CR_WRONG_LICENSE=1928,
+	};
+
+	enum{
+		ER_SET_IPLIST_NULL = 20001,
+		ER_SET_INSTANCE_PROPERTIES_ERR,
+		ER_KEY_TYPE,
+		ER_CC_VERSION_ERR,
+		ER_ROUTE_INFO_NULL,
+		ER_BID_VERSION_ERR,
+		ER_PORT_OUT_RANGE,
+		ER_STATUS_ERROR_VALUE,
+		ER_WEIGHT_ERROR_VALUE,
+		ER_IP_ERROR_VALUE,
+	};
+
+};
+
+#endif

+ 163 - 0
src/devel/cpp/examples/insert/inserttest.cpp

@@ -0,0 +1,163 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string>
+#include<stdint.h>
+#include<unistd.h>
+
+#include "dtcapi.h"
+
+int main(int argc,char* argv[])
+{
+	int retCode = 0;
+	unsigned int uid;
+	unsigned int age;
+	unsigned int lv = 0;
+	std::string name;
+	std::string city;
+	std::string descr;
+	unsigned int salary;
+
+	unsigned int uid1;
+	unsigned int age1;
+	std::string name1;
+	std::string city1;
+	std::string descr1;
+	unsigned int salary1;
+
+	lv = atoi(argv[1]);
+
+	DTC::Server stServer; // 只要server不析构,后台会保持长连接
+	stServer.int_key(); // 声明key类型
+	stServer.set_table_name("t_dtc_example");//设置dtc的表名,与table.conf中tablename应该一样
+	stServer.set_address("192.168.214.62", "10901");//设置的dtc的ip和端口
+	stServer.SetTimeout(5); // 设置网络超时时间
+	stServer.set_accesskey("0000090184d9cfc2f395ce883a41d7ffc1bbcf4e"); // 设置访问码 AccessToken,在申请dtc实例的时候网站端会生成
+
+	DTC::InsertRequest insertReq(&stServer);
+	//retCode = insertReq.set_key(key);
+
+	uid = atoi(argv[2]);
+	name = std::string(argv[3]);
+	city = std::string(argv[4]);
+	descr = std::string(argv[5]);
+	age = atoi(argv[6]);
+	salary = atoi(argv[7]);
+
+	insertReq.set_key(uid);
+	//insertReq.Set("key", 100003);
+	insertReq.Set("uid", uid);
+	insertReq.Set("name", name.c_str());
+	insertReq.Set("city", city.c_str());
+	insertReq.Set("descr", descr.c_str());
+	insertReq.Set("age", age);
+	insertReq.Set("salary", salary);
+
+	DTC::Result stResult;
+	retCode = insertReq.do_execute(stResult);
+	printf("retCode:%d, errmsg:%s, errfrom:%s\n", retCode, stResult.get_error_message(), stResult.get_error_from());
+	if(retCode == 0)
+	{
+		DTC::GetRequest getReq(&stServer);
+		getReq.set_key(uid);
+		if(retCode == 0)
+			retCode = getReq.need("uid");//设置需要select的字段,注意第一个key字段不能在这里出现
+		if(retCode == 0)
+			retCode = getReq.need("name");
+		if(retCode == 0)
+			retCode = getReq.need("city");
+		if(retCode == 0)
+			retCode = getReq.need("descr");
+		if(retCode == 0)
+			retCode = getReq.need("age");
+		if(retCode == 0)
+			retCode = getReq.need("salary");
+		if(retCode != 0)
+		{
+			printf("get-req set key or need error: %d", retCode);
+			fflush(stdout);
+			return(-1);
+		}
+
+		// do_execute & get result
+		stResult.Reset();
+		retCode = getReq.do_execute(stResult);
+		printf("retCode:%d, errmsg:%s, errfrom:%s\n", retCode, stResult.get_error_message(), stResult.get_error_from());
+		retCode = stResult.fetch_row();//开始获取数据
+		printf("uid:%lu\n", stResult.int_value("uid"));
+	    printf("name: %s\n", stResult.string_value("name"));//输出binary类型的数据
+		printf("city: %s\n", stResult.string_value("city"));
+		printf("descr: %s\n", stResult.binary_value("descr"));
+	    printf("age: %lu\n", stResult.int_value("age"));//输出int类型的数据
+	    printf("salary: %lu\n", stResult.int_value("salary"));//输出int类型的数据
+	}
+
+	printf("-------------first request end -----------------\n");
+	printf("-------------second request begin---------------\n");
+
+	DTC::Server stServer1; // 只要server不析构,后台会保持长连接
+	stServer1.int_key(); // 声明key类型
+	stServer1.set_table_name("tp1");//设置dtc的表名,与table.conf中tablename应该一样
+	stServer1.set_address("192.168.214.62", "10201");//设置的dtc的ip和端口
+	stServer1.SetTimeout(5); // 设置网络超时时间
+	stServer1.set_accesskey("0000020184d9cfc2f395ce883a41d7ffc1bbcf4e"); // 设置访问码 AccessToken,在申请dtc实例的时候网站端会生成
+
+	DTC::InsertRequest insertReq1(&stServer1);
+	//retCode = insertReq.set_key(key);
+
+	uid1 = atoi(argv[8]);
+	name1 = std::string(argv[9]);
+	city1 = std::string(argv[10]);
+	descr1 = std::string(argv[11]);
+	age1 = atoi(argv[12]);
+	salary1 = atoi(argv[13]);
+
+	insertReq1.set_key(uid1);
+	//insertReq.Set("key", 100003);
+	insertReq1.Set("uid", uid1);
+	insertReq1.Set("name", name1.c_str());
+	insertReq1.Set("city", city1.c_str());
+	insertReq1.Set("descr", descr1.c_str());
+	insertReq1.Set("age", age1);
+	insertReq1.Set("salary", salary1);
+
+	DTC::Result stResult1;
+	retCode = insertReq1.do_execute(stResult1);
+	printf("retCode:%d, errmsg:%s, errfrom:%s\n", retCode, stResult1.get_error_message(), stResult1.get_error_from());
+	if(retCode == 0)
+	{
+		DTC::GetRequest getReq1(&stServer1);
+		getReq1.set_key(uid);
+		if(retCode == 0)
+			retCode = getReq1.need("uid");//设置需要select的字段,注意第一个key字段不能在这里出现
+		if(retCode == 0)
+			retCode = getReq1.need("name");
+		if(retCode == 0)
+			retCode = getReq1.need("city");
+		if(retCode == 0)
+			retCode = getReq1.need("descr");
+		if(retCode == 0)
+			retCode = getReq1.need("age");
+		if(retCode == 0)
+			retCode = getReq1.need("salary");
+		if(retCode != 0)
+		{
+			printf("get-req set key or need error: %d", retCode);
+			fflush(stdout);
+			return(-1);
+		}
+
+		// do_execute & get result
+		stResult1.Reset();
+		retCode = getReq1.do_execute(stResult1);
+		printf("retCode:%d, errmsg:%s, errfrom:%s\n", retCode, stResult1.get_error_message(), stResult1.get_error_from());
+		retCode = stResult1.fetch_row();//开始获取数据
+		printf("uid:%lu\n", stResult1.int_value("uid"));
+	    printf("name: %s\n", stResult1.string_value("name"));//输出binary类型的数据
+		printf("city: %s\n", stResult1.string_value("city"));
+		printf("descr: %s\n", stResult1.binary_value("descr"));
+	    printf("age: %lu\n", stResult1.int_value("age"));//输出int类型的数据
+	    printf("salary: %lu\n", stResult1.int_value("salary"));//输出int类型的数据
+	}
+
+	return 0;  
+}  

+ 47 - 0
src/devel/cpp/examples/select/Makefile

@@ -0,0 +1,47 @@
+LIB = ../../libdtc.so
+
+OUTPUT1 = selecttest
+
+SOURCES =  selecttest.cpp 
+								   		
+OUTPUT2 = TestServerPool
+
+SOURCES = TestServerPool.cpp
+
+OBJECTS1= selecttest.o
+	CPPFLAGS = -g -O -Wall -fPIC -DMACROFOR64BIT -Wl,--no-undefined -Xlinker -zmuldefs
+	CFLAGS = $(CPPFLAGS)
+
+OBJECTS2=TestServerPool.o
+	CPPFLAGS = -g -O -Wall -fPIC -DMACROFOR64BIT -Wl,--no-undefined -Xlinker -zmuldefs
+	CFLAGS = $(CPPFLAGS)
+all:$(OUTPUT1) $(OUTPUT2) 
+
+.SUFFIXES: .o .cpp
+	.cpp.o:
+		$(CXX) $(CPPFLAGS) $(INCLUDE) -c $(filter %.cpp, $^) 
+
+.o:
+		$(CXX) $(CPPFLAGS) $(INCLUDE) -o $@ $^ 
+
+$(OUTPUT1): $(OBJECTS1)
+		$(CXX) $(CFLAGS) -fPIC  -o $@ $^ $(LIB)
+
+$(OUTPUT2): $(OBJECTS2)
+		$(CXX) $(CFLAGS) -fPIC  -o $@ $^ $(LIB)
+
+clean:
+		rm -f *.o *.so *.~ *.bak
+		rm -f $(OUTPUT1)
+		rm -f $(OUTPUT2)
+
+install:
+		cp -f $(OUTPUT) $(INSTALL_PATH)
+
+dep:
+		mkdep -p$(VPATH) $(INCLUDE) $(SOURCES) > .depend
+
+ifneq ($(wildcard .depend),)
+	include .depend
+endif
+

+ 118 - 0
src/devel/cpp/examples/select/TestServerPool.cpp

@@ -0,0 +1,118 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string>
+#include<stdint.h>
+#include<unistd.h>
+
+#include "dtcapi.h"
+
+using namespace DTC;
+
+int main(int argc,char* argv[])
+{
+	int ret = 0;
+	int uid = 0;
+	int age = 0;
+	int salary = 0;
+	std::string name;
+	std::string city;
+	std::string descr;
+
+	uid = atoi(argv[1]);
+	name = std::string(argv[2]);
+	city = std::string(argv[3]);
+	descr = std::string(argv[4]);
+	age = atoi(argv[5]);
+	salary = atoi(argv[6]);
+
+	ServerPool svp(5, 5);
+	Server sv1, sv2, sv3, sv4, sv5;
+
+	/* server-request-1 */
+	sv1.int_key();
+	sv1.set_table_name("tp1");
+	sv1.set_address("192.168.214.62", "10201");
+	sv1.set_accesskey("0000020184d9cfc2f395ce883a41d7ffc1bbcf4e");
+	sv1.SetTimeout(5);
+
+	InsertRequest req1(&sv1);
+	req1.set_key(uid);
+	//req1.Set("uid", 100001);
+	req1.Set("name", name.c_str());
+	req1.Set("city", city.c_str());
+	req1.Set("descr", descr.c_str());
+	req1.Set("age", age);
+	req1.Set("salary", salary);
+
+	/* server-request-2 */
+	sv2.int_key();
+	sv2.set_table_name("tp2");
+	sv2.set_address("192.168.214.62", "10202");
+	sv2.set_accesskey("0000020284d9cfc2f395ce883a41d7ffc1bbcf4e");
+	sv2.SetTimeout(5);
+
+	InsertRequest req2(&sv2);
+	req2.set_key(uid);
+	//req2.Set("uid", 100001);
+	req2.Set("name", name.c_str());
+	req2.Set("city", city.c_str());
+	req2.Set("descr", descr.c_str());
+	req2.Set("age", age);
+	req2.Set("salary", salary);
+	/* server-request-3 */
+	sv3.int_key();
+	sv3.set_table_name("tp3");
+	sv3.set_address("192.168.214.62", "10203");
+	sv3.set_accesskey("0000020384d9cfc2f395ce883a41d7ffc1bbcf4e");
+	sv3.SetTimeout(5);
+
+	InsertRequest req3(&sv3);
+	req3.set_key(uid);
+	//req2.Set("uid", 100001);
+	req3.Set("name", name.c_str());
+	req3.Set("city", city.c_str());
+	req3.Set("descr", descr.c_str());
+	req3.Set("age", age);
+	req3.Set("salary", salary);
+	/* server-request-4 */
+	sv4.int_key();
+	sv4.set_table_name("tp4");
+	sv4.set_address("192.168.214.62", "10204");
+	sv4.set_accesskey("0000020484d9cfc2f395ce883a41d7ffc1bbcf4e");
+	sv4.SetTimeout(5);
+
+	InsertRequest req4(&sv4);
+	req4.set_key(uid);
+	//req4.Set("uid", 100001);
+	req4.Set("name", name.c_str());
+	req4.Set("city", city.c_str());
+	req4.Set("descr", descr.c_str());
+	req4.Set("age", age);
+	req4.Set("salary", salary);
+	/* server-request-5 */
+	sv5.int_key();
+	sv5.set_table_name("tp5");
+	sv5.set_address("192.168.214.62", "10205");
+	sv5.set_accesskey("0000020584d9cfc2f395ce883a41d7ffc1bbcf4e");
+	sv5.SetTimeout(5);
+
+	InsertRequest req5(&sv5);
+	req5.set_key(uid);
+	//req5.Set("uid", 100001);
+	req5.Set("name", name.c_str());
+	req5.Set("city", city.c_str());
+	req5.Set("descr", descr.c_str());
+	req5.Set("age", age);
+	req5.Set("salary", salary);
+
+	svp.add_request(&req1, 1);
+	svp.add_request(&req2, 2);
+	svp.add_request(&req3, 3);
+	svp.add_request(&req4, 4);
+	svp.add_request(&req5, 5);
+
+	ret = svp.do_execute(120000);
+	printf("ret:%d\n", ret);
+
+	return 0;
+}

+ 1020 - 0
src/devel/cpp/examples/select/dtcapi.h

@@ -0,0 +1,1020 @@
+#ifndef __DTC_API_H__
+#define __DTC_API_H__
+
+#include <stdlib.h>
+#include <vector>
+#include <string>
+#include <stdint.h>
+
+#define IP_LENGHT 16
+
+namespace DTC {
+
+	typedef struct route_node
+	{
+		int bid;
+		int port;
+		int status;
+		int weight;
+		char ip[IP_LENGHT];
+	}ROUTE_NODE;
+
+	class Server;
+	class ServerPool;
+	class Request;
+	class Result;
+
+	const int kRequestSvrAdmin 	= 3;
+	const int kRequestGet 		= 4;
+	const int kRequestPurge 		= 5;
+	const int kRequestInsert 	= 6;
+	const int kRequestUpdate 	= 7;
+	const int kRequestDelete 	= 8;
+	const int kRequestReplace 	= 12;
+	const int kRequestFlush 		= 13;
+	const int kRequestInvalidate	= 14;
+
+	//mem monior Request;2014/06/6;by seanzheng
+	const int kRequestMonitor    = 15;
+
+	// sub-code of admin cmd
+	const int RegisterHB		= 1;
+	const int LogoutHB		= 2;
+	const int GetKeyList		= 3;
+	const int GetUpdateKey		= 4;
+	const int GetRawData		= 5;
+	const int ReplaceRawData	= 6;
+	const int AdjustLRU        	= 7;
+	const int VerifyHBT		= 8;
+	const int GetHBTime		= 9;
+	const int kSetReadOnly	= 10;
+	const int kSetReadWrite	= 11;
+	const int kQueryBinlogID		= 12;
+	const int kNodeHandleChange  = 13;
+	const int Migrate = 14;
+    const int kReloadClusterNodeList = 15;
+    const int kSetClusterNodeState  = 16;
+    const int kChangeNodeAddress  = 17;
+    const int kGetClusterState  = 18;
+    const int kPurgeForHit    = 19;
+	const int ClearCache = 21;
+	const int ColExpandStatus = 24;
+	const int kColExpand = 25;
+	const int ColExpandDone = 26;
+	const int ColExpandKey = 27;
+	
+	const int kKeyTypeNone		= 0;	// undefined
+	const int kKeyTypeInt		= 1;	// Signed Integer
+	const int kKeyTypeString		= 4;	// String, case insensitive, null ended
+
+	const int kFieldTypeNone		= 0;    // undefined
+	const int kFieldTypeSigned	= 1;	// Signed Integer
+	const int kFieldTypeUnsigned	= 2;	// Unsigned Integer
+	const int kFieldTypeFloat	= 3;	// float
+	const int kFieldTypeString	= 4;	// String, case insensitive, null ended
+	const int kFieldTypeBinary	= 5;	// binary
+
+
+	int  set_key_value_max(unsigned int count); // 设置批量操作一次最多多少个key(默认最多32个)
+#ifndef WIN32
+	void write_log (int level,
+			const char*file, const char *func, int lineno,
+			const char *fmt, ...)
+		__attribute__((format(printf,5,6)));
+#endif
+
+	class Result;
+	class Server {
+		private:
+			void *addr_;
+			long check;
+		public:
+			friend class Request;
+			friend class Result;
+			friend class ServerPool;
+			friend class QOSServerPool;
+
+			Server(void);
+			~Server(void);
+			Server(const Server &);
+			void clone_table_define(const Server& source);
+			int set_address(const char *host, const char *port=0);
+			int set_table_name(const char *);
+            //for compress
+            void set_compress_level(int);
+            //get address and tablename set by user
+			const char * get_address(void) const;
+			const char * get_table_name(void) const;
+            //get address and tablename set by dtc frame,for plugin only;
+			const char * get_server_address(void) const;
+			const char * get_server_table_name(void) const;
+			int int_key(void);
+			int binary_key(void);
+			int string_key(void);
+			int add_key(const char* name, int type);
+			int get_field_type(const char* name);
+			const char *get_error_message(void) const;
+			void SetTimeout(int);
+			void set_timeout(int);
+			int connect(void);
+			void close(void);
+			int ping(void);
+			void auto_ping(void);
+			void set_fd(int); // UNSUPPORTED API
+			void set_auto_Update_table(bool autoUpdate);
+			void set_auto_reconnect(int auto_reconnect);
+			int decode_packet(Result &, const char *, int);
+			int check_packet_size(const char *, int);
+
+			void set_accesskey(const char *token);
+
+		public:
+			void increase_error_count_();
+			uint64_t get_error_count();
+			void clear_error_count();
+			
+			void increase_remove_count();
+			int get_remove_count();
+			void clear_remove_count();
+
+			void increase_total_request();
+			uint64_t get_total_request();
+			void clear_total_request();
+
+			void add_total_elaps(uint64_t iElaps);
+			uint64_t get_total_elaps();
+			void clear_total_elaps();
+	};
+
+	class DTCQosServer;
+
+	class DTCServers
+	{
+		public:
+			DTCServers();
+			~DTCServers();
+
+		private:
+			DTCServers(const DTCServers&);
+			DTCServers& operator=(const DTCServers&);
+
+		public:
+			int set_route_list(std::vector<ROUTE_NODE>& ip_list);
+			void set_idc_no(int IDCNo);
+			Server* get_server();
+
+			int set_accesskey(const char *token);
+			int set_table_name(const char *tableName);
+			/*
+				Signed=1,   // Signed Integer
+				String=4,   // String, case insensitive, null ended
+				Binary=5,   // opaque binary data
+			*/
+			int set_key_type(int type);
+			void set_agenttime(int t);
+			void set_timeout(int n);
+			std::string get_error_msg();
+
+		private:
+			int is_server_has_existed(ROUTE_NODE& ip);
+			int construct_servers();
+			int construct_servers2(std::vector<ROUTE_NODE>& IPList);
+			void disorder_list(int *tmpBuckets, int size);
+			int construct_balance_buckets();
+			int refresh_balance_buckets(uint64_t );			
+			void remove_server_from_buckets(uint64_t );
+			Server* get_one_server_from_buckets();
+			void set_error_msg(int err, std::string from, std::string msg);
+
+		private:
+			int m_time_out;
+			int m_agent_time; 
+			int m_key_type;
+			char* m_table_name;
+			std::string m_access_token;
+			std::string m_err_msg;
+
+		private:
+			bool m_set_route;	
+			bool m_constructed_by_set_i_ps;
+			int m_bid;
+			int m_idc_no;
+			int m_buckets_pos;
+			int m_balance_bucket_size;
+			uint64_t m_bid_version;
+			uint64_t m_last_get_ca_time;
+			uint64_t m_refresh_buckets_time;
+			uint64_t m_remove_buckets_time;
+			int* m_load_balance_buckets;
+			DTCQosServer* m_qos_severs;
+			std::vector<ROUTE_NODE> m_ip_list;
+	};
+
+	class Request {
+		private:
+			void *addr_;
+			long check;
+			Request(const Request &);
+		public:
+			friend class Server;
+			friend class Result;
+			friend class ServerPool;
+
+			Request(Server *srv, int op);
+			Request(void);
+			~Request(void);
+			void Reset(void);
+			void Reset(int);
+			int attach_server(Server *srv);
+
+			void set_admin_code(int code);
+			void set_hotbackup_id(long long);
+			void set_master_hotbackup_timestamp(long long);
+			void set_slave_hotbackup_timestamp(long long);
+
+#define _API_DEFINE_LONG_(op, t) int op(const char *n, t a) { return op(n, (long long)a); }
+#define _API_DEFINE_FLOAT_(op, t) int op(const char *n, t a) { return op(n, (double)a); }
+			int need(const char *);
+			int need(const char *, int);
+			int get_field_type(const char*);
+			void no_cache(void);
+			void no_next_server(void);
+			void limit(unsigned int, unsigned int);
+			int EQ(const char *, long long);
+			int NE(const char *, long long);
+			int LT(const char *, long long);
+			int LE(const char *, long long);
+			int GT(const char *, long long);
+			int GE(const char *, long long);
+			int EQ(const char *, const char *);
+			int NE(const char *, const char *);
+			int EQ(const char *, const char *, int);
+			int NE(const char *, const char *, int);
+
+			_API_DEFINE_LONG_(EQ, unsigned long long);
+			_API_DEFINE_LONG_(EQ, long);
+			_API_DEFINE_LONG_(EQ, unsigned long);
+			_API_DEFINE_LONG_(EQ, int);
+			_API_DEFINE_LONG_(EQ, unsigned int);
+			_API_DEFINE_LONG_(EQ, short);
+			_API_DEFINE_LONG_(EQ, unsigned short);
+			_API_DEFINE_LONG_(EQ, char);
+			_API_DEFINE_LONG_(EQ, unsigned char);
+
+			_API_DEFINE_LONG_(NE, unsigned long long);
+			_API_DEFINE_LONG_(NE, long);
+			_API_DEFINE_LONG_(NE, unsigned long);
+			_API_DEFINE_LONG_(NE, int);
+			_API_DEFINE_LONG_(NE, unsigned int);
+			_API_DEFINE_LONG_(NE, short);
+			_API_DEFINE_LONG_(NE, unsigned short);
+			_API_DEFINE_LONG_(NE, char);
+			_API_DEFINE_LONG_(NE, unsigned char);
+
+			_API_DEFINE_LONG_(GT, unsigned long long);
+			_API_DEFINE_LONG_(GT, long);
+			_API_DEFINE_LONG_(GT, unsigned long);
+			_API_DEFINE_LONG_(GT, int);
+			_API_DEFINE_LONG_(GT, unsigned int);
+			_API_DEFINE_LONG_(GT, short);
+			_API_DEFINE_LONG_(GT, unsigned short);
+			_API_DEFINE_LONG_(GT, char);
+			_API_DEFINE_LONG_(GT, unsigned char);
+
+			_API_DEFINE_LONG_(GE, unsigned long long);
+			_API_DEFINE_LONG_(GE, long);
+			_API_DEFINE_LONG_(GE, unsigned long);
+			_API_DEFINE_LONG_(GE, int);
+			_API_DEFINE_LONG_(GE, unsigned int);
+			_API_DEFINE_LONG_(GE, short);
+			_API_DEFINE_LONG_(GE, unsigned short);
+			_API_DEFINE_LONG_(GE, char);
+			_API_DEFINE_LONG_(GE, unsigned char);
+
+			_API_DEFINE_LONG_(LT, unsigned long long);
+			_API_DEFINE_LONG_(LT, long);
+			_API_DEFINE_LONG_(LT, unsigned long);
+			_API_DEFINE_LONG_(LT, int);
+			_API_DEFINE_LONG_(LT, unsigned int);
+			_API_DEFINE_LONG_(LT, short);
+			_API_DEFINE_LONG_(LT, unsigned short);
+			_API_DEFINE_LONG_(LT, char);
+			_API_DEFINE_LONG_(LT, unsigned char);
+
+			_API_DEFINE_LONG_(LE, unsigned long long);
+			_API_DEFINE_LONG_(LE, long);
+			_API_DEFINE_LONG_(LE, unsigned long);
+			_API_DEFINE_LONG_(LE, int);
+			_API_DEFINE_LONG_(LE, unsigned int);
+			_API_DEFINE_LONG_(LE, short);
+			_API_DEFINE_LONG_(LE, unsigned short);
+			_API_DEFINE_LONG_(LE, char);
+			_API_DEFINE_LONG_(LE, unsigned char);
+
+			int Set(const char *, long long);
+			int OR(const char *, long long);
+			int Add(const char *, long long);
+			int Sub(const char *, long long);
+			int Set(const char *, double);
+			int Add(const char *, double);
+			int Sub(const char *, double);
+			int Set(const char *, const char *);
+			int Set(const char *, const char *, int);
+
+            //just for compress,only support binary field
+			int compress_set(const char *, const char *, int);
+			//just compress and set. Don't need compressflag
+			int compress_set_force(const char *, const char *, int);
+
+			//bits op
+			int set_multi_bits(const char *, int, int, unsigned int);
+			int set_bit  (const char *f, int o) { return set_multi_bits(f, o, 1, 1);}
+			int clear_bit(const char *f, int o) { return set_multi_bits(f, o, 1, 0);}
+
+			_API_DEFINE_LONG_(Set, unsigned long long);
+			_API_DEFINE_LONG_(Set, long);
+			_API_DEFINE_LONG_(Set, unsigned long);
+			_API_DEFINE_LONG_(Set, int);
+			_API_DEFINE_LONG_(Set, unsigned int);
+			_API_DEFINE_LONG_(Set, short);
+			_API_DEFINE_LONG_(Set, unsigned short);
+			_API_DEFINE_LONG_(Set, char);
+			_API_DEFINE_LONG_(Set, unsigned char);
+			_API_DEFINE_FLOAT_(Set, float);
+			_API_DEFINE_FLOAT_(Set, long double);
+
+			_API_DEFINE_LONG_(OR, unsigned long long);
+			_API_DEFINE_LONG_(OR, long);
+			_API_DEFINE_LONG_(OR, unsigned long);
+			_API_DEFINE_LONG_(OR, int);
+			_API_DEFINE_LONG_(OR, unsigned int);
+			_API_DEFINE_LONG_(OR, short);
+			_API_DEFINE_LONG_(OR, unsigned short);
+
+			_API_DEFINE_LONG_(Add, unsigned long long);
+			_API_DEFINE_LONG_(Add, long);
+			_API_DEFINE_LONG_(Add, unsigned long);
+			_API_DEFINE_LONG_(Add, int);
+			_API_DEFINE_LONG_(Add, unsigned int);
+			_API_DEFINE_LONG_(Add, short);
+			_API_DEFINE_LONG_(Add, unsigned short);
+			_API_DEFINE_LONG_(Add, char);
+			_API_DEFINE_LONG_(Add, unsigned char);
+			_API_DEFINE_FLOAT_(Add, float);
+			_API_DEFINE_FLOAT_(Add, long double);
+
+			_API_DEFINE_LONG_(Sub, unsigned long long);
+			_API_DEFINE_LONG_(Sub, long);
+			_API_DEFINE_LONG_(Sub, unsigned long);
+			_API_DEFINE_LONG_(Sub, int);
+			_API_DEFINE_LONG_(Sub, unsigned int);
+			_API_DEFINE_LONG_(Sub, short);
+			_API_DEFINE_LONG_(Sub, unsigned short);
+			_API_DEFINE_LONG_(Sub, char);
+			_API_DEFINE_LONG_(Sub, unsigned char);
+			_API_DEFINE_FLOAT_(Sub, float);
+			_API_DEFINE_FLOAT_(Sub, long double);
+#undef _API_DEFINE_LONG_
+
+			void unset_key(void);
+			int set_key(long long);
+			int set_key(const char *);
+			int set_key(const char *, int);
+#define _API_DEFINE_LONG_(t) int set_key(t a) { return set_key((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int add_key_value(const char* name, long long v);
+			int add_key_value(const char* name, const char *str);
+			int add_key_value(const char* name, const char *ptr, int len);
+#define _API_DEFINE_LONG_(t) int add_key_value(const char* name, t a) { return add_key_value(name, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			Result *do_execute(void);
+			Result *do_execute(long long);
+			Result *do_execute(const char *);
+			Result *do_execute(const char *, int);
+
+#define _API_DEFINE_LONG_(t) Result *do_execute(t a) { return do_execute((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int do_execute(Result&);
+			int do_execute(Result&, long long);
+			int do_execute(Result&, const char *);
+			int do_execute(Result&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int do_execute(Result &r, t a) { return do_execute(r, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int encode_packet(char *&, int&, long long&);
+			int encode_packet(char *&, int&, long long&, long long);
+			int encode_packet(char *&, int&, long long&, const char *);
+			int encode_packet(char *&, int&, long long&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int encode_packet(char *&p, int &l, long long &m, t a) { return encode_packet(p,l,m,(long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int set_cache_id(long long);
+#define _API_DEFINE_LONG_(t) int set_cache_id(t a) {return set_cache_id((long long)a);}
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+            const char *get_error_message(void) const;
+
+            //无源模式超时时间   add by xuxinxin, 2014/12/09
+			int set_expire_time(const char* key, int time);
+			int get_expire_time(const char* key);
+	};
+
+	class GetRequest : public Request {
+		public:
+			GetRequest(Server *srv): Request(srv, kRequestGet) {}
+			GetRequest(): Request((Server *)0, kRequestGet) {}
+	};
+
+	class InsertRequest : public Request {
+		public:
+			InsertRequest(Server *srv) : Request(srv, kRequestInsert) {}
+			InsertRequest() : Request((Server *)0, kRequestInsert) {}
+	};
+
+	class DeleteRequest : public Request {
+		public:
+			DeleteRequest(Server *srv) : Request(srv, kRequestDelete) {}
+			DeleteRequest() : Request((Server *)0, kRequestDelete) {}
+	};
+
+	class UpdateRequest : public Request {
+		public:
+			UpdateRequest(Server *srv) : Request(srv, kRequestUpdate) {}
+			UpdateRequest() : Request((Server *)0, kRequestUpdate) {}
+	};
+
+	class PurgeRequest : public Request {
+		public:
+			PurgeRequest(Server *srv) : Request(srv, kRequestPurge) {}
+			PurgeRequest() : Request((Server *)0, kRequestPurge) {}
+	};
+
+	class ReplaceRequest:public Request {
+		public:
+			ReplaceRequest(Server *srv) : Request(srv, kRequestReplace) {}
+			ReplaceRequest() : Request((Server *)0, kRequestReplace) {}
+	};
+
+	class FlushRequest : public Request {
+		public:
+			FlushRequest(Server *srv) : Request(srv, kRequestFlush) {}
+			FlushRequest(void) : Request((Server *)0, kRequestFlush) {}
+	};
+
+	class InvalidateRequest: public Request {
+		public:
+			InvalidateRequest(Server *srv) : Request(srv, kRequestInvalidate) {}
+	};
+
+	class SvrAdminRequest: public Request {
+		public:
+			SvrAdminRequest(Server *srv) : Request(srv, kRequestSvrAdmin) {}
+	};
+
+	class MonitorRequest: public Request {
+		public:
+			MonitorRequest(Server *srv) : Request(srv, kRequestMonitor){}
+	};
+
+	class Result {
+		private:
+			void *addr_;
+			long check;
+			Result(const Result &);
+			char *ServerInfo() const;
+		public:
+			friend class Server;
+			friend class Request;
+			friend class ServerPool;
+
+			Result(void);
+			~Result(void);
+			void Reset(void);
+
+			void set_error(int errcode, const char *from, const char *detail); // from will not dupped
+			int get_result_code(void) const;
+			const char *get_error_message(void) const;
+			const char *get_error_from(void) const;
+			long long get_hotbackup_id() const;
+			long long get_master_hotbackup_timestamp() const;
+			long long slave_hotbackup_timestamp() const;
+			long long get_binlog_id() const;
+			long long get_binlog_offset() const;
+			long long get_mem_size() const;
+			long long get_datd_size() const;
+			int get_num_row_size(void) const;
+			int get_total_rows_size(void) const;
+			int get_affected_rows_size(void) const;
+			int get_num_fields_size(void) const;
+			const char* get_field_name(int n) const;
+			int get_field_present(const char* name) const;
+			int get_field_type(int n) const;
+			long long get_tag(void) const;
+			void *get_tag_ptr(void) const;
+			long long magic(void) const;
+			long long get_server_timestamp(void) const;
+			long long get_insert_id(void) const;
+			long long int_key(void) const;
+			const char *binary_key(void) const;
+			const char *binary_key(int *) const;
+			const char *binary_key(int &) const;
+			const char *string_key(void) const;
+			const char *string_key(int *) const;
+			const char *string_key(int &) const;
+			long long int_value(const char *) const;
+			double float_value(const char *) const;
+			const char *string_value(const char *) const;
+			const char *string_value(const char *, int*) const;
+			const char *string_value(const char *, int&) const;
+			const char *binary_value(const char *) const;
+			const char *binary_value(const char *, int*) const;
+			const char *binary_value(const char *, int&) const;
+			int uncompress_binary_value(const char *name,char **buf,int *lenp);
+			//Uncompress Binary Value without check compressflag
+			int uncompress_binary_value_force(const char *name,char **buf,int *lenp);
+            const char * uncompress_error_message() const;
+			long long int_value(int) const;
+			double float_value(int) const;
+			const char *string_value(int) const;
+			const char *string_value(int, int*) const;
+			const char *string_value(int, int&) const;
+			const char *binary_value(int) const;
+			const char *binary_value(int, int*) const;
+			const char *binary_value(int, int&) const;
+			int fetch_row(void);
+			int rewind(void);
+	};
+
+	class ServerPool {
+		private:
+			void *addr_;
+			long check;
+			ServerPool(ServerPool &);
+		public:
+			friend class Server;
+			friend class Request;
+			friend class Result;
+
+			ServerPool(int max_servers, int max_requests);
+			~ServerPool(void);
+
+			int get_epoll_fd(int size);
+			int add_server(Server *srv, int mReq=1, int mConn=0);
+			int add_request(Request *, long long);
+			int add_request(Request *, long long, long long);
+			int add_request(Request *, long long, const char *);
+			int add_request(Request *, long long, const char *, int);
+			int add_request(Request *, void *);
+			int add_request(Request *, void *, long long);
+			int add_request(Request *, void *, const char *);
+			int add_request(Request *, void *, const char *, int);
+			int do_execute(int msec);
+			int execute_all(int msec);
+			int cancel_request(int);
+			int cancel_all_request(int type);
+			int abort_request(int);
+			int abort_all_request(int type);
+			Result *get_result(void);
+			Result *get_result(int);
+			int get_result(Result&);
+			int get_result(Result&, int);
+
+			int server_count(void) const;
+			int request_count(int type) const;
+			int request_state(int reqId) const;
+	};
+
+	const int WAIT = 1;
+	const int SEND = 2;
+	const int RECV = 4;
+	const int DONE = 8;
+	const int ALL_STATE = WAIT|SEND|RECV|DONE;
+
+	enum {
+		EC_ERROR_BASE = 2000,
+		EC_BAD_COMMAND,		// unsupported command
+		EC_MISSING_SECTION,	// missing mandatory section
+		EC_EXTRA_SECTION,	// incompatible section present
+		EC_DUPLICATE_TAG,	// same tag appear twice
+
+		EC_DUPLICATE_FIELD,	//5: same field appear twice in .need()
+		EC_BAD_SECTION_LENGTH,	// section length too short
+		EC_BAD_VALUE_LENGTH,	// value length not allow
+		EC_BAD_STRING_VALUE,	// string value w/o NULL
+		EC_BAD_FLOAT_VALUE,	// invalid float format
+
+		EC_BAD_FIELD_NUM,	//10: invalid total field#
+		EC_EXTRA_SECTION_DATA,	// section length too large
+		EC_BAD_VALUE_TYPE,	// incompatible value type
+		EC_BAD_OPERATOR,	// incompatible operator/comparison
+		EC_BAD_FIELD_ID,	// invalid field ID
+
+		EC_BAD_FIELD_NAME,	//15: invalud field name
+		EC_BAD_FIELD_TYPE,	// invalid field type
+		EC_BAD_FIELD_SIZE,	// invalid field size
+		EC_TABLE_REDEFINED,	// table defined twice
+		EC_TABLE_MISMATCH,	// request table != server table
+
+		EC_VERSION_MISMATCH,	//20: unsupported protocol version
+		EC_CHECKSUM_MISMATCH,	// table hash not equal
+		EC_NO_MORE_DATA,	// End of Result
+		EC_NEED_FULL_FIELDSET,	// only full field set accepted by helper
+		EC_BAD_KEY_TYPE,	// key type incompatible
+
+		EC_BAD_KEY_SIZE,	// 25: key size incompatible
+		EC_SERVER_BUSY,		//server error
+		EC_BAD_SOCKET,		// network failed
+		EC_NOT_INITIALIZED,	// object didn't initialized
+		EC_BAD_HOST_STRING,
+
+		EC_BAD_TABLE_NAME,	// 30
+		EC_TASK_NEED_DELETE,
+		EC_KEY_NEEDED,
+		EC_SERVER_ERROR,
+		EC_UPSTREAM_ERROR,
+
+		EC_KEY_OVERFLOW,	// 35
+		EC_BAD_MULTIKEY,
+		EC_READONLY_FIELD,
+		EC_BAD_ASYNC_CMD,
+		EC_OUT_OF_KEY_RANGE,
+
+		EC_REQUEST_ABORTED,     // 40
+		EC_PARALLEL_MODE,
+		EC_KEY_NOTEXIST,
+		EC_SERVER_READONLY,
+		EC_BAD_INVALID_FIELD,
+
+		EC_DUPLICATE_KEY,    	// 45
+		EC_TOO_MANY_KEY_VALUE,
+		EC_BAD_KEY_NAME,
+		EC_BAD_RAW_DATA,
+		EC_BAD_HOTBACKUP_JID,
+
+		EC_FULL_SYNC_COMPLETE,  //50
+		EC_FULL_SYNC_STAGE,
+		EC_INC_SYNC_STAGE,
+        EC_ERR_SYNC_STAGE,
+        EC_NOT_ALLOWED_INSERT,
+
+        EC_COMPRESS_ERROR,  //55
+        EC_UNCOMPRESS_ERROR,
+        EC_TASKPOOL,
+        EC_STATE_ERROR,
+        EC_DATA_NEEDED,
+
+    	EC_TASK_TIMEOUT,
+
+        EC_BUSINESS_WITHOUT_EXPIRETIME, //62
+        EC_EMPTY_TBDEF, //63
+    	EC_INVALID_KEY_VALUE, //64
+    	EC_INVALID_EXPIRETIME, //65
+
+    	EC_GET_EXPIRETIME_END_OF_RESULT, //66
+	};
+
+	enum {
+		ER_HASHCHK=1000,
+		ER_NISAMCHK=1001,
+		ER_NO=1002,
+		ER_YES=1003,
+		ER_CANT_CREATE_FILE=1004,
+		ER_CANT_CREATE_TABLE=1005,
+		ER_CANT_CREATE_DB=1006,
+		ER_DB_CREATE_EXISTS=1007,
+		ER_DB_DROP_EXISTS=1008,
+		ER_DB_DROP_DELETE=1009,
+		ER_DB_DROP_RMDIR=1010,
+		ER_CANT_DELETE_FILE=1011,
+		ER_CANT_FIND_SYSTEM_REC=1012,
+		ER_CANT_GET_STAT=1013,
+		ER_CANT_GET_WD=1014,
+		ER_CANT_LOCK=1015,
+		ER_CANT_OPEN_FILE=1016,
+		ER_FILE_NOT_FOUND=1017,
+		ER_CANT_READ_DIR=1018,
+		ER_CANT_SET_WD=1019,
+		ER_CHECKREAD=1020,
+		ER_DISK_FULL=1021,
+		ER_DUP_KEY=1022,
+		ER_ERROR_ON_CLOSE=1023,
+		ER_ERROR_ON_READ=1024,
+		ER_ERROR_ON_RENAME=1025,
+		ER_ERROR_ON_WRITE=1026,
+		ER_FILE_USED=1027,
+		ER_FILSORT_ABORT=1028,
+		ER_FORM_NOT_FOUND=1029,
+		ER_GET_ERRNO=1030,
+		ER_ILLEGAL_HA=1031,
+		ER_KEY_NOT_FOUND=1032,
+		ER_NOT_FORM_FILE=1033,
+		ER_NOT_KEYFILE=1034,
+		ER_OLD_KEYFILE=1035,
+		ER_OPEN_AS_READONLY=1036,
+		ER_OUTOFMEMORY=1037,
+		ER_OUT_OF_SORTMEMORY=1038,
+		ER_UNEXPECTED_EOF=1039,
+		ER_CON_COUNT_ERROR=1040,
+		ER_OUT_OF_RESOURCES=1041,
+		ER_BAD_HOST_ERROR=1042,
+		ER_HANDSHAKE_ERROR=1043,
+		ER_DBACCESS_DENIED_ERROR=1044,
+		ER_ACCESS_DENIED_ERROR=1045,
+		ER_NO_DB_ERROR=1046,
+		ER_UNKNOWN_COM_ERROR=1047,
+		ER_BAD_NULL_ERROR=1048,
+		ER_BAD_DB_ERROR=1049,
+		ER_TABLE_EXISTS_ERROR=1050,
+		ER_BAD_TABLE_ERROR=1051,
+		ER_NON_UNIQ_ERROR=1052,
+		ER_SERVER_SHUTDOWN=1053,
+		ER_BAD_FIELD_ERROR=1054,
+		ER_WRONG_FIELD_WITH_GROUP=1055,
+		ER_WRONG_GROUP_FIELD=1056,
+		ER_WRONG_SUM_SELECT=1057,
+		ER_WRONG_VALUE_COUNT=1058,
+		ER_TOO_LONG_IDENT=1059,
+		ER_DUP_FIELDNAME=1060,
+		ER_DUP_KEYNAME=1061,
+		ER_DUP_ENTRY=1062,
+		ER_WRONG_FIELD_SPEC=1063,
+		ER_PARSE_ERROR=1064,
+		ER_EMPTY_QUERY=1065,
+		ER_NONUNIQ_TABLE=1066,
+		ER_INVALID_DEFAULT=1067,
+		ER_MULTIPLE_PRI_KEY=1068,
+		ER_TOO_MANY_KEYS=1069,
+		ER_TOO_MANY_KEY_PARTS=1070,
+		ER_TOO_LONG_KEY=1071,
+		ER_KEY_COLUMN_DOES_NOT_EXITS=1072,
+		ER_BLOB_USED_AS_KEY=1073,
+		ER_TOO_BIG_FIELDLENGTH=1074,
+		ER_WRONG_AUTO_KEY=1075,
+		ER_READY=1076,
+		ER_NORMAL_SHUTDOWN=1077,
+		ER_GOT_SIGNAL=1078,
+		ER_SHUTDOWN_COMPLETE=1079,
+		ER_FORCING_CLOSE=1080,
+		ER_IPSOCK_ERROR=1081,
+		ER_NO_SUCH_INDEX=1082,
+		ER_WRONG_FIELD_TERMINATORS=1083,
+		ER_BLOBS_AND_NO_TERMINATED=1084,
+		ER_TEXTFILE_NOT_READABLE=1085,
+		ER_FILE_EXISTS_ERROR=1086,
+		ER_LOAD_INFO=1087,
+		ER_ALTER_INFO=1088,
+		ER_WRONG_SUB_KEY=1089,
+		ER_CANT_REMOVE_ALL_FIELDS=1090,
+		ER_CANT_DROP_FIELD_OR_KEY=1091,
+		ER_INSERT_INFO=1092,
+		ER_INSERT_TABLE_USED=1093,
+		ER_NO_SUCH_THREAD=1094,
+		ER_KILL_DENIED_ERROR=1095,
+		ER_NO_TABLES_USED=1096,
+		ER_TOO_BIG_SET=1097,
+		ER_NO_UNIQUE_LOGFILE=1098,
+		ER_TABLE_NOT_LOCKED_FOR_WRITE=1099,
+		ER_TABLE_NOT_LOCKED=1100,
+		ER_BLOB_CANT_HAVE_DEFAULT=1101,
+		ER_WRONG_DB_NAME=1102,
+		ER_WRONG_TABLE_NAME=1103,
+		ER_TOO_BIG_SELECT=1104,
+		ER_UNKNOWN_ERROR=1105,
+		ER_UNKNOWN_PROCEDURE=1106,
+		ER_WRONG_PARAMCOUNT_TO_PROCEDURE=1107,
+		ER_WRONG_PARAMETERS_TO_PROCEDURE=1108,
+		ER_UNKNOWN_TABLE=1109,
+		ER_FIELD_SPECIFIED_TWICE=1110,
+		ER_INVALID_GROUP_FUNC_USE=1111,
+		ER_UNSUPPORTED_EXTENSION=1112,
+		ER_TABLE_MUST_HAVE_COLUMNS=1113,
+		ER_RECORD_FILE_FULL=1114,
+		ER_UNKNOWN_CHARACTER_SET=1115,
+		ER_TOO_MANY_TABLES=1116,
+		ER_TOO_MANY_FIELDS=1117,
+		ER_TOO_BIG_ROWSIZE=1118,
+		ER_STACK_OVERRUN=1119,
+		ER_WRONG_OUTER_JOIN=1120,
+		ER_NULL_COLUMN_IN_INDEX=1121,
+		ER_CANT_FIND_UDF=1122,
+		ER_CANT_INITIALIZE_UDF=1123,
+		ER_UDF_NO_PATHS=1124,
+		ER_UDF_EXISTS=1125,
+		ER_CANT_OPEN_LIBRARY=1126,
+		ER_CANT_FIND_DL_ENTRY=1127,
+		ER_FUNCTION_NOT_DEFINED=1128,
+		ER_HOST_IS_BLOCKED=1129,
+		ER_HOST_NOT_PRIVILEGED=1130,
+		ER_PASSWORD_ANONYMOUS_USER=1131,
+		ER_PASSWORD_NOT_ALLOWED=1132,
+		ER_PASSWORD_NO_MATCH=1133,
+		ER_UPDATE_INFO=1134,
+		ER_CANT_CREATE_THREAD=1135,
+		ER_WRONG_VALUE_COUNT_ON_ROW=1136,
+		ER_CANT_REOPEN_TABLE=1137,
+		ER_INVALID_USE_OF_NULL=1138,
+		ER_REGEXP_ERROR=1139,
+		ER_MIX_OF_GROUP_FUNC_AND_FIELDS=1140,
+		ER_NONEXISTING_GRANT=1141,
+		ER_TABLEACCESS_DENIED_ERROR=1142,
+		ER_COLUMNACCESS_DENIED_ERROR=1143,
+		ER_ILLEGAL_GRANT_FOR_TABLE=1144,
+		ER_GRANT_WRONG_HOST_OR_USER=1145,
+		ER_NO_SUCH_TABLE=1146,
+		ER_NONEXISTING_TABLE_GRANT=1147,
+		ER_NOT_ALLOWED_COMMAND=1148,
+		ER_SYNTAX_ERROR=1149,
+		ER_DELAYED_CANT_CHANGE_LOCK=1150,
+		ER_TOO_MANY_DELAYED_THREADS=1151,
+		ER_ABORTING_CONNECTION=1152,
+		ER_NET_PACKET_TOO_LARGE=1153,
+		ER_NET_READ_ERROR_FROM_PIPE=1154,
+		ER_NET_FCNTL_ERROR=1155,
+		ER_NET_PACKETS_OUT_OF_ORDER=1156,
+		ER_NET_UNCOMPRESS_ERROR=1157,
+		ER_NET_READ_ERROR=1158,
+		ER_NET_READ_INTERRUPTED=1159,
+		ER_NET_ERROR_ON_WRITE=1160,
+		ER_NET_WRITE_INTERRUPTED=1161,
+		ER_TOO_LONG_STRING=1162,
+		ER_TABLE_CANT_HANDLE_BLOB=1163,
+		ER_TABLE_CANT_HANDLE_AUTO_INCREMENT=1164,
+		ER_DELAYED_INSERT_TABLE_LOCKED=1165,
+		ER_WRONG_COLUMN_NAME=1166,
+		ER_WRONG_KEY_COLUMN=1167,
+		ER_WRONG_MRG_TABLE=1168,
+		ER_DUP_UNIQUE=1169,
+		ER_BLOB_KEY_WITHOUT_LENGTH=1170,
+		ER_PRIMARY_CANT_HAVE_NULL=1171,
+		ER_TOO_MANY_ROWS=1172,
+		ER_REQUIRES_PRIMARY_KEY=1173,
+		ER_NO_RAID_COMPILED=1174,
+		ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE=1175,
+		ER_KEY_DOES_NOT_EXITS=1176,
+		ER_CHECK_NO_SUCH_TABLE=1177,
+		ER_CHECK_NOT_IMPLEMENTED=1178,
+		ER_CANT_DO_THIS_DURING_AN_TRANSACTION=1179,
+		ER_ERROR_DURING_COMMIT=1180,
+		ER_ERROR_DURING_ROLLBACK=1181,
+		ER_ERROR_DURING_FLUSH_LOGS=1182,
+		ER_ERROR_DURING_CHECKPOINT=1183,
+		ER_NEW_ABORTING_CONNECTION=1184,
+		ER_DUMP_NOT_IMPLEMENTED=   1185,
+		ER_FLUSH_MASTER_BINLOG_CLOSED=1186,
+		ER_INDEX_REBUILD= 1187,
+		ER_MASTER=1188,
+		ER_MASTER_NET_READ=1189,
+		ER_MASTER_NET_WRITE=1190,
+		ER_FT_MATCHING_KEY_NOT_FOUND=1191,
+		ER_LOCK_OR_ACTIVE_TRANSACTION=1192,
+		ER_UNKNOWN_SYSTEM_VARIABLE=1193,
+		ER_CRASHED_ON_USAGE=1194,
+		ER_CRASHED_ON_REPAIR=1195,
+		ER_WARNING_NOT_COMPLETE_ROLLBACK=1196,
+		ER_TRANS_CACHE_FULL=1197,
+		ER_SLAVE_MUST_STOP=1198,
+		ER_SLAVE_NOT_RUNNING=1199,
+		ER_BAD_SLAVE=1200,
+		ER_MASTER_INFO=1201,
+		ER_SLAVE_THREAD=1202,
+		ER_TOO_MANY_USER_CONNECTIONS=1203,
+		ER_SET_CONSTANTS_ONLY=1204,
+		ER_LOCK_WAIT_TIMEOUT=1205,
+		ER_LOCK_TABLE_FULL=1206,
+		ER_READ_ONLY_TRANSACTION=1207,
+		ER_DROP_DB_WITH_READ_LOCK=1208,
+		ER_CREATE_DB_WITH_READ_LOCK=1209,
+		ER_WRONG_ARGUMENTS=1210,
+		ER_NO_PERMISSION_TO_CREATE_USER=1211,
+		ER_UNION_TABLES_IN_DIFFERENT_DIR=1212,
+		ER_LOCK_DEADLOCK=1213,
+		ER_TABLE_CANT_HANDLE_FULLTEXT=1214,
+		ER_CANNOT_ADD_FOREIGN=1215,
+		ER_NO_REFERENCED_ROW=1216,
+		ER_ROW_IS_REFERENCED=1217,
+		ER_CONNECT_TO_MASTER=1218,
+		ER_QUERY_ON_MASTER=1219,
+		ER_ERROR_WHEN_EXECUTING_COMMAND=1220,
+		ER_WRONG_USAGE=1221,
+		ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT=1222,
+		ER_CANT_UPDATE_WITH_READLOCK=1223,
+		ER_MIXING_NOT_ALLOWED=1224,
+		ER_DUP_ARGUMENT=1225,
+		ER_USER_LIMIT_REACHED=1226,
+		ER_SPECIFIC_ACCESS_DENIED_ERROR=1227,
+		ER_LOCAL_VARIABLE=1228,
+		ER_GLOBAL_VARIABLE=1229,
+		ER_NO_DEFAULT=1230,
+		ER_WRONG_VALUE_FOR_VAR=1231,
+		ER_WRONG_TYPE_FOR_VAR=1232,
+		ER_VAR_CANT_BE_READ=1233,
+		ER_CANT_USE_OPTION_HERE=1234,
+		ER_NOT_SUPPORTED_YET=1235,
+		ER_MASTER_FATAL_ERROR_READING_BINLOG=1236,
+		ER_SLAVE_IGNORED_TABLE=1237,
+		ER_INCORRECT_GLOBAL_LOCAL_VAR=1238,
+		CR_UNKNOWN_ERROR=1900,
+		CR_SOCKET_CREATE_ERROR=1901,
+		CR_CONNECTION_ERROR=1902,
+		CR_CONN_HOST_ERROR=1903,
+		CR_IPSOCK_ERROR	=1904,
+		CR_UNKNOWN_HOST	=1905,
+		CR_SERVER_GONE_ERROR=1906,
+		CR_VERSION_ERROR=1907,
+		CR_OUT_OF_MEMORY=1908,
+		CR_WRONG_HOST_INFO=1909,
+		CR_LOCALHOST_CONNECTION=1910,
+		CR_TCP_CONNECTION=1911,
+		CR_SERVER_HANDSHAKE_ERR=1912,
+		CR_SERVER_LOST=1913,
+		CR_COMMANDS_OUT_OF_SYNC=1914,
+		CR_NAMEDPIPE_CONNECTION=1915,
+		CR_NAMEDPIPEWAIT_ERROR=1916,
+		CR_NAMEDPIPEOPEN_ERROR=1917,
+		CR_NAMEDPIPESETSTATE_ERROR=1918,
+		CR_CANT_READ_CHARSET=1919,
+		CR_NET_PACKET_TOO_LARGE=1920,
+		CR_EMBEDDED_CONNECTION=1921,
+		CR_PROBE_SLAVE_STATUS=1922,
+		CR_PROBE_SLAVE_HOSTS=1923,
+		CR_PROBE_SLAVE_CONNECT=1924,
+		CR_PROBE_MASTER_CONNECT=1925,
+		CR_SSL_CONNECTION_ERROR=1926,
+		CR_MALFORMED_PACKET=1927,
+		CR_WRONG_LICENSE=1928,
+	};
+
+	enum{
+		ER_SET_IPLIST_NULL = 20001,
+		ER_SET_INSTANCE_PROPERTIES_ERR,
+		ER_KEY_TYPE,
+		ER_CC_VERSION_ERR,
+		ER_ROUTE_INFO_NULL,
+		ER_BID_VERSION_ERR,
+		ER_PORT_OUT_RANGE,
+		ER_STATUS_ERROR_VALUE,
+		ER_WEIGHT_ERROR_VALUE,
+		ER_IP_ERROR_VALUE,
+	};
+
+};
+
+#endif

+ 91 - 0
src/devel/cpp/examples/select/selecttest.cpp

@@ -0,0 +1,91 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string>
+#include<stdint.h>
+#include<unistd.h>
+ 
+#include "dtcapi.h"
+
+int main(int argc,char* argv[])
+{
+	int iRet;
+	unsigned int uid;
+	DTC::Server stServer; // 只要server不析构,后台会保持长连接
+	stServer.int_key(); // 声明key类型
+	stServer.set_table_name("t_dtc_example");//设置dtc的表名,与table.conf中tablename应该一样
+	stServer.set_address("192.168.214.62", "10109");//设置的dtc的ip和端口
+	stServer.SetTimeout(5); // 设置网络超时时间
+	stServer.set_accesskey("0000010284d9cfc2f395ce883a41d7ffc1bbcf4e"); // 设置访问码 AccessToken,在申请dtc实例的时候网站端会生成
+	//下面三行代码是Get数据
+	unsigned int  age;
+	std::string name;
+	std::string city;
+	std::string descr;
+ 
+    DTC::GetRequest stGetReq(&stServer);
+    uid = atoi(argv[1]);
+    iRet = stGetReq.set_key(uid);
+ 
+	if(iRet == 0)
+		iRet = stGetReq.need("uid");//设置需要select的字段,注意第一个key字段不能在这里出现
+    if(iRet == 0)
+    	iRet = stGetReq.need("name");
+    if(iRet == 0)
+    	iRet = stGetReq.need("city");
+    if(iRet == 0)
+    	iRet = stGetReq.need("descr");
+    if(iRet == 0)
+    	iRet = stGetReq.need("age");
+    if(iRet == 0)
+    	iRet = stGetReq.GT("age", 24);
+		//iRet = stGetReq.OR("age", 27);
+
+    if(iRet != 0)
+    { 
+		printf("get-req set key or need error: %d", iRet);
+		fflush(stdout); 
+		return(-1); 
+    } 
+ 
+    // do_execute & get result
+    DTC::Result stResult; 
+    iRet = stGetReq.do_execute(stResult);
+    if(iRet != 0)
+	//如果出错,则输出错误码、错误阶段,错误信息,stResult.get_error_from(), stResult.get_error_message() 这两个错误信息很重要,一定要打印出来,方便定位问题
+    { 
+		printf ("uin[%u] dtc do_execute get error: %d, error_from:%s, msg:%s\n",
+			uid,//出错的key是多少
+			iRet,//错误码为多少
+			stResult.get_error_from(),//返回错误阶段
+			stResult.get_error_message()//返回错误信息
+			);
+		fflush(stdout);
+		return(-2); 
+    } 
+ 
+    if(stResult.get_num_row_size() <= 0)
+	{ 
+		// 数据不存在
+		printf("uin[%u] data not exist.\n", uid);
+		return(0); 
+    } 
+ 
+	printf("nubrow:%d\n", stResult.get_num_row_size());
+	for(int i=0;i<=stResult.get_num_row_size();++i)
+	{
+		iRet = stResult.fetch_row();//开始获取数据
+		if(iRet < 0)
+		{
+			printf ("uid[%lu] dtc fetch row error: %d\n", uid, iRet);
+			fflush(stdout);
+			return(-3);
+		}
+		//如果一切正确,则可以输出数据了
+		printf("uid: %d\n", stResult.int_value("uid"));//输出int类型的数据
+		printf("name: %s\n", stResult.string_value("name"));//输出string类型的数据
+		printf("city: %s\n", stResult.string_value("city"));//输出string类型的数据
+		printf("descr: %s\n", stResult.binary_value("descr"));//输出binary类型的数据
+		printf("age:%d\n",stResult.int_value("age"));
+	}
+    return(0);
+}  

+ 46 - 0
src/devel/cpp/examples/table.conf

@@ -0,0 +1,46 @@
+[DB_DEFINE]
+DbName		= test
+DbNum		= (1,1)
+dbMax       = 1
+MachineNum	= 1
+Deploy      = 0
+
+[Machine1]
+Procs		= 10
+WriteProcs	= 10
+CommitProcs	= 10
+#DbIdx		= [0]
+DbAddr		= 10.152.23.179:9005
+DbUser		= root
+DbPass		= rootcdb
+
+[TABLE_DEFINE]
+TableName	    = test 
+FieldCount	    = 4 
+KeyFieldCount	= 1
+#TableNum	    = (1,100)
+
+#None=0, Signed=1, Unsigned=2, Float=3, String=4, Binary=5
+[FIELD1]
+get_field_name	= name
+get_field_type	= 4
+FieldSize	= 255
+UniqField   = 1
+
+[FIELD2]
+get_field_name	= age
+get_field_type	= 1 
+FieldSize	= 4
+Value       = 0
+
+[FIELD3]
+get_field_name       = sex 
+get_field_type       = 1
+FieldSize       = 4
+Value       = 0
+
+[FIELD4]
+get_field_name       = city 
+get_field_type       = 1
+FieldSize       = 4
+Value       = 0

+ 38 - 0
src/devel/cpp/examples/update/Makefile

@@ -0,0 +1,38 @@
+LIB = ../../libdtc.so
+
+OUTPUT = update
+
+SOURCES =  updatetest.cpp 
+								   		
+
+OBJECTS= updatetest.o
+	CPPFLAGS = -g -O -Wall -fPIC -DMACROFOR64BIT -Wl,--no-undefined -Xlinker -zmuldefs
+	CFLAGS = $(CPPFLAGS)
+
+all:$(OUTPUT)
+
+.SUFFIXES: .o .cpp
+	.cpp.o:
+		$(CXX) $(CPPFLAGS) $(INCLUDE) -c $(filter %.cpp, $^) 
+
+.o:
+		$(CXX) $(CPPFLAGS) $(INCLUDE) -o $@ $^ 
+
+$(OUTPUT): $(OBJECTS)
+		$(CXX) $(CFLAGS) -fPIC  -o $@ $^ $(LIB)
+
+
+clean:
+		rm -f *.o *.so *.~ *.bak
+		rm -f $(OUTPUT)
+
+install:
+		cp -f $(OUTPUT) $(INSTALL_PATH)
+
+dep:
+		mkdep -p$(VPATH) $(INCLUDE) $(SOURCES) > .depend
+
+ifneq ($(wildcard .depend),)
+	include .depend
+endif
+

+ 1019 - 0
src/devel/cpp/examples/update/dtcapi.h

@@ -0,0 +1,1019 @@
+#ifndef __DTC_API_H__
+#define __DTC_API_H__
+
+#include <stdlib.h>
+#include <vector>
+#include <string>
+#include <stdint.h>
+
+#define IP_LENGHT 16
+
+namespace DTC {
+
+	typedef struct route_node
+	{
+		int bid;
+		int port;
+		int status;
+		int weight;
+		char ip[IP_LENGHT];
+	}ROUTE_NODE;
+
+	class Server;
+	class ServerPool;
+	class Request;
+	class Result;
+
+	const int kRequestSvrAdmin 	= 3;
+	const int kRequestGet 		= 4;
+	const int kRequestPurge 		= 5;
+	const int kRequestInsert 	= 6;
+	const int kRequestUpdate 	= 7;
+	const int kRequestDelete 	= 8;
+	const int kRequestReplace 	= 12;
+	const int kRequestFlush 		= 13;
+	const int kRequestInvalidate	= 14;
+
+	//mem monior Request;2014/06/6;by seanzheng
+	const int kRequestMonitor    = 15;
+
+	// sub-code of admin cmd
+	const int RegisterHB		= 1;
+	const int LogoutHB		= 2;
+	const int GetKeyList		= 3;
+	const int GetUpdateKey		= 4;
+	const int GetRawData		= 5;
+	const int ReplaceRawData	= 6;
+	const int AdjustLRU        	= 7;
+	const int VerifyHBT		= 8;
+	const int GetHBTime		= 9;
+	const int kSetReadOnly	= 10;
+	const int kSetReadWrite	= 11;
+	const int kQueryBinlogID		= 12;
+	const int kNodeHandleChange  = 13;
+	const int Migrate = 14;
+    const int kReloadClusterNodeList = 15;
+    const int kSetClusterNodeState  = 16;
+    const int kChangeNodeAddress  = 17;
+    const int kGetClusterState  = 18;
+    const int kPurgeForHit    = 19;
+	const int ClearCache = 21;
+	const int ColExpandStatus = 24;
+	const int kColExpand = 25;
+	const int ColExpandDone = 26;
+	const int ColExpandKey = 27;
+	
+	const int kKeyTypeNone		= 0;	// undefined
+	const int kKeyTypeInt		= 1;	// Signed Integer
+	const int kKeyTypeString		= 4;	// String, case insensitive, null ended
+
+	const int kFieldTypeNone		= 0;    // undefined
+	const int kFieldTypeSigned	= 1;	// Signed Integer
+	const int kFieldTypeUnsigned	= 2;	// Unsigned Integer
+	const int kFieldTypeFloat	= 3;	// float
+	const int kFieldTypeString	= 4;	// String, case insensitive, null ended
+	const int kFieldTypeBinary	= 5;	// binary
+
+	int  set_key_value_max(unsigned int count); // 设置批量操作一次最多多少个key(默认最多32个)
+#ifndef WIN32
+	void write_log (int level,
+			const char*file, const char *func, int lineno,
+			const char *fmt, ...)
+		__attribute__((format(printf,5,6)));
+#endif
+
+	class Result;
+	class Server {
+		private:
+			void *addr_;
+			long check;
+		public:
+			friend class Request;
+			friend class Result;
+			friend class ServerPool;
+			friend class QOSServerPool;
+
+			Server(void);
+			~Server(void);
+			Server(const Server &);
+			void clone_table_define(const Server& source);
+			int set_address(const char *host, const char *port=0);
+			int set_table_name(const char *);
+            //for compress
+            void set_compress_level(int);
+            //get address and tablename set by user
+			const char * get_address(void) const;
+			const char * get_table_name(void) const;
+            //get address and tablename set by dtc frame,for plugin only;
+			const char * get_server_address(void) const;
+			const char * get_server_table_name(void) const;
+			int int_key(void);
+			int binary_key(void);
+			int string_key(void);
+			int add_key(const char* name, int type);
+			int get_field_type(const char* name);
+			const char *get_error_message(void) const;
+			void SetTimeout(int);
+			void set_timeout(int);
+			int connect(void);
+			void close(void);
+			int ping(void);
+			void auto_ping(void);
+			void set_fd(int); // UNSUPPORTED API
+			void set_auto_Update_table(bool autoUpdate);
+			void set_auto_reconnect(int auto_reconnect);
+			int decode_packet(Result &, const char *, int);
+			int check_packet_size(const char *, int);
+
+			void set_accesskey(const char *token);
+
+		public:
+			void increase_error_count_();
+			uint64_t get_error_count();
+			void clear_error_count();
+			
+			void increase_remove_count();
+			int get_remove_count();
+			void clear_remove_count();
+
+			void increase_total_request();
+			uint64_t get_total_request();
+			void clear_total_request();
+
+			void add_total_elaps(uint64_t iElaps);
+			uint64_t get_total_elaps();
+			void clear_total_elaps();
+	};
+
+	class DTCQosServer;
+
+	class DTCServers
+	{
+		public:
+			DTCServers();
+			~DTCServers();
+
+		private:
+			DTCServers(const DTCServers&);
+			DTCServers& operator=(const DTCServers&);
+
+		public:
+			int set_route_list(std::vector<ROUTE_NODE>& ip_list);
+			void set_idc_no(int IDCNo);
+			Server* get_server();
+
+			int set_accesskey(const char *token);
+			int set_table_name(const char *tableName);
+			/*
+				Signed=1,   // Signed Integer
+				String=4,   // String, case insensitive, null ended
+				Binary=5,   // opaque binary data
+			*/
+			int set_key_type(int type);
+			void set_agenttime(int t);
+			voidset_timeout(int n);
+			std::string get_error_msg();
+
+		private:
+			int is_server_has_existed(ROUTE_NODE& ip);
+			int construct_servers();
+			int construct_servers2(std::vector<ROUTE_NODE>& IPList);
+			void disorder_list(int *tmpBuckets, int size);
+			int construct_balance_buckets();
+			int refresh_balance_buckets(uint64_t );			
+			void remove_server_from_buckets(uint64_t );
+			Server* get_one_server_from_buckets();
+			void set_error_msg(int err, std::string from, std::string msg);
+
+		private:
+			int m_time_out;
+			int m_agent_time; 
+			int m_key_type;
+			char* m_table_name;
+			std::string m_access_token;
+			std::string m_err_msg;
+
+		private:
+			bool m_set_route;	
+			bool m_constructed_by_set_i_ps;
+			int m_bid;
+			int m_idc_no;
+			int m_buckets_pos;
+			int m_balance_bucket_size;
+			uint64_t m_bid_version;
+			uint64_t m_last_get_ca_time;
+			uint64_t m_refresh_buckets_time;
+			uint64_t m_remove_buckets_time;
+			int* m_load_balance_buckets;
+			DTCQosServer* m_qos_severs;
+			std::vector<ROUTE_NODE> m_ip_list;
+	};
+
+	class Request {
+		private:
+			void *addr_;
+			long check;
+			Request(const Request &);
+		public:
+			friend class Server;
+			friend class Result;
+			friend class ServerPool;
+
+			Request(Server *srv, int op);
+			Request(void);
+			~Request(void);
+			void Reset(void);
+			void Reset(int);
+			int attach_server(Server *srv);
+
+			void set_admin_code(int code);
+			void set_hotbackup_id(long long);
+			void set_master_hotbackup_timestamp(long long);
+			void set_slave_hotbackup_timestamp(long long);
+
+#define _API_DEFINE_LONG_(op, t) int op(const char *n, t a) { return op(n, (long long)a); }
+#define _API_DEFINE_FLOAT_(op, t) int op(const char *n, t a) { return op(n, (double)a); }
+			int need(const char *);
+			int need(const char *, int);
+			int get_field_type(const char*);
+			void no_cache(void);
+			void no_next_server(void);
+			void limit(unsigned int, unsigned int);
+			int EQ(const char *, long long);
+			int NE(const char *, long long);
+			int LT(const char *, long long);
+			int LE(const char *, long long);
+			int GT(const char *, long long);
+			int GE(const char *, long long);
+			int EQ(const char *, const char *);
+			int NE(const char *, const char *);
+			int EQ(const char *, const char *, int);
+			int NE(const char *, const char *, int);
+
+			_API_DEFINE_LONG_(EQ, unsigned long long);
+			_API_DEFINE_LONG_(EQ, long);
+			_API_DEFINE_LONG_(EQ, unsigned long);
+			_API_DEFINE_LONG_(EQ, int);
+			_API_DEFINE_LONG_(EQ, unsigned int);
+			_API_DEFINE_LONG_(EQ, short);
+			_API_DEFINE_LONG_(EQ, unsigned short);
+			_API_DEFINE_LONG_(EQ, char);
+			_API_DEFINE_LONG_(EQ, unsigned char);
+
+			_API_DEFINE_LONG_(NE, unsigned long long);
+			_API_DEFINE_LONG_(NE, long);
+			_API_DEFINE_LONG_(NE, unsigned long);
+			_API_DEFINE_LONG_(NE, int);
+			_API_DEFINE_LONG_(NE, unsigned int);
+			_API_DEFINE_LONG_(NE, short);
+			_API_DEFINE_LONG_(NE, unsigned short);
+			_API_DEFINE_LONG_(NE, char);
+			_API_DEFINE_LONG_(NE, unsigned char);
+
+			_API_DEFINE_LONG_(GT, unsigned long long);
+			_API_DEFINE_LONG_(GT, long);
+			_API_DEFINE_LONG_(GT, unsigned long);
+			_API_DEFINE_LONG_(GT, int);
+			_API_DEFINE_LONG_(GT, unsigned int);
+			_API_DEFINE_LONG_(GT, short);
+			_API_DEFINE_LONG_(GT, unsigned short);
+			_API_DEFINE_LONG_(GT, char);
+			_API_DEFINE_LONG_(GT, unsigned char);
+
+			_API_DEFINE_LONG_(GE, unsigned long long);
+			_API_DEFINE_LONG_(GE, long);
+			_API_DEFINE_LONG_(GE, unsigned long);
+			_API_DEFINE_LONG_(GE, int);
+			_API_DEFINE_LONG_(GE, unsigned int);
+			_API_DEFINE_LONG_(GE, short);
+			_API_DEFINE_LONG_(GE, unsigned short);
+			_API_DEFINE_LONG_(GE, char);
+			_API_DEFINE_LONG_(GE, unsigned char);
+
+			_API_DEFINE_LONG_(LT, unsigned long long);
+			_API_DEFINE_LONG_(LT, long);
+			_API_DEFINE_LONG_(LT, unsigned long);
+			_API_DEFINE_LONG_(LT, int);
+			_API_DEFINE_LONG_(LT, unsigned int);
+			_API_DEFINE_LONG_(LT, short);
+			_API_DEFINE_LONG_(LT, unsigned short);
+			_API_DEFINE_LONG_(LT, char);
+			_API_DEFINE_LONG_(LT, unsigned char);
+
+			_API_DEFINE_LONG_(LE, unsigned long long);
+			_API_DEFINE_LONG_(LE, long);
+			_API_DEFINE_LONG_(LE, unsigned long);
+			_API_DEFINE_LONG_(LE, int);
+			_API_DEFINE_LONG_(LE, unsigned int);
+			_API_DEFINE_LONG_(LE, short);
+			_API_DEFINE_LONG_(LE, unsigned short);
+			_API_DEFINE_LONG_(LE, char);
+			_API_DEFINE_LONG_(LE, unsigned char);
+
+			int Set(const char *, long long);
+			int OR(const char *, long long);
+			int Add(const char *, long long);
+			int Sub(const char *, long long);
+			int Set(const char *, double);
+			int Add(const char *, double);
+			int Sub(const char *, double);
+			int Set(const char *, const char *);
+			int Set(const char *, const char *, int);
+
+            //just for compress,only support binary field
+			int compress_set(const char *, const char *, int);
+			//just compress and set. Don't need compressflag
+			int compress_set_force(const char *, const char *, int);
+
+			//bits op
+			int set_multi_bits(const char *, int, int, unsigned int);
+			int set_bit  (const char *f, int o) { return set_multi_bits(f, o, 1, 1);}
+			int clear_bit(const char *f, int o) { return set_multi_bits(f, o, 1, 0);}
+
+			_API_DEFINE_LONG_(Set, unsigned long long);
+			_API_DEFINE_LONG_(Set, long);
+			_API_DEFINE_LONG_(Set, unsigned long);
+			_API_DEFINE_LONG_(Set, int);
+			_API_DEFINE_LONG_(Set, unsigned int);
+			_API_DEFINE_LONG_(Set, short);
+			_API_DEFINE_LONG_(Set, unsigned short);
+			_API_DEFINE_LONG_(Set, char);
+			_API_DEFINE_LONG_(Set, unsigned char);
+			_API_DEFINE_FLOAT_(Set, float);
+			_API_DEFINE_FLOAT_(Set, long double);
+
+			_API_DEFINE_LONG_(OR, unsigned long long);
+			_API_DEFINE_LONG_(OR, long);
+			_API_DEFINE_LONG_(OR, unsigned long);
+			_API_DEFINE_LONG_(OR, int);
+			_API_DEFINE_LONG_(OR, unsigned int);
+			_API_DEFINE_LONG_(OR, short);
+			_API_DEFINE_LONG_(OR, unsigned short);
+
+			_API_DEFINE_LONG_(Add, unsigned long long);
+			_API_DEFINE_LONG_(Add, long);
+			_API_DEFINE_LONG_(Add, unsigned long);
+			_API_DEFINE_LONG_(Add, int);
+			_API_DEFINE_LONG_(Add, unsigned int);
+			_API_DEFINE_LONG_(Add, short);
+			_API_DEFINE_LONG_(Add, unsigned short);
+			_API_DEFINE_LONG_(Add, char);
+			_API_DEFINE_LONG_(Add, unsigned char);
+			_API_DEFINE_FLOAT_(Add, float);
+			_API_DEFINE_FLOAT_(Add, long double);
+
+			_API_DEFINE_LONG_(Sub, unsigned long long);
+			_API_DEFINE_LONG_(Sub, long);
+			_API_DEFINE_LONG_(Sub, unsigned long);
+			_API_DEFINE_LONG_(Sub, int);
+			_API_DEFINE_LONG_(Sub, unsigned int);
+			_API_DEFINE_LONG_(Sub, short);
+			_API_DEFINE_LONG_(Sub, unsigned short);
+			_API_DEFINE_LONG_(Sub, char);
+			_API_DEFINE_LONG_(Sub, unsigned char);
+			_API_DEFINE_FLOAT_(Sub, float);
+			_API_DEFINE_FLOAT_(Sub, long double);
+#undef _API_DEFINE_LONG_
+
+			void unset_key(void);
+			int set_key(long long);
+			int set_key(const char *);
+			int set_key(const char *, int);
+#define _API_DEFINE_LONG_(t) int set_key(t a) { return set_key((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int add_key_value(const char* name, long long v);
+			int add_key_value(const char* name, const char *str);
+			int add_key_value(const char* name, const char *ptr, int len);
+#define _API_DEFINE_LONG_(t) int add_key_value(const char* name, t a) { return add_key_value(name, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			Result *do_execute(void);
+			Result *do_execute(long long);
+			Result *do_execute(const char *);
+			Result *do_execute(const char *, int);
+
+#define _API_DEFINE_LONG_(t) Result *do_execute(t a) { return do_execute((long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int do_execute(Result&);
+			int do_execute(Result&, long long);
+			int do_execute(Result&, const char *);
+			int do_execute(Result&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int do_execute(Result &r, t a) { return do_execute(r, (long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int encode_packet(char *&, int&, long long&);
+			int encode_packet(char *&, int&, long long&, long long);
+			int encode_packet(char *&, int&, long long&, const char *);
+			int encode_packet(char *&, int&, long long&, const char *, int);
+
+#define _API_DEFINE_LONG_(t) int encode_packet(char *&p, int &l, long long &m, t a) { return encode_packet(p,l,m,(long long)a); }
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+
+			int set_cache_id(long long);
+#define _API_DEFINE_LONG_(t) int set_cache_id(t a) {return set_cache_id((long long)a);}
+			_API_DEFINE_LONG_(unsigned long long);
+			_API_DEFINE_LONG_(long);
+			_API_DEFINE_LONG_(unsigned long);
+			_API_DEFINE_LONG_(int);
+			_API_DEFINE_LONG_(unsigned int);
+			_API_DEFINE_LONG_(short);
+			_API_DEFINE_LONG_(unsigned short);
+			_API_DEFINE_LONG_(char);
+			_API_DEFINE_LONG_(unsigned char);
+#undef _API_DEFINE_LONG_
+            const char *get_error_message(void) const;
+
+            //无源模式超时时间   add by xuxinxin, 2014/12/09
+			int set_expire_time(const char* key, int time);
+			int get_expire_time(const char* key);
+	};
+
+	class GetRequest : public Request {
+		public:
+			GetRequest(Server *srv): Request(srv, kRequestGet) {}
+			GetRequest(): Request((Server *)0, kRequestGet) {}
+	};
+
+	class InsertRequest : public Request {
+		public:
+			InsertRequest(Server *srv) : Request(srv, kRequestInsert) {}
+			InsertRequest() : Request((Server *)0, kRequestInsert) {}
+	};
+
+	class DeleteRequest : public Request {
+		public:
+			DeleteRequest(Server *srv) : Request(srv, kRequestDelete) {}
+			DeleteRequest() : Request((Server *)0, kRequestDelete) {}
+	};
+
+	class UpdateRequest : public Request {
+		public:
+			UpdateRequest(Server *srv) : Request(srv, kRequestUpdate) {}
+			UpdateRequest() : Request((Server *)0, kRequestUpdate) {}
+	};
+
+	class PurgeRequest : public Request {
+		public:
+			PurgeRequest(Server *srv) : Request(srv, kRequestPurge) {}
+			PurgeRequest() : Request((Server *)0, kRequestPurge) {}
+	};
+
+	class ReplaceRequest:public Request {
+		public:
+			ReplaceRequest(Server *srv) : Request(srv, kRequestReplace) {}
+			ReplaceRequest() : Request((Server *)0, kRequestReplace) {}
+	};
+
+	class FlushRequest : public Request {
+		public:
+			FlushRequest(Server *srv) : Request(srv, kRequestFlush) {}
+			FlushRequest(void) : Request((Server *)0, kRequestFlush) {}
+	};
+
+	class InvalidateRequest: public Request {
+		public:
+			InvalidateRequest(Server *srv) : Request(srv, kRequestInvalidate) {}
+	};
+
+	class SvrAdminRequest: public Request {
+		public:
+			SvrAdminRequest(Server *srv) : Request(srv, kRequestSvrAdmin) {}
+	};
+
+	class MonitorRequest: public Request {
+		public:
+			MonitorRequest(Server *srv) : Request(srv, kRequestMonitor){}
+	};
+
+	class Result {
+		private:
+			void *addr_;
+			long check;
+			Result(const Result &);
+			char *ServerInfo() const;
+		public:
+			friend class Server;
+			friend class Request;
+			friend class ServerPool;
+
+			Result(void);
+			~Result(void);
+			void Reset(void);
+
+			void set_error(int errcode, const char *from, const char *detail); // from will not dupped
+			int get_result_code(void) const;
+			const char *get_error_message(void) const;
+			const char *get_error_from(void) const;
+			long long get_hotbackup_id() const;
+			long long get_master_hotbackup_timestamp() const;
+			long long slave_hotbackup_timestamp() const;
+			long long get_binlog_id() const;
+			long long get_binlog_offset() const;
+			long long get_mem_size() const;
+			long long get_datd_size() const;
+			int get_num_row_size(void) const;
+			int get_total_rows_size(void) const;
+			int get_affected_rows_size(void) const;
+			int get_num_fields_size(void) const;
+			const char* get_field_name(int n) const;
+			int get_field_present(const char* name) const;
+			int get_field_type(int n) const;
+			long long get_tag(void) const;
+			void *get_tag_ptr(void) const;
+			long long magic(void) const;
+			long long get_server_timestamp(void) const;
+			long long get_insert_id(void) const;
+			long long int_key(void) const;
+			const char *binary_key(void) const;
+			const char *binary_key(int *) const;
+			const char *binary_key(int &) const;
+			const char *string_key(void) const;
+			const char *string_key(int *) const;
+			const char *string_key(int &) const;
+			long long int_value(const char *) const;
+			double float_value(const char *) const;
+			const char *string_value(const char *) const;
+			const char *string_value(const char *, int*) const;
+			const char *string_value(const char *, int&) const;
+			const char *binary_value(const char *) const;
+			const char *binary_value(const char *, int*) const;
+			const char *binary_value(const char *, int&) const;
+			int uncompress_binary_value(const char *name,char **buf,int *lenp);
+			//Uncompress Binary Value without check compressflag
+			int uncompress_binary_value_force(const char *name,char **buf,int *lenp);
+            const char * uncompress_error_message() const;
+			long long int_value(int) const;
+			double float_value(int) const;
+			const char *string_value(int) const;
+			const char *string_value(int, int*) const;
+			const char *string_value(int, int&) const;
+			const char *binary_value(int) const;
+			const char *binary_value(int, int*) const;
+			const char *binary_value(int, int&) const;
+			int fetch_row(void);
+			int rewind(void);
+	};
+
+	class ServerPool {
+		private:
+			void *addr_;
+			long check;
+			ServerPool(ServerPool &);
+		public:
+			friend class Server;
+			friend class Request;
+			friend class Result;
+
+			ServerPool(int max_servers, int max_requests);
+			~ServerPool(void);
+
+			int get_epoll_fd(int size);
+			int add_server(Server *srv, int mReq=1, int mConn=0);
+			int add_request(Request *, long long);
+			int add_request(Request *, long long, long long);
+			int add_request(Request *, long long, const char *);
+			int add_request(Request *, long long, const char *, int);
+			int add_request(Request *, void *);
+			int add_request(Request *, void *, long long);
+			int add_request(Request *, void *, const char *);
+			int add_request(Request *, void *, const char *, int);
+			int do_execute(int msec);
+			int execute_all(int msec);
+			int cancel_request(int);
+			int cancel_all_request(int type);
+			int abort_request(int);
+			int abort_all_request(int type);
+			Result *get_result(void);
+			Result *get_result(int);
+			int get_result(Result&);
+			int get_result(Result&, int);
+
+			int server_count(void) const;
+			int request_count(int type) const;
+			int request_state(int reqId) const;
+	};
+
+	const int WAIT = 1;
+	const int SEND = 2;
+	const int RECV = 4;
+	const int DONE = 8;
+	const int ALL_STATE = WAIT|SEND|RECV|DONE;
+
+	enum {
+		EC_ERROR_BASE = 2000,
+		EC_BAD_COMMAND,		// unsupported command
+		EC_MISSING_SECTION,	// missing mandatory section
+		EC_EXTRA_SECTION,	// incompatible section present
+		EC_DUPLICATE_TAG,	// same tag appear twice
+
+		EC_DUPLICATE_FIELD,	//5: same field appear twice in .need()
+		EC_BAD_SECTION_LENGTH,	// section length too short
+		EC_BAD_VALUE_LENGTH,	// value length not allow
+		EC_BAD_STRING_VALUE,	// string value w/o NULL
+		EC_BAD_FLOAT_VALUE,	// invalid float format
+
+		EC_BAD_FIELD_NUM,	//10: invalid total field#
+		EC_EXTRA_SECTION_DATA,	// section length too large
+		EC_BAD_VALUE_TYPE,	// incompatible value type
+		EC_BAD_OPERATOR,	// incompatible operator/comparison
+		EC_BAD_FIELD_ID,	// invalid field ID
+
+		EC_BAD_FIELD_NAME,	//15: invalud field name
+		EC_BAD_FIELD_TYPE,	// invalid field type
+		EC_BAD_FIELD_SIZE,	// invalid field size
+		EC_TABLE_REDEFINED,	// table defined twice
+		EC_TABLE_MISMATCH,	// request table != server table
+
+		EC_VERSION_MISMATCH,	//20: unsupported protocol version
+		EC_CHECKSUM_MISMATCH,	// table hash not equal
+		EC_NO_MORE_DATA,	// End of Result
+		EC_NEED_FULL_FIELDSET,	// only full field set accepted by helper
+		EC_BAD_KEY_TYPE,	// key type incompatible
+
+		EC_BAD_KEY_SIZE,	// 25: key size incompatible
+		EC_SERVER_BUSY,		//server error
+		EC_BAD_SOCKET,		// network failed
+		EC_NOT_INITIALIZED,	// object didn't initialized
+		EC_BAD_HOST_STRING,
+
+		EC_BAD_TABLE_NAME,	// 30
+		EC_TASK_NEED_DELETE,
+		EC_KEY_NEEDED,
+		EC_SERVER_ERROR,
+		EC_UPSTREAM_ERROR,
+
+		EC_KEY_OVERFLOW,	// 35
+		EC_BAD_MULTIKEY,
+		EC_READONLY_FIELD,
+		EC_BAD_ASYNC_CMD,
+		EC_OUT_OF_KEY_RANGE,
+
+		EC_REQUEST_ABORTED,     // 40
+		EC_PARALLEL_MODE,
+		EC_KEY_NOTEXIST,
+		EC_SERVER_READONLY,
+		EC_BAD_INVALID_FIELD,
+
+		EC_DUPLICATE_KEY,    	// 45
+		EC_TOO_MANY_KEY_VALUE,
+		EC_BAD_KEY_NAME,
+		EC_BAD_RAW_DATA,
+		EC_BAD_HOTBACKUP_JID,
+
+		EC_FULL_SYNC_COMPLETE,  //50
+		EC_FULL_SYNC_STAGE,
+		EC_INC_SYNC_STAGE,
+        EC_ERR_SYNC_STAGE,
+        EC_NOT_ALLOWED_INSERT,
+
+        EC_COMPRESS_ERROR,  //55
+        EC_UNCOMPRESS_ERROR,
+        EC_TASKPOOL,
+        EC_STATE_ERROR,
+        EC_DATA_NEEDED,
+
+    	EC_TASK_TIMEOUT,
+
+        EC_BUSINESS_WITHOUT_EXPIRETIME, //62
+        EC_EMPTY_TBDEF, //63
+    	EC_INVALID_KEY_VALUE, //64
+    	EC_INVALID_EXPIRETIME, //65
+
+    	EC_GET_EXPIRETIME_END_OF_RESULT, //66
+	};
+
+	enum {
+		ER_HASHCHK=1000,
+		ER_NISAMCHK=1001,
+		ER_NO=1002,
+		ER_YES=1003,
+		ER_CANT_CREATE_FILE=1004,
+		ER_CANT_CREATE_TABLE=1005,
+		ER_CANT_CREATE_DB=1006,
+		ER_DB_CREATE_EXISTS=1007,
+		ER_DB_DROP_EXISTS=1008,
+		ER_DB_DROP_DELETE=1009,
+		ER_DB_DROP_RMDIR=1010,
+		ER_CANT_DELETE_FILE=1011,
+		ER_CANT_FIND_SYSTEM_REC=1012,
+		ER_CANT_GET_STAT=1013,
+		ER_CANT_GET_WD=1014,
+		ER_CANT_LOCK=1015,
+		ER_CANT_OPEN_FILE=1016,
+		ER_FILE_NOT_FOUND=1017,
+		ER_CANT_READ_DIR=1018,
+		ER_CANT_SET_WD=1019,
+		ER_CHECKREAD=1020,
+		ER_DISK_FULL=1021,
+		ER_DUP_KEY=1022,
+		ER_ERROR_ON_CLOSE=1023,
+		ER_ERROR_ON_READ=1024,
+		ER_ERROR_ON_RENAME=1025,
+		ER_ERROR_ON_WRITE=1026,
+		ER_FILE_USED=1027,
+		ER_FILSORT_ABORT=1028,
+		ER_FORM_NOT_FOUND=1029,
+		ER_GET_ERRNO=1030,
+		ER_ILLEGAL_HA=1031,
+		ER_KEY_NOT_FOUND=1032,
+		ER_NOT_FORM_FILE=1033,
+		ER_NOT_KEYFILE=1034,
+		ER_OLD_KEYFILE=1035,
+		ER_OPEN_AS_READONLY=1036,
+		ER_OUTOFMEMORY=1037,
+		ER_OUT_OF_SORTMEMORY=1038,
+		ER_UNEXPECTED_EOF=1039,
+		ER_CON_COUNT_ERROR=1040,
+		ER_OUT_OF_RESOURCES=1041,
+		ER_BAD_HOST_ERROR=1042,
+		ER_HANDSHAKE_ERROR=1043,
+		ER_DBACCESS_DENIED_ERROR=1044,
+		ER_ACCESS_DENIED_ERROR=1045,
+		ER_NO_DB_ERROR=1046,
+		ER_UNKNOWN_COM_ERROR=1047,
+		ER_BAD_NULL_ERROR=1048,
+		ER_BAD_DB_ERROR=1049,
+		ER_TABLE_EXISTS_ERROR=1050,
+		ER_BAD_TABLE_ERROR=1051,
+		ER_NON_UNIQ_ERROR=1052,
+		ER_SERVER_SHUTDOWN=1053,
+		ER_BAD_FIELD_ERROR=1054,
+		ER_WRONG_FIELD_WITH_GROUP=1055,
+		ER_WRONG_GROUP_FIELD=1056,
+		ER_WRONG_SUM_SELECT=1057,
+		ER_WRONG_VALUE_COUNT=1058,
+		ER_TOO_LONG_IDENT=1059,
+		ER_DUP_FIELDNAME=1060,
+		ER_DUP_KEYNAME=1061,
+		ER_DUP_ENTRY=1062,
+		ER_WRONG_FIELD_SPEC=1063,
+		ER_PARSE_ERROR=1064,
+		ER_EMPTY_QUERY=1065,
+		ER_NONUNIQ_TABLE=1066,
+		ER_INVALID_DEFAULT=1067,
+		ER_MULTIPLE_PRI_KEY=1068,
+		ER_TOO_MANY_KEYS=1069,
+		ER_TOO_MANY_KEY_PARTS=1070,
+		ER_TOO_LONG_KEY=1071,
+		ER_KEY_COLUMN_DOES_NOT_EXITS=1072,
+		ER_BLOB_USED_AS_KEY=1073,
+		ER_TOO_BIG_FIELDLENGTH=1074,
+		ER_WRONG_AUTO_KEY=1075,
+		ER_READY=1076,
+		ER_NORMAL_SHUTDOWN=1077,
+		ER_GOT_SIGNAL=1078,
+		ER_SHUTDOWN_COMPLETE=1079,
+		ER_FORCING_CLOSE=1080,
+		ER_IPSOCK_ERROR=1081,
+		ER_NO_SUCH_INDEX=1082,
+		ER_WRONG_FIELD_TERMINATORS=1083,
+		ER_BLOBS_AND_NO_TERMINATED=1084,
+		ER_TEXTFILE_NOT_READABLE=1085,
+		ER_FILE_EXISTS_ERROR=1086,
+		ER_LOAD_INFO=1087,
+		ER_ALTER_INFO=1088,
+		ER_WRONG_SUB_KEY=1089,
+		ER_CANT_REMOVE_ALL_FIELDS=1090,
+		ER_CANT_DROP_FIELD_OR_KEY=1091,
+		ER_INSERT_INFO=1092,
+		ER_INSERT_TABLE_USED=1093,
+		ER_NO_SUCH_THREAD=1094,
+		ER_KILL_DENIED_ERROR=1095,
+		ER_NO_TABLES_USED=1096,
+		ER_TOO_BIG_SET=1097,
+		ER_NO_UNIQUE_LOGFILE=1098,
+		ER_TABLE_NOT_LOCKED_FOR_WRITE=1099,
+		ER_TABLE_NOT_LOCKED=1100,
+		ER_BLOB_CANT_HAVE_DEFAULT=1101,
+		ER_WRONG_DB_NAME=1102,
+		ER_WRONG_TABLE_NAME=1103,
+		ER_TOO_BIG_SELECT=1104,
+		ER_UNKNOWN_ERROR=1105,
+		ER_UNKNOWN_PROCEDURE=1106,
+		ER_WRONG_PARAMCOUNT_TO_PROCEDURE=1107,
+		ER_WRONG_PARAMETERS_TO_PROCEDURE=1108,
+		ER_UNKNOWN_TABLE=1109,
+		ER_FIELD_SPECIFIED_TWICE=1110,
+		ER_INVALID_GROUP_FUNC_USE=1111,
+		ER_UNSUPPORTED_EXTENSION=1112,
+		ER_TABLE_MUST_HAVE_COLUMNS=1113,
+		ER_RECORD_FILE_FULL=1114,
+		ER_UNKNOWN_CHARACTER_SET=1115,
+		ER_TOO_MANY_TABLES=1116,
+		ER_TOO_MANY_FIELDS=1117,
+		ER_TOO_BIG_ROWSIZE=1118,
+		ER_STACK_OVERRUN=1119,
+		ER_WRONG_OUTER_JOIN=1120,
+		ER_NULL_COLUMN_IN_INDEX=1121,
+		ER_CANT_FIND_UDF=1122,
+		ER_CANT_INITIALIZE_UDF=1123,
+		ER_UDF_NO_PATHS=1124,
+		ER_UDF_EXISTS=1125,
+		ER_CANT_OPEN_LIBRARY=1126,
+		ER_CANT_FIND_DL_ENTRY=1127,
+		ER_FUNCTION_NOT_DEFINED=1128,
+		ER_HOST_IS_BLOCKED=1129,
+		ER_HOST_NOT_PRIVILEGED=1130,
+		ER_PASSWORD_ANONYMOUS_USER=1131,
+		ER_PASSWORD_NOT_ALLOWED=1132,
+		ER_PASSWORD_NO_MATCH=1133,
+		ER_UPDATE_INFO=1134,
+		ER_CANT_CREATE_THREAD=1135,
+		ER_WRONG_VALUE_COUNT_ON_ROW=1136,
+		ER_CANT_REOPEN_TABLE=1137,
+		ER_INVALID_USE_OF_NULL=1138,
+		ER_REGEXP_ERROR=1139,
+		ER_MIX_OF_GROUP_FUNC_AND_FIELDS=1140,
+		ER_NONEXISTING_GRANT=1141,
+		ER_TABLEACCESS_DENIED_ERROR=1142,
+		ER_COLUMNACCESS_DENIED_ERROR=1143,
+		ER_ILLEGAL_GRANT_FOR_TABLE=1144,
+		ER_GRANT_WRONG_HOST_OR_USER=1145,
+		ER_NO_SUCH_TABLE=1146,
+		ER_NONEXISTING_TABLE_GRANT=1147,
+		ER_NOT_ALLOWED_COMMAND=1148,
+		ER_SYNTAX_ERROR=1149,
+		ER_DELAYED_CANT_CHANGE_LOCK=1150,
+		ER_TOO_MANY_DELAYED_THREADS=1151,
+		ER_ABORTING_CONNECTION=1152,
+		ER_NET_PACKET_TOO_LARGE=1153,
+		ER_NET_READ_ERROR_FROM_PIPE=1154,
+		ER_NET_FCNTL_ERROR=1155,
+		ER_NET_PACKETS_OUT_OF_ORDER=1156,
+		ER_NET_UNCOMPRESS_ERROR=1157,
+		ER_NET_READ_ERROR=1158,
+		ER_NET_READ_INTERRUPTED=1159,
+		ER_NET_ERROR_ON_WRITE=1160,
+		ER_NET_WRITE_INTERRUPTED=1161,
+		ER_TOO_LONG_STRING=1162,
+		ER_TABLE_CANT_HANDLE_BLOB=1163,
+		ER_TABLE_CANT_HANDLE_AUTO_INCREMENT=1164,
+		ER_DELAYED_INSERT_TABLE_LOCKED=1165,
+		ER_WRONG_COLUMN_NAME=1166,
+		ER_WRONG_KEY_COLUMN=1167,
+		ER_WRONG_MRG_TABLE=1168,
+		ER_DUP_UNIQUE=1169,
+		ER_BLOB_KEY_WITHOUT_LENGTH=1170,
+		ER_PRIMARY_CANT_HAVE_NULL=1171,
+		ER_TOO_MANY_ROWS=1172,
+		ER_REQUIRES_PRIMARY_KEY=1173,
+		ER_NO_RAID_COMPILED=1174,
+		ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE=1175,
+		ER_KEY_DOES_NOT_EXITS=1176,
+		ER_CHECK_NO_SUCH_TABLE=1177,
+		ER_CHECK_NOT_IMPLEMENTED=1178,
+		ER_CANT_DO_THIS_DURING_AN_TRANSACTION=1179,
+		ER_ERROR_DURING_COMMIT=1180,
+		ER_ERROR_DURING_ROLLBACK=1181,
+		ER_ERROR_DURING_FLUSH_LOGS=1182,
+		ER_ERROR_DURING_CHECKPOINT=1183,
+		ER_NEW_ABORTING_CONNECTION=1184,
+		ER_DUMP_NOT_IMPLEMENTED=   1185,
+		ER_FLUSH_MASTER_BINLOG_CLOSED=1186,
+		ER_INDEX_REBUILD= 1187,
+		ER_MASTER=1188,
+		ER_MASTER_NET_READ=1189,
+		ER_MASTER_NET_WRITE=1190,
+		ER_FT_MATCHING_KEY_NOT_FOUND=1191,
+		ER_LOCK_OR_ACTIVE_TRANSACTION=1192,
+		ER_UNKNOWN_SYSTEM_VARIABLE=1193,
+		ER_CRASHED_ON_USAGE=1194,
+		ER_CRASHED_ON_REPAIR=1195,
+		ER_WARNING_NOT_COMPLETE_ROLLBACK=1196,
+		ER_TRANS_CACHE_FULL=1197,
+		ER_SLAVE_MUST_STOP=1198,
+		ER_SLAVE_NOT_RUNNING=1199,
+		ER_BAD_SLAVE=1200,
+		ER_MASTER_INFO=1201,
+		ER_SLAVE_THREAD=1202,
+		ER_TOO_MANY_USER_CONNECTIONS=1203,
+		ER_SET_CONSTANTS_ONLY=1204,
+		ER_LOCK_WAIT_TIMEOUT=1205,
+		ER_LOCK_TABLE_FULL=1206,
+		ER_READ_ONLY_TRANSACTION=1207,
+		ER_DROP_DB_WITH_READ_LOCK=1208,
+		ER_CREATE_DB_WITH_READ_LOCK=1209,
+		ER_WRONG_ARGUMENTS=1210,
+		ER_NO_PERMISSION_TO_CREATE_USER=1211,
+		ER_UNION_TABLES_IN_DIFFERENT_DIR=1212,
+		ER_LOCK_DEADLOCK=1213,
+		ER_TABLE_CANT_HANDLE_FULLTEXT=1214,
+		ER_CANNOT_ADD_FOREIGN=1215,
+		ER_NO_REFERENCED_ROW=1216,
+		ER_ROW_IS_REFERENCED=1217,
+		ER_CONNECT_TO_MASTER=1218,
+		ER_QUERY_ON_MASTER=1219,
+		ER_ERROR_WHEN_EXECUTING_COMMAND=1220,
+		ER_WRONG_USAGE=1221,
+		ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT=1222,
+		ER_CANT_UPDATE_WITH_READLOCK=1223,
+		ER_MIXING_NOT_ALLOWED=1224,
+		ER_DUP_ARGUMENT=1225,
+		ER_USER_LIMIT_REACHED=1226,
+		ER_SPECIFIC_ACCESS_DENIED_ERROR=1227,
+		ER_LOCAL_VARIABLE=1228,
+		ER_GLOBAL_VARIABLE=1229,
+		ER_NO_DEFAULT=1230,
+		ER_WRONG_VALUE_FOR_VAR=1231,
+		ER_WRONG_TYPE_FOR_VAR=1232,
+		ER_VAR_CANT_BE_READ=1233,
+		ER_CANT_USE_OPTION_HERE=1234,
+		ER_NOT_SUPPORTED_YET=1235,
+		ER_MASTER_FATAL_ERROR_READING_BINLOG=1236,
+		ER_SLAVE_IGNORED_TABLE=1237,
+		ER_INCORRECT_GLOBAL_LOCAL_VAR=1238,
+		CR_UNKNOWN_ERROR=1900,
+		CR_SOCKET_CREATE_ERROR=1901,
+		CR_CONNECTION_ERROR=1902,
+		CR_CONN_HOST_ERROR=1903,
+		CR_IPSOCK_ERROR	=1904,
+		CR_UNKNOWN_HOST	=1905,
+		CR_SERVER_GONE_ERROR=1906,
+		CR_VERSION_ERROR=1907,
+		CR_OUT_OF_MEMORY=1908,
+		CR_WRONG_HOST_INFO=1909,
+		CR_LOCALHOST_CONNECTION=1910,
+		CR_TCP_CONNECTION=1911,
+		CR_SERVER_HANDSHAKE_ERR=1912,
+		CR_SERVER_LOST=1913,
+		CR_COMMANDS_OUT_OF_SYNC=1914,
+		CR_NAMEDPIPE_CONNECTION=1915,
+		CR_NAMEDPIPEWAIT_ERROR=1916,
+		CR_NAMEDPIPEOPEN_ERROR=1917,
+		CR_NAMEDPIPESETSTATE_ERROR=1918,
+		CR_CANT_READ_CHARSET=1919,
+		CR_NET_PACKET_TOO_LARGE=1920,
+		CR_EMBEDDED_CONNECTION=1921,
+		CR_PROBE_SLAVE_STATUS=1922,
+		CR_PROBE_SLAVE_HOSTS=1923,
+		CR_PROBE_SLAVE_CONNECT=1924,
+		CR_PROBE_MASTER_CONNECT=1925,
+		CR_SSL_CONNECTION_ERROR=1926,
+		CR_MALFORMED_PACKET=1927,
+		CR_WRONG_LICENSE=1928,
+	};
+
+	enum{
+		ER_SET_IPLIST_NULL = 20001,
+		ER_SET_INSTANCE_PROPERTIES_ERR,
+		ER_KEY_TYPE,
+		ER_CC_VERSION_ERR,
+		ER_ROUTE_INFO_NULL,
+		ER_BID_VERSION_ERR,
+		ER_PORT_OUT_RANGE,
+		ER_STATUS_ERROR_VALUE,
+		ER_WEIGHT_ERROR_VALUE,
+		ER_IP_ERROR_VALUE,
+	};
+
+};
+
+#endif

+ 84 - 0
src/devel/cpp/examples/update/updatetest.cpp

@@ -0,0 +1,84 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string>
+#include<stdint.h>
+#include<unistd.h>
+
+#include "dtcapi.h"
+
+int main(int argc,char* argv[])
+{
+	int retCode = 0;
+	unsigned int uid;
+	unsigned int age;
+	std::string name;
+	std::string city;
+	std::string descr;
+
+	DTC::Server stServer; // 只要server不析构,后台会保持长连接
+	stServer.int_key(); // 声明key类型
+	stServer.set_table_name("t_dtc_example");//设置dtc的表名,与table.conf中tablename应该一样
+	stServer.set_address("192.168.214.62", "10009");//设置的dtc的ip和端口
+	stServer.SetTimeout(5); // 设置网络超时时间
+	stServer.set_accesskey("0000010284d9cfc2f395ce883a41d7ffc1bbcf4e"); // 设置访问码 AccessToken,在申请dtc实例的时候网站端会生成
+	
+	uid = atoi(argv[1]);
+	name = std::string(argv[2]);
+	city = std::string(argv[3]);
+	descr = std::string(argv[4]);
+	age = atoi(argv[5]);
+	DTC::UpdateRequest UpdateReq(&stServer);
+	retCode = UpdateReq.set_key(uid);
+	if(retCode != 0)
+	{
+		printf("update-req set key error: %d", retCode);
+		fflush(stdout);
+		return(-1);
+	}
+	retCode = UpdateReq.Set("name", name.c_str());
+	retCode = UpdateReq.Set("city", city.c_str());
+	retCode = UpdateReq.Set("descr", descr.c_str());
+	retCode = UpdateReq.Set("age", age);
+	if(retCode != 0)
+	{
+		printf("update-req set field error: %d", retCode);
+		fflush(stdout);
+		return(-1);
+	}
+
+	// do_execute & get result
+	DTC::Result stResult;
+	retCode = UpdateReq.do_execute(stResult);
+	printf("retCode:%d\n", retCode);
+	if(retCode == 0)
+	{
+		DTC::GetRequest getReq(&stServer);
+		getReq.set_key(uid);
+		if(retCode == 0)
+			retCode = getReq.need("uid");//设置需要select的字段,注意第一个key字段不能在这里出现
+		if(retCode == 0)
+			retCode = getReq.need("name");
+		if(retCode == 0)
+			retCode = getReq.need("city");
+		if(retCode == 0)
+			retCode = getReq.need("descr");
+		if(retCode == 0)
+			retCode = getReq.need("age");
+		if(retCode != 0)
+		{
+			printf("get-req set key or need error: %d", retCode);
+			fflush(stdout);
+			return(-1);
+		}
+
+		// do_execute & get result
+		retCode = getReq.do_execute(stResult);
+		retCode = stResult.fetch_row();//开始获取数据
+		printf("uid:%d\n", stResult.int_value("uid"));
+	    printf("name: %s\n", stResult.string_value("name"));//输出binary类型的数据
+		printf("city: %s\n", stResult.string_value("city"));
+		printf("descr: %s\n", stResult.binary_value("descr"));
+	    printf("age: %d\n", stResult.int_value("age"));//输出int类型的数据
+	}
+	return 0;
+}  

+ 149 - 0
src/devel/cpp/key_list.cc

@@ -0,0 +1,149 @@
+#include <errno.h>
+
+#include "mem_check.h"
+#include "protocol.h"
+#include "key_list.h"
+#include "dtc_error_code.h"
+
+int NCKeyValueList::key_value_max_ = 32;
+
+NCKeyInfo::~NCKeyInfo()
+{
+	for(int i = 0; i < 8; ++i) {
+		if(key_name_[i]) {
+			free(key_name_[i]);
+			key_name_[i] = NULL;
+		}
+	}
+}
+
+void NCKeyInfo::clear_key() 
+{
+	key_count_ = 0;
+	memset(key_type_, 0, sizeof(key_type_));
+	memset(key_name_, 0, sizeof(key_name_));
+	key_map_.clear();
+}
+int NCKeyInfo::get_key_index(const char *n) const
+{
+	namemap_t::const_iterator i = key_map_.find(n);
+	return i == key_map_.end() ? -1 : i->second;
+}
+
+int NCKeyInfo::add_key(const char* name, int type)
+{
+	switch(type) {
+		case DField::Signed:
+		case DField::String:
+			break;
+		default:
+			return -EC_BAD_KEY_TYPE;
+	}
+	if(get_key_index(name) >= 0) {
+		/**
+		 * return -EC_DUPLICATE_FIELD;
+		 * ignore duplicate key field name
+		 * because NCKeyInfo may be initialized by check_internal_service()
+		 * add again must be allowed for code compatibility
+		 */
+		return 0;
+	}
+	int cnt = get_key_fields_count();
+	if(cnt >= (int)(sizeof(key_type_)/sizeof(key_type_[0]))) return -EC_BAD_MULTIKEY;
+	char* localName = (char*)malloc(strlen(name)+1);
+	strcpy(localName, name);
+	key_name_[cnt] = localName;
+	key_map_[localName] = cnt;
+	key_type_[cnt] = type;
+	key_count_++;
+	return 0;
+}
+
+int NCKeyInfo::equal_key_name(const NCKeyInfo &other) const 
+{
+	int n = get_key_fields_count();
+	/* key field count mis-match */
+	if(other.get_key_fields_count() != n)
+		return 0;
+	/* key type mis-match */
+	if(memcmp(key_type_, other.key_type_, n)!=0)
+		return 0;
+	for(int i=0; i<n; i++) {
+		/* key name mis-match */
+		if(strcasecmp(key_name_[i], other.key_name_[i]) != 0)
+			return 0;
+	}
+	return 1;
+}
+
+void NCKeyValueList::unset_key(void) 
+{
+	if(key_count_) {
+		const int kn = get_key_fields_count();
+		for(int i=0; i<key_count_; i++) {
+			for(int j=0; j<kn; j++)
+				if(get_key_type(j) == DField::String || get_key_type(j) == DField::Binary)
+					FREE(Value(i, j).bin.ptr);
+	    }
+		FREE_CLEAR(val);
+		memset(fcount, 0, sizeof(fcount));
+		key_count_ = 0;
+	}
+}
+
+int NCKeyValueList::add_value(const char* name, const DTCValue &v, int type)
+{
+	const int kn = get_key_fields_count();
+
+	int col = keyinfo_->get_key_index(name);
+	if(col < 0 || col >= kn)
+		return -EC_BAD_KEY_NAME;
+
+	switch(get_key_type(col)) {
+		case DField::Signed:
+		case DField::Unsigned:
+			if(type != DField::Signed && type != DField::Unsigned)
+				return -EC_BAD_VALUE_TYPE;
+			break;
+		case DField::String:
+		case DField::Binary:
+			if(type != DField::String && type != DField::Binary)
+				return -EC_BAD_VALUE_TYPE;
+			if(v.bin.len > 255)
+				return -EC_KEY_OVERFLOW;
+			break;
+		default:
+			return -EC_BAD_KEY_TYPE;
+	}
+
+	int row = fcount[col];
+	if(row >= key_value_max_)
+	    /* key值太多 */
+		return -EC_TOO_MANY_KEY_VALUE; 
+	if(row >= key_count_) {
+		if(REALLOC(val, (key_count_+1)*kn*sizeof(DTCValue)) == NULL)
+			throw std::bad_alloc();
+		memset(&Value(row, 0), 0, kn*sizeof(DTCValue));
+		key_count_++;
+	}
+	DTCValue &slot = Value(row, col);
+	switch(get_key_type(col)) {
+		case DField::Signed:
+		case DField::Unsigned:
+			slot = v;
+			break;
+		
+		case DField::String:
+		case DField::Binary:
+			slot.bin.len = v.bin.len;
+			slot.bin.ptr =  (char *)MALLOC(v.bin.len+1);
+			if(slot.bin.ptr==NULL)
+				throw std::bad_alloc();
+			memcpy(slot.bin.ptr, v.bin.ptr, v.bin.len);
+			slot.bin.ptr[v.bin.len] = '\0';
+			break;
+	}
+	fcount[col]++;
+	return 0;
+}
+

+ 90 - 0
src/devel/cpp/key_list.h

@@ -0,0 +1,90 @@
+#ifndef __CHC_KEYLIST_H
+#define __CHC_KEYLIST_H
+
+#include <string.h>
+#include <map>
+#include <value.h>
+
+class NCKeyInfo 
+{
+private:
+    struct nocase
+	{
+		bool operator()(const char * const & a, const char * const & b) const
+		{
+			return strcasecmp(a, b) < 0; 
+			}
+	};
+	typedef std::map<const char *, int, nocase> namemap_t;
+private:
+	namemap_t key_map_;
+	char *key_name_[8];
+	uint8_t key_type_[8];
+	int key_count_;
+public:
+	NCKeyInfo() 
+	{
+		key_count_ = 0;
+		memset(key_type_, 0, sizeof(key_type_));
+		memset(key_name_, 0, sizeof(key_name_));
+	}
+	NCKeyInfo(const NCKeyInfo&that) 
+	{
+		key_count_ = that.key_count_;
+		memcpy(key_type_, that.key_type_, sizeof(key_type_));
+		memcpy(key_name_, that.key_name_, sizeof(key_name_));
+		for(int i=0; i<key_count_; i++)
+			key_map_[key_name_[i]] = i;
+	}
+	/* modified by neolv to fix char* name */
+	~NCKeyInfo();
+
+	/* zero is KeyField::None */
+	void clear_key();
+	int add_key(const char *name, int type);
+	int equal_key_name(const NCKeyInfo &other) const;
+	int get_key_index(const char *n) const;
+	const char *get_key_name(int n) const { return key_name_[n]; }
+	int get_key_type(int id) const { return key_type_[id]; }
+	int get_key_fields_count(void) const { return key_count_; }
+};
+
+class NCKeyValueList 
+{
+public:
+	static int key_value_max_;
+	NCKeyInfo *keyinfo_;
+	DTCValue *val;
+	int fcount[8];
+	int key_count_;
+public:
+	NCKeyValueList() : keyinfo_(NULL), val(NULL), key_count_(0) 
+	{
+		memset(fcount, 0, sizeof(fcount));
+	}
+	~NCKeyValueList() 
+	{
+		FREE_CLEAR(val);
+	}
+	int get_key_fields_count() const { return keyinfo_->get_key_fields_count(); }
+	int get_key_type(int id) const { return keyinfo_->get_key_type(id); }
+	int KeyCount() const { return key_count_; }
+	const char * get_key_name(int id) const { return keyinfo_->get_key_name(id); }
+
+	void unset_key();
+	int add_value(const char *, const DTCValue &, int);
+	DTCValue &Value(int row, int col) { return val[row*keyinfo_->get_key_fields_count()+col]; }
+	const DTCValue &Value(int row, int col) const { return val[row*keyinfo_->get_key_fields_count()+col]; }
+	DTCValue & operator()(int row, int col) { return Value(row, col); }
+	const DTCValue & operator()(int row, int col) const { return Value(row, col); }
+	int is_key_flat() const 
+	{
+		for(int i=1; i<keyinfo_->get_key_fields_count(); i++)
+			if(fcount[0] != fcount[i])
+				return 0;
+		return 1;
+	}
+};
+
+#endif
+

+ 11 - 0
src/devel/cpp/log_client.cc

@@ -0,0 +1,11 @@
+
+
+#include "dtcapi.h"
+#include <log/log.cc>
+
+__EXPORT
+
+__attribute__((format(printf,5,6)))
+__attribute__((__alias__("write_log")))
+;
+

+ 3 - 0
src/devel/cpp/readme.txt

@@ -0,0 +1,3 @@
+注意事项:
+1.auto_dtcc++.sh 该脚本是需要root权限去执行的,它的作用是将dtc sdk 的动态库
+放置在 /usr/lib 目录下,并且执行命令 ldconfig 使配置生效

+ 34 - 0
src/devel/cpp/somain.c

@@ -0,0 +1,34 @@
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <unistd.h>
+#include <version.h>
+#include <compiler.h>
+
+const char __invoke_dynamic_linker__[]
+__attribute__ ((section (".interp")))
+__HIDDEN
+=
+#if __x86_64__
+	"/lib64/ld-linux-x86-64.so.2"
+#else
+	"/lib/ld-linux.so.2"
+#endif
+	;
+
+__HIDDEN
+void _so_start(char *arg1,...) {
+#define BANNER "DTC client API v" DTC_VERSION_DETAIL "\n" \
+	"  - TCP connection supported\n" \
+	"  - UDP connection supported\n" \
+	"  - UNIX stream connection supported\n" \
+	"  - embeded threading connection supported\n" \
+	"  - protocol packet encode/decode interface supported\n" \
+	"  - async do_execute (except embeded threading) supported \n"
+
+	int unused = 0;
+	if(unused == 0)
+		unused = write(1, BANNER, sizeof(BANNER)-1);
+	_exit(0);
+}
+

+ 201 - 0
src/devel/cpp/udppool.cc

@@ -0,0 +1,201 @@
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <unistd.h>
+#include <alloca.h>
+#include "udppool.h"
+#include "log/log.h"
+
+static unsigned int bindip = 0xFFFFFFFF;
+
+unsigned int get_bindip()  
+{
+    int i;
+    int n = 0;
+    struct ifconf ifc;
+    struct ifreq *ifr = NULL;
+    ifc.ifc_len = 0;
+    ifc.ifc_req = NULL;
+    const char *name = getenv("DTCAPI_UDP_INTERFACE");  
+    if (name == NULL || name[0] == 0 || strcmp(name, "*") == 0)
+	    return 0;
+
+    int fd = socket(AF_INET, SOCK_DGRAM, 0);  
+    if (fd < 0)
+        return 0;
+
+    if (ioctl(fd, SIOCGIFCONF, &ifc) == 0) {  
+        ifr = (struct ifreq *)alloca(ifc.ifc_len > 128 ? ifc.ifc_len : 128);  
+        ifc.ifc_req = ifr;  
+        if (ioctl(fd, SIOCGIFCONF, &ifc) == 0)  
+            n = ifc.ifc_len / sizeof(struct ifreq);  
+    }
+    close(fd);
+    for (i = 0; i < n; i++) {  
+        if (strncmp(ifr[i].ifr_name, name, sizeof(ifr[i].ifr_name)) != 0)  
+            continue;
+        if (ifr[i].ifr_addr.sa_family == AF_INET)
+            return ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr.s_addr;
+    }
+    return 0;
+}
+
+static int create_port_ipv4()  
+{
+    int fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (bindip == 0xFFFFFFFF)
+        bindip = get_bindip();
+    if (bindip != 0) {
+        struct sockaddr_in addr;
+        memset(&addr, 0, sizeof(addr));
+        addr.sin_family = AF_INET;
+        addr.sin_addr.s_addr = bindip;
+        if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+            close(fd);
+            return -1;
+        }
+    }
+    return fd;
+}
+
+static int create_port_ipv6() 
+{
+    int fd = socket(AF_INET6, SOCK_DGRAM, 0);
+    return fd;
+}
+
+static int create_port_unix() 
+{
+    int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+    struct sockaddr_un addr;
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path),
+		    "@dtcapi-global-%d-%d-%d", getpid(), fd, (int)time(NULL));
+    socklen_t len = SUN_LEN(&addr);
+    addr.sun_path[0] = 0;  
+    if (bind(fd, (const struct sockaddr *)&addr, len) < 0) {
+	    close(fd);
+	    return -1;
+    }
+    return fd;
+}
+
+/* this destructor only called when unloading libdtc.so */
+NCUdpPortList::~NCUdpPortList()
+{
+	if (pthread_mutex_lock(&lock_) == 0) {
+		stop_ = 1;
+		while (list_node_ != NULL) {
+			NCUdpPort *port = list_node_;
+			list_node_ = port->next;
+			delete port;
+		}
+		pthread_mutex_unlock(&lock_);
+	}
+}
+
+NCUdpPortList* NCUdpPortList::get_port_list(int sa_family)   
+{
+    switch(sa_family) {
+        case AF_INET:
+            static NCUdpPortList ipv4List = { 0,
+                AF_INET,
+                create_port_ipv4,
+                PTHREAD_MUTEX_INITIALIZER,
+                NULL };
+            return &ipv4List;
+        case AF_INET6:
+            static NCUdpPortList ipv6List = { 0, 
+                AF_INET6, 
+                create_port_ipv6, 
+                PTHREAD_MUTEX_INITIALIZER, 
+                NULL };
+            return &ipv6List;
+        case AF_UNIX:
+            static NCUdpPortList unixList = { 0, 
+                AF_UNIX, 
+                create_port_unix, 
+                PTHREAD_MUTEX_INITIALIZER, 
+                NULL };
+            return &unixList;
+	}
+	return NULL;
+}
+
+NCUdpPort* NCUdpPortList::get_all_port()
+{
+    NCUdpPort *port = NULL;
+
+    if (pthread_mutex_lock(&lock_) == 0) {
+        if (list_node_ != NULL) {
+            port = list_node_;
+            list_node_ = port->next;
+        }
+        pthread_mutex_unlock(&lock_);
+    } else {
+        log4cplus_error("api mutex_lock error,may have fd leak");
+    }
+    if (port != NULL) {
+        if (getpid() == port->pid)
+            port->sn++;
+        else {
+            delete port;
+            port = NULL;
+        }
+    }
+    if (port == NULL) {
+        int fd = newport();
+        if (fd > 0) {
+            port = new NCUdpPort;
+            port->fd = fd;
+            unsigned int seed = fd + (long)port + (long) & port + (long)pthread_self() + (long)port;
+            port->sn = rand_r(&seed);
+            port->timeout = -1;
+            port->pid = getpid();
+            port->sa_family = sa_family_;
+        }
+    }
+    return port;
+}
+
+void NCUdpPortList::put_family_list_node(NCUdpPort *port)  
+{
+    if (this != NULL && pthread_mutex_lock(&lock_) == 0) {
+        if(stop_) {
+            /* always delete port after unloading process */
+            port->delete_port();
+        } else {
+            port->next = list_node_;
+            list_node_ = port;
+        }
+        pthread_mutex_unlock(&lock_);
+    } else {
+        port->delete_port();
+    }
+}
+
+NCUdpPort *NCUdpPort::get_family_port(int sa_family)  
+{
+    NCUdpPortList *portList = NCUdpPortList::get_port_list(sa_family);
+    if(portList == NULL)
+	    return NULL;
+    return portList->get_all_port();
+}
+
+void NCUdpPort::put_list_node()
+{
+    NCUdpPortList *portList = NCUdpPortList::get_port_list(sa_family);
+    portList->put_family_list_node(this);
+}
+
+void NCUdpPort::delete_port() 
+{
+    delete this;
+}
+
+

+ 65 - 0
src/devel/cpp/udppool.h

@@ -0,0 +1,65 @@
+#include <stdlib.h>
+
+struct NCPort
+{
+public:
+    uint64_t sn;
+    int fd;  
+    /* the timeout this socket is */
+    int timeout;
+
+public:
+    NCPort()
+    {
+        sn = 0;
+        fd = -1;
+        timeout = -1;
+    }
+
+    NCPort(const NCPort &that)
+    {
+        sn = that.sn;
+        fd = that.fd;
+        timeout = that.timeout;
+    }
+
+    ~NCPort()
+    {
+        if (fd >= 0) 
+            close(fd);
+    }
+};
+
+struct NCUdpPort : public NCPort
+{
+public:
+    int sa_family;
+    pid_t pid;
+    NCUdpPort* next;
+
+public:
+    NCUdpPort() { pid = -1; };
+
+public:
+    static NCUdpPort *get_family_port(int sa_family);
+    /* put back cache */
+    void put_list_node();  
+    void delete_port();
+};
+
+class NCUdpPortList 
+{
+public:
+	int stop_;
+	int sa_family_;
+	int (*newport)(void);
+	pthread_mutex_t lock_;
+	NCUdpPort *list_node_;  
+public:
+	~NCUdpPortList(void);
+public:
+	NCUdpPort *get_all_port(void);  
+	void put_family_list_node(NCUdpPort *);
+    static NCUdpPortList* get_port_list(int sa_family);
+};
+

+ 5 - 0
src/libs/Makefile

@@ -0,0 +1,5 @@
+include ../Make.conf
+
+SUBDIRS := common stat
+
+include ../Make.rules

+ 750 - 0
src/libs/cJSON/cJSON.c

@@ -0,0 +1,750 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include "cJSON.h"
+
+static const char *ep;
+
+const char *cJSON_GetErrorPtr(void) {return ep;}
+
+static int cJSON_strcasecmp(const char *s1,const char *s2)
+{
+	if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
+	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	if(*s1 == 0)	return 0;
+	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+}
+
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
+
+static char* cJSON_strdup(const char* str)
+{
+      size_t len;
+      char* copy;
+
+      len = strlen(str) + 1;
+      if (!(copy = (char*)cJSON_malloc(len))) return 0;
+      memcpy(copy,str,len);
+      return copy;
+}
+
+void cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+    if (!hooks) { /* Reset hooks */
+        cJSON_malloc = malloc;
+        cJSON_free = free;
+        return;
+    }
+
+	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
+	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free;
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(void)
+{
+	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+	if (node) memset(node,0,sizeof(cJSON));
+	return node;
+}
+
+/* Delete a cJSON structure. */
+void cJSON_Delete(cJSON *c)
+{
+	cJSON *next;
+	while (c)
+	{
+		next=c->next;
+		if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
+		if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
+		if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
+		cJSON_free(c);
+		c=next;
+	}
+}
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item,const char *num)
+{
+	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
+
+	if (*num=='-') sign=-1,num++;	/* Has sign? */
+	if (*num=='0') num++;			/* is zero */
+	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */
+	if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */
+	if (*num=='e' || *num=='E')		/* Exponent? */
+	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */
+		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */
+	}
+
+	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */
+	
+	item->valuedouble=n;
+	item->valueint=(int)n;
+	item->type=cJSON_Number;
+	return num;
+}
+
+static int pow2gt (int x)	{	--x;	x|=x>>1;	x|=x>>2;	x|=x>>4;	x|=x>>8;	x|=x>>16;	return x+1;	}
+
+typedef struct {char *buffer; int length; int offset; } printbuffer;
+
+static char* ensure(printbuffer *p,int needed)
+{
+	char *newbuffer;int newsize;
+	if (!p || !p->buffer) return 0;
+	needed+=p->offset;
+	if (needed<=p->length) return p->buffer+p->offset;
+
+	newsize=pow2gt(needed);
+	newbuffer=(char*)cJSON_malloc(newsize);
+	if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
+	if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
+	cJSON_free(p->buffer);
+	p->length=newsize;
+	p->buffer=newbuffer;
+	return newbuffer+p->offset;
+}
+
+static int update(printbuffer *p)
+{
+	char *str;
+	if (!p || !p->buffer) return 0;
+	str=p->buffer+p->offset;
+	return p->offset+strlen(str);
+}
+
+/* Render the number nicely from the given item into a string. */
+static char *print_number(cJSON *item,printbuffer *p)
+{
+	char *str=0;
+	double d=item->valuedouble;
+	if (d==0)
+	{
+		if (p)	str=ensure(p,2);
+		else	str=(char*)cJSON_malloc(2);	/* special case for 0. */
+		if (str) strcpy(str,"0");
+	}
+	else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
+	{
+		if (p)	str=ensure(p,21);
+		else	str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */
+		if (str)	sprintf(str,"%d",item->valueint);
+	}
+	else
+	{
+		if (p)	str=ensure(p,64);
+		else	str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */
+		if (str)
+		{
+			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
+			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)			sprintf(str,"%e",d);
+			else												sprintf(str,"%f",d);
+		}
+	}
+	return str;
+}
+
+static unsigned parse_hex4(const char *str)
+{
+	unsigned h=0;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	return h;
+}
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *parse_string(cJSON *item,const char *str)
+{
+	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
+	if (*str!='\"') {ep=str;return 0;}	/* not a string! */
+	
+	while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;	/* Skip escaped quotes. */
+	
+	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */
+	if (!out) return 0;
+	
+	ptr=str+1;ptr2=out;
+	while (*ptr!='\"' && *ptr)
+	{
+		if (*ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
+			ptr++;
+			switch (*ptr)
+			{
+				case 'b': *ptr2++='\b';	break;
+				case 'f': *ptr2++='\f';	break;
+				case 'n': *ptr2++='\n';	break;
+				case 'r': *ptr2++='\r';	break;
+				case 't': *ptr2++='\t';	break;
+				case 'u':	 /* transcode utf16 to utf8. */
+					uc=parse_hex4(ptr+1);ptr+=4;	/* get the unicode char. */
+
+					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/
+
+					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/
+					{
+						if (ptr[1]!='\\' || ptr[2]!='u')	break;	/* missing second-half of surrogate.	*/
+						uc2=parse_hex4(ptr+3);ptr+=6;
+						if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/
+						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
+					}
+
+					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
+					
+					switch (len) {
+						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 1: *--ptr2 =(uc | firstByteMark[len]);
+					}
+					ptr2+=len;
+					break;
+				default:  *ptr2++=*ptr; break;
+			}
+			ptr++;
+		}
+	}
+	*ptr2=0;
+	if (*ptr=='\"') ptr++;
+	item->valuestring=out;
+	item->type=cJSON_String;
+	return ptr;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static char *print_string_ptr(const char *str,printbuffer *p)
+{
+	const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
+	
+	for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
+	if (!flag)
+	{
+		len=ptr-str;
+		if (p) out=ensure(p,len+3);
+		else		out=(char*)cJSON_malloc(len+3);
+		if (!out) return 0;
+		ptr2=out;*ptr2++='\"';
+		strcpy(ptr2,str);
+		ptr2[len]='\"';
+		ptr2[len+1]=0;
+		return out;
+	}
+	
+	if (!str)
+	{
+		if (p)	out=ensure(p,3);
+		else	out=(char*)cJSON_malloc(3);
+		if (!out) return 0;
+		strcpy(out,"\"\"");
+		return out;
+	}
+	ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
+	
+	if (p)	out=ensure(p,len+3);
+	else	out=(char*)cJSON_malloc(len+3);
+	if (!out) return 0;
+
+	ptr2=out;ptr=str;
+	*ptr2++='\"';
+	while (*ptr)
+	{
+		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
+			*ptr2++='\\';
+			switch (token=*ptr++)
+			{
+				case '\\':	*ptr2++='\\';	break;
+				case '\"':	*ptr2++='\"';	break;
+				case '\b':	*ptr2++='b';	break;
+				case '\f':	*ptr2++='f';	break;
+				case '\n':	*ptr2++='n';	break;
+				case '\r':	*ptr2++='r';	break;
+				case '\t':	*ptr2++='t';	break;
+				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */
+			}
+		}
+	}
+	*ptr2++='\"';*ptr2++=0;
+	return out;
+}
+/* Invote print_string_ptr (which is useful) on an item. */
+static char *print_string(cJSON *item,printbuffer *p)	{return print_string_ptr(item->valuestring,p);}
+
+/* Predeclare these prototypes. */
+static const char *parse_value(cJSON *item,const char *value);
+static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
+static const char *parse_array(cJSON *item,const char *value);
+static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
+static const char *parse_object(cJSON *item,const char *value);
+static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
+{
+	const char *end=0;
+	cJSON *c=cJSON_New_Item();
+	ep=0;
+	if (!c) return 0;       /* memory fail */
+
+	end=parse_value(c,skip(value));
+	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */
+
+	/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+	if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
+	if (return_parse_end) *return_parse_end=end;
+	return c;
+}
+/* Default options for cJSON_Parse */
+cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
+
+/* Render a cJSON item/entity/structure to text. */
+char *cJSON_Print(cJSON *item)				{return print_value(item,0,1,0);}
+char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0,0);}
+
+char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
+{
+	printbuffer p;
+	p.buffer=(char*)cJSON_malloc(prebuffer);
+	p.length=prebuffer;
+	p.offset=0;
+	return print_value(item,0,fmt,&p);
+	return p.buffer;
+}
+
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *parse_value(cJSON *item,const char *value)
+{
+	if (!value)						return 0;	/* Fail on null. */
+	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; }
+	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; }
+	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; }
+	if (*value=='\"')				{ return parse_string(item,value); }
+	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); }
+	if (*value=='[')				{ return parse_array(item,value); }
+	if (*value=='{')				{ return parse_object(item,value); }
+
+	ep=value;return 0;	/* failure. */
+}
+
+/* Render a value to text. */
+static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
+{
+	char *out=0;
+	if (!item) return 0;
+	if (p)
+	{
+		switch ((item->type)&255)
+		{
+			case cJSON_NULL:	{out=ensure(p,5);	if (out) strcpy(out,"null");	break;}
+			case cJSON_False:	{out=ensure(p,6);	if (out) strcpy(out,"false");	break;}
+			case cJSON_True:	{out=ensure(p,5);	if (out) strcpy(out,"true");	break;}
+			case cJSON_Number:	out=print_number(item,p);break;
+			case cJSON_String:	out=print_string(item,p);break;
+			case cJSON_Array:	out=print_array(item,depth,fmt,p);break;
+			case cJSON_Object:	out=print_object(item,depth,fmt,p);break;
+		}
+	}
+	else
+	{
+		switch ((item->type)&255)
+		{
+			case cJSON_NULL:	out=cJSON_strdup("null");	break;
+			case cJSON_False:	out=cJSON_strdup("false");break;
+			case cJSON_True:	out=cJSON_strdup("true"); break;
+			case cJSON_Number:	out=print_number(item,0);break;
+			case cJSON_String:	out=print_string(item,0);break;
+			case cJSON_Array:	out=print_array(item,depth,fmt,0);break;
+			case cJSON_Object:	out=print_object(item,depth,fmt,0);break;
+		}
+	}
+	return out;
+}
+
+/* Build an array from input text. */
+static const char *parse_array(cJSON *item,const char *value)
+{
+	cJSON *child;
+	if (*value!='[')	{ep=value;return 0;}	/* not an array! */
+
+	item->type=cJSON_Array;
+	value=skip(value+1);
+	if (*value==']') return value+1;	/* empty array. */
+
+	item->child=child=cJSON_New_Item();
+	if (!item->child) return 0;		 /* memory fail */
+	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */
+	if (!value) return 0;
+
+	while (*value==',')
+	{
+		cJSON *new_item;
+		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */
+		child->next=new_item;new_item->prev=child;child=new_item;
+		value=skip(parse_value(child,skip(value+1)));
+		if (!value) return 0;	/* memory fail */
+	}
+
+	if (*value==']') return value+1;	/* end of array */
+	ep=value;return 0;	/* malformed. */
+}
+
+/* Render an array to text */
+static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
+{
+	char **entries;
+	char *out=0,*ptr,*ret;int len=5;
+	cJSON *child=item->child;
+	int numentries=0,i=0,fail=0;
+	size_t tmplen=0;
+	
+	/* How many entries in the array? */
+	while (child) numentries++,child=child->next;
+	/* Explicitly handle numentries==0 */
+	if (!numentries)
+	{
+		if (p)	out=ensure(p,3);
+		else	out=(char*)cJSON_malloc(3);
+		if (out) strcpy(out,"[]");
+		return out;
+	}
+
+	if (p)
+	{
+		/* Compose the output array. */
+		i=p->offset;
+		ptr=ensure(p,1);if (!ptr) return 0;	*ptr='[';	p->offset++;
+		child=item->child;
+		while (child && !fail)
+		{
+			print_value(child,depth+1,fmt,p);
+			p->offset=update(p);
+			if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;}
+			child=child->next;
+		}
+		ptr=ensure(p,2);if (!ptr) return 0;	*ptr++=']';*ptr=0;
+		out=(p->buffer)+i;
+	}
+	else
+	{
+		/* Allocate an array to hold the values for each */
+		entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+		if (!entries) return 0;
+		memset(entries,0,numentries*sizeof(char*));
+		/* Retrieve all the results: */
+		child=item->child;
+		while (child && !fail)
+		{
+			ret=print_value(child,depth+1,fmt,0);
+			entries[i++]=ret;
+			if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
+			child=child->next;
+		}
+		
+		/* If we didn't fail, try to malloc the output string */
+		if (!fail)	out=(char*)cJSON_malloc(len);
+		/* If that fails, we fail. */
+		if (!out) fail=1;
+
+		/* Handle failure. */
+		if (fail)
+		{
+			for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
+			cJSON_free(entries);
+			return 0;
+		}
+		
+		/* Compose the output array. */
+		*out='[';
+		ptr=out+1;*ptr=0;
+		for (i=0;i<numentries;i++)
+		{
+			tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
+			if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
+			cJSON_free(entries[i]);
+		}
+		cJSON_free(entries);
+		*ptr++=']';*ptr++=0;
+	}
+	return out;	
+}
+
+/* Build an object from the text. */
+static const char *parse_object(cJSON *item,const char *value)
+{
+	cJSON *child;
+	if (*value!='{')	{ep=value;return 0;}	/* not an object! */
+	
+	item->type=cJSON_Object;
+	value=skip(value+1);
+	if (*value=='}') return value+1;	/* empty array. */
+	
+	item->child=child=cJSON_New_Item();
+	if (!item->child) return 0;
+	value=skip(parse_string(child,skip(value)));
+	if (!value) return 0;
+	child->string=child->valuestring;child->valuestring=0;
+	if (*value!=':') {ep=value;return 0;}	/* fail! */
+	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
+	if (!value) return 0;
+	
+	while (*value==',')
+	{
+		cJSON *new_item;
+		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */
+		child->next=new_item;new_item->prev=child;child=new_item;
+		value=skip(parse_string(child,skip(value+1)));
+		if (!value) return 0;
+		child->string=child->valuestring;child->valuestring=0;
+		if (*value!=':') {ep=value;return 0;}	/* fail! */
+		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
+		if (!value) return 0;
+	}
+	
+	if (*value=='}') return value+1;	/* end of array */
+	ep=value;return 0;	/* malformed. */
+}
+
+/* Render an object to text. */
+static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
+{
+	char **entries=0,**names=0;
+	char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
+	cJSON *child=item->child;
+	int numentries=0,fail=0;
+	size_t tmplen=0;
+	/* Count the number of entries. */
+	while (child) numentries++,child=child->next;
+	/* Explicitly handle empty object case */
+	if (!numentries)
+	{
+		if (p) out=ensure(p,fmt?depth+4:3);
+		else	out=(char*)cJSON_malloc(fmt?depth+4:3);
+		if (!out)	return 0;
+		ptr=out;*ptr++='{';
+		if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
+		*ptr++='}';*ptr++=0;
+		return out;
+	}
+	if (p)
+	{
+		/* Compose the output: */
+		i=p->offset;
+		len=fmt?2:1;	ptr=ensure(p,len+1);	if (!ptr) return 0;
+		*ptr++='{';	if (fmt) *ptr++='\n';	*ptr=0;	p->offset+=len;
+		child=item->child;depth++;
+		while (child)
+		{
+			if (fmt)
+			{
+				ptr=ensure(p,depth);	if (!ptr) return 0;
+				for (j=0;j<depth;j++) *ptr++='\t';
+				p->offset+=depth;
+			}
+			print_string_ptr(child->string,p);
+			p->offset=update(p);
+			
+			len=fmt?2:1;
+			ptr=ensure(p,len);	if (!ptr) return 0;
+			*ptr++=':';if (fmt) *ptr++='\t';
+			p->offset+=len;
+			
+			print_value(child,depth,fmt,p);
+			p->offset=update(p);
+
+			len=(fmt?1:0)+(child->next?1:0);
+			ptr=ensure(p,len+1); if (!ptr) return 0;
+			if (child->next) *ptr++=',';
+			if (fmt) *ptr++='\n';*ptr=0;
+			p->offset+=len;
+			child=child->next;
+		}
+		ptr=ensure(p,fmt?(depth+1):2);	 if (!ptr) return 0;
+		if (fmt)	for (i=0;i<depth-1;i++) *ptr++='\t';
+		*ptr++='}';*ptr=0;
+		out=(p->buffer)+i;
+	}
+	else
+	{
+		/* Allocate space for the names and the objects */
+		entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+		if (!entries) return 0;
+		names=(char**)cJSON_malloc(numentries*sizeof(char*));
+		if (!names) {cJSON_free(entries);return 0;}
+		memset(entries,0,sizeof(char*)*numentries);
+		memset(names,0,sizeof(char*)*numentries);
+
+		/* Collect all the results into our arrays: */
+		child=item->child;depth++;if (fmt) len+=depth;
+		while (child)
+		{
+			names[i]=str=print_string_ptr(child->string,0);
+			entries[i++]=ret=print_value(child,depth,fmt,0);
+			if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
+			child=child->next;
+		}
+		
+		/* Try to allocate the output string */
+		if (!fail)	out=(char*)cJSON_malloc(len);
+		if (!out) fail=1;
+
+		/* Handle failure */
+		if (fail)
+		{
+			for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
+			cJSON_free(names);cJSON_free(entries);
+			return 0;
+		}
+		
+		/* Compose the output: */
+		*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
+		for (i=0;i<numentries;i++)
+		{
+			if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
+			tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
+			*ptr++=':';if (fmt) *ptr++='\t';
+			strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
+			if (i!=numentries-1) *ptr++=',';
+			if (fmt) *ptr++='\n';*ptr=0;
+			cJSON_free(names[i]);cJSON_free(entries[i]);
+		}
+		
+		cJSON_free(names);cJSON_free(entries);
+		if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
+		*ptr++='}';*ptr++=0;
+	}
+	return out;	
+}
+
+/* Get Array size/item / object item. */
+int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
+cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
+cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
+/* Utility for handling references. */
+static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
+
+/* Add item to array/object. */
+void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
+void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
+void   cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
+void	cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)						{cJSON_AddItemToArray(array,create_reference(item));}
+void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)	{cJSON_AddItemToObject(object,string,create_reference(item));}
+
+cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
+	if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
+void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
+cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
+void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
+
+/* Replace array/object items with new ones. */
+void   cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}
+	newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
+void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
+	newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
+	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
+void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
+
+/* Create basic types: */
+cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
+cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
+cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
+cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
+cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
+cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
+cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
+cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
+
+/* Create Arrays: */
+cJSON *cJSON_CreateIntArray(const int *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateFloatArray(const float *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateDoubleArray(const double *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateStringArray(const char **strings,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+
+/* Duplication */
+cJSON *cJSON_Duplicate(cJSON *item,int recurse)
+{
+	cJSON *newitem,*cptr,*nptr=0,*newchild;
+	/* Bail on bad ptr */
+	if (!item) return 0;
+	/* Create new item */
+	newitem=cJSON_New_Item();
+	if (!newitem) return 0;
+	/* Copy over all vars */
+	newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
+	if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}}
+	if (item->string)		{newitem->string=cJSON_strdup(item->string);			if (!newitem->string)		{cJSON_Delete(newitem);return 0;}}
+	/* If non-recursive, then we're done! */
+	if (!recurse) return newitem;
+	/* Walk the ->next chain for the child. */
+	cptr=item->child;
+	while (cptr)
+	{
+		newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */
+		if (!newchild) {cJSON_Delete(newitem);return 0;}
+		if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */
+		else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */
+		cptr=cptr->next;
+	}
+	return newitem;
+}
+
+void cJSON_Minify(char *json)
+{
+	char *into=json;
+	while (*json)
+	{
+		if (*json==' ') json++;
+		else if (*json=='\t') json++;	/* Whitespace characters. */
+		else if (*json=='\r') json++;
+		else if (*json=='\n') json++;
+		else if (*json=='/' && json[1]=='/')  while (*json && *json!='\n') json++;	/* double-slash comments, to end of line. */
+		else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;}	/* multiline comments. */
+		else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */
+		else *into++=*json++;			/* All other characters. */
+	}
+	*into=0;	/* and null-terminate. */
+}

+ 150 - 0
src/libs/cJSON/cJSON.h

@@ -0,0 +1,150 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+ 
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+ 
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+ 
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+	
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON {
+	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+
+	int type;					/* The type of the item, as above. */
+
+	char *valuestring;			/* The item's string, if type==cJSON_String */
+	int valueint;				/* The item's number, if type==cJSON_Number */
+	double valuedouble;			/* The item's number, if type==cJSON_Number */
+
+	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+} cJSON;
+
+typedef struct cJSON_Hooks {
+      void *(*malloc_fn)(size_t sz);
+      void (*free_fn)(void *ptr);
+} cJSON_Hooks;
+
+/* Supply malloc, realloc and free functions to cJSON */
+extern void cJSON_InitHooks(cJSON_Hooks* hooks);
+
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+extern char  *cJSON_Print(cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+extern char  *cJSON_PrintUnformatted(cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
+/* Delete a cJSON entity and all subentities. */
+extern void   cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int	  cJSON_GetArraySize(cJSON *array);
+/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+extern const char *cJSON_GetErrorPtr(void);
+	
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull(void);
+extern cJSON *cJSON_CreateTrue(void);
+extern cJSON *cJSON_CreateFalse(void);
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray(void);
+extern cJSON *cJSON_CreateObject(void);
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
+extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
+extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
+
+/* Append item to the specified array/object. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
+extern void	cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);	/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
+extern void   cJSON_DeleteItemFromArray(cJSON *array,int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
+extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string);
+	
+/* Update array items. */
+extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem);	/* Shifts pre-existing items to the right. */
+extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+
+/* Duplicate a cJSON item */
+extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+need to be released. With recurse!=0, it will duplicate any children connected to the item.
+The item->next and ->prev pointers are always zero on return from Duplicate. */
+
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
+
+extern void cJSON_Minify(char *json);
+
+/* Macros for creating things quickly. */
+#define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
+#define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+#define cJSON_SetNumberValue(object,val)		((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 96 - 0
src/libs/common/Condition.h

@@ -0,0 +1,96 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __DTC_CONDITION_H__
+#define __DTC_CONDITION_H__
+
+#include "algorithm/non_copyable.h"
+
+class condition : private noncopyable {
+    public:
+	condition(void)
+	{
+		pthread_mutex_init(&m_lock, NULL);
+		pthread_cond_init(&m_cond, NULL);
+	}
+
+	~condition(void)
+	{
+		pthread_mutex_destroy(&m_lock);
+		pthread_cond_destroy(&m_cond);
+	}
+
+	void notify_one(void)
+	{
+		pthread_cond_signal(&m_cond);
+	}
+	void notify_all(void)
+	{
+		pthread_cond_broadcast(&m_cond);
+	}
+
+	void wait(void)
+	{
+		pthread_cond_wait(&m_cond, &m_lock);
+	}
+
+	void lock(void)
+	{
+		pthread_mutex_lock(&m_lock);
+	}
+
+	void unlock(void)
+	{
+		pthread_mutex_unlock(&m_lock);
+	}
+
+    private:
+	pthread_cond_t m_cond;
+	pthread_mutex_t m_lock;
+};
+
+class copedEnterCritical {
+    public:
+	copedEnterCritical(condition &c) : m_cond(c)
+	{
+		m_cond.lock();
+	}
+
+	~copedEnterCritical(void)
+	{
+		m_cond.unlock();
+	}
+
+    private:
+	condition &m_cond;
+};
+
+class copedLeaveCritical {
+    public:
+	copedLeaveCritical(condition &c) : m_cond(c)
+	{
+		m_cond.unlock();
+	}
+
+	~copedLeaveCritical(void)
+	{
+		m_cond.lock();
+	}
+
+    private:
+	condition &m_cond;
+};
+
+#endif //__DTC_CONDITION_H__

+ 44 - 0
src/libs/common/Makefile

@@ -0,0 +1,44 @@
+LIB_PATH = ../..
+
+include ../../Make.conf
+
+target = libcommon.a libcommon_nopic.a
+CFLAGS+=-I../../devel/cpp -I. -I../../daemons -I../stat $(LOG4CPLUS_INC) $(ZINC) -std=gnu++11 $(YAML_CPP_INC)
+LIBS = $(Z_LIB)  $(LOG4CPLUS_LIB) $(YAML_CPP_LIB) 
+SRC_FOLDER := $(shell find . -maxdepth 1 -type d)
+VPATH = ../../daemons $(basename $(patsubst ./%, %/, $(SRC_FOLDER)))
+GIT_VERSION=$(shell git log | head -n 4 | grep "commit" | cut -d " " -f 2 | cut -c 1-7)
+ifeq "$(GIT_VERSION)a" "a"
+	GIT_REVISION = "(unknown)"
+endif
+$(shell sed -i '11s/"[^"]*"/"$(GIT_VERSION)"/' version.h)
+
+filelist := md5 value decode encode field section table_def \
+	packet_base packet_server packet_result \
+	task_const task_base task_pkey task_server task_copy task_request task_api \
+	poller timer_list config version system_lock log \
+	shmem mem_check dbconfig dbconfig_tdef hotbackup_table_def \
+	daemon daemon_wait proc_title thread poller_base poll_thread_group thread_cpu_stat \
+	buffer localip \
+	key_helper bitsop socket_addr socket_bind blacklist blacklist_unit \
+	multi_request task_multi_unit \
+	connector_client data_connector_ask_chain connector_group \
+	listener listener_pool decoder_base \
+	client_sync client_async client_unit client_dgram  \
+	plugin_request plugin_mgr plugin_dgram plugin_sync \
+	plugin_worker plugin_unit plugin_listener_pool \
+	plugin_global plugin_decoder plugin_timer dtc_global\
+	compress client_resource_pool \
+	new_hash remote_dtc_ask_answer_chain consistent_hash_selector chash\
+	file_backed_key_set markup_stl parse_cluster_config key_route_ask_chain \
+	agent_client job_entrance_ask_chain agent_listener agent_listen_pool agent_unit agent_receiver agent_sender \
+	agent_multi_request plugin_proxy_mgr plugin_proxy_listener_pool fork hotback_task table_def_manager
+
+libcommon_objs := $(filelist:%=%_pic.o)
+%_pic.o: CFLAGS  += -pthread -fPIC 
+
+libcommon_nopic_objs := $(filelist:%=%.o)
+%.o: CFLAGS  += -pthread
+
+include ../../Make.rules
+

+ 354 - 0
src/libs/common/agent/agent_client.cc

@@ -0,0 +1,354 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <errno.h>
+
+#include "agent/agent_client.h"
+#include "job_entrance_ask_chain.h"
+#include "agent_receiver.h"
+#include "agent_sender.h"
+#include "log/log.h"
+#include "poll/poller_base.h"
+#include "agent/agent_multi_request.h"
+#include "packet/packet.h"
+#include "task/task_request.h"
+#include "agent/agent_multi_request.h"
+#include "stat_dtc.h"
+#include "table/table_def_manager.h"
+
+extern DTCTableDefinition *g_table_def[];
+
+static StatCounter stat_agent_accept_count;
+static StatCounter stat_agent_cur_conn_count;
+static StatCounter stat_agent_expore_count;
+static StatCounter stat_task_client_timeout;
+
+AgentResultQueue::~AgentResultQueue()
+{
+	Packet *p;
+
+	while (NULL != (p = packet.Pop())) {
+		p->free_result_buff();
+		delete p;
+	}
+}
+
+class AgentReply : public JobAnswerInterface<DTCJobOperation> {
+    public:
+	AgentReply()
+	{
+		init_stat_flag = false;
+	}
+	virtual ~AgentReply()
+	{
+	}
+	virtual void job_answer_procedure(DTCJobOperation *job);
+
+    private:
+	bool init_stat_flag;
+};
+
+void AgentReply::job_answer_procedure(DTCJobOperation *job)
+{
+	log4cplus_debug("AgentReply::job_answer_procedure start");
+
+	ClientAgent *client = job->owner_client();
+	if (client == NULL) {
+		/* client gone, finish this job */
+		job->done_one_agent_sub_request();
+		return;
+	}
+
+	client->record_request_process_time(job);
+
+	int client_timeout = job->requestInfo.tag_present(1) == 0 ?
+				     job->default_expire_time() :
+				     job->requestInfo.get_expire_time(
+					     job->versionInfo.CTLibIntVer());
+	int req_delaytime = job->responseTimer.live();
+
+	if (!init_stat_flag) {
+		stat_agent_expore_count =
+			g_stat_mgr.get_stat_int_counter(INCOMING_EXPIRE_REQ);
+		stat_task_client_timeout =
+			g_stat_mgr.get_stat_int_counter(TASK_CLIENT_TIMEOUT);
+		init_stat_flag = true;
+	}
+
+	stat_task_client_timeout = client_timeout;
+	log4cplus_debug("job client_timeout: %d", client_timeout);
+
+	if ((req_delaytime / 1000) >= client_timeout) //ms
+	{
+		log4cplus_debug(
+			"AgentReply::job_answer_procedure client_timeout[%d]ms, req delay time[%d]us",
+			client_timeout, req_delaytime);
+		job->done_one_agent_sub_request();
+		stat_agent_expore_count++;
+		return;
+	}
+	Packet *packet = new Packet();
+	if (packet == NULL) {
+		/* make response error, finish this job */
+		job->done_one_agent_sub_request();
+		log4cplus_error("no mem new Packet");
+		return;
+	}
+
+	packet->encode_result(job);
+	job->detach_result_in_result_writer();
+	job->done_one_agent_sub_request();
+
+	client->add_packet(packet);
+	if (client->send_result() < 0) {
+		log4cplus_error("cliengAgent send_result error");
+		delete client;
+		return;
+	}
+
+	log4cplus_debug("AgentReply::job_answer_procedure stop");
+}
+
+static AgentReply agent_reply;
+
+/* sender and receiver should inited ok */
+ClientAgent::ClientAgent(PollerBase *o, JobEntranceAskChain *u, int fd)
+	: EpollBase(o, fd), ownerThread(o), owner(u), tlist(NULL)
+{
+	tlist = u->get_timer_list();
+	sender = new AgentSender(fd);
+	if (NULL == sender) {
+		log4cplus_error("no mem to new sender");
+		throw(int) - ENOMEM;
+	}
+
+	if (sender && sender->initialization() < 0) {
+		delete sender;
+		sender = NULL;
+		log4cplus_error("no mem to init sender");
+		throw(int) - ENOMEM;
+	}
+
+	if (sender) {
+		receiver = new AgentReceiver(fd);
+		if (NULL == receiver) {
+			log4cplus_error("no mem to new receiver");
+			throw(int) - ENOMEM;
+		}
+
+		if (receiver && receiver->initialization() < 0) {
+			log4cplus_error("no mem to init receiver");
+			throw(int) - ENOMEM;
+		}
+	}
+
+	stat_agent_accept_count =
+		g_stat_mgr.get_stat_int_counter(AGENT_ACCEPT_COUNT);
+	stat_agent_cur_conn_count =
+		g_stat_mgr.get_stat_int_counter(AGENT_CONN_COUNT);
+
+	stat_agent_accept_count++;
+	stat_agent_cur_conn_count++;
+}
+
+ClientAgent::~ClientAgent()
+{
+	log4cplus_debug("~ClientAgent start");
+	ListObject<AgentMultiRequest> *node = rememberReqHeader.ListNext();
+	AgentMultiRequest *req;
+
+	/* notify all request of this client I'm gone */
+	while (node != &rememberReqHeader) {
+		req = node->ListOwner();
+		req->clear_owner_info();
+		req->detach_from_owner_client();
+		node = rememberReqHeader.ListNext();
+	}
+
+	if (receiver)
+		delete receiver;
+	if (sender)
+		delete sender;
+
+	detach_poller();
+
+	stat_agent_cur_conn_count--;
+	log4cplus_debug("~ClientAgent end");
+}
+
+int ClientAgent::attach_thread()
+{
+	disable_output();
+	enable_input();
+
+	if (attach_poller() < 0) {
+		log4cplus_error("client agent attach agengInc thread failed");
+		return -1;
+	}
+
+	/* no idle test */
+	return 0;
+}
+
+void ClientAgent::remember_request(DTCJobOperation *request)
+{
+	request->link_to_owner_client(rememberReqHeader);
+}
+
+DTCJobOperation *ClientAgent::parse_job_message(char *recvbuff, int recvlen,
+						int pktcnt)
+{
+	DTCJobOperation *job;
+
+	job = new DTCJobOperation(
+		TableDefinitionManager::instance()->get_cur_table_def());
+	if (NULL == job) {
+		free(recvbuff);
+		log4cplus_error("no mem allocate for new agent request");
+		return NULL;
+	}
+
+	job->set_hotbackup_table(
+		TableDefinitionManager::instance()->get_hot_backup_table_def());
+	job->set_owner_info(this, 0, NULL);
+	job->set_owner_client(this);
+	job->push_reply_dispatcher(&agent_reply);
+	job->save_recved_result(recvbuff, recvlen, pktcnt);
+
+	/* assume only a few sub request decode error */
+	if (job->decode_agent_request() < 0) {
+		delete job;
+		return NULL;
+	}
+
+	/* no mem new job case */
+	if (job->is_agent_request_completed()) {
+		delete job;
+		return NULL;
+	}
+
+	remember_request(job);
+
+	return job;
+}
+
+int ClientAgent::recv_request()
+{
+	RecvedPacket packets;
+	char *recvbuff = NULL;
+	int recvlen = 0;
+	int pktcnt = 0;
+	DTCJobOperation *job_operation = NULL;
+
+	packets = receiver->receive_network_packet();
+
+	if (packets.err < 0)
+		return -1;
+	else if (packets.pktCnt == 0)
+		return 0;
+
+	recvbuff = packets.buff;
+	recvlen = packets.len;
+	pktcnt = packets.pktCnt;
+
+	job_operation = parse_job_message(recvbuff, recvlen, pktcnt);
+	if (job_operation != NULL)
+		owner->start_job_ask_procedure(job_operation);
+
+	return 0;
+}
+
+/* exit when recv error*/
+void ClientAgent::input_notify()
+{
+	log4cplus_debug("enter input_notify.");
+	if (recv_request() < 0) {
+		log4cplus_debug("erro when recv");
+		delete this;
+		return;
+	}
+	delay_apply_events();
+	log4cplus_debug("leave input_notify.");
+	return;
+}
+
+/*
+return error if sender broken
+*/
+int ClientAgent::send_result()
+{
+	if (sender->is_broken()) {
+		log4cplus_error("sender broken");
+		return -1;
+	}
+
+	while (1) {
+		Packet *frontPkt = resQueue.Front();
+		if (NULL == frontPkt) {
+			break;
+		}
+
+		if (frontPkt->vec_count() + sender->vec_count() >
+		    SENDER_MAX_VEC) {
+			/*这个地方打印error,如果在10s内会5次走入此次分支的话,统计子进程会上报告警*/
+			log4cplus_error(
+				"the sum value of front packet veccount[%d] and sender veccount[%d]is greater than SENDER_MAX_VEC[%d]",
+				frontPkt->vec_count(), sender->vec_count(),
+				SENDER_MAX_VEC);
+			break;
+		} else {
+			Packet *pkt;
+			pkt = resQueue.Pop();
+			if (NULL == pkt) {
+				break;
+			}
+			if (sender->add_packet(pkt) < 0) {
+				return -1;
+			}
+		}
+	}
+
+	if (sender->send_packet() < 0) {
+		log4cplus_error("agent client send error");
+		return -1;
+	}
+
+	if (sender->left_len() != 0)
+		enable_output();
+	else
+		disable_output();
+
+	delay_apply_events();
+
+	return 0;
+}
+
+void ClientAgent::output_notify()
+{
+	log4cplus_debug("enter output_notify.");
+	if (send_result() < 0) {
+		log4cplus_debug("error when response");
+		delete this;
+		return;
+	}
+	log4cplus_debug("leave output_notify.");
+
+	return;
+}
+
+void ClientAgent::record_request_process_time(DTCJobOperation *job)
+{
+	owner->record_job_procedure_time(job);
+}

+ 95 - 0
src/libs/common/agent/agent_client.h

@@ -0,0 +1,95 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __AGENT_CLIENT_H__
+#define __AGENT_CLIENT_H__
+
+#include <pthread.h>
+
+#include "poll/poller.h"
+#include "timer/timer_list.h"
+#include "queue/lqueue.h"
+#include "value.h"
+#include "agent_receiver.h"
+
+class Packet;
+class AgentResultQueue {
+    public:
+	LinkQueue<Packet *> packet;
+
+	AgentResultQueue()
+	{
+	}
+	~AgentResultQueue();
+
+	inline void Push(Packet *pkt)
+	{
+		packet.Push(pkt);
+	}
+	inline Packet *Pop()
+	{
+		return packet.Pop();
+	}
+	inline Packet *Front()
+	{
+		return packet.Front();
+	}
+	inline bool queue_empty()
+	{
+		return packet.queue_empty();
+	}
+};
+
+class PollerBase;
+class JobEntranceAskChain;
+class AgentReceiver;
+class AgentSender;
+class AgentMultiRequest;
+class AgentMultiRequest;
+class DTCJobOperation;
+class ClientAgent : public EpollBase, public TimerObject {
+    public:
+	ClientAgent(PollerBase *o, JobEntranceAskChain *u, int fd);
+	virtual ~ClientAgent();
+
+	int attach_thread();
+	inline void add_packet(Packet *p)
+	{
+		resQueue.Push(p);
+	}
+	void remember_request(AgentMultiRequest *agentrequest);
+	int send_result();
+	void record_request_process_time(DTCJobOperation *job);
+
+	virtual void input_notify();
+	virtual void output_notify();
+
+    private:
+	PollerBase *ownerThread;
+	JobEntranceAskChain *owner;
+	TimerList *tlist;
+
+	AgentReceiver *receiver;
+	AgentSender *sender;
+	AgentResultQueue resQueue;
+	ListObject<AgentMultiRequest> rememberReqHeader;
+
+	DTCJobOperation *parse_job_message(char *recvbuff, int recvlen,
+					   int pktcnt);
+	int recv_request();
+	void remember_request(DTCJobOperation *request);
+};
+
+#endif

+ 192 - 0
src/libs/common/agent/agent_listen_pool.cc

@@ -0,0 +1,192 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "agent_listen_pool.h"
+#include "agent_listener.h"
+#include "job_entrance_ask_chain.h"
+#include "poll/poller_base.h"
+#include "config/config.h"
+#include "task/task_request.h"
+#include "log/log.h"
+#include "stat_dtc.h"
+
+AgentListenPool::AgentListenPool()
+{
+	memset(thread, 0, sizeof(PollerBase *) * MAX_AGENT_LISTENER);
+	memset(job_entrance_ask_instance, 0,
+	       sizeof(JobEntranceAskChain *) * MAX_AGENT_LISTENER);
+	memset(listener, 0, sizeof(AgentListener *) * MAX_AGENT_LISTENER);
+
+	StatCounter stat_agent_cur_conn_count =
+		g_stat_mgr.get_stat_int_counter(AGENT_CONN_COUNT);
+	stat_agent_cur_conn_count = 0;
+}
+
+AgentListenPool::~AgentListenPool()
+{
+	for (int i = 0; i < MAX_AGENT_LISTENER; i++) {
+		if (thread[i])
+			thread[i]->interrupt();
+		delete listener[i];
+		delete job_entrance_ask_instance[i];
+	}
+}
+
+int AgentListenPool::register_entrance_chain_multi_thread(
+	DTCConfig *gc, JobAskInterface<DTCJobOperation> *next_chain)
+{
+	char bindstr[64];
+	const char *bindaddr;
+	const char *errmsg = NULL;
+	char thread_name[64];
+	int checktime;
+	int blog;
+
+	checktime = gc->get_int_val("cache", "AgentRcvBufCheck", 5);
+	blog = gc->get_int_val("cache", "AgentListenBlog", 256);
+
+	for (int i = 0; i < MAX_AGENT_LISTENER; i++) {
+		if (i == 0)
+			snprintf(bindstr, sizeof(bindstr), "BindAddr");
+		else
+			snprintf(bindstr, sizeof(bindstr), "BindAddr%d", i);
+
+		bindaddr = gc->get_str_val("cache", bindstr);
+		if (NULL == bindaddr)
+			continue;
+
+		if ((errmsg = socket_address[i].set_address(
+			     bindaddr, (const char *)NULL)))
+			continue;
+
+		snprintf(thread_name, sizeof(thread_name), "dtc-thread-main-%d",
+			 i);
+		thread[i] = new PollerBase(thread_name);
+		if (thread[i] == NULL) {
+			log4cplus_error(
+				"no mem to create multi-thread main thread %d",
+				i);
+			return -1;
+		}
+		if (thread[i]->initialize_thread() < 0) {
+			log4cplus_error(
+				"multi-thread main thread %d init error", i);
+			return -1;
+		}
+
+		job_entrance_ask_instance[i] =
+			new JobEntranceAskChain(thread[i], checktime);
+		if (job_entrance_ask_instance[i] == NULL) {
+			log4cplus_error("no mem to new agent client unit %d",
+					i);
+			return -1;
+		}
+		job_entrance_ask_instance[i]
+			->get_main_chain()
+			->register_next_chain(next_chain);
+
+		listener[i] = new AgentListener(thread[i],
+						job_entrance_ask_instance[i],
+						socket_address[i]);
+		if (listener[i] == NULL) {
+			log4cplus_error("no mem to new agent listener %d", i);
+			return -1;
+		}
+		if (listener[i]->do_bind(blog) < 0) {
+			log4cplus_error("agent listener %d bind error", i);
+			return -1;
+		}
+
+		if (listener[i]->attach_thread() < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+int AgentListenPool::register_entrance_chain(
+	DTCConfig *gc, JobAskInterface<DTCJobOperation> *next_chain,
+	PollerBase *bind_thread)
+{
+	char bindstr[64];
+	const char *bindaddr;
+	const char *errmsg = NULL;
+	int checktime;
+	int blog;
+
+	checktime = gc->get_int_val("cache", "AgentRcvBufCheck", 5);
+	blog = gc->get_int_val("cache", "AgentListenBlog", 256);
+
+	snprintf(bindstr, sizeof(bindstr), "BindAddr");
+
+	bindaddr = gc->get_str_val("cache", bindstr);
+	if (bindaddr == NULL) {
+		log4cplus_error("get cache BindAddr configure failed");
+		return -1;
+	}
+
+	if ((errmsg = socket_address[0].set_address(bindaddr,
+						    (const char *)NULL))) {
+		log4cplus_error("socket_address[0] setaddress failed");
+		return -1;
+	}
+
+	thread[0] = bind_thread;
+
+	job_entrance_ask_instance[0] =
+		new JobEntranceAskChain(thread[0], checktime);
+	if (job_entrance_ask_instance[0] == NULL) {
+		log4cplus_error("no mem to new agent client unit");
+		return -1;
+	}
+	job_entrance_ask_instance[0]->get_main_chain()->register_next_chain(
+		next_chain);
+
+	listener[0] = new AgentListener(thread[0], job_entrance_ask_instance[0],
+					socket_address[0]);
+	if (listener[0] == NULL) {
+		log4cplus_error("no mem to new agent listener");
+		return -1;
+	}
+	if (listener[0]->do_bind(blog) < 0) {
+		log4cplus_error("agent listener bind error");
+		return -1;
+	}
+	if (listener[0]->attach_thread() < 0)
+		return -1;
+
+	return 0;
+}
+
+int AgentListenPool::running_all_threads()
+{
+	for (int i = 0; i < MAX_AGENT_LISTENER; i++) {
+		if (thread[i])
+			thread[i]->running_thread();
+	}
+
+	return 0;
+}
+
+int AgentListenPool::Match(const char *host, const char *port)
+{
+	for (int i = 0; i < MAX_AGENT_LISTENER; i++) {
+		if (listener[i] == NULL)
+			continue;
+		if (socket_address[i].Match(host, port))
+			return 1;
+	}
+	return 0;
+}

+ 50 - 0
src/libs/common/agent/agent_listen_pool.h

@@ -0,0 +1,50 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __AGENT_LISTEN_POOL_H__
+#define __AGENT_LISTEN_POOL_H__
+
+#include "request/request_base.h"
+#include "socket/socket_addr.h"
+
+#define MAX_AGENT_LISTENER 10
+
+class JobEntranceAskChain;
+class AgentListener;
+class PollerBase;
+class DTCConfig;
+class DTCJobOperation;
+class AgentListenPool {
+    private:
+	SocketAddress socket_address[MAX_AGENT_LISTENER];
+	PollerBase *thread[MAX_AGENT_LISTENER];
+	JobEntranceAskChain *job_entrance_ask_instance[MAX_AGENT_LISTENER];
+	AgentListener *listener[MAX_AGENT_LISTENER];
+
+    public:
+	AgentListenPool();
+	~AgentListenPool();
+
+	int register_entrance_chain_multi_thread(
+		DTCConfig *gc, JobAskInterface<DTCJobOperation> *next_chain);
+	int
+	register_entrance_chain(DTCConfig *gc,
+				JobAskInterface<DTCJobOperation> *next_chain,
+				PollerBase *bind_thread);
+	int running_all_threads();
+	int Match(const char *host, const char *port);
+};
+
+#endif

+ 86 - 0
src/libs/common/agent/agent_listener.cc

@@ -0,0 +1,86 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <errno.h>
+
+#include "agent_listener.h"
+#include "agent/agent_client.h"
+#include "poll/poller_base.h"
+#include "log/log.h"
+
+AgentListener::AgentListener(PollerBase *t, JobEntranceAskChain *o,
+			     SocketAddress &a)
+	: EpollBase(t, 0), ownerThread(t), out(o), addr(a)
+{
+}
+
+AgentListener::~AgentListener()
+{
+}
+
+/* part of framework construction */
+int AgentListener::do_bind(int blog)
+{
+	if ((netfd = socket_bind(&addr, blog, 0, 0, 1 /*reuse*/, 1 /*nodelay*/,
+				 1 /*defer_accept*/)) == -1)
+		return -1;
+	return 0;
+}
+
+int AgentListener::attach_thread()
+{
+	enable_input();
+	if (EpollBase::attach_poller() < 0) {
+		log4cplus_error("agent listener attach agentInc thread error");
+		return -1;
+	}
+	return 0;
+}
+
+void AgentListener::input_notify()
+{
+	log4cplus_debug("enter input_notify.");
+	while (1) {
+		int newfd;
+		struct sockaddr peer;
+		socklen_t peersize = sizeof(peer);
+
+		newfd = accept(netfd, &peer, &peersize);
+		if (newfd < 0) {
+			if (EINTR != errno && EAGAIN != errno)
+				log4cplus_error(
+					"agent listener accept error, %m");
+			break;
+		}
+
+		log4cplus_debug("new CAgentClient accepted!!");
+
+		ClientAgent *client;
+		try {
+			client = new ClientAgent(ownerThread, out, newfd);
+		} catch (int err) {
+			return;
+		}
+
+		if (NULL == client) {
+			log4cplus_error("no mem for new client agent");
+			break;
+		}
+
+		client->attach_thread();
+		client->input_notify();
+	}
+	log4cplus_debug("leave input_notify.");
+}

+ 40 - 0
src/libs/common/agent/agent_listener.h

@@ -0,0 +1,40 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __AGENT_LISTENER_H__
+#define __AGENT_LISTENER_H__
+
+#include "poll/poller.h"
+#include "socket/socket_addr.h"
+
+class PollerBase;
+class JobEntranceAskChain;
+class AgentListener : public EpollBase {
+    private:
+	PollerBase *ownerThread;
+	JobEntranceAskChain *out;
+	const SocketAddress addr;
+
+	virtual void input_notify();
+
+    public:
+	AgentListener(PollerBase *t, JobEntranceAskChain *o, SocketAddress &a);
+	virtual ~AgentListener();
+
+	int do_bind(int blog);
+	int attach_thread();
+};
+
+#endif

+ 161 - 0
src/libs/common/agent/agent_multi_request.cc

@@ -0,0 +1,161 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "agent/agent_multi_request.h"
+#include "task/task_request.h"
+#include "agent/agent_client.h"
+#include "table/table_def_manager.h"
+
+extern DTCTableDefinition *g_table_def[];
+
+AgentMultiRequest::AgentMultiRequest(DTCJobOperation *o)
+	: packetCnt(0), owner(o), taskList(NULL), compleTask(0),
+	  owner_client_(NULL)
+{
+	if (o)
+		owner_client_ = o->owner_client();
+}
+
+AgentMultiRequest::~AgentMultiRequest()
+{
+	list_del();
+
+	if (taskList) {
+		for (int i = 0; i < packetCnt; i++)
+			if (taskList[i].job)
+				delete taskList[i].job;
+
+		delete[] taskList;
+	}
+
+	if (!!packets)
+		free(packets.ptr);
+}
+
+void AgentMultiRequest::complete_task(int index)
+{
+	if (taskList[index].job) {
+		delete taskList[index].job;
+		taskList[index].job = NULL;
+	}
+
+	compleTask++;
+	/* delete owner taskrequest along with us if all sub request's result putted into ClientAgent's send queue */
+
+	if (compleTask == packetCnt) {
+		delete owner;
+	}
+}
+
+void AgentMultiRequest::clear_owner_info()
+{
+	owner_client_ = NULL;
+
+	if (taskList == NULL)
+		return;
+
+	for (int i = 0; i < packetCnt; i++) {
+		if (taskList[i].job)
+			taskList[i].job->clear_owner_client();
+	}
+}
+
+/*
+error case: set this job processed
+1. no mem: set job processed
+2. decode error: set job processed, reply this job
+*/
+void AgentMultiRequest::DecodeOneRequest(char *packetstart, int packetlen,
+					 int index)
+{
+	int err = 0;
+	DTCJobOperation *job = NULL;
+	DecodeResult decoderes;
+
+	job = new DTCJobOperation(
+		TableDefinitionManager::instance()->get_cur_table_def());
+	if (NULL == job) {
+		log4cplus_error(
+			"not enough mem for new job creation, client wont recv response");
+		compleTask++;
+		return;
+	}
+
+	job->set_hotbackup_table(
+		TableDefinitionManager::instance()->get_hot_backup_table_def());
+	decoderes = job->do_decode(packetstart, packetlen, 2);
+	switch (decoderes) {
+	default:
+	case DecodeFatalError:
+		if (errno != 0)
+			log4cplus_info("decode fatal error, msg = %m");
+		break;
+	case DecodeDataError:
+		job->response_timer_start();
+		job->mark_as_hit();
+		taskList[index].processed = 1;
+		break;
+	case DecodeDone:
+		if ((err = job->prepare_process()) < 0) {
+			log4cplus_error("build packed key error: %d, %s", err,
+					job->resultInfo.error_message());
+			taskList[index].processed = 1;
+		}
+		break;
+	}
+
+	job->set_owner_info(this, index, NULL);
+	job->set_owner_client(this->owner_client_);
+
+	taskList[index].job = job;
+
+	return;
+}
+
+int AgentMultiRequest::decode_agent_request()
+{
+	int cursor = 0;
+
+	taskList = new DecodedTask[packetCnt];
+	if (NULL == taskList) {
+		log4cplus_error("no mem new taskList");
+		return -1;
+	}
+	memset((void *)taskList, 0, sizeof(DecodedTask) * packetCnt);
+
+	/* whether can work, reply on input buffer's correctness */
+	for (int i = 0; i < packetCnt; i++) {
+		char *packetstart;
+		int packetlen;
+
+		packetstart = packets.ptr + cursor;
+		packetlen = packet_body_len(*(PacketHeader *)packetstart) +
+			    sizeof(PacketHeader);
+
+		DecodeOneRequest(packetstart, packetlen, i);
+
+		cursor += packetlen;
+	}
+
+	return 0;
+}
+
+void AgentMultiRequest::copy_reply_for_sub_task()
+{
+	for (int i = 0; i < packetCnt; i++) {
+		if (taskList[i].job)
+			taskList[i].job->copy_reply_path(owner);
+	}
+}

+ 74 - 0
src/libs/common/agent/agent_multi_request.h

@@ -0,0 +1,74 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef AGENT_MULTI_REQUEST_H___
+#define AGENT_MULTI_REQUEST_H___
+
+#include "list/list.h"
+#include "value.h"
+
+class DTCJobOperation;
+typedef struct {
+	DTCJobOperation *volatile job;
+	volatile int processed;
+} DecodedTask;
+
+class ClientAgent;
+class AgentMultiRequest : public ListObject<AgentMultiRequest> {
+    public:
+	AgentMultiRequest(DTCJobOperation *o);
+	virtual ~AgentMultiRequest();
+
+	int decode_agent_request();
+	inline int packet_count()
+	{
+		return packetCnt;
+	}
+	inline DTCJobOperation *curr_task(int index)
+	{
+		return taskList[index].job;
+	}
+	void copy_reply_for_sub_task();
+	void clear_owner_info();
+	inline bool is_completed()
+	{
+		return compleTask == packetCnt;
+	}
+	void complete_task(int index);
+	inline void detach_from_owner_client()
+	{
+		list_del();
+	}
+	inline bool is_curr_task_processed(int index)
+	{
+		return taskList[index].processed == 1;
+	}
+	inline void save_recved_result(char *buff, int len, int pktcnt)
+	{
+		packets.Set(buff, len);
+		packetCnt = pktcnt;
+	}
+
+    private:
+	DTCBinary packets;
+	int packetCnt;
+	DTCJobOperation *owner;
+	DecodedTask *volatile taskList;
+	volatile int compleTask;
+	ClientAgent *volatile owner_client_;
+	void DecodeOneRequest(char *packetstart, int packetlen, int index);
+};
+
+#endif

+ 279 - 0
src/libs/common/agent/agent_receiver.cc

@@ -0,0 +1,279 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <string.h>
+
+#include "agent_receiver.h"
+#include "log/log.h"
+#include "mem_check.h"
+#include "protocol.h"
+#include "task/task_request.h"
+
+AgentReceiver::AgentReceiver(int f)
+	: fd(f), buffer(NULL), offset(0), buffSize(0), pktTail(0), pktCnt(0)
+{
+}
+
+AgentReceiver::~AgentReceiver()
+{
+	/* fd will closed by ClientAgent */
+	if (buffer)
+		free(buffer);
+}
+
+int AgentReceiver::initialization()
+{
+	buffer = (char *)malloc(AGENT_INIT_RECV_BUFF_SIZE);
+	if (NULL == buffer)
+		return -1;
+	buffSize = AGENT_INIT_RECV_BUFF_SIZE;
+	return 0;
+}
+
+/*
+discription: recv
+main_chain:
+<0: recv error or remote close
+=0: nothing recved
+>0: recved 
+*/
+int AgentReceiver::recv_once()
+{
+	int rv;
+
+	rv = recv(fd, offset + buffer, buffSize - offset, 0);
+	if (rv < 0) {
+		if (EAGAIN == errno || EINTR == errno || EINPROGRESS == errno)
+			return 0;
+		log4cplus_error("agent receiver recv error: %m, %d", errno);
+		return -errno;
+	} else if (0 == rv) {
+		log4cplus_debug("remote close connection, fd[%d]", fd);
+		errno = ECONNRESET;
+		return -errno;
+	}
+
+	offset += rv;
+
+	return rv;
+}
+
+/*
+return value:
+<0: error
+=0: nothing recved or have no completed packet
+>0: recved and have completed packet
+*/
+RecvedPacket AgentReceiver::receive_network_packet()
+{
+	int err = 0;
+	RecvedPacket packet;
+
+	memset((void *)&packet, 0, sizeof(packet));
+
+	if ((err = real_recv()) < 0) {
+		packet.err = -1;
+		return packet;
+	} else if (err == 0)
+		return packet;
+
+	if ((err = recv_again()) < 0) {
+		packet.err = -1;
+		return packet;
+	}
+
+	set_recved_info(packet);
+
+	return packet;
+}
+
+/*
+discription: recv data
+main_chain:
+<0: recv error or remote close
+=0: nothing recved
+>0: received
+*/
+int AgentReceiver::real_recv()
+{
+	int rv = 0;
+
+	if (is_need_enlarge_buffer()) {
+		if (enlarge_buffer() < 0) {
+			log4cplus_error("no mme enlarge recv buffer error");
+			return -ENOMEM;
+		}
+	}
+
+	if ((rv = recv_once()) < 0)
+		return -1;
+
+	return rv;
+}
+
+/*
+main_chain:
+=0: no need enlarge recv buffer or enlarge ok but recv nothing
+<0: error
+>0: recved
+*/
+int AgentReceiver::recv_again()
+{
+	int rv = 0;
+
+	if (!is_need_enlarge_buffer())
+		return 0;
+
+	if (enlarge_buffer() < 0) {
+		log4cplus_error("no mme enlarge recv buffer error");
+		return -ENOMEM;
+	}
+
+	if ((rv = recv_once()) < 0)
+		return -1;
+
+	return rv;
+}
+
+int AgentReceiver::decode_header(PacketHeader *header)
+{
+	if (header->version != 1) { // version not supported
+		log4cplus_error("version incorrect: %d", header->version);
+		return -1;
+	}
+
+	if (header->scts != DRequest::Section::Total) { // tags# mismatch
+		log4cplus_error("session count incorrect: %d", header->scts);
+		return -1;
+	}
+
+	int pktbodylen = 0;
+	for (int i = 0; i < DRequest::Section::Total; i++) {
+#if __BYTE_ORDER == __BIG_ENDIAN
+		const unsigned int v = bswap_32(header->len[i]);
+#else
+		const unsigned int v = header->len[i];
+#endif
+
+		if (v > MAXPACKETSIZE) {
+			log4cplus_error("section [%d] len > MAXPACKETSIZE", i);
+			return -1;
+		}
+
+		pktbodylen += v;
+	}
+
+	if (pktbodylen > MAXPACKETSIZE) {
+		log4cplus_error("packet len > MAXPACKETSIZE 20M");
+		return -1;
+	}
+
+	return pktbodylen;
+}
+
+int AgentReceiver::count_packet()
+{
+	char *pos = buffer;
+	int leftlen = offset;
+
+	pktCnt = 0;
+
+	if (pos == NULL || leftlen == 0)
+		return 0;
+
+	while (1) {
+		int pktbodylen = 0;
+		PacketHeader *header = NULL;
+
+		if (leftlen < (int)sizeof(PacketHeader))
+			break;
+
+		header = (PacketHeader *)pos;
+		pktbodylen = decode_header(header);
+		if (pktbodylen < 0)
+			return -1;
+
+		if (leftlen < (int)sizeof(PacketHeader) + pktbodylen)
+			break;
+
+		pos += sizeof(PacketHeader) + pktbodylen;
+		leftlen -= sizeof(PacketHeader) + pktbodylen;
+		pktCnt++;
+	}
+
+	pktTail = pos - buffer;
+	return 0;
+}
+
+/*
+return value:
+<0: error
+=0: contain no packet
+>0: contain packet
+*/
+void AgentReceiver::set_recved_info(RecvedPacket &packet)
+{
+	if (count_packet() < 0) {
+		packet.err = -1;
+		return;
+	}
+
+	/* not even ont packet recved, do nothing */
+	if (pktCnt == 0)
+		return;
+
+	char *tmpbuff;
+	if (NULL == (tmpbuff = (char *)malloc(buffSize))) {
+		/* recved buffer willbe free by outBuff */
+		log4cplus_error("no mem malloc new recv buffer");
+		packet.err = -1;
+		return;
+	}
+
+	if (pktTail < offset)
+		memcpy(tmpbuff, buffer + pktTail, offset - pktTail);
+
+	packet.buff = buffer;
+	packet.len = pktTail;
+	packet.pktCnt = pktCnt;
+
+	buffer = tmpbuff;
+	offset -= pktTail;
+
+	return;
+}
+
+/*
+main_chain:
+=0: enlarge ok
+<0: enlarge error
+*/
+int AgentReceiver::enlarge_buffer()
+{
+	buffer = (char *)REALLOC(buffer, buffSize * 2);
+	if (buffer == NULL)
+		return -1;
+	buffSize *= 2;
+	return 0;
+}
+
+bool AgentReceiver::is_need_enlarge_buffer()
+{
+	return offset == buffSize;
+}

+ 59 - 0
src/libs/common/agent/agent_receiver.h

@@ -0,0 +1,59 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __AGENT_RECEIVER_H__
+#define __AGENT_RECEIVER_H__
+
+#include <stdint.h>
+
+#include "value.h"
+#include "protocol.h"
+
+#define AGENT_INIT_RECV_BUFF_SIZE 4096
+
+typedef struct {
+	char *buff;
+	int len;
+	int pktCnt;
+	int err;
+} RecvedPacket;
+
+class AgentReceiver {
+    public:
+	AgentReceiver(int f);
+	virtual ~AgentReceiver();
+
+	int initialization();
+	RecvedPacket receive_network_packet();
+
+    private:
+	int fd;
+	char *buffer;
+	uint32_t offset;
+	uint32_t buffSize;
+	uint32_t pktTail;
+	int pktCnt;
+
+	int enlarge_buffer();
+	bool is_need_enlarge_buffer();
+	int recv_once();
+	int real_recv();
+	int recv_again();
+	int decode_header(PacketHeader *header);
+	void set_recved_info(RecvedPacket &packet);
+	int count_packet();
+};
+
+#endif

+ 163 - 0
src/libs/common/agent/agent_sender.cc

@@ -0,0 +1,163 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "agent_sender.h"
+#include "packet/packet.h"
+#include "log/log.h"
+
+AgentSender::AgentSender(int f)
+	: fd(f), vec(NULL), totalVec(1024), currVec(0), packet(NULL),
+	  totalPacket(512), currPacket(0), totalLen(0), sended(0), leftLen(0),
+	  broken(0)
+{
+}
+
+AgentSender::~AgentSender()
+{
+	/* fd will closed by ClientAgent */
+	for (uint32_t j = 0; j < currPacket; j++) {
+		if (packet[j]) {
+			packet[j]->free_result_buff();
+			delete packet[j];
+		}
+	}
+	if (vec)
+		free(vec);
+	if (packet)
+		free(packet);
+}
+
+int AgentSender::initialization()
+{
+	vec = (struct iovec *)malloc(1024 * sizeof(struct iovec));
+	if (NULL == vec) {
+		broken = 1;
+		return -1;
+	}
+
+	if (vec) {
+		packet = (Packet **)malloc(512 * sizeof(Packet *));
+		if (NULL == packet) {
+			broken = 1;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int AgentSender::add_packet(Packet *pkt)
+{
+	if (currVec == totalVec) {
+		vec = (struct iovec *)realloc(
+			vec, totalVec * 2 * sizeof(struct iovec));
+		if (NULL == vec) {
+			broken = 1;
+			return -ENOMEM;
+		}
+		totalVec *= 2;
+	}
+
+	if (currPacket == totalPacket) {
+		packet = (Packet **)realloc(packet,
+					    totalPacket * 2 * sizeof(Packet *));
+		if (NULL == packet) {
+			broken = 1;
+			return -ENOMEM;
+		}
+		totalPacket *= 2;
+	}
+
+	for (int i = 0; i < pkt->vec_count(); i++) {
+		vec[currVec++] = pkt->IOVec()[i];
+	}
+	packet[currPacket++] = pkt;
+	leftLen += pkt->Bytes();
+
+	return 0;
+}
+
+int AgentSender::send_packet()
+{
+	if (0 == leftLen)
+		return 0;
+
+	int sd;
+	struct msghdr msgh;
+	uint32_t cursor = 0;
+	struct iovec *v = vec;
+	uint32_t pcursor = 0;
+	Packet **p = packet;
+
+	msgh.msg_name = NULL;
+	msgh.msg_namelen = 0;
+	msgh.msg_iov = vec;
+	msgh.msg_iovlen = currVec;
+	msgh.msg_control = NULL;
+	msgh.msg_controllen = 0;
+	msgh.msg_flags = 0;
+
+	sd = sendmsg(fd, &msgh, MSG_DONTWAIT | MSG_NOSIGNAL);
+	if (sd < 0) {
+		if (EINTR == errno || EAGAIN == errno || EINPROGRESS == errno)
+			return 0;
+		log4cplus_error(
+			"agent sender send error. errno: %d, left len: %d, currVec: %d, IOV_MAX: %d",
+			errno, leftLen, currVec, IOV_MAX);
+		broken = 1;
+		return -1;
+	}
+
+	totalLen = leftLen;
+	sended = sd;
+	leftLen -= sended;
+
+	if (0 == sd)
+		return 0;
+
+	while (cursor < currVec && (uint32_t)sd >= v->iov_len) {
+		sd -= v->iov_len;
+		cursor++;
+		v++;
+		(*p)->send_done_one_vec();
+		if ((*p)->is_send_done()) {
+			(*p)->free_result_buff();
+			delete *p;
+			pcursor++;
+			p++;
+		}
+	}
+
+	if (sd > 0) {
+		v->iov_base = (char *)v->iov_base + sd;
+		v->iov_len -= sd;
+	}
+
+	memmove((void *)vec, (void *)(vec + cursor),
+		(currVec - cursor) * sizeof(struct iovec));
+	currVec -= cursor;
+
+	memmove((void *)packet, (void *)(packet + pcursor),
+		(currPacket - pcursor) * sizeof(Packet *));
+	currPacket -= pcursor;
+
+	return 0;
+}

+ 69 - 0
src/libs/common/agent/agent_sender.h

@@ -0,0 +1,69 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __AGENT_SENDER_H__
+#define __AGENT_SENDER_H__
+
+#include <stdint.h>
+
+#define SENDER_MAX_VEC 1024
+
+class Packet;
+class AgentSender {
+    private:
+	int fd;
+	struct iovec *vec;
+	uint32_t totalVec;
+	uint32_t currVec;
+	Packet **packet;
+	uint32_t totalPacket;
+	uint32_t currPacket;
+
+	uint32_t totalLen;
+	uint32_t sended;
+	uint32_t leftLen;
+
+	int broken;
+
+    public:
+	AgentSender(int f);
+	virtual ~AgentSender();
+
+	int initialization();
+	int is_broken()
+	{
+		return broken;
+	}
+	int add_packet(Packet *pkt);
+	int send_packet();
+	inline uint32_t total_len()
+	{
+		return totalLen;
+	}
+	inline uint32_t Sended()
+	{
+		return sended;
+	}
+	inline uint32_t left_len()
+	{
+		return leftLen;
+	}
+	inline uint32_t vec_count()
+	{
+		return currVec;
+	}
+};
+
+#endif

+ 58 - 0
src/libs/common/agent/agent_unit.cc

@@ -0,0 +1,58 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "agent_unit.h"
+#include "poll/poller_base.h"
+#include "task/task_request.h"
+#include "log/log.h"
+
+AgentHubAskChain::AgentHubAskChain(PollerBase *o)
+	: JobAskInterface<DTCJobOperation>(o), ownerThread(o), main_chain(o)
+{
+}
+
+AgentHubAskChain::~AgentHubAskChain()
+{
+}
+
+void AgentHubAskChain::job_ask_procedure(DTCJobOperation *curr)
+{
+	log4cplus_debug("enter job_ask_procedure");
+	curr->copy_reply_for_agent_sub_task();
+
+	//there is a race condition here:
+	//curr may be deleted during process (in job->turn_around_job_answer())
+	int taskCount = curr->agent_sub_task_count();
+	log4cplus_debug("job_ask_procedure job count is %d", taskCount);
+	for (int i = 0; i < taskCount; i++) {
+		DTCJobOperation *job = NULL;
+
+		if (NULL == (job = curr->curr_agent_sub_task(i)))
+			continue;
+
+		if (curr->is_curr_sub_task_processed(i)) {
+			log4cplus_debug("job_ask_procedure job reply notify");
+			job->turn_around_job_answer();
+		}
+
+		else {
+			log4cplus_debug("job_ask_procedure next process");
+			main_chain.job_ask_procedure(job);
+		}
+	}
+	log4cplus_debug("leave job_ask_procedure");
+
+	return;
+}

+ 47 - 0
src/libs/common/agent/agent_unit.h

@@ -0,0 +1,47 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* 
+* Author:  Yangshuang, yangshuang68@jd.com    Wuxinzhen, wuxinzhen1@jd.com
+*/
+#ifndef __AGENT_UNIT_H__
+#define __AGENT_UNIT_H__
+
+#include "request/request_base.h"
+
+class PollerBase;
+class DTCJobOperation;
+
+class AgentHubAskChain : public JobAskInterface<DTCJobOperation> {
+    private:
+	PollerBase *ownerThread;
+	ChainJoint<DTCJobOperation> main_chain;
+
+    public:
+	AgentHubAskChain(PollerBase *o);
+	virtual ~AgentHubAskChain();
+
+	inline void register_next_chain(JobAskInterface<DTCJobOperation> *p)
+	{
+		main_chain.register_next_chain(p);
+	}
+	ChainJoint<DTCJobOperation> *get_main_chain()
+	{
+		return &main_chain;
+	}
+
+	virtual void job_ask_procedure(DTCJobOperation *curr);
+};
+
+#endif

+ 45 - 0
src/libs/common/algorithm/bitsop.cc

@@ -0,0 +1,45 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "algorithm/bitsop.h"
+
+const unsigned char __bitcount[256] = {
+	/* 00 */ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+	/* 10 */ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	/* 20 */ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	/* 30 */ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	/* 40 */ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	/* 50 */ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	/* 60 */ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	/* 70 */ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	/* 80 */ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	/* 90 */ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	/* a0 */ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	/* b0 */ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	/* c0 */ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	/* d0 */ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	/* e0 */ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	/* f0 */ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+int CountBits(const char *buf, int sz)
+{
+	int c;
+	for (c = 0; sz > 0; buf++, sz--) {
+		c += __bitcount[*(unsigned char *)buf];
+	}
+	return c;
+}

+ 98 - 0
src/libs/common/algorithm/bitsop.h

@@ -0,0 +1,98 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef __BITSOP_H__
+#define __BITSOP_H__
+#include <linux/types.h>
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+/*
+   bits操作函数
+   */
+
+/* 
+ *
+ *   select.h中提供的FD_*宏在32位机器上是按照byte来置位的(汇编实现),但在64位
+ *   机器上是按照8 bytes来置位的,所以当碰到mmap文件末尾时,有可能segment fault。
+ */
+
+#define CHAR_BITS 8
+
+extern const unsigned char __bitcount[];
+extern int CountBits(const char *buf, int sz);
+
+//bits op interface
+#define SET_B(bit, addr) __set_b(bit, addr)
+#define CLR_B(bit, addr) __clr_b(bit, addr)
+#define ISSET_B(bit, addr) __isset_b(bit, addr)
+#define COPY_B(dest_bit, dest_addr, src_bit, src_addr, count)                  \
+	__bit_copy(dest_bit, dest_addr, src_bit, src_addr, count)
+#define COUNT_B(buf, size) CountBits(buf, size)
+
+static inline void __set_b(__u32 bit, const volatile void *addr)
+{
+	volatile __u8 *begin = (volatile __u8 *)addr + (bit / CHAR_BITS);
+	__u8 shift = bit % CHAR_BITS;
+
+	*begin |= ((__u8)0x1 << shift);
+
+	return;
+}
+
+static inline int __isset_b(__u32 bit, const volatile void *addr)
+{
+	volatile __u8 *begin = (volatile __u8 *)addr + (bit / CHAR_BITS);
+	__u8 shift = bit % CHAR_BITS;
+
+	return (*begin & ((__u8)0x1 << shift)) > 0 ? 1 : 0;
+}
+
+static inline void __clr_b(__u32 bit, const volatile void *addr)
+{
+	volatile __u8 *begin = (volatile __u8 *)addr + (bit / CHAR_BITS);
+	__u8 shift = bit % CHAR_BITS;
+
+	*begin &= ~((__u8)0x1 << shift);
+}
+
+static inline __u8 __readbyte(const volatile void *addr)
+{
+	return *(volatile __u8 *)addr;
+}
+static inline void __writebyte(__u8 val, volatile void *addr)
+{
+	*(volatile __u8 *)addr = val;
+}
+
+static inline void __bit_copy(__u32 dest_bit, volatile void *dest,
+			      __u32 src_bit, volatile void *src, __u32 count)
+{
+	__u32 i;
+	for (i = 0; i < count; i++) {
+		if (__isset_b(src_bit, src))
+			__set_b(dest_bit, dest);
+		else
+			__clr_b(dest_bit, dest);
+
+		dest_bit++;
+		src_bit++;
+	}
+
+	return;
+}
+
+__END_DECLS
+#endif

+ 107 - 0
src/libs/common/algorithm/chash.cc

@@ -0,0 +1,107 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "algorithm/chash.h"
+
+#define mix(a, b, c)                                                           \
+	{                                                                      \
+		a = a - b;                                                     \
+		a = a - c;                                                     \
+		a = a ^ (c >> 13);                                             \
+		b = b - c;                                                     \
+		b = b - a;                                                     \
+		b = b ^ (a << 8);                                              \
+		c = c - a;                                                     \
+		c = c - b;                                                     \
+		c = c ^ (b >> 13);                                             \
+		a = a - b;                                                     \
+		a = a - c;                                                     \
+		a = a ^ (c >> 12);                                             \
+		b = b - c;                                                     \
+		b = b - a;                                                     \
+		b = b ^ (a << 16);                                             \
+		c = c - a;                                                     \
+		c = c - b;                                                     \
+		c = c ^ (b >> 5);                                              \
+		a = a - b;                                                     \
+		a = a - c;                                                     \
+		a = a ^ (c >> 3);                                              \
+		b = b - c;                                                     \
+		b = b - a;                                                     \
+		b = b ^ (a << 10);                                             \
+		c = c - a;                                                     \
+		c = c - b;                                                     \
+		c = c ^ (b >> 15);                                             \
+	}
+
+typedef unsigned int u4;
+
+unsigned int chash(const char *k, int length)
+{
+	unsigned int a, b, c; /* the internal state */
+	u4 len; /* how many key bytes still need mixing */
+
+	/* Set up the internal state */
+	len = length;
+	a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+	// 'TMJR'
+	c = 0x544D4A52; /* variable initialization of internal state */
+
+	/*---------------------------------------- handle most of the key */
+	while (len >= 12) {
+		a = a + (k[0] + ((u4)k[1] << 8) + ((u4)k[2] << 16) +
+			 ((u4)k[3] << 24));
+		b = b + (k[4] + ((u4)k[5] << 8) + ((u4)k[6] << 16) +
+			 ((u4)k[7] << 24));
+		c = c + (k[8] + ((u4)k[9] << 8) + ((u4)k[10] << 16) +
+			 ((u4)k[11] << 24));
+		mix(a, b, c);
+		k = k + 12;
+		len = len - 12;
+	}
+
+	/*------------------------------------- handle the last 11 bytes */
+	c = c + length;
+	switch (len) /* all the case statements fall through */
+	{
+	case 11:
+		c = c + ((u4)k[10] << 24);
+	case 10:
+		c = c + ((u4)k[9] << 16);
+	case 9:
+		c = c + ((u4)k[8] << 8);
+		/* the first byte of c is reserved for the length */
+	case 8:
+		b = b + ((u4)k[7] << 24);
+	case 7:
+		b = b + ((u4)k[6] << 16);
+	case 6:
+		b = b + ((u4)k[5] << 8);
+	case 5:
+		b = b + k[4];
+	case 4:
+		a = a + ((u4)k[3] << 24);
+	case 3:
+		a = a + ((u4)k[2] << 16);
+	case 2:
+		a = a + ((u4)k[1] << 8);
+	case 1:
+		a = a + k[0];
+		/* case 0: nothing left to add */
+	}
+	mix(a, b, c);
+	/*-------------------------------------------- report the result */
+	return c;
+}

+ 25 - 0
src/libs/common/algorithm/chash.h

@@ -0,0 +1,25 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef BITMAP_C_HASH_H__
+#define BITMAP_C_HASH_H__
+
+#include <stdint.h>
+
+//hash function for consistent hash
+//the algorithm is the same as new_hash, but use another initial value
+uint32_t chash(const char *data, int len);
+
+#endif

+ 94 - 0
src/libs/common/algorithm/compress.cc

@@ -0,0 +1,94 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "algorithm/compress.h"
+#include "zlib.h"
+#include "mem_check.h"
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+DTCCompress::DTCCompress()
+{
+	_level = 1;
+	_buflen = 0;
+	_len = 0;
+	_buf = NULL;
+}
+
+DTCCompress::~DTCCompress()
+{
+	if (_buf)
+		FREE(_buf);
+}
+
+void DTCCompress::set_compress_level(int level)
+{
+	_level = level < 1 ? 1 : (level > 9 ? 9 : level);
+}
+int DTCCompress::set_buffer_len(unsigned long len)
+{
+	if (_buf == NULL) {
+		_buflen = len;
+		_buf = (unsigned char *)MALLOC(len);
+	} else if (_buflen < len) {
+		_buflen = len;
+		FREE(_buf);
+		_buf = (unsigned char *)MALLOC(len);
+	}
+	if (_buf == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+//source 被压缩的缓冲区 sourcelen 被压缩缓冲区的原始长度
+//dest   压缩后的缓冲区 destlen   被压缩后的缓冲区长度
+//注意调用该函数时, destlen 首先要设置为dest缓冲区最大可以容纳的长度
+int DTCCompress::compress(const char *source, unsigned long sourceLen)
+{
+	if (_buf == NULL || source == NULL) {
+		return -111111;
+	}
+	_len = _buflen;
+	return compress2(_buf, &_len, (Bytef *)source, sourceLen, _level);
+}
+
+//source 待解压的缓冲区 sourcelen 待解压缓冲区的原始长度
+//dest   解压后的缓冲区 destlen   解缩后的缓冲区长度
+//注意调用该函数时, destlen 首先要设置为dest缓冲区最大可以容纳的长度
+int DTCCompress::UnCompress(char **buf, int *lenp, const char *source,
+			    unsigned long sourceLen)
+{
+	if (_buf == NULL || source == NULL) {
+		snprintf(errmsg_, sizeof(errmsg_),
+			 "input buffer or uncompress buffer is null");
+		return -111111;
+	}
+	_len = _buflen;
+	int iret = uncompress(_buf, &_len, (Bytef *)source, sourceLen);
+	if (iret) {
+		snprintf(
+			errmsg_, sizeof(errmsg_),
+			"uncompress error,error code is:%d.check it in /usr/include/zlib.h",
+			iret);
+		return -111111;
+	}
+	*buf = (char *)MALLOC(_len);
+	if (*buf == NULL)
+		return -ENOMEM;
+	memcpy(*buf, _buf, _len);
+	*lenp = _len;
+	return 0;
+}

+ 54 - 0
src/libs/common/algorithm/compress.h

@@ -0,0 +1,54 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+class DTCCompress {
+    public:
+	DTCCompress();
+	virtual ~DTCCompress();
+
+	void set_compress_level(int level);
+	int set_buffer_len(unsigned long len);
+	const char *error_message(void) const
+	{
+		return errmsg_;
+	}
+
+	//source 被压缩的缓冲区 sourcelen 被压缩缓冲区的原始长度
+	//dest   压缩后的缓冲区 destlen   被压缩后的缓冲区长度
+	//注意调用该函数时, destlen 首先要设置为dest缓冲区最大可以容纳的长度
+	int compress(const char *source, unsigned long sourceLen);
+
+	//source 待解压的缓冲区 sourcelen 待解压缓冲区的原始长度
+	//dest   解压后的缓冲区 destlen   解缩后的缓冲区长度
+	//注意调用该函数时, destlen 首先要设置为dest缓冲区最大可以容纳的长度
+	int UnCompress(char **dest, int *destlen, const char *source,
+		       unsigned long sourceLen);
+
+	unsigned long get_len(void)
+	{
+		return _len;
+	}
+	char *get_buf(void)
+	{
+		return (char *)_buf;
+	}
+	char errmsg_[512];
+
+    private:
+	unsigned long _buflen;
+	unsigned char *_buf;
+	unsigned long _len;
+	int _level;
+};

+ 1908 - 0
src/libs/common/algorithm/markup_stl.cc

@@ -0,0 +1,1908 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifdef _CGIHOST_PROCESS
+#include "../include/tsfnew.h"
+#endif
+
+#include "algorithm/markup_stl.h"
+#include <stdio.h>
+#include <stdint.h>
+using namespace std;
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#define new DEBUG_NEW
+#endif
+
+//[CMARKUPDEV
+// To add a version tag to new documents, define MARKUP_VERSIONTAG
+#ifdef MARKUP_VERSIONTAG
+#define x_VERSIONTAG "<?xml version=\"1.0\"?>\r\n"
+#endif
+//]CMARKUPDEV
+
+void MarkupSTL::operator=(const MarkupSTL &markup)
+{
+	m_iPosParent = markup.m_iPosParent;
+	m_iPos = markup.m_iPos;
+	m_iPosChild = markup.m_iPosChild;
+	m_iPosFree = markup.m_iPosFree;
+	m_nNodeType = markup.m_nNodeType;
+	//[CMARKUPDEV
+	m_nNodeOffset = markup.m_nNodeOffset;
+	m_nNodeLength = markup.m_nNodeLength;
+	//]CMARKUPDEV
+	m_aPos = markup.m_aPos;
+	m_strDoc = markup.m_strDoc;
+	MARKUP_SETDEBUGSTATE;
+}
+
+bool MarkupSTL::set_doc(const char *szDoc)
+{
+	// Reset indexes
+	m_iPosFree = 1;
+	reset_pos();
+	m_mapSavedPos.clear();
+
+	// Set document text
+	if (szDoc)
+		m_strDoc = szDoc;
+	else
+		m_strDoc.erase();
+
+	// Starting size of position array: 1 element per 64 bytes of document
+	// Tight fit when parsing small doc, only 0 to 2 reallocs when parsing large doc
+	// Start at 8 when creating new document
+	uint32_t nStartSize = m_strDoc.size() / 64 + 8;
+	if (m_aPos.size() < nStartSize)
+		m_aPos.resize(nStartSize);
+
+	// Parse document
+	bool bWellFormed = false;
+	if (m_strDoc.size()) {
+		m_aPos[0].Clear();
+		int iPos = x_ParseElem(0);
+		if (iPos > 0) {
+			m_aPos[0].iElemChild = iPos;
+			bWellFormed = true;
+		}
+	}
+
+	// Clear indexes if parse failed or empty document
+	if (!bWellFormed) {
+		m_aPos[0].Clear();
+		m_iPosFree = 1;
+	}
+
+	reset_pos();
+	return bWellFormed;
+};
+
+bool MarkupSTL::is_well_formed()
+{
+	if (m_aPos.size() && m_aPos[0].iElemChild)
+		return true;
+	return false;
+}
+
+bool MarkupSTL::Load(const char *szFileName)
+{
+	// Load document from file
+	bool bResult = false;
+	FILE *fp = fopen(szFileName, "rb");
+	if (fp) {
+		// Determine file length
+		fseek(fp, 0L, SEEK_END);
+		int nFileLen = ftell(fp);
+		fseek(fp, 0L, SEEK_SET);
+
+		// Load string
+		allocator<char> mem;
+		allocator<char>::pointer pBuffer =
+			mem.allocate(nFileLen + 1, NULL);
+		if (fread(pBuffer, nFileLen, 1, fp) == 1) {
+			pBuffer[nFileLen] = '\0';
+			bResult = set_doc(pBuffer);
+		}
+		fclose(fp);
+		mem.deallocate(pBuffer, 1);
+	}
+	if (!bResult) {
+		set_doc(NULL);
+	}
+	MARKUP_SETDEBUGSTATE;
+	return bResult;
+}
+
+bool MarkupSTL::Save(const char *szFileName)
+{
+	// Save document to file
+	bool bResult = false;
+	FILE *fp = fopen(szFileName, "wb");
+	if (fp) {
+		// Save string
+		int nFileLen = m_strDoc.size();
+		if (!nFileLen)
+			bResult = true;
+		else if (fwrite(m_strDoc.c_str(), nFileLen, 1, fp) == 1)
+			bResult = true;
+		fclose(fp);
+	}
+	return bResult;
+}
+
+bool MarkupSTL::find_elem(const char *szName)
+{
+	// Change current position only if found
+	//
+	if (m_aPos.size()) {
+		int iPos = x_FindElem(m_iPosParent, m_iPos, szName);
+		if (iPos) {
+			// Assign new position
+			x_SetPos(m_aPos[iPos].iElemParent, iPos, 0);
+			return true;
+		}
+	}
+	return false;
+}
+
+bool MarkupSTL::find_child_elem(const char *szName)
+{
+	// Change current child position only if found
+	//
+	// Shorthand: call this with no current main position
+	// means find child under root element
+	if (!m_iPos)
+		find_elem();
+
+	int iPosChild = x_FindElem(m_iPos, m_iPosChild, szName);
+	if (iPosChild) {
+		// Assign new position
+		int iPos = m_aPos[iPosChild].iElemParent;
+		x_SetPos(m_aPos[iPos].iElemParent, iPos, iPosChild);
+		return true;
+	}
+
+	return false;
+}
+
+//[CMARKUPDEV
+int MarkupSTL::find_node(int nType)
+{
+	// Change current node position only if a node is found
+	// If nType is 0 find any node, otherwise find node of type nType
+	// Return type of node or 0 if not found
+	// If found node is an element, change m_iPos
+
+	// Determine where in document to start scanning for node
+	int nTypeFound = 0;
+	int nNodeOffset = m_nNodeOffset;
+	if (m_nNodeType > 1) {
+		// By-pass current node
+		nNodeOffset += m_nNodeLength;
+	} else {
+		// Set position to begin looking for node
+		nNodeOffset = 0; // default to start of document
+		if (m_iPos) {
+			// After element
+			nNodeOffset = m_aPos[m_iPos].nEndR + 1;
+		} else {
+			// Immediately after start tag of parent
+			if (m_aPos[m_iPosParent].is_empty_element())
+				return 0;
+			if (m_iPosParent)
+				nNodeOffset = m_aPos[m_iPosParent].nStartR + 1;
+		}
+	}
+
+	// Get nodes until we find what we're looking for
+	int iPosNew = m_iPos;
+	TokenPos token(m_strDoc.c_str());
+	token.nNext = nNodeOffset;
+	do {
+		nNodeOffset = token.nNext;
+		nTypeFound = x_ParseNode(token);
+		if (!nTypeFound)
+			return 0;
+		if (nTypeFound == MNT_ELEMENT) {
+			if (iPosNew)
+				iPosNew = m_aPos[iPosNew].iElemNext;
+			else
+				iPosNew = m_aPos[m_iPosParent].iElemChild;
+			if (!iPosNew)
+				return 0;
+			if (!nType || (nType & nTypeFound)) {
+				// Found node, move position to this element
+				x_SetPos(m_iPosParent, iPosNew, 0);
+				return m_nNodeType;
+			}
+			token.nNext = m_aPos[iPosNew].nEndR + 1;
+		}
+	} while (nType && !(nType & nTypeFound));
+
+	m_iPos = iPosNew;
+	m_iPosChild = 0;
+	m_nNodeOffset = nNodeOffset;
+	m_nNodeLength = token.nNext - nNodeOffset;
+	m_nNodeType = nTypeFound;
+	MARKUP_SETDEBUGSTATE;
+	return m_nNodeType;
+}
+
+bool MarkupSTL::remove_node()
+{
+	if (m_iPos || m_nNodeLength) {
+		x_RemoveNode(m_iPosParent, m_iPos, m_nNodeType, m_nNodeOffset,
+			     m_nNodeLength);
+		m_iPosChild = 0;
+		MARKUP_SETDEBUGSTATE;
+		return true;
+	}
+	return false;
+}
+//]CMARKUPDEV
+
+string MarkupSTL::get_tag_name() const
+{
+	// Return the tag name at the current main position
+	string strTagName;
+
+	//[CMARKUPDEV
+	// This method is primarily for elements, however
+	// it does return something for certain other nodes
+	if (m_nNodeLength) {
+		switch (m_nNodeType) {
+		case MNT_PROCESSING_INSTRUCTION: {
+			// Processing instruction returns target
+			// For the document version it returns "xml"
+			TokenPos token(m_strDoc.c_str());
+			token.nNext = m_nNodeOffset + 2;
+			if (x_FindToken(token))
+				strTagName = x_GetToken(token);
+		} break;
+		case MNT_COMMENT:
+			strTagName = "#comment";
+			break;
+		case MNT_CDATA_SECTION:
+			strTagName = "#cdata-section";
+			break;
+		case MNT_DOCUMENT_TYPE: {
+			// Document type returns document type name
+			TokenPos token(m_strDoc.c_str());
+			token.nNext = m_nNodeOffset + 2;
+			// Find second token
+			if (x_FindToken(token) && x_FindToken(token))
+				strTagName = x_GetToken(token);
+		} break;
+		case MNT_TEXT:
+		case MNT_WHITESPACE:
+			strTagName = "#text";
+			break;
+		}
+		return strTagName;
+	}
+	//]CMARKUPDEV
+
+	if (m_iPos)
+		strTagName = x_GetTagName(m_iPos);
+	return strTagName;
+}
+
+bool MarkupSTL::into_elem()
+{
+	// If there is no child position and into_elem is called it will succeed in release 6.3
+	// (A subsequent call to find_elem will find the first element)
+	// The following short-hand behavior was never part of EDOM and was misleading
+	// It would find a child element if there was no current child element position and go into it
+	// It is removed in release 6.3, this change is NOT backwards compatible!
+	// if ( ! m_iPosChild )
+	//	find_child_elem();
+
+	if (m_iPos && m_nNodeType == MNT_ELEMENT) {
+		x_SetPos(m_iPos, m_iPosChild, 0);
+		return true;
+	}
+	return false;
+}
+
+bool MarkupSTL::out_of_elem()
+{
+	// Go to parent element
+	if (m_iPosParent) {
+		x_SetPos(m_aPos[m_iPosParent].iElemParent, m_iPosParent,
+			 m_iPos);
+		return true;
+	}
+	return false;
+}
+
+string MarkupSTL::get_attrib_name(int n) const
+{
+	// Return nth attribute name of main position
+	if (!m_iPos || m_nNodeType != MNT_ELEMENT)
+		return "";
+
+	TokenPos token(m_strDoc.c_str());
+	token.nNext = m_aPos[m_iPos].nStartL + 1;
+	for (int nAttrib = 0; nAttrib <= n; ++nAttrib)
+		if (!x_FindAttrib(token))
+			return "";
+
+	// Return substring of document
+	return x_GetToken(token);
+}
+
+bool MarkupSTL::save_pos(const char *szPosName)
+{
+	// Save current element position in saved position map
+	if (szPosName) {
+		SavedPos savedpos;
+		savedpos.iPosParent = m_iPosParent;
+		savedpos.iPos = m_iPos;
+		savedpos.iPosChild = m_iPosChild;
+		string strPosName = szPosName;
+		m_mapSavedPos[strPosName] = savedpos;
+		return true;
+	}
+	return false;
+}
+
+bool MarkupSTL::restore_pos(const char *szPosName)
+{
+	// Restore element position if found in saved position map
+	if (szPosName) {
+		string strPosName = szPosName;
+		mapSavedPosT::const_iterator iterSavePos =
+			m_mapSavedPos.find(strPosName);
+		if (iterSavePos != m_mapSavedPos.end()) {
+			SavedPos savedpos = (*iterSavePos).second;
+			x_SetPos(savedpos.iPosParent, savedpos.iPos,
+				 savedpos.iPosChild);
+			return true;
+		}
+	}
+	return false;
+}
+
+bool MarkupSTL::get_offsets(int &nStart, int &nEnd) const
+{
+	// Return document offsets of current main position element
+	// This is not part of EDOM but is used by the Markup project
+	if (m_iPos) {
+		nStart = m_aPos[m_iPos].nStartL;
+		nEnd = m_aPos[m_iPos].nEndR;
+		return true;
+	}
+	return false;
+}
+
+string MarkupSTL::get_child_sub_doc() const
+{
+	if (m_iPosChild) {
+		int nL = m_aPos[m_iPosChild].nStartL;
+		int nR = m_aPos[m_iPosChild].nEndR + 1;
+		TokenPos token(m_strDoc.c_str());
+		token.nNext = nR;
+		if (!x_FindToken(token) || m_strDoc[token.nL] == '<')
+			nR = token.nL;
+		return m_strDoc.substr(nL, nR - nL);
+	}
+	return "";
+}
+
+bool MarkupSTL::remove_elem()
+{
+	// Remove current main position element
+	if (m_iPos && m_nNodeType == MNT_ELEMENT) {
+		int iPos = x_RemoveElem(m_iPos);
+		x_SetPos(m_iPosParent, iPos, 0);
+		return true;
+	}
+	return false;
+}
+
+bool MarkupSTL::remove_child_elem()
+{
+	// Remove current child position element
+	if (m_iPosChild) {
+		int iPosChild = x_RemoveElem(m_iPosChild);
+		x_SetPos(m_iPosParent, m_iPos, iPosChild);
+		return true;
+	}
+	return false;
+}
+
+//[CMARKUPDEV
+string MarkupSTL::find_get_data(const char *szName)
+{
+	if (find_elem(szName))
+		return x_GetData(m_iPos);
+	return "";
+}
+
+bool MarkupSTL::find_set_data(const char *szName, const char *szData,
+			      int nCDATA)
+{
+	if (find_elem(szName))
+		return x_SetData(m_iPos, szData, nCDATA);
+	return false;
+}
+
+// Base64 methods
+string MarkupSTL::EncodeBase64(const unsigned char *pBuffer, int nBufferLen)
+{
+	// Return Base64 string
+	// 1 byte takes 2, 2:3, 3:4, 4:6, 5:7, 6:8, 7:10....
+	int nLenBase64 = nBufferLen + nBufferLen / 3 + 3;
+	nLenBase64 += (nLenBase64 / 64) * 2 + 4; // CRLFs
+	string strBase64;
+	strBase64.resize(nLenBase64);
+
+	// Start with CRLF
+	int nOffsetBase64 = 0;
+	strBase64[nOffsetBase64++] = '\r';
+	strBase64[nOffsetBase64++] = '\n';
+
+	// Loop through pBuffer 3 bytes at a time
+	const char *pCodes =
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+	int nOffsetBuffer = 0;
+	unsigned int n3BufferBytes;
+	int nTop;
+	int nPad = 0;
+	while (nOffsetBuffer < nBufferLen) {
+		// Set n3BufferBytes
+		n3BufferBytes = pBuffer[nOffsetBuffer++];
+		n3BufferBytes = n3BufferBytes << 8;
+		if (nOffsetBuffer < nBufferLen)
+			n3BufferBytes |= pBuffer[nOffsetBuffer++];
+		else
+			++nPad;
+		n3BufferBytes = n3BufferBytes << 8;
+		if (nOffsetBuffer < nBufferLen)
+			n3BufferBytes |= pBuffer[nOffsetBuffer++];
+		else
+			++nPad;
+
+		// Fill strBase64
+		nTop = nOffsetBase64 + 4;
+		while (nTop != nOffsetBase64) {
+			--nTop;
+			if (nPad == 0 || nTop < nOffsetBase64 + 4 - nPad)
+				strBase64[nTop] = pCodes[n3BufferBytes & 0x3f];
+			else
+				strBase64[nTop] = '=';
+			n3BufferBytes = n3BufferBytes >> 6;
+		}
+		nOffsetBase64 += 4;
+
+		if (!(nOffsetBase64 % 66) || nPad) {
+			strBase64[nOffsetBase64++] = '\r';
+			strBase64[nOffsetBase64++] = '\n';
+		}
+	}
+
+	strBase64.resize(nOffsetBase64);
+	return strBase64;
+}
+
+int MarkupSTL::DecodeBase64(const string &strBase64, unsigned char *pBuffer,
+			    int nBufferLen)
+{
+	// Return length of binary buffer after decoding
+	// If nBufferLen is 0, returns long enough length without decoding
+	// so that you can allocate a large enough buffer
+	// 1 byte takes 2, 2:3, 3:4, 4:6, 5:7, 6:8, 7:10....
+	// Otherwise, returns actual decoded length as long as it fits inside nBufferLen
+	int nLenBase64 = strBase64.size();
+	if (!nBufferLen)
+		return (nLenBase64 / 4) * 3 + 3;
+
+	// Loop through Base64, 4 bytes at a time
+	const unsigned char *pBase64 = (const unsigned char *)strBase64.c_str();
+	int nOffsetBase64 = 0;
+	int nOffsetBuffer = 0;
+	unsigned int n3BufferBytes;
+	int nTop;
+	int nCount;
+	int nCode;
+	int nPad = 0;
+	while (nOffsetBase64 < nLenBase64) {
+		// Set n3BufferBytes
+		nCount = 0;
+		n3BufferBytes = 0;
+		while (nCount != 4 && nOffsetBase64 < nLenBase64) {
+			// Check encoded character and bypass if whitespace
+			nCode = pBase64[nOffsetBase64++];
+			if (nCode == '\r' || nCode == '\n')
+				continue;
+
+			// Shift previous bits up before OR-ing 6 lower sig bits
+			n3BufferBytes = n3BufferBytes << 6;
+
+			// Use ASCII codes for fast conversion
+			if (nCode > 96) //(a-z)
+				n3BufferBytes |= (nCode - 71);
+			else if (nCode > 64) //(A-Z)
+				n3BufferBytes |= (nCode - 65);
+			else if (nCode == 61) //(=)
+				++nPad;
+			else if (nCode > 47) //(0-9)
+				n3BufferBytes |= (nCode + 4);
+			else if (nCode == 47) //(/)
+				n3BufferBytes |= 63;
+			else if (nCode == 43) //(+)
+				n3BufferBytes |= 62;
+			++nCount;
+		}
+
+		if (nCount == 4) {
+			// Fill pBuffer
+			nTop = nOffsetBuffer + 3;
+			if (nTop - nPad > nBufferLen)
+				return 0;
+			while (nTop != nOffsetBuffer) {
+				--nTop;
+				if (nPad == 0 ||
+				    nTop < nOffsetBuffer + 3 - nPad)
+					pBuffer[nTop] =
+						(unsigned char)(n3BufferBytes &
+								0xff);
+				n3BufferBytes = n3BufferBytes >> 8;
+			}
+			nOffsetBuffer += 3 - nPad;
+		}
+	}
+
+	return nOffsetBuffer;
+}
+//]CMARKUPDEV
+
+//////////////////////////////////////////////////////////////////////
+// Private Methods
+//////////////////////////////////////////////////////////////////////
+
+int MarkupSTL::x_GetFreePos()
+{
+	//
+	// This returns the index of the next unused ElemPos in the array
+	//
+	if ((uint32_t)m_iPosFree == m_aPos.size())
+		m_aPos.resize(m_iPosFree + m_iPosFree / 2);
+	++m_iPosFree;
+	return m_iPosFree - 1;
+}
+
+int MarkupSTL::x_ReleasePos()
+{
+	//
+	// This decrements the index of the next unused ElemPos in the array
+	// allowing the element index returned by GetFreePos() to be reused
+	//
+	--m_iPosFree;
+	return 0;
+}
+
+int MarkupSTL::x_ParseError(const char *szError, const char *szName)
+{
+	if (szName) {
+		char szFormat[300];
+		snprintf(szFormat, 299, szError, szName);
+		m_strError = szFormat;
+	} else
+		m_strError = szError;
+	x_ReleasePos();
+	return -1;
+}
+
+int MarkupSTL::x_ParseElem(int iPosParent)
+{
+	// This is either called by set_doc, x_AddSubDoc, or itself recursively
+	// m_aPos[iPosParent].nEndL is where to start parsing for the child element
+	// This returns the new position if a tag is found, otherwise zero
+	// In all cases we need to get a new ElemPos, but release it if unused
+	//
+	int iPos = x_GetFreePos();
+	m_aPos[iPos].nStartL = m_aPos[iPosParent].nEndL;
+	m_aPos[iPos].iElemParent = iPosParent;
+	m_aPos[iPos].iElemChild = 0;
+	m_aPos[iPos].iElemNext = 0;
+
+	// Start get_tag
+	// A loop is used to ignore all remarks tags and special tags
+	// i.e. <?xml version="1.0"?>, and <!-- comment here -->
+	// So any tag beginning with ? or ! is ignored
+	// Loop past ignored tags
+	TokenPos token(m_strDoc.c_str());
+	token.nNext = m_aPos[iPosParent].nEndL;
+	string strName;
+	while (strName.empty()) {
+		// Look for left angle bracket of start tag
+		m_aPos[iPos].nStartL = token.nNext;
+		if (!x_FindChar(token.szDoc, m_aPos[iPos].nStartL, '<'))
+			return x_ParseError("Element tag not found");
+
+		// Set parent's End tag to start looking from here (or later)
+		m_aPos[iPosParent].nEndL = m_aPos[iPos].nStartL;
+
+		// Determine whether this is an element, or bypass other type of node
+		token.nNext = m_aPos[iPos].nStartL + 1;
+		if (x_FindToken(token)) {
+			if (token.bIsString)
+				return x_ParseError("get_tag starts with quote");
+			char cFirstChar = m_strDoc[token.nL];
+			if (cFirstChar == '?' || cFirstChar == '!') {
+				token.nNext = m_aPos[iPos].nStartL;
+				if (!x_ParseNode(token))
+					return x_ParseError("Invalid node");
+			} else if (cFirstChar != '/') {
+				strName = x_GetToken(token);
+				// Look for end of tag
+				if (!x_FindChar(token.szDoc, token.nNext, '>'))
+					return x_ParseError(
+						"End of tag not found");
+			} else
+				return x_ReleasePos(); // probably end tag of parent
+		} else
+			return x_ParseError("Abrupt end within tag");
+	}
+	m_aPos[iPos].nStartR = token.nNext;
+
+	// Is ending mark within start tag, i.e. empty element?
+	if (m_strDoc[m_aPos[iPos].nStartR - 1] == '/') {
+		// Empty element
+		// close tag left is set to ending mark, and right to open tag right
+		m_aPos[iPos].nEndL = m_aPos[iPos].nStartR - 1;
+		m_aPos[iPos].nEndR = m_aPos[iPos].nStartR;
+	} else // look for end tag
+	{
+		// Element probably has contents
+		// Determine where to start looking for left angle bracket of end tag
+		// This is done by recursively parsing the contents of this element
+		int iInner, iInnerPrev = 0;
+		m_aPos[iPos].nEndL = m_aPos[iPos].nStartR + 1;
+		while ((iInner = x_ParseElem(iPos)) > 0) {
+			// Set links to iInner
+			if (iInnerPrev)
+				m_aPos[iInnerPrev].iElemNext = iInner;
+			else
+				m_aPos[iPos].iElemChild = iInner;
+			iInnerPrev = iInner;
+
+			// Set offset to reflect child
+			m_aPos[iPos].nEndL = m_aPos[iInner].nEndR + 1;
+		}
+		if (iInner == -1)
+			return -1;
+
+		// Look for left angle bracket of end tag
+		if (!x_FindChar(token.szDoc, m_aPos[iPos].nEndL, '<'))
+			return x_ParseError("End tag of %s element not found",
+					    strName.c_str());
+
+		// Look through tokens of end tag
+		token.nNext = m_aPos[iPos].nEndL + 1;
+		int nTokenCount = 0;
+		while (x_FindToken(token)) {
+			++nTokenCount;
+			if (!token.bIsString) {
+				// Is first token not an end slash mark?
+				if (nTokenCount == 1 &&
+				    m_strDoc[token.nL] != '/')
+					return x_ParseError(
+						"Expecting end tag of element %s",
+						strName.c_str());
+
+				else if (nTokenCount == 2 &&
+					 !token.Match(strName.c_str()))
+					return x_ParseError(
+						"End tag does not correspond to %s",
+						strName.c_str());
+
+				// Else is it a right angle bracket?
+				else if (m_strDoc[token.nL] == '>')
+					break;
+			}
+		}
+
+		// Was a right angle bracket not found?
+		if (!token.szDoc[token.nL] || nTokenCount < 2)
+			return x_ParseError(
+				"End tag not completed for element %s",
+				strName.c_str());
+		m_aPos[iPos].nEndR = token.nL;
+	}
+
+	// Successfully parsed element (and contained elements)
+	return iPos;
+}
+
+bool MarkupSTL::x_FindChar(const char *szDoc, int &nChar, char c)
+{
+	// static function
+	const char *pChar = &szDoc[nChar];
+	while (*pChar && *pChar != c)
+		pChar += 1;
+	nChar = pChar - szDoc;
+	if (!*pChar)
+		return false;
+	/*
+	while ( szDoc[nChar] && szDoc[nChar] != c )
+		nChar += _tclen( &szDoc[nChar] );
+	if ( ! szDoc[nChar] )
+		return false;
+	*/
+	return true;
+}
+
+bool MarkupSTL::x_FindToken(MarkupSTL::TokenPos &token)
+{
+	// Starting at token.nNext, bypass whitespace and find the next token
+	// returns true on success, members of token point to token
+	// returns false on end of document, members point to end of document
+	const char *szDoc = token.szDoc;
+	int nChar = token.nNext;
+	token.bIsString = false;
+
+	// By-pass leading whitespace
+	while (szDoc[nChar] && strchr(" \t\n\r", szDoc[nChar]))
+		++nChar;
+	if (!szDoc[nChar]) {
+		// No token was found before end of document
+		token.nL = nChar;
+		token.nR = nChar;
+		token.nNext = nChar;
+		return false;
+	}
+
+	// Is it an opening quote?
+	char cFirstChar = szDoc[nChar];
+	if (cFirstChar == '\"' || cFirstChar == '\'') {
+		token.bIsString = true;
+
+		// Move past opening quote
+		++nChar;
+		token.nL = nChar;
+
+		// Look for closing quote
+		x_FindChar(token.szDoc, nChar, cFirstChar);
+
+		// Set right to before closing quote
+		token.nR = nChar - 1;
+
+		// Set nChar past closing quote unless at end of document
+		if (szDoc[nChar])
+			++nChar;
+	} else {
+		// Go until special char or whitespace
+		token.nL = nChar;
+		while (szDoc[nChar] && !strchr(" \t\n\r<>=\\/?!", szDoc[nChar]))
+			nChar += 1;
+
+		// Adjust end position if it is one special char
+		if (nChar == token.nL)
+			++nChar; // it is a special char
+		token.nR = nChar - 1;
+	}
+
+	// nNext points to one past last char of token
+	token.nNext = nChar;
+	return true;
+}
+
+string MarkupSTL::x_GetToken(const MarkupSTL::TokenPos &token) const
+{
+	// The token contains indexes into the document identifying a small substring
+	// Build the substring from those indexes and return it
+	if (token.nL > token.nR)
+		return "";
+	return m_strDoc.substr(
+		token.nL, (token.nR - token.nL +
+			   (((uint32_t)(token.nR) < m_strDoc.size()) ? 1 : 0)));
+}
+
+int MarkupSTL::x_FindElem(int iPosParent, int iPos, const char *szPath)
+{
+	// If szPath is NULL or empty, go to next sibling element
+	// Otherwise go to next sibling element with matching path
+	//
+	/*
+	if ( iPos )
+		iPos = m_aPos[iPos].iElemNext;
+	else
+		iPos = m_aPos[iPosParent].iElemChild;
+
+	// Finished here if szPath not specified
+	if ( szPath == NULL || !szPath[0] )
+		return iPos;
+
+	// Search
+	TokenPos token( m_strDoc.c_str() );
+	while ( iPos )
+	{
+		// Compare tag name
+		token.nNext = m_aPos[iPos].nStartL + 1;
+		x_FindToken( token ); // Locate tag name
+		if ( token.Match(szPath) )
+			return iPos;
+		iPos = m_aPos[iPos].iElemNext;
+	}
+	return 0;
+	*/
+
+	//[CMARKUPDEV
+	//
+	// Example relative paths:
+	//
+	// "ITEM/QTY" first QTY child element of next ITEM element
+	// "ITEM/*" first child element of next ITEM element
+	//
+	// Example absolute paths:
+	//
+	// "/"  root
+	// "/ORDER"  root must be an ORDER element
+	// "/*/ITEM" first ITEM child element of root
+	//
+	int iPathOffset = 0;
+	if (szPath && szPath[0] == '/') {
+		// Go to root
+		iPos = m_aPos[0].iElemChild;
+		iPosParent = 0;
+		++iPathOffset;
+	} else if (iPos)
+		iPos = m_aPos[iPos].iElemNext;
+	else
+		iPos = m_aPos[iPosParent].iElemChild;
+
+	// Finished here if szPath not specified
+	if (szPath == NULL || !szPath[iPathOffset])
+		return iPos;
+
+	// Search
+	TokenPos token(m_strDoc.c_str());
+	while (iPos) {
+		// Compare tag name
+		token.nNext = m_aPos[iPos].nStartL + 1;
+		x_FindToken(token); // Locate tag name
+		if (szPath[iPathOffset] == '*') {
+			// Wildcard
+			if (szPath[iPathOffset + 1] == '/') {
+				iPathOffset += 2;
+				iPosParent = iPos;
+				iPos = m_aPos[iPosParent].iElemChild;
+			} else
+				return iPos;
+		} else if (token.Match(&szPath[iPathOffset])) {
+			// Matched tag name
+			int nLen = token.nR - token.nL + 1;
+			if (szPath[iPathOffset + nLen] == '/') {
+				iPathOffset += nLen + 1;
+				iPosParent = iPos;
+				iPos = m_aPos[iPosParent].iElemChild;
+			} else
+				return iPos;
+		} else
+			iPos = m_aPos[iPos].iElemNext;
+	}
+	return 0;
+	//]CMARKUPDEV
+}
+
+int MarkupSTL::x_ParseNode(MarkupSTL::TokenPos &token)
+{
+	// Call this with token.nNext set to the start of the node
+	// This returns the node type and token.nNext set to the char after the node
+	// If the node is not found or an element, token.nR is not determined
+	// White space between elements is a text node
+	int nTypeFound = 0;
+	const char *szDoc = token.szDoc;
+	token.nL = token.nNext;
+	if (szDoc[token.nL] == '<') {
+		// Started with <, could be:
+		// <!--...--> comment
+		// <!DOCTYPE ...> dtd
+		// <?target ...?> processing instruction
+		// <![CDATA[...]]> cdata section
+		// <NAME ...> element
+		//
+		if (!szDoc[token.nL + 1] || !szDoc[token.nL + 2])
+			return 0;
+		char cFirstChar = szDoc[token.nL + 1];
+		const char *szEndOfNode = NULL;
+		if (cFirstChar == '?') {
+			nTypeFound =
+				MNT_PROCESSING_INSTRUCTION; // processing instruction
+			szEndOfNode = "?>";
+		} else if (cFirstChar == '!') {
+			char cSecondChar = szDoc[token.nL + 2];
+			if (cSecondChar == '[') {
+				nTypeFound = MNT_CDATA_SECTION;
+				szEndOfNode = "]]>";
+			} else if (cSecondChar == '-') {
+				nTypeFound = MNT_COMMENT;
+				szEndOfNode = "-->";
+			} else {
+				// Document type requires tokenizing because of strings and brackets
+				nTypeFound = 0;
+				int nBrackets = 0;
+				while (x_FindToken(token)) {
+					if (!token.bIsString) {
+						char cChar = szDoc[token.nL];
+						if (cChar == '[')
+							++nBrackets;
+						else if (cChar == ']')
+							--nBrackets;
+						else if (nBrackets == 0 &&
+							 cChar == '>') {
+							nTypeFound =
+								MNT_DOCUMENT_TYPE;
+							break;
+						}
+					}
+				}
+				if (!nTypeFound)
+					return 0;
+			}
+		} else if (cFirstChar == '/') {
+			// End tag means no node found within parent element
+			return 0;
+		} else {
+			nTypeFound = MNT_ELEMENT;
+		}
+
+		// Search for end of node if not found yet
+		if (szEndOfNode) {
+			const char *pEnd =
+				strstr(&szDoc[token.nNext], szEndOfNode);
+			if (!pEnd)
+				return 0; // not well-formed
+			token.nNext = (pEnd - szDoc) + strlen(szEndOfNode);
+		}
+	} else if (szDoc[token.nL]) {
+		// It is text or whitespace because it did not start with <
+		nTypeFound = MNT_WHITESPACE;
+		if (x_FindToken(token)) {
+			if (szDoc[token.nL] == '<')
+				token.nNext = token.nL;
+			else {
+				nTypeFound = MNT_TEXT;
+				x_FindChar(token.szDoc, token.nNext, '<');
+			}
+		}
+	}
+	return nTypeFound;
+}
+
+string MarkupSTL::x_GetTagName(int iPos) const
+{
+	// Return the tag name at specified element
+	TokenPos token(m_strDoc.c_str());
+	token.nNext = m_aPos[iPos].nStartL + 1;
+	if (!iPos || !x_FindToken(token))
+		return "";
+
+	// Return substring of document
+	return x_GetToken(token);
+}
+
+bool MarkupSTL::x_FindAttrib(MarkupSTL::TokenPos &token,
+			     const char *szAttrib) const
+{
+	// If szAttrib is NULL find next attrib, otherwise find named attrib
+	// Return true if found
+	int nAttrib = 0;
+	for (int nCount = 0; x_FindToken(token); ++nCount) {
+		if (!token.bIsString) {
+			// Is it the right angle bracket?
+			if (m_strDoc[token.nL] == '>' ||
+			    m_strDoc[token.nL] == '/')
+				break; // attrib not found
+
+			// Equal sign
+			if (m_strDoc[token.nL] == '=')
+				continue;
+
+			// Potential attribute
+			if (!nAttrib && nCount) {
+				// Attribute name search?
+				if (!szAttrib || !szAttrib[0])
+					return true; // return with token at attrib name
+
+				// Compare szAttrib
+				if (token.Match(szAttrib))
+					nAttrib = nCount;
+			}
+		} else if (nAttrib && nCount == nAttrib + 2) {
+			return true;
+		}
+	}
+
+	// Not found
+	return false;
+}
+
+string MarkupSTL::x_GetAttrib(int iPos, const char *szAttrib) const
+{
+	// Return the value of the attrib at specified element
+	if (!iPos || m_nNodeType != MNT_ELEMENT)
+		return "";
+
+	TokenPos token(m_strDoc.c_str());
+	token.nNext = m_aPos[iPos].nStartL + 1;
+	if (szAttrib && x_FindAttrib(token, szAttrib))
+		return x_TextFromDoc(
+			token.nL,
+			token.nR - (((uint32_t)(token.nR) < m_strDoc.size()) ?
+					    0 :
+					    1));
+	return "";
+}
+
+bool MarkupSTL::x_SetAttrib(int iPos, const char *szAttrib, int nValue)
+{
+	// Convert integer to string and call set_child_attrib
+	char szVal[25];
+	snprintf(szVal, 24, "%d", nValue);
+	return x_SetAttrib(iPos, szAttrib, szVal);
+}
+
+bool MarkupSTL::x_SetAttrib(int iPos, const char *szAttrib, const char *szValue)
+{
+	// Set attribute in iPos element
+	if (!iPos || m_nNodeType != MNT_ELEMENT)
+		return false;
+
+	TokenPos token(m_strDoc.c_str());
+	token.nNext = m_aPos[iPos].nStartL + 1;
+	int nInsertAt, nReplace = 0;
+	string strInsert;
+	if (x_FindAttrib(token, szAttrib)) {
+		// Decision: for empty value leaving attrib="" instead of removing attrib
+		// Replace value only
+		strInsert = x_TextToDoc(szValue, true);
+		nInsertAt = token.nL;
+		nReplace = token.nR - token.nL + 1;
+	} else {
+		// Insert string name value pair
+		string strFormat;
+		strFormat = " ";
+		strFormat += szAttrib;
+		strFormat += "=\"";
+		strFormat += x_TextToDoc(szValue, true);
+		strFormat += "\"";
+		strInsert = strFormat;
+
+		// take into account whether it is an empty element
+		nInsertAt = m_aPos[iPos].nStartR -
+			    (m_aPos[iPos].is_empty_element() ? 1 : 0);
+	}
+
+	x_DocChange(nInsertAt, nReplace, strInsert);
+	int nAdjust = strInsert.size() - nReplace;
+	m_aPos[iPos].nStartR += nAdjust;
+	m_aPos[iPos].adjust_end(nAdjust);
+	x_Adjust(iPos, nAdjust);
+	MARKUP_SETDEBUGSTATE;
+	return true;
+}
+
+//[CMARKUPDEV
+bool MarkupSTL::x_RemoveAttrib(int iPos, const char *szAttrib)
+{
+	// Find attribute in iPos element and remove it
+	if (iPos && m_nNodeType == MNT_ELEMENT) {
+		TokenPos token(m_strDoc.c_str());
+		token.nNext = m_aPos[iPos].nStartL + 1;
+		while (x_FindAttrib(token)) {
+			// Compare szAttrib
+			if (token.Match(szAttrib)) {
+				int nInsertAt =
+					token.nL - 1; // preceding whitespace
+				if (x_FindToken(token) &&
+				    m_strDoc[token.nL] == '=' &&
+				    x_FindToken(token) && token.bIsString) {
+					int nReplace = token.nR - nInsertAt + 2;
+					x_DocChange(nInsertAt, nReplace, "");
+					m_aPos[iPos].nStartR -= nReplace;
+					m_aPos[iPos].adjust_end(-nReplace);
+					x_Adjust(iPos, -nReplace);
+					MARKUP_SETDEBUGSTATE;
+					return true;
+				}
+			}
+		}
+	}
+	return false;
+}
+//]CMARKUPDEV
+
+bool MarkupSTL::x_CreateNode(string &strNode, int nNodeType, const char *szText)
+{
+	// Set strNode based on nNodeType and szText
+	// Return false if szText would jeopardize well-formed document
+	//
+	switch (nNodeType) {
+	case MNT_CDATA_SECTION:
+		if (strstr(szText, "]]>") != NULL)
+			return false;
+		strNode = "<![CDATA[";
+		strNode += szText;
+		strNode += "]]>";
+		break;
+	//[CMARKUPDEV
+	case MNT_PROCESSING_INSTRUCTION:
+		strNode = "<?";
+		strNode += szText;
+		strNode += "?>";
+		break;
+	case MNT_COMMENT:
+		strNode = "<!--";
+		strNode += szText;
+		strNode += "-->";
+		break;
+	case MNT_ELEMENT:
+		strNode = "<";
+		strNode += szText;
+		strNode += "/>";
+		break;
+	case MNT_TEXT:
+	case MNT_WHITESPACE:
+		strNode = x_TextToDoc(szText);
+		break;
+	case MNT_DOCUMENT_TYPE:
+		strNode = szText;
+		break;
+		//]CMARKUPDEV
+	}
+	return true;
+}
+
+bool MarkupSTL::x_SetData(int iPos, const char *szData, int nCDATA)
+{
+	// Set data at specified position
+	// if nCDATA==1, set content of element to a CDATA Section
+	string strInsert;
+
+	//[CMARKUPDEV
+	if (iPos == m_iPos && m_nNodeLength) {
+		// Not an element
+		if (!x_CreateNode(strInsert, m_nNodeType, szData))
+			return false;
+		x_DocChange(m_nNodeOffset, m_nNodeLength, strInsert);
+		x_AdjustForNode(m_iPosParent, iPos,
+				strInsert.size() - m_nNodeLength);
+		m_nNodeLength = strInsert.size();
+		MARKUP_SETDEBUGSTATE;
+		return true;
+	}
+	//]CMARKUPDEV
+
+	// Set data in iPos element
+	if (!iPos || m_aPos[iPos].iElemChild)
+		return false;
+
+	// Build strInsert from szData based on nCDATA
+	// If CDATA section not valid, use parsed text (PCDATA) instead
+	if (nCDATA != 0)
+		if (!x_CreateNode(strInsert, MNT_CDATA_SECTION, szData))
+			nCDATA = 0;
+	if (nCDATA == 0)
+		strInsert = x_TextToDoc(szData);
+
+	// Decide where to insert
+	int nInsertAt, nReplace;
+	if (m_aPos[iPos].is_empty_element()) {
+		nInsertAt = m_aPos[iPos].nEndL;
+		nReplace = 1;
+
+		// Pre-adjust since <NAME/> becomes <NAME>data</NAME>
+		string strTagName = x_GetTagName(iPos);
+		m_aPos[iPos].nStartR -= 1;
+		m_aPos[iPos].nEndL -= (1 + strTagName.size());
+		string strFormat;
+		strFormat = ">";
+		strFormat += strInsert;
+		strFormat += "</";
+		strFormat += strTagName;
+		strInsert = strFormat;
+	} else {
+		nInsertAt = m_aPos[iPos].nStartR + 1;
+		nReplace = m_aPos[iPos].nEndL - m_aPos[iPos].nStartR - 1;
+	}
+	x_DocChange(nInsertAt, nReplace, strInsert);
+	int nAdjust = strInsert.size() - nReplace;
+	x_Adjust(iPos, nAdjust);
+	m_aPos[iPos].adjust_end(nAdjust);
+	MARKUP_SETDEBUGSTATE;
+	return true;
+}
+
+string MarkupSTL::x_GetData(int iPos) const
+{
+	//[CMARKUPDEV
+	if (iPos == m_iPos && m_nNodeLength) {
+		if (m_nNodeType == MNT_COMMENT)
+			return m_strDoc.substr(m_nNodeOffset + 4,
+					       m_nNodeLength - 7);
+		else if (m_nNodeType == MNT_PROCESSING_INSTRUCTION)
+			return m_strDoc.substr(m_nNodeOffset + 2,
+					       m_nNodeLength - 4);
+		else if (m_nNodeType == MNT_CDATA_SECTION)
+			return m_strDoc.substr(m_nNodeOffset + 8,
+					       m_nNodeLength - 11);
+		else if (m_nNodeType == MNT_TEXT)
+			return x_TextFromDoc(m_nNodeOffset,
+					     m_nNodeOffset + m_nNodeLength - 1);
+		else
+			return m_strDoc.substr(m_nNodeOffset, m_nNodeLength);
+	}
+	//]CMARKUPDEV
+
+	// Return a string representing data between start and end tag
+	// Return empty string if there are any children elements
+	if (!m_aPos[iPos].iElemChild && !m_aPos[iPos].is_empty_element()) {
+		// See if it is a CDATA section
+		TokenPos token(m_strDoc.c_str());
+		token.nNext = m_aPos[iPos].nStartR + 1;
+		if (x_FindToken(token) && m_strDoc[token.nL] == '<' &&
+		    token.nL + 11 < m_aPos[iPos].nEndL &&
+		    strncmp(&token.szDoc[token.nL + 1], "![CDATA[", 8) == 0) {
+			int nEndCDATA = m_strDoc.find("]]>", token.nNext);
+			if (nEndCDATA != (int32_t)(string::npos) &&
+			    nEndCDATA < m_aPos[iPos].nEndL) {
+				return m_strDoc.substr(
+					token.nL + 9, nEndCDATA - token.nL - 9);
+			}
+		}
+		return x_TextFromDoc(m_aPos[iPos].nStartR + 1,
+				     m_aPos[iPos].nEndL - 1);
+	}
+	return "";
+}
+
+string MarkupSTL::x_TextToDoc(const char *szText, bool bAttrib) const
+{
+	//
+	// &lt;   less than
+	// &amp;  ampersand
+	// &gt;   greater than
+	//
+	// and for attributes:
+	//
+	// &apos; apostrophe or single quote
+	// &quot; double quote
+	//
+	static const char *szaReplace[] = { "&lt;", "&amp;", "&gt;", "&apos;",
+					    "&quot;" };
+	const char *pFind = bAttrib ? "<&>\'\"" : "<&>";
+	const char *pSource = szText;
+	string strResult;
+	int nLen = strlen(szText);
+	strResult.reserve(nLen + nLen / 10);
+	char cSource = *pSource;
+	char *pFound;
+	while (cSource) {
+		if ((pFound = (char *)strchr(pFind, cSource)) != NULL) {
+			pFound = (char *)szaReplace[pFound - pFind];
+			strResult.append(pFound);
+		} else {
+			strResult += cSource;
+		}
+		cSource = *(++pSource);
+	}
+	return strResult;
+}
+
+string MarkupSTL::x_TextFromDoc(int nLeft, int nRight) const
+{
+	//
+	// Conveniently the result is always the same or shorter in length
+	//
+	static const char *szaCode[] = { "lt;", "amp;", "gt;", "apos;",
+					 "quot;" };
+	static int anCodeLen[] = { 3, 4, 3, 5, 5 };
+	static const char *szSymbol = "<&>\'\"";
+	string strResult;
+	strResult.reserve(nRight - nLeft + 1);
+	const char *pSource = m_strDoc.c_str();
+	int nChar = nLeft;
+	char cSource = pSource[nChar];
+	while (nChar <= nRight) {
+		if (cSource == '&') {
+			// If no match is found it means XML doc is invalid
+			// no devastating harm done, ampersand code will just be left in result
+			for (int nMatch = 0; nMatch < 5; ++nMatch) {
+				if (nChar <= nRight - anCodeLen[nMatch] &&
+				    strncmp(szaCode[nMatch],
+					    &pSource[nChar + 1],
+					    anCodeLen[nMatch]) == 0) {
+					cSource = szSymbol[nMatch];
+					nChar += anCodeLen[nMatch];
+					break;
+				}
+			}
+		}
+		strResult += cSource;
+		nChar++;
+		cSource = pSource[nChar];
+	}
+	return strResult;
+}
+
+void MarkupSTL::x_DocChange(int nLeft, int nReplace, const string &strInsert)
+{
+	// Insert strInsert int m_strDoc at nLeft replacing nReplace chars
+	//
+	//[CMARKUPDEV
+	// When creating a document, reduce reallocs by reserving string space
+	// Allow for 1.5 times the current allocation, with minimum of 200
+	int nNewLength = strInsert.size() + m_strDoc.size() - nReplace;
+	int nAllocLen = m_strDoc.capacity();
+	if (nNewLength > nAllocLen) {
+		int nReserve = nAllocLen + nAllocLen / 2;
+		if (nReserve < nNewLength)
+			nReserve = nNewLength;
+		if (nReserve < 200)
+			nReserve = 200;
+		m_strDoc.reserve(nReserve);
+	}
+	//]CMARKUPDEV
+	m_strDoc.replace(nLeft, nReplace, strInsert);
+}
+
+void MarkupSTL::x_Adjust(int iPos, int nShift, bool bAfterPos)
+{
+	// Loop through affected elements and adjust indexes
+	// Algorithm:
+	// 1. update children unless bAfterPos
+	//    (if no children or bAfterPos is true, end tag of iPos not affected)
+	// 2. update next siblings and their children
+	// 3. go up until there is a next sibling of a parent and update end tags
+	// 4. step 2
+	int iPosTop = m_aPos[iPos].iElemParent;
+	bool bPosFirst = bAfterPos; // mark as first to skip its children
+	while (iPos) {
+		// Were we at containing parent of affected position?
+		bool bPosTop = false;
+		if (iPos == iPosTop) {
+			// Move iPosTop up one towards root
+			iPosTop = m_aPos[iPos].iElemParent;
+			bPosTop = true;
+		}
+
+		// Traverse to the next update position
+		if (!bPosTop && !bPosFirst && m_aPos[iPos].iElemChild) {
+			// Depth first
+			iPos = m_aPos[iPos].iElemChild;
+		} else if (m_aPos[iPos].iElemNext) {
+			iPos = m_aPos[iPos].iElemNext;
+		} else {
+			// Look for next sibling of a parent of iPos
+			// When going back up, parents have already been done except iPosTop
+			while ((iPos = m_aPos[iPos].iElemParent) != 0 &&
+			       iPos != iPosTop)
+				if (m_aPos[iPos].iElemNext) {
+					iPos = m_aPos[iPos].iElemNext;
+					break;
+				}
+		}
+		bPosFirst = false;
+
+		// Shift indexes at iPos
+		if (iPos != iPosTop)
+			m_aPos[iPos].adjust_start(nShift);
+		m_aPos[iPos].adjust_end(nShift);
+	}
+}
+
+void MarkupSTL::x_LocateNew(int iPosParent, int &iPosRel, int &nOffset,
+			    int nLength, int nFlags)
+{
+	// Determine where to insert new element or node
+	//
+	bool bInsert = (nFlags & 1) ? true : false;
+	bool bHonorWhitespace = (nFlags & 2) ? true : false;
+
+	int nStartL;
+	if (nLength) {
+		// Located at a non-element node
+		if (bInsert)
+			nStartL = nOffset;
+		else
+			nStartL = nOffset + nLength;
+	} else if (iPosRel) {
+		// Located at an element
+		if (bInsert) // precede iPosRel
+			nStartL = m_aPos[iPosRel].nStartL;
+		else // follow iPosRel
+			nStartL = m_aPos[iPosRel].nEndR + 1;
+	} else if (m_aPos[iPosParent].is_empty_element()) {
+		// Parent has no separate end tag, so split empty element
+		nStartL = m_aPos[iPosParent].nStartR;
+	} else {
+		if (bInsert) // after start tag
+			nStartL = m_aPos[iPosParent].nStartR + 1;
+		else // before end tag
+			nStartL = m_aPos[iPosParent].nEndL;
+	}
+
+	// Go up to start of next node, unless its splitting an empty element
+	if (!bHonorWhitespace && !m_aPos[iPosParent].is_empty_element()) {
+		TokenPos token(m_strDoc.c_str());
+		token.nNext = nStartL;
+		if (!x_FindToken(token) || m_strDoc[token.nL] == '<')
+			nStartL = token.nL;
+	}
+
+	// Determine iPosBefore
+	int iPosBefore = 0;
+	if (iPosRel) {
+		if (bInsert) {
+			// Is iPosRel past first sibling?
+			int iPosPrev = m_aPos[iPosParent].iElemChild;
+			if (iPosPrev != iPosRel) {
+				// Find previous sibling of iPosRel
+				while (m_aPos[iPosPrev].iElemNext != iPosRel)
+					iPosPrev = m_aPos[iPosPrev].iElemNext;
+				iPosBefore = iPosPrev;
+			}
+		} else {
+			iPosBefore = iPosRel;
+		}
+	} else if (m_aPos[iPosParent].iElemChild) {
+		if (!bInsert) {
+			// Find last element under iPosParent
+			int iPosLast = m_aPos[iPosParent].iElemChild;
+			int iPosNext = iPosLast;
+			while (iPosNext) {
+				iPosLast = iPosNext;
+				iPosNext = m_aPos[iPosNext].iElemNext;
+			}
+			iPosBefore = iPosLast;
+		}
+	}
+
+	nOffset = nStartL;
+	iPosRel = iPosBefore;
+}
+
+bool MarkupSTL::x_AddElem(const char *szName, const char *szValue, bool bInsert,
+			  bool bAddChild)
+{
+	if (bAddChild) {
+		// Adding a child element under main position
+		if (!m_iPos)
+			return false;
+	} else if (m_iPosParent == 0) {
+		// Adding root element
+		if (is_well_formed())
+			return false;
+
+//[CMARKUPDEV
+#if defined(x_VERSIONTAG)
+		if (m_strDoc.is_empty())
+			m_strDoc = x_VERSIONTAG;
+#endif
+		//]CMARKUPDEV
+
+		// Locate after any version and DTD
+		m_aPos[0].nEndL = m_strDoc.size();
+	}
+
+	// Locate where to add element relative to current node
+	int iPosParent, iPosBefore, nOffset = 0, nLength = 0;
+	if (bAddChild) {
+		iPosParent = m_iPos;
+		iPosBefore = m_iPosChild;
+	} else {
+		iPosParent = m_iPosParent;
+		iPosBefore = m_iPos;
+		//[CMARKUPDEV
+		nOffset = m_nNodeOffset;
+		nLength = m_nNodeLength;
+		//]CMARKUPDEV
+	}
+	int nFlags = bInsert ? 1 : 0;
+	x_LocateNew(iPosParent, iPosBefore, nOffset, nLength, nFlags);
+	bool bEmptyParent = m_aPos[iPosParent].is_empty_element();
+	if (bEmptyParent)
+		nOffset += 2; // include CRLF
+
+	// Create element and modify positions of affected elements
+	// If no szValue is specified, an empty element is created
+	// i.e. either <NAME>value</NAME> or <NAME/>
+	//
+	int iPos = x_GetFreePos();
+	m_aPos[iPos].nStartL = nOffset;
+
+	// Set links
+	m_aPos[iPos].iElemParent = iPosParent;
+	m_aPos[iPos].iElemChild = 0;
+	m_aPos[iPos].iElemNext = 0;
+	if (iPosBefore) {
+		// Link in after iPosBefore
+		m_aPos[iPos].iElemNext = m_aPos[iPosBefore].iElemNext;
+		m_aPos[iPosBefore].iElemNext = iPos;
+	} else {
+		// First child
+		m_aPos[iPos].iElemNext = m_aPos[iPosParent].iElemChild;
+		m_aPos[iPosParent].iElemChild = iPos;
+	}
+
+	// Create string for insert
+	string strInsert;
+	int nLenName = strlen(szName);
+	int nLenValue = szValue ? strlen(szValue) : 0;
+	if (!nLenValue) {
+		// <NAME/> empty element
+		strInsert = "<";
+		strInsert += szName;
+		strInsert += "/>\r\n";
+		m_aPos[iPos].nStartR = m_aPos[iPos].nStartL + nLenName + 2;
+		m_aPos[iPos].nEndL = m_aPos[iPos].nStartR - 1;
+		m_aPos[iPos].nEndR = m_aPos[iPos].nEndL + 1;
+	} else {
+		// <NAME>value</NAME>
+		string strValue = x_TextToDoc(szValue);
+		nLenValue = strValue.size();
+		strInsert = "<";
+		strInsert += szName;
+		strInsert += ">";
+		strInsert += strValue;
+		strInsert += "</";
+		strInsert += szName;
+		strInsert += ">\r\n";
+		m_aPos[iPos].nStartR = m_aPos[iPos].nStartL + nLenName + 1;
+		m_aPos[iPos].nEndL = m_aPos[iPos].nStartR + nLenValue + 1;
+		m_aPos[iPos].nEndR = m_aPos[iPos].nEndL + nLenName + 2;
+	}
+
+	// Insert
+	int nReplace = 0, nLeft = m_aPos[iPos].nStartL;
+	if (bEmptyParent) {
+		string strParentTagName = x_GetTagName(iPosParent);
+		string strFormat;
+		strFormat = ">\r\n";
+		strFormat += strInsert;
+		strFormat += "</";
+		strFormat += strParentTagName;
+		strInsert = strFormat;
+		nLeft -= 3;
+		nReplace = 1;
+		// x_Adjust is going to update all affected indexes by one amount
+		// This will satisfy all except the empty parent
+		// Here we pre-adjust for the empty parent
+		// The empty tag slash is removed
+		m_aPos[iPosParent].nStartR -= 1;
+		// For the newly created end tag, see the following example:
+		// <A/> (len 4) becomes <A><B/></A> (len 11)
+		// In x_Adjust everything will be adjusted 11 - 4 = 7
+		// But the nEndL of element A should only be adjusted 5
+		m_aPos[iPosParent].nEndL -= (strParentTagName.size() + 1);
+	}
+	x_DocChange(nLeft, nReplace, strInsert);
+	x_Adjust(iPos, strInsert.size() - nReplace);
+
+	if (bAddChild)
+		x_SetPos(m_iPosParent, iPosParent, iPos);
+	else
+		x_SetPos(iPosParent, iPos, 0);
+	return true;
+}
+
+bool MarkupSTL::x_AddSubDoc(const char *szSubDoc, bool bInsert, bool bAddChild)
+{
+	// Add subdocument, parse, and modify positions of affected elements
+	//
+	int nOffset = 0, iPosParent, iPosBefore;
+	if (bAddChild) {
+		// Add a subdocument under main position, after current child position
+		if (!m_iPos)
+			return false;
+		iPosParent = m_iPos;
+		iPosBefore = m_iPosChild;
+	} else {
+		iPosParent = m_iPosParent;
+		iPosBefore = m_iPos;
+	}
+	int nFlags = bInsert ? 1 : 0;
+	x_LocateNew(iPosParent, iPosBefore, nOffset, 0, nFlags);
+	bool bEmptyParent = m_aPos[iPosParent].is_empty_element();
+	if (bEmptyParent)
+		nOffset += 2; // include CRLF
+
+	// if iPosBefore is NULL, insert as first element under parent
+	int nParentEndLBeforeAdd = m_aPos[iPosParent].nEndL;
+	int iPosFreeBeforeAdd = m_iPosFree;
+
+	// Skip version tag or DTD at start of subdocument
+	TokenPos token(szSubDoc);
+	int nNodeType = x_ParseNode(token);
+	while (nNodeType && nNodeType != MNT_ELEMENT) {
+		token.szDoc = &szSubDoc[token.nNext];
+		token.nNext = 0;
+		nNodeType = x_ParseNode(token);
+	}
+	string strInsert = token.szDoc;
+
+	// Insert subdocument
+	m_aPos[iPosParent].nEndL = nOffset;
+	int nReplace = 0, nLeft = nOffset;
+	string strParentTagName;
+	if (bEmptyParent) {
+		strParentTagName = x_GetTagName(iPosParent);
+		string strFormat;
+		strFormat = ">\r\n";
+		strFormat += strInsert;
+		strFormat += "</";
+		strFormat += strParentTagName;
+		strInsert = strFormat;
+		m_aPos[iPosParent].nEndL = m_aPos[iPosParent].nStartR + 2;
+		nLeft = m_aPos[iPosParent].nStartR - 1;
+		nReplace = 1;
+	}
+	x_DocChange(nLeft, nReplace, strInsert);
+
+	// Parse subdocument
+	int iPos = x_ParseElem(iPosParent);
+	m_aPos[iPosParent].nEndL = nParentEndLBeforeAdd;
+	if (iPos <= 0) {
+		// Abort because not well-formed
+		string strRevert = bEmptyParent ? "/" : "";
+		x_DocChange(nLeft, strInsert.size(), strRevert);
+		m_iPosFree = iPosFreeBeforeAdd;
+		return false;
+	} else {
+		// Link in parent and siblings
+		m_aPos[iPos].iElemParent = iPosParent;
+		if (iPosBefore) {
+			m_aPos[iPos].iElemNext = m_aPos[iPosBefore].iElemNext;
+			m_aPos[iPosBefore].iElemNext = iPos;
+		} else {
+			m_aPos[iPos].iElemNext = m_aPos[iPosParent].iElemChild;
+			m_aPos[iPosParent].iElemChild = iPos;
+		}
+
+		// Make empty parent pre-adjustment
+		if (bEmptyParent) {
+			m_aPos[iPosParent].nStartR -= 1;
+			m_aPos[iPosParent].nEndL -=
+				(strParentTagName.size() + 1);
+		}
+
+		// Adjust, but don't adjust children of iPos (bAfterPos=true)
+		x_Adjust(iPos, strInsert.size() - nReplace, true);
+	}
+
+	// Set position to top element of subdocument
+	if (bAddChild)
+		x_SetPos(m_iPosParent, iPosParent, iPos);
+	else // Main
+		x_SetPos(m_iPosParent, iPos, 0);
+	return true;
+}
+
+int MarkupSTL::x_RemoveElem(int iPos)
+{
+	// Remove element and all contained elements
+	// Return new position
+	//
+	int iPosParent = m_aPos[iPos].iElemParent;
+
+	// Find previous sibling and bypass removed element
+	// This leaves orphan positions in m_aPos array
+	int iPosLook = m_aPos[iPosParent].iElemChild;
+	int iPosPrev = 0;
+	while (iPosLook != iPos) {
+		iPosPrev = iPosLook;
+		iPosLook = m_aPos[iPosLook].iElemNext;
+	}
+	if (iPosPrev)
+		m_aPos[iPosPrev].iElemNext = m_aPos[iPos].iElemNext;
+	else
+		m_aPos[iPosParent].iElemChild = m_aPos[iPos].iElemNext;
+
+	// Remove from document
+	// Links have been changed to go around removed element
+	// But element position and links are still valid
+	int nAfterEnd = m_aPos[iPos].nEndR + 1;
+	TokenPos token(m_strDoc.c_str());
+	token.nNext = nAfterEnd;
+	if (!x_FindToken(token) || token.szDoc[token.nL] == '<')
+		nAfterEnd = token.nL;
+	int nLen = nAfterEnd - m_aPos[iPos].nStartL;
+	x_DocChange(m_aPos[iPos].nStartL, nLen, string());
+	x_Adjust(iPos, -nLen, true);
+	return iPosPrev;
+}
+
+//[CMARKUPDEV
+void MarkupSTL::x_AdjustForNode(int iPosParent, int iPos, int nShift)
+{
+	// Adjust affected indexes
+	if (!iPos) {
+		// Adjust end tag of parent, and adjust from there
+		int iPosChild = m_aPos[iPosParent].iElemChild;
+		if (!iPosParent) {
+			if (!iPosChild)
+				return; // no elements in this document yet
+
+			// Change happened before root element
+			m_aPos[iPosChild].adjust_start(nShift);
+			iPos = m_aPos[iPosChild].iElemChild;
+			if (iPos)
+				m_aPos[iPos].adjust_start(nShift);
+			else
+				iPos = iPosChild;
+		} else {
+			// Change happened before or at first element under iPosParent
+			iPos = iPosChild;
+			if (iPos)
+				m_aPos[iPos].adjust_start(nShift);
+			else
+				iPos = iPosParent;
+		}
+		m_aPos[iPos].adjust_end(nShift);
+	}
+	x_Adjust(iPos, nShift, true);
+}
+
+bool MarkupSTL::x_AddNode(int nNodeType, const char *szText, bool bInsert)
+{
+	// Add node of nNodeType after current node position
+	string strInsert;
+	if (!x_CreateNode(strInsert, nNodeType, szText))
+		return false;
+
+	// Only comments, DTDs, and processing instructions are followed by CRLF
+	// Other nodes are usually concerned with mixed content, so no CRLF
+	bool bNewline = false;
+	if (nNodeType == MNT_PROCESSING_INSTRUCTION ||
+	    nNodeType == MNT_COMMENT || nNodeType == MNT_DOCUMENT_TYPE)
+		bNewline = true;
+
+	// Locate where to add node relative to current node
+	int iPosBefore = m_iPos;
+	int iPosParent = m_iPosParent;
+	int nNodeOffset = m_nNodeOffset;
+	int nNodeLength = m_nNodeLength;
+	int nFlags = bNewline ? 0 : 2;
+	if (bInsert)
+		nFlags |= 1;
+	x_LocateNew(iPosParent, iPosBefore, nNodeOffset, nNodeLength, nFlags);
+	bool bEmptyParent = m_aPos[iPosParent].is_empty_element();
+	int nInsertAt = nNodeOffset;
+
+	// Get node length before adding CRLF
+	nNodeLength = strInsert.size();
+	if (bNewline)
+		strInsert += "\r\n";
+
+	// If its a new element, link it in
+	int iPos = iPosBefore;
+	if (nNodeType == MNT_ELEMENT) {
+		// Set indexes
+		iPos = x_GetFreePos();
+		m_aPos[iPos].nStartL = nNodeOffset;
+		m_aPos[iPos].nStartR = nNodeOffset + nNodeLength - 1;
+		m_aPos[iPos].nEndL = m_aPos[iPos].nStartR - 1;
+		m_aPos[iPos].nEndR = m_aPos[iPos].nStartR;
+		nNodeOffset = 0;
+		nNodeLength = 0;
+
+		// Set links
+		m_aPos[iPos].iElemParent = iPosParent;
+		m_aPos[iPos].iElemChild = 0;
+		m_aPos[iPos].iElemNext = 0;
+		if (iPosBefore) {
+			// Link in after iPosBefore
+			m_aPos[iPos].iElemNext = m_aPos[iPosBefore].iElemNext;
+			m_aPos[iPosBefore].iElemNext = iPos;
+		} else {
+			// First child
+			m_aPos[iPos].iElemNext = m_aPos[iPosParent].iElemChild;
+			m_aPos[iPosParent].iElemChild = iPos;
+		}
+	}
+
+	// Insert
+	int nReplace = 0;
+	if (bEmptyParent) {
+		nReplace = 1;
+		--nInsertAt;
+		string strParentTagName = x_GetTagName(iPosParent);
+		string strFormat;
+		strFormat = ">";
+		if (bNewline)
+			strFormat += "\r\n";
+		strFormat += strInsert;
+		strFormat += "</";
+		strFormat += strParentTagName;
+		strInsert = strFormat;
+		m_aPos[iPosParent].nStartR -= 1;
+		m_aPos[iPosParent].nEndL -= (strParentTagName.size() + 1);
+	}
+	x_DocChange(nInsertAt, nReplace, strInsert);
+
+	// need to adjust element positions after iPos
+	x_AdjustForNode(iPosParent, iPos, strInsert.size() - nReplace);
+
+	// Set current position
+	m_iPos = iPos;
+	m_iPosChild = 0;
+	m_nNodeOffset = nNodeOffset;
+	m_nNodeLength = nNodeLength;
+	m_nNodeType = nNodeType;
+	MARKUP_SETDEBUGSTATE;
+	return true;
+}
+
+void MarkupSTL::x_RemoveNode(int iPosParent, int &iPos, int &nNodeType,
+			     int &nNodeOffset, int &nNodeLength)
+{
+	// Remove node and return new position
+	//
+	int iPosPrev = iPos;
+
+	// Removing an element?
+	if (nNodeType == MNT_ELEMENT) {
+		nNodeOffset = m_aPos[iPos].nStartL;
+		nNodeLength = m_aPos[iPos].nEndR - m_aPos[iPos].nStartL + 1;
+
+		// Deleting iPos element, so find previous element if any
+		iPosPrev = m_aPos[iPosParent].iElemChild;
+		if (iPosPrev == iPos) {
+			iPosPrev = 0;
+			m_aPos[iPosParent].iElemChild = m_aPos[iPos].iElemNext;
+		} else {
+			while (m_aPos[iPosPrev].iElemNext != iPos)
+				iPosPrev = m_aPos[iPosPrev].iElemNext;
+			m_aPos[iPosPrev].iElemNext = m_aPos[iPos].iElemNext;
+		}
+	}
+
+	// Find previous node type, offset and length
+	int nPrevOffset = 0;
+	if (iPosPrev)
+		nPrevOffset = m_aPos[iPosPrev].nEndR + 1;
+	else if (iPosParent)
+		nPrevOffset = m_aPos[iPosParent].nStartR + 1;
+	TokenPos token(m_strDoc.c_str());
+	token.nNext = nPrevOffset;
+	int nPrevType = 0;
+	while (token.nNext < nNodeOffset) {
+		nPrevOffset = token.nNext;
+		nPrevType = x_ParseNode(token);
+	}
+	int nPrevLength = nNodeOffset - nPrevOffset;
+	if (!nPrevLength) {
+		// Previous node is iPosPrev element
+		nPrevOffset = 0;
+		if (iPosPrev)
+			nPrevType = MNT_ELEMENT;
+	}
+
+	// Remove node from document
+	x_DocChange(nNodeOffset, nNodeLength, string());
+	x_AdjustForNode(iPosParent, iPos, -nNodeLength);
+
+	nNodeType = nPrevType;
+	nNodeOffset = nPrevOffset;
+	nNodeLength = nPrevLength;
+	iPos = iPosPrev;
+}
+//]CMARKUPDEV

+ 384 - 0
src/libs/common/algorithm/markup_stl.h

@@ -0,0 +1,384 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#if !defined(AFX_MARKUPSTL_H__948A2705_9E68_11D2_A0BF_00105A27C570__INCLUDED_)
+#define AFX_MARKUPSTL_H__948A2705_9E68_11D2_A0BF_00105A27C570__INCLUDED_
+
+#include <string>
+#include <string.h>
+#include <map>
+#include <vector>
+
+#ifdef _DEBUG
+#define _DS(i) (i ? &(m_strDoc.c_str())[m_aPos[i].nStartL] : 0)
+#define MARKUP_SETDEBUGSTATE                                                   \
+	m_pMainDS = _DS(m_iPos);                                               \
+	m_pChildDS = _DS(m_iPosChild)
+#else
+#define MARKUP_SETDEBUGSTATE
+#endif
+
+class MarkupSTL {
+    public:
+	MarkupSTL()
+	{
+		set_doc(NULL);
+	};
+	MarkupSTL(const char *szDoc)
+	{
+		set_doc(szDoc);
+	};
+	MarkupSTL(const MarkupSTL &markup)
+	{
+		*this = markup;
+	};
+	void operator=(const MarkupSTL &markup);
+	virtual ~MarkupSTL(){};
+
+	// Navigate
+	bool Load(const char *szFileName);
+	bool set_doc(const char *szDoc);
+	bool is_well_formed();
+	bool find_elem(const char *szName = NULL);
+	bool find_child_elem(const char *szName = NULL);
+	bool into_elem();
+	bool out_of_elem();
+	void reset_child_pos()
+	{
+		x_SetPos(m_iPosParent, m_iPos, 0);
+	};
+
+	void reset_main_pos()
+	{
+		x_SetPos(m_iPosParent, 0, 0);
+	};
+	void reset_pos()
+	{
+		x_SetPos(0, 0, 0);
+	};
+	std::string get_tag_name() const;
+	std::string get_child_tag_name() const
+	{
+		return x_GetTagName(m_iPosChild);
+	};
+	std::string do_get() const
+	{
+		return x_GetData(m_iPos);
+	};
+	std::string get_child_data() const
+	{
+		return x_GetData(m_iPosChild);
+	};
+	//[CMARKUPDEV
+	std::string find_get_data(const char *szName);
+	//]CMARKUPDEV
+	std::string get_attrib(const char *szAttrib) const
+	{
+		return x_GetAttrib(m_iPos, szAttrib);
+	};
+	std::string get_child_attrib(const char *szAttrib) const
+	{
+		return x_GetAttrib(m_iPosChild, szAttrib);
+	};
+	std::string get_attrib_name(int n) const;
+	bool save_pos(const char *szPosName = "");
+	bool restore_pos(const char *szPosName = "");
+	bool get_offsets(int &nStart, int &nEnd) const;
+	std::string get_error() const
+	{
+		return m_strError;
+	};
+
+	enum MarkupNodeType {
+		MNT_ELEMENT = 1, // 0x01
+		MNT_TEXT = 2, // 0x02
+		MNT_WHITESPACE = 4, // 0x04
+		MNT_CDATA_SECTION = 8, // 0x08
+		MNT_PROCESSING_INSTRUCTION = 16, // 0x10
+		MNT_COMMENT = 32, // 0x20
+		MNT_DOCUMENT_TYPE = 64, // 0x40
+		MNT_EXCLUDE_WHITESPACE = 123, // 0x7b
+	};
+	//[CMARKUPDEV
+	int find_node(int nType = 0);
+	int get_node_type()
+	{
+		return m_nNodeType;
+	};
+	bool add_node(int nType, const char *szText)
+	{
+		return x_AddNode(nType, szText, false);
+	};
+	bool insert_node(int nType, const char *szText)
+	{
+		return x_AddNode(nType, szText, true);
+	};
+	bool remove_node();
+	//]CMARKUPDEV
+
+	// Create
+	bool Save(const char *szFileName);
+	std::string get_doc() const
+	{
+		return m_strDoc;
+	};
+	bool add_elem(const char *szName, const char *szData = NULL)
+	{
+		return x_AddElem(szName, szData, false, false);
+	};
+	bool insert_elem(const char *szName, const char *szData = NULL)
+	{
+		return x_AddElem(szName, szData, true, false);
+	};
+	bool add_child_elem(const char *szName, const char *szData = NULL)
+	{
+		return x_AddElem(szName, szData, false, true);
+	};
+	bool insert_child_elem(const char *szName, const char *szData = NULL)
+	{
+		return x_AddElem(szName, szData, true, true);
+	};
+	bool add_attrib(const char *szAttrib, const char *szValue)
+	{
+		return x_SetAttrib(m_iPos, szAttrib, szValue);
+	};
+	bool add_child_attrib(const char *szAttrib, const char *szValue)
+	{
+		return x_SetAttrib(m_iPosChild, szAttrib, szValue);
+	};
+	bool add_attrib(const char *szAttrib, int nValue)
+	{
+		return x_SetAttrib(m_iPos, szAttrib, nValue);
+	};
+	bool add_child_attrib(const char *szAttrib, int nValue)
+	{
+		return x_SetAttrib(m_iPosChild, szAttrib, nValue);
+	};
+	bool add_child_sub_doc(const char *szSubDoc)
+	{
+		return x_AddSubDoc(szSubDoc, false, true);
+	};
+	bool insert_child_sub_doc(const char *szSubDoc)
+	{
+		return x_AddSubDoc(szSubDoc, true, true);
+	};
+	std::string get_child_sub_doc() const;
+
+	// Modify
+	bool remove_elem();
+	bool remove_child_elem();
+	bool set_attrib(const char *szAttrib, const char *szValue)
+	{
+		return x_SetAttrib(m_iPos, szAttrib, szValue);
+	};
+	bool set_child_attrib(const char *szAttrib, const char *szValue)
+	{
+		return x_SetAttrib(m_iPosChild, szAttrib, szValue);
+	};
+	bool set_attrib(const char *szAttrib, int nValue)
+	{
+		return x_SetAttrib(m_iPos, szAttrib, nValue);
+	};
+	bool set_child_attrib(const char *szAttrib, int nValue)
+	{
+		return x_SetAttrib(m_iPosChild, szAttrib, nValue);
+	};
+	//[CMARKUPDEV
+	bool remove_attrib(const char *szAttrib)
+	{
+		return x_RemoveAttrib(m_iPos, szAttrib);
+	};
+	bool remove_child_attrib(const char *szAttrib)
+	{
+		return x_RemoveAttrib(m_iPosChild, szAttrib);
+	};
+	bool find_set_data(const char *szName, const char *szData,
+			   int nCDATA = 0);
+	//]CMARKUPDEV
+	bool set_data(const char *szData, int nCDATA = 0)
+	{
+		return x_SetData(m_iPos, szData, nCDATA);
+	};
+	bool set_child_data(const char *szData, int nCDATA = 0)
+	{
+		return x_SetData(m_iPosChild, szData, nCDATA);
+	};
+
+	//[CMARKUPDEV
+	// Base64
+	static std::string EncodeBase64(const unsigned char *pBuffer,
+					int nBufferLen);
+	static int DecodeBase64(const std::string &strBase64,
+				unsigned char *pBuffer, int nBufferLen);
+	//]CMARKUPDEV
+
+    protected:
+#ifdef _DEBUG
+	const char *m_pMainDS;
+	const char *m_pChildDS;
+#endif
+
+	std::string m_strDoc;
+	std::string m_strError;
+
+	struct ElemPos {
+		ElemPos()
+		{
+			Clear();
+		};
+		ElemPos(const ElemPos &pos)
+		{
+			*this = pos;
+		};
+		bool is_empty_element() const
+		{
+			return (nStartR == nEndL + 1);
+		};
+		void Clear()
+		{
+			nStartL = 0;
+			nStartR = 0;
+			nEndL = 0;
+			nEndR = 0;
+			nReserved = 0;
+			iElemParent = 0;
+			iElemChild = 0;
+			iElemNext = 0;
+		};
+		void adjust_start(int n)
+		{
+			nStartL += n;
+			nStartR += n;
+		};
+		void adjust_end(int n)
+		{
+			nEndL += n;
+			nEndR += n;
+		};
+		int nStartL;
+		int nStartR;
+		int nEndL;
+		int nEndR;
+		int nReserved;
+		int iElemParent;
+		int iElemChild;
+		int iElemNext;
+	};
+
+	typedef std::vector<ElemPos> vectorElemPosT;
+	vectorElemPosT m_aPos;
+	int m_iPosParent;
+	int m_iPos;
+	int m_iPosChild;
+	int m_iPosFree;
+	int m_nNodeType;
+	//[CMARKUPDEV
+	int m_nNodeOffset;
+	int m_nNodeLength;
+	//]CMARKUPDEV
+
+	struct TokenPos {
+		TokenPos(const char *sz)
+		{
+			Clear();
+			szDoc = sz;
+		};
+		void Clear()
+		{
+			nL = 0;
+			nR = -1;
+			nNext = 0;
+			bIsString = false;
+		};
+		bool Match(const char *szName)
+		{
+			int nLen = nR - nL + 1;
+// To ignore case, define MARKUP_IGNORECASE
+#ifdef MARKUP_IGNORECASE
+			return ((strnicmp(&szDoc[nL], szName, nLen) == 0)
+#else
+			return ((strncmp(&szDoc[nL], szName, nLen) == 0)
+#endif
+				&& (szName[nLen] == '\0' ||
+				    strchr(" =/[", szName[nLen])));
+		};
+		int nL;
+		int nR;
+		int nNext;
+		const char *szDoc;
+		bool bIsString;
+	};
+
+	struct SavedPos {
+		int iPosParent;
+		int iPos;
+		int iPosChild;
+	};
+	typedef std::map<std::string, SavedPos> mapSavedPosT;
+	mapSavedPosT m_mapSavedPos;
+
+	void x_SetPos(int iPosParent, int iPos, int iPosChild)
+	{
+		m_iPosParent = iPosParent;
+		m_iPos = iPos;
+		m_iPosChild = iPosChild;
+		m_nNodeType = iPos ? MNT_ELEMENT : 0;
+		//[CMARKUPDEV
+		m_nNodeOffset = 0;
+		m_nNodeLength = 0;
+		//]CMARKUPDEV
+		MARKUP_SETDEBUGSTATE;
+	};
+
+	int x_GetFreePos();
+	int x_ReleasePos();
+
+	int x_ParseElem(int iPos);
+	int x_ParseError(const char *szError, const char *szName = NULL);
+	static bool x_FindChar(const char *szDoc, int &nChar, char c);
+	static bool x_FindToken(TokenPos &token);
+	std::string x_GetToken(const TokenPos &token) const;
+	int x_FindElem(int iPosParent, int iPos, const char *szPath);
+	std::string x_GetTagName(int iPos) const;
+	std::string x_GetData(int iPos) const;
+	std::string x_GetAttrib(int iPos, const char *szAttrib) const;
+	bool x_AddElem(const char *szName, const char *szValue, bool bInsert,
+		       bool bAddChild);
+	bool x_AddSubDoc(const char *szSubDoc, bool bInsert, bool bAddChild);
+	bool x_FindAttrib(TokenPos &token, const char *szAttrib = NULL) const;
+	bool x_SetAttrib(int iPos, const char *szAttrib, const char *szValue);
+	bool x_SetAttrib(int iPos, const char *szAttrib, int nValue);
+	//[CMARKUPDEV
+	bool x_RemoveAttrib(int iPos, const char *szAttrib);
+	bool x_AddNode(int nNodeType, const char *szText, bool bInsert);
+	void x_RemoveNode(int iPosParent, int &iPos, int &nNodeType,
+			  int &nNodeOffset, int &nNodeLength);
+	void x_AdjustForNode(int iPosParent, int iPos, int nShift);
+	//]CMARKUPDEV
+	bool x_CreateNode(std::string &strNode, int nNodeType,
+			  const char *szText);
+	void x_LocateNew(int iPosParent, int &iPosRel, int &nOffset,
+			 int nLength, int nFlags);
+	int x_ParseNode(TokenPos &token);
+	bool x_SetData(int iPos, const char *szData, int nCDATA);
+	int x_RemoveElem(int iPos);
+	void x_DocChange(int nLeft, int nReplace, const std::string &strInsert);
+	void x_PosInsert(int iPos, int nInsertLength);
+	void x_Adjust(int iPos, int nShift, bool bAfterPos = false);
+	std::string x_TextToDoc(const char *szText, bool bAttrib = false) const;
+	std::string x_TextFromDoc(int nLeft, int nRight) const;
+};
+
+#endif // !defined(AFX_MARKUPSTL_H__948A2705_9E68_11D2_A0BF_00105A27C570__INCLUDED_)

+ 354 - 0
src/libs/common/algorithm/md5.cc

@@ -0,0 +1,354 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifdef _WIN32
+#define inline __inline
+#endif
+#define __USE_STRING_INLINES 1
+#include <string.h>
+#include <endian.h>
+#include "algorithm/md5.h"
+
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define byteReverse(x, y) /* */
+#else
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+	uint32_t t;
+	do {
+		t = (uint32_t)((unsigned)buf[3] << 8 | buf[2]) << 16 |
+		    ((unsigned)buf[1] << 8 | buf[0]);
+		*(uint32_t *)buf = t;
+		buf += 4;
+	} while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+	ctx->buf[0] = 0x67452301;
+	ctx->buf[1] = 0xefcdab89;
+	ctx->buf[2] = 0x98badcfe;
+	ctx->buf[3] = 0x10325476;
+
+	ctx->bits[0] = 0;
+	ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+	register uint32_t t;
+
+	/* Update bitcount */
+
+	t = ctx->bits[0];
+	if ((ctx->bits[0] = t + ((uint32_t)len << 3)) < t)
+		ctx->bits[1]++; /* Carry from low to high */
+	ctx->bits[1] += len >> 29;
+
+	t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+	/* get_handle any leading odd-sized chunks */
+
+	if (t) {
+		unsigned char *p = (unsigned char *)ctx->in + t;
+
+		t = 64 - t;
+		if (len < t) {
+			memcpy(p, buf, len);
+			return;
+		}
+		memcpy(p, buf, t);
+		byteReverse(ctx->in, 16);
+		MD5Transform(ctx->buf, (uint32_t *)ctx->in);
+		buf += t;
+		len -= t;
+	}
+	/* Process data in 64-byte chunks */
+
+	while (len >= 64) {
+		memcpy(ctx->in, buf, 64);
+		byteReverse(ctx->in, 16);
+		MD5Transform(ctx->buf, (uint32_t *)ctx->in);
+		buf += 64;
+		len -= 64;
+	}
+
+	/* get_handle any remaining bytes of data. */
+
+	memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+	unsigned int count;
+	unsigned char *p;
+
+	/* Compute number of bytes mod 64 */
+	count = (ctx->bits[0] >> 3) & 0x3F;
+
+	/* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+	p = ctx->in + count;
+	*p++ = 0x80;
+
+	/* Bytes of padding needed to make 64 bytes */
+	count = 64 - 1 - count;
+
+	/* Pad out to 56 mod 64 */
+	if (count < 8) {
+		/* Two lots of padding:  Pad the first block to 64 bytes */
+		memset(p, 0, count);
+		byteReverse(ctx->in, 16);
+		MD5Transform(ctx->buf, (uint32_t *)ctx->in);
+
+		/* Now fill the next block with 56 bytes */
+		memset(ctx->in, 0, 56);
+	} else {
+		/* Pad block to 56 bytes */
+		memset(p, 0, count - 8);
+	}
+	byteReverse(ctx->in, 14);
+
+	/* Append length in bits and transform */
+	((uint32_t *)ctx->in)[14] = ctx->bits[0];
+	((uint32_t *)ctx->in)[15] = ctx->bits[1];
+
+	MD5Transform(ctx->buf, (uint32_t *)ctx->in);
+	byteReverse((unsigned char *)ctx->buf, 4);
+	memcpy(digest, ctx->buf, 16);
+	memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s)                                        \
+	(w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+	register uint32_t a, b, c, d;
+
+	a = buf[0];
+	b = buf[1];
+	c = buf[2];
+	d = buf[3];
+
+	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+#if 0
+void MD5Digest( const unsigned char *msg, int len, unsigned char *digest) {
+	struct MD5Context ctx;
+	MD5Init (&ctx);
+	MD5Update (&ctx, msg, len);
+	MD5Final (digest, &ctx);
+}
+
+void MD5DigestHex( const unsigned char *msg, int len, unsigned char *digest) {
+	struct MD5Context ctx;
+	unsigned char h[16];
+	const char xdigit[] = "0123456789abcdef";
+	int i;
+
+	MD5Init (&ctx);
+	MD5Update (&ctx, msg, len);
+	MD5Final (h, &ctx);
+	for(i=0; i<16; i++) {
+		*digest++ = xdigit[h[i]>>4];
+		*digest++ = xdigit[h[i]&0xf];
+	}
+	*digest = '\0';
+}
+
+void MD5HMAC (const unsigned char *password,  unsigned pass_len,
+		const unsigned char *challenge, unsigned chal_len,
+		unsigned char response[16])
+{
+	int i;
+	unsigned char ipad[64];
+	unsigned char opad[64];
+	unsigned char hash_passwd[16];
+
+	struct MD5Context ctx;
+
+	if (pass_len > sizeof (ipad))
+	{
+		MD5Init (&ctx);
+		MD5Update (&ctx, password, pass_len);
+		MD5Final (hash_passwd, &ctx);
+		password = hash_passwd; pass_len = sizeof (hash_passwd);
+	}
+
+	memset (ipad, 0, sizeof (ipad));
+	memset (opad, 0, sizeof (opad));
+	memcpy (ipad, password, pass_len);
+	memcpy (opad, password, pass_len);
+
+	for (i=0; i<64; i++) {
+		ipad[i] ^= 0x36;
+		opad[i] ^= 0x5c;
+	}
+
+	MD5Init (&ctx);
+	MD5Update (&ctx, ipad, sizeof (ipad));
+	MD5Update (&ctx, challenge, chal_len);
+	MD5Final (response, &ctx);
+
+	MD5Init (&ctx);
+	MD5Update (&ctx, opad, sizeof (opad));
+	MD5Update (&ctx, response, 16);
+	MD5Final (response, &ctx);
+}
+
+void MD5HMAC2 (const unsigned char *password,  unsigned pass_len,
+		const unsigned char *challenge, unsigned chal_len,
+		const unsigned char *challenge2, unsigned chal_len2,
+		unsigned char response[16])
+{
+	int i;
+	unsigned char ipad[64];
+	unsigned char opad[64];
+	unsigned char hash_passwd[16];
+
+	struct MD5Context ctx;
+
+	if (pass_len > sizeof (ipad))
+	{
+		MD5Init (&ctx);
+		MD5Update (&ctx, password, pass_len);
+		MD5Final (hash_passwd, &ctx);
+		password = hash_passwd; pass_len = sizeof (hash_passwd);
+	}
+
+	memset (ipad, 0, sizeof (ipad));
+	memset (opad, 0, sizeof (opad));
+	memcpy (ipad, password, pass_len);
+	memcpy (opad, password, pass_len);
+
+	for (i=0; i<64; i++) {
+		ipad[i] ^= 0x36;
+		opad[i] ^= 0x5c;
+	}
+
+	MD5Init (&ctx);
+	MD5Update (&ctx, ipad, sizeof (ipad));
+	MD5Update (&ctx, challenge, chal_len);
+	MD5Update (&ctx, challenge2, chal_len2);
+	MD5Final (response, &ctx);
+
+	MD5Init (&ctx);
+	MD5Update (&ctx, opad, sizeof (opad));
+	MD5Update (&ctx, response, 16);
+	MD5Final (response, &ctx);
+}
+#endif

+ 54 - 0
src/libs/common/algorithm/md5.h

@@ -0,0 +1,54 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef _H_MD5_H
+#define _H_MD5_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+
+#define MD5Init _TX_MD5Init_
+#define MD5Update _TX_MD5Update_
+#define MD5Final _TX_MD5Final_
+#define MD5Digest _TX_MD5Digest_
+#define MD5DigestHex _TX_MD5DigestHex_
+#define MD5HMAC _TX_MD5HMAC_
+#define MD5HMAC2 _TX_MD5HMAC2_
+
+struct MD5Context {
+	uint32_t buf[4];
+	uint32_t bits[2];
+	uint8_t in[64];
+};
+
+typedef struct MD5Context md5_t;
+
+extern void MD5Init(struct MD5Context *);
+extern void MD5Update(struct MD5Context *, unsigned char const *, unsigned);
+extern void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
+extern void MD5Digest(const unsigned char *msg, int len, unsigned char *digest);
+extern void MD5DigestHex(const unsigned char *msg, int len,
+			 unsigned char *digest);
+extern void MD5HMAC(const unsigned char *password, unsigned pass_len,
+		    const unsigned char *challenge, unsigned chal_len,
+		    unsigned char response[16]);
+extern void MD5HMAC2(const unsigned char *password, unsigned pass_len,
+		     const unsigned char *challenge, unsigned chal_len,
+		     const unsigned char *challenge2, unsigned chal_len2,
+		     unsigned char response[16]);
+
+__END_DECLS
+#endif

+ 107 - 0
src/libs/common/algorithm/new_hash.cc

@@ -0,0 +1,107 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "algorithm/new_hash.h"
+
+#define mix(a, b, c)                                                           \
+	{                                                                      \
+		a = a - b;                                                     \
+		a = a - c;                                                     \
+		a = a ^ (c >> 13);                                             \
+		b = b - c;                                                     \
+		b = b - a;                                                     \
+		b = b ^ (a << 8);                                              \
+		c = c - a;                                                     \
+		c = c - b;                                                     \
+		c = c ^ (b >> 13);                                             \
+		a = a - b;                                                     \
+		a = a - c;                                                     \
+		a = a ^ (c >> 12);                                             \
+		b = b - c;                                                     \
+		b = b - a;                                                     \
+		b = b ^ (a << 16);                                             \
+		c = c - a;                                                     \
+		c = c - b;                                                     \
+		c = c ^ (b >> 5);                                              \
+		a = a - b;                                                     \
+		a = a - c;                                                     \
+		a = a ^ (c >> 3);                                              \
+		b = b - c;                                                     \
+		b = b - a;                                                     \
+		b = b ^ (a << 10);                                             \
+		c = c - a;                                                     \
+		c = c - b;                                                     \
+		c = c ^ (b >> 15);                                             \
+	}
+
+typedef unsigned int u4;
+
+unsigned int new_hash(const char *k, int length)
+{
+	unsigned int a, b, c; /* the internal state */
+	u4 len; /* how many key bytes still need mixing */
+
+	/* Set up the internal state */
+	len = length;
+	a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+	// 'HTTC'
+	c = 0x48545443; /* variable initialization of internal state */
+
+	/*---------------------------------------- handle most of the key */
+	while (len >= 12) {
+		a = a + (k[0] + ((u4)k[1] << 8) + ((u4)k[2] << 16) +
+			 ((u4)k[3] << 24));
+		b = b + (k[4] + ((u4)k[5] << 8) + ((u4)k[6] << 16) +
+			 ((u4)k[7] << 24));
+		c = c + (k[8] + ((u4)k[9] << 8) + ((u4)k[10] << 16) +
+			 ((u4)k[11] << 24));
+		mix(a, b, c);
+		k = k + 12;
+		len = len - 12;
+	}
+
+	/*------------------------------------- handle the last 11 bytes */
+	c = c + length;
+	switch (len) /* all the case statements fall through */
+	{
+	case 11:
+		c = c + ((u4)k[10] << 24);
+	case 10:
+		c = c + ((u4)k[9] << 16);
+	case 9:
+		c = c + ((u4)k[8] << 8);
+		/* the first byte of c is reserved for the length */
+	case 8:
+		b = b + ((u4)k[7] << 24);
+	case 7:
+		b = b + ((u4)k[6] << 16);
+	case 6:
+		b = b + ((u4)k[5] << 8);
+	case 5:
+		b = b + k[4];
+	case 4:
+		a = a + ((u4)k[3] << 24);
+	case 3:
+		a = a + ((u4)k[2] << 16);
+	case 2:
+		a = a + ((u4)k[1] << 8);
+	case 1:
+		a = a + k[0];
+		/* case 0: nothing left to add */
+	}
+	mix(a, b, c);
+	/*-------------------------------------------- report the result */
+	return c;
+}

+ 23 - 0
src/libs/common/algorithm/new_hash.h

@@ -0,0 +1,23 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef BITMAP_NEW_HASH_H__
+#define BITMAP_NEW_HASH_H__
+
+#include <stdint.h>
+
+uint32_t new_hash(const char *data, int len);
+
+#endif

+ 39 - 0
src/libs/common/algorithm/non_copyable.h

@@ -0,0 +1,39 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __DTC_NONCOPY_H__
+#define __DTC_NONCOPY_H__
+
+#include "namespace.h"
+
+DTC_BEGIN_NAMESPACE
+
+class noncopyable {
+    protected:
+	noncopyable(void)
+	{
+	}
+	~noncopyable(void)
+	{
+	}
+
+    private:
+	noncopyable(const noncopyable &);
+	const noncopyable &operator=(const noncopyable &);
+};
+
+DTC_END_NAMESPACE
+
+#endif

+ 74 - 0
src/libs/common/algorithm/relative_hour_calculator.h

@@ -0,0 +1,74 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef _RELATIVE_HOUR_CALCULATOR_H_
+#define _RELATIVE_HOUR_CALCULATOR_H_
+
+#include <string>
+#include "algorithm/singleton.h"
+#include <sys/time.h>
+
+class RelativeHourCalculator {
+    public:
+	RelativeHourCalculator()
+	{
+	}
+	~RelativeHourCalculator()
+	{
+	}
+	/*由于mktimehelper原因,需要减去八个小时*/
+	void set_base_hour(uint64_t ddwBaseYear)
+	{
+		uint64_t ddwRelativeTime =
+			mktime_helper(ddwBaseYear, 1, 1, 0, 0, 0);
+		m_BaseHour = (ddwRelativeTime / 3600 - 8);
+	}
+	uint64_t get_relative_hour()
+	{
+		uint64_t ddwCurHour = time(NULL) / 3600;
+
+		return (ddwCurHour - m_BaseHour);
+	}
+	uint64_t get_base_hour()
+	{
+		return m_BaseHour;
+	}
+
+	uint64_t mktime_helper(uint64_t year, uint64_t mon, uint64_t day,
+			       uint64_t hour, uint64_t min, uint64_t sec)
+	{
+		if (0 >= (int)(mon -= 2)) { /**/ /* 1..12 -> 11,12,1..10 */
+			mon += 12;
+				/**/ /* Puts Feb last since it has leap day */
+			year -= 1;
+		}
+
+		return (((((unsigned long)(year / 4 - year / 100 + year / 400 +
+					   367 * mon / 12 + day) +
+			   year * 365 - 719499) *
+				  24 +
+			  hour /**/ /* now have hours */
+			  ) * 60 +
+			 min /**/ /* now have minutes */
+			 ) * 60 +
+			sec);
+		/**/ /* finally seconds */
+	}
+
+    private:
+	uint64_t m_BaseHour; /*本业务对应的ModuleId*/
+};
+#define RELATIVE_HOUR_CALCULATOR Singleton<RelativeHourCalculator>::instance()
+#endif

+ 99 - 0
src/libs/common/algorithm/singleton.h

@@ -0,0 +1,99 @@
+/*
+* Copyright [2021] JD.com, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __SINGLETON_H__
+#define __SINGLETON_H__
+#include "lock/lock.h"
+#include "namespace.h"
+
+DTC_BEGIN_NAMESPACE
+
+template <class T> struct CreateUsingNew {
+	static T *Create(void)
+	{
+		return new T;
+	}
+
+	static void destory(T *p)
+	{
+		delete p;
+	}
+};
+
+template <class T, template <class> class CreationPolicy = CreateUsingNew>
+class Singleton {
+    public:
+	static T *instance(void);
+	static void destory(void);
+
+    private:
+	Singleton(void);
+	Singleton(const Singleton &);
+	Singleton &operator=(const Singleton &);
+
+    private:
+	static T *_instance;
+	static Mutex _mutex;
+};
+
+DTC_END_NAMESPACE
+
+DTC_USING_NAMESPACE
+
+//implement
+template <class T, template <class> class CreationPolicy>
+Mutex Singleton<T, CreationPolicy>::_mutex;
+
+template <class T, template <class> class CreationPolicy>
+T *Singleton<T, CreationPolicy>::_instance = 0;
+
+template <class T, template <class> class CreationPolicy>
+T *Singleton<T, CreationPolicy>::instance(void)
+{
+	if (0 == _instance) {
+		ScopedLock guard(_mutex);
+
+		if (0 == _instance) {
+			_instance = CreationPolicy<T>::Create();
+		}
+	}
+
+	return _instance;
+}
+
+/* BUGFIX by ada*/
+#if 0
+template <class T, template <class> class CreationPolicy> 
+void Singleton<T, CreationPolicy>::destory (void)
+{
+	return CreationPolicy<T>::destory (_instance);
+}
+#endif
+
+template <class T, template <class> class CreationPolicy>
+void Singleton<T, CreationPolicy>::destory(void)
+{
+	if (0 != _instance) {
+		ScopedLock guard(_mutex);
+		if (0 != _instance) {
+			CreationPolicy<T>::destory(_instance);
+			_instance = 0;
+		}
+	}
+
+	return;
+}
+
+#endif //__SINGLETON_H__

Vissa filer visades inte eftersom för många filer har ändrats