diff --git a/Makefile b/Makefile
index c6eb1d15d..6c7f4a51b 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ ifndef CC
CC = gcc
endif
-INCPATH += -I./src -I./include -I./src/leveldb/include -I./src/leveldb \
+INCPATH += -I./src -I./include -I./src/leveldb/include -I./src/leveldb -I./src/sdk \
-I./src/sdk/java/native-src $(DEPS_INCPATH)
CFLAGS += $(OPT) $(INCPATH) -fPIC -fvisibility=hidden # hide internal symbol of tera
CXXFLAGS += -std=gnu++11 $(CFLAGS)
@@ -28,28 +28,42 @@ PROTO_OUT_H := $(PROTO_FILES:.proto=.pb.h)
MASTER_SRC := $(wildcard src/master/*.cc)
TABLETNODE_SRC := $(wildcard src/tabletnode/*.cc)
IO_SRC := $(wildcard src/io/*.cc)
-SDK_SRC := $(wildcard src/sdk/*.cc)
+SDK_SRC := $(wildcard src/sdk/*.cc) $(wildcard src/sdk/test/global_txn_testutils.cc) \
+ src/observer/rowlocknode/zk_rowlock_client_zk_adapter.cc src/observer/rowlocknode/ins_rowlock_client_zk_adapter.cc
HTTP_SRC := $(wildcard src/sdk/http/*.cc)
PROTO_SRC := $(filter-out %.pb.cc, $(wildcard src/proto/*.cc)) $(PROTO_OUT_CC)
JNI_TERA_SRC := $(wildcard src/sdk/java/native-src/*.cc)
VERSION_SRC := src/version.cc
OTHER_SRC := $(wildcard src/zk/*.cc) $(wildcard src/utils/*.cc) $(VERSION_SRC) \
- src/tera_flags.cc
+ src/tera_flags.cc src/sdk/test/global_txn_testutils.cc
COMMON_SRC := $(wildcard src/common/base/*.cc) $(wildcard src/common/net/*.cc) \
$(wildcard src/common/file/*.cc) $(wildcard src/common/file/recordio/*.cc) \
- $(wildcard src/common/console/*.cc)
+ $(wildcard src/common/console/*.cc) $(wildcard src/common/log/*.cc) \
+ $(wildcard src/common/metric/*.cc)
SERVER_WRAPPER_SRC := src/tera_main_wrapper.cc
SERVER_SRC := src/tera_main.cc src/tera_entry.cc
CLIENT_SRC := src/teracli_main.cc
+TERAUTIL_SRC := src/terautil.cc
+GTXN_TEST_SRC := src/sdk/test/global_txn_test_tool.cc
TEST_CLIENT_SRC := src/tera_test_main.cc
TERA_C_SRC := src/tera_c.cc
MONITOR_SRC := src/monitor/teramo_main.cc
MARK_SRC := src/benchmark/mark.cc src/benchmark/mark_main.cc
+COMMON_TEST_SRC := $(wildcard src/common/test/*.cc)
TEST_SRC := src/utils/test/prop_tree_test.cc src/utils/test/tprinter_test.cc \
src/io/test/tablet_io_test.cc src/io/test/tablet_scanner_test.cc \
src/io/test/load_test.cc src/master/test/master_test.cc \
src/master/test/master_impl_test.cc src/master/test/trackable_gc_test.cc \
- src/common/test/thread_pool_test.cc
+ src/observer/test/rowlock_test.cc src/observer/test/scanner_test.cc \
+ src/observer/test/observer_test.cc \
+ $(wildcard src/sdk/test/*_test.cc) $(COMMON_TEST_SRC)
+
+TIMEORACLE_SRC := $(wildcard src/timeoracle/*.cc) src/tera_entry.cc
+TIMEORACLE_BENCH_SRC := src/timeoracle/bench/timeoracle_bench.cc
+ROWLOCK_SRC := $(wildcard src/observer/rowlocknode/*.cc) src/sdk/rowlock_client.cc
+ROWLOCK_PROXY_SRC := $(wildcard src/observer/rowlockproxy/*.cc)
+OBSERVER_SRC := src/observer/executor/scanner_impl.cc src/observer/executor/random_key_selector.cc
+OBSERVER_DEMO_SRC := $(wildcard src/observer/observer_demo.cc)
TEST_OUTPUT := test_output
UNITTEST_OUTPUT := $(TEST_OUTPUT)/unittest
@@ -65,39 +79,53 @@ COMMON_OBJ := $(COMMON_SRC:.cc=.o)
SERVER_WRAPPER_OBJ := $(SERVER_WRAPPER_SRC:.cc=.o)
SERVER_OBJ := $(SERVER_SRC:.cc=.o)
CLIENT_OBJ := $(CLIENT_SRC:.cc=.o)
+TERAUTIL_OBJ := $(TERAUTIL_SRC:.cc=.o)
+GTXN_TEST_OBJ := $(GTXN_TEST_SRC:.cc=.o)
TEST_CLIENT_OBJ := $(TEST_CLIENT_SRC:.cc=.o)
TERA_C_OBJ := $(TERA_C_SRC:.cc=.o)
MONITOR_OBJ := $(MONITOR_SRC:.cc=.o)
MARK_OBJ := $(MARK_SRC:.cc=.o)
HTTP_OBJ := $(HTTP_SRC:.cc=.o)
+COMMON_TEST_OBJ := $(COMMON_TEST_SRC:.cc=.o)
TEST_OBJ := $(TEST_SRC:.cc=.o)
+TIMEORACLE_OBJ := $(TIMEORACLE_SRC:.cc=.o)
+TIMEORACLE_BENCH_OBJ := $(TIMEORACLE_BENCH_SRC:.cc=.o)
+ROWLOCK_OBJ := $(ROWLOCK_SRC:.cc=.o)
+ROWLOCK_PROXY_OBJ := $(ROWLOCK_PROXY_SRC:.cc=.o)
+OBSERVER_OBJ := $(OBSERVER_SRC:.cc=.o)
+OBSERVER_DEMO_OBJ := $(OBSERVER_DEMO_SRC:.cc=.o)
ALL_OBJ := $(MASTER_OBJ) $(TABLETNODE_OBJ) $(IO_OBJ) $(SDK_OBJ) $(PROTO_OBJ) \
- $(JNI_TERA_OBJ) $(OTHER_OBJ) $(COMMON_OBJ) $(SERVER_OBJ) $(CLIENT_OBJ) \
+ $(JNI_TERA_OBJ) $(OTHER_OBJ) $(COMMON_OBJ) $(SERVER_OBJ) $(CLIENT_OBJ) $(TERAUTIL_OBJ) \
$(TEST_CLIENT_OBJ) $(TERA_C_OBJ) $(MONITOR_OBJ) $(MARK_OBJ) \
- $(SERVER_WRAPPER_OBJ)
+ $(SERVER_WRAPPER_OBJ) $(TIMEORACLE_OBJ) $(ROWLOCK_OBJ) $(ROWLOCK_PROXY_OBJ) $(OBSERVER_OBJ) $(OBSERVER_DEMO_OBJ)
LEVELDB_LIB := src/leveldb/libleveldb.a
LEVELDB_UTIL := src/leveldb/util/histogram.o src/leveldb/port/port_posix.o
-PROGRAM = tera_main tera_master tabletserver teracli teramo tera_test
+PROGRAM = tera_main tera_master tabletserver teracli terautil teramo tera_test timeoracle timeoracle_bench rowlock observer_demo rowlock_proxy
+TEST_PROGRAM=gtxn_test_tool
+
LIBRARY = libtera.a
SOLIBRARY = libtera.so
TERA_C_SO = libtera_c.so
JNILIBRARY = libjni_tera.so
+OBSERVER_LIBRARY = libobserver.a
BENCHMARK = tera_bench tera_mark
TESTS = prop_tree_test tprinter_test string_util_test tablet_io_test \
- tablet_scanner_test fragment_test progress_bar_test master_test load_test \
- thread_pool_test
+ tablet_scanner_test fragment_test progress_bar_test master_test load_test observer_test \
+ common_test sdk_test
.PHONY: all clean cleanall test
-all: $(PROGRAM) $(LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY) $(BENCHMARK)
+all: $(PROGRAM) $(TEST_PROGRAM) $(LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY) $(BENCHMARK) $(OBSERVER_LIBRARY)
mkdir -p build/include build/lib build/bin build/log build/benchmark
cp $(PROGRAM) build/bin
- cp $(LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY) build/lib
+ cp $(LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY) $(OBSERVER_LIBRARY) build/lib
cp src/leveldb/tera_bench .
cp -r benchmark/*.sh benchmark/ycsb4tera/ $(BENCHMARK) build/benchmark
cp -r include build/
cp -r conf build
+ mkdir -p test/tools
+ cp $(TEST_PROGRAM) test/tools
echo 'Done'
test: $(TESTS)
@@ -115,11 +143,12 @@ check: test
clean:
rm -rf $(ALL_OBJ) $(TEST_OBJ) $(PROTO_OUT_CC) $(PROTO_OUT_H) $(TEST_OUTPUT)
$(MAKE) clean -C src/leveldb
- rm -rf $(PROGRAM) $(LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY) $(BENCHMARK) $(TESTS) terahttp
+ rm -rf $(PROGRAM) $(TEST_PROGRAM) $(LIBRARY) $(OBSERVER_LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY) $(BENCHMARK) $(TESTS) terahttp
cleanall:
$(MAKE) clean
rm -rf build
+ rm -rf test/tools
tera_main: src/tera_main_wrapper.o src/version.o src/tera_flags.o
$(CXX) -o $@ $^ $(LDFLAGS)
@@ -135,6 +164,13 @@ tabletserver: $(SERVER_OBJ) $(TABLETNODE_OBJ) $(IO_OBJ) $(SDK_OBJ) \
libtera.a: $(SDK_OBJ) $(PROTO_OBJ) $(OTHER_OBJ) $(COMMON_OBJ) $(LEVELDB_UTIL)
$(AR) -rs $@ $^
+observer_demo : $(OBSERVER_DEMO_OBJ) $(OBSERVER_LIBRARY) $(LIBRARY)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
+libobserver.a: $(OBSERVER_OBJ) $(SDK_OBJ) $(PROTO_OBJ) $(OTHER_OBJ) $(COMMON_OBJ) $(LEVELDB_UTIL) \
+ $(IO_OBJ) $(SDK_OBJ)
+ $(AR) -rs $@ $^
+
libtera.so: $(SDK_OBJ) $(PROTO_OBJ) $(OTHER_OBJ) $(COMMON_OBJ) $(LEVELDB_UTIL)
$(CXX) -o $@ $^ $(SO_LDFLAGS)
@@ -144,6 +180,12 @@ libtera_c.so: $(TERA_C_OBJ) $(LIBRARY)
teracli: $(CLIENT_OBJ) $(LIBRARY)
$(CXX) -o $@ $^ $(LDFLAGS)
+terautil: $(TERAUTIL_OBJ) $(LIBRARY)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
+gtxn_test_tool: $(GTXN_TEST_OBJ) $(LIBRARY)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
teramo: $(MONITOR_OBJ) $(LIBRARY)
$(CXX) -o $@ $^ $(LDFLAGS)
@@ -153,6 +195,18 @@ tera_mark: $(MARK_OBJ) $(LIBRARY) $(LEVELDB_LIB)
tera_test: $(TEST_CLIENT_OBJ) $(LIBRARY)
$(CXX) -o $@ $(TEST_CLIENT_OBJ) $(LIBRARY) $(LDFLAGS)
+timeoracle: $(TIMEORACLE_OBJ) $(PROTO_OBJ) $(COMMON_OBJ) $(OTHER_OBJ)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
+timeoracle_bench : $(TIMEORACLE_BENCH_OBJ) $(LIBRARY)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
+rowlock : $(SERVER_OBJ) $(ROWLOCK_OBJ) $(PROTO_OBJ) $(OTHER_OBJ) $(COMMON_OBJ)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
+rowlock_proxy : $(SERVER_OBJ) $(ROWLOCK_PROXY_OBJ) $(PROTO_OBJ) $(OTHER_OBJ) $(COMMON_OBJ) $(OBSERVER_LIBRARY)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
terahttp: $(HTTP_OBJ) $(PROTO_OBJ) $(LIBRARY)
$(CXX) -o $@ $^ $(LDFLAGS)
@@ -165,7 +219,7 @@ src/leveldb/libleveldb.a: FORCE
tera_bench:
# unit test
-thread_pool_test: src/common/test/thread_pool_test.o $(LIBRARY)
+common_test: $(COMMON_TEST_OBJ) $(LIBRARY)
$(CXX) -o $@ $^ $(LDFLAGS)
prop_tree_test: src/utils/test/prop_tree_test.o $(LIBRARY)
@@ -200,6 +254,15 @@ master_test: src/master/test/master_test.o src/master/test/master_impl_test.o \
$(PROTO_OBJ) $(OTHER_OBJ) $(COMMON_OBJ) $(LEVELDB_LIB)
$(CXX) -o $@ $^ $(LDFLAGS)
+sdk_test: src/sdk/test/global_txn_internal_test.o src/sdk/test/global_txn_test.o \
+ src/sdk/test/filter_utils_test.o src/sdk/test/scan_impl_test.o \
+ src/sdk/test/sdk_timeout_manager_test.o src/sdk/test/sdk_test.o $(SDK_OBJ) \
+ $(PROTO_OBJ) $(OTHER_OBJ) $(COMMON_OBJ) $(LEVELDB_LIB)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
+observer_test: src/observer/test/rowlock_test.o src/observer/test/scanner_test.o src/observer/test/observer_test.o src/observer/observer_demo/demo_observer.o $(PROTO_OBJ) $(COMMON_OBJ) $(OTHER_OBJ) $(OBSERVER_OBJ) $(LIBRARY)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
$(ALL_OBJ): %.o: %.cc $(PROTO_OUT_H)
$(CXX) $(CXXFLAGS) -c $< -o $@
@@ -222,8 +285,8 @@ proto: $(PROTO_OUT_CC) $(PROTO_OUT_H)
# install output into system directories
.PHONY: install
-install: $(PROGRAM) $(LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY)
+install: $(PROGRAM) $(LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY)
mkdir -p $(INSTALL_PREFIX)/bin $(INSTALL_PREFIX)/include $(INSTALL_PREFIX)/lib
cp -rf $(PROGRAM) $(INSTALL_PREFIX)/bin
cp -rf include/* $(INSTALL_PREFIX)/include
- cp -rf $(LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY) $(INSTALL_PREFIX)/lib
+ cp -rf $(LIBRARY) $(SOLIBRARY) $(TERA_C_SO) $(JNILIBRARY) $(INSTALL_PREFIX)/lib
diff --git a/benchmark/run_test.sh b/benchmark/run_test.sh
index 8f33ce5e6..b1e9e7c34 100755
--- a/benchmark/run_test.sh
+++ b/benchmark/run_test.sh
@@ -1,8 +1,8 @@
#!/bin/bash
-if [[ $# != 7 || $6 -lt 0 || $6 -gt 100 ]]; then
- echo "$0 DIST[zipfian, uniform, latest] ROW_NUM OP_NUM VALUE_SIZE COLUMN_NUM UPDATE_PROPORTION[0~100] TABLE_NAME"
- exit 0
+if [[ $# != 9 || $6 -lt 0 || $6 -gt 100 ]]; then
+ echo "$0 DIST[zipfian, uniform, latest] ROW_NUM OP_NUM VALUE_SIZE COLUMN_NUM UPDATE_PROPORTION[0~100] OP_SPEED THREAD_NUM TABLE_NAME"
+ exit 1
fi
DIST=$1
@@ -11,11 +11,12 @@ OP_NUM=$3
VALUE_SIZE=$4
COLUMN_NUM=$5
UPDATE_PROPORTION=$6
-TABLE_NAME=$7
+OP_SPEED=$7
+THREAD_NUM=$8
+TABLE_NAME=$9
-UPDATE_PROPORTION=`printf "%02d" $6`
-READ_PROPORTION=`expr 100 - $UPDATE_PROPORTION`
-READ_PROPORTION=`printf "%02d" $READ_PROPORTION`
+UPDATE_PROPORTION=`echo $6 | awk '{printf("%.2f",$1/100)}'`
+READ_PROPORTION=`echo $6 | awk '{printf("%.2f",(100-$1)/100)}'`
echo "$UPDATE_PROPORTION"
echo "$READ_PROPORTION"
@@ -30,8 +31,12 @@ bin/ycsb run tera -p workload=com.yahoo.ycsb.workloads.CoreWorkload \
-p operationcount=$OP_NUM \
-p fieldlength=$VALUE_SIZE \
-p fieldcount=$COLUMN_NUM \
- -p updateproportion=0.$UPDATE_PROPORTION \
- -p readproportion=0.$READ_PROPORTION \
+ -p updateproportion=$UPDATE_PROPORTION \
+ -p readproportion=$READ_PROPORTION \
+ -p target=$OP_SPEED \
+ -p thread=$THREAD_NUM \
-p exportfile=ycsb.out \
| ./tera_mark --mode=m --tablename=$TABLE_NAME --type=async --verify=false
+exit $?
+
diff --git a/benchmark/ycsb4tera.md b/benchmark/ycsb4tera.md
index f32ae9e28..d348434ce 100644
--- a/benchmark/ycsb4tera.md
+++ b/benchmark/ycsb4tera.md
@@ -30,6 +30,13 @@
更新(写入)占所有操作的比例
updateproportion: what proportion of operations should be updates (default: 0.05)
+
+ 每秒总共操作的次数
+ target: target ops/sec all threads (default: unthrottled)
+
+ 客户端线程数
+ thread: number of client threads (default: 1)
+
```
以下参数对于tera的测试意义不大,使用默认值即可:
diff --git a/build.conf.template b/build.conf.template
index 1fd914ec6..170383dde 100755
--- a/build.conf.template
+++ b/build.conf.template
@@ -18,6 +18,7 @@ LIBUNWIND_VERSION=0.99
GPERFTOOLS_VERSION=2.5
INS_VERSION=0.17
NOSE_VERSION=1.3.7
+MONGOOSE_VERSION=6.8
if [ $MIRROR == "china" ]; then
BOOST_URL=http://mirrors.tuna.tsinghua.edu.cn/macports/distfiles/boost/boost_${BOOST_VERSION}.tar.bz2
@@ -32,6 +33,7 @@ if [ $MIRROR == "china" ]; then
GPERFTOOLS_URL=https://github.com/00k/gperftools/raw/master/gperftools-${GPERFTOOLS_VERSION}.tar.gz
INS_URL=https://github.com/baidu/ins/archive/${INS_VERSION}.tar.gz
NOSE_URL=http://mirrors.163.com/gentoo/distfiles/nose-${NOSE_VERSION}.tar.gz
+ MONGOOSE_URL=https://github.com/cesanta/mongoose/archive/${MONGOOSE_VERSION}.tar.gz
elif [ $MIRROR == "origin" ]; then
BOOST_URL=http://downloads.sourceforge.net/project/boost/boost/1.58.0/boost_${BOOST_VERSION}.tar.bz2
PROTOBUF_URL=https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-${PROTOBUF_VERSION}.tar.bz2
@@ -45,19 +47,7 @@ elif [ $MIRROR == "origin" ]; then
GPERFTOOLS_URL=https://github.com/gperftools/gperftools/releases/download/gperftools-${GPERFTOOLS_VERSION}/gperftools-${GPERFTOOLS_VERSION}.tar.gz
INS_URL=https://github.com/baidu/ins/archive/${INS_VERSION}.tar.gz
NOSE_URL=https://pypi.python.org/packages/58/a5/0dc93c3ec33f4e281849523a5a913fa1eea9a3068acfa754d44d88107a44/nose-${NOSE_VERSION}.tar.gz
-elif [ $MIRROR == "baidu" ]; then
- BOOST_URL=http://gitlab.baidu.com/baidups/third/raw/master/boost_${BOOST_VERSION}.tar.bz2
- PROTOBUF_URL=http://gitlab.baidu.com/baidups/third/raw/master/protobuf-${PROTOBUF_VERSION}.tar.bz2
- SNAPPY_URL=http://gitlab.baidu.com/baidups/third/raw/master/snappy-${SNAPPY_VERSION}.tar.gz
- SOFA_PBRPC_URL=http://gitlab.baidu.com/baidups/third/raw/master/sofa-pbrpc-${SOFA_PBRPC_VERSION}.tar.gz
- ZOOKEEPER_URL=http://gitlab.baidu.com/baidups/third/raw/master/zookeeper-${ZOOKEEPER_VERSION}.tar.gz
- GFLAGS_URL=http://gitlab.baidu.com/baidups/third/raw/master/gflags-${GFLAGS_VERSION}.tar.gz
- GLOG_URL=http://gitlab.baidu.com/baidups/third/raw/master/glog-${GLOG_VERSION}.tar.gz
- GTEST_URL=http://gitlab.baidu.com/baidups/third/raw/master/googletest-release-${GTEST_VERSION}.tar.gz
- LIBUNWIND_URL=http://gitlab.baidu.com/baidups/third/raw/master/libunwind-${LIBUNWIND_VERSION}.tar.gz
- GPERFTOOLS_URL=http://gitlab.baidu.com/baidups/third/raw/master/gperftools-${GPERFTOOLS_VERSION}.tar.gz
- INS_URL=http://gitlab.baidu.com/baidups/third/raw/master/ins-${INS_VERSION}.tar.gz
- NOSE_URL=http://gitlab.baidu.com/baidups/third/raw/master/nose-${NOSE_VERSION}.tar.gz
+ MONGOOSE_URL=https://github.com/cesanta/mongoose/archive/${MONGOOSE_VERSION}.tar.gz
else
return 1
fi
diff --git a/build.sh b/build.sh
index 1e1156aa9..f565149ef 100755
--- a/build.sh
+++ b/build.sh
@@ -218,7 +218,7 @@ elif [ ! -f "${FLAG_DIR}/ins_${INS_VERSION}" ] \
sed -i "s|^PROTOBUF_PATH ?=.*|PROTOBUF_PATH ?=${DEPS_PREFIX}|" Makefile
sed -i "s|^PBRPC_PATH ?=.*|PBRPC_PATH ?=${DEPS_PREFIX}|" Makefile
sed -i "s|^GTEST_PATH ?=.*|GTEST_PATH ?=${DEPS_PREFIX}|" Makefile
- #BOOST_PATH=${DEPS_PREFIX}/boost_${BOOST_VERSION} make install_sdk
+ # BOOST_PATH=${DEPS_PREFIX}/boost_${BOOST_VERSION} make install_sdk
make -j4 install_sdk
cd -
touch "${FLAG_DIR}/ins_${INS_VERSION}"
@@ -239,6 +239,23 @@ elif [ ! -f "${FLAG_DIR}/nose_${NOSE_VERSION}" ] \
touch "${FLAG_DIR}/nose_${NOSE_VERSION}"
fi
+# mongoose
+if [ ${MONGOOSE_VERSION} == "DISABLE" ]; then
+ echo "Disable mongoose."
+elif [ ! -f "${FLAG_DIR}/mongoose_${MONGOOSE_VERSION}" ] \
+ || [ ! -f "${DEPS_PREFIX}/include/mongoose.h" ] \
+ || [ ! -f "${DEPS_PREFIX}/lib/libmongoose.a" ]; then
+ wget --no-check-certificate -O mongoose-${MONGOOSE_VERSION}.tar.gz ${MONGOOSE_URL}
+ tar zxf mongoose-${MONGOOSE_VERSION}.tar.gz --recursive-unlink
+ cd mongoose-${MONGOOSE_VERSION}
+ cp -af mongoose.h ${DEPS_PREFIX}/include
+ gcc -c mongoose.c -o mongoose.o -g2 -pipe -Wall -Werror -fPIC
+ ar -rv libmongoose.a mongoose.o
+ cp -af libmongoose.a ${DEPS_PREFIX}/lib
+ cd -
+ touch "${FLAG_DIR}/mongoose_${MONGOOSE_VERSION}"
+fi
+
cd ${WORK_DIR}
########################################
diff --git a/build_version.sh b/build_version.sh
index 8cac725a6..2534fcb85 100755
--- a/build_version.sh
+++ b/build_version.sh
@@ -56,7 +56,7 @@ GIT_INFO_FILE=git_info.tmp
VERSION_CPP_FILE=src/version.cc
# generate template file
-git log | head -n 6 | sed 's/$/&\\n\\/g' > $GIT_INFO_FILE
+git log | head -n 6 | sed 's/"/\\"/g' | sed 's/$/&\\n\\/g' > $GIT_INFO_FILE
gen_info_template_header > $TEMPLATE_HEADER_FILE
gen_info_template_foot > $TEMPLATE_FOOT_FILE
gen_info_print_template >> $TEMPLATE_FOOT_FILE
diff --git a/depends.mk.template b/depends.mk.template
index 191cd8162..f0dbea180 100644
--- a/depends.mk.template
+++ b/depends.mk.template
@@ -14,17 +14,19 @@ GLOG_PREFIX=./thirdparty
GTEST_PREFIX=./thirdparty
GPERFTOOLS_PREFIX=./thirdparty
INS_PREFIX=./thirdparty
+MONGOOSE_PREFIX=./thirdparty
BOOST_INCDIR=./thirdparty/boost_1_57_0
SOFA_PBRPC_INCDIR = $(SOFA_PBRPC_PREFIX)/include
PROTOBUF_INCDIR = $(PROTOBUF_PREFIX)/include
SNAPPY_INCDIR = $(SNAPPY_PREFIX)/include
-ZOOKEEPER_INCDIR = $(ZOOKEEPER_PREFIX)/include
+ZOOKEEPER_INCDIR = $(ZOOKEEPER_PREFIX)/include/zookeeper
GFLAGS_INCDIR = $(GFLAGS_PREFIX)/include
GLOG_INCDIR = $(GLOG_PREFIX)/include
GTEST_INCDIR = $(GTEST_PREFIX)/include
GPERFTOOLS_INCDIR = $(GPERFTOOLS_PREFIX)/include
INS_INCDIR = $(INS_PREFIX)/include
+MONGOOSE_INCDIR = $(MONGOOSE_PREFIX)/include
SOFA_PBRPC_LIBDIR = $(SOFA_PBRPC_PREFIX)/lib
PROTOBUF_LIBDIR = $(PROTOBUF_PREFIX)/lib
@@ -35,6 +37,7 @@ GLOG_LIBDIR = $(GLOG_PREFIX)/lib
GTEST_LIBDIR = $(GTEST_PREFIX)/lib
GPERFTOOLS_LIBDIR = $(GPERFTOOLS_PREFIX)/lib
INS_LIBDIR = $(INS_PREFIX)/lib
+MONGOOSE_LIBDIR = $(MONGOOSE_PREFIX)/lib
PROTOC = $(PROTOBUF_PREFIX)/bin/protoc
@@ -45,13 +48,13 @@ PROTOC = $(PROTOBUF_PREFIX)/bin/protoc
DEPS_INCPATH = -I$(SOFA_PBRPC_INCDIR) -I$(PROTOBUF_INCDIR) \
-I$(SNAPPY_INCDIR) -I$(ZOOKEEPER_INCDIR) \
-I$(GFLAGS_INCDIR) -I$(GLOG_INCDIR) -I$(GTEST_INCDIR) \
- -I$(GPERFTOOLS_INCDIR) -I$(BOOST_INCDIR) -I$(INS_INCDIR)
+ -I$(GPERFTOOLS_INCDIR) -I$(BOOST_INCDIR) -I$(INS_INCDIR) -I$(MONGOOSE_INCDIR)
DEPS_LDPATH = -L$(SOFA_PBRPC_LIBDIR) -L$(PROTOBUF_LIBDIR) \
-L$(SNAPPY_LIBDIR) -L$(ZOOKEEPER_LIBDIR) \
-L$(GFLAGS_LIBDIR) -L$(GLOG_LIBDIR) -L$(GTEST_LIBDIR) \
- -L$(GPERFTOOLS_LIBDIR) -L$(INS_LIBDIR)
+ -L$(GPERFTOOLS_LIBDIR) -L$(INS_LIBDIR) -L$(MONGOOSE_LIBDIR)
SO_DEPS_LDFLAGS = -lins_sdk -lsofa-pbrpc -lprotobuf -lsnappy -lzookeeper_mt \
- -lgtest_main -lgtest -lglog -lgflags
+ -lgtest_main -lgtest -lglog -lgflags -lmongoose
DEPS_LDFLAGS = $(SO_DEPS_LDFLAGS) -ltcmalloc_minimal -lunwind
################################################################
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 000000000..eb4ed0d0a
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,160 @@
+
+# Tera SDK及工具说明
+
+## 目录
+### 1. [主要数据结构](#main-data-structure)
+
+* tera::[client](./sdk_reference/client.md)
+* tera::[table](./sdk_reference/table.md)
+* tera::[mutation](./sdk_reference/mutation.md)
+* tera::[reader](./sdk_reference/reader.md)
+* tera::[table_descriptor](./sdk_reference/table_descriptor.md)
+* tera::[transaction](./sdk_reference/transaction.md)
+* tera::[scan](./sdk_reference/scan.md)
+* tera::[utils](./sdk_reference/utils.md)
+
+### 2. [主要工具](#main-tools)
+* [teracli](./tools/teracli.md)
+* [terautil](./tools/terautil.md)
+* [tera_bench & tera_mark](./tools/benchmark.md)
+* [YCSB](./tools/ycsb.md)
+
+
+
+### 1. 主要数据结构
+#### (1) tera::client 访问tera服务主结构,所有对tera的访问或操作全部由此发起。
+一个集群对应一个client即可,如需访问多个client,需要创建多个
+##### 主要功能包括:
+* 表格操作:建、删、加载、卸载、打开、关闭、更新表结构、获取表格信息、快照等
+* 用户管理:建、删、修改密码、组管理等
+* 集群信息获取:获取全部表格列表、状态等
+
+#### (2) tera::table 表格主结构,对表格的所有增删查改操作由此发起。
+由tera::Client::OpenTable产生,tera::Client::CloseTable关闭,不可析构。
+
+#### (3) tera::error_code 错误码,很多操作会返回,注意检查。
+
+#### (4) tera::mutation
+
+#### (5) tera::scan 扫描操作,并获取返回数据。
+
+#### (6) tera::reader 读取操作,并获取返回数据。
+
+#### (7) tera::table_descriptor 表格描述符主体
+
+#### (8) tera::transaction 单行事务
+
+#### (9) tera::scan 扫描
+
+#### (10) tera::utils 编码解码
+
+
+### 2. 主要工具
+#### (1) teracli 操作tera的工具
+* 实际上封装了对数据的操作等,可用来进行表格创建、schema更新等管理、控制操作。
+* 查看有哪些命令可用 :./teracli help;
+* 查看某个命令的help:./teracli help [cmd],例如./teracli help tablet
+
+#### (2) terautil 集群间数据迁移的dump工具
+
+* 具体用法./terautil dump help
+* 建表主要用法:./terautil --flagfile=../conf/terautil.flag dump prepare_safe
+* 扫表run起来主要用法:./terautil --flagfile=../conf/terautil.flag dump run
+* flag配置
+
+
+| flag名称 |
+flag默认值或格式 |
+flag介绍 |
+
+
+| dump_tera_src_conf |
+../conf/src_tera.flag(格式) |
+tera的源集群 |
+
+
+| dump_tera_dest_conf |
+../conf/dest_tera.flag(格式) |
+tera的目的集群 |
+
+
+| dump_tera_src_root_path |
+/xxx_(路径格式) |
+tera的源路径 |
+
+
+| dump_tera_dest_root_path |
+/xxx_(路径格式) |
+tera的目的路径 |
+
+
+| ins_cluster_addr |
+terautil_ins(格式) |
+锁服务器的地址 |
+
+
+| ins_cluster_root_path |
+/terautil/dump/xxxx(格式) |
+锁服务器路径 |
+
+
+| dump_tera_src_meta_addr |
+“” |
+源meta表的地址 |
+
+
+| dump_tera_dest_meta_addr |
+“” |
+目的meta表的地址 |
+
+
+| dump_manual_split_interval |
+1000 |
+手动分裂时间间隔,单位为ms |
+
+
+| dump_enable_manual_split |
+false |
+是否允许手动分裂 |
+
+
+
+
+#### (3) tera_mark 读写数据
+* 支持异步读写scan
+```
+#示例:
+./tera_mark --mode=w --tablename=test --type=async --verify=false --entry_limit=1000
+```
+* 参数列表
+
+参数名 | 意义 | 有效取值 | 单位 | 默认值 | 其它说明
+--- | --- | --- | --- | --- | ---
+table | 表名 | - | - | "" |
+mode | 模式 | "w"/"r"/"s"/"m" | - | "w" | -
+type | 类型 | "sync"/"async" | - | "async" | -
+pend_size | 最大pending大小 | - | - | 100 | -
+pend_count | 最大pending数 | - | - | 100000 | -
+start_key | scan的开始key | - | - | "" | -
+end_key | scan的结束key | - | - | "" | -
+cf_list | scan的列簇 | - | - | "" | -
+print | scan的结果是否需要打印 | true/false | - | false | -
+buf_size | scan的buffer_size | >0 | - | 65536 | -
+verify | md5 verify(writer&read) | true/false | - | true | -
+max_outflow | max_outflow | - | - | -1 | -
+max_rate | max_rate | - | - | -1 | -
+scan_streaming | enable streaming scan | true/false | - | false | -
+batch_count | batch_count(sync) | - | - | 1 | -
+entry_limit | writing/reading speed limit | - | - | 0 | -
+
+#### (4) tera_bench 造数据的工具
+```
+./tera_bench --compression_ratio=1 --key_seed=1 --value_seed=20 --value_size=1000 --num=200000
+--benchmarks=random --key_size=24 --key_step=1
+```
+
+#### (5) YCSB 业界通用NoSQL测试的基准测试工具
+
+* 全称Yahoo! Cloud Serving Benchmark,Yahoo公司开发的专门用于NoSQL测试的基准测试工具
+* YCSB支持各种不同的数据分布方式,如Uniform(等概论随机选择记录)、Zipfian(随机选择记录,存在热记录)、Latest(近期写入的记录为热记录)
+
diff --git a/doc/cn/README.md b/doc/cn/README.md
index d18e4cf74..12eeb4d98 100644
--- a/doc/cn/README.md
+++ b/doc/cn/README.md
@@ -1,5 +1,5 @@
-# Tera文档专区
+# Tera文档专区
## 简介
[系统设计](../tera_design.md)
@@ -10,9 +10,15 @@
[体验单机Tera](onebox.md)
-[命令行工具teracli使用方法](teracli.md)
+[命令行工具teracli使用方法](../tools/teracli.md)
+
+[集群间数据迁移的dump工具terautil使用方法](../tools/terautil.md)
-[主要api使用方法](sdk_guide.md)
+[造数据的工具 & 读写数据使用方法](../tools/benchmark.md)
+
+[性能测试工具ycsb的使用方法](../tools/ycsb.md)
+
+[主要api使用方法](../sdk_reference/readme.md)
[搭建tera集群](cluster_setup.md)
@@ -35,3 +41,4 @@
## 版本发布
[版本发布及管理](../release_management.md)
+
diff --git a/doc/global_txn.md b/doc/global_txn.md
new file mode 100644
index 000000000..bb62d4c79
--- /dev/null
+++ b/doc/global_txn.md
@@ -0,0 +1,3 @@
+# Tera全局事务的原理及实现
+
+[image-1]: ../resources/images/global_txn.png
diff --git a/doc/sdk_reference/client.md b/doc/sdk_reference/client.md
new file mode 100644
index 000000000..a7f6fe878
--- /dev/null
+++ b/doc/sdk_reference/client.md
@@ -0,0 +1,169 @@
+
+# Client接口说明
+
+## 主要功能
+
+#### 1. 表格管理
+##### (1) 新建client Client::NewClient
+```
+1.1) static Client* NewClient(const std::string& confpath, const std::string& log_prefix, ErrorCode* err = NULL)
+1.2) static Client* NewClient(const std::string& confpath, ErrorCode* err = NULL)
+1.3) static Client* NewClient()
+```
+
+##### (2) 打开表格 Client::OpenTable
+```
+Table* OpenTable(const std::string& table_name, ErrorCode* err) = 0
+```
+##### (3) 建表 Client::CreateTable
+```
+1) bool CreateTable(const TableDescriptor& desc, ErrorCode* err) = 0 //新建带有具体描述符的表格
+2) bool CreateTable(const TableDescriptor& desc, const std::vector& tablet_delim, ErrorCode* err) = 0 //新建多个前缀为tablet_delim的tablets
+```
+
+##### (4) 更新schema Client::UpdateTableSchema
+
+```
+bool ClientImpl::UpdateTableSchema(const TableDescriptor& desc, ErrorCode* err) = 0
+```
+调用UpdateTable(desc, err),分两种情况:
+* 更新lg属性。需要先disable表格
+* 更新cf属性。直接更新
+##### (5) 检查更新状态 Client::UpdateCheck
+
+```
+bool UpdateCheck(const std::string& table_name, bool* done, ErrorCode* err) = 0
+```
+
+##### (6) disable表 Client::DisableTable
+暂停表,表格不再提供读、写服务。某些属性的更新需要先disable表;使用drop删除表时,需要先执行disable操作,此操作不可回滚。
+
+```
+bool DisableTable(const std::string& name, ErrorCode* err) = 0
+```
+
+##### (7) drop表 Client::DropTable
+删除处于disable状态的表格,此操作不可回滚。
+
+```
+bool DropTable(const std::string& name, ErrorCode* err) = 0
+```
+
+##### (8) enable表 Client::EnableTable
+
+将处于disable状态的表格重新enable,恢复读、写服务。
+
+```
+bool EnableTable(const std::string& name, ErrorCode* err) = 0
+```
+
+##### (9) 获取表的描述符 Client::GetTableDescriptor
+```
+TableDescriptor* GetTableDescriptor(const std::string& table_name, ErrorCode* err) = 0
+```
+
+##### (10) 列出所有的表 Client::List
+```
+bool List(std::vector* table_list, ErrorCode* err) = 0;//列出所有的表
+bool List(const std::string& table_name, TableInfo* table_info, std::vector* tablet_list, ErrorCode* err) = 0;//获取指定的表
+```
+##### (11) 检查表是否存在 Client::IsTableExist
+```
+bool IsTableExist(const std::string& table_name, ErrorCode* err) = 0
+```
+
+##### (12) 检查表是否为enable状态 Client::IsTableEnabled
+```
+bool IsTableEnabled(const std::string& table_name, ErrorCode* err) = 0
+```
+
+##### (13) 检查表是否为空 Client::IsTableEmpty
+```
+bool IsTableEmpty(const std::string& table_name, ErrorCode* err) = 0
+```
+
+##### (14) 发送请求给服务器 Client::CmdCtrl
+```
+bool CmdCtrl(const std::string& command, const std::vector& arg_list, bool* bool_result, std::string* str_result, ErrorCode* err) = 0
+```
+
+##### (15) 使用glog的用户防止冲突 Client::SetGlogIsInitialized
+```
+void SetGlogIsInitialized()
+```
+
+##### (16) 删除表格 Client::DeleteTable
+```
+bool DeleteTable(const std::string& name, ErrorCode* err) = 0
+```
+
+##### (17) 更新表格 Client::UpdateTable
+```
+bool UpdateTable(const TableDescriptor& desc, ErrorCode* err) = 0
+```
+
+##### (18) 获得表格的位置 Client::GetTabletLocation
+```
+bool GetTabletLocation(const std::string& table_name, std::vector* tablets, ErrorCode* err) = 0
+```
+
+##### (19) 重命名表格 Client::Rename
+```
+bool Rename(const std::string& old_table_name, const std::string& new_table_name, ErrorCode* err) = 0
+```
+#### 2. 用户管理
+
+##### (1) 创建用户 Client::CreateUser
+
+```
+bool ClientImpl::CreateUser(const std::string& user,
+ const std::string& password, ErrorCode* err) = 0
+```
+##### (2) 删除用户 Client::DeleteUser
+
+```
+bool ClientImpl::DeleteUser(const std::string& user, ErrorCode* err) = 0
+```
+
+##### (3) 修改用户密码 Client::ChangePwd
+
+```
+bool ClientImpl::ChangePwd(const std::string& user, const std::string& password, ErrorCode* err) = 0
+```
+
+##### (4) 显示指定用户信息 Client::ShowUser
+
+```
+bool ClientImpl::ShowUser(const std::string& user, std::vector& user_groups, ErrorCode* err) = 0
+```
+
+##### (5) 添加用户到用户群 Client::AddUserToGroup
+
+```
+bool ClientImpl::AddUserToGroup(const std::string& user_name, const std::string& group_name, ErrorCode* err)= 0
+```
+
+##### (6) 从用户群中删除用户 Client::DeleteUserFromGroup
+
+```
+bool ClientImpl::DeleteUserFromGroup(const std::string& user_name, const std::string& group_name, ErrorCode* err) = 0
+```
+
+
+
diff --git a/doc/sdk_reference/mutation.md b/doc/sdk_reference/mutation.md
index 54e444607..752891f9b 100644
--- a/doc/sdk_reference/mutation.md
+++ b/doc/sdk_reference/mutation.md
@@ -1,108 +1,154 @@
-# RowMutation
+# RowMutation接口说明
tera sdk中通过RowMutation结构描述一次行更新操作,包含删除操作。
-一个RowMutaion中可以同时对多列进行操作,保证:
- * 服务端生效时序与RowMutation的执行时序相同。比如对某列的删除+更新,服务端生效时不会乱序,导致先更新再删除的情况发生。
- * 同一个RowMutation中的操作保证同时成功或失败。
- * 操作不存在的列族会返回成功,但无法读取。
-
-## 创建与析构
-
-由tera::Table::NewRowMutation创建,不能由用户创建。
-
-用户需要自行析构:
- * 同步模式下Put返回后即可析构
- * 异步模式下需要等待回调返回,并处理完成后析构,建议在回调函数末尾进行析构
-## API
-
-### 更新
-
-Key-value模式更新。若设定ttl,数据会在ttl时间超时后被淘汰。
+## 1. 数据结构
+```
+ enum Type {
+ kPut,
+ kDeleteColumn,
+ kDeleteColumns,
+ kDeleteFamily,
+ kDeleteRow,
+ kAdd,
+ kPutIfAbsent,
+ kAppend,
+ kAddInt64
+ };
+ struct Mutation {
+ Type type;
+ std::string family;
+ std::string qualifier;
+ std::string value;
+ int64_t timestamp;
+ int32_t ttl;
+ };
+```
+
+## 2. 主要接口与用法
+#### 2.1 更新
+
+
+表格类型 | 接口功能 | 接口 | 参数 | 可省参数 | 返回值类型 | 其它说明
+--- | --- | --- | --- | --- | --- | ---
+表格模式 | 修改一个列 | Put | const std::string& family, const std::string& qualifier, const int64_t value, int64_t timestamp | timestamp可省,省略时为-1 | void | Counter场景下使用,设定初始值。
+表格模式 | 修改一个列的特定版本 | Put | const std::string& family, const std::string& qualifier, const std::string& value, int64_t timestamp| timestamp可省,省略时为-1 | void | 若设定timestamp,数据会被更新至指定时间,危险,不建议使用
+表格模式 | 修改一个带TTL列的特定版本 | Put | const std::string& family, const std::string& qualifier, int64_t timestamp, const std::string& value, int32_t ttl | | void |
+表格模式 | 修改一个列的特定版本 | Put | const std::string& family, const std::string& qualifier, int64_t timestamp, const std::string& value | | void |
+表格模式 | 原子操作:如果不存在才能Put成功 | PutIfAbsent | const std::string& family, const std::string& qualifier, const int64_t delta | | void |若不存在,更新生效;否则更新数据不生效。delta可为负数。
+表格模式 | 原子加一个Cell | Add | const std::string& family, const std::string& qualifier, const int64_t delta | | void | Counter场景下使用,累加。若无初始值,会从0开始累加
+表格模式 | 原子加一个Cell | Append | const std::string& family, const std::string& qualifier, const std::string& value | | void | 将value追加至此列原数据末尾;若原数据不存在,则与Put等效。
+k-v模式 |修改带TTL的默认列 | Put | const std::string& value, int32_t ttl | ttl 可省,默认为-1 | void |若设定ttl,数据会在ttl时间超时后被淘汰。
+
+#### 2.2 删除
+##### (1) 删除整行 RowMutation::DeleteRow
+删除整行的指定范围版本。
+```
+void DeleteRow(int64_t timestamp = -1) = 0;//若设定timestamp,则删除此时间之前的所有更新。 Key-value模式下timestamp不生效。
+```
+
+##### (2) 删除某列族 RowMutation::DeleteFamily
+删除一个列族的所有列的指定范围版本。
```
-void Put(const std::string& value, int32_t ttl = -1);
+void DeleteFamily(const std::string& family, int64_t timestamp = -1) = 0;//若设定timestamp,则删除此时间之前的所有更新。
```
-表格模式更新。若设定timestamp,数据会被更新至指定时间,危险,不建议使用。
+
+##### (3) 删除某列所有版本 RowMutation::DeleteColumns
+删除一个列的指定范围版本。
```
-void Put(const std::string& family, const std::string& qualifier, const std::string& value, int64_t timestamp = -1);
+void DeleteColumns(const std::string& family, const std::string& qualifier, int64_t timestamp = -1) = 0;//若设定timestamp,则删除此时间之前的所有更新。
```
-表格模式更新。Counter场景下使用,设定初始值。
+
+##### (4) 删除一个列的指定版本 RowMutation::DeleteColumn
```
-void Put(const std::string& family, const std::string& qualifier, int64_t value, int64_t timestamp = -1);
+void DeleteColumn(const std::string& family, const std::string& qualifier, int64_t timestamp) = 0;//若不存在,则不生效。
```
-表格模式更新。Counter场景下使用,累加。若无初始值,会从0开始累加。
+
+
+#### 2.3 错误码
+##### (1) 行更新错误码 RowMutation::ErrorCode
```
-void Add(const std::string& family, const std::string& qualifier, const int64_t delta);
+const ErrorCode& GetError() = 0; //成功返回KOK
```
-表格模式更新。若不存在,更新生效;否则更新数据不生效。
+##### (2) 设置错误码 RowMutation::SetError
```
-void PutIfAbsent(const std::string& family, const std::string& qualifier, const std::string& value);
+void SetError(ErrorCode::ErrorCodeType err, const std::string& reason) = 0;
```
-表格模式更新。将value追加至此列原数据末尾;若原数据不存在,则与Put等效。
+#### 2.4 异步
+若设定回调,则异步提交;否则同步提交。
+##### (1) 设置回调 RowMutation::SetCallBack
+
+设置异步回调, 操作会异步返回。
```
-void Append(const std::string& family, const std::string& qualifier, const std::string& value);
+void SetCallBack(Callback callback) = 0;
```
-### 删除
-
-删除整行。若设定timestamp,则删除此时间之前的所有更新。
-Key-value模式下timestamp不生效。
+##### (2) 获得回调函数 RowMutation::GetCallBack
```
-void DeleteRow(int64_t timestamp = -1);
+Callback GetCallBack() = 0;
```
-删除某列族。若设定timestamp,则删除此时间之前的所有更新。
+
+#### 2.5 上下文设定
+##### (1) 设置上下文 RowMutation::SetContext
+设置用户上下文,可在回调函数中获取。
```
-void DeleteFamily(const std::string& family, int64_t timestamp = -1);
+void SetContext(void* context) = 0;
```
-删除某列所有版本。若设定timestamp,则删除此时间之前的所有更新。
+
+##### (2) 获取用户上下文 RowMutation::GetContext
```
-void DeleteColumns(const std::string& family, const std::string& qualifier, int64_t timestamp = -1);
+void* GetContext() = 0;
```
-删除某列指定时间更新。若不存在,则不生效。
+#### 2.6 超时设定
+设定单个mutation的超时时间。 如没有特殊需要,不必单独设定,使用sdk的统一超时即可。
+##### (1) 设置超时时间 RowMutation::SetTimeOut
+
+设置超时时间(只影响当前操作,不影响Table::SetWriteTimeout设置的默认写超时)
```
-void DeleteColumn(const std::string& family, const std::string& qualifier, int64_t timestamp);
+void SetTimeOut(int64_t timeout_ms) = 0;
```
-
-### 异步
-
-若设定回调,则异步提交;否则同步提交。
+
+##### (2) 超时 RowMutation::TimeOut
```
-typedef void (*Callback)(RowMutation* param);
-void SetCallBack(Callback callback);
-Callback GetCallBack();
-bool IsAsync();
+int64_t TimeOut() = 0
```
-
-### 超时设定
-
-设定单个mutation的超时时间。
-如没有特殊需要,不必要单独设定,使用sdk的统一超时即可。
+ #### 2.7 其他操作
+##### (1) 获取行更新的操作数 RowMutation::MutationNum
```
-void SetTimeOut(int64_t timeout_ms);
-int64_t TimeOut() = 0;
+uint32_t MutationNum() = 0;
```
-
-### 上下文设定
-
-用于回调中获取用户自定义上下文信息。
-内存由用户自己管理。
-
+
+##### (2) 获取mutation总大小 RowMutation::Size
```
-void SetContext(void* context);
-void* GetContext();
+uint32_t Size() = 0;
```
-
-### 其它
-
+
+##### (3) 返回row_key RowMutation::RowKey
```
-uint32_t MutationNum();
-uint32_t Size();
-const RowMutation::Mutation& GetMutation(uint32_t index);
+const std::string& RowKey() = 0;
```
-
-### 预发布
-
-获取所属事务
+
+##### (4) 返回mutation RowMutation::GetMutation
```
-Transaction* GetTransaction();
+const RowMutation::Mutation& GetMutation(uint32_t index) = 0;
```
+
diff --git a/doc/sdk_reference/reader.md b/doc/sdk_reference/reader.md
index 476d945fb..876e5f8ca 100644
--- a/doc/sdk_reference/reader.md
+++ b/doc/sdk_reference/reader.md
@@ -1,103 +1,61 @@
-# RowReader
+# Reader接口说明
tera sdk中通过RowReader结构描述一次行读取操作,并获取返回数据。
-## 创建与析构
-
-由tera::Table::NewRowReader创建,不能由用户创建。
-
-用户需要自行析构:
- * 同步模式下Get返回后即可析构
- * 异步模式下需要等待回调返回,并处理完成后析构,建议在回调函数末尾进行析构
-
-## API
-
-### 描述过滤条件
-
-通过相关的API可以对列名、更新时间、版本数目等信息描述,从而对返回数据集合进行过滤。
-
-如果不进行任何描述,默认返回此行所有数据。
-
-#### AddColumnFamily
-
+## 1. 主要接口与用法
+#### 1.1 描述过滤条件
+通过相关的API可以对列名、更新时间、版本数目等信息描述,从而对返回数据集合进行过滤。如果不进行任何描述,默认返回此行所有数据。
+##### (1) 可以增加多个列族 RowReader::AddColumnFamily
```
-void AddColumnFamily(const std::string& family);
+void AddColumnFamily(const std::string& family) = 0;//如此“family”不存在于表格的schema中,则不进行过滤
```
-
-限定返回数据的列族为“family”。
-
-可以增加多个列族。
-
-如此“family”不存在于表格的schema中,则不进行过滤。
-
-#### AddColumn
-
+
+##### (2) 可以增加多个列 RowReader::AddColumn
```
-void AddColumn(const std::string& family, const std::string& qualifier);
+void AddColumn(const std::string& family, const std::string& qualifier); //除限定返回数据列族为“family”外,其列名必须为“qualifier”。
```
-
-与AddColumnFamily类似,除限定返回数据列族为“family”外,其列名必须为“qualifier”。
-
-此操作与AddColumnFamily共同生效,返回数据为二者并集。
-
-#### SetTimeRange
-
+
+##### (3) 设定最大版本数 RowReader::SetMaxVersions
```
-void SetTimeRange(int64_t ts_start, int64_t ts_end);
+void SetMaxVersions(uint32_t max_version) = 0; //从最新版本开始计数,若实际数据版本数小于此值,全部返回。在最大版本数基础上再进行时间过滤。
```
-
-设定返回数据的更新时间范围。
-
-只返回更新时间在[ts_start, ts_end]范围内的数据。
-
-其中ts_start、ts_end均为Unix时间戳,单位为微秒(us)。
-
-#### SetMaxVersions
-
+
+##### (4) 设定返回数据的更新时间范围 RowReader::SetTimeRange
```
-void SetMaxVersions(uint32_t max_version);
+void SetTimeRange(int64_t ts_start, int64_t ts_end) = 0;//只返回更新时间在[ts_start, ts_end]范围内的数据。其中ts_start、ts_end均为Unix时间戳,单位为微秒(us)。
```
-
-设定最大版本数。
-
-从最新版本开始计数,若实际数据版本数小于此值,全部返回。
-
-过滤优先级高于TimeRange,即在最大版本数基础上再进行时间过滤。
-
-### 获取数据
-
+
+#### 1.2 获取数据
在RowReader被提交至服务端并返回后,可以从此结构中获取返回的数据。
-
支持两种获取方式:
+
+- 迭代器方式。依次遍历所有列、所有版本。
+- 全量输出。返回一个特定结构的std::Map,可按列名等信息进行访问。
+
- * 迭代器方式。依次遍历所有列、所有版本。
- * 全量输出。返回一个特定结构的std::Map,可按列名等信息进行访问。
-
-#### 迭代器方式
+##### (1) 访问数据前通过Done进行确认 RowReader::Done
+```
+bool Done() = 0;;//若返回false,则数据已遍历完毕。
```
-bool Done();
-void Next();
+
+##### (2) 访问数据前通过Next进行确认 RowReader::Next
```
-
-访问数据前通过Done()进行确认。
-
-若返回false,则数据已遍历完毕。
-
+void Next() = 0;
+```
+
+##### (3) 当数据存在时,可以通过以下接口访问此单元格的各字段值
+当通过RowReader访问key-value模式的表时,除RowKey和Value外,其它字段值无效。
```
const std::string& RowKey();
std::string Value();
-std::string Family();
-std::string Qualifier();
-int64_t Timestamp();
+std::string Family() = 0;
+std::string Qualifier() = 0;
+int64_t Timestamp() = 0;
```
-
-当数据存在时,可以通过这些接口访问此单元格的各字段值。
-
-当通过RowReader访问key-value模式的表时,除RowKey和Value外,其它字段值无效。
-
-#### 全量输出
-
+
+##### (4) 全量输出
+通过多级std::map的形式进行访问。
```
typedef std::map TColumn;
typedef std::map TColumnFamily;
@@ -105,37 +63,50 @@ typedef std::map TRow;
virtual void ToMap(TRow* rowmap);
```
-通过多级std::map的形式进行访问。
-
-### 异步与上下文设定
-
+#### 1.3 错误码
+##### (1) 获取错误码 RowReader::ErrorCode
+```
+const ErrorCode& GetError() = 0; //成功返回KOK
+```
+#### 1.4 异步
若设定回调,则异步提交;否则同步提交。
+##### (1) 设置回调 RowReader::SetCallBack
```
-typedef void (*Callback)(RowMutation* param);
-void SetCallBack(Callback callback);
-Callback GetCallBack();
+void SetCallBack(Callback callback) = 0;
```
-用于回调中获取用户自定义上下文信息。
-内存由用户自己管理。
-
+##### (2) 设置回调 RowReader::GetCallBack
```
-void SetContext(void* context);
-void* GetContext();
+void (*Callback)(RowReader* param);
```
-### 超时设定
+#### 1.5 上下文设定
+用于回调中获取用户自定义上下文信息。 内存由用户自己管理。
-设定单个reader的超时时间。
-如没有特殊需要,不必要单独设定,使用sdk的统一超时即可。
+##### (1) 设置上下文 RowReader::SetContext
```
-void SetTimeOut(int64_t timeout_ms);
-int64_t TimeOut() = 0;
+void SetContext(void* context) = 0;
```
-
-### 预发布
-
-获取所属事务
+
+##### (2) 获取上下文 RowReader::GetContext
+```
+void* GetContext() = 0;
+```
+#### 1.6 超时设定
+设定单个reader的超时时间。如没有特殊需要,不必要单独设定,使用sdk的统一超时即可。
+##### (1) 设置超时时间 RowReader::SetTimeOut
+```
+void SetTimeOut(int64_t timeout_ms) = 0;
+```
+
+#### 1.7 其他
+##### (1) 获取表格 RowReader::GetTable
+```
+Table* GetTable() = 0;
+```
+
+##### (2) 获取按列过滤的map
```
-Transaction* GetTransaction();
+typedef std::map >ReadColumnList;
+const ReadColumnList& GetReadColumnList() = 0;
```
diff --git a/doc/sdk_reference/readme.md b/doc/sdk_reference/readme.md
new file mode 100644
index 000000000..c57f747cf
--- /dev/null
+++ b/doc/sdk_reference/readme.md
@@ -0,0 +1,42 @@
+# Tera SDK主要api接口说明
+
+
+### 主要数据结构
+
+* tera::[client](../sdk_reference/client.md)
+* tera::[table](../sdk_reference/table.md)
+* tera::[mutation](../sdk_reference/mutation.md)
+* tera::[reader](../sdk_reference/reader.md)
+* tera::[table_descriptor](../sdk_reference/table_descriptor.md)
+* tera::[transaction](../sdk_reference/transaction.md)
+* tera::[scan](../sdk_reference/scan.md)
+* tera::[utils](../sdk_reference/utils.md)
+
+
+### 介绍
+#### (1) tera::client 访问tera服务主结构,所有对tera的访问或操作全部由此发起。
+一个集群对应一个client即可,如需访问多个client,需要创建多个
+##### 主要功能包括:
+* 表格操作:建、删、加载、卸载、打开、关闭、更新表结构、获取表格信息、快照等
+* 用户管理:建、删、修改密码、组管理等
+* 集群信息获取:获取全部表格列表、状态等
+
+#### (2) tera::table 表格主结构,对表格的所有增删查改操作由此发起。
+由tera::Client::OpenTable产生,tera::Client::CloseTable关闭,不可析构。
+
+#### (3) tera::error_code 错误码,很多操作会返回,注意检查。
+
+#### (4) tera::mutation
+
+#### (5) tera::scan 扫描操作,并获取返回数据。
+
+#### (6) tera::reader 读取操作,并获取返回数据。
+
+#### (7) tera::table_descriptor 表格描述符主体
+
+#### (8) tera::transaction 单行事务
+
+
+#### (9) tera::scan 扫描
+
+#### (10) tera::utils 编码解码
diff --git a/doc/sdk_reference/scan.md b/doc/sdk_reference/scan.md
new file mode 100644
index 000000000..dadb915fd
--- /dev/null
+++ b/doc/sdk_reference/scan.md
@@ -0,0 +1,98 @@
+
+# scan接口说明
+tera中scan操作由ResultStream和ScanDescriptor两个数据结构进行描述。
+### 1. ResultStream
+
+##### (1) 检查迭代是否结束
+```
+bool Done(ErrorCode* err = NULL) = 0; //如果检查失败则返回error code。
+```
+
+##### (2) 移到下一个cell
+
+```
+void Next() = 0;
+```
+
+##### (3) 获取当前cell的rowkey名字
+```
+std::string RowName() const = 0;
+```
+##### (4) 获取当前cell的簇
+```
+std::string Family() const = 0;
+```
+
+##### (5) 获取当前cell的列
+```
+std::string Qualifier() const = 0;
+```
+
+##### (6) 返回时间戳
+```
+int64_t Timestamp() const = 0;
+```
+
+##### (7) 返回当前cell的值
+```
+std::string Value() const = 0;
+int64_t ValueInt64() const = 0;
+```
+
+### 2. ScanDescriptor
+
+##### (1) 设置扫描的结束key
+```
+void SetEnd(const std::string& rowkey);
+```
+
+##### (2) 设置扫描的目标cf
+
+```
+void AddColumnFamily(const std::string& cf);
+```
+
+##### (3) 设置扫描的目标列
+```
+ void AddColumn(const std::string& cf, const std::string& qualifier);
+```
+##### (4) 设置每列的maxversion
+```
+void SetMaxVersions(int32_t versions);
+```
+
+##### (5) 设置每个扫描结果的时间范围
+```
+void SetTimeRange(int64_t ts_end, int64_t ts_start);
+```
+
+##### (6) 设置批量扫描模式
+```
+void SetAsync(bool async);
+```
+
+##### (7) 检查扫描是否为批量扫描模式
+```
+bool IsAsync() const;
+```
+
+##### (8) 设置扫描的超时时间
+```
+void SetPackInterval(int64_t timeout);
+```
+
+##### (9) 设置扫描的buffersize
+```
+void SetBufferSize(int64_t buf_size);//默认为64K
+```
+
+##### (10) 设置每次扫描的cell数
+```
+void SetNumberLimit(int64_t number_limit);
+```
+
+##### (11) 获取每次扫描的cell数
+```
+int64_t GetNumberLimit();
+```
+
diff --git a/doc/sdk_reference/table.md b/doc/sdk_reference/table.md
new file mode 100644
index 000000000..58894a8ed
--- /dev/null
+++ b/doc/sdk_reference/table.md
@@ -0,0 +1,100 @@
+
+# Table接口说明
+
+## 1. 主要数据结构
+#### 1. 表格信息
+```
+struct TableInfo {
+ TableDescriptor* table_desc; //表的描述符
+ std::string status; //表格状态信息
+};
+```
+#### 2. tablet信息
+```
+struct TabletInfo {
+ std::string table_name; //表名
+ std::string path; //路径
+ std::string server_addr; //服务器地址
+ std::string start_key; //起始key
+ std::string end_key; //结束key
+ int64_t data_size; //数据大小
+ std::string status; //状态
+};
+```
+
+## 2. 主要接口
+##### (1) 获取表名 Table::GetName
+```
+const std::string GetName() = 0
+```
+
+##### (2) 行mutation操作 Table::NewRowMutation
+```
+RowMutation* NewRowMutation(const std::string& row_key) = 0
+```
+##### (3) 写数据 Table::Put
+```
+1) void Put(RowMutation* row_mutation) = 0
+2) void Put(const std::vector& row_mutations) = 0
+3) bool Put(const std::string& row_key, const std::string& family, const std::string& qualifier, const std::string& value, ErrorCode* err) = 0
+4) bool Put(const std::string& row_key, const std::string& family, const std::string& qualifier, const int64_t value, ErrorCode* err) = 0;
+5) bool PutIfAbsent(const std::string& row_key, const std::string& family, const std::string& qualifier, const std::string& value, ErrorCode* err) = 0;
+```
+
+##### (4) 检查写数据是否结束 Table::IsPutFinished
+
+```
+bool IsPutFinished() = 0
+```
+
+##### (5) 添加数据 Table::Add
+
+```
+bool Add(const std::string& row_key, const std::string& family, const std::string& qualifier, int64_t delta, ErrorCode* err) = 0;
+```
+
+##### (6) 追加数据 Table::Append
+
+```
+bool Append(const std::string& row_key, const std::string& family, const std::string& qualifier, const std::string& value, ErrorCode* err) = 0;
+```
+
+##### (7) 按行读数据 Table::NewRowReader
+
+```
+RowReader* NewRowReader(const std::string& row_key) = 0
+```
+
+##### (8) 读数据 Table::Get
+
+```
+1) void Get(RowReader* row_reader) = 0
+2) void Get(const std::vector& row_readers) = 0;
+3) bool Get(const std::string& row_key, const std::string& family, const std::string& qualifier, std::string* value, ErrorCode* err) = 0;
+4) bool Get(const std::string& row_key, const std::string& family, const std::string& qualifier, int64_t* value, ErrorCode* err) = 0;
+```
+
+##### (9) 检查get是否结束 Table::IsGetFinished
+```
+bool IsGetFinished() = 0;
+```
+
+##### (10) 扫描 Table::Scan
+```
+ResultStream* Scan(const ScanDescriptor& desc, ErrorCode* err) = 0
+```
+##### (11) 按行事务处理 Table::StartRowTransaction
+```
+Transaction* StartRowTransaction(const std::string& row_key) = 0
+```
+
+##### (12) 提交行事务 Table::CommitRowTransaction
+```
+void CommitRowTransaction(Transaction* transaction) = 0
+```
+
+##### (13) 执行mutation Table::ApplyMutation
+```c
+void ApplyMutation(RowMutation* row_mu) = 0;
+void ApplyMutation(const std::vector& row_mu_list) = 0;
+```
diff --git a/doc/sdk_reference/table_descriptor.md b/doc/sdk_reference/table_descriptor.md
index ccf79a1f1..cbc2e0670 100644
--- a/doc/sdk_reference/table_descriptor.md
+++ b/doc/sdk_reference/table_descriptor.md
@@ -1,350 +1,217 @@
-# 表格描述
-tera中的表格由TableDescriptor、LocalityGroupDescriptor、ColumnFamilyDescriptor三个数据结构进行描述,C++接口。
-
-同时也支持更简单的字符串描述,参见本文最后。
-
-## TableDescriptor
-
-表格描述符主体,LocalityGroupDescriptor、ColumnFamilyDescriptor由其管理。
-
-描述表格全局属性,如key拼装方式、分片分裂合并阈值、ACL等信息。
-
-### 创建与析构
-
-此结构由用户自己创建并析构。
+# table_descriptor接口说明
+tera中的表格由ColumnFamilyDescriptor、LocalityGroupDescriptor、TableDescriptor三个数据结构进行描述。
+### 1. ColumnFamilyDescriptor
+描述一个列族的属性。
+属性支持动态更新。更新状态为最终一致,过程中存在分片之前属性不一致情况,使用时需要注意。
+##### (1) TTL
+设定列族内cell的TTL(time-to-live),单位秒,默认无穷大。
+当列族内某cell的更新时间超过此值后,读取时被屏蔽,并在垃圾回收时物理删除。
+```
+void SetTimeToLive(int32_t ttl) = 0;
+int32_t TimeToLive() const = 0;
+```
-### 使用场景
+##### (2) 最大版本数MaxVersions
+设定列族内cell的最大版本数,默认为1。
+当某cell的版本数超过此限制后,会将最旧的版本进行屏蔽,并在垃圾回收时物理删除。
+此值不做最大值限制,但随着版本数大量增加,相应的随机读、扫描性能会下降,存储使用上升,用户可按实际情况调整。
+```
+void SetMaxVersions(int32_t max_versions) = 0;
+int32_t MaxVersions() const = 0;
+```
- * 表格创建,通过`tera::Client::CreateTable`
- * 表格Schema更新,通过`tera::Client::UpdateTable`
- * 获取表格属性,通过`tera::Client::GetTableDescriptor`
-
-### API
+##### (3) 获取LG的名字
+```
+const std::string& LocalityGroup() const = 0;
+```
+##### (4) 获取Id
+```
+int32_t Id() const = 0;
+```
-#### TableDescriptor
+### 2. LocalityGroupDescriptor
+描述一个locality group的属性。
+##### (1) 获取此LG名字
```
-TableDescriptor(const std::string& name);
+const std::string& Name() const;
```
-构造表格名为“name”的表格描述符。
+##### (2) 设定、获取存储介质,默认kInDisk
+```
+void SetStore(StoreType type) = 0;
+StoreType Store() const = 0;
+enum StoreType {
+ kInDisk = 0,
+ kInFlash = 1,
+ kInMemory = 2,
+};
+```
-其中表格名长度需要小于256字节,字符只支持{[a-z],[A-Z],[0-9],'_','-'}。
+##### (3) 设定、获取物理文件内部block大小
+```
+void SetBlockSize(int block_size) = 0;//设定、获取物理文件内部block大小,单位KB,默认值:4。
+int BlockSize() const = 0;
+```
+##### (4) 设定、获取物理文件基础大小
+```
+int32_t SstSize() const = 0;//设定、获取物理文件内部block大小,单位KB,默认值:4。
+void SetSstSize(int32_t sst_size) = 0;
+```
+##### (5) 获取/得到compress type
+```
+ void SetCompress(CompressType type) = 0;
+ CompressType Compress() const = 0;
+```
+##### (6) 设定、获取是否使用bloom filter
+设定、获取是否使用bloom filter,默认不使用。
+```
+void SetUseBloomfilter(bool use_bloomfilter) = 0;
+bool UseBloomfilter() const = 0;
+```
+##### (7) 内存内compact
+是否使用内存内compact。
+```
+bool UseMemtableOnLeveldb() const = 0;
+void SetUseMemtableOnLeveldb(bool use_mem_ldb) = 0;
+```
+##### (8) 设定、获取内存compact中写缓存大小
+设定、获取内存compact中写缓存大小,单位KB。
+```
+int32_t MemtableLdbWriteBufferSize() const = 0;
+void SetMemtableLdbWriteBufferSize(int32_t buffer_size) = 0;
+```
+##### (9) 设定、获取内存compact中对应block大小
+设定、获取内存compact中对应block大小,单位KB。
+```
+int32_t MemtableLdbBlockSize() const = 0;
+void SetMemtableLdbBlockSize(int32_t block_size) = 0;
+```
+
+### 3. TableDescriptor
+表格描述符主体,LocalityGroupDescriptor、ColumnFamilyDescriptor由其管理。
+描述表格全局属性,如key拼装方式、分片分裂合并阈值、ACL等信息。
+使用场景
+
+- 表格创建,通过tera::Client::CreateTable
+- 表格Schema更新,通过tera::Client::UpdateTable
+- 获取表格属性,通过tera::Client::GetTableDescriptor
+
-#### TableName
+#### 3.1 TableDescriptor
+##### (1) 获取表名
+设置、返回表格名。
```
void SetTableName(const std::string& name);
std::string TableName() const;
```
-设置、返回表格名。
-
-#### LocalityGroup
-
+##### (2) 新增一个名为‘lg_name’的LG
+其中,LocalityGroup名长度需要小于256字节,字符只支持{[a-z],[A-Z],[0-9],'_','-'}
```
LocalityGroupDescriptor* AddLocalityGroup(const std::string& lg_name);
```
-新增一个名为‘lg_name’的LG。
-
-其中的LocalityGroup名长度需要小于256字节,字符只支持{[a-z],[A-Z],[0-9],'_','-'}。
-
+##### (3) 删除名为‘lg_name’的LG
```
-bool RemoveLocalityGroup(const std::string& lg_name);
+bool RemoveLocalityGroup(const std::string& lg_name);//如果此LG中还有列族存在,删除失败。
```
-
-删除名为‘lg_name’的LG。
-
-如果此LG中还有列族存在,删除失败。
-
+##### (4) 通过id/名称访问对应LG
+LG在表格内部以vector形式保存,id为其对应的下标。
```
const LocalityGroupDescriptor* LocalityGroup(int32_t id) const;
const LocalityGroupDescriptor* LocalityGroup(const std::string& lg_name) const;
```
-
-通过id/名称访问对应LG。
-
-LG在表格内部以vector形式保存,id为其对应的下标。
-
+##### (5) 获取/得到compress type
```
-int32_t LocalityGroupNum() const;
+ void SetCompress(CompressType type) = 0;
+ CompressType Compress() const = 0;
```
-
-返回当前表格中LG数量。
-
-#### ColumnFamily
-
+##### (6) 返回当前表格中LG数量
```
-ColumnFamilyDescriptor* AddColumnFamily(const std::string& cf_name,const std::string& lg_name);
+int32_t LocalityGroupNum() const;
```
+
+#### 3.2 ColumnFamily
-在‘lg_name’下新增一个名为‘cf_name’的列族。
-
-若‘lg_name’不存在,返回NULL。
-
-其中列族名长度需要小于256字节,字符只支持{[a-z],[A-Z],[0-9],'_','-'}。
-
+##### (1) 在‘lg_name’下新增一个名为‘cf_name’的列族
+若‘lg_name’不存在,返回NULL。其中列族名长度需要小于256字节,字符只支持{[a-z],[A-Z],[0-9],'_','-'}。
+```
+ColumnFamilyDescriptor* AddColumnFamily(const std::string& cf_name, const std::string& lg_name = "lg0");
```
+##### (2) 删除名为‘cf_name’的列族
+```
void RemoveColumnFamily(const std::string& cf_name);
```
-
-删除名为‘cf_name’的列族。
-
+##### (3) 通过id/名称访问对应列族
+列族在表格内部以vector形式保存,id为其对应的下标。
```
const ColumnFamilyDescriptor* ColumnFamily(int32_t id) const;
const ColumnFamilyDescriptor* ColumnFamily(const std::string& cf_name) const;
```
-
-通过id/名称访问对应列族。
-
-列族在表格内部以vector形式保存,id为其对应的下标。
-
+##### (4) 返回当前表格中列族数量
```
int32_t ColumnFamilyNum() const;
```
-返回当前表格中列族数量。
+#### 3.3 RawKey
-#### RawKey
-
-```
+##### (1) 表格内部key的拼装格式
+决定了表格的存储及访问格式,推荐kBinary。
+```
+void SetRawKey(RawKeyType type);
+RawKeyType RawKey() const;
enum RawKeyType {
kReadable = 0,
- kBinary = 1,
+ kBinary = 1,
kTTLKv = 2,
kGeneralKv = 3,
-};
-void SetRawKey(RawKeyType type);
-RawKeyType RawKey() const;
-```
-
-表格内部key的拼装格式。
-
-决定了表格的存储及访问格式,推荐kBinary。
-
-#### SplitSize
-
-```
-void SetSplitSize(int64_t size);
-int64_t SplitSize() const;
+};
```
-
-分片分裂阈值。
-
+#### 3.4 SplitSize
+##### (1) 分片分裂阈值
当分片数据量(物理存储)超过此阈值时,会被一分为二,并可能被两个不同服务器加载。
-
此分裂阈值是一个基础参考值,系统会根据实际动态负载在此值基础上进行调整。
-
-#### MergeSize
-
```
-void SetMergeSize(int64_t size);
-int64_t MergeSize() const;
+void SetSplitSize(int64_t size);
+int64_t SplitSize() const;
```
-分片合并阈值。
-
+#### 3.5 MergeSize
+##### (1) 分片合并阈值
当分片数据量(物理存储)低于此阈值时,会被合并至相临分片中。
-
此值是一个基础参考值,系统会根据实际动态负载在此值基础上进行调整。
-
需要小于分裂阈值的1/3,防止出现合并、分裂的循环出现。
-#### Write Ahead Log
-
-```
-void DisableWal();
-bool IsWalDisabled() const;
+```
+void SetMergeSize(int64_t size);
+int64_t MergeSize() const;
```
-
-配置日志开关,默认打开。
-
+#### 3.6 Write Ahead Log
+##### (1) 配置日志开关,默认打开
当此表格数据没有强特久化需求时,可以选择关闭日志。
-
会大幅提升写性能、降低系统IO消耗。
-
当有服务器宕机时,内存中数据将丢失,谨慎关闭。
-#### Admin
-
-```
-void SetAdmin(const std::string& name);
-std::string Admin() const;
-void SetAdminGroup(const std::string& name);
-std::string AdminGroup() const;
-```
-
-设置表格ACL信息。
-
-## LocalityGroupDescriptor
-
-描述一个locality group的属性。
-
-### 创建与析构
-
-通过`TableDescriptor::AddLocalityGroup`进行创建。
-
-无须用户析构。
-
-### API
-
-#### Name
-
-```
-const std::string& Name() const;
-```
-
-获取此LG名字。
-
-#### Store
-
-```
-enum StoreType {
- kInDisk = 0,
- kInFlash = 1,
- kInMemory = 2,
-};
-void SetStore(StoreType type);
-StoreType Store() const;
-```
-
-设定、获取存储介质,默认kInDisk。
-
-#### BlockSize、SstSize、BloomFilter
-
-```
-void SetBlockSize(int block_size);
-int BlockSize() const;
-```
-
-设定、获取物理文件内部block大小,单位KB,默认值:4。
-
-物理存储基于leveldb开发,此概念与leveldb中的block相似。
-
-```
-void SetSstSize(int sst_size);
-int SstSize() const;
-```
-
-设定、获取物理文件基础大小,单位MB,默认值:8。
-
-物理存储基于leveldb开发,此概念与leveldb中的level1文件大小相同。
-
-```
-void SetUseBloomfilter(bool use_bloomfilter);
-bool UseBloomfilter() const;
-```
-
-设定、获取是否使用bloom filter,默认不使用。
-
-物理存储基于leveldb开发,此概念与leveldb中的bloom filter。
-
-#### 内存内compact
-
-```
-bool UseMemtableOnLeveldb() const;
-void SetUseMemtableOnLeveldb(bool use_mem_ldb);
-```
-
-是否使用内存内compact。
-
-```
-int32_t MemtableLdbWriteBufferSize() const;
-void SetMemtableLdbWriteBufferSize(int32_t buffer_size);
-```
-
-设定、获取内存compact中写缓存大小,单位KB。
-
-```
-int32_t MemtableLdbBlockSize() const;
-void SetMemtableLdbBlockSize(int32_t block_size);
+```
+void DisableWal();
+bool IsWalDisabled() const;
```
-
-设定、获取内存compact中对应block大小,单位KB。
-
-## ColumnFamilyDescriptor
-
-描述一个列族的属性。
-
-属性支持动态更新。更新状态为最终一致,过程中存在分片之前属性不一致情况,使用时需要注意。
-
-### 创建与析构
-
-通过`TableDescriptor::AddColumnFamily`进行创建。
-
-无须用户析构。
-
-### API
-
-#### TTL
+#### 3.7 事务
+##### (1) 事务处理
```
-void SetTimeToLive(int32_t ttl);
-int32_t TimeToLive() const;
+void EnableTxn();
+bool IsTxnEnabled() const;
```
-
-设定列族内cell的TTL(time-to-live),单位秒,默认无穷大。
-
-当列族内某cell的更新时间超过此值后,读取时被屏蔽,并在垃圾回收时物理删除。
-
-#### MaxVersion
+#### 3.8 Admin
+##### (1) 设置表格的admin
```
-void SetMaxVersions(int32_t max_versions);
-int32_t MaxVersions() const;
+void SetAdmin(const std::string& name);
+std::string Admin() const;
+void SetAdminGroup(const std::string& name);
+std::string AdminGroup() const;
```
-
-设定列族内cell的最大版本数,默认为1。
-
-当某cell的版本数超过此限制后,会将最旧的版本进行屏蔽,并在垃圾回收时物理删除。
-
-此值不做最大值限制,但随着版本数大量增加,相应的随机读、扫描性能会下降,存储使用上升,用户可按实际情况调整。
-
-## 字符串描述
-
-描述表格的字符串是一个支持描述节点属性的树结构,语法详见[PropTree](https://github.com/BaiduPS/tera/blob/master/doc/prop_tree.md)
-
-### 描述表格存储
-
-表格结构中包含表名、locality groups定义、column families定义,一个典型的表格定义如下(可写入文件):
-
- # tablet分裂阈值为4096M,合并阈值为512M
- # 三个lg,分别配置为flash、flash、磁盘存储
- table_hello {
- lg_index {
- update_flag
- },
- lg_props {
- level,
- weight
- },
- lg_raw {
- data
- }
- }
-
-如果无需配置LG,指定表名和所需列名即可(所有的属性可配):
-
- table_hello {cf0, cf1, cf2}
-
-### 描述key-value存储
-
-只需指定表名即可,若需要指定存储介质等属性,可选择性添加:
-
- kv_hello # 简单key-value
- kv_hello # 配置若干属性
-
-### 属性及含义
-
-span | 属性名 | 意义 | 有效取值 | 单位 | 默认值 | 其它说明
---- | --- | --- | --- | --- | --- | ---
-table | splitsize | 某个tablet增大到此阈值时分裂为2个子tablets| >=0,等于0时关闭split | MB | 512 |
-table | mergesize | 某个tablet减小到此阈值时和相邻的1个tablet合并 | >=0,等于0时关闭merge | MB | 0 | splitsize至少要为mergesize的5倍
-lg | storage | 存储类型 | "disk" / "flash" / "memory" | - | "disk" |
-lg | blocksize | LevelDB中block的大小 | >0 | KB | 4 |
-lg | use_memtable_on_leveldb | 是否启用内存compact | "true" / "false" | - | false |
-lg | sst_size | 第一层sst文件大小 | >0 | MB | 8 |
-cf | maxversions | 保存的最大版本数 | >0 | - | 1 |
-cf | ttl | 数据有效时间 | >=0,等于0时此数据永远有效 | second | 0 |
diff --git a/doc/sdk_reference/transaction.md b/doc/sdk_reference/transaction.md
new file mode 100644
index 000000000..7a9ba1ae1
--- /dev/null
+++ b/doc/sdk_reference/transaction.md
@@ -0,0 +1,60 @@
+
+# 单行事务transaction接口说明
+
+## 主要功能
+
+
+##### (1) 提交一个修改操作 Transaction::ApplyMutation
+```
+void ApplyMutation(RowMutation* row_mu) = 0
+```
+
+##### (2) 读取操作 Transaction::Get
+```
+ErrorCode Get(RowReader* row_reader) = 0
+```
+##### (3) 回调函数原型 Transaction::Callback
+```
+typedef void (*Callback)(Transaction* transaction)
+```
+
+##### (4) 设置提交回调, 提交操作会异步返回 Transaction::SetCommitCallback
+
+```
+void SetCommitCallback(Callback callback) = 0;
+```
+
+##### (5) 获取提交回调 Transaction::GetCommit
+
+```
+Callback GetCommitCallback() = 0;
+```
+
+##### (6) 设置用户上下文,可在回调函数中获取 Transaction::SetContext
+
+```
+void SetContext(void* context) = 0;
+```
+
+##### (7) 获取用户上下文 Transaction::GetContext
+
+```
+void* GetContext() = 0
+```
+
+##### (8) 获得结果错误码 Transaction::GetError
+
+```
+const ErrorCode& GetError() = 0; // 异步模式下,通过GetError()获取提交结果
+```
+
+##### (9) 同步模式下,获得提交的结果 Transaction::Commit
+```
+ErrorCode Commit() = 0 // 同步模式下,Commit()的返回值代表了提交操作的结果(成功 或者 失败及其原因)
+```
+
+##### (10) 获取事务开始时间戳 Transaction::GetStartTimestamp
+```
+int64_t GetStartTimestamp() = 0 //仅在全局事务场景下有效
+```
+
diff --git a/doc/sdk_reference/utils.md b/doc/sdk_reference/utils.md
new file mode 100644
index 000000000..0ad5ba27a
--- /dev/null
+++ b/doc/sdk_reference/utils.md
@@ -0,0 +1,14 @@
+
+# utils接口说明
+tera中utils操作主要用来编码和解码counter cell
+##### (1) 编码
+```
+static std::string EncodeCounter(int64_t counter);
+```
+
+##### (2) 解码
+
+```
+static bool DecodeCounter(const std::string& buf, int64_t* counter);
+```
+
diff --git a/doc/tools/benchmark.md b/doc/tools/benchmark.md
new file mode 100644
index 000000000..5f8ce2941
--- /dev/null
+++ b/doc/tools/benchmark.md
@@ -0,0 +1,38 @@
+
+## 1. tera_bench
+造数据的工具
+### (1) 用法
+```
+./tera_bench --compression_ratio=1 --key_seed=1 --value_seed=20 --value_size=1000 --num=200000 --benchmarks=random --key_size=24 --key_step=1
+```
+
+## 2. tera_mark
+读写数据,支持异步读写scan
+
+### (1) 用法
+```
+#示例:
+./tera_mark --mode=w --tablename=test --type=async --verify=false --entry_limit=1000
+```
+
+### (2) 参数列表
+
+参数名 | 意义 | 有效取值 | 单位 | 默认值 | 其它说明
+--- | --- | --- | --- | --- | ---
+table | 表名 | - | - | "" |
+mode | 模式 | "w"/"r"/"s"/"m" | - | "w" | -
+type | 类型 | "sync"/"async" | - | "async" | -
+pend_size | 最大pending大小 | - | - | 100 | -
+pend_count | 最大pending数 | - | - | 100000 | -
+start_key | scan的开始key | - | - | "" | -
+end_key | scan的结束key | - | - | "" | -
+cf_list | scan的列簇 | - | - | "" | -
+print | scan的结果是否需要打印 | true/false | - | false | -
+buf_size | scan的buffer_size | >0 | - | 65536 | -
+verify | md5 verify(writer&read) | true/false | - | true | -
+max_outflow | max_outflow | - | - | -1 | -
+max_rate | max_rate | - | - | -1 | -
+scan_streaming | enable streaming scan | true/false | - | false | -
+batch_count | batch_count(sync) | - | - | 1 | -
+entry_limit | writing/reading speed limit | - | - | 0 | -
+
diff --git a/doc/tools/readme.md b/doc/tools/readme.md
new file mode 100644
index 000000000..401fad9e9
--- /dev/null
+++ b/doc/tools/readme.md
@@ -0,0 +1,10 @@
+
+# Tera 主要工具说明
+
+## 主要工具
+* 操作tera的工具: [teracli](../tools/teracli.md)
+* 集群间数据迁移的dump工具: [terautil](../tools/terautil.md)
+* 造数据 & 读写数据的工具: [tera_bench & tera_mark](../tools/benchmark.md)
+* 业界通用NoSQL测试的基准测试工具: [YCSB](../tools/ycsb.md)
+
+
diff --git a/doc/tools/teracli.md b/doc/tools/teracli.md
new file mode 100644
index 000000000..1ca78c460
--- /dev/null
+++ b/doc/tools/teracli.md
@@ -0,0 +1,448 @@
+
+# teracli使用说明
+./teracli help即可看到相关的命令和使用方法
+
+### 1. create 创建表格
+#### 1.1 基本命令
+
+```c
+./teracli create []
+./teracli createbyfile []
+```
+说明:
+* table-schema是一个描述表格结构的字符串。
+* 表名规范:首字符为字母(大小写均可),
+* 有效字符包括大小写的英文字母(a-zA-Z)、数字(0-9)、下划线(_)、连字符(-)、点(.)。 1 <= 有效长度 <=
+* 512
+* Tera支持在建立表格时预分配若干tablet,tablet分隔的key写在tablet-delimiter-file中,按“\n”分隔。
+* 如果表格schema比较复杂,可以将其写入文件中,通过createbyfile命令进行创建。
+
+#### 1.2 创建table模式存储
+表格结构中包含表名、locality groups定义、column families定义,一个典型的表格定义如下(可写入文件)
+```c
+# tablet分裂阈值为4096M,合并阈值为512M
+# 三个lg,分别配置为flash、flash、磁盘存储
+table_hello {
+ lg_index {
+ update_flag
+ },
+ lg_props {
+ level,
+ weight
+ },
+ lg_raw {
+ data
+ }
+}
+```
+如果只希望简单的使用tera,对性能没有很高要求,那么schema只需指定表名和所需列名即可(如需要,所有的属性也是可配的):
+```c
+table_hello {cf0, cf1, cf2}
+```
+
+#### 1.3 创建key-value表
+tera支持高性能的key-value存储,其schema只需指定表名即可,若需要指定存储介质等属性,可选择性添加:
+```c
+ # 表名为key-value,默认storage为disk, splitsize为512M, mergesize为0
+./teracli create kv_hello
+ # 配置若干属性
+./teracli create "kv_hello "
+```
+#### 1.4 表格各级属性
+
+span | 属性名 | 意义 | 有效取值 | 单位 | 默认值 | 其它说明
+--- | --- | --- | --- | --- | --- | ---
+table | splitsize | 某个tablet增大到此阈值时分裂为2个子tablets| >=0,等于0时关闭split | MB | 512 |
+table | mergesize | 某个tablet减小到此阈值时和相邻的1个tablet合并 | >=0,等于0时关闭merge | MB | 0 |
+splitsize至少要为mergesize的3倍,建议为mergesize的10倍,避免merge后又分裂
+lg | storage | 存储类型 | "disk" / "flash" / "memory" | - | "disk" |
+lg | blocksize | LevelDB中block的大小 | >0 | KB | 4 |
+lg | use_memtable_on_leveldb | 是否启用内存compact | "true" / "false" | - | false |
+lg | sst_size | 第一层sst文件大小 | >0 | MB | 8 |
+cf | maxversions | 保存的最大版本数 | >0 | - | 1 |
+cf | ttl | 数据有效时间 | >=0,等于0时此数据永远有效 | second | 0 |
+和minversions冲突时以minversions为准
+
+
+### 2 update 更新表格schema
+更新时使用schema语法和建表时的语法基本一致,
+不同主要在于更新时只需指定要更新的属性,不需要改动的属性无需列出。
+#### 2.1 基本语法
+```c
+./teracli update
+```
+#### 2.2 分类
+主要分为两大类更新:
+* 更新table模式schema
+* 更新kv模式schema
+
+#### 2.3 更新table模式schema
+
+支持表格、cf属性热更新
+##### 2.3.1 更新table的属性(不更新lg、cf属性)
+```c
+./teracli update "table_hello" //更新mergesize
+./teracli update "table_hello" //更新mergesize和splitsize
+```
+##### 2.3.2 更新lg属性时,***需要disable表格***
+```c
+./teracli disable table_hello
+./teracli update "table_hello{lg0}"
+./teracli update "table_hello{lg0}" //也可以同时修改table属性
+```
+##### 2.3.3 更新cf属性
+```c
+./teracli update "table_hello{lg0{cf0}}"
+#也可以同时修改table或者lg属性
+./teracli update "table_hello{lg0{cf0}}"
+```
+##### 2.3.4 增加、删除cf
+
+```c
+# 在lg0下增加cf1,并设置属性ttl值为123.
+# op意为操作,op=add需要放在cf属性的最前面
+./teracli update "table_hello{lg0{cf1}}"
+
+# 从lg0中删除cf1
+./teracli update "table_hello{lg0{cf1}}"
+```
+
+#### 2.4 更新kv模式schema
+```c
+# 更新部分属性时需要disable表格,程序会在运行时给出提示
+./teracli update "kv_hello"
+```
+
+### 3. update-check
+
+### 4. enable
+将处于disable状态的表格重新enable,恢复读、写服务。
+```c
+./teracli enable
+```
+
+### 5. disable
+将处于表格置于disable状态,不再提供读、写服务。
+```c
+./teracli enable
+```
+
+### 6. drop
+删除处于disable状态的表格,此操作不可回滚。
+```c
+./teracli drop
+```
+### 7. rename 重命名表格
+```c
+#语法:
+./teracli rename
+```
+示例:
+```c
+./teracli rename tb1 tb2
+```
+
+### 8. put 向表中写入一个value
+向表中写入以rowkey为key,列为columnfamily:qualifier的值value.对于kv模式的表来说,无需columnfamily:qualifier.
+```c
+#语法:
+./teracli put []
+```
+示例:
+```c
+./teracli put mytable rowkey cf0:qu0 value
+```
+
+### 9. put-ttl 新增的ttl字段表示这个value的有效时间
+```c
+#语法:
+./teracli put-ttl []
+```
+示例:
+```c
+#这个value在20秒内有效,超时就读不到了。
+./teracli put-ttl mytable rowkey cf0:qu0 value 20
+```
+
+### 10. putif 原子操作,如果不存在才能put成功
+
+```c
+#语法:
+./teracli putif []
+```
+
+### 11. get 读取一个value
+```c
+#语法:
+./teracli get []
+```
+示例:
+```c
+#这个value在20秒内有效,超时就读不到了。
+./teracli get mytable rowkey cf0:qu0
+```
+
+### 12. scan 扫描一个表
+将表中key从[startkey, endkey)范围的所有数据扫描出来。
+每个value可以有多个版本(versions),scan命令默认只输出每个value的最新版本,
+想要获取全部版本可以使用scanallv命令。
+```c
+#语法:
+./teracli scan[allv]
+```
+示例:
+```c
+#扫描整个表
+./teracli scan mytable "" ""
+```
+
+
+### 13. delete 删除一个value
+如果只想删除某列最新的一个版本可以用delete1v命令。
+```c
+#语法:
+./teracli delete[1v] []
+```
+
+### 14. put_counter 写入一个counter(计数器)
+```c
+#语法:
+./teracli put_counter []
+```
+示例:
+```c
+#写入一个初始值为3的计数器:
+./teracli put_counter mytable rowkey cf0:qu0 3
+```
+### 15. get_counter 读取一个counter
+```
+#语法:
+./teracli get_counter []
+```
+示例:
+```c
+#读取之前写入的那个counter:
+./teracli get_counter mytable rowkey cf0:qu0
+```
+
+### 16. add 给某个counter加上一个delta值
+```
+#语法:
+./teracli add delta
+```
+示例:
+```c
+#读取之前写入的那个counter:
+./teracli get_counter mytable rowkey cf0:qu0
+```
+
+### 17. putint64 写入一个int64类型counter(计数器)
+
+```
+#语法:
+./teracli putint64 []
+```
+示例:
+```c
+#写入一个初始值为67的计数器:
+./teracli putint64 mytable row1 cf0:qu0 67
+```
+
+### 18. getint64 读取一个int64类型的counter
+
+```
+#语法:
+./teracli getint64 []
+```
+示例:
+```c
+./teracli getint64 mytable row1 cf0:qu0
+```
+
+### 19. addint64 对int64类型的counter执行原子加操作
+```
+#语法:
+./teracli addint64 delta
+```
+示例:
+```c
+#对之前写入的counter执行-3的操作:
+# addint64操作执行完以后,该counter的值为 64
+./teracli addint64 mytable row1 cf0:qu0 -3
+```
+### 20. append 原子操作:追加内容到一个Cell
+```
+#语法:
+./teracli append []
+```
+示例:
+```c
+./teracli put mytalbe rowkey cf0:qu0 hello
+./teracli append mytable rowkey cf0:qu0 world
+#此时再去get会得到helloworld
+./teracli get mytable rowkey cf0:qu0
+```
+### 20. batchput 批量写数据
+```
+#语法:
+./teracli batchput
+```
+### 21. batchget 批量读数据
+```
+#语法:
+./teracli batchget
+```
+### 22. show 显示表格信息
+```
+#语法:
+./teracli show[x] []
+```
+示例:
+```c
+#查看某个table的信息:
+./teracli show mytable
+#查看集群内所有table的信息:
+./teracli show
+```
+
+### 23. showx 显示表格详细信息
+```
+#语法:
+./teracli show[x] []
+```
+示例:
+```c
+#查看某个table的信息:
+./teracli showx mytable
+```
+
+### 24. showschema 显示表格schema
+表格schema里含有很多属性(例如某个cf保留的最小版本数),创建表格时,没有显示指定的属性都取默认值,
+这些属性在showschema时不会显示出来;想要显示全部属性,可以使用showschemax命令。
+```
+#语法:
+./teracli showschema[x]
+```
+
+
+### 25. showts 显示tabletnode的信息
+带上后缀'x'得到的信息会更详细(showtsx)。
+```
+#语法:
+./teracli showts []
+```
+示例:
+```c
+#显示某个tabletnode的信息:
+./teracli showts "example.company.com:7770"
+#显示集群内所有tabletnode的信息:
+./teracli showts
+```
+
+### 26. range 显示表的范围
+```
+#语法:
+./teracli range
+```
+### 27. txn 事务(仅支持单事务行操作)
+```
+#语法:
+./teracli txn
+operation包括start和commit
+./teracli txn start
+./teracli txn commit
+```
+
+### 28. user用户管理
+```
+#语法:
+./teracli user
+operation包括create、changepwd、show、delete、addtogroup和deletefromgroup
+user
+ create
+ changepwd
+ show
+ delete
+ addtogroup
+ deletefromgroup
+```
+### 29. tablet
+```
+#语法:
+./teracli tablet
+operation包括move、reload、compact、split、merge和scan
+tablet
+ move
+ reload
+ force to unload and load on the same ts
+ compact
+ split
+ merge
+ scan
+```
+
+### 30. compact
+```
+#语法:
+./teracli compact
+```
+
+### 31. safemode
+```
+#语法:
+./teracli safemode [get|enter|leave]
+```
+
+### 32. meta
+meta for master memory, meta2 for meta table.
+```
+#语法:
+./teracli meta[2] [backup|check|repair|show]
+```
+### 33. findmaster master的位置
+```
+#语法:
+./teracli findmaster
+```
+### 34. reload
+```
+#语法:
+./teracli reload config hostname:port
+```
+
+### 35. kick
+```
+#语法:
+./teracli kick
+```
+
+### 36. findtablet
+```
+#语法:
+./teracli findtablet
+./teracli findtablet
+```
+
+### 37. cookie
+```
+#语法:
+./teracli cookie
+cookie
+ dump cookie-file -- dump contents of specified files
+ findkey cookie-file key -- find the info of a key
+```
+
+### 38. version版本
+```
+#语法:
+./teracli version
+```
+
diff --git a/doc/tools/terautil.md b/doc/tools/terautil.md
new file mode 100644
index 000000000..842b572eb
--- /dev/null
+++ b/doc/tools/terautil.md
@@ -0,0 +1,78 @@
+
+
+# terautil
+
+集群间数据迁移的dump工具
+### 1. 用法
+```
+./terautil dump help
+```
+#### (1)建表
+```
+./terautil --flagfile=../conf/terautil.flag dump prepare_safe
+```
+#### (2) 将扫表操作run起来
+```
+./terautil --flagfile=../conf/terautil.flag dump run
+```
+
+### 2. flag配置
+
+
+| flag名称 |
+flag默认值或格式 |
+flag介绍 |
+
+
+| dump_tera_src_conf |
+../conf/src_tera.flag(格式) |
+tera的源集群 |
+
+
+| dump_tera_dest_conf |
+../conf/dest_tera.flag(格式) |
+tera的目的集群 |
+
+
+| dump_tera_src_root_path |
+/xxx_(路径格式) |
+tera的源路径 |
+
+
+| dump_tera_dest_root_path |
+/xxx_(路径格式) |
+tera的目的路径 |
+
+
+| ins_cluster_addr |
+terautil_ins(格式) |
+锁服务器的地址 |
+
+
+| ins_cluster_root_path |
+/terautil/dump/xxxx(格式) |
+锁服务器路径 |
+
+
+| dump_tera_src_meta_addr |
+“” |
+源meta表的地址 |
+
+
+| dump_tera_dest_meta_addr |
+“” |
+目的meta表的地址 |
+
+
+| dump_manual_split_interval |
+1000 |
+手动分裂时间间隔,单位为ms |
+
+
+| dump_enable_manual_split |
+false |
+是否允许手动分裂 |
+
+
+
+
diff --git a/doc/tools/ycsb.md b/doc/tools/ycsb.md
new file mode 100644
index 000000000..b6f922bc7
--- /dev/null
+++ b/doc/tools/ycsb.md
@@ -0,0 +1,294 @@
+
+# YCSB工具使用说明
+
+### 1. 属性
+
+#### 1.1 核心YCSB属性
+所有工作量文件可以指定以下属性:
+
+
+| 参数名 |
+意义 |
+默认值 |
+
+
+
+| workload |
+要使用的工作量类,如com.yahoo.ycsb.workloads.CoreWorkload |
+ |
+
+
+
+| db |
+要使用的数据库类。可选地,这在命令行可以指定 |
+com.yahoo.ycsb.BasicDB |
+
+
+
+| exporter |
+要是用的测量结果的输出类 |
+com.yahoo.ycsb.measurements.exporter.TextMeasurementsExporter |
+
+
+
+| exportfile |
+用于替代stdout的输出文件路径 |
+未定义/输出到stdout |
+
+
+
+| threadcount |
+YCSB客户端的线程数。可选地,这可以在命令行指定 |
+1 |
+
+
+
+| measurementtype |
+支持的测量结果类型有直方图和时间序列 |
+直方图 |
+
+
+
+
+
+
+
+
+#### 1.2 核心工作量包属性
+和核心工作量构造器一起使用的属性文件可以指定以下属性及值
+#####1.2.1 重要参数
+
+
+| 参数名 |
+意义 |
+默认值 |
+有效取值 |
+
+
+
+| recordcount |
+数据行数,装载进数据库的初始记录数 |
+0 |
+ |
+
+
+
+| operationcount |
+要进行的操作数数量 |
+无 |
+ |
+
+
+
+| fieldcount |
+每行的qualifier个数 |
+10 |
+ |
+
+
+
+| fieldlength |
+
+ | 100 |
+ |
+
+
+
+| requestdistribution |
+随机读的数据分布 |
+uniform |
+uniform、zipfian、latest |
+
+
+
+| insertorder |
+写入顺序,ordered是顺序写,hashed是随机写 |
+hashed |
+ordered、hashed |
+
+
+
+| readallfields |
+读取所有qualifier还是只读一个qualifier |
+true |
+true、false |
+
+
+
+| readproportion |
+随机读占所有操作的比例 |
+0.95 |
+ |
+
+
+
+| readproportion |
+更新(写入)占所有操作的比例 |
+0.05 |
+ |
+
+
+
+| target |
+每秒总共操作的次数 |
+unthrottled |
+ |
+
+
+
+| thread |
+客户端线程数 |
+1 |
+ |
+
+
+
+
+##### 1.2.2 非必需参数(对tera测试意义不大,用默认值即可)
+
+
+| 参数名 |
+意义 |
+默认值 |
+有效取值 |
+
+
+
+
+| insertproportion |
+插入(写入)占所有操作的比例 |
+0 |
+ |
+
+
+
+| scanproportion |
+scan占所有操作的比例,tera_mark不支持 |
+0 |
+ |
+
+
+
+| readmodifywriteproportion |
+readmodifywrite占所有操作的比例,tera不支持该操作 |
+0 |
+ |
+
+
+
+| maxscanlength |
+每次scan需要读取的行数,tera不支持指定行数的scan |
+1000 |
+ |
+
+
+
+| scanlengthdistribution |
+scan的行数选择策略 |
+uniform |
+ |
+
+
+
+| maxexecutiontime |
+最大执行时间,超过此时间会强行结束测试(单位为秒) |
+ |
+ |
+
+
+
+| table |
+表名,tera_mark不支持 |
+usertable |
+ |
+
+
+
+#### 1.3 测量结果属性
+每一个测量结果类型可以为如下属性形式:
+
+
+| 类型 |
+参数名 |
+意义 |
+默认值 |
+有效取值 |
+
+
+
+| 直方图 |
+histogram.buckets |
+直方图输出的区间数 |
+1000 |
+ |
+
+
+
+| 时间序列 |
+timeseries.granularity |
+时间序列输出的粒度 |
+1000 |
+ |
+
+
+
+
+### 2 运行时参数
+即使工作负载类和参数文件定义了一个特定的工作负载,在运行基准测试时你还是想指定一些额外的设置。当你运行YCSB客户端时命令行提供了这些设置。这些设置包括:
+* -threads :客户端的线程。默认地,YCSB客户端使用一个工作者线程,但是额外的线程可以被指定。当需要增加对数据库的装载数量时这是经常使用的。
+* -target:每秒的目标操作数。默认地,YCSB客户端将试图尽可能地执行最多操作。例如,如果每个操作平均使用了100ms,客户端每个工作者线程每秒将执行10个操作。然而,你可以限制每秒的目标操作数。比如,为了生成一条延迟-吞吐量曲线,你可以指定不同的目标吞吐量,以测试每种吞吐量下的延迟。
+* -s:状态。对于一个运行时间长的工作负载,让客户端报告状态是有用的,这可以让你知道它并没有挂掉,并且给你某些对它的执行过程的想法。通过在命令行指定“-s”,客户端将每10秒输出状态到stderr。
+
+
+
+
+### 3 用法
+
+#### 3.1 相关命令
+* load: 执行加载命令
+* run: 执行工作负载
+* shell: 交互式模式
+```
+#basic参数告诉客户端使用哑BasicDB层。你也可以在你的参数文件中使用“db”属性指定它(例如,“db=com.yahoo.ycsb.BasicDB”)
+./bin/ycsb shell basic
+> help
+Commands:
+read key [field1 field2 ...] // Read a record
+scan key recordcount [field1 field2 ...] // Scan starting at key
+insert key name1=value1 [name2=value2 ...] // Insert a new record
+update key name1=value1 [name2=value2 ...] // Update a record
+delete key // Delete a record
+table [tablename] // Get or [set] the name of the table
+quit // Quit
+```
+
+#### 3.2 使用方法
+使用时,先建表,再加载数据,最后执行相关事务。
+
+##### 3.2.1 建表
+ycsb的生成的row都是“user”+19位数字的格式,如 user9105318085603802964。 因此,如果需要预分表,必须以“user”+N个数字作为分隔,建议选择2个数字。 例如要预分4个tablet,分隔字符串为:user25、user50、user75
+```
+create 'usertable','f1','f2','f3'
+```
+
+##### 3.2.2 向tera中加载测试数据
+```
+bin/ycsb load tera -p workload=com.yahoo.ycsb.workloads.CoreWorkload \ //load参数告诉客户端执行工作负载的装载阶段。
+ -p recordcount=$(ROW_NUM) \ //-p参数被用于设置参数,-P参数用于装载属性文件。
+ -p fieldlength=$(QUALIFIER_NUM) \
+ -p fieldcount=$(VALUE_SIZE)
+```
+
+##### 3.2.3 执行测试
+```
+bin/ycsb run tera -p workload=com.yahoo.ycsb.workloads.CoreWorkload \
+ -p recordcount=$(ROW_NUM) \
+ -p operationcount=$(ROW_NUM) \
+ -p requestdistribution=$(DIST) \
+ -p fieldlength=$(QUALIFIER_NUM) \
+ -p fieldcount=$(VALUE_SIZE) \
+ -p updateproportion=$(WRITE_PROP) \
+ -p readproportion=$(READ_PROP)
+```
+
+
diff --git a/example/onebox/conf/tera.flag b/example/onebox/conf/tera.flag
index 99f62b45e..37329893d 100644
--- a/example/onebox/conf/tera.flag
+++ b/example/onebox/conf/tera.flag
@@ -7,10 +7,10 @@
--tera_leveldb_env_type=local
## 是否使用zk
-# 指定使用非zk模式, 但只能本机访问tera
---tera_zk_enabled=false
+# 指定使用fake_zk模式, 只能本机访问tera
+--tera_coord_type=fake_zk
# 指定使用zk, 可以跨服务使用, 配置相应地址和路径即可
-#--tera_zk_enabled=true
+--tera_zk_enabled=false
#--tera_zk_addr_list=localhost:2181
#--tera_zk_root_path=/tera
--tera_master_query_tabletnode_period=1000
@@ -18,3 +18,18 @@
# sdk
--tera_sdk_timeout=20000
+
+# balancer
+#--tera_info_log_clean_enable=false
+#--logbugsecs=0
+#--v=5
+#--tera_master_load_balance_ts_load_threshold=1000000000
+#--tera_master_load_balance_ts_size_threshold=10000000000000
+#--tera_master_meta_isolate_enabled=true
+#--tera_lb_load_balance_period_s=60
+#--tera_lb_tablet_max_move_num=10
+#--tera_lb_min_cost_need_balance=0.05
+#--tera_lb_move_cost_weight=10
+#--tera_lb_size_cost_weight=90
+#--tera_lb_debug_mode_enabled=false
+--online_schema_update_enabled=true
diff --git a/include/tera/client.h b/include/tera/client.h
index 2ef68638e..80308a911 100644
--- a/include/tera/client.h
+++ b/include/tera/client.h
@@ -12,6 +12,7 @@
#include "error_code.h"
#include "table.h"
#include "table_descriptor.h"
+#include "transaction.h"
#pragma GCC visibility push(default)
namespace tera {
@@ -101,6 +102,10 @@ class Client {
// Rename a table.
virtual bool Rename(const std::string& old_table_name, const std::string& new_table_name,
ErrorCode* err) = 0 ;
+
+ /// New a global transaction
+ virtual Transaction* NewGlobalTransaction() = 0;
+
Client() {}
virtual ~Client() {}
diff --git a/include/tera/error_code.h b/include/tera/error_code.h
index a03df0905..ad6ab2b64 100644
--- a/include/tera/error_code.h
+++ b/include/tera/error_code.h
@@ -26,7 +26,22 @@ class ErrorCode {
kNoAuth = 7,
kUnknown = 8,
kNotImpl = 9,
- kTxnFail = 10
+ kTxnFail = 10,
+
+ // only for global transaction error
+ kGTxnDataTooLarge = 101,
+ kGTxnNotSupport = 102,
+ kGTxnSchemaError = 103,
+ kGTxnOpAfterCommit = 104,
+ kGTxnPrimaryLost = 105,
+ kGTxnWriteConflict = 106,
+ kGTxnLockConflict = 107,
+ kGTxnOKButAckFailed = 108,
+ kGTxnOKButNotifyFailed = 109,
+ kGTxnPrewriteTimeout = 110,
+ kGTxnPrimaryCommitTimeout = 111,
+ kGTxnTimestampLost = 112
+ // end of global transaction error
};
public:
diff --git a/include/tera/reader.h b/include/tera/reader.h
index cc916c14d..08615f4d8 100644
--- a/include/tera/reader.h
+++ b/include/tera/reader.h
@@ -31,6 +31,12 @@ class RowReader {
virtual void AddColumn(const std::string& family, const std::string& qualifier) = 0;
// Set the maximum number of versions of each column.
virtual void SetMaxVersions(uint32_t max_version) = 0;
+
+ // Set the the max qualifiers of each column family when read this row
+ // This is useful when a column family contains too many qualifiers
+ // If this value is not set, the default value is std::numeric_limits::max()
+ virtual void SetMaxQualifiers(uint64_t max_qualifiers) = 0;
+
// If set, only returns cells of which update timestamp is within [ts_start, ts_end].
virtual void SetTimeRange(int64_t ts_start, int64_t ts_end) = 0;
diff --git a/include/tera/scan.h b/include/tera/scan.h
index 45646ec9d..c9023f9b6 100644
--- a/include/tera/scan.h
+++ b/include/tera/scan.h
@@ -79,6 +79,11 @@ class ScanDescriptor {
// Set max version number per column.
void SetMaxVersions(int32_t versions);
+ // Set the the max qualifiers of each column family when read this row
+ // This is useful when a column family contains too many qualifiers
+ // If this value is not set, the default value is std::numeric_limits::max()
+ void SetMaxQualifiers(uint64_t max_qualifiers);
+
// Set time range for the scan result,
// which likes the SQL statement (SELECT * from Table WHERE timestamp in [ts_start, ts_end]).
// Return the newest value first.
diff --git a/include/tera/table_descriptor.h b/include/tera/table_descriptor.h
index 8865d5a9d..4b464070f 100644
--- a/include/tera/table_descriptor.h
+++ b/include/tera/table_descriptor.h
@@ -54,6 +54,12 @@ class ColumnFamilyDescriptor {
virtual int64_t DiskQuota() const = 0;
virtual void SetAcl(ACL acl) = 0;
virtual ACL Acl() const = 0;
+ virtual void EnableGlobalTransaction() = 0;
+ virtual void DisableGlobalTransaction() = 0;
+ virtual bool GlobalTransaction() const = 0;
+ virtual void EnableNotify() = 0;
+ virtual void DisableNotify() = 0;
+ virtual bool IsNotifyEnabled() const = 0;
ColumnFamilyDescriptor() {}
virtual ~ColumnFamilyDescriptor() {}
diff --git a/include/tera/transaction.h b/include/tera/transaction.h
index dc63a7842..81722f35b 100644
--- a/include/tera/transaction.h
+++ b/include/tera/transaction.h
@@ -15,9 +15,15 @@
#pragma GCC visibility push(default)
namespace tera {
-
class RowReader;
class RowMutation;
+class Table;
+
+/// 事务隔离级别
+enum class IsolationLevel {
+ kReadCommitedSnapshot = 0,
+ kSnapshot = 1
+};
/// 事务操作接口
class Transaction {
@@ -47,9 +53,36 @@ class Transaction {
/// 异步模式下,通过GetError()获取提交结果
virtual ErrorCode Commit() = 0;
- /// 获取事务开始时间戳,仅在多行事务场景下有效
+ /// 获取事务开始时间戳
virtual int64_t GetStartTimestamp() = 0;
+ /// 获取事务提交时间戳
+ virtual int64_t GetCommitTimestamp() = 0;
+
+ /// 仅全局事务支持
+ virtual void Ack(Table* t,
+ const std::string& row_key,
+ const std::string& column_family,
+ const std::string& qualifier) = 0;
+
+ /// 仅全局事务支持
+ virtual void Notify(Table* t,
+ const std::string& row_key,
+ const std::string& column_family,
+ const std::string& qualifier) = 0;
+
+ /// 设置隔离级别
+ virtual void SetIsolation(const IsolationLevel& isolation_level) = 0;
+
+ /// 获取隔离级别
+ virtual IsolationLevel Isolation() = 0;
+
+ // Set timeout(ms).
+ virtual void SetTimeout(int64_t timeout_ms) = 0;
+
+ // Get timeout(ms).
+ virtual int64_t Timeout() = 0;
+
Transaction() {}
virtual ~Transaction() {}
@@ -58,10 +91,6 @@ class Transaction {
void operator=(const Transaction&);
};
-/// cross-row, cross-table transaction
-/// 跨行,跨表事务
-Transaction* NewTransaction();
-
} // namespace tera
#pragma GCC visibility pop
diff --git a/readme-cn.md b/readme-cn.md
index 7e136a26c..7edc5362f 100644
--- a/readme-cn.md
+++ b/readme-cn.md
@@ -1,63 +1,48 @@
[高性能、可伸缩的结构化数据库](http://github.com/baidu/tera)
====
Tera是一个高性能、可伸缩的结构化数据存储系统,被设计用来管理搜索引擎万亿量级的超链与网页信息。为实现数据的实时分析与高效访问,我们使用按行键、列名和时间戳全局排序的三维数据模型组织数据,使用多级Cache系统,充分利用新一代服务器硬件大内存、SSD盘和万兆网卡的性能优势,做到模型灵活的同时,实现了高吞吐与水平扩展。([English](README.md))
-
# 特性
- * 全局有序
- * 热点自动分片
- * 数据强一致
- * 多版本,自动垃圾收集
- * 按列存储,支持内存表
- * 动态schema
- * 支持表格快照
- * 高效随机读写
-
+* 全局有序
+* 热点自动分片
+* 数据强一致
+* 多版本,自动垃圾收集
+* 按列存储,支持内存表
+* 动态schema
+* 支持表格快照
+* 高效随机读写
# 数据模型
Tera使用了Bigtable的数据模型,可以将一张表格理解为这样一种数据结构:
```
map > >
```
其中RowKey、ColumnFamily、Qualifier和Value是字符串,Timestamp是一个64位整形。ColumnFamliy需要建表时指定,是访问控制、版本保留等策略的基本单位。
-
# 系统架构
系统主要由Tabletserver、Master和ClientSDK三部分构成。其中Tabletserver是核心服务器,承载着所有的数据管理与访问;Master是系统的仲裁者,负责表格的创建、schema更新与负载均衡;ClientSDK包含供管理员使用的命令行工具teracli和给用户使用的SDK。
表格被按RowKey全局排序,并横向切分成多个Tablet,每个Tablet负责服务RowKey的一个区间,表格又被纵向切分为多个LocalityGroup,一个Tablet的多个Localitygroup在物理上单独存储,可以选择不同的存储介质,以优化访问效率。
-

-
# 系统依赖
- * 使用分布式文件系统([BFS](https://github.com/baidu/bfs)、HDFS等)持久化数据与元信息
- * 使用分布式协调服务([Nexus](https://github.com/baidu/ins/)或者Zookeeper)选主与协调
- * 使用[Sofa-pbrpc](https://github.com/baidu/sofa-pbrpc/)实现跨进程通信
-
+* 使用分布式文件系统([BFS](https://github.com/baidu/bfs)、HDFS等)持久化数据与元信息
+* 使用分布式协调服务([Nexus](https://github.com/baidu/ins/)或者Zookeeper)选主与协调
+* 使用[Sofa-pbrpc](https://github.com/baidu/sofa-pbrpc/)实现跨进程通信
# 系统构建
-sh ./build.sh
+sh ./build.sh
参考[BUILD](BUILD-cn)
-
# 使用示例
-
[体验单机Tera](doc/cn/onebox.md)
-
[通过docker体验Tera](example/docker)
-
-[主要api使用方法](doc/cn/sdk_guide.md)
-
-[客户端teracli使用方法](doc/cn/teracli.md)
-
+[主要api使用方法](doc/sdk_reference/README.md)
+[客户端teracli使用方法](doc/tools/teracli.md)
+[集群间数据迁移的dump工具terautil使用方法](doc/tools/terautil.md)
+[造数据 & 读写数据的工具使用方法](doc/tools/benchmark.md)
+[性能测试工具ycsb使用方法](doc/tools/ycsb.md)
[其它文档](doc/cn/README.md)
-
#反馈与技术支持
tera_dev at baidu.com
-
# 成为贡献者
阅读[RoadMap](doc/cn/roadmap.md)文件或者源代码,了解我们当前的开发方向。
-
完成[5个小任务](doc/to_be_a_contributor.md),帮你一步步成为tera贡献者。
-
# Become a Committer
-
成为tera的committer,你需要知道的一些[规则](doc/cn/to_be_a_committer.md)。
-
# 欢迎加入
如果你热爱开源,热爱分布式技术,请将简历发送至:
opensearch at baidu.com
diff --git a/resources/images/global_txn.png b/resources/images/global_txn.png
new file mode 100644
index 000000000..0e6e8f950
Binary files /dev/null and b/resources/images/global_txn.png differ
diff --git a/src/benchmark/mark.cc b/src/benchmark/mark.cc
index a0081e2e4..a53d1f8b7 100644
--- a/src/benchmark/mark.cc
+++ b/src/benchmark/mark.cc
@@ -49,7 +49,7 @@ void sdk_write_callback(tera::RowMutation* row_mu) {
adapter->WriteCallback(row_mu, req_size, req_time);
}
-void Adapter::Write(const std::string& row,
+void Adapter::Write(int opt, const std::string& row,
std::map >& column,
uint64_t timestamp,
std::string& value) {
@@ -74,7 +74,13 @@ void Adapter::Write(const std::string& row,
if (FLAGS_verify) {
add_checksum(row, family, qualifier, &value);
}
- row_mu->Put(family, qualifier, value, (int64_t)timestamp);
+ if (opt == PUT) {
+ row_mu->Put(family, qualifier, value, (int64_t)timestamp);
+ } else if (opt == PIF) {
+ row_mu->PutIfAbsent(family, qualifier, value);
+ } else {
+ abort();
+ }
if (FLAGS_verify) {
remove_checksum(&value);
}
@@ -122,6 +128,8 @@ void Adapter::WriteCallback(tera::RowMutation* row_mu, size_t req_size,
tera::ErrorCode err = row_mu->GetError();
if (err.GetType() == tera::ErrorCode::kOK) {
write_marker_.OnSuccess(req_size, latency);
+ } else if (err.GetType() == tera::ErrorCode::kTxnFail) {
+ write_marker_.OnConflict(req_size, latency);
} else {
/*std::cerr << "fail to write: row=[" << row << "], column=["
<< family << ":" << qualifier << "], timestamp=["
diff --git a/src/benchmark/mark.h b/src/benchmark/mark.h
index c510de42c..ec5099eb5 100644
--- a/src/benchmark/mark.h
+++ b/src/benchmark/mark.h
@@ -18,7 +18,7 @@
#include "common/mutex.h"
#include "tera.h"
-#include "utils/counter.h"
+#include "common/counter.h"
DECLARE_int64(pend_size);
DECLARE_int64(pend_count);
@@ -46,7 +46,8 @@ enum OP {
PUT = 1,
GET = 2,
SCN = 3,
- DEL = 4
+ DEL = 4,
+ PIF = 5
};
int64_t Now();
@@ -201,8 +202,11 @@ class Statistic {
last_finish_size_(0),
last_success_count_(0),
last_success_size_(0),
+ last_conflict_count_(0),
+ last_conflict_size_(0),
finish_marker_(1000000),
- success_marker_(1000000) {}
+ success_marker_(1000000),
+ conflict_marker_(1000000) {}
int GetOpt() {
return opt_;
@@ -210,24 +214,30 @@ class Statistic {
void GetStatistic(int64_t* total_count, int64_t* total_size,
int64_t* finish_count, int64_t* finish_size,
- int64_t* success_count, int64_t* success_size) {
+ int64_t* success_count, int64_t* success_size,
+ int64_t* conflict_count, int64_t* conflict_size) {
*total_count = last_total_count_ = total_count_.Get();
*total_size = last_total_size_ = total_size_.Get();
*finish_count = last_finish_count_ = finish_count_.Get();
*finish_size = last_finish_size_ = finish_size_.Get();
*success_count = last_success_count_ = success_count_.Get();
*success_size = last_success_size_ = success_size_.Get();
+ *conflict_count = last_conflict_count_ = conflict_count_.Get();
+ *conflict_size = last_conflict_size_ = conflict_size_.Get();
}
void GetLastStatistic(int64_t* total_count, int64_t* total_size,
int64_t* finish_count, int64_t* finish_size,
- int64_t* success_count, int64_t* success_size) {
+ int64_t* success_count, int64_t* success_size,
+ int64_t* conflict_count, int64_t* conflict_size) {
*total_count = last_total_count_;
*total_size = last_total_size_;
*finish_count = last_finish_count_;
*finish_size = last_finish_size_;
*success_count = last_success_count_;
*success_size = last_success_size_;
+ *conflict_count = last_conflict_count_;
+ *conflict_size = last_conflict_size_;
}
Marker* GetFinishMarker() {
@@ -238,6 +248,10 @@ class Statistic {
return &success_marker_;
}
+ Marker* GetConflictMarker() {
+ return &conflict_marker_;
+ }
+
void OnReceive(size_t size) {
last_send_time_ = Now();
last_send_size_ = size;
@@ -257,6 +271,12 @@ class Statistic {
success_marker_.AddLatency(latency);
}
+ void OnConflict(size_t size, uint32_t latency) {
+ conflict_count_.Inc();
+ conflict_size_.Add(size);
+ conflict_marker_.AddLatency(latency);
+ }
+
void CheckPending() {
int64_t max_pend_count = FLAGS_pend_count;
int64_t max_pend_size = FLAGS_pend_size << 20;
@@ -297,6 +317,8 @@ class Statistic {
tera::Counter finish_size_;
tera::Counter success_count_;
tera::Counter success_size_;
+ tera::Counter conflict_count_;
+ tera::Counter conflict_size_;
size_t last_send_size_;
int64_t last_send_time_;
@@ -307,9 +329,12 @@ class Statistic {
int64_t last_finish_size_;
int64_t last_success_count_;
int64_t last_success_size_;
+ int64_t last_conflict_count_;
+ int64_t last_conflict_size_;
Marker finish_marker_;
Marker success_marker_;
+ Marker conflict_marker_;
};
class Adapter {
@@ -317,7 +342,7 @@ class Adapter {
Adapter(tera::Table* table);
~Adapter();
- void Write(const std::string& row,
+ void Write(int opt, const std::string& row,
std::map >& column,
uint64_t timestamp,
std::string& value);
diff --git a/src/benchmark/mark_main.cc b/src/benchmark/mark_main.cc
index 36ae66c4b..dd57af93a 100644
--- a/src/benchmark/mark_main.cc
+++ b/src/benchmark/mark_main.cc
@@ -6,6 +6,7 @@
#include
#include
+#include
#include
#include
#include
@@ -61,6 +62,8 @@ bool parse_row(const char* buffer, ssize_t size,
*op = GET;
} else if (strncmp(buffer, "PUT", 3) == 0) {
*op = PUT;
+ } else if (strncmp(buffer, "PIF", 3) == 0) {
+ *op = PIF;
} else {
return false;
}
@@ -76,13 +79,14 @@ bool parse_row(const char* buffer, ssize_t size,
delim = end;
}
row->assign(buffer, delim - buffer);
- if ((delim == end && mode != WRITE && (mode != MIX || *op != PUT)) ||
- (delim == end && mode == DELETE)) {
+ if ((delim == end && mode != WRITE &&
+ (mode != MIX || (*op != PUT && *op != PIF)))
+ ||(delim == end && mode == DELETE)) {
return true;
}
// parse value
- if (mode == WRITE || (mode == MIX && *op == PUT)) {
+ if (mode == WRITE || (mode == MIX && (*op == PUT || *op == PIF))) {
if (delim == end) {
return false;
}
@@ -170,7 +174,7 @@ bool parse_row(const char* buffer, ssize_t size,
}
if (comma == end) {
return true;
- } else if (mode == WRITE || (mode == MIX && *op == PUT)) {
+ } else if (mode == WRITE || (mode == MIX && (*op == PUT || *op == PIF))) {
return false;
}
@@ -217,10 +221,11 @@ bool get_next_row(int* op, std::string* row,
void print_header() {
std::cout << "HH:MM:SS OPT\t";
if (mode != SCAN && type == ASYNC) {
- std::cout << "SENT [speed/total]\t\t";
+ std::cout << "SENT [total/speed]\t\t";
}
- std::cout << "FINISH [speed/total]\t\t";
- std::cout << "SUCCESS [speed/total]\t\t";
+ std::cout << "FINISH [total/speed]\t\t";
+ std::cout << "SUCCESS [total/speed]\t\t";
+ std::cout << "CONFLICT [total/speed]\t\t";
if (mode != SCAN && type == ASYNC) {
std::cout << "PENDING [count]";
}
@@ -271,24 +276,28 @@ void print_size_and_count(int64_t size, int64_t count) {
}
void print_statistic(Statistic* statistic) {
- int64_t old_total_count, old_finish_count, old_success_count;
- int64_t old_total_size, old_finish_size, old_success_size;
+ int64_t old_total_count, old_finish_count, old_success_count, old_conflict_count;
+ int64_t old_total_size, old_finish_size, old_success_size, old_conflict_size;
statistic->GetLastStatistic(&old_total_count, &old_total_size,
&old_finish_count, &old_finish_size,
- &old_success_count, &old_success_size);
+ &old_success_count, &old_success_size,
+ &old_conflict_count, &old_conflict_size);
- int64_t new_total_count, new_finish_count, new_success_count;
- int64_t new_total_size, new_finish_size, new_success_size;
+ int64_t new_total_count, new_finish_count, new_success_count, new_conflict_count;
+ int64_t new_total_size, new_finish_size, new_success_size, new_conflict_size;
statistic->GetStatistic(&new_total_count, &new_total_size,
&new_finish_count, &new_finish_size,
- &new_success_count, &new_success_size);
+ &new_success_count, &new_success_size,
+ &new_conflict_count, &new_conflict_size);
int64_t total_count = new_total_count - old_total_count;
int64_t finish_count = new_finish_count - old_finish_count;
int64_t success_count = new_success_count - old_success_count;
+ int64_t conflict_count = new_conflict_count - old_conflict_count;
int64_t total_size = new_total_size - old_total_size;
int64_t finish_size = new_finish_size - old_finish_size;
int64_t success_size = new_success_size - old_success_size;
+ int64_t conflict_size = new_conflict_size - old_conflict_size;
int64_t total_pending_count = new_total_count - new_finish_count;
// scan
@@ -317,6 +326,11 @@ void print_statistic(Statistic* statistic) {
std::cout << "/";
print_size_and_count(success_size, success_count);
std::cout << "\t\t";
+
+ print_size_and_count(new_conflict_size, new_conflict_count);
+ std::cout << "/";
+ print_size_and_count(conflict_size, conflict_count);
+ std::cout << "\t\t";
if (mode != SCAN && type == ASYNC) {
std::cout << total_pending_count;
@@ -341,6 +355,11 @@ void print_marker(Statistic* statistic) {
std::cout << " [SUCCESS]" << std::endl;
Marker* success_marker = statistic->GetSuccessMarker();
print_marker(success_marker);
+ if (statistic->GetOpt() == PUT) {
+ std::cout << " [CONFLICT]" << std::endl;
+ Marker* conflict_marker = statistic->GetConflictMarker();
+ print_marker(conflict_marker);
+ }
}
void* print_proc(void* param) {
@@ -416,11 +435,12 @@ void* print_proc(void* param) {
}
void print_summary(Statistic* marker, double duration) {
- int64_t total_count, finish_count, success_count;
- int64_t total_size, finish_size, success_size;
+ int64_t total_count, finish_count, success_count, conflict_count;
+ int64_t total_size, finish_size, success_size, conflict_size;
marker->GetStatistic(&total_count, &total_size,
&finish_count, &finish_size,
- &success_count, &success_size);
+ &success_count, &success_size,
+ &conflict_count, &conflict_size);
print_opt(marker);
std::streamsize precision = std::cout.precision();
@@ -432,7 +452,10 @@ void print_summary(Statistic* marker, double duration) {
<< (double)finish_size / 1048576 / duration << " MB/s\n"
<< " succ: " << success_size << " bytes "
<< success_count << " records "
- << (double)success_size / 1048576 / duration << " MB/s"
+ << (double)success_size / 1048576 / duration << " MB/s\n"
+ << " conflict: " << conflict_size << " bytes "
+ << conflict_count << " records "
+ << (double)conflict_size / 1048576 / duration << " MB/s"
<< std::endl;
std::cout.precision(precision);
std::cout.flags(flag);
@@ -616,10 +639,11 @@ int main(int argc, char** argv) {
switch (opt) {
case PUT:
+ case PIF:
if (type == SYNC && mode == MIX && last_opt == GET) {
adapter->CommitSyncRead();
}
- adapter->Write(row, column, largest_ts, value);
+ adapter->Write(opt, row, column, largest_ts, value);
break;
case GET:
if (type == SYNC && mode == MIX && last_opt == PUT) {
diff --git a/src/benchmark/tpcc/data_generator.cc b/src/benchmark/tpcc/data_generator.cc
new file mode 100644
index 000000000..8fd76cbe6
--- /dev/null
+++ b/src/benchmark/tpcc/data_generator.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/data_generator.h"
+#include "benchmark/tpcc/tpccdb.h"
+#include "common/thread_pool.h"
+#include "common/timer.h"
+
+DECLARE_int32(warehouses_count);
+DECLARE_int32(tpcc_thread_pool_size);
+DECLARE_int32(generate_data_wait_times);
+
+namespace tera {
+namespace tpcc {
+
+DataGenerator::DataGenerator(RandomGenerator* rand_gen, TpccDb* db)
+ : event_(),
+ rand_gen_(rand_gen),
+ db_(db),
+ now_datatime_(get_curtime_str()),
+ thread_pool_(FLAGS_tpcc_thread_pool_size) {
+ for (int i = 0; i < kTpccTableCnt; ++i) {
+ states_.push_back(std::make_pair(Counter(), Counter()));
+ }
+}
+
+void DataGenerator::PrintJoinTimeoutInfo(int need_cnt, int table_enum_num) {
+ if (need_cnt > states_[table_enum_num].first.Get() + states_[table_enum_num].second.Get()) {
+ LOG(ERROR) << "table:" << kTpccTables[table_enum_num]
+ << "[need/succ/fail]:["
+ << need_cnt << "/"
+ << states_[table_enum_num].first.Get() << "/"
+ << states_[table_enum_num].first.Get() << "]";
+ }
+}
+
+void DataGenerator::Join() {
+ event_.Trigger();
+ if (!event_.TimeWait(FLAGS_generate_data_wait_times)) {
+ int stock_cnt = FLAGS_warehouses_count * kItemCount;
+ int districts_cnt = FLAGS_warehouses_count * kDistrictCountPerWarehouse;
+ int customers_cnt = districts_cnt * kCustomerCountPerDistrict;
+ PrintJoinTimeoutInfo(kItemCount, kItemTable);
+ PrintJoinTimeoutInfo(stock_cnt, kStockTable);
+ PrintJoinTimeoutInfo(FLAGS_warehouses_count, kWarehouseTable);
+ PrintJoinTimeoutInfo(districts_cnt, kDistrictTable);
+ PrintJoinTimeoutInfo(customers_cnt, kCustomerTable);
+ PrintJoinTimeoutInfo(customers_cnt, kCustomerLastIndex);
+ PrintJoinTimeoutInfo(customers_cnt, kHistoryTable);
+ }
+}
+
+void DataGenerator::GenStocks(int32_t warehouse_id) {
+ IdSet original_ids = PickUniqueIdSet(rand_gen_, kItemCount / 10, 1, kItemCount);
+ event_.AddEventSources(kItemCount);
+ for (int id = 1; id <= kItemCount; ++id) {
+ bool is_original = original_ids.find(id) != original_ids.end();
+ PushToInsertQueue(std::bind(&DataGenerator::GenStock, this, id, warehouse_id, is_original));
+ }
+}
+
+void DataGenerator::GenStock(int32_t id, int32_t warehouse_id, bool is_original) {
+ Stock s(id, warehouse_id, is_original, rand_gen_);
+ VLOG(12) << s.ToString();
+ db_->InsertStock(s) ? states_[kStockTable].first.Inc() : states_[kStockTable].second.Inc();
+ event_.Complete();
+}
+
+void DataGenerator::GenCustomers(int32_t district_id, int32_t warehouse_id) {
+ IdSet bad_credit_ids = PickUniqueIdSet(rand_gen_,
+ kCustomerCountPerDistrict / 10, 1, kCustomerCountPerDistrict);
+ event_.AddEventSources(kCustomerCountPerDistrict);
+ for (int c_id = 1; c_id <= kCustomerCountPerDistrict; ++c_id) {
+ bool is_bad_credit = bad_credit_ids.find(c_id) != bad_credit_ids.end();
+ Customer c(c_id, district_id, warehouse_id, now_datatime_, is_bad_credit, rand_gen_);
+ VLOG(12) << c.ToString();
+ db_->InsertCustomer(c) ? states_[kCustomerTable].first.Inc() : states_[kCustomerTable].second.Inc();
+ }
+ event_.Complete(kCustomerCountPerDistrict);
+}
+
+void DataGenerator::GenHistorys(int32_t district_id, int32_t warehouse_id) {
+ event_.AddEventSources(kCustomerCountPerDistrict);
+ for (int h_id = 1; h_id <= kCustomerCountPerDistrict; ++h_id) {
+ History h(h_id, district_id, warehouse_id, now_datatime_, rand_gen_);
+ VLOG(12) << h.ToString();
+ db_->InsertHistory(h) ? states_[kHistoryTable].first.Inc() : states_[kHistoryTable].second.Inc();
+ }
+ event_.Complete(kCustomerCountPerDistrict);
+}
+
+void DataGenerator::GenOrderLines(int cnt, int32_t order_id, int32_t district_id,
+ int32_t warehouse_id, bool new_order) {
+ event_.AddEventSources(cnt);
+ for (int i = 1; i <= cnt; ++i) {
+ OrderLine ol(order_id, district_id, warehouse_id, i, new_order, now_datatime_, rand_gen_);
+ VLOG(12) << ol.ToString();
+ db_->InsertOrderLine(ol) ? states_[kOrderLineTable].first.Inc() : states_[kOrderLineTable].second.Inc();
+ }
+ event_.Complete(cnt);
+}
+
+void DataGenerator::GenOrders(int32_t d_id, int32_t w_id) {
+ std::vector disorder_ids = rand_gen_->MakeDisOrderList(1, kCustomerCountPerDistrict);
+ event_.AddEventSources(kCustomerCountPerDistrict);
+ for (int o_id = 1; o_id <= kCustomerCountPerDistrict; ++o_id) {
+ bool new_order = (kCustomerCountPerDistrict - kInitNewOrderCountPerDistrict) < o_id;
+ int32_t c_id = disorder_ids[o_id];
+ Order o(o_id, c_id, d_id, w_id, new_order, now_datatime_, rand_gen_);
+ // insert order line and new order first
+ // this use sync interface
+ GenOrderLines(o.o_ol_cnt, o_id, d_id, w_id, new_order);
+ if (new_order) {
+ event_.AddEventSources(1);
+ NewOrder no(o_id, d_id, w_id);
+ VLOG(12) << no.ToString();
+ db_->InsertNewOrder(no) ? states_[kNewOrderTable].first.Inc() : states_[kNewOrderTable].second.Inc();
+ event_.Complete(1);
+ }
+ // wait orderline and neworder insert done
+ VLOG(12) << o.ToString();
+ db_->InsertOrder(o) ? states_[kOrderTable].first.Inc() : states_[kOrderTable].second.Inc();
+ }
+ event_.Complete(kCustomerCountPerDistrict);
+}
+
+void DataGenerator::GenDistricts(int32_t warehouse_id) {
+ event_.AddEventSources(kDistrictCountPerWarehouse);
+ for (int d_id = 1; d_id <= kDistrictCountPerWarehouse; ++d_id) {
+ District d(d_id, warehouse_id, rand_gen_);
+ VLOG(12) << d.ToString();
+ db_->InsertDistrict(d) ? states_[kDistrictTable].first.Inc() : states_[kDistrictTable].second.Inc();
+ GenCustomers(d_id, warehouse_id);
+ GenHistorys(d_id, warehouse_id);
+
+ GenOrders(d_id, warehouse_id);
+ }
+ event_.Complete(kDistrictCountPerWarehouse);
+}
+
+void DataGenerator::GenWarehouses() {
+ event_.AddEventSources(FLAGS_warehouses_count);
+ for (int32_t w_id = 1; w_id <= FLAGS_warehouses_count; ++w_id) {
+ GenStocks(w_id);
+ Warehouse w(w_id, rand_gen_);
+ VLOG(12) << w.ToString();
+ db_->InsertWarehouse(w) ? states_[kWarehouseTable].first.Inc() : states_[kWarehouseTable].second.Inc();
+
+ GenDistricts(w_id);
+ }
+ event_.Complete(FLAGS_warehouses_count);
+}
+
+void DataGenerator::GenItems() {
+ IdSet original_ids = PickUniqueIdSet(rand_gen_, kItemCount / 10, 1, kItemCount);
+ event_.AddEventSources(kItemCount);
+ for (int i_id = 1; i_id <= kItemCount; ++i_id) {
+ bool is_original = original_ids.find(i_id) != original_ids.end();
+ PushToInsertQueue(std::bind(&DataGenerator::GenItem, this, i_id, is_original));
+ }
+}
+
+void DataGenerator::GenItem(int32_t item_id, bool is_original) {
+ Item item(item_id, is_original, rand_gen_);
+ VLOG(12) << item.ToString();
+ db_->InsertItem(item) ? states_[kItemTable].first.Inc() : states_[kItemTable].second.Inc();
+ event_.Complete();
+}
+
+void DataGenerator::PushToInsertQueue(const ThreadPool::Task& task) {
+ while(thread_pool_.PendingNum() > FLAGS_tpcc_thread_pool_size / 2) {
+ usleep(100);
+ }
+ thread_pool_.AddTask(task);
+ VLOG(12) << "thread_pool pending num = " << thread_pool_.PendingNum();
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/data_generator.h b/src/benchmark/tpcc/data_generator.h
new file mode 100644
index 000000000..f5593b64c
--- /dev/null
+++ b/src/benchmark/tpcc/data_generator.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#ifndef TERA_BENCHMARK_TPCC_DATA_GENERATOR_H
+#define TERA_BENCHMARK_TPCC_DATA_GENERATOR_H
+
+#include
+#include
+
+#include "benchmark/tpcc/random_generator.h"
+#include "benchmark/tpcc/tpccdb.h"
+#include "common/counter.h"
+#include "common/event.h"
+#include "common/thread_pool.h"
+
+namespace tera {
+namespace tpcc {
+
+
+class DataGenerator {
+public:
+ DataGenerator(RandomGenerator* random_gen, TpccDb* db);
+ ~DataGenerator(){}
+ void GenWarehouses();
+ void GenItems();
+ void Join();
+
+private:
+ void PrintJoinTimeoutInfo(int need_cnt, int table_enum_num);
+
+ // for generate data
+ void GenStocks(int32_t warehouse_id);
+ void GenCustomers(int32_t district_id, int32_t warehouse_id);
+ void GenHistorys(int32_t district_id, int32_t warehouse_id);
+ void GenOrderLines(int cnt, int32_t order_id, int32_t district_id,
+ int32_t warehouse_id, bool new_order);
+ void GenOrders(int32_t district_id, int32_t warehouse_id);
+ void GenDistricts(int32_t warehouse_id);
+
+ void GenItem(int32_t item_id, bool is_original);
+ void GenStock(int32_t id, int32_t warehouse_id, bool is_original);
+
+ // for async insert
+ void PushToInsertQueue(const ThreadPool::Task& task);
+private:
+ typedef std::vector> InsertStates;
+ CompletedEvent event_;
+ RandomGenerator* rand_gen_;
+ TpccDb* db_;
+ InsertStates states_;
+ std::string now_datatime_;
+ common::ThreadPool thread_pool_;
+};
+
+} // namespace tpcc
+} // namespace tera
+
+#endif /* TERA_BENCHMARK_TPCC_DATA_GENERATOR_H */
diff --git a/src/benchmark/tpcc/driver.cc b/src/benchmark/tpcc/driver.cc
new file mode 100644
index 000000000..aed2e6235
--- /dev/null
+++ b/src/benchmark/tpcc/driver.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/driver.h"
+#include "benchmark/tpcc/tpccdb.h"
+#include "common/thread_pool.h"
+#include "common/timer.h"
+
+DECLARE_int32(driver_wait_times);
+DECLARE_int32(warehouses_count);
+DECLARE_int32(tpcc_run_gtxn_thread_pool_size);
+DECLARE_int64(transactions_count);
+
+namespace tera {
+namespace tpcc {
+
+Driver::Driver(RandomGenerator* rand_gen, TpccDb* db)
+ : event_(),
+ rand_gen_(rand_gen),
+ db_(db),
+ now_datatime_(get_curtime_str()),
+ thread_pool_(FLAGS_tpcc_run_gtxn_thread_pool_size) {
+}
+
+void Driver::PrintJoinTimeoutInfo(int need_cnt, int table_enum_num) {
+ if (need_cnt < states_[table_enum_num].first.Get() + states_[table_enum_num].second.Get()) {
+ LOG(ERROR) << "table:" << kTpccTables[table_enum_num]
+ << "[need/succ/fail]:["
+ << need_cnt << "/"
+ << states_[table_enum_num].first.Get() << "/"
+ << states_[table_enum_num].first.Get() << "]";
+ }
+}
+
+void Driver::RunTransactions() {
+ for (int64_t i = 0; i < FLAGS_transactions_count; ++i) {
+ RunOneTransaction();
+ }
+}
+
+void Driver::Join() {
+ event_.Trigger();
+ if (!event_.TimeWait(FLAGS_driver_wait_times)) {
+ // TODO
+ }
+}
+
+void Driver::RunOneTransaction() {
+ int rand_num = rand_gen_->GetRandom(1, 100);
+ if (rand_num <= kTpccTransactionRatios[0]) { // %4 do stock_level
+ RunStockLevelTxn();
+ } else if (rand_num <= kTpccTransactionRatios[1]) { // %4 do order_status
+ RunOrderStatusTxn();
+ } else if (rand_num <= kTpccTransactionRatios[2]) { // %4 do delivery
+ RunDeliveryTxn();
+ } else if (rand_num <= kTpccTransactionRatios[3]) { // %43 do payment
+ RunPaymentTxn();
+ } else { // %45 do new_order
+ RunNewOrderTxn();
+ }
+}
+
+void Driver::RunStockLevelTxn() {
+ int32_t threshold = rand_gen_->GetRandom(kMinStockLevelThreshold, kMaxStockLevelThreshold);
+ StockLevelResult ret;
+ db_->StockLevelTxn(FindWareHouse(), FindDistrict(), threshold, &ret);
+}
+
+void Driver::RunOrderStatusTxn() {
+ int x = rand_gen_->GetRandom(1, 100);
+ OrderStatusResult ret;
+ if (x <= 60) {
+ // 60% order_status by lastname
+ std::string last_name = GenLastName(rand_gen_, kCustomerCountPerDistrict);
+ db_->OrderStatusTxn(true, FindWareHouse(), FindDistrict(),
+ -1, last_name, &ret);
+ } else {
+ // 40% order_status by customer_id
+ db_->OrderStatusTxn(false, FindWareHouse(), FindDistrict(),
+ FindCustomerId(), "", &ret);
+ }
+}
+
+void Driver::RunDeliveryTxn() {
+ int32_t carrier_id = rand_gen_->GetRandom(kMinCarrierId, kMaxCarrierId);
+ DeliveryResult ret;;
+ db_->DeliveryTxn(FindWareHouse(), carrier_id, get_curtime_str(), &ret);
+}
+
+void Driver::RunPaymentTxn() {
+ int32_t warehouse_id = FindWareHouse();
+ int32_t district_id = FindDistrict();
+
+ float h_amount = rand_gen_->MakeFloat(kRuntimeMinAmount, kRuntimeMaxAmount,
+ kRuntimeAmountDigits);
+
+ int32_t customer_warehouse_id = -1;
+ int32_t customer_district_id = -1;
+
+ int x = rand_gen_->GetRandom(1, 100);
+
+ // set customer c_w_id and c_d_id
+ if (FLAGS_warehouses_count == 1 && x <= 85) {
+ // 85% payment through local warehouse (or only one warehouse)
+ customer_warehouse_id = warehouse_id;
+ customer_district_id = district_id;
+ } else {
+ // 15% payment through remote warehouse
+ customer_warehouse_id =
+ rand_gen_->GetRandom(1, FLAGS_warehouses_count, warehouse_id);
+ customer_district_id = FindDistrict();
+ }
+
+ x = rand_gen_->GetRandom(1, 100);
+ PaymentResult ret;
+ if (x <= 60) {
+ // 60% payment by lastname
+ std::string last_name = GenLastName(rand_gen_, kCustomerCountPerDistrict);
+ db_->PaymentTxn(true, warehouse_id, district_id,
+ customer_warehouse_id, customer_district_id, -1,
+ last_name, h_amount, &ret);
+ } else {
+ // 40% payment by customer_id
+ db_->PaymentTxn(false, warehouse_id, district_id,
+ customer_warehouse_id, customer_district_id, FindCustomerId(),
+ "", h_amount, &ret);
+ }
+}
+
+void Driver::RunNewOrderTxn() {
+ int32_t warehouse_id = FindWareHouse();
+
+ // init NewOrderInfo
+ NewOrderInfo info;
+ // 1% of new_order transactions will be failed
+ info.need_failed = rand_gen_->GetRandom(1,100) == 1 ? true : false;
+ info.o_ol_cnt = rand_gen_->GetRandom(kMinOrderLineCnt, kMaxOrderLineCnt);
+
+ info.ol_supply_w_ids.reserve(info.o_ol_cnt);
+ info.ol_i_ids.reserve(info.o_ol_cnt);
+ info.ol_quantities.reserve(info.o_ol_cnt);
+ info.o_all_local = 1;
+ for (int32_t i = 0; i < info.o_ol_cnt; ++i) {
+ // 1% of orderlines will be remote order
+ bool remote = rand_gen_->GetRandom(1, 100) == 1 ? true : false;
+ if (FLAGS_warehouses_count > 1 && remote) {
+ info.ol_supply_w_ids.emplace_back(
+ rand_gen_->GetRandom(1, FLAGS_warehouses_count, warehouse_id));
+ info.o_all_local = 0;
+ } else {
+ info.ol_supply_w_ids.emplace_back(warehouse_id);
+ }
+ info.ol_i_ids.emplace_back(FindItemId());
+ info.ol_quantities.emplace_back(
+ rand_gen_->GetRandom(1, kMaxOrderLineQuantity));
+ }
+
+ NewOrderResult ret;
+ db_->NewOrderTxn(warehouse_id, FindDistrict(), FindCustomerId(), info, &ret);
+}
+
+void Driver::PushToInsertQueue(const ThreadPool::Task& task) {
+ while(thread_pool_.PendingNum() > FLAGS_tpcc_run_gtxn_thread_pool_size / 2) {
+ usleep(100);
+ }
+ thread_pool_.AddTask(task);
+ VLOG(12) << "thread_pool pending num = " << thread_pool_.PendingNum();
+}
+
+int32_t Driver::FindWareHouse() {
+ return rand_gen_->GetRandom(1, FLAGS_warehouses_count);
+}
+
+int32_t Driver::FindDistrict() {
+ return rand_gen_->GetRandom(1, kDistrictCountPerWarehouse);
+}
+
+int32_t Driver::FindCustomerId() {
+ return rand_gen_->NURand(1023, 1, kCustomerCountPerDistrict);
+}
+
+int32_t Driver::FindItemId() {
+ return rand_gen_->NURand(8191, 1, kItemCount);
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/driver.h b/src/benchmark/tpcc/driver.h
new file mode 100644
index 000000000..56bf5a66f
--- /dev/null
+++ b/src/benchmark/tpcc/driver.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#ifndef TERA_BENCHMARK_TPCC_DRIVER_H
+#define TERA_BENCHMARK_TPCC_DRIVER_H
+
+#include
+#include
+
+#include "benchmark/tpcc/random_generator.h"
+#include "benchmark/tpcc/tpccdb.h"
+#include "common/counter.h"
+#include "common/event.h"
+#include "common/thread_pool.h"
+
+namespace tera {
+namespace tpcc {
+
+class Driver {
+public:
+ Driver(RandomGenerator* random_gen, TpccDb* db);
+ ~Driver(){}
+ void RunTransactions();
+ void Join();
+
+private:
+ void PrintJoinTimeoutInfo(int need_cnt, int table_enum_num);
+
+ // for run transaction
+ void RunOneTransaction();
+ //
+ void RunStockLevelTxn();
+
+ void RunOrderStatusTxn();
+
+ void RunDeliveryTxn();
+
+ void RunPaymentTxn();
+
+ void RunNewOrderTxn();
+
+ // for async run txn
+ void PushToInsertQueue(const ThreadPool::Task& task);
+
+ int32_t FindWareHouse();
+
+ int32_t FindDistrict();
+
+ int32_t FindCustomerId();
+
+ int32_t FindItemId();
+private:
+ typedef std::vector> TxnStates;
+ CompletedEvent event_;
+ RandomGenerator* rand_gen_;
+ TpccDb* db_;
+ TxnStates states_;
+ std::string now_datatime_;
+ common::ThreadPool thread_pool_;
+};
+
+} // namespace tpcc
+} // namespace tera
+
+#endif /* TERA_BENCHMARK_TPCC_DATA_GENERATOR_H */
diff --git a/src/benchmark/tpcc/mock_tpccdb.cc b/src/benchmark/tpcc/mock_tpccdb.cc
new file mode 100644
index 000000000..ee8cce0d0
--- /dev/null
+++ b/src/benchmark/tpcc/mock_tpccdb.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/mock_tpccdb.h"
+
+#include
+#include
+
+namespace tera {
+namespace tpcc {
+
+MockTpccDb::MockTpccDb() : flag_(true) {}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/mock_tpccdb.h b/src/benchmark/tpcc/mock_tpccdb.h
new file mode 100644
index 000000000..0f29f0320
--- /dev/null
+++ b/src/benchmark/tpcc/mock_tpccdb.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#ifndef TERA_BENCHMARK_TPCC_MOCK_TPCCDB_H
+#define TERA_BENCHMARK_TPCC_MOCK_TPCCDB_H
+
+#include "benchmark/tpcc/tpccdb.h"
+
+namespace tera {
+namespace tpcc {
+
+class TpccDb;
+class TxnResult;
+
+class MockTpccDb : public TpccDb {
+public:
+ MockTpccDb();
+ virtual ~MockTpccDb() {}
+
+ virtual bool CreateTables() { return true; }
+ virtual bool CleanTables() { return true; }
+
+ // init db
+ virtual bool InsertItem(const Item& i) {
+ return flag_;
+ }
+
+ virtual bool InsertWarehouse(const Warehouse& w) {
+ return flag_;
+ }
+
+ virtual bool InsertDistrict(const District& d) {
+ return flag_;
+ }
+
+ virtual bool InsertCustomer(const Customer& c) {
+ return flag_;
+ }
+
+ virtual bool InsertHistory(const History& h) {
+ return flag_;
+ }
+
+ virtual bool InsertStock(const Stock& s) {
+ return flag_;
+ }
+
+ virtual bool InsertOrder(const Order& o) {
+ return flag_;
+ }
+
+ virtual bool InsertOrderLine(const OrderLine& ol) {
+ return flag_;
+ }
+
+ virtual bool InsertNewOrder(const NewOrder& no) {
+ return flag_;
+ }
+
+ virtual void StockLevelTxn(int32_t warehouse_id, int32_t district_id,
+ int32_t threshold,
+ StockLevelResult* ret) {}
+
+ virtual void DeliveryTxn(int32_t warehouse_id,
+ int32_t carrier_id,
+ const std::string& delivery_datetime,
+ DeliveryResult* ret) {}
+
+ virtual void OrderStatusTxn(bool by_last_name,
+ int32_t warehouse_id, int32_t district_id,
+ int32_t c_customer_id,
+ const std::string& last_name,
+ OrderStatusResult* ret) {}
+
+ virtual void PaymentTxn(bool by_last_name,
+ int32_t warehouse_id, int32_t district_id,
+ int32_t c_warehouse_id, int32_t c_district_id,
+ int32_t c_customer_id,
+ const std::string& last_name,
+ int32_t h_amount,
+ PaymentResult* ret) {}
+
+ virtual void NewOrderTxn(int32_t warehouse_id,
+ int32_t district_id,
+ int32_t customer_id, const NewOrderInfo& info,
+ NewOrderResult* ret) {}
+
+private:
+ bool flag_;
+};
+
+} // namespace tpcc
+} // namespace tera
+
+#endif /* TERA_BENCHMARK_TPCC_MOCK_TPCCDB_H */
diff --git a/src/benchmark/tpcc/random_generator.cc b/src/benchmark/tpcc/random_generator.cc
new file mode 100644
index 000000000..9308ec6e9
--- /dev/null
+++ b/src/benchmark/tpcc/random_generator.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/random_generator.h"
+
+#include
+
+namespace tera {
+namespace tpcc {
+
+RandomGenerator::RandomGenerator():c_({0,0,0}) {
+ InitRandomState();
+}
+
+void RandomGenerator::InitRandomState() {
+ memset(&rand_state_, 0, sizeof(rand_state_));
+ int ret = initstate_r(static_cast(time(NULL)),
+ rand_state_buf_,
+ sizeof(rand_state_buf_),
+ &rand_state_);
+ assert(ret == 0);
+}
+
+NURandConstant RandomGenerator::GetRandomConstant() const {
+ return c_;
+}
+
+void RandomGenerator::SetRandomConstant() {
+ c_.c_last = GetRandom(0, 255);
+ c_.c_id = GetRandom(0, 1023);
+ c_.ol_i_id = GetRandom(0, 8191);
+}
+
+inline bool VarfiyConstantAvailableForRun(int run_last, int load_last) {
+ int delta = run_last - load_last;
+ delta = delta > 0 ? delta : -1 * delta;
+ return 65 <=delta && delta <= 119 && delta != 96 && delta != 112;
+}
+
+void RandomGenerator::SetRandomConstant(const NURandConstant& constant_for_load) {
+ c_.c_last = GetRandom(0, 255);
+ c_.c_id = GetRandom(0, 1023);
+ c_.ol_i_id = GetRandom(0, 8191);
+ while (!VarfiyConstantAvailableForRun(c_.c_last, constant_for_load.c_last)) {
+ c_.c_last = GetRandom(0, 255);
+ }
+}
+
+int RandomGenerator::GetRandom(int lower, int upper) {
+ int ret = 0;
+ int err = random_r(&rand_state_, &ret);
+ assert(err == 0);
+ return lower <= upper ? (ret % (upper - lower + 1) + lower) : (ret % (lower - upper + 1) + upper);
+}
+
+int RandomGenerator::GetRandom(int lower, int upper, int exclude) {
+ if (exclude > upper || exclude < lower) {
+ return GetRandom(lower, upper);
+ } else {
+ int rand = GetRandom(lower, upper - 1);
+ if (rand >= exclude) {
+ ++rand;
+ }
+ return rand;
+ }
+}
+
+std::string RandomGenerator::MakeAString(int lower_len, int upper_len) {
+ int len = GetRandom(lower_len, upper_len);
+ std::string ret;
+ for (int i = 0; i < len; ++i) {
+ ret += (char)('a' + GetRandom(0, 25));
+ }
+ return ret;
+}
+
+std::string RandomGenerator::MakeNString(int lower_len, int upper_len) {
+ int len = GetRandom(lower_len, upper_len);
+ std::string ret;
+ for (int i = 0; i < len; ++i) {
+ ret += (char)('0' + GetRandom(0, 9));
+ }
+ return ret;
+}
+
+float RandomGenerator::MakeFloat(float lower, float upper, int digits) {
+ float num = 1.0;
+ for (int i = 0; i < digits; ++i) {
+ num *= 10;
+ }
+ return GetRandom(int(lower * num + 0.5), int(upper * num + 0.5)) / num;
+}
+
+std::vector RandomGenerator::MakeDisOrderList(int lower, int upper) {
+ std::vector ret(upper - lower + 1, -1);
+ for (int i = 0; i < upper - lower + 1; ++i) {
+ int rand_pos = GetRandom(0, upper - lower);
+ while (true) {
+ if (ret[rand_pos] == -1) {
+ ret[rand_pos] = lower + i;
+ break;
+ }
+ rand_pos = GetRandom(0, upper - lower);
+ }
+ }
+ return ret;
+}
+
+int RandomGenerator::NURand(int A, int x, int y) {
+ int C = 0;
+ switch(A) {
+ case 255:
+ C = c_.c_last;
+ break;
+ case 1023:
+ C = c_.c_id;
+ break;
+ case 8191:
+ C = c_.ol_i_id;
+ break;
+ default:
+ LOG(ERROR) << "NURand: A = " << A << " not available";
+ abort();
+ }
+ return (((GetRandom(0, A) | GetRandom(x, y)) + C) % (y - x + 1)) + x;
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/random_generator.h b/src/benchmark/tpcc/random_generator.h
new file mode 100644
index 000000000..c39070294
--- /dev/null
+++ b/src/benchmark/tpcc/random_generator.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#ifndef TERA_BENCHMARK_TPCC_RANDOM_GENERATOR_H
+#define TERA_BENCHMARK_TPCC_RANDOM_GENERATOR_H
+
+#include
+#include
+#include
+
+#include "benchmark/tpcc/tpcc_types.h"
+
+namespace tera {
+namespace tpcc {
+
+struct NURandConstant {
+ int c_last;
+ int c_id;
+ int ol_i_id;
+};
+
+class RandomGenerator {
+public:
+ RandomGenerator();
+ virtual ~RandomGenerator(){}
+
+ NURandConstant GetRandomConstant() const;
+ void SetRandomConstant();
+ void SetRandomConstant(const NURandConstant& constant_for_load);
+
+ // make a string A len=rand[lower_len, upper_len] A[x] = set(a..z)
+ std::string MakeAString(int lower_len, int upper_len);
+
+ // make a string N len=rand[lower_len, upper_len] N[x] = set(0..9)
+ std::string MakeNString(int lower_len, int upper_len);
+
+ float MakeFloat(float lower, float upper, int digits);
+
+ std::vector MakeDisOrderList(int lower, int upper);
+
+ int NURand(int A, int lower, int upper);
+
+ // get rand int from [lower, upper]
+ int GetRandom(int lower, int upper);
+
+ int GetRandom(int lower, int upper, int exclude);
+private:
+ void InitRandomState();
+private:
+ // for system call random_r and initstate_r
+ char rand_state_buf_[kRandomStateSize];
+ struct random_data rand_state_;
+
+ // for NURand, need a constant
+ NURandConstant c_;
+};
+
+} // namespace tpcc
+} // namespace tera
+
+#endif /* TERA_BENCHMARK_TPCC_RANDOM_GENERATOR_H */
diff --git a/src/benchmark/tpcc/tera_tpccdb.cc b/src/benchmark/tpcc/tera_tpccdb.cc
new file mode 100644
index 000000000..f35f4ed2a
--- /dev/null
+++ b/src/benchmark/tpcc/tera_tpccdb.cc
@@ -0,0 +1,538 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/tera_tpccdb.h"
+
+#include
+#include
+
+#include "sdk/client_impl.h"
+#include "sdk/sdk_utils.h"
+
+DECLARE_string(tera_client_flagfile);
+DECLARE_string(tera_table_schema_dir);
+
+namespace tera {
+namespace tpcc {
+
+TeraTpccDb::TeraTpccDb() : client_(NULL) {
+ ErrorCode error_code;
+ client_ = Client::NewClient(FLAGS_tera_client_flagfile, "tera_tpcc", &error_code);
+ if (client_ == NULL) {
+ LOG(ERROR) << "new client failed. err:" << error_code.ToString();
+ _Exit(EXIT_FAILURE);
+ }
+}
+
+TeraTpccDb::~TeraTpccDb() {
+ delete client_;
+}
+
+bool TeraTpccDb::CreateTables() {
+ ErrorCode err;
+ for (auto table : kTpccTables) {
+ std::string schema_file = FLAGS_tera_table_schema_dir + table;
+ TableDescriptor* desc = new TableDescriptor();
+ if (ParseTableSchemaFile(schema_file, desc, &err)) {
+ if (client_->CreateTable(*desc, &err) && err.GetType() == ErrorCode::kOK) {
+ LOG(INFO) << "create table " << table << " ok";
+ Table* table_ptr = client_->OpenTable(table, &err);
+ if (table_ptr == NULL) {
+ LOG(ERROR) << "open table " << table << " failed";
+ delete desc;
+ return false;
+ } else {
+ table_map_[table] = table_ptr;
+ LOG(INFO) << "open table " << table << " ok";
+ }
+ } else {
+ LOG(ERROR) << "create table " << table << " failed";
+ delete desc;
+ return false;
+ }
+ } else {
+ LOG(ERROR) << "load schema failed, schema_file:" << schema_file << "err:" << err.ToString();
+ delete desc;
+ return false;
+ }
+ delete desc;
+ }
+ return true;
+}
+
+bool TeraTpccDb::CleanTables() {
+ ErrorCode err;
+ for (auto table : kTpccTables) {
+ if (!client_->DisableTable(table, &err)) {
+ LOG(ERROR) << "fail to disable table : " << table << " err: " <(client_);
+ if (!client_impl->ShowTablesInfo(table, &table_meta, &tablet_list, &err)) {
+ LOG(ERROR) << "table not exist: " << table;
+ continue;
+ }
+ uint64_t tablet_num = tablet_list.meta_size();
+ VLOG(11) << tablet_num;
+ int wait_times = 0;
+ while (true) {
+ if (!client_impl->ShowTablesInfo(table, &table_meta, &tablet_list, &err)) {
+ LOG(ERROR) << "table not exist: " << table;
+ break;
+ }
+ uint64_t tablet_cnt = 0;
+ for (int32_t i = 0; i < tablet_list.meta_size(); ++i) {
+ const TabletMeta& tablet = tablet_list.meta(i);
+ if (tablet.status() == kTabletDisable || tablet.status() == kTableOffLine) {
+ tablet_cnt++;
+ }
+ }
+ if (tablet_cnt == tablet_num) {
+ break;
+ }
+ if (wait_times < 20) {
+ sleep(1);
+ } else {
+ LOG(ERROR) << "disable table : " << table << " failed, try " << wait_times << " time(s)";
+ break;
+ }
+ }
+ }
+ if (!client_->DeleteTable(table, &err)) {
+ LOG(ERROR) << "drop table: " << table << " failed. " << err.ToString();
+ } else {
+ LOG(INFO) << "drop table: "<< table << " done.";
+ }
+ }
+ return true;
+}
+
+// init db
+bool TeraTpccDb::InsertItem(const Item& i) {
+ std::string tablename = "t_item";
+ if ( table_map_.find(tablename) == table_map_.end()) {
+ return false;
+ }
+ Table* table = table_map_[tablename];
+ Transaction* gtxn = client_->NewGlobalTransaction();
+ RowMutation* mu = table->NewRowMutation(i.PrimaryKey());
+ mu->Put("cf0", "i_id", std::to_string(i.i_id));
+ mu->Put("cf0", "i_im_id", std::to_string(i.i_im_id));
+ mu->Put("cf0", "i_price", std::to_string(i.i_price));
+ mu->Put("cf0", "i_name", i.i_name);
+ mu->Put("cf0", "i_data", i.i_data);
+ gtxn->ApplyMutation(mu);
+ gtxn->Commit();
+ delete mu;
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ LOG(ERROR) << "insert table:" << tablename << " failed. err:"
+ << gtxn->GetError().ToString();
+ delete gtxn;
+ return false;
+ }
+ delete gtxn;
+ return true;
+}
+
+bool TeraTpccDb::InsertWarehouse(const Warehouse& w) {
+ std::string tablename = "t_warehouse";
+ if ( table_map_.find(tablename) == table_map_.end()) {
+ return false;
+ }
+ Table* table = table_map_[tablename];
+ Transaction* gtxn = client_->NewGlobalTransaction();
+ RowMutation* mu = table->NewRowMutation(w.PrimaryKey());
+ mu->Put("cf0", "w_id", std::to_string(w.w_id));
+ mu->Put("cf0", "w_tax", std::to_string(w.w_tax));
+ mu->Put("cf0", "w_ytd", std::to_string(w.w_ytd));
+ mu->Put("cf0", "w_name", w.w_name);
+ mu->Put("cf0", "w_street_1", w.w_street_1);
+ mu->Put("cf0", "w_street_2", w.w_street_2);
+ mu->Put("cf0", "w_city", w.w_city);
+ mu->Put("cf0", "w_state", w.w_state);
+ mu->Put("cf0", "w_zip", w.w_zip);
+ gtxn->ApplyMutation(mu);
+ gtxn->Commit();
+ delete mu;
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ LOG(ERROR) << "insert table:" << tablename << " failed. err:"
+ << gtxn->GetError().ToString();
+ delete gtxn;
+ return false;
+ }
+ delete gtxn;
+ return true;
+}
+
+bool TeraTpccDb::InsertDistrict(const District& d) {
+ std::string tablename = "t_district";
+ if ( table_map_.find(tablename) == table_map_.end()) {
+ return false;
+ }
+ Table* table = table_map_[tablename];
+ Transaction* gtxn = client_->NewGlobalTransaction();
+ RowMutation* mu = table->NewRowMutation(d.PrimaryKey());
+ mu->Put("cf0", "d_id", std::to_string(d.d_id));
+ mu->Put("cf0", "d_w_id", std::to_string(d.d_w_id));
+ mu->Put("cf0", "d_tax", std::to_string(d.d_tax));
+ mu->Put("cf0", "d_ytd", std::to_string(d.d_ytd));
+ mu->Put("cf0", "d_next_o_id", std::to_string(d.d_next_o_id));
+ mu->Put("cf0", "d_name", d.d_name);
+ mu->Put("cf0", "d_street_1", d.d_street_1);
+ mu->Put("cf0", "d_street_2", d.d_street_2);
+ mu->Put("cf0", "d_city", d.d_city);
+ mu->Put("cf0", "d_state", d.d_state);
+ mu->Put("cf0", "d_zip", d.d_zip);
+ gtxn->ApplyMutation(mu);
+ gtxn->Commit();
+ delete mu;
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ LOG(ERROR) << "insert table:" << tablename << " failed. err:"
+ << gtxn->GetError().ToString();
+ delete gtxn;
+ return false;
+ }
+ delete gtxn;
+ return true;
+}
+
+bool TeraTpccDb::InsertCustomer(const Customer& c) {
+ std::string tablename = "t_customer";
+ std::string c_last_index_name = "t_customer_last_index";
+ if ( table_map_.find(tablename) == table_map_.end()
+ || table_map_.find(c_last_index_name) == table_map_.end()) {
+ return false;
+ }
+ Table* table = table_map_[tablename];
+ Table* t_index = table_map_[tablename];
+ Transaction* gtxn = client_->NewGlobalTransaction();
+ std::string key = std::to_string(c.c_w_id) + "_" + std::to_string(c.c_d_id)
+ + "_" + c.c_last + "_" + std::to_string(c.c_id);
+ RowMutation* index_mu = t_index->NewRowMutation(key);
+ index_mu->Put("cf0", "c_id", std::to_string(c.c_id));
+ index_mu->Put("cf0", "c_d_id", std::to_string(c.c_d_id));
+ index_mu->Put("cf0", "c_w_id", std::to_string(c.c_w_id));
+ index_mu->Put("cf0", "c_last", c.c_last);
+ gtxn->ApplyMutation(index_mu);
+ delete index_mu;
+
+ RowMutation* mu = table->NewRowMutation(c.PrimaryKey());
+ mu->Put("cf0", "c_id", std::to_string(c.c_id));
+ mu->Put("cf0", "c_d_id", std::to_string(c.c_d_id));
+ mu->Put("cf0", "c_w_id", std::to_string(c.c_w_id));
+ mu->Put("cf0", "c_credit_lim", std::to_string(c.c_credit_lim));
+ mu->Put("cf0", "c_discount", std::to_string(c.c_discount));
+ mu->Put("cf0", "c_balance", std::to_string(c.c_balance));
+ mu->Put("cf0", "c_ytd_payment", std::to_string(c.c_ytd_payment));
+ mu->Put("cf0", "c_payment_cnt", std::to_string(c.c_payment_cnt));
+ mu->Put("cf0", "c_delivery_cnt", std::to_string(c.c_delivery_cnt));
+ mu->Put("cf0", "c_first", c.c_first);
+ mu->Put("cf0", "c_middle", c.c_middle);
+ mu->Put("cf0", "c_last", c.c_last);
+ mu->Put("cf0", "c_street_1", c.c_street_1);
+ mu->Put("cf0", "c_street_2", c.c_street_2);
+ mu->Put("cf0", "c_city", c.c_city);
+ mu->Put("cf0", "c_state", c.c_state);
+ mu->Put("cf0", "c_zip", c.c_zip);
+ mu->Put("cf0", "c_phone", c.c_phone);
+ mu->Put("cf0", "c_since", c.c_since);
+ mu->Put("cf0", "c_credit", c.c_credit);
+ mu->Put("cf0", "c_data", c.c_data);
+ gtxn->ApplyMutation(mu);
+ gtxn->Commit();
+ delete mu;
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ LOG(ERROR) << "insert table:" << tablename << " failed. err:"
+ << gtxn->GetError().ToString();
+ delete gtxn;
+ return false;
+ }
+ delete gtxn;
+ return true;
+}
+
+bool TeraTpccDb::InsertHistory(const History& h) {
+ std::string tablename = "t_history";
+ std::string history_index_name = "t_history_index";
+
+ if (table_map_.find(tablename) == table_map_.end() ||
+ table_map_.find(history_index_name) == table_map_.end()) {
+ return false;
+ }
+ Table* table = table_map_[tablename];
+ Table* t_history_index = table_map_[history_index_name];
+ Transaction* gtxn = client_->NewGlobalTransaction();
+
+ RowReader* hindex_reader = t_history_index->NewRowReader("count");
+ RetTuples hindex_ret;
+ int cnt = -1;
+ TxnResult ret;
+ if (hindex_reader->GetError().GetType() != ErrorCode::kNotFound
+ && !GetValues(&ret, gtxn, hindex_reader,
+ {"count"},
+ &hindex_ret,
+ "@insert_history|hindex_reader|count")) {
+ return false;
+ } else if (hindex_reader->GetError().GetType() == ErrorCode::kNotFound) {
+ cnt = 0;
+ } else {
+ cnt = std::stoi(hindex_ret["count"]);
+ }
+
+ RowMutation* hindex_mu = t_history_index->NewRowMutation("count");
+ hindex_mu->Put("cf0", "count", std::to_string(++cnt));
+ gtxn->ApplyMutation(hindex_mu);
+ delete hindex_mu;
+
+ RowMutation* mu = table->NewRowMutation(std::to_string(cnt));
+ mu->Put("cf0", "h_c_id", std::to_string(h.h_c_id));
+ mu->Put("cf0", "h_c_d_id", std::to_string(h.h_c_d_id));
+ mu->Put("cf0", "h_c_w_id", std::to_string(h.h_c_w_id));
+ mu->Put("cf0", "h_d_id", std::to_string(h.h_d_id));
+ mu->Put("cf0", "h_w_id", std::to_string(h.h_w_id));
+ mu->Put("cf0", "h_amount", std::to_string(h.h_amount));
+ mu->Put("cf0", "h_date", h.h_date);
+ mu->Put("cf0", "h_data", h.h_data);
+ gtxn->ApplyMutation(mu);
+ gtxn->Commit();
+ delete mu;
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ LOG(ERROR) << "insert table:" << tablename << " failed. err:"
+ << gtxn->GetError().ToString();
+ delete gtxn;
+ return false;
+ }
+ delete gtxn;
+ return true;
+}
+
+bool TeraTpccDb::InsertStock(const Stock& s) {
+ std::string tablename = "t_stock";
+ if ( table_map_.find(tablename) == table_map_.end()) {
+ return false;
+ }
+ Table* table = table_map_[tablename];
+ Transaction* gtxn = client_->NewGlobalTransaction();
+ RowMutation* mu = table->NewRowMutation(s.PrimaryKey());
+
+ mu->Put("cf0", "s_i_id", std::to_string(s.s_i_id));
+ mu->Put("cf0", "s_w_id", std::to_string(s.s_w_id));
+ mu->Put("cf0", "s_quantity", std::to_string(s.s_quantity));
+ mu->Put("cf0", "s_ytd", std::to_string(s.s_ytd));
+ mu->Put("cf0", "s_order_cnt", std::to_string(s.s_order_cnt));
+ mu->Put("cf0", "s_remote_cnt", std::to_string(s.s_remote_cnt));
+ int i = 0;
+ for (auto dist : s.s_dist) {
+ mu->Put("cf0", "s_dist_" + std::to_string(++i), dist);
+ }
+ mu->Put("cf0", "s_data", s.s_data);
+
+ gtxn->ApplyMutation(mu);
+ gtxn->Commit();
+ delete mu;
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ LOG(ERROR) << "insert table:" << tablename << " failed. err:"
+ << gtxn->GetError().ToString();
+ delete gtxn;
+ return false;
+ }
+ delete gtxn;
+ return true;
+}
+
+bool TeraTpccDb::InsertOrder(const Order& o) {
+ std::string tablename = "t_order";
+ std::string indexname = "t_order_index";
+ if ( table_map_.find(tablename) == table_map_.end() ||
+ table_map_.find(indexname) == table_map_.end()) {
+ return false;
+ }
+ Table* table = table_map_[tablename];
+ Table* index = table_map_[indexname];
+
+ Transaction* gtxn = client_->NewGlobalTransaction();
+ RowMutation* mu = table->NewRowMutation(o.PrimaryKey());
+ std::string index_key = o.ForeignKey() + "_" + std::to_string(o.o_id);
+ RowMutation* index_mu = index->NewRowMutation(index_key);
+ index_mu->Put("cf0", "o_id", std::to_string(o.o_id));
+ index_mu->Put("cf0", "o_c_id", std::to_string(o.o_c_id));
+ index_mu->Put("cf0", "o_d_id", std::to_string(o.o_d_id));
+ index_mu->Put("cf0", "o_w_id", std::to_string(o.o_w_id));
+ mu->Put("cf0", "o_id", std::to_string(o.o_id));
+ mu->Put("cf0", "o_c_id", std::to_string(o.o_c_id));
+ mu->Put("cf0", "o_d_id", std::to_string(o.o_d_id));
+ mu->Put("cf0", "o_w_id", std::to_string(o.o_w_id));
+ mu->Put("cf0", "o_carrier_id", std::to_string(o.o_carrier_id));
+ mu->Put("cf0", "o_ol_cnt", std::to_string(o.o_ol_cnt));
+ mu->Put("cf0", "o_all_local", std::to_string(o.o_all_local));
+ mu->Put("cf0", "o_entry_d", o.o_entry_d);
+ gtxn->ApplyMutation(mu);
+ gtxn->ApplyMutation(index_mu);
+ delete mu;
+ delete index_mu;
+ gtxn->Commit();
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ LOG(ERROR) << "insert table:" << tablename << " failed. err:"
+ << gtxn->GetError().ToString();
+ delete gtxn;
+ return false;
+ }
+ delete gtxn;
+ return true;
+}
+
+bool TeraTpccDb::InsertOrderLine(const OrderLine& ol) {
+ std::string tablename = "t_orderline";
+ if ( table_map_.find(tablename) == table_map_.end()) {
+ return false;
+ }
+ Table* table = table_map_[tablename];
+ Transaction* gtxn = client_->NewGlobalTransaction();
+ RowMutation* mu = table->NewRowMutation(ol.PrimaryKey());
+ mu->Put("cf0", "ol_o_id", std::to_string(ol.ol_o_id));
+ mu->Put("cf0", "ol_d_id", std::to_string(ol.ol_d_id));
+ mu->Put("cf0", "ol_w_id", std::to_string(ol.ol_w_id));
+ mu->Put("cf0", "ol_number", std::to_string(ol.ol_number));
+ mu->Put("cf0", "ol_i_id", std::to_string(ol.ol_i_id));
+ mu->Put("cf0", "ol_supply_w_id", std::to_string(ol.ol_supply_w_id));
+ mu->Put("cf0", "ol_quantity", std::to_string(ol.ol_quantity));
+ mu->Put("cf0", "ol_amount", std::to_string(ol.ol_amount));
+ mu->Put("cf0", "ol_delivery_d", ol.ol_delivery_d);
+ mu->Put("cf0", "ol_dist_info", ol.ol_dist_info);
+ gtxn->ApplyMutation(mu);
+ gtxn->Commit();
+ delete mu;
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ LOG(ERROR) << "insert table:" << tablename << " failed. err:"
+ << gtxn->GetError().ToString();
+ delete gtxn;
+ return false;
+ }
+ delete gtxn;
+ return true;
+}
+
+bool TeraTpccDb::InsertNewOrder(const NewOrder& no) {
+ std::string tablename = "t_neworder";
+ if ( table_map_.find(tablename) == table_map_.end()) {
+ return false;
+ }
+ Table* table = table_map_[tablename];
+ Transaction* gtxn = client_->NewGlobalTransaction();
+ RowMutation* mu = table->NewRowMutation(no.PrimaryKey());
+ mu->Put("cf0", "no_o_id", std::to_string(no.no_o_id));
+ mu->Put("cf0", "no_d_id", std::to_string(no.no_d_id));
+ mu->Put("cf0", "no_w_id", std::to_string(no.no_w_id));
+ gtxn->ApplyMutation(mu);
+ gtxn->Commit();
+ delete mu;
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ LOG(ERROR) << "insert table:" << tablename << " failed. err:"
+ << gtxn->GetError().ToString();
+ delete gtxn;
+ return false;
+ }
+ delete gtxn;
+ return true;
+}
+
+void TeraTpccDb::SetTxnResult(TxnResult* ret, Transaction* gtxn, bool state,
+ const std::string& msg) {
+ ret->SetState(state);
+ if (msg != "") {
+ ret->SetReason(gtxn->GetError().GetReason() + " msg:" + msg);
+ } else {
+ ret->SetReason(gtxn->GetError().GetReason());
+ }
+}
+
+bool TeraTpccDb::GetValues(TxnResult* ret, Transaction* gtxn, RowReader* reader,
+ std::initializer_list qu_names_initlist,
+ RetTuples* ret_tuples,
+ const std::string& if_error_msg) {
+ std::vector qu_names(qu_names_initlist);
+ for (auto& qu_name : qu_names) {
+ reader->AddColumn("cf0", qu_name);
+ }
+ gtxn->Get(reader);
+ if (gtxn->GetError().GetType() != ErrorCode::kOK) {
+ SetTxnResult(ret, gtxn, false, if_error_msg);
+ delete reader;
+ return false;
+ } else {
+ RowReader::TRow row;
+ reader->ToMap(&row);
+ for (auto qu_name : qu_names) {
+ if (row["cf0"].find(qu_name) != row["cf0"].end()) {
+ for (auto k : row["cf0"][qu_name]) {
+ ret_tuples->insert({{qu_name, k.second}});
+ break;
+ }
+ }
+ }
+ delete reader;
+ }
+ return true;
+}
+
+bool TeraTpccDb::GetCustomer(TxnResult* ret, Transaction* gtxn, bool by_last_name,
+ const std::string& last_name, int32_t customer_id,
+ int32_t warehouse_id, int32_t district_id,
+ std::string* customer_key, RetTuples* customer_ret) {
+ // open table
+ Table* t_customer_last_index = table_map_[kTpccTables[kCustomerLastIndex]];
+ Table* t_customer = table_map_[kTpccTables[kCustomerTable]];
+ *customer_key = std::to_string(warehouse_id) + "_" + std::to_string(district_id) + "_";
+
+ if (by_last_name) {
+ ErrorCode error_code;
+ std::string start_key = *customer_key + last_name + "_";
+ ScanDescriptor scan_desc(start_key);
+ scan_desc.SetEnd(start_key + "~");
+ scan_desc.AddColumnFamily("cf0");
+ ResultStream* scanner = t_customer_last_index->Scan(scan_desc, &error_code);
+ std::vector keys;
+ for (scanner->LookUp(start_key); !scanner->Done(); scanner->Next()) {
+ std::string row_key = scanner->RowName();
+ if (row_key.find(start_key) == std::string::npos) {
+ break;
+ }
+
+ RowReader* index_reader = t_customer_last_index->NewRowReader(row_key);
+ RetTuples index_ret;
+ if (!GetValues(ret, gtxn, index_reader,
+ {"c_id"},
+ &index_ret,
+ "@get_customer|index_reader|" + row_key)) {
+ delete scanner;
+ return false;
+ }
+ keys.push_back(index_ret["c_id"]);
+ }
+ delete scanner;
+ size_t pos = keys.size();
+ pos = pos % 2 == 0 ? (pos / 2 - 1) : (pos / 2);
+ *customer_key += keys.at(pos);
+ } else {
+ *customer_key += std::to_string(customer_id);
+ }
+ RowReader* customer_reader = t_customer->NewRowReader(*customer_key);
+ if (!GetValues(ret, gtxn, customer_reader,
+ {"c_id", "c_d_id", "c_w_id", "c_first", "c_middle", "c_last",
+ "c_balance", "c_ytd_payment", "c_payment_cnt", "c_credit",
+ "c_data", "c_street_1", "c_street_2", "c_city", "c_state",
+ "c_zip", "c_phone", "c_since", "c_credit_lim", "c_discount"},
+ customer_ret,
+ "@get_customer|customer_reader" + *customer_key)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/tera_tpccdb.h b/src/benchmark/tpcc/tera_tpccdb.h
new file mode 100644
index 000000000..a300166b0
--- /dev/null
+++ b/src/benchmark/tpcc/tera_tpccdb.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#ifndef TERA_BENCHMARK_TPCC_TERA_TPCCDB_H
+#define TERA_BENCHMARK_TPCC_TERA_TPCCDB_H
+
+#include "tera.h"
+#include "benchmark/tpcc/tpccdb.h"
+
+namespace tera {
+namespace tpcc {
+
+class TpccDb;
+class TxnResult;
+
+class TeraTpccDb : public TpccDb {
+public:
+ TeraTpccDb();
+ virtual ~TeraTpccDb();
+
+ virtual bool CreateTables();
+ virtual bool CleanTables();
+
+ // init db
+ virtual bool InsertItem(const Item& i);
+
+ virtual bool InsertWarehouse(const Warehouse& w);
+
+ virtual bool InsertDistrict(const District& d);
+
+ virtual bool InsertCustomer(const Customer& c);
+
+ virtual bool InsertHistory(const History& h);
+
+ virtual bool InsertStock(const Stock& s);
+
+ virtual bool InsertOrder(const Order& o);
+
+ virtual bool InsertOrderLine(const OrderLine& ol);
+
+ virtual bool InsertNewOrder(const NewOrder& no);
+
+ virtual void StockLevelTxn(int32_t warehouse_id, int32_t district_id,
+ int32_t threshold,
+ StockLevelResult* ret);
+
+ virtual void DeliveryTxn(int32_t warehouse_id,
+ int32_t carrier_id,
+ const std::string& delivery_datetime,
+ DeliveryResult* ret);
+
+ virtual void OrderStatusTxn(bool by_last_name,
+ int32_t warehouse_id, int32_t district_id,
+ int32_t c_customer_id,
+ const std::string& last_name,
+ OrderStatusResult* ret);
+
+ virtual void PaymentTxn(bool by_last_name,
+ int32_t warehouse_id, int32_t district_id,
+ int32_t c_warehouse_id, int32_t c_district_id,
+ int32_t c_customer_id,
+ const std::string& last_name,
+ int32_t h_amount,
+ PaymentResult* ret);
+
+ virtual void NewOrderTxn(int32_t warehouse_id,
+ int32_t district_id,
+ int32_t customer_id, const NewOrderInfo& info,
+ NewOrderResult* ret);
+
+private:
+ void SetTxnResult(TxnResult* ret, Transaction* gtxn, bool state = true,
+ const std::string& msg = "");
+
+ bool GetValues(TxnResult* ret, Transaction* gtxn, RowReader* reader,
+ std::initializer_list qu_names_initlist,
+ RetTuples* ret_tuples,
+ const std::string& if_error_msg);
+
+ bool GetCustomer(TxnResult* ret, Transaction* gtxn, bool by_last_name,
+ const std::string& last_name, int32_t customer_id,
+ int32_t warehouse_id, int32_t district_id,
+ std::string* customer_key, RetTuples* customer_ret);
+private:
+ void SetPaymentSingleLineRet(const RetTuples& warehouse_ret,
+ const RetTuples& district_ret,
+ const RetTuples& customer_ret,
+ const RetTuples& other_ret,
+ RetTuples* payment_ret);
+private:
+ Client* client_;
+ std::unordered_map table_map_;
+};
+
+} // namespace tpcc
+} // namespace tera
+
+#endif /* TERA_BENCHMARK_TPCC_TERA_TPCCDB_H */
diff --git a/src/benchmark/tpcc/tera_txn/delivery_txn.cc b/src/benchmark/tpcc/tera_txn/delivery_txn.cc
new file mode 100644
index 000000000..d1a7a3e18
--- /dev/null
+++ b/src/benchmark/tpcc/tera_txn/delivery_txn.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/tera_tpccdb.h"
+
+#include
+#include
+
+#include "sdk/client_impl.h"
+#include "sdk/sdk_utils.h"
+
+namespace tera {
+namespace tpcc {
+
+void TeraTpccDb::DeliveryTxn(int32_t warehouse_id,
+ int32_t carrier_id,
+ const std::string& delivery_datetime,
+ DeliveryResult* ret) {
+ // open table
+ Table* t_neworder = table_map_[kTpccTables[kNewOrderTable]];
+ Table* t_order = table_map_[kTpccTables[kOrderTable]];
+ Table* t_orderline = table_map_[kTpccTables[kOrderLineTable]];
+ Table* t_customer = table_map_[kTpccTables[kCustomerTable]];
+ // begin transaction
+ Transaction* gtxn = client_->NewGlobalTransaction();
+ for (int32_t district_id = 1; district_id <= kDistrictCountPerWarehouse; ++district_id) {
+ // The row in the NEW-ORDER table with matching NO_W_ID (equals W_ID)
+ // and NO_D_ID (equals D_ID) and with the lowest NO_O_ID value is selected.
+ ErrorCode error_code;
+ std::string start_key = std::to_string(warehouse_id) + "_" + std::to_string(district_id) + "_";
+ ScanDescriptor scan_desc(start_key);
+ scan_desc.SetEnd(start_key + "~");
+ scan_desc.AddColumnFamily("cf0");
+ tera::ResultStream* scanner = t_neworder->Scan(scan_desc, &error_code);
+ bool not_new_order = false;
+ int32_t order_id = INT32_MAX;
+ for (scanner->LookUp(start_key); !scanner->Done(); scanner->Next()) {
+ std::string row_key = scanner->RowName();
+ if (row_key.find(start_key) == std::string::npos) {
+ not_new_order = true;
+ break;
+ }
+ std::size_t found = row_key.find_last_of("_");
+ int32_t found_order_id = std::stoi(row_key.substr(found + 1));
+ if (order_id > found_order_id) {
+ order_id = found_order_id;
+ }
+ }
+ delete scanner;
+ // If no matching row is found, then the delivery of an order
+ // for this district is skipped.
+ if (not_new_order || order_id == INT32_MAX) {
+ continue;
+ }
+
+ // The selected row in the NEW-ORDER table is deleted
+ std::string no_primary_key = start_key + std::to_string(order_id);
+ RowReader* no_reader = t_neworder->NewRowReader(no_primary_key);
+ RetTuples no_ret;
+ if (!GetValues(ret, gtxn, no_reader,
+ {"no_o_id"},
+ &no_ret,
+ "@delivery|no_reader|" + no_primary_key)) {
+ return;
+ }
+
+ RowMutation* no_mu = t_neworder->NewRowMutation(no_primary_key);
+ no_mu->DeleteColumns("cf0", "no_o_id", gtxn->GetStartTimestamp());
+ no_mu->DeleteColumns("cf0", "no_d_id", gtxn->GetStartTimestamp());
+ no_mu->DeleteColumns("cf0", "no_w_id", gtxn->GetStartTimestamp());
+ gtxn->ApplyMutation(no_mu);
+ delete no_mu;
+
+ // The row in the ORDER table with matching
+ // O_W_ID (equals W_ID), O_D_ID (equals D_ID), and O_ID (equals NO_O_ID)
+ // is selected, O_C_ID, the customer number, is retrieved,
+ // and O_CARRIER_ID is updated.
+ std::string order_primary_key = no_primary_key;
+ RowReader* order_reader = t_order->NewRowReader(order_primary_key);
+ RetTuples order_ret;
+ if (!GetValues(ret, gtxn, order_reader,
+ {"o_carrier_id", "o_ol_cnt", "o_c_id"},
+ &order_ret,
+ "@delivery|order_reader|" + order_primary_key)) {
+ return;
+ }
+ RowMutation* order_mu = t_order->NewRowMutation(order_primary_key);
+ order_mu->Put("cf0", "o_carrier_id", std::to_string(carrier_id));
+ gtxn->ApplyMutation(order_mu);
+ delete order_mu;
+
+ int32_t o_ol_cnt = std::stoi(order_ret["o_ol_cnt"]);
+ // the sum of all OL_AMOUNT.
+ float amount = 0.0f;
+ // All rows in the ORDER-LINE table with matching
+ // OL_W_ID (= O_W_ID), OL_D_ID (= O_D_ID), and OL_O_ID (= O_ID) are selected.
+ for (int32_t ol_number = 1; ol_number <= o_ol_cnt; ++ ol_number) {
+ std::string ol_key = order_primary_key + "_" + std::to_string(ol_number);
+ RowReader* ol_reader = t_orderline->NewRowReader(ol_key);
+ RetTuples ol_ret;
+ if (!GetValues(ret, gtxn, ol_reader,
+ {"ol_amount", "ol_delivery_d"},
+ &ol_ret,
+ "@delivery|ol_reader|" + ol_key)) {
+ return;
+ }
+ amount += std::stof(ol_ret["ol_amount"]);
+ RowMutation* ol_mu = t_orderline->NewRowMutation(ol_key);
+ // All OL_DELIVERY_D, the delivery dates,
+ // are updated to the current system time as returned by the OS
+ ol_mu->Put("cf0","ol_delivery_d",delivery_datetime);
+ gtxn->ApplyMutation(ol_mu);
+ delete ol_mu;
+ }
+
+ // The row in the CUSTOMER table with matching
+ // C_W_ID (= W_ID), C_D_ID (= D_ID), and C_ID (= O_C_ID) is selected
+ std::string customer_key = start_key + order_ret["o_c_id"];
+ RowReader* customer_reader = t_customer->NewRowReader(customer_key);
+ RetTuples customer_ret;
+ if (!GetValues(ret, gtxn, customer_reader,
+ {"c_balance", "c_delivery_cnt"},
+ &customer_ret,
+ "@delivery|customer_reader" + customer_key)) {
+ return;
+ }
+ // and C_BALANCE + sum(OL_AMOUNT) previously retrieved. C_DELIVERY_CNT + 1.
+ RowMutation* customer_mu = t_customer->NewRowMutation(customer_key);
+ customer_mu->Put("cf0", "c_balance",
+ std::to_string(std::stof(customer_ret["c_balance"]) + amount));
+ customer_mu->Put("cf0", "c_delivery_cnt",
+ std::to_string(std::stoi(customer_ret["c_delivery_cnt"]) + 1));
+ gtxn->ApplyMutation(customer_mu);
+ delete customer_mu;
+ }
+ gtxn->Commit();
+ SetTxnResult(ret, gtxn, gtxn->GetError().GetType() == ErrorCode::kOK);
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/tera_txn/new_order_txn.cc b/src/benchmark/tpcc/tera_txn/new_order_txn.cc
new file mode 100644
index 000000000..df4100824
--- /dev/null
+++ b/src/benchmark/tpcc/tera_txn/new_order_txn.cc
@@ -0,0 +1,214 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/tera_tpccdb.h"
+
+#include
+#include
+
+#include "sdk/client_impl.h"
+#include "sdk/sdk_utils.h"
+
+namespace tera {
+namespace tpcc {
+
+void TeraTpccDb::NewOrderTxn(int32_t warehouse_id,
+ int32_t district_id,
+ int32_t customer_id, const NewOrderInfo& info,
+ NewOrderResult* ret) {
+ // open table
+ Table* t_warehouse = table_map_[kTpccTables[kWarehouseTable]];
+ Table* t_district = table_map_[kTpccTables[kDistrictTable]];
+ Table* t_customer = table_map_[kTpccTables[kCustomerTable]];
+ Table* t_order = table_map_[kTpccTables[kOrderTable]];
+ Table* t_order_index = table_map_[kTpccTables[kOrderIndex]];
+ Table* t_neworder = table_map_[kTpccTables[kNewOrderTable]];
+ Table* t_orderline = table_map_[kTpccTables[kOrderLineTable]];
+ Table* t_item = table_map_[kTpccTables[kItemTable]];
+ Table* t_stock = table_map_[kTpccTables[kStockTable]];
+ // begin transaction
+ std::unique_ptr gtxn(client_->NewGlobalTransaction());
+ std::string datetime = get_curtime_str();
+ std::string warehouse_key = std::to_string(warehouse_id);
+ std::string district_key = warehouse_key + "_" + std::to_string(district_id);
+ std::string customer_key = district_key + "_" + std::to_string(customer_id);
+
+ RowReader* warehouse_reader = t_warehouse->NewRowReader(warehouse_key);
+ RetTuples warehouse_ret;
+ if (!GetValues(ret, gtxn.get(), warehouse_reader,
+ {"w_tax"},
+ &warehouse_ret,
+ "@new_order|warehouse_reader|" + warehouse_key)) {
+ return;
+ }
+
+ RowReader* district_reader = t_district->NewRowReader(district_key);
+ RetTuples district_ret;
+ if (!GetValues(ret, gtxn.get(), district_reader,
+ {"d_next_o_id", "d_tax"},
+ &district_ret,
+ "@new_order|district_reader|" + district_key)) {
+ return;
+ }
+ std::string d_next_o_id_str = std::to_string(std::stoi(district_ret["d_next_o_id"]) + 1);
+
+ RowReader* customer_reader = t_customer->NewRowReader(customer_key);
+ RetTuples customer_ret;
+ if (!GetValues(ret, gtxn.get(), customer_reader,
+ {"c_discount", "c_credit", "c_last"},
+ &customer_ret,
+ "@new_order|customer_reader|" + customer_key)) {
+ return;
+ }
+
+ RowMutation* district_mu = t_district->NewRowMutation(district_key);
+ district_mu->Put("cf0", "d_next_o_id", d_next_o_id_str);
+ gtxn->ApplyMutation(district_mu);
+ delete district_mu;
+
+ std::string order_key = district_key + "_" + d_next_o_id_str;
+ RowMutation* order_mu = t_order->NewRowMutation(order_key);
+ std::string order_index_key = customer_key + "_" + d_next_o_id_str;
+ RowMutation* order_index_mu = t_order_index->NewRowMutation(order_index_key);
+ order_index_mu->Put("cf0", "o_id", d_next_o_id_str);
+ order_index_mu->Put("cf0", "o_c_id", std::to_string(customer_id));
+ order_index_mu->Put("cf0", "o_d_id", std::to_string(district_id));
+ order_index_mu->Put("cf0", "o_w_id", warehouse_key);
+ order_mu->Put("cf0", "o_id", d_next_o_id_str);
+ order_mu->Put("cf0", "o_c_id", std::to_string(customer_id));
+ order_mu->Put("cf0", "o_d_id", std::to_string(district_id));
+ order_mu->Put("cf0", "o_w_id", warehouse_key);
+ order_mu->Put("cf0", "o_carrier_id", std::to_string(0));
+ order_mu->Put("cf0", "o_ol_cnt", std::to_string(info.o_ol_cnt));
+ order_mu->Put("cf0", "o_all_local", std::to_string(info.o_all_local));
+ order_mu->Put("cf0", "o_entry_d", datetime);
+ gtxn->ApplyMutation(order_mu);
+ gtxn->ApplyMutation(order_index_mu);
+ delete order_mu;
+ delete order_index_mu;
+
+ RowMutation* no_mu = t_neworder->NewRowMutation(order_key);
+ no_mu->Put("cf0", "no_o_id", d_next_o_id_str);
+ no_mu->Put("cf0", "no_d_id", std::to_string(district_id));
+ no_mu->Put("cf0", "no_w_id", warehouse_key);
+ gtxn->ApplyMutation(no_mu);
+ delete no_mu;
+
+ std::string ol_dist_info_key;
+ if (district_id == kDistrictCountPerWarehouse) {
+ ol_dist_info_key = "s_dist_10";
+ } else {
+ ol_dist_info_key = "s_dist_0" + std::to_string(district_id);
+ }
+
+ float ol_amount_sum = 0;
+ for (int32_t i = 0; i < info.o_ol_cnt; ++i) {
+ int32_t i_id = info.ol_i_ids[i];
+ std::string item_key = std::to_string(i_id);
+ RowReader* item_reader = t_item->NewRowReader(item_key);
+ RetTuples item_ret;
+ if (!GetValues(ret, gtxn.get(), item_reader,
+ {"i_price", "i_name", "i_data"},
+ &item_ret,
+ "@new_order|item_reader|" + item_key)) {
+ return;
+ }
+
+ std::string ol_supply_w_id_str = std::to_string(info.ol_supply_w_ids[i]);
+ std::string stock_key = ol_supply_w_id_str+ "_" + item_key;
+ RowReader* stock_reader = t_item->NewRowReader(stock_key);
+ RetTuples stock_ret;
+ if (!GetValues(ret, gtxn.get(), stock_reader,
+ {"s_quantity", "s_ytd", "s_order_cnt", "s_remote_cnt", "s_data", ol_dist_info_key},
+ &stock_ret,
+ "@new_order|stock_reader|" + stock_key)) {
+ return;
+ }
+
+ int32_t ol_quantity = info.ol_quantities[i];
+ float ol_amount = std::stof(item_ret["i_price"]) * ol_quantity;
+ ol_amount_sum += ol_amount;
+ std::string ol_number_str = std::to_string(i + 1);
+ std::string ol_key = order_key + "_" + ol_number_str;
+ RowMutation* ol_mu = t_orderline->NewRowMutation(ol_key);
+ ol_mu->Put("cf0", "ol_o_id", d_next_o_id_str);
+ ol_mu->Put("cf0", "ol_d_id", std::to_string(district_id));
+ ol_mu->Put("cf0", "ol_w_id", warehouse_key);
+ ol_mu->Put("cf0", "ol_number", ol_number_str);
+ ol_mu->Put("cf0", "ol_i_id", item_key);
+ ol_mu->Put("cf0", "ol_supply_w_id", ol_supply_w_id_str);
+ ol_mu->Put("cf0", "ol_delivery_d", "");
+ ol_mu->Put("cf0", "ol_quantity", std::to_string(ol_quantity));
+ ol_mu->Put("cf0", "ol_amount", std::to_string(ol_amount));
+ ol_mu->Put("cf0", "ol_dist_info", stock_ret[ol_dist_info_key]);
+ gtxn->ApplyMutation(ol_mu);
+ delete ol_mu;
+ // update stock
+ int32_t s_quantity = std::stoi(stock_ret["s_quantity"]);
+ if (s_quantity > ol_quantity + 10) {
+ s_quantity -= ol_quantity;
+ } else {
+ s_quantity = (s_quantity - ol_quantity) + 91;
+ }
+ float s_ytd = std::stof(stock_ret["s_quantity"]) + ol_quantity;
+ int32_t s_order_cnt = std::stoi(stock_ret["s_order_cnt"]) + 1;
+ int32_t s_remote_cnt = std::stoi(stock_ret["s_remote_cnt"]);
+ if (info.ol_supply_w_ids[i] != warehouse_id) {
+ ++s_remote_cnt;
+ }
+ RowMutation* stock_mu = t_stock->NewRowMutation(stock_key);
+ stock_mu->Put("cf0", "s_quantity", std::to_string(s_quantity));
+ stock_mu->Put("cf0", "s_ytd", std::to_string(s_ytd));
+ stock_mu->Put("cf0", "s_order_cnt", std::to_string(s_order_cnt));
+ stock_mu->Put("cf0", "s_remote_cnt", std::to_string(s_remote_cnt));
+ gtxn->ApplyMutation(stock_mu);
+ delete stock_mu;
+
+ // set result
+ RetTuples line;
+ line["ol_supply_w_id"] = ol_supply_w_id_str;
+ line["ol_i_id"] = item_key;
+ line["i_name"] = item_ret["i_name"];
+ line["ol_quantity"] = std::to_string(ol_quantity);
+ line["s_quantity"] = std::to_string(s_quantity);
+ line["i_price"] = item_ret["i_price"];
+ line["ol_amount"] = std::to_string(ol_amount);
+ std::string i_data = item_ret["i_data"];
+ std::string s_data = item_ret["s_data"];
+ if (i_data.find("ORIGINAL") != std::string::npos &&
+ s_data.find("ORIGINAL") != std::string::npos) {
+ line["brand_generic"] = "B";
+ } else {
+ line["brand_generic"] = "G";
+ }
+ ret->AddLine(line);
+ }
+ if (!info.need_failed) {
+ RetTuples single_line;
+ single_line["o_id"] = d_next_o_id_str;
+ single_line["o_ol_cnt"] = std::to_string(info.o_ol_cnt);
+ single_line["c_last"] = customer_ret["c_last"];
+ single_line["c_credit"] = customer_ret["c_credit"];
+ single_line["c_discount"] = customer_ret["c_discount"];
+ single_line["w_tax"] = warehouse_ret["w_tax"];
+ single_line["d_tax"] = district_ret["d_tax"];
+ single_line["o_entry_d"] = datetime;
+ float c_discount = std::stof(customer_ret["c_discount"]);
+ float w_tax = std::stof(warehouse_ret["w_tax"]);
+ float d_tax = std::stof(district_ret["d_tax"]);
+ float total_amount = ol_amount_sum * ( 1 - c_discount) * (1 + w_tax + d_tax);
+ single_line["total_amount"] = std::to_string(total_amount);
+ ret->SetSingleLine(single_line);
+ gtxn->Commit();
+ SetTxnResult(ret, gtxn.get());
+ } else {
+ // set commit failed
+ SetTxnResult(ret, gtxn.get(), false, "@new_order|rowback simulation");
+ }
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/tera_txn/order_status_txn.cc b/src/benchmark/tpcc/tera_txn/order_status_txn.cc
new file mode 100644
index 000000000..a88fe7e0c
--- /dev/null
+++ b/src/benchmark/tpcc/tera_txn/order_status_txn.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/tera_tpccdb.h"
+
+#include
+#include
+
+#include "sdk/client_impl.h"
+#include "sdk/sdk_utils.h"
+
+namespace tera {
+namespace tpcc {
+
+void TeraTpccDb::OrderStatusTxn(bool by_last_name,
+ int32_t warehouse_id, int32_t district_id,
+ int32_t c_customer_id,
+ const std::string& last_name,
+ OrderStatusResult* ret) {
+ // open table
+ Table* t_order_index = table_map_[kTpccTables[kOrderIndex]];
+ Table* t_orderline = table_map_[kTpccTables[kOrderLineTable]];
+ Table* t_order = table_map_[kTpccTables[kOrderTable]];
+ // begin transaction
+ std::unique_ptr gtxn(client_->NewGlobalTransaction());
+ std::string customer_key = "";
+ RetTuples customer_ret;
+ if (!GetCustomer(ret, gtxn.get(), by_last_name, last_name, c_customer_id,
+ warehouse_id, district_id, &customer_key, &customer_ret)) {
+ return;
+ }
+
+ // find newest order from order index
+ ErrorCode error_code;
+ std::string prefix_key = std::to_string(warehouse_id) + "_"
+ + std::to_string(district_id) + "_";
+ std::string start_key = prefix_key + customer_ret["c_id"] + "_";
+ ScanDescriptor scan_desc(start_key);
+ scan_desc.SetEnd(start_key + "~");
+ scan_desc.AddColumnFamily("cf0");
+ ResultStream* scanner = t_order_index->Scan(scan_desc, &error_code);
+ int32_t max_order_id = -1;
+ for (scanner->LookUp(start_key); !scanner->Done(); scanner->Next()) {
+ std::string row_key = scanner->RowName();
+ RowReader* index_reader = t_order_index->NewRowReader(row_key);
+ RetTuples index_ret;
+ if (!GetValues(ret, gtxn.get(), index_reader,
+ {"o_id"},
+ &index_ret,
+ "@order_status|order_index_reader|" + row_key)) {
+ break;
+ }
+ if ( max_order_id < std::stoi(index_ret["o_id"])) {
+ max_order_id = std::stoi(index_ret["o_id"]);
+ }
+ }
+ delete scanner;
+ if (max_order_id == -1) {
+ SetTxnResult(ret, gtxn.get(), false, "not found order|" + start_key);
+ return;
+ }
+ std::string order_key = prefix_key + std::to_string(max_order_id);
+ RowReader* order_reader = t_order->NewRowReader(order_key);
+ RetTuples order_ret;
+ if (!GetValues(ret, gtxn.get(), order_reader,
+ {"o_ol_cnt", "o_id"},
+ &order_ret,
+ "@order_status|order_reader|" + order_key)) {
+ return;
+ }
+ for (int32_t i = 1; i <= std::stoi(order_ret["o_ol_cnt"]); ++i) {
+ std::string ol_key = prefix_key + order_ret["o_id"] + "_" + std::to_string(i);
+ RowReader* ol_reader = t_orderline->NewRowReader(ol_key);
+ RetTuples ol_ret;
+ if (!GetValues(ret, gtxn.get(), ol_reader,
+ {}, // TODO
+ &ol_ret,
+ "@order_status|ol_reader|" + ol_key)) {
+ return;
+ }
+ }
+ SetTxnResult(ret, gtxn.get());
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/tera_txn/payment_txn.cc b/src/benchmark/tpcc/tera_txn/payment_txn.cc
new file mode 100644
index 000000000..c45d371bd
--- /dev/null
+++ b/src/benchmark/tpcc/tera_txn/payment_txn.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/tera_tpccdb.h"
+
+#include
+#include
+
+#include "sdk/client_impl.h"
+#include "sdk/sdk_utils.h"
+
+namespace tera {
+namespace tpcc {
+
+void TeraTpccDb::PaymentTxn(bool by_last_name,
+ int32_t warehouse_id, int32_t district_id,
+ int32_t customer_warehouse_id, int32_t customer_district_id,
+ int32_t c_customer_id,
+ const std::string& last_name,
+ int32_t h_amount,
+ PaymentResult* ret) {
+ // open table
+ Table* t_warehouse = table_map_[kTpccTables[kWarehouseTable]];
+ Table* t_district = table_map_[kTpccTables[kDistrictTable]];
+ Table* t_customer = table_map_[kTpccTables[kCustomerTable]];
+ Table* t_history = table_map_[kTpccTables[kHistoryTable]];
+ Table* t_history_index = table_map_[kTpccTables[kHistoryIndex]];
+
+ // begin transaction
+ Transaction* gtxn = client_->NewGlobalTransaction();
+
+ // read customer
+ std::string customer_key = "";
+ RetTuples customer_ret;
+ if (!GetCustomer(ret, gtxn, by_last_name, last_name, c_customer_id,
+ customer_warehouse_id, customer_district_id, &customer_key, &customer_ret)) {
+ return;
+ }
+
+ // read warehouse
+ std::string warehouse_key = std::to_string(warehouse_id);
+ RowReader* warehouse_reader = t_warehouse->NewRowReader(warehouse_key);
+ RetTuples warehouse_ret;
+ if (!GetValues(ret, gtxn, warehouse_reader,
+ {"w_ytd", "w_name", "w_street_1", "w_street_2", "w_city", "w_state", "w_zip"},
+ &warehouse_ret,
+ "@payment|warehouse_reader|" + warehouse_key)) {
+ return;
+ }
+
+ // update warehouse
+ RowMutation* warehouse_mu = t_warehouse->NewRowMutation(warehouse_key);
+ // add amount of this payment to the ytd balance of current warehouse.
+ float w_ytd = std::stof(warehouse_ret["w_ytd"]) + h_amount;
+ warehouse_mu->Put("cf0", "w_ytd", std::to_string(w_ytd));
+ gtxn->ApplyMutation(warehouse_mu);
+ delete warehouse_mu;
+
+ // read district
+ std::string district_id_str = std::to_string(district_id);
+ std::string district_key = warehouse_key + "_" + district_id_str;
+ RowReader* district_reader = t_district->NewRowReader(district_key);
+ RetTuples district_ret;
+ if (!GetValues(ret, gtxn, district_reader,
+ {"d_ytd", "d_name", "d_street_1", "d_street_2", "d_city", "d_state", "d_zip"},
+ &district_ret,
+ "@payment|district_reader|" + district_key)) {
+ return;
+ }
+
+ // update district
+ RowMutation* district_mu = t_district->NewRowMutation(district_key);
+ // add amount of this payment to the ytd balance of current district.
+ float d_ytd = std::stof(district_ret["d_ytd"]) + h_amount;
+ district_mu->Put("cf0", "d_ytd", std::to_string(d_ytd));
+ gtxn->ApplyMutation(district_mu);
+ delete district_mu;
+
+ // update customer
+ // [Revision 5.11 - Page 34] see Clause 2.5.2.2
+ // C_BALANCE is decreased by H_AMOUNT.
+ // C_YTD_PAYMENT is increased by H_AMOUNT.
+ // C_PAYMENT_CNT is incremented by 1.
+ RowMutation* customer_mu = t_customer->NewRowMutation(customer_key);
+ std::string c_balance_str = std::to_string(std::stof(customer_ret["c_balance"]) - h_amount);
+ customer_mu->Put("cf0", "c_balance", c_balance_str);
+ customer_mu->Put("cf0", "c_ytd_payment",
+ std::to_string(std::stof(customer_ret["c_ytd_payment"]) + h_amount));
+ customer_mu->Put("cf0", "c_payment_cnt",
+ std::to_string(std::stof(customer_ret["c_payment_cnt"]) + h_amount));
+
+ if (customer_ret["c_credit"] == "BC") {
+ std::string data_info = customer_key + "_" + district_key + "_" + std::to_string(h_amount);
+ customer_ret["c_data"].insert(0, data_info);
+ if (customer_ret["c_data"].size() > kCustomerDataUpperLen) {
+ customer_ret["c_data"].substr(0, kCustomerDataUpperLen);
+ }
+ customer_mu->Put("cf0", "c_data", customer_ret["c_data"]);
+ }
+ gtxn->ApplyMutation(customer_mu);
+ delete customer_mu;
+
+ // read history_index (find newest history)
+ std::string history_data = warehouse_ret["w_name"] + " " + district_ret["d_name"];
+ RowReader* hindex_reader = t_history_index->NewRowReader("count");
+ RetTuples hindex_ret;
+ if (!GetValues(ret, gtxn, hindex_reader,
+ {"count"},
+ &hindex_ret,
+ "@payment|hindex_reader|count")) {
+ return;
+ }
+ int cnt = std::stoi(hindex_ret["count"]);
+
+ // update history_index
+ RowMutation* hindex_mu = t_history_index->NewRowMutation("count");
+ hindex_mu->Put("cf0", "count", std::to_string(++cnt));
+ gtxn->ApplyMutation(hindex_mu);
+ delete hindex_mu;
+
+ // update history use now newest count as the primary key(row_key) of history
+ // default t_history don't have priamry key in tpcc
+ std::string history_key = std::to_string(cnt);
+ RowMutation* mu = t_history->NewRowMutation(history_key);
+ mu->Put("cf0", "h_c_id", customer_ret["c_id"]);
+ mu->Put("cf0", "h_c_d_id", customer_ret["c_d_id"]);
+ mu->Put("cf0", "h_c_w_id", customer_ret["c_w_id"]);
+ mu->Put("cf0", "h_d_id", district_id_str);
+ mu->Put("cf0", "h_w_id", warehouse_key);
+ mu->Put("cf0", "h_amount", std::to_string(h_amount));
+ // The payment date (H_DATE) in generated within the SUT
+ // by using the current system date and time
+ std::string datetime = get_curtime_str();
+ mu->Put("cf0", "h_date", datetime);
+ mu->Put("cf0", "h_data", history_data);
+ gtxn->ApplyMutation(mu);
+ delete mu;
+
+ gtxn->Commit();
+ RetTuples single_line;
+ RetTuples other_ret = {
+ {"w_id", warehouse_key},
+ {"d_id", district_id_str},
+ {"h_amount", std::to_string(h_amount)},
+ {"h_date", datetime},
+ {"c_balance", c_balance_str},
+ {"c_data", customer_ret["c_data"].substr(0,200)}
+ };
+ SetPaymentSingleLineRet(warehouse_ret, district_ret, customer_ret, other_ret,
+ &single_line);
+
+ SetTxnResult(ret, gtxn);
+}
+
+void TeraTpccDb::SetPaymentSingleLineRet(const RetTuples& warehouse_ret,
+ const RetTuples& district_ret,
+ const RetTuples& customer_ret,
+ const RetTuples& other_ret,
+ RetTuples* payment_ret) {
+ // The following fields are displayed:
+ // W_ID, D_ID, C_ID, C_D_ID, C_W_ID,
+ // W_STREET_1, W_STREET_2, W_CITY, W_STATE, W_ZIP,
+ // D_STREET_1, D_STREET_2, D_CITY, D_STATE, D_ZIP,
+ // C_FIRST, C_MIDDLE, C_LAST, C_STREET_1, C_STREET_2, C_CITY, C_STATE,
+ // C_ZIP, C_PHONE, C_SINCE, C_CREDIT, C_CREDIT_LIM, C_DISCOUNT, C_BALANCE,
+ // the first 200 characters of C_DATA (only if C_CREDIT = "BC"),
+ // H_AMOUNT, and H_DATE.
+ payment_ret->insert(other_ret.begin(), other_ret.end());
+ for (auto t : warehouse_ret) {
+ if (t.first != "w_ytd" && t.first != "w_name") {
+ payment_ret->insert(t);
+ }
+ }
+ for (auto t : district_ret) {
+ if (t.first != "d_ytd" && t.first != "w_name") {
+ payment_ret->insert(t);
+ }
+ }
+ std::unordered_set c_names = {"c_id", "c_d_id", "c_w_id",
+ "c_first", "c_middle", "c_last", "c_street_1", "c_street_2", "c_city",
+ "c_state", "c_zip", "c_phone", "c_since", "c_credit", "c_credit_lim",
+ "c_discount"};
+ for (auto t : customer_ret) {
+ if (c_names.find(t.first) != c_names.end()) {
+ payment_ret->insert(t);
+ }
+ }
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/tera_txn/stocklevel_txn.cc b/src/benchmark/tpcc/tera_txn/stocklevel_txn.cc
new file mode 100644
index 000000000..eeb7bb06d
--- /dev/null
+++ b/src/benchmark/tpcc/tera_txn/stocklevel_txn.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/tera_tpccdb.h"
+
+#include
+#include
+
+#include "sdk/client_impl.h"
+#include "sdk/sdk_utils.h"
+
+namespace tera {
+namespace tpcc {
+
+void TeraTpccDb::StockLevelTxn(int32_t warehouse_id, int32_t district_id,
+ int32_t threshold,
+ StockLevelResult* ret) {
+ // open table
+ Table* t_district = table_map_[kTpccTables[kDistrictTable]];
+ Table* t_order = table_map_[kTpccTables[kOrderTable]];
+ Table* t_orderline = table_map_[kTpccTables[kOrderLineTable]];
+ Table* t_stock = table_map_[kTpccTables[kStockTable]];
+ // begin transaction
+ std::unique_ptr gtxn(client_->NewGlobalTransaction());
+ std::string district_primary_key = std::to_string(warehouse_id)
+ + "_" + std::to_string(district_id);
+ RowReader* district_reader = t_district->NewRowReader(district_primary_key);
+ RetTuples district_ret;
+ if (!GetValues(ret, gtxn.get(), district_reader, {"d_next_o_id"}, &district_ret,
+ "@stock_level|district_reader|" + district_primary_key)) {
+ return;
+ }
+ int32_t order_id = std::stoi(district_ret["d_next_o_id"]);
+
+ int32_t cnt = 0;
+ for (int32_t ol_o_id = order_id - 20; ol_o_id <= order_id; ++ol_o_id) {
+ std::string order_primary_key = std::to_string(warehouse_id)
+ + "_" + std::to_string(district_id) + "_" + std::to_string(ol_o_id);
+ RowReader* order_reader = t_order->NewRowReader(order_primary_key);
+ RetTuples order_ret;
+ if (!GetValues(ret, gtxn.get(), order_reader, {"o_ol_cnt"}, &order_ret,
+ "@stock_level|order_reader|" + order_primary_key)) {
+ return;
+ }
+ int32_t o_ol_cnt = std::stoi(order_ret["o_ol_cnt"]);
+ for (int32_t ol_number = 1; ol_number <= o_ol_cnt; ++ ol_number) {
+ std::string ol_primary_key = order_primary_key + "_" + std::to_string(ol_number);
+ RowReader* ol_reader = t_orderline->NewRowReader(ol_primary_key);
+ RetTuples ol_ret;
+ ol_reader->AddColumn("cf0", "ol_i_id");
+ if (!GetValues(ret, gtxn.get(), ol_reader, {"ol_i_id"}, &ol_ret,
+ "@stock_level|ol_reader|" + ol_primary_key)) {
+ return;
+ }
+ int32_t ol_i_id = std::stoi(ol_ret["ol_i_id"]);
+ std::string stock_key = std::to_string(warehouse_id)
+ + "_" + std::to_string(ol_i_id);
+ RowReader* stock_reader = t_stock->NewRowReader(stock_key);
+ RetTuples stock_ret;
+ if (!GetValues(ret, gtxn.get(), stock_reader, {"s_quantity"}, &stock_ret,
+ "@stock_level|stock_reader|" + stock_key)) {
+ return;
+ }
+ int32_t s_quantity = std::stoi(stock_ret["s_quantity"]);
+ if (s_quantity < threshold) {
+ ++cnt;
+ }
+ }
+ }
+ // only read not need commit
+ ret->SetLowStock(cnt);
+ SetTxnResult(ret, gtxn.get());
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/test/data_generator_test.cc b/src/benchmark/tpcc/test/data_generator_test.cc
new file mode 100644
index 000000000..6c5b71fe7
--- /dev/null
+++ b/src/benchmark/tpcc/test/data_generator_test.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include
+
+#include "benchmark/tpcc/data_generator.h"
+#include "benchmark/tpcc/mock_tpccdb.h"
+#include "benchmark/tpcc/random_generator.h"
+#include "benchmark/tpcc/tpccdb.h"
+
+#include "gflags/gflags.h"
+#include "gtest/gtest.h"
+
+DECLARE_int32(warehouses_count);
+
+namespace tera {
+namespace tpcc {
+
+class DataGeneratorTest : public ::testing::Test {
+public:
+ DataGeneratorTest() {
+ random_gen_.SetRandomConstant();
+ TpccDb* db_ = (TpccDb*)(&mdb_);
+ data_gen_ = new DataGenerator(&random_gen_, db_);
+ }
+
+ void CleanStateCounter(int table_enum_num = -1) {
+ if (table_enum_num == -1) {
+ for (int i = 0; i < kTpccTableCnt; ++i) {
+ data_gen_->states_[i].first.Set(0);
+ data_gen_->states_[i].second.Set(0);
+ }
+ } else if (table_enum_num > -1 && table_enum_num < kTpccTableCnt) {
+ data_gen_->states_[table_enum_num].first.Set(0);
+ data_gen_->states_[table_enum_num].second.Set(0);
+ }
+ }
+
+ ~DataGeneratorTest() {
+ delete data_gen_;
+ }
+private:
+ RandomGenerator random_gen_;
+ TpccDb* db_;
+ MockTpccDb mdb_;
+ DataGenerator* data_gen_;
+
+};
+
+TEST_F(DataGeneratorTest, GenItem) {
+ CleanStateCounter();
+ mdb_.flag_ = true;
+ data_gen_->GenItem(1, false);
+ EXPECT_TRUE(data_gen_->states_[kItemTable].first.Get() == 1);
+ data_gen_->GenItem(1, false);
+ EXPECT_TRUE(data_gen_->states_[kItemTable].first.Get() == 2);
+ mdb_.flag_ = false;
+ data_gen_->GenItem(1, false);
+ EXPECT_TRUE(data_gen_->states_[kItemTable].second.Get() == 1);
+}
+
+TEST_F(DataGeneratorTest, GenStock) {
+ CleanStateCounter();
+ mdb_.flag_ = true;
+ data_gen_->GenStock(1, 2, false);
+ EXPECT_TRUE(data_gen_->states_[kStockTable].first.Get() == 1);
+ data_gen_->GenStock(1, 2, false);
+ EXPECT_TRUE(data_gen_->states_[kStockTable].first.Get() == 2);
+ mdb_.flag_ = false;
+ data_gen_->GenStock(1, 3, false);
+ EXPECT_TRUE(data_gen_->states_[kStockTable].second.Get() == 1);
+}
+
+TEST_F(DataGeneratorTest, GenStocks) {
+ CleanStateCounter();
+ mdb_.flag_ = true;
+ for (int i = 1; i <=FLAGS_warehouses_count; ++i) {
+ data_gen_->GenStocks(i);
+ }
+ data_gen_->Join();
+ EXPECT_TRUE(data_gen_->states_[kStockTable].first.Get() == FLAGS_warehouses_count * kItemCount);
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/test/random_generator_test.cc b/src/benchmark/tpcc/test/random_generator_test.cc
new file mode 100644
index 000000000..978521739
--- /dev/null
+++ b/src/benchmark/tpcc/test/random_generator_test.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "benchmark/tpcc/random_generator.h"
+
+#include "gtest/gtest.h"
+
+namespace tera {
+namespace tpcc {
+
+class RandomGenerator;
+
+class RandomGeneratorTest : public ::testing::Test, public RandomGenerator {
+public:
+ RandomGeneratorTest() : RandomGenerator() {
+ SetRandomConstant();
+ }
+
+ ~RandomGeneratorTest() {}
+};
+
+TEST_F(RandomGeneratorTest, MakeFloat) {
+ EXPECT_EQ(MakeFloat(1.0, 1.0, 1), 1.0);
+ float f = MakeFloat(0, 1.0, 2);
+ std::cout << std::to_string(f) << std::endl;
+ EXPECT_TRUE(f >= 0 && f <= 1);
+}
+
+TEST_F(RandomGeneratorTest, MakeAString) {
+ EXPECT_TRUE(MakeAString(0, 0) == "");
+ EXPECT_TRUE((MakeAString(1, 1)).length() == 1);
+ std::string a_str = MakeAString(1,10);
+ EXPECT_TRUE(a_str.length() <= 10 && a_str.length() >= 1);
+ std::string a_str1 = MakeAString(26,27);
+ int cnt = 0;
+ for (int i = 0; i < a_str1.length(); ++i) {
+ for (int j = i + 1; j < a_str1.length(); ++j) {
+ if (a_str1[i] == a_str1[j]) {
+ ++cnt;
+ }
+ }
+ }
+ EXPECT_TRUE(cnt > 0);
+}
+
+TEST_F(RandomGeneratorTest, MakeNString) {
+ EXPECT_TRUE(MakeNString(0, 0) == "");
+ EXPECT_TRUE((MakeNString(1, 1)).length() == 1);
+ std::string n_str = MakeNString(1,10);
+ EXPECT_TRUE(n_str.length() <= 10 && n_str.length() >= 1);
+}
+
+TEST_F(RandomGeneratorTest, MakeDisOrderList) {
+ std::vector dis_order_list = MakeDisOrderList(10,20);
+ sort(dis_order_list.begin(),dis_order_list.end());
+ for (int i = 10; i <= 20; ++i) {
+ EXPECT_EQ(dis_order_list[i-10], i);
+ }
+}
+
+TEST_F(RandomGeneratorTest, SetRandomConstant) {
+ SetRandomConstant();
+ NURandConstant c = GetRandomConstant();
+ EXPECT_TRUE(c.c_last >= 0 && c.c_last <= 255);
+ EXPECT_TRUE(c.c_last >= 0 && c.c_last <= 1023);
+ EXPECT_TRUE(c.c_last >= 0 && c.c_last <= 8191);
+}
+
+TEST_F(RandomGeneratorTest, GetRandom) {
+ EXPECT_EQ(GetRandom(1, 1) , 1);
+ int rand_num = GetRandom(0, 1);
+ int rand_num1 = GetRandom(1, 0);
+ EXPECT_TRUE(rand_num == 0 || rand_num == 1);
+ EXPECT_TRUE(rand_num == 0 || rand_num == 1);
+}
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/test/tpcc_test.cc b/src/benchmark/tpcc/test/tpcc_test.cc
new file mode 100644
index 000000000..04d5b4890
--- /dev/null
+++ b/src/benchmark/tpcc/test/tpcc_test.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+namespace tera {
+namespace tpcc {
+
+int main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
+
+} // namespace tpcc
+} // namespace tera
diff --git a/src/benchmark/tpcc/tpcc_flags.cc b/src/benchmark/tpcc/tpcc_flags.cc
new file mode 100644
index 000000000..4de8b300e
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_flags.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include "gflags/gflags.h"
+
+DEFINE_int64(transactions_count, 200, "the count of transactions");
+DEFINE_int32(warehouses_count, 2, "the count of warsehouses");
+DEFINE_int32(tpcc_thread_pool_size, 20, "size of tpcc thread pool");
+DEFINE_int32(tpcc_run_gtxn_thread_pool_size, 20, "size of tpcc run global transactions thread pool");
+DEFINE_string(db_type, "tera", "test db type");
+DEFINE_string(tera_client_flagfile, "./tera.flag", "the flag file path of tera client");
+DEFINE_string(tera_table_schema_dir, "./tpcc_schemas/", "table schema directory");
+DEFINE_int32(generate_data_wait_times, 36000000, "generate data wait times, default 1h");
+DEFINE_int32(driver_wait_times, 36000000, "driver wait times, default 1h");
diff --git a/src/benchmark/tpcc/tpcc_main.cc b/src/benchmark/tpcc/tpcc_main.cc
new file mode 100644
index 000000000..2e2df8e26
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_main.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include
+
+#include
+#include
+
+#include "benchmark/tpcc/data_generator.h"
+#include "benchmark/tpcc/driver.h"
+#include "benchmark/tpcc/random_generator.h"
+#include "benchmark/tpcc/tpccdb.h"
+#include "benchmark/tpcc/tpcc_types.h"
+#include "types.h"
+#include "common/timer.h"
+#include "version.h"
+
+DECLARE_int64(transactions_count);
+DECLARE_int32(warehouses_count);
+DECLARE_string(db_type);
+
+int main(int argc, char *argv[]) {
+ // load conf from flags
+ ::google::ParseCommandLineFlags(&argc, &argv, true);
+
+ if (argc > 1 && strcmp(argv[1], "version") == 0) {
+ PrintSystemVersion();
+ return 0;
+ }
+ if (FLAGS_warehouses_count > tera::tpcc::kMaxWarehouseId
+ && FLAGS_warehouses_count <= 0) {
+ LOG(ERROR) << "--warehouses_count=" << FLAGS_warehouses_count << " is not availability";
+ return -1;
+ }
+
+ tera::tpcc::RandomGenerator random_gen;
+ random_gen.SetRandomConstant();
+
+ tera::tpcc::TpccDb* db = tera::tpcc::TpccDb::NewTpccDb(FLAGS_db_type);
+ // do clean tables
+ if (argc == 2 && strcmp(argv[1], "clean") == 0) {
+ if(!db->CleanTables()) {
+ LOG(ERROR) << "clean tables failed, exit";
+ _Exit(EXIT_FAILURE);
+ }
+ delete db;
+ return 0;
+ }
+
+ if (!db->CreateTables()) {
+ LOG(ERROR) << "create tables failed, exit";
+ _Exit(EXIT_FAILURE);
+ }
+
+ tera::tpcc::DataGenerator data_gen(&random_gen, db);
+ int64_t beg_ts = tera::get_micros();
+ data_gen.GenItems();
+ data_gen.GenWarehouses();
+ data_gen.Join();
+ int64_t cost_t = tera::get_micros() - beg_ts;
+ LOG(INFO) << "Generate Tables Cost:" << cost_t << "us";
+
+ // init driver
+ tera::tpcc::NURandConstant constant = random_gen.GetRandomConstant();
+ random_gen.SetRandomConstant(constant);
+ tera::tpcc::Driver driver(&random_gen, db);
+ // run test
+ int64_t beg_txn_ts = tera::get_micros();
+ driver.RunTransactions();
+ driver.Join();
+ int64_t cost_txn_t = tera::get_micros() - beg_txn_ts;
+ LOG(INFO) << "RunTransactions Cost:" << cost_txn_t << "us";
+ delete db;
+ return 0;
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_customer b/src/benchmark/tpcc/tpcc_schemas/t_customer
new file mode 100644
index 000000000..7b8c7ddfd
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_customer
@@ -0,0 +1,5 @@
+t_customer {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_customer_last_index b/src/benchmark/tpcc/tpcc_schemas/t_customer_last_index
new file mode 100644
index 000000000..e7990ca13
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_customer_last_index
@@ -0,0 +1,5 @@
+t_customer_last_index {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_district b/src/benchmark/tpcc/tpcc_schemas/t_district
new file mode 100644
index 000000000..2a6cbe3a3
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_district
@@ -0,0 +1,5 @@
+t_district {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_history b/src/benchmark/tpcc/tpcc_schemas/t_history
new file mode 100644
index 000000000..a21f40001
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_history
@@ -0,0 +1,5 @@
+t_history {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_history_index b/src/benchmark/tpcc/tpcc_schemas/t_history_index
new file mode 100644
index 000000000..205b3aa23
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_history_index
@@ -0,0 +1,5 @@
+t_history_index {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_item b/src/benchmark/tpcc/tpcc_schemas/t_item
new file mode 100644
index 000000000..02bf1ff5a
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_item
@@ -0,0 +1,5 @@
+t_item {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_neworder b/src/benchmark/tpcc/tpcc_schemas/t_neworder
new file mode 100644
index 000000000..e7ef005e0
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_neworder
@@ -0,0 +1,5 @@
+t_neworder {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_order b/src/benchmark/tpcc/tpcc_schemas/t_order
new file mode 100644
index 000000000..4e7d0139f
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_order
@@ -0,0 +1,5 @@
+t_order {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_order_index b/src/benchmark/tpcc/tpcc_schemas/t_order_index
new file mode 100644
index 000000000..6d2a47528
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_order_index
@@ -0,0 +1,5 @@
+t_order_index {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_orderline b/src/benchmark/tpcc/tpcc_schemas/t_orderline
new file mode 100644
index 000000000..d075e7918
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_orderline
@@ -0,0 +1,5 @@
+t_orderline {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_stock b/src/benchmark/tpcc/tpcc_schemas/t_stock
new file mode 100644
index 000000000..a35115aa0
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_stock
@@ -0,0 +1,5 @@
+t_stock {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_schemas/t_warehouse b/src/benchmark/tpcc/tpcc_schemas/t_warehouse
new file mode 100644
index 000000000..9102544ff
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_schemas/t_warehouse
@@ -0,0 +1,5 @@
+t_warehouse {
+ lg0 {
+ cf0
+ }
+}
diff --git a/src/benchmark/tpcc/tpcc_types.h b/src/benchmark/tpcc/tpcc_types.h
new file mode 100644
index 000000000..c73e9f489
--- /dev/null
+++ b/src/benchmark/tpcc/tpcc_types.h
@@ -0,0 +1,139 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#ifndef TERA_BENCHMARK_TPCC_TPCC_TYPES_H
+#define TERA_BENCHMARK_TPCC_TPCC_TYPES_H
+
+#include
+
+#include
+#include
+
+namespace tera {
+namespace tpcc {
+
+const int kTpccTableCnt = 12;
+
+// t_customer_last_index is the index of t_customer
+//
+const char* const kTpccTables[] = {"t_item", "t_warehouse", "t_district",
+ "t_customer", "t_history", "t_stock",
+ "t_order", "t_orderline", "t_neworder",
+ "t_customer_last_index", "t_order_index",
+ "t_history_index"};
+
+// StockLevel 4% 4
+// OrderStatus 4% 8
+// Delivery 4% 12
+// Payment 43% 55
+// NewOrder 45% 100
+const int kTpccTransactionRatios[] = {4, 8, 12, 55, 100};
+
+// http://www.man7.org/linux/man-pages/man3/initstate.3.html
+// Current "optimal" values for the size of the state array n
+// are 8, 32, 64, 128, and 256 bytes;
+const int kRandomStateSize = 64;
+
+// YTD
+const float kInitYTD = 300000.00f;
+
+// tax
+const float kTaxMax = 0.20f;
+const float kTaxMin = 0.10f;
+const int kTaxDigits = 2;
+
+// address
+const int kStreetLowerLen = 10;
+const int kStreetUpperLen = 20;
+const int kCityLowerLen = 10;
+const int kCityUpperLen = 20;
+const int kStateLen = 2;
+const int kZipLen = 9;
+
+// warehourse
+const int kMaxWarehouseId = 100;
+const int kWareHouseNameLowerLen = 6;
+const int kWareHouseNameUpperLen = 10;
+
+// stock
+const int kMaxQuantity = 100;
+const int kMinQuantity = 10;
+const int kDistLen = 24;
+const int kStockDataLowerLen = 26;
+const int kStockDataUpperLen = 50;
+const int kMinStockLevelThreshold = 10;
+const int kMaxStockLevelThreshold = 20;
+
+// item
+const int kItemCount = 100000;
+const int kItemMaxIm = 10000;
+const int kItemMinIm = 1;
+const float kItemMaxPrice = 100.00;
+const float kItemMinPrice = 1.00;
+const int kItemPriceDigits = 2;
+const int kItemMaxNameLen = 24;
+const int kItemMinNameLen = 14;
+const int kItemMaxDataLen = 50;
+const int kItemMinDataLen = 26;
+
+// district
+const int kDistrictCountPerWarehouse = 10;
+const int kDistrictNameLowerLen = 6;
+const int kDistrictNameUpperLen = 10;
+
+// customer
+const int kCustomerCountPerDistrict = 3000;
+const float kInitCreditLimit = 5000.00;
+const float kMaxDisCount = 0.0;
+const float kMinDisCount = 0.5;
+const int kDisCountDigits = 2;
+const float kInitBalance = -10.00;
+const float kInitYTDPayment = 10.00;
+const int kInitPaymentCnt = 1;
+const int kInitDeliveryCnt = 0;
+const int kFirstLowerLen = 6;
+const int kFirstUpperLen = 10;
+const int kMiddleLen = 2;
+const int kLastLen = 16;
+const int kPhoneLen = 16;
+const int kCreditLen = 2;
+const int kCustomerDataUpperLen = 500;
+const int kCustomerDataLowerLen = 300;
+
+// order
+const int kInitOrdersPerDistrict = 3000;
+const int kInitAllLocal = 1;
+const int kMaxCarrierId = 10;
+const int kMinCarrierId = 1;
+const int kMaxOrderLineCnt = 15;
+const int kMinOrderLineCnt = 5;
+
+// new order
+const int kInitNewOrderCountPerDistrict = 900;
+
+// order line
+const int kMaxItemId = 100000;
+const int kMinItemId = 1;
+const int kInitQuantity = 5;
+const int kMaxOrderLineQuantity = 10;
+const float kOrderLineMinAmount = 0.01f;
+const float kOrderLineMaxAmount = 9999.99f;
+const int kOrderLineAmountDigits = 2;
+
+// history
+const float kInitHistoryAmount = 10.00f;
+const int kHistoryDataLowerLen = 12;
+const int kHistoryDataUpperLen = 24;
+
+// runtime h_amount
+const float kRuntimeMaxAmount = 5000.00f;
+const float kRuntimeMinAmount = 1.00f;
+const int kRuntimeAmountDigits = 2;
+
+} // namespace tpcc
+} // namepsace tera
+
+#endif /* TERA_BENCHMARK_TPCC_TPCC_TYPES_H */
diff --git a/src/benchmark/tpcc/tpccdb.cc b/src/benchmark/tpcc/tpccdb.cc
new file mode 100644
index 000000000..bb7e0cfb5
--- /dev/null
+++ b/src/benchmark/tpcc/tpccdb.cc
@@ -0,0 +1,360 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#include
+
+#include "benchmark/tpcc/mock_tpccdb.h"
+#include "benchmark/tpcc/tera_tpccdb.h"
+#include "benchmark/tpcc/tpccdb.h"
+
+namespace tera {
+namespace tpcc {
+
+class TeraTpccDb;
+class MockTpccDb;
+
+/// ------------------------- [begin item table] -------------------------- ///
+std::string Item::ToString() const {
+ std::stringstream ss;
+ ss << "i_id = " << i_id
+ << ",i_im_id = " << i_im_id
+ << ",i_price = " << i_price
+ << ",i_name = " << i_name
+ << ",i_data = " << i_data;
+ return ss.str();
+}
+
+/// ------------------------- [begin warehouse table] --------------------- ///
+std::string Warehouse::ToString() const {
+ std::stringstream ss;
+ ss << "w_id = " << w_id
+ << ",w_tax = " << w_tax
+ << ",w_ytd = " << w_ytd
+ << ",w_name = " << w_name
+ << ",w_street_1 = " << w_street_1
+ << ",w_street_2 = " << w_street_2
+ << ",w_city = " << w_city
+ << ",w_state = " << w_state
+ << ",w_zip = " << w_zip;
+ return ss.str();
+}
+
+/// ------------------------- [begin district table] ---------------------- ///
+
+District::District(int32_t id, int32_t w_id, RandomGenerator* rand_gen)
+ : d_id(id), d_w_id(w_id), d_ytd(kInitYTD), d_next_o_id(kCustomerCountPerDistrict + 1) {
+ d_tax = GenTax(rand_gen);
+ d_name = rand_gen->MakeAString(kDistrictNameLowerLen, kDistrictNameUpperLen);
+ d_street_1 = rand_gen->MakeAString(kStreetLowerLen, kStreetUpperLen);
+ d_street_2 = rand_gen->MakeAString(kStreetLowerLen, kStreetUpperLen);
+ d_city = rand_gen->MakeAString(kCityLowerLen, kCityUpperLen);
+ d_state = rand_gen->MakeAString(kStateLen,kStateLen);
+ d_zip = GenZip(rand_gen);
+}
+
+std::string District::PrimaryKey() const {
+ return std::to_string(d_w_id) + "_"
+ + std::to_string(d_id);
+}
+
+std::string District::ForeignKey() const {
+ return std::to_string(d_w_id);
+}
+
+std::string District::ToString() const {
+ std::stringstream ss;
+ ss << "d_id = " << d_id
+ << ",d_w_id = " << d_w_id
+ << ",d_tax = " << d_tax
+ << ",d_ytd = " << d_ytd
+ << ",d_next_o_id = " << d_next_o_id
+ << ",d_name = " << d_name
+ << ",d_street_1 = " << d_street_1
+ << ",d_street_2 = " << d_street_2
+ << ",d_city = " << d_city
+ << ",d_state = " << d_state
+ << ",d_zip = " << d_zip;
+ return ss.str();
+}
+
+/// ------------------------- [begin stock table] ------------------------- ///
+
+Stock::Stock(int32_t id, int32_t w_id, bool is_original, RandomGenerator* rand_gen)
+ : s_i_id (id), s_w_id(w_id) {
+ s_quantity = rand_gen->GetRandom(kMinQuantity, kMaxQuantity);
+ s_ytd = 0;
+ s_order_cnt = 0;
+ s_remote_cnt = 0;
+ for (int i = 0; i < kDistrictCountPerWarehouse; ++i) {
+ s_dist.push_back(rand_gen->MakeAString(kDistLen, kDistLen));
+ }
+ s_data = GenData(rand_gen, kStockDataLowerLen, kStockDataUpperLen, is_original);
+}
+
+std::string Stock::PrimaryKey() const {
+ return std::to_string(s_w_id) + "_" + std::to_string(s_i_id);
+}
+
+std::string Stock::ForeignKey() const {
+ return std::to_string(s_i_id);
+}
+
+std::string Stock::ToString() const {
+ std::stringstream ss;
+ ss << "s_w_id = " << s_w_id
+ << ",s_quantity = " << s_quantity
+ << ",s_ytd = " << s_ytd
+ << ",s_order_cnt = " << s_order_cnt
+ << ",s_remote_cnt = " << s_remote_cnt
+ << ",s_data = " << s_data
+ << ",s_dist = [";
+ for (auto d : s_dist) {
+ ss << d << ",";
+ }
+ ss << "]";
+ return ss.str();
+}
+
+/// ------------------------- [begin order table] ------------------------- ///
+
+Order::Order(int32_t id, int32_t c_id, int32_t d_id, int32_t w_id,
+ bool new_order, const std::string& datetime,
+ RandomGenerator* rand_gen)
+ : o_id(id), o_c_id(c_id), o_d_id(d_id), o_w_id(w_id),
+ o_carrier_id(0), o_all_local(kInitAllLocal),
+ o_entry_d(datetime) {
+
+ if (!new_order) {
+ o_carrier_id = rand_gen->GetRandom(kMinCarrierId, kMaxCarrierId);
+ }
+ o_ol_cnt = rand_gen->GetRandom(kMinOrderLineCnt, kMaxOrderLineCnt);
+}
+
+std::string Order::PrimaryKey() const {
+ return std::to_string(o_w_id) + "_"
+ + std::to_string(o_d_id) + "_"
+ + std::to_string(o_id);
+}
+
+std::string Order::ForeignKey() const {
+ return std::to_string(o_w_id) + "_"
+ + std::to_string(o_d_id) + "_"
+ + std::to_string(o_c_id);
+}
+
+std::string Order::ToString() const {
+ std::stringstream ss;
+ ss << "o_id = " << o_id
+ << ",o_c_id = " << o_c_id
+ << ",o_d_id = " << o_d_id
+ << ",o_w_id = " << o_w_id
+ << ",o_carrier_id = " << o_carrier_id
+ << ",o_ol_cnt = " << o_ol_cnt
+ << ",o_all_local = " << o_all_local
+ << ",o_entry_d = " << o_entry_d;
+ return ss.str();
+}
+
+/// ------------------------- [begin neworder table] ---------------------- ///
+
+
+NewOrder::NewOrder(int32_t o_id, int32_t d_id, int32_t w_id)
+ : no_o_id(o_id), no_d_id(d_id), no_w_id(w_id) {
+}
+
+std::string NewOrder::ToString() const {
+ std::stringstream ss;
+ ss << "no_o_id = " << no_o_id
+ << ",no_d_id = " << no_d_id
+ << ",no_w_id = " << no_w_id;
+ return ss.str();
+}
+
+std::string NewOrder::PrimaryKey() const {
+ return std::to_string(no_w_id)
+ + "_" + std::to_string(no_d_id)
+ + "_" + std::to_string(no_o_id);
+}
+
+std::string NewOrder::ForeignKey() const {
+ return std::to_string(no_w_id)
+ + "_" + std::to_string(no_d_id)
+ + "_" + std::to_string(no_o_id);
+}
+
+/// ------------------------- [begin orderline table] --------------------- ///
+
+OrderLine::OrderLine(int32_t o_id, int32_t d_id, int32_t w_id, int32_t number,
+ bool new_order, const std::string& datetime,
+ RandomGenerator* rand_gen)
+ : ol_o_id(o_id), ol_d_id(d_id), ol_w_id(w_id), ol_number(number),
+ ol_supply_w_id(w_id), ol_quantity(kInitQuantity),
+ ol_amount(0.00f), ol_delivery_d(datetime) {
+
+ ol_i_id = rand_gen->GetRandom(kMinItemId, kMaxItemId);
+ if (new_order) {
+ ol_amount = rand_gen->MakeFloat(kOrderLineMinAmount,
+ kOrderLineMaxAmount,
+ kOrderLineAmountDigits);
+ ol_delivery_d = "";
+ }
+ ol_dist_info = rand_gen->MakeAString(kDistLen, kDistLen);
+}
+
+std::string OrderLine::PrimaryKey() const {
+ return std::to_string(ol_w_id) + "_"
+ + std::to_string(ol_d_id) + "_"
+ + std::to_string(ol_o_id) + "_"
+ + std::to_string(ol_number);
+}
+
+ForeignKeyMap OrderLine::ForeignKeys() const {
+ ForeignKeyMap foreign_keys;
+ std::string order_index = std::to_string(ol_w_id) + "_"
+ + std::to_string(ol_d_id) + "_"
+ + std::to_string(ol_o_id);
+ std::string item_index = std::to_string(ol_supply_w_id) + "_"
+ + std::to_string(ol_i_id);
+ foreign_keys["order_index"] = order_index;
+ foreign_keys["item_index"] = item_index;
+ return foreign_keys;
+}
+
+std::string OrderLine::ToString() const {
+ std::stringstream ss;
+ ss << "ol_o_id = " << ol_o_id
+ << ",ol_d_id = " << ol_d_id
+ << ",ol_w_id = " << ol_w_id
+ << ",ol_number = " << ol_number
+ << ",ol_i_id = " << ol_i_id
+ << ",ol_supply_w_id = " << ol_supply_w_id
+ << ",ol_quantity = " << ol_quantity
+ << ",ol_amount = " << ol_amount
+ << ",ol_delivery_d = " << ol_delivery_d
+ << ",ol_dist_info = " << ol_dist_info;
+ return ss.str();
+}
+
+/// ------------------------- [begin customer table] ---------------------- ///
+
+Customer::Customer(int32_t id, int32_t d_id, int32_t w_id, const std::string& datetime,
+ bool bad_credit, RandomGenerator* rand_gen)
+ : c_id(id),
+ c_d_id(d_id),
+ c_w_id(w_id),
+ c_credit_lim(kInitCreditLimit),
+ c_balance(kInitBalance),
+ c_ytd_payment(kInitYTDPayment),
+ c_payment_cnt(kInitPaymentCnt),
+ c_delivery_cnt(kInitDeliveryCnt),
+ c_middle("OE"),
+ c_since(datetime) {
+ c_discount = rand_gen->MakeFloat(kMinDisCount, kMaxDisCount, kDisCountDigits);
+ c_first = rand_gen->MakeAString(kFirstLowerLen, kFirstUpperLen);
+ c_last = GenLastName(rand_gen, (id <= 1000 ? id : kCustomerCountPerDistrict));
+ c_street_1 = rand_gen->MakeAString(kStreetLowerLen, kStreetUpperLen);
+ c_street_2 = rand_gen->MakeAString(kStreetLowerLen, kStreetUpperLen);
+ c_city = rand_gen->MakeAString(kCityLowerLen, kCityUpperLen);
+ c_state = rand_gen->MakeAString(kStateLen,kStateLen);
+ c_zip = GenZip(rand_gen);
+ c_phone = rand_gen->MakeNString(kPhoneLen,kPhoneLen);
+ c_credit = bad_credit ? "BC" : "GC";
+ c_data = GenData(rand_gen, kCustomerDataLowerLen, kCustomerDataUpperLen, false);
+}
+
+std::string Customer::PrimaryKey() const {
+ return std::to_string(c_w_id) + "_" + std::to_string(c_d_id)
+ + "_" + std::to_string(c_id);
+}
+
+std::string Customer::ForeignKey() const {
+ return std::to_string(c_w_id) + "_" + std::to_string(c_d_id);
+}
+
+std::string Customer::ToString() const {
+ std::stringstream ss;
+ ss << "c_id = " << c_id
+ << ",c_d_id = " << c_d_id
+ << ",c_w_id = " << c_w_id
+ << ",c_credit_lim = " << c_credit_lim
+ << ",c_discount = " << c_discount
+ << ",c_balance = " << c_balance
+ << ",c_ytd_payment = " << c_ytd_payment
+ << ",c_payment_cnt = " << c_payment_cnt
+ << ",c_delivery_cnt = " << c_delivery_cnt
+ << ",c_name = [" << c_first << "," << c_middle << "," << c_last << "]"
+ << ",c_street_1 = " << c_street_1
+ << ",c_street_2 = " << c_street_2
+ << ",c_city = " << c_city
+ << ",c_state = " << c_state
+ << ",c_zip = " << c_zip
+ << ",c_phone = " << c_phone
+ << ",c_since = " << c_since
+ << ",c_credit = " << c_credit
+ << ",c_data = " << c_data;
+ return ss.str();
+}
+
+/// ------------------------- [begin history table] ----------------------- ///
+std::string History::ToString() const {
+ std::stringstream ss;
+ ss << "h_c_id = " << h_c_id
+ << ",h_c_d_id = " << h_c_d_id
+ << ",h_c_w_id = " << h_c_w_id
+ << ",h_d_id = " << h_d_id
+ << ",h_w_id = " << h_w_id
+ << ",h_amount = " << h_amount
+ << ",h_date = " << h_date
+ << ",h_data = " << h_data;
+ return ss.str();
+}
+
+/// ------------------------- [end tables] -------------------------------- ///
+
+bool TxnResult::State() const {
+ return status_;
+}
+
+void TxnResult::SetState(bool status) {
+ status_ = status;
+}
+
+void TxnResult::SetReason(const std::string& reason) {
+ reason_ = reason;
+}
+
+void StockLevelResult::SetLowStock(int low_stock) {
+ low_stock_ = low_stock;
+}
+
+int StockLevelResult::LowStock() const {
+ return low_stock_;
+}
+
+void PaymentResult::SetSingleLine(const RetTuples& single_line) {
+ single_line_ = single_line;
+}
+
+void NewOrderResult::AddLine(const RetTuples& line) {
+ lines_.push_back(line);
+}
+
+void NewOrderResult::SetSingleLine(const RetTuples& single_line) {
+ single_line_ = single_line;
+}
+
+TpccDb* TpccDb::NewTpccDb(const std::string& db_type) {
+ if (db_type == "tera") {
+ return new TeraTpccDb();
+ } else {
+ LOG(ERROR) << "not support db:" << db_type;
+ }
+ return NULL;
+}
+
+} // namespace tpcc
+} // namespace tera
+
diff --git a/src/benchmark/tpcc/tpccdb.h b/src/benchmark/tpcc/tpccdb.h
new file mode 100644
index 000000000..93b3c32f3
--- /dev/null
+++ b/src/benchmark/tpcc/tpccdb.h
@@ -0,0 +1,471 @@
+// Copyright (c) 2015-2017, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Author: baorenyi@baidu.com
+
+#ifndef TERA_BENCHMARK_TPCC_TPCCDB_H
+#define TERA_BENCHMARK_TPCC_TPCCDB_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "benchmark/tpcc/random_generator.h"
+#include "benchmark/tpcc/tpcc_types.h"
+
+namespace tera {
+namespace tpcc {
+
+typedef std::unordered_set IdSet;
+typedef std::unordered_map ForeignKeyMap;
+typedef std::unordered_map RetTuples;
+
+
+inline float GenTax(RandomGenerator* rand_gen) {
+ return rand_gen->MakeFloat(kTaxMax, kTaxMin, kTaxDigits);
+}
+
+inline std::string GenZip(RandomGenerator* rand_gen) {
+ return rand_gen->MakeNString(kZipLen, kZipLen);
+}
+
+inline std::string GenData(RandomGenerator* rand_gen,
+ int lower_len,
+ int upper_len,
+ bool is_original) {
+ std::string ret = rand_gen->MakeAString(lower_len, upper_len);
+ if (is_original) {
+ int pos = rand_gen->GetRandom(0, ret.size() - 8);
+ ret = ret.replace(pos, 8, "ORIGINAL");
+ }
+ return ret;
+}
+
+inline std::string GenLastName(RandomGenerator* rand_gen, int id) {
+ if (id > 999) {
+ id = rand_gen->NURand(255, 0, std::min(999, id - 1));
+ }
+ std::vector labels = {"BAR", "OUGHT", "ABLE", "PRI", "PRES",
+ "ESE", "ANTI", "CALLY", "ATION", "EING"};
+ return labels[id / 100] + labels[(id / 10) % 10] + labels[id % 10];
+}
+
+inline IdSet PickUniqueIdSet(RandomGenerator* rand_gen, size_t cnt, int lower_id, int upper_id) {
+ IdSet ids;
+ while(ids.size() < cnt) {
+ int tmp_id = rand_gen->GetRandom(lower_id, upper_id);
+ if (ids.find(tmp_id) == ids.end()) {
+ ids.insert(tmp_id);
+ }
+ }
+ return ids;
+}
+
+struct Item {
+ int32_t i_id;
+ int32_t i_im_id;
+ float i_price;
+ std::string i_name;
+ std::string i_data;
+
+ Item(int32_t id, bool is_original, RandomGenerator* rand_gen) : i_id(id) {
+ i_im_id = rand_gen->GetRandom(kItemMinIm, kItemMaxIm);
+ i_price = rand_gen->MakeFloat(kItemMinPrice, kItemMaxPrice, kItemPriceDigits);
+ i_name = rand_gen->MakeAString(kItemMinNameLen, kItemMaxNameLen);
+ i_data = GenData(rand_gen, kItemMinDataLen, kItemMaxDataLen, is_original);
+ }
+
+ std::string PrimaryKey() const { return std::to_string(i_id); }
+ std::string ToString() const;
+};
+
+struct Warehouse {
+ int32_t w_id;
+ float w_tax;
+ float w_ytd;
+ std::string w_name;
+ std::string w_street_1;
+ std::string w_street_2;
+ std::string w_city;
+ std::string w_state;
+ std::string w_zip;
+ Warehouse(int32_t id, RandomGenerator* rand_gen) : w_id(id) {
+ w_tax = GenTax(rand_gen);
+ w_ytd = kInitYTD;
+ w_name = rand_gen->MakeAString(kWareHouseNameLowerLen, kWareHouseNameUpperLen);
+ w_street_1 = rand_gen->MakeAString(kStreetLowerLen, kStreetUpperLen);
+ w_street_2 = rand_gen->MakeAString(kStreetLowerLen, kStreetUpperLen);
+ w_city = rand_gen->MakeAString(kCityLowerLen, kCityUpperLen);
+ w_state = rand_gen->MakeAString(kStateLen,kStateLen);
+ w_zip = GenZip(rand_gen);
+ }
+ std::string PrimaryKey() const { return std::to_string(w_id); }
+ std::string ToString() const;
+};
+
+struct District {
+ int32_t d_id;
+ int32_t d_w_id;
+ float d_tax;
+ float d_ytd;
+ int32_t d_next_o_id;
+ std::string d_name;
+ std::string d_street_1;
+ std::string d_street_2;
+ std::string d_city;
+ std::string d_state;
+ std::string d_zip;
+
+ District(int32_t id, int32_t w_id, RandomGenerator* rand_gen);
+ std::string PrimaryKey() const;
+ std::string ForeignKey() const;
+ std::string ToString() const;
+};
+
+struct Stock {
+int32_t s_i_id;
+ int32_t s_w_id;
+ int32_t s_quantity;
+ int32_t s_ytd;
+ int32_t s_order_cnt;
+ int32_t s_remote_cnt;
+ std::vector s_dist;
+ std::string s_data;
+
+ Stock(int32_t id, int32_t w_id, bool is_original, RandomGenerator* rand_gen);
+ std::string PrimaryKey() const;
+ std::string ForeignKey() const;
+ std::string ToString() const;
+};
+
+struct Customer {
+ int32_t c_id;
+ int32_t c_d_id;
+ int32_t c_w_id;
+ float c_credit_lim;
+ float c_discount;
+ float c_balance;
+ float c_ytd_payment;
+ int32_t c_payment_cnt;
+ int32_t c_delivery_cnt;
+ std::string c_first;
+ std::string c_middle;
+ std::string c_last;
+ std::string c_street_1;
+ std::string c_street_2;
+ std::string c_city;
+ std::string c_state;
+ std::string c_zip;
+ std::string c_phone;
+ std::string c_since;
+ std::string c_credit;
+ std::string c_data;
+ Customer(int32_t id, int32_t d_id, int32_t w_id, const std::string& datetime,
+ bool bad_credit, RandomGenerator* rand_gen);
+ std::string PrimaryKey() const;
+ std::string ForeignKey() const;
+ std::string ToString() const;
+};
+
+struct Order {
+ int32_t o_id;
+ int32_t o_c_id;
+ int32_t o_d_id;
+ int32_t o_w_id;
+ int32_t o_carrier_id;
+ int32_t o_ol_cnt;
+
+ // If the order includes only home order-lines,
+ // then O_ALL_LOCAL is set to 1, otherwise O_ALL_LOCAL is set to 0.
+ int32_t o_all_local;
+ std::string o_entry_d;
+
+ Order(int32_t id, int32_t c_id, int32_t d_id, int32_t w_id, bool new_order,
+ const std::string& datetime, RandomGenerator* rand_gen);
+ std::string PrimaryKey() const;
+ std::string ForeignKey() const;
+ std::string ToString() const;
+};
+
+// An order-line is said to be 'home' if it is supplied by the home warehouse
+// (i.e., when OL_SUPPLY_W_ID equals O_W_ID).
+//
+// An order-line is said to be remote when it is supplied by a remote warehouse
+// (i.e., when OL_SUPPLY_W_ID does not equal O_W_ID).
+//
+struct OrderLine {
+ int32_t ol_o_id;
+ int32_t ol_d_id;
+ int32_t ol_w_id;
+ int32_t ol_number;
+ int32_t ol_i_id;
+ int32_t ol_supply_w_id;
+ int32_t ol_quantity;
+ float ol_amount;
+ std::string ol_delivery_d;
+ std::string ol_dist_info;
+
+ OrderLine(int32_t o_id, int32_t d_id, int32_t w_id, int32_t number,
+ bool new_order, const std::string& datetime,
+ RandomGenerator* rand_gen);
+ std::string PrimaryKey() const;
+ ForeignKeyMap ForeignKeys() const;
+ std::string ToString() const;
+};
+
+struct NewOrder {
+ int32_t no_o_id;
+ int32_t no_d_id;
+ int32_t no_w_id;
+
+ NewOrder(int32_t o_id, int32_t d_id, int32_t w_id);
+ std::string PrimaryKey() const;
+ std::string ForeignKey() const;
+ std::string ToString() const;
+};
+
+struct History {
+ int32_t h_c_id;
+ int32_t h_c_d_id;
+ int32_t h_c_w_id;
+ int32_t h_d_id;
+ int32_t h_w_id;
+ float h_amount;
+ std::string h_date;
+ std::string h_data;
+
+ History(int32_t c_id, int32_t d_id, int32_t w_id, const std::string& datetime,
+ RandomGenerator* rand_gen)
+ : h_c_id(c_id), h_c_d_id(d_id), h_c_w_id(w_id), h_d_id(d_id), h_w_id(w_id),
+ h_amount(kInitHistoryAmount), h_date(datetime) {
+ h_data = rand_gen->MakeAString(kHistoryDataLowerLen, kHistoryDataUpperLen);
+ }
+ std::string PrimaryKey() const { return std::to_string(h_c_id); }
+ std::string ToString() const;
+};
+
+struct NewOrderInfo {
+ bool need_failed;
+ int32_t o_all_local;
+ int32_t o_ol_cnt;
+ std::vector ol_supply_w_ids;
+ std::vector ol_i_ids;
+ std::vector ol_quantities;
+};
+
+enum TpccTables
+{
+ kItemTable = 0,
+ kWarehouseTable = 1,
+ kDistrictTable = 2,
+ kCustomerTable = 3,
+ kHistoryTable = 4,
+ kStockTable = 5,
+ kOrderTable = 6,
+ kOrderLineTable = 7,
+ kNewOrderTable = 8,
+
+ // the index of table
+ kCustomerLastIndex = 9,
+ kOrderIndex = 10,
+ kHistoryIndex = 11
+};
+
+/// ------------------------- transaction result ---------------------------///
+
+class TxnResult {
+public:
+ void SetState(bool status);
+ bool State() const;
+ void SetReason(const std::string& reason);
+ const std::string& Reason() const;
+private:
+ bool status_;
+ std::string reason_;
+};
+
+class StockLevelResult : public TxnResult {
+public:
+ void SetLowStock(int low_stock);
+ int LowStock() const;
+private:
+ int low_stock_;
+};
+
+class PaymentResult : public TxnResult {
+public:
+ void SetSingleLine(const RetTuples& single_line);
+private:
+ RetTuples single_line_;
+};
+
+class NewOrderResult : public TxnResult {
+public:
+ void AddLine(const RetTuples& line);
+ void SetSingleLine(const RetTuples& single_line);
+private:
+ std::vector lines_;
+ RetTuples single_line_;
+};
+
+class OrderStatusResult : public TxnResult {
+
+};
+
+class DeliveryResult : public TxnResult {
+
+};
+
+class TpccDb {
+public:
+ TpccDb(){}
+ virtual ~TpccDb(){}
+
+ // init db
+ virtual bool CreateTables() = 0;
+ virtual bool CleanTables() = 0;
+
+ // for insert table
+ virtual bool InsertItem(const Item& i) = 0;
+
+ virtual bool InsertWarehouse(const Warehouse& w) = 0;
+
+ virtual bool InsertDistrict(const District& d) = 0;
+
+ virtual bool InsertCustomer(const Customer& c) = 0;
+
+ virtual bool InsertHistory(const History& h) = 0;
+
+ virtual bool InsertStock(const Stock& s) = 0;
+
+ virtual bool InsertOrder(const Order& o) = 0;
+
+ virtual bool InsertOrderLine(const OrderLine& ol) = 0;
+
+ virtual bool InsertNewOrder(const NewOrder& no) = 0;
+
+ // for transaction
+
+ // The Stock-Level Transaction [Revision 5.11 - Page 44]
+ //
+ // (warehouse_id, district_id)
+ // is the primarykey of t_district
+ // Each terminal must use a unique value of (W_ID, D_ID) that is constant
+ // over the whole measurement, i.e., D_IDs cannot be re-used within a warehouse
+ //
+ // threshold
+ // The threshold of minimum quantity in stock (threshold) is selected
+ // at random within [10 .. 20].
+ //
+ virtual void StockLevelTxn(int32_t warehouse_id, int32_t district_id,
+ int32_t threshold,
+ StockLevelResult* ret) = 0;
+
+ // The Delivery Transaction [Revision 5.11 - Page 40]
+ //
+ // warehouse_id
+ // For any given terminal, the home warehouse number (W_ID) is constant
+ // over the whole measurement interval
+ //
+ // carrier_id
+ // The carrier number (O_CARRIER_ID) is randomly selected within [1 .. 10].
+ //
+ // delivery_datetime
+ // The delivery date (OL_DELIVERY_D) is generated within the
+ // SUT by using the current system date and time.
+ //
+ virtual void DeliveryTxn(int32_t warehouse_id,
+ int32_t carrier_id,
+ const std::string& delivery_datetime,
+ DeliveryResult* ret) = 0;
+
+ // The Order-Status Transaction [Revision 5.11 - Page 37]
+ //
+ // warehouse_id
+ // For any given terminal, the home warehouse number (W_ID) is constant
+ // over the whole measurement interval
+ //
+ // district_id
+ // The district number (D_ID) is randomly selected within [1 .. 10]
+ // from the home warehouse (D_W_ID = W_ID).
+ //
+ // c_warehouse_id, c_district_id, last_name
+ // customer is randomly selected
+ // 60% of the time by last name (C_W_ID, C_D_ID, C_LAST)
+ // from the selected district (C_D_ID = D_ID)
+ // and the home warehouse number (C_W_ID = W_ID).
+ //
+ // c_warehouse_id, c_district_id, customer_id
+ // 40% of the time by number (C_W_ID, C_D_ID, C_ID)
+ // from the selected district (C_D_ID = D_ID)
+ // and the home warehouse number (C_W_ID = W_ID).
+ //
+ virtual void OrderStatusTxn(bool by_last_name,
+ int32_t warehouse_id, int32_t district_id,
+ int32_t c_customer_id,
+ const std::string& last_name,
+ OrderStatusResult* ret) = 0;
+
+ // The Payment Transaction [Revision 5.11 - Page 33]
+ //
+ // warehouse_id
+ // For any given terminal, the home warehouse number (W_ID) is constant
+ // over the whole measurement interval
+ //
+ // district_id
+ // The district number (D_ID) is randomly selected within [1 .. 10]
+ // from the home warehouse (D_W_ID = W_ID).
+ //
+ // c_warehouse_id, c_district_id, last_name
+ // The customer is randomly selected
+ // 1) 60% of the time by last name (C_W_ID , C_D_ID, C_LAST)
+ // c_warehouse_id, c_district_id, customer_id
+ // The customer is randomly selected
+ // 2) 40% of the time by number (C_W_ID , C_D_ID , C_ID).
+ //
+ // h_amount
+ // The payment amount (H_AMOUNT) is randomly selected within
+ // [1.00 .. 5,000.00].
+ //
+ virtual void PaymentTxn(bool by_last_name,
+ int32_t warehouse_id, int32_t district_id,
+ int32_t c_warehouse_id, int32_t c_district_id,
+ int32_t c_customer_id,
+ const std::string& last_name,
+ int32_t h_amount,
+ PaymentResult* ret) = 0;
+
+
+ // The New-Order Transaction [Revision 5.11 - Page 28]
+ // warehouse_id
+ // For any given terminal, the home warehouse number (W_ID) is constant
+ // over the whole measurement interval
+ //
+ // district_id
+ // The district number (D_ID) is randomly selected within [1 .. 10]
+ // from the home warehouse (D_W_ID = W_ID).
+ //
+ // customer_id
+ // The non-uniform random customer number (C_ID) is selected using
+ // the NURand(1023,1,3000) function from the selected district
+ // number (C_D_ID = D_ID) and the home warehouse number (C_W_ID = W_ID).
+ //
+ virtual void NewOrderTxn(int32_t warehouse_id,
+ int32_t district_id,
+ int32_t customer_id, const NewOrderInfo& info,
+ NewOrderResult* ret) = 0;
+
+ static TpccDb* NewTpccDb(const std::string& db_type);
+};
+
+} // namespace tpcc
+} // namespace tera
+
+#endif /* TERA_BENCHMARK_TPCC_TPCCDB_H */
diff --git a/src/common/atomic.h b/src/common/atomic.h
index 6837cb302..195a7b0da 100644
--- a/src/common/atomic.h
+++ b/src/common/atomic.h
@@ -1,11 +1,10 @@
+#pragma once
// Copyright (c) 2015, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include
-#ifndef TERA_COUNTER_ATOMIC_H_
-#define TERA_COUNTER_ATOMIC_H_
-
-namespace common {
+namespace tera {
static inline int atomic_add(volatile int *mem, int add)
{
@@ -106,5 +105,4 @@ static inline int64_t atomic_comp_swap64(volatile void *mem, int64_t xchg, int64
return cmp;
}
-} // namespace common
-#endif // TERA_COMMON_ATOMIC_H_
+}
diff --git a/src/common/counter.h b/src/common/counter.h
index c9869f633..d4687bfd8 100644
--- a/src/common/counter.h
+++ b/src/common/counter.h
@@ -7,10 +7,10 @@
#include
-#include "atomic.h"
-#include "timer.h"
+#include "common/atomic.h"
+#include "common/timer.h"
-namespace common {
+namespace tera {
class Counter {
public:
@@ -47,19 +47,19 @@ class AutoCounter {
: counter_(counter),
msg1_(msg1),
msg2_(msg2) {
- start_ = timer::get_micros();
+ start_ = get_micros();
counter_->Inc();
}
~AutoCounter() {
- int64_t end = timer::get_micros();
+ int64_t end = get_micros();
if (end - start_ > 5000000) {
int64_t t = (end - start_) / 1000000;
if (!msg2_) {
fprintf(stderr, "%s [AutoCounter] %s hang for %ld s\n",
- timer::get_curtime_str().data(), msg1_, t);
+ get_curtime_str().data(), msg1_, t);
} else {
fprintf(stderr, "%s [AutoCounter] %s %s hang for %ld s\n",
- timer::get_curtime_str().data(), msg1_, msg2_, t);
+ get_curtime_str().data(), msg1_, msg2_, t);
}
}
counter_->Dec();
diff --git a/src/common/cpu_profiler.cc b/src/common/cpu_profiler.cc
new file mode 100644
index 000000000..758ed674d
--- /dev/null
+++ b/src/common/cpu_profiler.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2015, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include
+#include
+
+#include "common/cpu_profiler.h"
+
+namespace tera {
+
+CpuProfiler::CpuProfiler()
+ : exit_(false),
+ thread_(&CpuProfiler::run, this) {}
+
+CpuProfiler::~CpuProfiler() {
+ exit_ = true;
+ cv_.notify_one();
+ thread_.join();
+ ProfilerState ps;
+ ProfilerGetCurrentState(&ps);
+ if (ps.enabled) {
+ ProfilerStop();
+ }
+}
+
+void CpuProfiler::run() {
+ while (!exit_.load()) {
+ if (enable_) {
+ ProfilerState ps;
+ ProfilerGetCurrentState(&ps);
+ if (ps.enabled == 0) {
+ ProfilerStart(profiler_file_.c_str());
+ }
+
+ ProfilerFlush();
+ LOG(INFO) << "[Cpu Profiler] Cpu Profiler Dumped";
+ } else {
+ ProfilerState ps;
+ ProfilerGetCurrentState(&ps);
+ if (ps.enabled) {
+ ProfilerStop();
+ }
+ }
+ std::unique_lock lock(lock_);
+ cv_.wait_for(lock, interval_);
+ }
+}
+
+} // namespace tera
\ No newline at end of file
diff --git a/src/common/cpu_profiler.h b/src/common/cpu_profiler.h
new file mode 100644
index 000000000..ccf0686ab
--- /dev/null
+++ b/src/common/cpu_profiler.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2015, Baidu.com, Inc. All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TERA_CPU_PROFILER_H
+#define TERA_CPU_PROFILER_H
+
+#include
+#include
+#include
+#include
+#include