提交 85766f9f 编写于 作者: O oceanbase-admin

init push

上级

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
###### lines below this line must be placed at the top of the file
unittest/**/test_*
unittest/**/*_test
unittest/**/**/test_*
unittest/**/**/*_test
unittest/**/unittest_*
!unittest/**/test_*.*
!unittest/**/**/test_*.*
!unittest/**/unittest_*.*
###### lines above this line must be placed at the top of the file
tools/deploy/obperf
tools/deploy/sysbench
tools/deploy/bin
tools/deploy/bin/*
tools/deploy/lib
tools/deploy/tools
.configured
Makefile.in
Makefile.d
Makefile
aclocal.m4
autom4te.cache/
build/
build
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
libtool
compile
.libs
*.bak
*.o
*.a
*.la
*.lo
*.pyc
*.log
*.log.wf
.deps*
*.gcno
*.gcda
*.orig
*.swn
*checker
Makefile.in
Makefile
*.gcov
*my
paratest*
tags
TAGS
.clang_complete
src/election/election
src/election/election_admin
src/lib/regex/regex/re
src/lib/regex/strings/conf_to_src
src/sql/parser/*.output
src/observer/observer
src/observer/*:*
src/obproxy/iocore/eventsystem/test_event
src/obproxy/iocore/net/test_net
src/obproxy/obproxy
src/obproxy/opsql/*.output
src/client/*
coverage/
doc/**/*.html
!doc/*/Makefile
tools/deploy/config*.py
tools/deploy/lib/
tools/deploy/nohup*
tools/deploy/mytest.log*
tools/deploy/mysql_test/r/*.reject
tools/deploy/syschecker/gen_sstable.conf
tools/deploy/syschecker/gen_sstable.schema
src/sql/parser/expr_parser.output
src/sql/parser/sql_parser.output
unittest/sql/executor/rpc_remote_scheduler
unittest/sql/executor/stress_interm_result_manager
unittest/sql/executor/stress_scanner_pool
*~
cscope.*
build_version.c
build_version.cpp
BROWSE
ltmain.sh
missing
*.patch
svn_dist_version
GPATH
GRTAGS
GTAGS
coverage.zip
app.info
.review/
.configured
observer.log*
launch_bootstrap
major_freeze
*.pyc
tools/deploy/bin/
tools/deploy/mysql_test/r/*.reject
tools/deploy/list
tools/storage_perf/storage_perf
unittest/clog/deploy/log_tool
unittest/clog/deploy/ob_server_main
unittest/clog/deploy/post_msg_main
obproxy_config.bin
obproxy.*
*.tmp
*.temp.*
.project
.cproject
/.settings/
.pydevproject
ncscope.out
*.swp
.dep_create/
multiplog_*
src/lib/oberror
src/liboblog/tests/oblog_tailf
.ob-pretest.result
*.run.*
*.reject
unittest/sql/engine/expr/arithmatic.out
unittest/sql/engine/expr/*_test
unittest/sql/engine/*/test_*
unittest/storage/blocksstable/query_speed_tool
unittest/storage/exception_transaction/ob_exception_transaction
unittest/storage/storage_bench
unittest/rpc/rpc_bench
unittest/storage/tmp
unittest/storage/sstable
unittest/storage/libnone.so
unittest/storage/blocksstable/clog/
unittest/storage/blocksstable/libnone.so
unittest/storage/blocksstable/ob_test_data_file
unittest/storage/blocksstable/redo_log_test/
unittest/storage/blocksstable/scanner/
unittest/obproxy/*checker
unittest/obproxy/failed.result
unittest/obproxy/failed.sql
unittest/obproxy/.conf/
unittest/obproxy/etc/
unittest/common/kv_storecache
unittest/common/small_allocator
unittest/lib/*.log*
.dirstamp
svn_version.c
tools/deploy/collected_log/
tools/deploy/config1.py
unittest/sql/optimizer/cost_model_util
unittest/sql/resolver/ddl_resolver
tools/storage_test/storagetest
tools/log_parser/slog_parser
tools/log_tool/log_statistics
tools/log_tool/log_tool
tools/ob_admin/ob_admin
tools/omtest/client
tools/omtest/omtest
tools/trace/trace_tool
unittest/storage/transaction/performance
tools/log_tool/logtool
unittest/lib/hash.data
Build (GNU)
tools/deploy/avg_rt_*
tools/deploy/focus_*
!src/rpc/easy/**
.idea/*
src/.idea/*
src/cmake-build-debug/*
CMakeLists.txt
.DS_Store
src/.DS_Store
unittest/.DS_Store
ob_proxy_parser.output
deps/3rd/home
deps/3rd/var
deps/3rd/usr
deps/3rd/pkg
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity, and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at info@oceanbase.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality about the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4.
For answers to common questions about this code of conduct, see [FAQ](https://www.contributor-covenant.org/faq).
# How to contribute
ODP is a community-driven open source project and we welcome all the contributors. Contributions to the ODP project are expected to adhere to our [Code of Conduct](CODE_OF_CONDUCT.md).
## Before you contribute
Before you contribute, please click the **Sign in with Github to agree button** to sign the CLA. You can find an example [here](https://cla-assistant.io/pingcap/tidb?pullRequest=16303).
What is [CLA](https://en.wikipedia.org/wiki/Contributor_License_Agreement)?
## Contribution guide
Please follow these steps to create your Pull Request to this repository.
> **Note:**
>
> This section takes creating a PR to the `master` branch as an example. The steps of creating PRs for other branches are similar.
### Step 1: Fork the repository
1. Visit the project (link TODO)
2. Click the **Fork** button to establish an online fork.
### Step 2: Clone your fork to local
```bash
# Define your working directory
working_dir=$HOME/Workspace
# Configure GitHub
user={your Github profile name}
# Create your clone
mkdir -p $working_dir
cd $working_dir
git clone link TODO
# Add upstream
git remote add upstream link TODO
# Set no push for the upstream master
git remote set-url --push upstream no_push
# Confirm your remote setting
git remote -v
```
### Step 3: Create a new branch
1. Get your local master up-to-date with the upstream/master.
```bash
cd $working_dir/docs
git fetch upstream
git checkout master
git rebase upstream/master
```
2. Create a new branch based on the master branch.
```bash
git checkout -b new-branch-name
```
### Step 4: Develop
Edit some file(s) on the `new-branch-name` branch and save your changes.
### Step 5: Commit your changes
```bash
git status # Checks the local status
git add <file> ... # Adds the file(s) you want to commit. If you want to commit all changes, you can directly use `git add.`
git commit -m "commit-message: update the xx"
```
### Step 6: Keep your branch in sync with upstream/master
```bash
# While on your new branch
git fetch upstream
git rebase upstream/master
```
### Step 7: Push your changes to the remote
```bash
git push -u origin new-branch-name # "-u" is used to track the remote branch from the origin
```
### Step 8: Create a pull request
1. Visit your fork at <https://github.com/$user/docs> (replace `$user` with your GitHub account).
2. Click the `Compare & pull request` button next to your `new-branch-name` branch to create your PR.
此差异已折叠。
EXTRA_DIST=build.sh svn_dist_version script/deploy unittest/Makefile.in unittest/obproxy/Makefile.in deps/easy
bin_SCRIPTS=script/deploy/obproxyd.sh
if WITH_TEST_CASE
TEST_DIR:=unittest
endif
SUBDIRS=src $(TEST_DIR)
DIST_SUBDIRS=src $(TEST_DIR)
utest: check
.PHONY: utest
# rules to auto generate build_version.c
include $(top_srcdir)/build_version.mk
# OceanBase Database Proxy
TODO: some badges here
OceanBase Database Proxy(简称 ODP)是 OceanBase 数据库专用的代理服务器。OceanBase 数据库的用户数据以多副本的形式存放在各个 OBServer 上,ODP 接收用户发出的 SQL 请求,并将 SQL 请求转发至最佳目标 OBServer,最后将执行结果返回给用户。
## 快速使用
请查看快速使用指南[link TODO]开始试用 ODP。
## 文档
- 简体中文 [link TODO]
- 英文(English) [link TODO]
## 许可证
ODP 使用 [MulanPubL - 2.0](https://license.coscl.org.cn/MulanPubL-2.0/index.html) 许可证。您可以免费复制及使用源代码。当您修改或分发源代码时,请遵守木兰协议。
## 如何贡献
我们十分欢迎并感谢您为我们贡献。以下是您参与贡献的几种方式:
- 向我们提 issue [link TODO]。
- 提交 PR。详情参见[如何贡献](CONTRIBUTING.md)
## 获取帮助
如果您在使用 ODP 时遇到任何问题,欢迎通过以下方式寻求帮助:
- GitHub Issue [link TODO]
- 官方论坛 [link TODO]
- 知识问答 [link TODO]
# OceanBase Database Proxy
TODO: some badges here
OceanBase Database Proxy (ODP for short) is a dedicated proxy server for OceanBase Database. OceanBase Database stores its user data in multiple copies on different OBServers. ODP receives the SQL requests from the users, transfers the SQL requests to the target OBServer, then returns the execution results to the users.
## Quick start
Refer to the Get Started guide [link TODO] to try out ODP.
## Documentation
- English [link TODO]
- Simplified Chinese (简体中文) [link TODO]
## Licencing
ODP is under [MulanPubL - 2.0](https://license.coscl.org.cn/MulanPubL-2.0/index.html) licence. You can freely copy and use the source code. When you modify or distribute the source code, please obey the MulanPubL - 1.0 licence.
## Contributing
Contributions are warmly welcomed and greatly appreciated. Here are a few ways you can contribute:
- Raise us an issue [link TODO].
- Submit Pull Requests. For details, see [How to contribute](CONTRIBUTING.md).
## Support
In cease you have any problems when using OceanBase Database, welcome reach out for help:
- GitHub Issue [link TODO]
- Official forum [link TODO]
- Knowledge base [link TODO]
#!/bin/sh
TOPDIR="$(dirname $(readlink -f "$0"))"
DEP_DIR=${TOPDIR}/deps/3rd/usr/local/oceanbase/deps/devel
TOOLS_DIR=${TOPDIR}/deps/3rd/usr/local/oceanbase/devtools
RUNTIME_DIR=${TOPDIR}/deps/3rd/home/admin/oceanbase
MAKE_ARGS=(-j $CPU_CORES)
function sw()
{
export DEP_DIR;
export TOOLS_DIR;
export RUNTIME_DIR;
export DEP_VAR=$DEP_DIR/var/;
/sbin/ldconfig -n $DEP_DIR/lib;
export LD_LIBRARY_PATH=$DEP_DIR/lib:$DEP_VAR/usr/local/lib64:$DEP_VAR/usr/local/lib:$DEP_VAR/usr/lib64:$DEP_VAR/usr/lib;
export LIBRARY_PATH=$DEP_DIR/lib:$DEP_VAR/usr/local/lib64:$DEP_VAR/usr/local/lib:$DEP_VAR/usr/lib64:$DEP_VAR/usr/lib;
export CPLUS_INCLUDE_PATH=$DEP_DIR/include:${RUNTIME_DIR}/include:$DEP_VAR/usr/local/include:$DEP_VAR/usr/include;
export C_INCLUDE_PATH=$DEP_DIR/include:${RUNTIME_DIR}/include;
export PATH=$DEP_DIR/bin:$TOOLS_DIR/bin:$PATH;
}
export AUTOM4TE="autom4te"
export AUTOCONF="autoconf"
function do_init()
{
set -x
sw
aclocal
libtoolize --force --copy --automake
autoconf --force
automake --foreign --copy --add-missing -Woverride -Werror
}
function do_dep_init()
{
(cd $TOPDIR/deps/3rd && sh dep_create.sh)
cd $TOPDIR
do_init
}
function do_clean()
{
echo 'cleaning...'
make distclean >/dev/null 2>&1
rm -rf autom4te.cache
for fn in aclocal.m4 configure config.guess config.sub depcomp install-sh \
ltmain.sh libtool missing mkinstalldirs config.log config.status Makefile; do
rm -f $fn
done
find . -name Makefile.in -exec rm -f {} \;
find . -path ./tools/codestyle/astyle/build -prune -o -path ./doc -prune -o -name Makefile -exec rm -f {} \;
find . -name .deps -prune -exec rm -rf {} \;
echo 'done'
}
function do_config()
{
set -x
sw
case "x$1" in
xdebug)
# configure for developers
./configure --with-gcc-version=5.2.0 --with-coverage=no --enable-buildtime=no --enable-strip-ut=no --enable-silent-rules --enable-dlink-observer=no
echo -e "\033[31m ===build debug version=== \033[0m"
;;
xgcov)
# configure for release
./configure --with-gcc-version=5.2.0 --with-coverage=yes --enable-buildtime=no --enable-strip-ut=no --enable-silent-rules --enable-dlink-observer=no
echo -e "\033[31m ===build gcov version=== \033[0m"
;;
*)
# configure for release
./configure --with-gcc-version=5.2.0 --with-coverage=no --enable-buildtime=no --enable-strip-ut=no --enable-silent-rules --enable-dlink-observer=no --with-release
echo -e "\033[31m ===build release version=== \033[0m"
;;
esac
}
function do_make()
{
set -x
sw
make "${MAKE_ARGS[@]}"
}
function do_rpm()
{
set -x
sw
PACKAGE=obproxy
VERSION=3.1.0
RELEASE=1
PREFIX=/home/admin/obproxy
SPEC_FILE=obproxy.spec
echo "[BUILD] make dist..."
make dist-gzip || exit 1
TMP_DIR=/${TOPDIR}/obproxy-tmp.$$
echo "[BUILD] create tmp dirs...TMP_DIR=${TMP_DIR}"
mkdir -p ${TMP_DIR}
mkdir -p ${TMP_DIR}/BUILD
mkdir -p ${TMP_DIR}/RPMS
mkdir -p ${TMP_DIR}/SOURCES
mkdir -p ${TMP_DIR}/SRPMS
cp obproxy-${VERSION}.tar.gz ${TMP_DIR}/SOURCES
cd ${TMP_DIR}/BUILD
echo "[BUILD] make rpms..._prefix=${PREFIX} spec_file=${SPEC_FILE}"
rpmbuild --define "_topdir ${TMP_DIR}" --define "NAME ${PACKAGE}" --define "VERSION ${VERSION}" --define "_prefix ${PREFIX}" --define "RELEASE ${RELEASE}" -ba ${TOPDIR}/deps/3rd/${SPEC_FILE} || exit 2
echo "[BUILD] make rpms done."
cd ${TOPDIR}
find ${TMP_DIR}/RPMS/ -name "*.rpm" -exec mv '{}' ./ \;
rm -rf ${TMP_DIR}
}
case "x$1" in
xinit)
do_dep_init
;;
xqinit)
do_init
;;
xclean)
do_clean
;;
xconfig)
do_config $2
;;
xmake)
do_make
;;
xrpm)
do_dep_init
do_config
do_rpm
;;
*)
do_dep_init
do_config
do_make
;;
esac
BUILT_SOURCES=build_version.c
CLEANFILES=build_version.c
if UPDATE_BUILDTIME
if HAVESVNWC
$(top_srcdir)/svn_dist_version: $(top_srcdir)/FORCE
@revision@ > $@
endif
build_version.c: $(top_srcdir)/FORCE
echo -n 'const char* build_version() { return "' > $@ && @revision@ | tr -d '\n' >> $@ && echo '"; }' >> $@
echo 'const char* build_date() { return __DATE__; }' >> $@
echo 'const char* build_time() { return __TIME__; }' >> $@
echo -n 'const char* build_flags() { return "' >> $@ && echo -n $(AM_CXXFLAGS) $(CXXFLAGS) |sed s/\"//g >> $@ && echo '"; }' >> $@
$(top_srcdir)/FORCE:
else
if HAVESVNWC
$(top_srcdir)/svn_dist_version:
@revision@ > $@
endif
build_version.c:
echo -n 'const char* build_version() { return "' > $@ && @revision@ | tr -d '\n' >> $@ && echo '"; }' >> $@
echo 'const char* build_date() { return __DATE__; }' >> $@
echo 'const char* build_time() { return __TIME__; }' >> $@
echo -n 'const char* build_flags() { return "' >> $@ && echo -n $(AM_CXXFLAGS) $(CXXFLAGS) |sed s/\"//g >> $@ && echo '"; }' >> $@
endif
AC_INIT([OceanBase],
[3.1.0],
[huating.zmq@alipay.com],
[obproxy],
[http://oceanbase.taobao.org/])
obapi_version="3.1.0"
AC_SUBST(obapi_version)
AC_DISABLE_STATIC
AC_PROG_RANLIB
AC_PROG_LIBTOOL
AM_INIT_AUTOMAKE([subdir-objects silent-rules])
ac_default_prefix=${HOME}/oceanbase_bin # for convenience
AC_PROG_CXX
AC_LANG([C++])
AC_SUBST([host_cpu])
AC_PROG_CC
AC_CANONICAL_HOST
dnl configure compiler flags
AC_ARG_WITH([release],
AS_HELP_STRING([--with-release],
[use optimize (default is NO)]),
[
if test "$withval" = "yes"; then
case "$host_cpu" in
*aarch64* )
AM_CXXFLAGS="-g -O2 -D_OB_VERSION=1000 -D_NO_EXCEPTION -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -DNDEBUG -D__USE_LARGEFILE64 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -Wall -Wextra -Wunused-parameter -Wformat -Wconversion -Wno-deprecated -Wno-invalid-offsetof -finline-functions -fno-strict-aliasing -mtune=generic -Wno-psabi -Wno-sign-compare"
AM_CFLAGS="-g -O2 -D_OB_VERSION=1000 -DCOMPATIBLE -D__USE_LARGEFILE64 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DNDEBUG -finline-functions -fno-strict-aliasing -Wall -mtune=generic -Wno-psabi -Wno-sign-compare"
;;
* )
AM_CXXFLAGS="-g -O2 -D_OB_VERSION=1000 -D_NO_EXCEPTION -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -DNDEBUG -D__USE_LARGEFILE64 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -Wall -Wextra -Wunused-parameter -Wformat -Wconversion -Wno-deprecated -Wno-invalid-offsetof -finline-functions -fno-strict-aliasing -mtune=core2 -Wno-psabi -Wno-sign-compare"
AM_CFLAGS="-g -O2 -D_OB_VERSION=1000 -DCOMPATIBLE -D__USE_LARGEFILE64 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DNDEBUG -finline-functions -fno-strict-aliasing -Wall -mtune=core2 -Wno-psabi -Wno-sign-compare"
;;
esac
fi
],
[ AM_CXXFLAGS="-D__STDC_LIMIT_MACROS -D_OB_VERSION=1000 -D__STDC_CONSTANT_MACROS -D_NO_EXCEPTION -g -Wall -Wextra -Wunused-parameter -Wformat -Wconversion -Wno-invalid-offsetof -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -mtune=generic -Wno-psabi -Wno-sign-compare"
AM_CFLAGS="-D_OB_VERSION=1000 -DCOMPATIBLE -D__USE_LARGEFILE64 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fno-omit-frame-pointer -g -Wall -Wno-psabi -Wno-sign-compare"
]
)
#check gcc version, add -Wno-ignored-qualifiers flag for gcc version greater than 4.3.0
GCC_VERSION=`$CC -dumpversion`
if test $? -eq 0; then
major=`echo $GCC_VERSION | cut -d. -f1`
minor=`echo $GCC_VERSION | cut -d. -f2`
fi
if test $major -eq 4 -a $minor -ge 3 ; then
AM_CXXFLAGS="${AM_CXXFLAGS} -Wno-ignored-qualifiers"
else test $major -eq 5 -a $minor -eq 2;
AM_CXXFLAGS="${AM_CXXFLAGS} -DGCC_52"
fi
gcc_version="4.4.4"
dnl condition OPT_GCC_VERSION
AC_ARG_WITH([gcc-version],
AS_HELP_STRING([--with-gcc-version],
[opt gcc version (default is 4.4.4)]),
[
if test ! -z $withval; then
gcc_version=$withval
fi
],
[gcc_version="4.4.4"])
if test "X$gcc_version" != "X$GCC_VERSION"; then
echo "you choice gcc: ${gcc_version}, but now gcc is: $GCC_VERSION"
exit 127
fi
OSVER=`cat /etc/issue|head -1|awk -F. '{print $1}' | awk '{print $NF}'`
if test $OSVER -le 6; then
AM_CXXFLAGS="${AM_CXXFLAGS} -DUSE_POSIX_FALLOCATE"
fi
support_sse4_2=`cat /proc/cpuinfo|grep flags|head -1|grep -oE sse4_2`
if test "$support_sse4_2" = "sse4_2" ; then
AM_CXXFLAGS="${AM_CXXFLAGS} -DSUPPORT_SSE4_2"
fi
AC_ARG_WITH([atomic-time],
AS_HELP_STRING([--with-atomic-time],
[record atomic instructions time (default is NO)]),
[
if test "$withval" == "yes"; then
AM_CXXFLAGS="${AM_CXXFLAGS} -DATOMIC_TIME_PERF"
fi
],
[])
AC_ARG_WITH([memory-check],
AS_HELP_STRING([--with-memory-check],
[memory check (defualt is NO)]),
[
if test "$withval" = "yes"; then
AM_CXXFLAGS="${AM_CXXFLAGS} -DMEMCHK_LEVEL=1"
fi
],
[])
AC_ARG_WITH([perf],
AS_HELP_STRING([--with-perf],
[with perf (default is NO)]),
[
if test "$withval" = "yes"; then
test_perf=yes
AM_CXXFLAGS="${AM_CXXFLAGS} -D__NEED_PERF__"
AM_LDFLAGS="${AM_LDFLAGS} -lprofiler"
fi
],
[with_perf=no]
)
AC_ARG_WITH([5u-support],
AS_HELP_STRING([--with-5u-support],
[with 5u support (default is NO)]),
[
if test "$withval" = "yes"; then
support5u=yes
fi
],
[support5u=no]
)
if test $support5u = "no"
then
AM_CXXFLAGS="${AM_CXXFLAGS} -DHAVE_SCHED_GETCPU -DHAVE_REALTIME_COARSE -DOB_HAVE_EVENTFD -DHAVE_FALLOCATE"
fi
AM_CONDITIONAL([SUPPORT5U], test x$support5u = xno )
AC_ARG_WITH([preload],
AS_HELP_STRING([--with-preload],
[with preload (default is NO)]),
[
if test "$withval" = "yes"; then
with_preload=yes
AM_CXXFLAGS="${AM_CXXFLAGS} -D__ENABLE_PRELOAD__"
fi
],
[
with_preload=no
]
)
AC_ARG_WITH([mem-trace],
AS_HELP_STRING([--with-mem-trace],
[with memory trace (default is NO)]),
[
if test "$withval" = "yes"; then
memtrace=yes
fi
],
[memtrace=no]
)
if test $memtrace = "yes"
then
AM_CXXFLAGS="${AM_CXXFLAGS} -D__OB_MTRACE__ -rdynamic"
fi
AM_CONDITIONAL([MEMTRACE], test x$memtrace = xyes )
AC_ARG_WITH([mem-debug],
AS_HELP_STRING([--with-mem-debug],
[with memory debug features (default is NO)]),
[
if test "$withval" = "yes"; then
memdebug=yes
fi
],
[memdebug=no]
)
if test $memdebug = "yes"
then
AM_CXXFLAGS="${AM_CXXFLAGS} -D__OB_MDEBUG__"
fi
AM_CONDITIONAL([MEMDEBUG], test x$memdebug = xyes )
AM_LDFLAGS="${AM_LDFLAGS} -L${DEP_DIR}/lib -L${DEP_DIR}/lib/mysql"
dnl global default INCLUDES
AM_CPPFLAGS="${AM_CPPFLAGS} -I${DEP_DIR}/include -I${DEP_DIR}/include/mysql"
if test "X${CXXFLAGS}" = "X-g -O2"; then
CXXFLAGS=""
fi
if test "X${CFLAGS}" = "X-g -O2"; then
CFLAGS=""
fi
dnl condition COVERAGE
AC_ARG_WITH([coverage],
AS_HELP_STRING([--with-coverage],
[with coverage (default is NO)]),
[case "${withval}" in
yes) coverage=true ;;
no) coverage=false ;;
*) AC_MSG_ERROR([bad value ${withval} for --with-coverage]) ;;
esac
],
[coverage=false]
)
AM_CONDITIONAL([COVERAGE], test x$coverage = xtrue )
if test "X$coverage" = X"true"; then
AM_CXXFLAGS="${AM_CXXFLAGS} -fprofile-arcs -ftest-coverage -DTEST_COVER"
AM_CFLAGS="${AM_CFLAGS} -fprofile-arcs -ftest-coverage -DTEST_COVER"
AM_LDFLAGS="${AM_LDFLAGS} -lgcov"
fi
dnl define global flags
AC_SUBST([AM_CPPFLAGS])
AC_SUBST([AM_LDFLAGS])
AC_SUBST([AM_CXXFLAGS])
AC_SUBST([AM_CFLAGS])
AC_SUBST([AM_CXXFLAGS_WITH_ARCH])
AC_SUBST([AM_CFLAGS_WITH_ARCH])
dnl condition WITH_TEST_CASE
AC_ARG_WITH([test_case],
AS_HELP_STRING([--with-test-case],
[with test case (default is YES)]),
[
if test "$withval" = "no"; then
test_case=no
fi
],
[ test_case=yes ]
)
AM_CONDITIONAL([WITH_TEST_CASE], test x$test_case = xyes )
AC_ARG_WITH([simplify_verification],
AS_HELP_STRING([--with-simplify-verification],
[with simplify verification (default is NO)]),
[
if test "$withval" = "yes"; then
AC_DEFINE(SIMPLIFY_VERIFICATION)
fi
],
[ echo "simplify-verification is no" ]
)
dnl strip_ut
AC_ARG_ENABLE([strip_ut],
AS_HELP_STRING([--enable-strip-ut], [strip unit test binaries. (default is NO)]),
[case "${enableval}" in
yes) strip_ut=true ;;
no) strip_ut=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-strip-ut]) ;;
esac],
[strip_ut=false])
AM_CONDITIONAL([STRIP_UT], [test x$strip_ut = xtrue])
dnl dlink_observer
AC_ARG_ENABLE([dlink_observer],
AS_HELP_STRING([--enable-dlink-observer], [unit test dynamic link observer. (default is NO)]),
[case "${enableval}" in
yes) dlink_observer=true ;;
no) dlink_observer=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-dlink-observer]) ;;
esac],
[dlink_observer=false])
AM_CONDITIONAL([DLINK_OBSERVER], [test x$dlink_observer = xtrue])
dnl build_version.mk related:
dnl see whether git is installed
AC_PATH_PROG(svnversioncommand, git)
AC_ARG_WITH([svnfile],
AS_HELP_STRING([--with-svnfile],
[use svnfile svn_dist_version instead of running git (default is NO)]),
[
if test "$withval" = "yes"; then
use_svnfile=yes
fi
],
[use_svnfile=no]
)
dnl use git to record the current repository revision only if
dnl git is installed and we are in a working copy
if test "X$use_svnfile" = "Xyes"; then
revision="cat \$(top_srcdir)/svn_dist_version"
build_num="$($revision)"
AM_CONDITIONAL([HAVESVNWC], false)
elif test "X$svnversioncommand" = "X"; then
revision="-"
build_num="$($revision)"
AM_CONDITIONAL([HAVESVNWC], true)
elif test "X$AONE_BUILD_NUMBER" != "X"; then
build_num="$AONE_BUILD_NUMBER"
revision="(cd \$(top_srcdir) && echo $AONE_BUILD_NUMBER-$(git rev-parse HEAD))"
AM_CONDITIONAL([HAVESVNWC], true)
else
build_num="$(git rev-list --all | wc -l)"
revision="(cd \$(top_srcdir) && echo $build_num-local-$(git rev-parse HEAD))"
AM_CONDITIONAL([HAVESVNWC], true)
fi
dnl substitute revision in build_version.mk
AC_SUBST(revision)
dnl define RELEASEID
AC_ARG_VAR([RELEASEID], [release number when building in Taobao ABS])
if test "X$RELEASEID" = "X"; then
RELEASEID="$build_num.el$(cat /etc/redhat-release | cut -d " " -f 7 | cut -d "." -f 1)"
fi
AC_DEFINE_UNQUOTED([RELEASEID], "$RELEASEID")
dnl LDADD
AM_LDFLAGS="${AM_LDFLAGS} -Wl,--allow-multiple-definition"
BIN_LDFLAGS="-lc -lrt"
if test "X5.2.0" = "X$GCC_VERSION"; then
AM_LDFLAGS="${AM_LDFLAGS} -static-libstdc++ -static-libgcc"
BIN_LDFLAGS="${BIN_LDFLAGS} ${TOOLS_DIR}/lib64/libstdc++.a"
postdeps_CXX=`echo " $postdeps_CXX " | sed 's, -lstdc++ ,,g'`
fi
AC_SUBST(BIN_LDFLAGS)
dnl with-buildtime
AC_ARG_ENABLE([buildtime],
AS_HELP_STRING([--enable-buildtime], [auto-update build_time, build_version etc. (default is YES)]),
[case "${enableval}" in
yes) buildtime=true ;;
no) buildtime=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-buildtime]) ;;
esac],
[buildtime=true])
AM_CONDITIONAL([UPDATE_BUILDTIME], [test x$buildtime = xtrue])
dnl condition WITH_MYSQLTEST
AC_ARG_WITH([mysqltest],
AS_HELP_STRING([--with-mysqltest],
[whether to build mysqltest (default is NO)]),
[],
[with_mysqltest="no"])
AM_CONDITIONAL([WITH_MYSQLTEST], test x$with_mysqltest = xyes)
dnl condition 7U_SUPPORT
AC_ARG_WITH([7u-support],
AS_HELP_STRING([--with-7u-support],
[with 7u support (default is NO)]),
[
if test "$withval" == "yes"; then
BIN_LDFLAGS="-lc -lrt -pthread ${TOOLS_DIR}/lib64/libstdc++.a"
fi
],
[])
AC_CONFIG_FILES([\
Makefile \
src/Makefile \
unittest/Makefile \
unittest/obproxy/Makefile
])
AM_CXXFLAGS_WITH_ARCH="${AM_CXXFLAGS}"
AM_CFLAGS_WITH_ARCH="${AM_CFLAGS}"
if test $OSVER -gt 6; then
AM_CXXFLAGS_WITH_ARCH="${AM_CXXFLAGS_WITH_ARCH} -Werror"
AM_CFLAGS_WITH_ARCH="${AM_CFLAGS_WITH_ARCH} -Werror"
fi
AM_CXXFLAGS="${AM_CXXFLAGS} -Werror"
AM_CFLAGS="${AM_CFLAGS} -Werror"
AC_OUTPUT
dnl print global flags
AC_MSG_RESULT([Global Compile Flags:])
AC_MSG_RESULT([DEP_DIR=${DEP_DIR}])
AC_MSG_RESULT([TOOLS_DIR=${TOOLS_DIR}])
AC_MSG_RESULT([RUNTIME_DIR=${RUNTIME_DIR}])
AC_MSG_RESULT([AM_CPPFLAGS=${AM_CPPFLAGS}])
AC_MSG_RESULT([AM_LDFLAGS=${AM_LDFLAGS}])
AC_MSG_RESULT([AM_CXXFLAGS=${AM_CXXFLAGS}])
AC_MSG_RESULT([AM_CFLAGS=${AM_CFLAGS}])
AC_MSG_RESULT([AM_CXXFLAGS_WITH_ARCH=${AM_CXXFLAGS_WITH_ARCH}])
AC_MSG_RESULT([AM_CFLAGS_WITH_ARCH=${AM_CFLAGS_WITH_ARCH}])
AC_MSG_RESULT([BIN_LDFLAGS=${BIN_LDFLAGS}])
#!/bin/bash
#clear env
unalias -a
PWD="$(cd $(dirname $0); pwd)"
OS_RELEASE="$(grep -Po '(?<=release )\d' /etc/redhat-release)" || exit 1
OS_ARCH="$(uname -p)" || exit 1
OS_TAG="el$OS_RELEASE.$OS_ARCH"
DEP_FILE="obproxy.${OS_TAG}.deps"
echo -e "check dependencies profile for ${OS_TAG}... \c"
if [[ ! -f "${DEP_FILE}" ]]; then
echo "NOT FOUND" 1>&2
exit 2
else
echo "FOUND"
fi
mkdir "${PWD}/pkg" >/dev/null 2>&1
echo -e "check repository address in profile... \c"
REPO="$(grep -Po '(?<=repo=).*' "${DEP_FILE}" 2>/dev/null)"
if [[ $? -eq 0 ]]; then
echo "$REPO"
else
echo "NOT FOUND" 1>&2
exit 3
fi
echo "download dependencies..."
RPMS="$(grep '\.rpm' "${DEP_FILE}" | grep -Pv '^#')"
for pkg in $RPMS
do
if [[ -f "${PWD}/pkg/${pkg}" ]]; then
echo "find package <${pkg}> in cache"
else
echo -e "download package <${pkg}>... \c"
TEMP=$(mktemp -p "/" -u ".${pkg}.XXXX")
DOWNLOAD_URL="${REPO}/${pkg}"
if [[ $pkg == "oceanbase-ce"* ]]; then
DOWNLOAD_URL="https://mirrors.aliyun.com/oceanbase/community/stable/el/$OS_RELEASE/$OS_ARCH/${pkg}"
fi
wget "$DOWNLOAD_URL" -q -O "${PWD}/pkg/${TEMP}"
if [[ $? -eq 0 ]]; then
mv -f "${PWD}/pkg/$TEMP" "${PWD}/pkg/${pkg}"
echo "SUCCESS"
else
rm -rf "${PWD}/pkg/$TEMP"
echo "FAILED" 1>&2
exit 4
fi
fi
echo -e "unpack package <${pkg}>... \c"
rpm2cpio "${PWD}/pkg/${pkg}" | cpio -di -u --quiet
if [[ $? -eq 0 ]]; then
echo "SUCCESS"
else
echo "FAILED" 1>&2
exit 5
fi
done
[target]
os=7
arch=x86_64
repo=https://mirrors.aliyun.com/oceanbase/development-kit/el/7/x86_64/
[deps]
devdeps-openssl-static-1.0.1e-3.el7.x86_64.rpm
devdeps-libcurl-static-7.29.0-3.el7.x86_64.rpm
devdeps-mariadb-connector-c-3.1.12-3.el7.x86_64.rpm
devdeps-prometheus-cpp-0.8.0-3.el7.x86_64.rpm
devdeps-gtest-1.8.0-3.el7.x86_64.rpm
devdeps-grpc-1.20.1-3.el7.x86_64.rpm
[tools]
obdevtools-gcc-5.2.0-3.el7.x86_64.rpm
obdevtools-bintuils-2.30-3.el7.x86_64.rpm
obdevtools-bison-2.4.1-3.el7.x86_64.rpm
obdevtools-flex-2.5.35-3.el7.x86_64.rpm
[release]
oceanbase-ce-sql-parser-3.1.0-1.el7.x86_64.rpm
[target]
os=8
arch=x86_64
repo=https://mirrors.aliyun.com/oceanbase/development-kit/el/8/x86_64/
[deps]
devdeps-openssl-static-1.0.1e-3.el8.x86_64.rpm
devdeps-libcurl-static-7.29.0-3.el8.x86_64.rpm
devdeps-mariadb-connector-c-3.1.12-3.el8.x86_64.rpm
devdeps-prometheus-cpp-0.8.0-3.el8.x86_64.rpm
devdeps-gtest-1.8.0-3.el8.x86_64.rpm
devdeps-grpc-1.20.1-3.el8.x86_64.rpm
[tools]
obdevtools-gcc-5.2.0-3.el8.x86_64.rpm
obdevtools-bintuils-2.30-3.el8.x86_64.rpm
obdevtools-bison-2.4.1-3.el8.x86_64.rpm
obdevtools-flex-2.5.35-3.el8.x86_64.rpm
[release]
oceanbase-ce-sql-parser-3.1.0-1.el8.x86_64.rpm
# Copyright (c) 2021 OceanBase
# OceanBase Database Proxy(ODP) is licensed under Mulan PubL v2.
# You can use this software according to the terms and conditions of the Mulan PubL v2.
# You may obtain a copy of Mulan PubL v2 at:
# http://license.coscl.org.cn/MulanPubL-2.0
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PubL v2 for more details.
Name: %NAME
Version: %VERSION
Release: %{RELEASE}%{?dist}
Summary: OceanBase Database Proxy
Group: Applications/Databases
URL: http://oceanbase.alibaba-inc.com/
Packager: yiming.czw
License: Mulan PubL v2
Prefix: %{_prefix}
Source:%{NAME}-%{VERSION}.tar.gz
BuildRoot: %(pwd)/%{name}-root
Autoreq: no
%description
OceanBase Database Proxy
%define _unpackaged_files_terminate_build 0
%undefine _missing_build_ids_terminate_build 0
%define __debug_install_post %{_rpmconfigdir}/find-debuginfo.sh %{?_find_debuginfo_opts} "%{_builddir}/%{?buildsubdir}" %{nil}
%define debug_package %{nil}
%define install_dir /home/admin/obproxy-%{version}
%prep
%setup
%build
./configure CXX=${CXX} CC=${CC} --with-gcc-version=5.2.0 RELEASEID=%{RELEASE} --prefix=%{_prefix} --with-test-case=no --with-release=yes --with-tblib-root=/opt/csr/common --with-easy-root=/usr --with-easy-lib-path=/usr/lib64 --with-svnfile --enable-shared=default --enable-silent-rules
mkdir -p unittest
make %{?_smp_mflags}
%install
make DESTDIR=$RPM_BUILD_ROOT install
mkdir -p $RPM_BUILD_ROOT%{install_dir}/bin
cp src/obproxy/obproxy $RPM_BUILD_ROOT%{install_dir}/bin
cp script/deploy/obproxyd.sh $RPM_BUILD_ROOT%{install_dir}/bin
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-, admin, admin)
%dir %{install_dir}/bin
%{install_dir}/bin/obproxy
%{install_dir}/bin/obproxyd.sh
%pre
rm -rf %{install_dir}/log
rm -rf %{install_dir}/bin
rm -rf %{install_dir}/etc
rm -rf %{install_dir}/.conf
%post
chown -R admin:admin %{install_dir}
#ifndef EASY_LOCK_ATOMIC_H_
#define EASY_LOCK_ATOMIC_H_
#include <easy_define.h>
#include <stdint.h>
#include <sched.h>
EASY_CPP_START
#define easy_atomic_set(v,i) ((v) = (i))
typedef volatile int32_t easy_atomic32_t;
// 32bit
static __inline__ void easy_atomic32_add(easy_atomic32_t *v, int i)
{
__sync_fetch_and_add(v, i); //for x86 and arm
}
static __inline__ int32_t easy_atomic32_add_return(easy_atomic32_t *value, int32_t diff)
{
return __sync_add_and_fetch( value, diff ) ; // for x86 and arm
}
static __inline__ void easy_atomic32_inc(easy_atomic32_t *v)
{
__sync_add_and_fetch( v, 1 ); // for x86 and arm
}
static __inline__ void easy_atomic32_dec(easy_atomic32_t *v)
{
__sync_sub_and_fetch( v, 1 ); // for x86 and arm
}
// 64bit
#if __WORDSIZE == 64
typedef volatile int64_t easy_atomic_t;
static __inline__ void easy_atomic_add(easy_atomic_t *v, int64_t i)
{
__sync_fetch_and_add(v, i); // for x86 and arm
}
static __inline__ int64_t easy_atomic_add_return(easy_atomic_t *value, int64_t i)
{
return __sync_add_and_fetch( value, i ) ; // for x86 and arm
}
static __inline__ int64_t easy_atomic_cmp_set(easy_atomic_t *lock, int64_t old, int64_t set)
{
return __sync_bool_compare_and_swap(lock, old, set); // for x86 and arm
}
static __inline__ void easy_atomic_inc(easy_atomic_t *v)
{
__sync_add_and_fetch( v, 1 ); //for x86 and arm
}
static __inline__ void easy_atomic_dec(easy_atomic_t *v)
{
__sync_sub_and_fetch( v, 1 ); //for x86 and arm
}
#else
typedef volatile int32_t easy_atomic_t;
#define easy_atomic_add(v,i) easy_atomic32_add(v,i)
#define easy_atomic_add_return(v,diff) easy_atomic32_add_return(v,diff)
#define easy_atomic_inc(v) easy_atomic32_inc(v)
#define easy_atomic_dec(v) easy_atomic32_dec(v)
static __inline__ int32_t easy_atomic_cmp_set(easy_atomic_t *lock, int32_t old, int32_t set)
{
return __sync_bool_compare_and_swap(lock, old, set); // for x86 and arm
}
#endif
#define easy_trylock(lock) (*(lock) == 0 && easy_atomic_cmp_set(lock, 0, 1))
#define easy_unlock(lock) __atomic_store_n(lock, 0, __ATOMIC_SEQ_CST)
#define easy_spin_unlock easy_unlock
#define easy_mfence() __atomic_thread_fence(__ATOMIC_SEQ_CST)
static __inline__ void easy_spin_lock(easy_atomic_t *lock)
{
int i, n;
for ( ; ; ) {
if (*lock == 0 && easy_atomic_cmp_set(lock, 0, 1)) {
return;
}
for (n = 1; n < 1024; n <<= 1) {
for (i = 0; i < n; i++) {
#if defined(__x86_64__)
__asm__ (".byte 0xf3, 0x90");
#elif defined(__aarch64__)
__asm__ ("yield"); // for ARM
#else
#error arch unsupported
#endif
}
if (*lock == 0 && easy_atomic_cmp_set(lock, 0, 1)) {
return;
}
}
sched_yield();
}
}
static __inline__ void easy_clear_bit(unsigned long nr, volatile void *addr)
{
int8_t *m = ((int8_t *) addr) + (nr >> 3);
*m &= (int8_t)(~(1 << (nr & 7)));
}
static __inline__ void easy_set_bit(unsigned long nr, volatile void *addr)
{
int8_t *m = ((int8_t *) addr) + (nr >> 3);
*m |= (int8_t)(1 << (nr & 7));
}
typedef struct easy_spinrwlock_t {
easy_atomic_t ref_cnt;
easy_atomic_t wait_write;
} easy_spinrwlock_t;
#define EASY_SPINRWLOCK_INITIALIZER {0, 0}
static __inline__ int easy_spinrwlock_rdlock(easy_spinrwlock_t *lock)
{
int ret = EASY_OK;
if (NULL == lock) {
ret = EASY_ERROR;
} else {
int cond = 1;
while (cond) {
int loop = 1;
do {
easy_atomic_t oldv = lock->ref_cnt;
if (0 <= oldv
&& 0 == lock->wait_write) {
easy_atomic_t newv = oldv + 1;
if (easy_atomic_cmp_set(&lock->ref_cnt, oldv, newv)) {
cond = 0;
break;
}
}
#if defined(__x86_64__)
asm("pause");
#elif defined(__aarch64__)
asm("yield"); // for ARM
#else
#error arch unsupported
#endif
loop <<= 1;
} while (loop < 1024);
sched_yield();
}
}
return ret;
}
static __inline__ int easy_spinrwlock_wrlock(easy_spinrwlock_t *lock)
{
int ret = EASY_OK;
if (NULL == lock) {
ret = EASY_ERROR;
} else {
int cond = 1;
easy_atomic_inc(&lock->wait_write);
while (cond) {
int loop = 1;
do {
easy_atomic_t oldv = lock->ref_cnt;
if (0 == oldv) {
easy_atomic_t newv = -1;
if (easy_atomic_cmp_set(&lock->ref_cnt, oldv, newv)) {
cond = 0;
break;
}
}
#if defined(__x86_64__)
asm("pause");
#elif defined(__aarch64__)
asm("yield"); // for ARM
#else
#error arch unsupported
#endif
loop <<= 1;
} while (loop < 1024);
sched_yield();
}
easy_atomic_dec(&lock->wait_write);
}
return ret;
}
static __inline__ int easy_spinrwlock_try_rdlock(easy_spinrwlock_t *lock)
{
int ret = EASY_OK;
if (NULL == lock) {
ret = EASY_ERROR;
} else {
ret = EASY_AGAIN;
easy_atomic_t oldv = lock->ref_cnt;
if (0 <= oldv
&& 0 == lock->wait_write) {
easy_atomic_t newv = oldv + 1;
if (easy_atomic_cmp_set(&lock->ref_cnt, oldv, newv)) {
ret = EASY_OK;
}
}
}
return ret;
}
static __inline__ int easy_spinrwlock_try_wrlock(easy_spinrwlock_t *lock)
{
int ret = EASY_OK;
if (NULL == lock) {
ret = EASY_ERROR;
} else {
ret = EASY_AGAIN;
easy_atomic_t oldv = lock->ref_cnt;
if (0 == oldv) {
easy_atomic_t newv = -1;
if (easy_atomic_cmp_set(&lock->ref_cnt, oldv, newv)) {
ret = EASY_OK;
}
}
}
return ret;
}
static __inline__ int easy_spinrwlock_unlock(easy_spinrwlock_t *lock)
{
int ret = EASY_OK;
if (NULL == lock) {
ret = EASY_ERROR;
} else {
while (1) {
easy_atomic_t oldv = lock->ref_cnt;
if (-1 == oldv) {
easy_atomic_t newv = 0;
if (easy_atomic_cmp_set(&lock->ref_cnt, oldv, newv)) {
break;
}
} else if (0 < oldv) {
easy_atomic_t newv = oldv - 1;
if (easy_atomic_cmp_set(&lock->ref_cnt, oldv, newv)) {
break;
}
} else {
ret = EASY_ERROR;
break;
}
}
}
return ret;
}
EASY_CPP_END
#endif
#ifndef EASY_DEFINE_H_
#define EASY_DEFINE_H_
#ifdef __cplusplus
# define EASY_CPP_START extern "C" {
# define EASY_CPP_END }
#else
# define EASY_CPP_START
# define EASY_CPP_END
#endif
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <stddef.h>
#include <inttypes.h>
#include <unistd.h>
#include <execinfo.h>
#include <sys/uio.h>
///////////////////////////////////////////////////////////////////////////////////////////////////
// define
#define easy_free(ptr) if(ptr) free(ptr)
#define easy_malloc(size) malloc(size)
#define easy_realloc(ptr, size) realloc(ptr, size)
#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#define easy_align_ptr(p, a) (uint8_t*)(((uintptr_t)(p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
#define easy_align(d, a) (((d) + (a - 1)) & ~(a - 1))
#define easy_max(a,b) (a > b ? a : b)
#define easy_min(a,b) (a < b ? a : b)
#define easy_div(a,b) ((b) ? ((a)/(b)) : 0)
#define easy_memcpy(dst, src, n) (((char *) memcpy(dst, src, (n))) + (n))
#define easy_const_strcpy(b, s) easy_memcpy(b, s, sizeof(s)-1)
#define easy_safe_close(fd) {if((fd)>=0){close((fd));(fd)=-1;}}
#define easy_ignore(exp) {int ignore __attribute__ ((unused)) = (exp);}
#define EASY_OK 0
#define EASY_ERROR (-1)
#define EASY_ABORT (-2)
#define EASY_ASYNC (-3)
#define EASY_BREAK (-4)
#define EASY_AGAIN (-EAGAIN)
#define EASY_STOP (-45)
#define EASY_DISCONNECT (-46)
#define EASY_TIMEOUT (-47)
#define EASY_ALLOC_FAIL (-48)
#define EASY_CONNECT_FAIL (-49)
#define EASY_KEEPALIVE_ERROR (-50)
#define EASY_DISPATCH_ERROR (-51)
// interval
#define EASY_REACH_TIME_INTERVAL(i) \
({ \
char bret = 0; \
static volatile int64_t last_time = 0; \
int64_t cur_time = current_time(); \
int64_t old_time = last_time; \
if ((i + last_time) < cur_time \
&& easy_atomic_cmp_set(&last_time, old_time, cur_time)) \
{ \
bret = 1; \
} \
bret; \
})
// DEBUG
//#define EASY_DEBUG_DOING 1
//#define EASY_DEBUG_MAGIC 1
///////////////////////////////////////////////////////////////////////////////////////////////////
// typedef
typedef struct easy_addr_t {
uint16_t family;
uint16_t port;
union {
uint32_t addr;
uint8_t addr6[16];
} u;
uint32_t cidx;
} easy_addr_t;
typedef unsigned long long cycles_t;
#endif
#ifndef EASY_LIST_H_
#define EASY_LIST_H_
#include "easy_define.h"
EASY_CPP_START
// from kernel list
typedef struct easy_list_t easy_list_t;
struct easy_list_t {
easy_list_t *next, *prev;
};
#define EASY_LIST_HEAD_INIT(name) {&(name), &(name)}
#define easy_list_init(ptr) do { \
(ptr)->next = (ptr); \
(ptr)->prev = (ptr); \
} while (0)
static inline void __easy_list_add(easy_list_t *list,
easy_list_t *prev, easy_list_t *next)
{
next->prev = list;
list->next = next;
list->prev = prev;
prev->next = list;
}
// list head to add it after
static inline void easy_list_add_head(easy_list_t *list, easy_list_t *head)
{
__easy_list_add(list, head, head->next);
}
// list head to add it before
static inline void easy_list_add_tail(easy_list_t *list, easy_list_t *head)
{
__easy_list_add(list, head->prev, head);
}
static inline void __easy_list_del(easy_list_t *prev, easy_list_t *next)
{
next->prev = prev;
prev->next = next;
}
// deletes entry from list
static inline void easy_list_del(easy_list_t *entry)
{
__easy_list_del(entry->prev, entry->next);
easy_list_init(entry);
}
static inline void easy_list_replace(easy_list_t* entry, easy_list_t* new_entry)
{
__easy_list_add(new_entry, entry->prev, entry->next);
easy_list_init(entry);
}
// tests whether a list is empty
static inline int easy_list_empty(const easy_list_t *head)
{
return (head->next == head);
}
// move list to new_list
static inline void easy_list_movelist(easy_list_t *list, easy_list_t *new_list)
{
if (!easy_list_empty(list)) {
new_list->prev = list->prev;
new_list->next = list->next;
new_list->prev->next = new_list;
new_list->next->prev = new_list;
easy_list_init(list);
} else {
easy_list_init(new_list);
}
}
// join list to head
static inline void easy_list_join(easy_list_t *list, easy_list_t *head)
{
if (!easy_list_empty(list)) {
easy_list_t *first = list->next;
easy_list_t *last = list->prev;
easy_list_t *at = head->prev;
first->prev = at;
at->next = first;
last->next = head;
head->prev = last;
}
}
// get last
#define easy_list_get_last(list, type, member) \
easy_list_empty(list) ? NULL : easy_list_entry((list)->prev, type, member)
// get first
#define easy_list_get_first(list, type, member) \
easy_list_empty(list) ? NULL : easy_list_entry((list)->next, type, member)
#define easy_list_entry(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define easy_list_for_each_entry(pos, head, member) \
for (pos = easy_list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = easy_list_entry(pos->member.next, typeof(*pos), member))
#define easy_list_for_each_entry_reverse(pos, head, member) \
for (pos = easy_list_entry((head)->prev, typeof(*pos), member); \
&pos->member != (head); \
pos = easy_list_entry(pos->member.prev, typeof(*pos), member))
#define easy_list_for_each_entry_safe(pos, n, head, member) \
for (pos = easy_list_entry((head)->next, typeof(*pos), member), \
n = easy_list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = easy_list_entry(n->member.next, typeof(*n), member))
#define easy_list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = easy_list_entry((head)->prev, typeof(*pos), member), \
n = easy_list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = easy_list_entry(n->member.prev, typeof(*n), member))
EASY_CPP_END
#endif
#include <pthread.h>
#include <sys/socket.h>
#include <sys/prctl.h>
#include "easy_io_struct.h"
#include "easy_log.h"
#include "easy_baseth_pool.h"
#include "easy_connection.h"
#include "easy_message.h"
__thread easy_baseth_t *easy_baseth_self;
static void easy_baseth_pool_invoke(struct ev_loop *loop);
static void easy_baseth_pool_invoke_debug(struct ev_loop *loop);
static int easy_monitor_interval = 100;
static const int64_t easy_monitor_signal = 34;
/**
* start
*/
void *easy_baseth_on_start(void *args)
{
easy_baseth_t *th;
easy_io_t *eio;
th = (easy_baseth_t *) args;
easy_baseth_self = th;
eio = th->eio;
if (eio->block_thread_signal)
pthread_sigmask(SIG_BLOCK, &eio->block_thread_sigset, NULL);
ev_run(th->loop, 0);
easy_baseth_self = NULL;
easy_debug_log("pthread exit: %lx.\n", pthread_self());
return (void *)NULL;
}
/**
* wakeup
*/
void easy_baseth_on_wakeup(void *args)
{
easy_baseth_t *th = (easy_baseth_t *)args;
easy_spin_lock(&th->thread_lock);
ev_async_fsend(th->loop, &th->thread_watcher);
easy_spin_unlock(&th->thread_lock);
}
void easy_baseth_init(void *args, easy_thread_pool_t *tp,
easy_baseth_on_start_pt *start, easy_baseth_on_wakeup_pt *wakeup)
{
easy_baseth_t *th = (easy_baseth_t *)args;
th->idx = (((char *)(th)) - (&(tp)->data[0])) / (tp)->member_size;
th->on_start = start;
th->loop = ev_loop_new(0);
th->thread_lock = 0;
th->lastrun = 0.0;
ev_async_init (&th->thread_watcher, wakeup);
th->thread_watcher.data = th;
ev_async_start (th->loop, &th->thread_watcher);
ev_set_userdata(th->loop, th);
if (tp->monitor_tid) {
ev_set_invoke_pending_cb(th->loop, easy_baseth_pool_invoke_debug);
} else {
ev_set_invoke_pending_cb(th->loop, easy_baseth_pool_invoke);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
* create a thread pool
*/
easy_thread_pool_t *easy_baseth_pool_create(easy_io_t *eio, int thread_count, int member_size)
{
easy_baseth_t *th;
easy_thread_pool_t *tp;
int size;
size = sizeof(easy_thread_pool_t) + member_size * thread_count;
if ((tp = (easy_thread_pool_t *) easy_pool_calloc(eio->pool, size)) == NULL)
return NULL;
tp->thread_count = thread_count;
tp->member_size = member_size;
tp->last = &tp->data[0] + member_size * thread_count;
easy_list_add_tail(&tp->list_node, &eio->thread_pool_list);
easy_thread_pool_for_each(th, tp, 0) {
th->eio = eio;
}
// start monitor
const char *ptr = getenv("easy_thread_monitor");
if (ptr) {
easy_monitor_interval = atoi(ptr);
}
return tp;
}
/**
* wakeup pool
*/
void easy_baseth_pool_on_wakeup(easy_thread_pool_t *tp)
{
easy_baseth_t *th;
easy_thread_pool_for_each(th, tp, 0) {
easy_baseth_on_wakeup(th);
}
}
/**
* destroy pool
*/
void easy_baseth_pool_destroy(easy_thread_pool_t *tp)
{
easy_baseth_t *th;
easy_thread_pool_for_each(th, tp, 0) {
ev_loop_destroy(th->loop);
}
}
static void easy_baseth_pool_wakeup_session(easy_baseth_t *th)
{
if (th->iot == 0)
return;
easy_connection_t *c, *c1;
easy_session_t *s, *s1;
easy_io_thread_t *ioth = (easy_io_thread_t *) th;
// session at ioth
easy_spin_lock(&ioth->thread_lock);
easy_list_for_each_entry_safe(s, s1, &ioth->session_list, session_list_node) {
if (s->status == 0 || s->status == EASY_CONNECT_SEND) {
easy_warn_log("session fail due to io thread exit %p", s);
easy_list_del(&s->session_list_node);
easy_session_process(s, 0, EASY_STOP);
}
}
// connection at ioth
easy_list_for_each_entry_safe(c, c1, &ioth->conn_list, conn_list_node) {
easy_connection_wakeup_session(c);
}
// foreach connected_list
easy_list_for_each_entry_safe(c, c1, &ioth->connected_list, conn_list_node) {
easy_connection_wakeup_session(c);
}
easy_spin_unlock(&ioth->thread_lock);
}
/**
* check exit status
*/
static void easy_baseth_pool_invoke(struct ev_loop *loop)
{
easy_baseth_t *th = (easy_baseth_t *) ev_userdata (loop);
easy_connection_t *c, *c1;
easy_io_thread_t *ioth;
easy_listen_t *l;
th->lastrun = ev_now(loop);
if (th->user_process) (*th->user_process)(th);
ev_invoke_pending(loop);
if (th->eio->shutdown && th->iot == 1) {
ioth = (easy_io_thread_t *) ev_userdata (loop);
if (ioth->eio->listen) {
int ts = (ioth->eio->listen_all || ioth->eio->io_thread_count == 1);
for (l = ioth->eio->listen; l; l = l->next) {
if (l->reuseport || ts) {
ev_io_stop(loop, &l->read_watcher[ioth->idx]);
} else {
ev_timer_stop (loop, &ioth->listen_watcher);
}
}
}
// connection at ioth
easy_list_for_each_entry_safe(c, c1, &ioth->conn_list, conn_list_node) {
shutdown(c->fd, SHUT_RD);
EASY_CONNECTION_DESTROY(c, "close conn_list in ev_invoke");
}
// foreach connected_list
easy_list_for_each_entry_safe(c, c1, &ioth->connected_list, conn_list_node) {
shutdown(c->fd, SHUT_RD);
EASY_CONNECTION_DESTROY(c, "close connected_list in ev_invoke");
}
}
th->lastrun = 0.0;
if (th->eio->stoped) {
easy_baseth_pool_wakeup_session(th);
ev_break(loop, EVBREAK_ALL);
easy_debug_log("ev_break: eio=%p\n", th->eio);
}
}
void easy_baseth_pool_invoke_debug(struct ev_loop *loop)
{
ev_tstamp st = ev_time();
easy_baseth_pool_invoke(loop);
ev_tstamp et = ev_time();
if (et - st > easy_monitor_interval / 1000.0) {
easy_warn_log("EASY SLOW: start: %f end: %f cost: %f", st, et, et - st);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static void *easy_baseth_pool_monitor_func(void *args)
{
easy_baseth_t *th;
easy_thread_pool_t *tp = (easy_thread_pool_t *) args;
int64_t loopcnts[tp->thread_count];
int64_t slowcnts[tp->thread_count];
prctl(PR_SET_NAME, "EasyBasethPoolMonitor");
memset(loopcnts, 0, sizeof(loopcnts));
memset(slowcnts, 0, sizeof(slowcnts));
const int64_t us = easy_monitor_interval * 1000L;
const double sec = easy_monitor_interval / 1000.0;
easy_info_log("monitor us :%ld sec :%f", us, sec);
while(tp->stoped == 0) {
usleep(us);
ev_tstamp now = ev_time();
easy_thread_pool_for_each(th, tp, 0) {
ev_tstamp last = th->lastrun;
int id = ev_loop_count(th->loop);
if (loopcnts[th->idx] != id) {
loopcnts[th->idx] = id;
slowcnts[th->idx] = 0;
}
if (last > 0 && now - last > sec) {
slowcnts[th->idx] ++;
if (slowcnts[th->idx] < 10) {
//pthread_kill(th->tid, easy_monitor_signal);
}
if (EASY_REACH_TIME_INTERVAL(1 * 1000 * 1000)) {
easy_warn_log("EASY SLOW: thread: %lx, lastrun: %f cost: %f loop:%d, slowcnt: %ld",
th->tid, last, now - last, id, slowcnts[th->idx]);
}
}
}
}
easy_info_log("easy monitor thread stopped");
return NULL;
}
static void easy_baseth_pool_sighand(int sig, siginfo_t *sinfo, void *ucontext)
{
int saved_errno = errno;
{
ev_tstamp last = 0.0;
int lid = 0;
if (easy_baseth_self) {
last = easy_baseth_self->lastrun;
lid = ev_loop_count(easy_baseth_self->loop);
}
void *array[25];
int i, idx = 0;
char _buffer_stack_[512];
int n = backtrace(array, 25);
if (n > 2) {
for (i = 2; i < n; i++) idx += lnprintf(idx + _buffer_stack_, 20, "%p ", array[i]);
_buffer_stack_[idx] = '\0';
easy_warn_log("EASY SLOW STACK:%f %d %f => %s", last, lid, ev_time() - last, _buffer_stack_);
}
}
errno = saved_errno;
}
void easy_baseth_pool_monitor(easy_thread_pool_t *tp)
{
int rc, err;
struct sigaction sa;
if (tp->monitor_tid) {
return;
} else if (easy_monitor_interval > 10) {
sa.sa_sigaction = easy_baseth_pool_sighand;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&sa.sa_mask);
rc = sigaction(easy_monitor_signal, &sa, NULL);
err = pthread_create(&tp->monitor_tid, NULL, easy_baseth_pool_monitor_func, tp);
if (err != 0) {
tp->monitor_tid = 0;
easy_error_log("sigaction: %d, monitor_thread: 0x%lx, err:%d, errno:%d", rc, tp->monitor_tid, err, errno);
} else {
easy_info_log("monitor thread created, tp=0x%lx tid=%lx\n", tp, tp->monitor_tid);
}
}
}
#ifndef EASY_BASETH_POOL_H
#define EASY_BASETH_POOL_H
#include <easy_define.h>
/**
* base pthread thread pool
*/
EASY_CPP_START
#include "easy_io_struct.h"
#define easy_thread_pool_for_each(th, tp, offset) \
for((th) = (typeof(*(th))*)&(tp)->data[offset]; \
(char*)(th) < (tp)->last; \
th = (typeof(*th)*)(((char*)th) + (tp)->member_size))
// no n
static inline void *easy_thread_pool_index(easy_thread_pool_t *tp, int n)
{
if (n < 0 || n >= tp->thread_count)
return NULL;
return &tp->data[n * tp->member_size];
}
static inline void *easy_thread_pool_hash(easy_thread_pool_t *tp, uint64_t hv)
{
hv %= tp->thread_count;
return &tp->data[hv * tp->member_size];
}
static inline void *easy_thread_pool_rr(easy_thread_pool_t *tp, int start)
{
int n, t;
if ((t = tp->thread_count - start) > 0) {
n = easy_atomic32_add_return(&tp->last_number, 1);
n %= t;
n += start;
} else {
n = 0;
}
return &tp->data[n * tp->member_size];
}
// baseth
void *easy_baseth_on_start(void *args);
void easy_baseth_on_wakeup(void *args);
void easy_baseth_init(void *args, easy_thread_pool_t *tp,
easy_baseth_on_start_pt *start, easy_baseth_on_wakeup_pt *wakeup);
void easy_baseth_pool_on_wakeup(easy_thread_pool_t *tp);
easy_thread_pool_t *easy_baseth_pool_create(easy_io_t *eio, int thread_count, int member_size);
void easy_baseth_pool_destroy(easy_thread_pool_t *tp);
void easy_baseth_pool_monitor(easy_thread_pool_t *tp);
EASY_CPP_END
#endif
#include "easy_io.h"
#include "easy_client.h"
#include "easy_connection.h"
#include "easy_message.h"
#include "easy_ssl.h"
static int easy_client_uthread_wakeup_conn(easy_connection_t *c);
static int easy_client_uthread_wakeup_session(easy_request_t *r);
int easy_client_dispatch(easy_io_t *eio, easy_addr_t addr, easy_session_t *s)
{
easy_io_thread_t *ioth;
uint64_t index;
int ret;
int issend;
if (unlikely(!eio->started)) {
easy_error_log("easy_io_dispatch is failure: easy not started\n");
return EASY_ERROR;
} else if (unlikely(eio->stoped)) {
easy_error_log("easy_io_dispatch is failure: easy stopped\n");
return EASY_ERROR;
}
index = (addr.cidx < 256 ? addr.cidx : easy_hash_code(&addr, sizeof(easy_addr_t), 7));
ioth = (easy_io_thread_t *)easy_thread_pool_hash(eio->io_thread_pool, index);
issend = (s->status == 0 || s->status == EASY_CONNECT_SEND);
if (unlikely(ioth->eio->checkdrc == 0 && ioth->doing_request_count >= EASY_IOTH_DOING_REQ_CNT && issend)) {
static int lastlog = 0;
if (lastlog != time(NULL)) {
lastlog = time(NULL);
easy_error_log("ioth->doing_request_count: %d, EASY_IOTH_DOING_REQ_CNT: %d\n",
ioth->doing_request_count, EASY_IOTH_DOING_REQ_CNT);
}
return EASY_ERROR;
}
s->async = 1;
s->addr = addr;
if (issend) {
easy_atomic32_inc(&ioth->doing_request_count);
}
char buffer[32];
easy_debug_log("send to %s, status=%d", easy_inet_addr_to_str(&s->addr, buffer, 32), s->status);
// dispatch
ret = EASY_OK;
easy_spin_lock(&ioth->thread_lock);
if (likely(eio->stoped == 0)) {
easy_list_add_tail(&s->session_list_node, &ioth->session_list);
} else {
easy_error_log("eio stoped.");
ret = EASY_ERROR;
}
easy_spin_unlock(&ioth->thread_lock);
if (ret == EASY_OK) {
ev_async_send(ioth->loop, &ioth->thread_watcher);
}
return ret;
}
void *easy_client_send(easy_io_t *eio, easy_addr_t addr, easy_session_t *s)
{
int ret;
easy_client_wait_t wobj;
easy_client_wait_init(&wobj);
easy_session_set_wobj(s, &wobj);
s->callback = easy_client_wait_process;
if ((ret = easy_client_dispatch(eio, addr, s)) == EASY_ERROR) {
s->error = EASY_DISPATCH_ERROR;
easy_warn_log("easy_session_dispatch failed: %d\n", ret);
return NULL;
}
// easy_info_log("easy_client_send 1, c = %s, %p, %p, %p\n", easy_connection_str(s->c), &wobj.cond, s, s->callback);
easy_client_wait(&wobj, 1);
pthread_cond_destroy(&wobj.cond);
pthread_mutex_destroy(&wobj.mutex);
return s->r.ipacket;
}
// init
void easy_client_wait_init(easy_client_wait_t *w)
{
w->done_count = 0;
w->status = EASY_CONN_OK;
easy_list_init(&w->next_list);
easy_list_init(&w->session_list);
pthread_mutex_init(&w->mutex, NULL);
pthread_cond_init(&w->cond, NULL);
}
void easy_client_wait_cleanup(easy_client_wait_t *w)
{
easy_session_t *s, *s2;
pthread_cond_destroy(&w->cond);
pthread_mutex_destroy(&w->mutex);
easy_list_for_each_entry_safe(s, s2, &w->session_list, session_list_node) {
easy_session_destroy(s);
}
}
void easy_client_wait_wakeup(easy_client_wait_t *w)
{
pthread_mutex_lock(&w->mutex);
w->done_count ++;
pthread_cond_signal(&w->cond);
pthread_mutex_unlock(&w->mutex);
}
void easy_client_wait_wakeup_request(easy_request_t *r)
{
if (r->client_wait) {
easy_atomic_inc(&r->ms->c->pool->ref);
easy_atomic_inc(&r->ms->pool->ref);
easy_client_wait_wakeup(r->client_wait);
}
}
void easy_client_wait(easy_client_wait_t *w, int count)
{
pthread_mutex_lock(&w->mutex);
while (w->done_count < count) {
pthread_cond_wait(&w->cond, &w->mutex);
}
pthread_mutex_unlock(&w->mutex);
if (easy_list_empty(&w->next_list))
return;
// next
easy_list_t *list = &w->next_list;
easy_session_t *s, *sn;
int cnt = 0;
easy_list_for_each_entry_safe(s, sn, list, session_list_node) {
w = (easy_client_wait_t *)s->r.request_list_node.prev;
easy_list_del(&s->session_list_node);
easy_list_add_tail(&s->session_list_node, &w->session_list);
if (++ cnt >= 2) {
easy_list_movelist(list, &w->next_list);
easy_client_wait_wakeup(w);
break;
} else {
easy_client_wait_wakeup(w);
}
}
}
int easy_client_wait_process(easy_request_t *r)
{
easy_client_wait_t *w = (easy_client_wait_t *)r->request_list_node.prev;
easy_session_t *s = (easy_session_t *)r->ms;
// easy_info_log("easy_client_wait_process, c = %s, %p, %p\n", easy_connection_str(s->c), s, &w->cond);
pthread_mutex_lock(&w->mutex);
easy_list_add_tail(&s->session_list_node, &w->session_list);
w->done_count ++;
pthread_cond_signal(&w->cond);
pthread_mutex_unlock(&w->mutex);
return EASY_OK;
}
int easy_client_wait_batch_process(easy_message_t *m)
{
easy_list_t *list = (easy_list_t *) m;
easy_session_t *s;
easy_client_wait_t *w;
s = easy_list_get_first(list, easy_session_t, session_list_node);
w = (easy_client_wait_t *)s->r.request_list_node.prev;
easy_list_del(&s->session_list_node);
easy_list_add_tail(&s->session_list_node, &w->session_list);
easy_list_movelist(list, &w->next_list);
easy_client_wait_wakeup(w);
return EASY_OK;
}
/*
int easy_client_wait_on_connect(easy_connection_t *c)
{
easy_client_wait_t *w;
if ((w = (easy_client_wait_t *)c->user_data))
easy_client_wait_wakeup(w);
return EASY_OK;
}
*/
// add addr
int easy_client_list_add(easy_hash_t *table, easy_addr_t *addr, easy_hash_list_t *list)
{
uint64_t n;
easy_hash_list_t *first;
n = easy_hash_code(addr, sizeof(easy_addr_t), 5);
n &= table->mask;
// init
list->key = (long)(void *)addr;
table->count ++;
table->seqno ++;
// add to list
first = table->buckets[n];
list->next = first;
if (first) first->pprev = &list->next;
table->buckets[n] = (easy_hash_list_t *)list;
list->pprev = &(table->buckets[n]);
return EASY_OK;
}
void *easy_client_list_find(easy_hash_t *table, easy_addr_t *addr)
{
uint64_t n;
int lookup = 0;
easy_hash_list_t *list;
easy_addr_t *baddr;
n = easy_hash_code(addr, sizeof(easy_addr_t), 5);
n &= table->mask;
list = table->buckets[n];
// foreach
while (list) {
baddr = (easy_addr_t *)(long)list->key;
if (memcmp(baddr, addr, sizeof(easy_addr_t)) == 0) {
if (lookup > 100) easy_warn_log("lookup: %d", lookup);
return ((char *)list - table->offset);
}
list = list->next;
lookup ++;
}
if (lookup > 100) easy_warn_log("lookup: %d", lookup);
return NULL;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// uthread wait;
int easy_client_uthread_wait_conn(easy_connection_t *c)
{
if (c->status == EASY_CONN_OK)
return EASY_OK;
if ((c->uthread = easy_uthread_current()) == NULL) {
return EASY_ERROR;
} else {
easy_uthread_switch();
return easy_uthread_get_errcode();
}
}
int easy_client_uthread_wait_session(easy_session_t *s)
{
if ((s->thread_ptr = easy_uthread_current()) == NULL) {
return EASY_ERROR;
} else {
easy_uthread_switch();
return easy_uthread_get_errcode();
}
}
void easy_client_uthread_set_handler(easy_io_handler_pt *handler)
{
handler->on_connect = easy_client_uthread_wakeup_conn;
handler->on_disconnect = easy_client_uthread_wakeup_conn;
handler->process = easy_client_uthread_wakeup_session;
handler->is_uthread = 1;
}
// io_handler
static int easy_client_uthread_wakeup_conn(easy_connection_t *c)
{
if (c->uthread) {
easy_uthread_ready(c->uthread);
easy_uthread_set_errcode(c->uthread, (c->conn_has_error ? EASY_ERROR : EASY_OK));
c->uthread = NULL;
}
return EASY_OK;
}
static int easy_client_uthread_wakeup_session(easy_request_t *r)
{
easy_session_t *s;
easy_uthread_t *uth;
s = (easy_session_t *) r->ms;
if (s->type != EASY_TYPE_SESSION) {
easy_fatal_log("session error, r->ms->type: %d\n", s->type);
return EASY_ERROR;
}
if (s->thread_ptr) {
uth = (easy_uthread_t *)s->thread_ptr;
easy_uthread_ready(uth);
easy_uthread_set_errcode(uth, (s->c->conn_has_error ? EASY_ERROR : EASY_OK));
s->thread_ptr = NULL;
}
return EASY_OK;
}
#ifndef EASY_CLIENT_H_
#define EASY_CLIENT_H_
#include <easy_define.h>
#include "easy_io_struct.h"
EASY_CPP_START
void *easy_client_list_find(easy_hash_t *table, easy_addr_t *addr);
int easy_client_list_add(easy_hash_t *table, easy_addr_t *addr, easy_hash_list_t *list);
EASY_CPP_END
#endif
此差异已折叠。
#ifndef EASY_CONNECTION_H_
#define EASY_CONNECTION_H_
#include <easy_define.h>
#include "easy_io_struct.h"
EASY_CPP_START
// fuction
easy_listen_t *easy_connection_listen_addr(easy_io_t *eio, easy_addr_t addr, easy_io_handler_pt *handler);
void easy_connection_on_wakeup(struct ev_loop *loop, ev_async *w, int revents);
void easy_connection_on_listen(struct ev_loop *loop, ev_timer *w, int revents);
int easy_connection_write_socket(easy_connection_t *c);
int easy_connection_request_process(easy_request_t *r, easy_io_process_pt *process);
uint64_t easy_connection_get_packet_id(easy_connection_t *c, void *packet, int flag);
int easy_connection_send_session_list(easy_list_t *list);
int easy_connection_session_build(easy_session_t *s);
void easy_connection_wakeup_session(easy_connection_t *c);
void easy_connection_destroy(easy_connection_t *c, const char* msg);
int easy_connection_request_done(easy_request_t *c);
int easy_connection_write_again(easy_connection_t *c);
void easy_connection_on_readable(struct ev_loop *loop, ev_io *w, int revents);
void easy_connection_on_writable(struct ev_loop *loop, ev_io *w, int revents);
void easy_connection_reuseport(easy_io_t *eio, easy_listen_t *l, int idx);
void easy_connection_on_accept(struct ev_loop *loop, ev_io *w, int revents);
void easy_connection_on_udpread(struct ev_loop *loop, ev_io *w, int revents);
int64_t current_time();
#define EASY_CONNECTION_DESTROY(c, msg) { easy_connection_destroy(c, msg); c = NULL; }
EASY_CPP_END
#endif
#undef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#include <unistd.h>
#include <sys/sendfile.h>
#include "easy_io.h"
#include "easy_file.h"
#include "easy_connection.h"
#include "easy_message.h"
#include "easy_request.h"
#include "easy_file.h"
#include "easy_client.h"
#include "easy_socket.h"
#include "easy_log.h"
#include <fcntl.h>
easy_file_task_t *easy_file_task_create(easy_request_t *r, int fd, int bufsize)
{
struct stat fs;
easy_file_task_t *ft;
ft = (easy_file_task_t *)easy_pool_calloc(r->ms->pool, sizeof(easy_file_task_t));
if (ft == NULL)
return NULL;
ft->fd = fd;
if (bufsize < 0) {
ft->bufsize = -1;
ft->b = NULL;
ft->buffer = NULL;
ft->count = -1;
return ft;
}
if (fstat(fd, &fs) == 0)
ft->count = fs.st_size;
if (bufsize == 0) bufsize = EASY_MAX_FILE_BUFFER;
ft->bufsize = easy_min(ft->count, bufsize);
ft->b = easy_buf_create(r->ms->pool, ft->bufsize);
ft->buffer = ft->b->pos;
if (ft->b == NULL)
return NULL;
return ft;
}
void easy_file_task_set(easy_file_task_t *ft, char *buffer, int64_t offset, int64_t bufsize, void *args)
{
ft->buffer = buffer;
ft->offset = offset;
ft->count = ft->bufsize = bufsize;
ft->args = args;
}
void easy_file_task_reset(easy_file_task_t *ft, int type)
{
easy_list_init(&ft->b->node);
ft->b->pos = ft->buffer;
ft->b->last = ft->b->pos;
((easy_file_buf_t *)ft->b)->flags = type;
}
#ifndef EASY_FILE_H_
#define EASY_FILE_H_
#include <easy_define.h>
#include "easy_io_struct.h"
EASY_CPP_START
#define EASY_MAX_FILE_BUFFER 65536
EASY_CPP_END
#endif
#include "easy_io.h"
#include "easy_baseth_pool.h"
#include "easy_connection.h"
#include "easy_message.h"
#include "easy_request.h"
#include "easy_file.h"
#include "easy_client.h"
#include "easy_socket.h"
#include "easy_mod_stat.h"
#include <sched.h>
char *easy_version = "LIBEASY VERSION: 1.1.22 OceanBase Embedded Edition, BUILD: " __DATE__ " " __TIME__;
easy_io_t easy_io_var = {NULL};
easy_atomic_t easy_io_list_lock = 0;
easy_list_t easy_io_list_var = EASY_LIST_HEAD_INIT(easy_io_list_var);
static void *easy_io_on_thread_start(void *args);
static void easy_io_on_uthread_start(void *args);
static void easy_io_on_uthread_evstart(void *args);
static void easy_io_uthread_invoke(struct ev_loop *loop);
static void easy_io_thread_destroy(easy_io_thread_t *ioth);
static void easy_io_stat_process(struct ev_loop *loop, ev_timer *w, int revents);
static void easy_io_print_status(easy_io_t *eio);
static void easy_signal_handler(int sig);
static void easy_listen_close(easy_listen_t *l);
easy_io_t *easy_eio_create(easy_io_t *eio, int io_thread_count)
{
easy_io_thread_t *ioth;
easy_thread_pool_t *tp;
easy_pool_t *pool;
int v;
{
static int show_version = 1;
if (show_version) {
show_version = 0;
easy_info_log("%s \n", easy_version);
}
}
if (eio != NULL && eio->pool != NULL) {
return eio;
}
if (io_thread_count <= 0 || io_thread_count > EASY_MAX_THREAD_CNT) {
io_thread_count = sysconf(_SC_NPROCESSORS_CONF);
}
if ((pool = easy_pool_create(0)) == NULL) {
return NULL;
}
if (eio == NULL && (eio = (easy_io_t *)easy_pool_alloc(pool, sizeof(easy_io_t))) == NULL) {
easy_pool_destroy(pool);
return NULL;
}
memset(eio, 0, sizeof(easy_io_t));
eio->pool = pool;
eio->io_thread_count = io_thread_count;
eio->start_time = ev_time();
easy_list_init(&eio->thread_pool_list);
ev_set_allocator(realloc_lowlevel);
//create summary buffer
eio->eio_summary = easy_summary_create();
tp = easy_baseth_pool_create(eio, io_thread_count, sizeof(easy_io_thread_t));
if (tp == NULL) {
goto error_exit;
}
eio->io_thread_pool = tp;
eio->tcp_nodelay = 1;
eio->no_delayack = 1;
eio->use_accept4 = 1;
eio->tcp_defer_accept = 1;
eio->do_signal = 1;
eio->tcp_keepalive = 1; // open tcp_keepAlive
eio->send_qlen = EASY_CONN_DOING_REQ_CNT * 16;
eio->support_ipv6 = easy_socket_support_ipv6();
eio->listen_backlog = 1024;
eio->ssl = NULL;
eio->ssl_rwlock_.ref_cnt = 0;
eio->ssl_rwlock_.wait_write = 0;
eio->keepalive_enabled = 0;
#ifdef HAVE_RECVMMSG
eio->recv_vlen = 8;
#endif
easy_thread_pool_for_each(ioth, tp, 0) {
easy_list_init(&ioth->connected_list);
v = offsetof(easy_client_t, client_list_node);
ioth->client_list = easy_hash_create(pool, EASY_MAX_CLIENT_CNT / io_thread_count, v);
ioth->client_array = easy_array_create(sizeof(easy_client_t));
easy_list_init(&ioth->conn_list);
easy_list_init(&ioth->session_list);
easy_list_init(&ioth->request_list);
ev_timer_init(&ioth->listen_watcher, easy_connection_on_listen, 0.0, 0.1);
ioth->listen_watcher.data = ioth;
ioth->iot = 1;
// base thread init
easy_baseth_init(ioth, tp, easy_io_on_thread_start, easy_connection_on_wakeup);
}
signal(SIGPIPE, SIG_IGN);
// add to easy_io_list_var
easy_spin_lock(&easy_io_list_lock);
easy_list_add_tail(&eio->eio_list_node, &easy_io_list_var);
easy_spin_unlock(&easy_io_list_lock);
return eio;
error_exit:
easy_eio_destroy(eio);
return NULL;
}
void easy_eio_destroy(easy_io_t *eio)
{
easy_pool_t *pool;
easy_io_thread_t *ioth;
easy_thread_pool_t *tp;
easy_listen_t *l;
if (eio == NULL)
return;
easy_spin_lock(&easy_io_list_lock);
eio->stoped = 1;
if (eio->eio_list_node.prev) easy_list_del(&eio->eio_list_node);
easy_spin_unlock(&easy_io_list_lock);
// close listen
for (l = eio->listen; l; l = l->next) {
easy_listen_close(l);
}
for (l = eio->listenadd; l; l = l->next) {
easy_listen_close(l);
}
// destroy io_thread
if (eio->io_thread_pool) {
easy_thread_pool_for_each(ioth, eio->io_thread_pool, 0) {
easy_io_thread_destroy(ioth);
}
}
// destroy baseth pool
easy_list_for_each_entry(tp, &eio->thread_pool_list, list_node) {
easy_baseth_pool_destroy(tp);
}
easy_summary_destroy(eio->eio_summary);
pool = eio->pool;
memset(eio, 0, sizeof(easy_io_t));
easy_pool_destroy(pool);
easy_debug_log("easy_eio_destroy, eio=%p\n", eio);
}
int easy_eio_start(easy_io_t *eio)
{
easy_baseth_t *th;
easy_thread_pool_t *tp;
if (eio == NULL || eio->pool == NULL) {
return EASY_ERROR;
}
if (eio->started) {
return EASY_ABORT;
}
if (eio->tcp_nodelay) {
eio->tcp_cork = 0;
eio->no_delayack = 0;
}
if (eio->do_signal) {
struct sigaction sigact;
memset(&sigact, 0, sizeof(struct sigaction));
sigact.sa_handler = easy_signal_handler;
sigemptyset(&sigact.sa_mask);
sigaction(39, &sigact, NULL);
sigact.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
}
easy_spin_lock(&eio->lock);
easy_list_for_each_entry(tp, &eio->thread_pool_list, list_node) {
easy_thread_pool_for_each(th, tp, 0) {
pthread_create(&(th->tid), NULL, th->on_start, (void *)th);
}
easy_baseth_pool_monitor(tp);
}
eio->started = 1;
easy_spin_unlock(&eio->lock);
return EASY_OK;
}
int easy_eio_wait(easy_io_t *eio)
{
easy_baseth_t *th;
easy_thread_pool_t *tp;
easy_spin_lock(&eio->lock);
easy_list_for_each_entry(tp, &eio->thread_pool_list, list_node) {
easy_spin_unlock(&eio->lock);
easy_thread_pool_for_each(th, tp, 0) {
if (th->tid && pthread_join(th->tid, NULL) == EDEADLK) {
easy_fatal_log("easy_io_wait fatal, eio=%p, tid=%lx\n", eio, th->tid);
abort();
}
th->tid = 0;
}
easy_spin_lock(&eio->lock);
easy_info_log("easy_io_wait join monitor, tp=0x%lx tid=%lx\n", tp, tp->monitor_tid);
if (tp->monitor_tid && pthread_join(tp->monitor_tid, NULL) == EDEADLK) {
easy_fatal_log("easy_io_wait fatal, eio=%p, tid=%lx\n", eio, tp->monitor_tid);
abort();
}
tp->monitor_tid = 0;
}
easy_spin_unlock(&eio->lock);
easy_debug_log("easy_io_wait exit, eio=%p\n", eio);
return EASY_OK;
}
int easy_eio_shutdown(easy_io_t *eio)
{
easy_thread_pool_t *tp, *tp1;
if (eio == NULL || eio->shutdown) {
return EASY_ERROR;
}
easy_debug_log("easy_eio_shutdown exit, eio=%p\n", eio);
eio->shutdown = 1;
easy_list_for_each_entry_safe(tp, tp1, &eio->thread_pool_list, list_node) {
easy_baseth_pool_on_wakeup(tp);
}
easy_debug_log("easy_eio_shutdown exit, eio=%p %s\n", eio, easy_version);
return EASY_OK;
}
int easy_eio_stop(easy_io_t *eio)
{
easy_thread_pool_t *tp, *tp1;
if (eio == NULL || eio->stoped) {
return EASY_ERROR;
}
easy_debug_log("easy_eio_stop exit, eio=%p\n", eio);
eio->stoped = 1;
easy_list_for_each_entry_safe(tp, tp1, &eio->thread_pool_list, list_node) {
tp->stoped = 1;
easy_baseth_pool_on_wakeup(tp);
}
easy_debug_log("easy_eio_stop exit, eio=%p %s\n", eio, easy_version);
return EASY_OK;
}
/**
* set keepalive_enabled of eio.
*/
void easy_eio_set_keepalive(easy_io_t *eio, int keepalive_enabled)
{
eio->keepalive_enabled = keepalive_enabled;
}
struct ev_loop *easy_eio_thread_loop(easy_io_t *eio, int index)
{
easy_io_thread_t *ioth;
ioth = (easy_io_thread_t *)easy_thread_pool_index(eio->io_thread_pool, index);
return (ioth ? ioth->loop : NULL);
}
void easy_eio_stat_watcher_start(easy_io_t *eio, ev_timer *stat_watcher, double interval,
easy_io_stat_t *iostat, easy_io_stat_process_pt *process)
{
easy_io_thread_t *ioth;
memset(iostat, 0, sizeof(easy_io_stat_t));
iostat->last_cnt = 0;
iostat->last_time = eio->start_time;
iostat->process = process;
iostat->eio = eio;
ioth = (easy_io_thread_t *)easy_thread_pool_index(eio->io_thread_pool, 0);
ev_timer_init(stat_watcher, easy_io_stat_process, 0., interval);
stat_watcher->data = iostat;
ev_timer_start(ioth->loop, stat_watcher);
easy_baseth_on_wakeup(ioth);
}
void easy_eio_set_uthread_start(easy_io_t *eio, easy_io_uthread_start_pt *on_utstart, void *args)
{
easy_io_thread_t *ioth;
eio->uthread_enable = 1;
easy_thread_pool_for_each(ioth, eio->io_thread_pool, 0) {
ioth->on_utstart = on_utstart;
ioth->ut_args = args;
}
}
//////////////////////////////////////////////////////////////////////////////
static void *easy_io_on_thread_start(void *args)
{
easy_listen_t *l;
easy_io_thread_t *ioth;
easy_io_t *eio;
ioth = (easy_io_thread_t *) args;
easy_baseth_self = (easy_baseth_t *) args;
eio = ioth->eio;
if (eio->block_thread_signal) {
pthread_sigmask(SIG_BLOCK, &eio->block_thread_sigset, NULL);
}
// sched_setaffinity
if (eio->affinity_enable) {
static easy_atomic_t cpuid = -1;
int cpunum = sysconf(_SC_NPROCESSORS_CONF);
cpu_set_t mask;
int idx = (easy_atomic_add_return(&cpuid, 1) & 0x7fffffff) % cpunum;
CPU_ZERO(&mask);
CPU_SET(idx, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
easy_error_log("sched_setaffinity error: %d (%s), cpuid=%d\n", errno, strerror(errno), cpuid);
}
}
if (eio->listen) {
int ts = (eio->listen_all || eio->io_thread_count == 1);
for (l = eio->listen; l; l = l->next) {
if (l->reuseport || ts) {
if (ntohs(l->addr.port) >= 1024) {
easy_connection_reuseport(eio, l, ioth->idx);
}
ev_io_start(ioth->loop, &l->read_watcher[ioth->idx]);
} else {
if (ntohs(l->addr.port) >= 1024) {
ev_timer_start(ioth->loop, &ioth->listen_watcher);
}
}
}
}
if (eio->uthread_enable) {
easy_uthread_control_t control;
ev_set_invoke_pending_cb(ioth->loop, easy_io_uthread_invoke);
easy_uthread_init(&control);
easy_uthread_create(easy_io_on_uthread_evstart, ioth->loop, 256 * 1024);
if (ioth->on_utstart) {
easy_uthread_create(easy_io_on_uthread_start, ioth, EASY_UTHREAD_STACK);
easy_baseth_on_wakeup(ioth);
}
easy_uthread_scheduler();
easy_uthread_destroy();
} else {
if (ioth->on_utstart) ioth->on_utstart(ioth->ut_args);
ev_run(ioth->loop, 0);
}
easy_baseth_self = NULL;
easy_debug_log("pthread exit: %lx\n", pthread_self());
return (void *)NULL;
}
static void easy_io_on_uthread_start(void *args)
{
easy_io_thread_t *ioth = (easy_io_thread_t *)args;
if (ioth->on_utstart) {
(ioth->on_utstart)(ioth->ut_args);
}
}
static void easy_io_on_uthread_evstart(void *args)
{
ev_run((struct ev_loop *)args, 0);
}
static void easy_io_thread_destroy(easy_io_thread_t *ioth)
{
easy_connection_t *c, *c1;
easy_session_t *s, *s1;
// session at ioth
easy_spin_lock(&ioth->thread_lock);
easy_list_for_each_entry_safe(s, s1, &ioth->session_list, session_list_node) {
easy_list_del(&s->session_list_node);
if (s->status && s->pool) {
easy_pool_destroy(s->pool);
}
}
// connection at ioth
easy_list_for_each_entry_safe(c, c1, &ioth->conn_list, conn_list_node) {
EASY_CONNECTION_DESTROY(c, "thread_destroy");
}
// foreach connected_list
easy_list_for_each_entry_safe(c, c1, &ioth->connected_list, conn_list_node) {
EASY_CONNECTION_DESTROY(c, "thread_destroy");
}
easy_spin_unlock(&ioth->thread_lock);
easy_array_destroy(ioth->client_array);
}
static void easy_io_stat_process(struct ev_loop *loop, ev_timer *w, int revents)
{
easy_io_stat_t *iostat;
ev_tstamp last_time, t1, t2;
int64_t last_cnt;
easy_io_thread_t *ioth;
easy_io_t *eio;
iostat = (easy_io_stat_t *)w->data;
eio = iostat->eio;
last_time = ev_now(loop);
last_cnt = 0;
int ql = 0;
easy_connection_t *c;
easy_thread_pool_for_each(ioth, eio->io_thread_pool, 0) {
last_cnt += ioth->done_request_count;
easy_list_for_each_entry(c, &ioth->connected_list, conn_list_node) {
ql += c->con_summary->doing_request_count;
}
}
t1 = last_time - iostat->last_time;
t2 = last_time - eio->start_time;
iostat->last_speed = (last_cnt - iostat->last_cnt) / t1;
iostat->total_speed = last_cnt / t2;
iostat->last_cnt = last_cnt;
iostat->last_time = last_time;
if (iostat->process == NULL) {
easy_info_log("cnt: %" PRId64 ", speed: %.2f, total_speed: %.2f, ql:%d\n",
iostat->last_cnt, iostat->last_speed, iostat->total_speed, ql);
} else {
(iostat->process)(iostat);
}
}
static void easy_signal_handler(int sig)
{
easy_io_t *eio, *e1;
if (easy_trylock(&easy_io_list_lock) == 0) {
return;
}
if (sig == SIGINT || sig == SIGTERM) {
easy_list_for_each_entry_safe(eio, e1, &easy_io_list_var, eio_list_node) {
easy_eio_stop(eio);
}
} else if (sig == 39) {
easy_list_for_each_entry_safe(eio, e1, &easy_io_list_var, eio_list_node) {
easy_io_print_status(eio);
}
}
easy_unlock(&easy_io_list_lock);
}
static void easy_io_uthread_invoke(struct ev_loop *loop)
{
easy_baseth_t *th = (easy_baseth_t *) ev_userdata(loop);
if (th->eio->stoped) {
ev_break(loop, EVBREAK_ALL);
easy_uthread_stop();
return;
}
ev_invoke_pending(loop);
while (easy_uthread_yield() > 0);
}
static void easy_io_print_status(easy_io_t *eio)
{
easy_connection_t *c;
easy_io_thread_t *ioth;
// foreach connected_list
easy_thread_pool_for_each(ioth, eio->io_thread_pool, 0) {
easy_info_log("thread:%d, doing: %d, done: %" PRIdFAST32 "\n", ioth->idx,
ioth->doing_request_count, ioth->done_request_count);
easy_list_for_each_entry(c, &ioth->connected_list, conn_list_node) {
easy_info_log("%d %s => doing: %d, done:%" PRIdFAST32 "\n", ioth->idx, easy_connection_str(c),
c->con_summary->doing_request_count, c->con_summary->done_request_count);
}
}
}
static void easy_listen_close(easy_listen_t *l)
{
int i;
if (l->reuseport) {
for (i = 0; i < l->bind_port_cnt; i++) {
if (l->read_watcher[i].fd != l->fd) {
easy_socket_set_linger(l->read_watcher[i].fd, 0);
easy_safe_close(l->read_watcher[i].fd);
}
}
}
easy_socket_set_linger(l->fd, 0);
easy_safe_close(l->fd);
}
#ifndef EASY_IO_H_
#define EASY_IO_H_
#include <easy_define.h>
#include <unistd.h>
#include <pthread.h>
#include "easy_io_struct.h"
#include "easy_log.h"
#include "easy_summary.h"
EASY_CPP_START
///////////////////////////////////////////////////////////////////////////////////////////////////
// easy_io_t
extern easy_io_t *easy_eio_create(easy_io_t *eio, int io_thread_count);
extern int easy_eio_start(easy_io_t *eio);
extern int easy_eio_wait(easy_io_t *eio);
extern int easy_eio_stop(easy_io_t *eio);
extern int easy_eio_shutdown(easy_io_t *eio);
extern void easy_eio_destroy(easy_io_t *eio);
extern void easy_eio_set_keepalive(easy_io_t *eio, int keepalive_enabled);
extern void easy_eio_set_uthread_start(easy_io_t *eio, easy_io_uthread_start_pt *on_utstart, void *args);
extern struct ev_loop *easy_eio_thread_loop(easy_io_t *eio, int index);
extern void easy_eio_stat_watcher_start(easy_io_t *eio, ev_timer *stat_watcher,
double interval, easy_io_stat_t *iostat, easy_io_stat_process_pt *process);
///////////////////////////////////////////////////////////////////////////////////////////////////
// easy_connection_t
extern easy_listen_t *easy_connection_add_listen(easy_io_t *eio, const char *host, int port, easy_io_handler_pt *handler);
extern easy_connection_t *easy_connection_connect_thread(easy_io_t *eio, easy_addr_t addr,
easy_io_handler_pt *handler, int conn_timeout, void *args, int flags);
extern int easy_connection_connect(easy_io_t *eio, easy_addr_t addr,
easy_io_handler_pt *handler, int conn_timeout, void *args, int flags);
extern int easy_connection_disconnect(easy_io_t *eio, easy_addr_t addr);
extern int easy_connection_disconnect_thread(easy_io_t *eio, easy_addr_t addr);
extern int easy_connection_send_session(easy_connection_t *c, easy_session_t *s);
extern int easy_connection_send_session_data(easy_connection_t *c, easy_session_t *s);
extern char *easy_connection_str(easy_connection_t *c);
extern int easy_connection_dispatch_to_thread(easy_connection_t *c, easy_io_thread_t *ioth);
extern easy_session_t *easy_connection_connect_init(easy_session_t *s, easy_io_handler_pt *handler,
int conn_timeout, void *args, int flags, char *servername);
extern easy_connection_t *easy_connection_connect_thread_ex(easy_addr_t addr, easy_session_t *s);
extern int easy_connection_connect_ex(easy_io_t *eio, easy_addr_t addr, easy_session_t *s);
extern int easy_connection_destroy_dispatch(easy_connection_t *c);
extern easy_listen_t *easy_add_listen(easy_io_t *eio, const char *host, int port,
easy_io_handler_pt *handler, void *args);
extern easy_listen_t *easy_add_listen_addr(easy_io_t *eio, easy_addr_t addr,
easy_io_handler_pt *handler, int udp, void *args);
extern int easy_connection_write_buffer(easy_connection_t *c, const char *data, int len);
extern int easy_connection_pause(easy_connection_t *c, int ms);
///////////////////////////////////////////////////////////////////////////////////////////////////
// easy_session
extern easy_session_t *easy_session_create(int64_t size);
extern void easy_session_destroy(void *s);
///////////////////////////////////////////////////////////////////////////////////////////////////
// easy_client uthread
extern int easy_client_uthread_wait_conn(easy_connection_t *c);
extern int easy_client_uthread_wait_session(easy_session_t *s);
extern void easy_client_uthread_set_handler(easy_io_handler_pt *handler);
///////////////////////////////////////////////////////////////////////////////////////////////////
// easy_client_wait
extern void easy_client_wait_init(easy_client_wait_t *w);
extern void easy_client_wait(easy_client_wait_t *w, int count);
extern void easy_client_wait_cleanup(easy_client_wait_t *w);
extern void easy_client_wait_wakeup(easy_client_wait_t *w);
extern void easy_client_wait_wakeup_request(easy_request_t *r);
extern int easy_client_wait_process(easy_request_t *r);
extern int easy_client_wait_batch_process(easy_message_t *m);
extern void *easy_client_send(easy_io_t *eio, easy_addr_t addr, easy_session_t *s);
extern int easy_client_dispatch(easy_io_t *eio, easy_addr_t addr, easy_session_t *s);
///////////////////////////////////////////////////////////////////////////////////////////////////
// easy_request
extern int easy_request_do_reply(easy_request_t *r);
extern easy_thread_pool_t *easy_thread_pool_create(easy_io_t *eio, int cnt, easy_request_process_pt *cb, void *args);
extern easy_thread_pool_t *easy_thread_pool_create_ex(easy_io_t *eio, int cnt, easy_baseth_on_start_pt *start,
easy_request_process_pt *cb, void *args);
extern int easy_thread_pool_push(easy_thread_pool_t *tp, easy_request_t *r, uint64_t hv);
extern int easy_thread_pool_push_message(easy_thread_pool_t *tp, easy_message_t *m, uint64_t hv);
extern int easy_thread_pool_push_session(easy_thread_pool_t *tp, easy_session_t *s, uint64_t hv);
extern void easy_request_addbuf(easy_request_t *r, easy_buf_t *b);
extern void easy_request_addbuf_list(easy_request_t *r, easy_list_t *list);
extern void easy_request_wakeup(easy_request_t *r);
extern void easy_request_sleeping(easy_request_t *r);
extern void easy_request_sleepless(easy_request_t *r);
///////////////////////////////////////////////////////////////////////////////////////////////////
// easy_file
extern easy_file_task_t *easy_file_task_create(easy_request_t *r, int fd, int bufsize);
extern void easy_file_task_set(easy_file_task_t *ft, char *buffer, int64_t offset, int64_t bufsize, void *args);
extern void easy_file_task_reset(easy_file_task_t *ft, int type);
///////////////////////////////////////////////////////////////////////////////////////////////////
// easy_ssl
extern int easy_ssl_init();
extern int easy_ssl_cleanup();
extern easy_ssl_t *easy_ssl_config_load(char *filename);
//extern easy_ssl_t *easy_ssl_config_load_for_mysql(const char *ssl_ca, const char *ssl_cert, const char *ssl_key);
extern easy_ssl_ctx_t *easy_ssl_ctx_load(easy_pool_t *pool, const char *ssl_ca,
const char *ssl_cert, const char *ssl_key,
const int is_from_file, const int is_babassl,
const int is_server);
extern int easy_ssl_ob_config_load(easy_io_t *eio, const char *ssl_ca,
const char *ssl_cert, const char *ssl_key,
const int is_from_file, const int is_babassl,
const int used_for_rpc);
extern int easy_ssl_ob_config_check(const char *ssl_ca,
const char *ssl_cert, const char *ssl_key,
const int is_from_file, const int is_babassl);
extern int easy_ssl_config_destroy(easy_ssl_t *ssl);
extern int easy_ssl_client_authenticate(easy_ssl_t *ssl, SSL *conn, const void *host, int len);
///////////////////////////////////////////////////////////////////////////////////////////////////
// define
#define EASY_IOTH_SELF ((easy_io_thread_t*) easy_baseth_self)
#define easy_session_set_args(s, a) (s)->r.args = (void*)a
#define easy_session_set_handler(s,h,ua) (s)->thread_ptr = (void *)h; (s)->status = EASY_CONNECT_SEND; (s)->r.user_data = (void *)ua;
#define easy_session_set_timeout(s, t) (s)->timeout = t
#define easy_request_set_wobj(r, w) (r)->request_list_node.prev = (easy_list_t *)w
#define easy_session_set_wobj(s, w) easy_request_set_wobj(&((s)->r), w)
#define easy_session_set_request(s, p, t, a) \
(s)->r.opacket = (void*) p; \
(s)->r.args = (void*)a; (s)->timeout = t;
#define easy_session_packet_create(type, s, size) \
((s = easy_session_create(size + sizeof(type))) ? ({ \
memset(&((s)->data[0]), 0, sizeof(type)); \
(s)->r.opacket = &((s)->data[0]); \
(type*) &((s)->data[0]);}) : NULL)
#define easy_session_class_create(type, s, ...) \
((s = easy_session_create(sizeof(type))) ? ({ \
new(&((s)->data[0]))type(__VA_ARGS__); \
(s)->r.opacket = &((s)->data[0]); \
(type*) &((s)->data[0]);}) : NULL)
#ifdef EASY_MULTIPLICITY
#define easy_io_create(eio, cnt) easy_eio_create(eio, cnt)
#define easy_io_start(eio) easy_eio_start(eio)
#define easy_io_wait(eio) easy_eio_wait(eio)
#define easy_io_stop(eio) easy_eio_stop(eio)
#define easy_io_shutdown(eio) easy_eio_shutdown(eio)
#define easy_io_destroy(eio) easy_eio_destroy(eio)
#define easy_io_thread_loop(a,b) easy_eio_thread_loop(a,b)
#define easy_io_set_uthread_start(eio,start,args) easy_eio_set_uthread_start(eio,start,args)
#define easy_io_stat_watcher_start(a1,a2,a3,a4,a5) easy_eio_stat_watcher_start(a1,a2,a3,a4,a5)
#define easy_io_add_listen(eio,host,port,handler) easy_connection_add_listen(eio,host,port,handler)
#define easy_io_connect(eio,addr,handler,t,args) easy_connection_connect(eio,addr,handler,t,args,0)
#define easy_io_connect_thread(eio,addr,h,t,args) easy_connection_connect_thread(eio,addr,h,t,args,0)
#define easy_io_disconnect(eio,addr) easy_connection_disconnect(eio,addr)
#define easy_io_disconnect_thread(eio,addr) easy_connection_disconnect_thread(eio,addr)
#define easy_request_thread_create(eio,cnt,cb,args) easy_thread_pool_create(eio,cnt,cb,args)
#define easy_io_dispatch(eio,addr,s) easy_client_dispatch(eio,addr,s)
#define easy_io_send(eio,addr,s) easy_client_send(eio,addr,s);
#else
#define easy_io_create(cnt) easy_eio_create(&easy_io_var, cnt)
#define easy_io_start() easy_eio_start(&easy_io_var)
#define easy_io_wait() easy_eio_wait(&easy_io_var)
#define easy_io_stop() easy_eio_stop(&easy_io_var)
#define easy_io_shutdown() easy_eio_shutdown(&easy_io_var)
#define easy_io_destroy() easy_eio_destroy(&easy_io_var)
#define easy_io_thread_loop(a) easy_eio_thread_loop(&easy_io_var,a)
#define easy_io_set_uthread_start(start,args) easy_eio_set_uthread_start(&easy_io_var,start,args)
#define easy_io_stat_watcher_start(a1,a2,a3,a4) easy_eio_stat_watcher_start(&easy_io_var,a1,a2,a3,a4)
#define easy_io_add_listen(host,port,handler) easy_connection_add_listen(&easy_io_var,host,port,handler)
#define easy_io_connect(addr,handler,t,args) easy_connection_connect(&easy_io_var,addr,handler,t,args,0)
#define easy_io_connect_thread(addr,h,t,args) easy_connection_connect_thread(&easy_io_var,addr,h,t,args,0)
#define easy_io_disconnect(addr) easy_connection_disconnect(&easy_io_var,addr)
#define easy_io_disconnect_thread(addr) easy_connection_disconnect_thread(&easy_io_var,addr)
#define easy_request_thread_create(cnt, cb, args) easy_thread_pool_create(&easy_io_var, cnt, cb, args)
#define easy_io_dispatch(addr,s) easy_client_dispatch(&easy_io_var,addr,s)
#define easy_io_send(addr,s) easy_client_send(&easy_io_var,addr,s);
#endif
extern __thread easy_baseth_t *easy_baseth_self;
extern easy_io_t easy_io_var;
EASY_CPP_END
#endif
此差异已折叠。
#include <easy_log.h>
#include <easy_time.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "easy_io.h"
#define gettid() syscall(__NR_gettid)
easy_log_print_pt easy_log_print = easy_log_print_default;
easy_log_format_pt easy_log_format = easy_log_format_default;
easy_log_level_t easy_log_level = EASY_LOG_INFO;
__attribute__((constructor)) void init_easy_warn_threshold()
{
ev_loop_warn_threshold = atoll(getenv("easy_warn_threshold") ? : "10000");
}
void easy_log_set_print(easy_log_print_pt p)
{
easy_log_print = p;
ev_set_syserr_cb(easy_log_print);
}
int64_t get_us()
{
return fast_current_time();
}
uint64_t easy_fnv_hash(const char *str)
{
uint32_t offset_basis = 0x811C9DC5;
uint32_t prime = 0x01000193;
uint32_t fnv1 = offset_basis;
uint32_t fnv1a = offset_basis;
const char *p = str;
while (*p != '\0') {
fnv1 *= prime;
fnv1 ^= *p;
fnv1a ^= *p;
fnv1a *= prime;
p++;
}
return (uint64_t)fnv1 << 32 | fnv1a;
}
void easy_log_set_format(easy_log_format_pt p)
{
easy_log_format = p;
}
void easy_log_format_default(int level, const char *file, int line, const char *function, uint64_t location_hash_val,
const char *fmt, ...)
{
((void)(location_hash_val));
static __thread ev_tstamp oldtime = 0.0;
static __thread char time_str[32];
ev_tstamp now;
int len;
char buffer[4096];
if (easy_baseth_self && easy_baseth_self->loop) {
now = ev_now(easy_baseth_self->loop);
} else {
now = time(NULL);
}
if (oldtime != now) {
time_t t;
struct tm tm;
oldtime = now;
t = (time_t) now;
easy_localtime((const time_t *)&t, &tm);
lnprintf(time_str, 32, "[%04d-%02d-%02d %02d:%02d:%02d.%03d]",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, (int)((now - t) * 1000));
}
// print
len = lnprintf(buffer, 128, "%s %s:%d(tid:%lx)[%ld] ", time_str, file, line, pthread_self(), gettid());
va_list args;
va_start(args, fmt);
len += easy_vsnprintf(buffer + len, 4090 - len, fmt, args);
va_end(args);
while (buffer[len - 1] == '\n') {
len --;
}
buffer[len++] = '\n';
buffer[len] = '\0';
easy_log_print(buffer);
}
void easy_log_print_default(const char *message)
{
easy_ignore(write(2, message, strlen(message)));
}
void __attribute__((constructor)) easy_log_start_()
{
char *p = getenv("easy_log_level");
if (p) easy_log_level = (easy_log_level_t)atoi(p);
}
#ifndef EASY_LOG_H_
#define EASY_LOG_H_
#include <easy_define.h>
#include <easy_string.h>
#include <easy_baseth_pool.h>
#include "easy_time.h"
EASY_CPP_START
typedef void (*easy_log_print_pt)(const char *message);
typedef void (*easy_log_format_pt)(int level, const char *file, int line, const char *function,
uint64_t location_hash_val, const char *fmt, ...);
typedef enum {
EASY_LOG_OFF = -2,
EASY_LOG_FATAL,
EASY_LOG_ERROR,
EASY_LOG_USER_ERROR, // align with observer
EASY_LOG_WARN,
EASY_LOG_INFO,
EASY_LOG_DEBUG,
EASY_LOG_TRACE,
EASY_LOG_ALL
} easy_log_level_t;
#define EASY_STRINGIZE_(x) #x
#define EASY_STRINGIZE(x) EASY_STRINGIZE_(x)
#define easy_common_log(level, format, args...) \
do { \
if (easy_log_level>=level) { \
static uint64_t hash_val = 0; \
if (0 == hash_val) { \
hash_val = easy_fnv_hash(__FILE__":"EASY_STRINGIZE(__LINE__)); \
} \
easy_log_format(level, __FILE__, __LINE__, __FUNCTION__, hash_val, format, ## args); \
} \
} while (0)
#define easy_fatal_log(format, args...) easy_common_log(EASY_LOG_FATAL, format, ## args)
#define easy_error_log(format, args...) easy_common_log(EASY_LOG_ERROR, format, ## args)
#define easy_warn_log(format, args...) easy_common_log(EASY_LOG_WARN, format, ## args)
#define easy_info_log(format, args...) easy_common_log(EASY_LOG_INFO, format, ## args)
#define easy_debug_log(format, args...) easy_common_log(EASY_LOG_DEBUG, format, ## args)
#define easy_trace_log(format, args...) easy_common_log(EASY_LOG_TRACE, format, ## args)
#define SYS_ERROR(format...) easy_error_log(format)
#define EASY_PRINT_BT(format, args...) \
{char _buffer_stack_[256];{void *array[10];int i, idx=0, n = backtrace(array, 10); \
for (i = 0; i < n; i++) idx += lnprintf(idx+_buffer_stack_, 25, "%p ", array[i]);}\
easy_log_format(EASY_LOG_OFF, __FILE__, __LINE__, __FUNCTION__, "%s" format, _buffer_stack_, ## args);}
extern easy_log_level_t easy_log_level;
extern easy_log_format_pt easy_log_format;
extern void easy_log_set_print(easy_log_print_pt p);
extern void easy_log_set_format(easy_log_format_pt p);
extern void easy_log_format_default(int level, const char *file, int line, const char *function,
uint64_t location_hash_val, const char *fmt, ...);
extern void easy_log_print_default(const char *message);
int64_t get_us();
uint64_t easy_fnv_hash(const char *str);
extern int64_t ev_loop_warn_threshold;
extern __thread int64_t ev_malloc_count;
extern __thread int64_t ev_malloc_time;
extern __thread int64_t ev_write_count;
extern __thread int64_t ev_write_time;
extern __thread int64_t ev_read_count;
extern __thread int64_t ev_read_time;
extern __thread int64_t ev_client_cb_count;
extern __thread int64_t ev_client_cb_time;
extern __thread int64_t ev_server_process_count;
extern __thread int64_t ev_server_process_time;
extern __thread void *ev_watch_pending_addr;
extern __thread int ev_watch_pending;
#ifndef __clang__
#define EASY_STAT_TIME_GUARD(stat, format, ...) void __tg_cleanup(void* s) { int64_t cost = get_us() - *(int64_t*)s; stat; if (cost > ev_loop_warn_threshold) {easy_warn_log("easy cost too much time: %ldus " format, cost, ##__VA_ARGS__);} } \
int64_t _tg_s __attribute__((cleanup(__tg_cleanup))) = get_us();
#define EASY_SOCKET_IO_TIME_GUARD(stat, format, ...) \
void __tg_cleanup(void* s) \
{ \
int ret; \
int64_t cost = get_us() - *(int64_t*)s; \
double loadavg[3]; \
stat; \
if (cost > ev_loop_warn_threshold) { \
ret = getloadavg(loadavg, 3); \
if (ret == 3) { \
easy_warn_log("easy cost too much time(%ldus). loadavg(%lf, %lf, %lf)" format, cost, loadavg[0], loadavg[1], loadavg[2], ##__VA_ARGS__); \
} else { \
easy_warn_log("easy cost too much time(%ldus) " format, cost, ##__VA_ARGS__); \
} \
} \
} \
int64_t _tg_s __attribute__((cleanup(__tg_cleanup))) = get_us();
#else
#define EASY_STAT_TIME_GUARD(...)
#define EASY_SOCKET_IO_TIME_GUARD(...)
#endif
#define EASY_TIME_GUARD(format, ...) EASY_STAT_TIME_GUARD((void)0, format, ##__VA_ARGS__)
EASY_CPP_END
#endif
#include "easy_maccept.h"
#include <sys/epoll.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "easy_define.h"
#include "easy_log.h"
#include "easy_socket.h"
#define ma_log(level, fd, format, ...) easy_ ## level ## _log ("easy dispatch socket: fd=%d remote=%s " format, fd, easy_peername(fd), ## __VA_ARGS__)
#define MAX_GROUP_COUNT 16
#define MAX_THREAD_COUNT 256
typedef struct easy_ma_t {
easy_addr_t addr;
int flags;
int efd;
int lfd;
pthread_t th;
volatile int stop;
int g_count;
int g_start[MAX_GROUP_COUNT];
int g_size[MAX_GROUP_COUNT];
int chan[MAX_GROUP_COUNT * MAX_THREAD_COUNT];
} easy_ma_t;
easy_ma_t g_ma;
void easy_ma_init(int port)
{
int i;
g_ma.addr = easy_inet_str_to_addr((port & 0x10000) ? "[]" : NULL, port & 0xffff);
g_ma.flags = EASY_FLAGS_DEFERACCEPT | EASY_FLAGS_SREUSEPORT;
g_ma.stop = 1;
for (i = 0; i < MAX_GROUP_COUNT; i++) {
g_ma.g_start[i] = MAX_THREAD_COUNT;
}
}
static int round_robin(int base, int cnt, int idx)
{
return base + ((idx - base) % cnt);
}
static int choose_dispatch_chan(int* gstart, int* gsize, int idx)
{
static int accept_seq = 0;
int i = 0;
for (i = 0; i < MAX_GROUP_COUNT; i++) {
if (gstart[i] > idx)
break;
}
if (i <= 0 || i >= MAX_GROUP_COUNT) {
return round_robin(gstart[0], gsize[0], accept_seq++);
} else {
return round_robin(gstart[i - 1], gsize[i - 1], idx);
}
}
static char* easy_peername(int fd)
{
static char buf[256];
easy_addr_t addr = easy_inet_getpeername(fd);
return easy_inet_addr_to_str(&addr, buf, sizeof(buf));
}
static void easy_ma_dispatch(int idx, int fd)
{
if (fd < 0) return;
int t = choose_dispatch_chan(g_ma.g_start, g_ma.g_size, idx);
int wb = 0;
while ((wb = write(g_ma.chan[t], &fd, sizeof(fd))) < 0
&& errno == EINTR);
if (wb != sizeof(fd)) {
ma_log(error, fd, "write gid fail: idx=%d", idx);
} else {
ma_log(info, fd, "dispatch succ: idx=%d", idx);
}
}
static struct epoll_event *__make_epoll_event(struct epoll_event *event, uint32_t event_flag, int fd)
{
event->events = event_flag;
event->data.fd = fd;
return event;
}
static int epoll_add(int efd, int fd, int mask)
{
struct epoll_event event;
return epoll_ctl(efd, EPOLL_CTL_ADD, fd, __make_epoll_event(&event, mask, fd));
}
static int do_accept(int efd, int lfd)
{
int nfd = accept4(lfd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (nfd < 0) return -1;
if (0 != epoll_add(efd, nfd, EPOLLIN | EPOLLPRI)) {
ma_log(error, nfd, "epoll add fail: errno=%d", errno);
close(nfd);
nfd = -1;
}
return nfd;
}
static int handle_listen_fd(int efd, int lfd, uint32_t emask)
{
int j;
if (emask & EPOLLERR) {
return -1;
}
for (j = 0; j < 64; j++) {
if (do_accept(efd, lfd) < 0) break;
}
return 0;
}
static int read_sock_pri(int fd)
{
int rb = 0;
uint8_t idx = 0;
while ((rb = recv(fd, &idx, sizeof(idx), MSG_OOB)) < 0
&& EINTR == errno)
;
return rb != 1 ? INT32_MAX : (int32_t)idx;
}
static void handle_sock_fd(int efd, int fd, uint32_t emask)
{
if (emask & EPOLLERR) {
ma_log(warn, fd, "epoll trigger error");
close(fd);
return;
}
int idx = INT32_MAX;
if (emask & EPOLLPRI) {
idx = read_sock_pri(fd);
if (idx > MAX_THREAD_COUNT) {
ma_log(error, fd, "read_sock_pri fail: errno=%d", errno);
}
} else {
ma_log(warn, fd, "old version client");
}
epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL);
easy_ma_dispatch(idx, fd);
}
void* easy_ma_thread_func(easy_ma_t* ma)
{
int i;
int efd = ma->efd;
int lfd = ma->lfd;
while (!ma->stop) {
const int maxevents = 64;
struct epoll_event events[maxevents];
int cnt = epoll_wait(efd, events, maxevents, 1000);
for (i = 0; i < cnt; i++) {
int cfd = events[i].data.fd;
int emask = events[i].events;
if (lfd == cfd) {
if (0 != handle_listen_fd(efd, lfd, emask))
goto error_exit;
} else {
handle_sock_fd(efd, cfd, emask);
}
}
}
error_exit:
easy_warn_log("easy dispatch socket thread exit: lfd=%d errno=%d", lfd, errno);
if (lfd >= 0) {
close(lfd);
}
if (efd >= 0) {
close(efd);
}
return NULL;
}
int easy_ma_start()
{
char addr_buf[128];
int lfd = -1, efd = -1;
if (g_ma.g_count <= 0) {
easy_info_log("easy dispatch thread do not need to start");
return 0;
}
easy_inet_addr_to_str(&g_ma.addr, addr_buf, sizeof(addr_buf));
if ((lfd = easy_socket_listen(0, &g_ma.addr, &g_ma.flags, 10240)) < 0) {
goto error_exit;
}
if ((efd = epoll_create1(EPOLL_CLOEXEC)) < 0) {
goto error_exit;
}
if (0 != epoll_add(efd, lfd, EPOLLIN)) {
goto error_exit;
}
g_ma.efd = efd;
g_ma.lfd = lfd;
g_ma.stop = 0;
if (0 != pthread_create(&g_ma.th, NULL, (void*)easy_ma_thread_func, (void*)&g_ma)) {
goto error_exit;
}
easy_info_log("easy dispatch socket thread start: lfd=%d addr=%s", lfd, addr_buf);
return 0;
error_exit:
easy_error_log("easy dispatch socket thread start fail: gcount=%d addr=%s lfd=%d efd=%d errno=%d epoll_add_succ=%d", g_ma.g_count, addr_buf, lfd, efd, errno, g_ma.stop == 0);
g_ma.stop = 1;
return -1;
}
void easy_ma_stop()
{
if (!g_ma.stop) {
g_ma.stop = 1;
pthread_join(g_ma.th, NULL);
}
}
static int create_pipe(int* wfd)
{
int fd[2];
if (0 != pipe2(fd, O_NONBLOCK)) return -1;
*wfd = fd[1];
return fd[0];
}
int easy_ma_regist(int gid, int idx)
{
if (g_ma.g_count <= 0 || g_ma.g_start[g_ma.g_count - 1] != gid) {
g_ma.g_start[g_ma.g_count++] = gid;
}
g_ma.g_size[g_ma.g_count - 1] = idx + 1;
return create_pipe(g_ma.chan + gid + idx);
}
int easy_ma_handshake(int fd, int idx)
{
int err = 0;
uint8_t id = idx;
int wb = 0;
int64_t time_limit = get_us() + 100 * 1000;
if (g_ma.stop) {
return 0;
}
while (0 == err && (wb = send(fd, &id, 1, MSG_OOB)) < 0) {
if (EINTR == errno) {
// pass
} else if (EAGAIN == errno || EWOULDBLOCK == errno) {
if (get_us() > time_limit) {
ma_log(error, fd, "handshake EAGAIN: idx=%d", idx);
break;
}
} else {
err = errno;
}
}
return err;
}
#ifndef __EASY_MACCEPT_H__
#define __EASY_MACCEPT_H__
#include "easy_define.h"
EASY_CPP_START
extern void easy_ma_init(int port);
extern int easy_ma_start();
extern void easy_ma_stop();
extern int easy_ma_regist(int gid, int idx);
extern int easy_ma_handshake(int fd, int id);
EASY_CPP_END
#endif /* __EASY_MACCEPT_H__ */
#include "easy_io.h"
#include "easy_message.h"
#include "easy_connection.h"
#include "easy_request.h"
#include "easy_baseth_pool.h"
#include "easy_util.h"
#ifdef EASY_DEBUG_DOING
easy_atomic_t easy_debug_uuid = 0;
#endif
easy_message_t *easy_message_create_nlist(easy_connection_t *c)
{
easy_pool_t *pool;
easy_message_t *m;
easy_buf_t *input;
int size;
if ((pool = easy_pool_create(c->default_msglen)) == NULL) {
return NULL;
}
pool->ref = 1;
m = (easy_message_t *)easy_pool_calloc(pool, sizeof(easy_message_t));
size = c->first_msglen;
input = easy_buf_create(pool, size);
if (m == NULL || input == NULL) {
easy_error_log("Failed to alloc easy buffer due to OOM. System will crash.");
easy_pool_destroy(pool);
return NULL;
}
#ifdef EASY_DEBUG_MAGIC
m->magic = EASY_DEBUG_MAGIC_MESSAGE;
#endif
m->pool = pool;
m->c = c;
m->next_read_len = (c->sc != NULL) ? EASY_IO_BUFFER_SIZE : size;
m->input = input;
m->type = EASY_TYPE_MESSAGE;
m->status = EASY_OK;
m->request_list_count = 0;
easy_list_init(&m->request_list);
easy_list_init(&m->all_list);
return m;
}
easy_message_t *easy_message_create(easy_connection_t *c)
{
easy_message_t *m = easy_message_create_nlist(c);
if (m == NULL) {
return NULL;
} else {
easy_list_add_tail(&m->message_list_node, &c->message_list);
}
return m;
}
int easy_message_destroy(easy_message_t *m, int del)
{
easy_request_t *r, *n;
// delete from message_list
if (del) {
if (m->status == EASY_MESG_DESTROY)
return EASY_OK;
m->status = EASY_MESG_DESTROY;
easy_list_del(&m->message_list_node);
}
if (easy_atomic_add_return(&m->pool->ref, -1) == 0) {
// server done
easy_list_for_each_entry_safe(r, n, &m->all_list, all_node) {
easy_list_del(&r->all_node);
easy_list_del(&r->request_list_node);
easy_request_server_done(r);
}
easy_list_del(&m->message_list_node);
if (m->input) easy_buf_destroy(m->input);
#ifdef EASY_DEBUG_MAGIC
m->magic++;
#endif
if (m->enable_trace) {
easy_debug_log("easy_message_destroy, m(%p), lbt(%s).", m, easy_lbt());
}
easy_pool_destroy(m->pool);
return EASY_BREAK;
}
return EASY_OK;
}
easy_session_t *easy_session_create(int64_t asize)
{
easy_pool_t *pool;
easy_session_t *s;
int hint = (int)(asize >> 32);
int size = (int)asize;
size += sizeof(easy_session_t);
if ((pool = easy_pool_create((hint < size ? size : hint))) == NULL) {
return NULL;
}
if ((s = (easy_session_t *)easy_pool_alloc(pool, size)) == NULL) {
easy_pool_destroy(pool);
return NULL;
}
memset(s, 0, sizeof(easy_session_t));
#ifdef EASY_DEBUG_MAGIC
s->magic = EASY_DEBUG_MAGIC_SESSION;
s->r.magic = EASY_DEBUG_MAGIC_REQUEST;
#endif
#ifdef EASY_DEBUG_DOING
s->r.uuid = easy_atomic_add_return(&easy_debug_uuid, 1);
#endif
s->pool = pool;
s->r.ms = (easy_message_session_t *)s;
s->type = EASY_TYPE_SESSION;
easy_list_init(&s->session_list_node);
return s;
}
void easy_session_destroy(void *data)
{
easy_message_t *m;
easy_session_t *s;
s = (easy_session_t *) data;
if (s->cleanup) {
(s->cleanup)(&s->r, NULL);
}
if (s->async && (m = (easy_message_t *)s->r.request_list_node.next)) {
s->r.request_list_node.next = NULL;
easy_message_destroy(m, 0);
}
#ifdef EASY_DEBUG_MAGIC
s->magic++;
#endif
easy_pool_destroy(s->pool);
}
int discard_residual_data_of_timeout_session = 0;
static easy_buf_t* easy_copy_and_replace_residual_data_node(easy_buf_t* b)
{
easy_buf_t* nb = discard_residual_data_of_timeout_session ? NULL : easy_buf_clone_with_private_pool(b);
if (nb) {
easy_list_replace(&b->node, &nb->node);
easy_debug_log("easy keep residual data for timeout session: size=%ld", easy_buf_len(nb));
}
return nb;
}
int easy_session_process_low_level(easy_session_t *s, int stop, int need_copy_residual_data)
{
int ret = EASY_ERROR;
int discard_cnt = 0;
int keep_cnt = 0;
int do_replace = 0;
easy_list_t *cur = NULL, *prev = NULL;
easy_buf_t *ebuf = NULL;
easy_connection_t *conn;
EASY_STAT_TIME_GUARD((ev_client_cb_count++, ev_client_cb_time += cost), "session_process");
if (stop) {
ev_timer_stop(s->c->loop, &s->timeout_watcher);
easy_list_del(&s->session_list_node);
easy_request_client_done(&s->r);
easy_atomic_dec(&s->c->pool->ref);
}
conn = s->c;
if (s->nextb && easy_list_empty(s->nextb) == 0) {
/*
* The only purpose to copy the buffers armed on connection output queue is
* to keep data integrity. When timeout happens, there are 3 cases for the
* session status: (1) the message bound to the session is completely sent
* to kernel; (2) the message is patially sent to kernel; (3) no data of the
* message is sent to kernel. Only for case(2), we have to copy the rest of
* data of the message which has not been sent to kernel. For other cases,
* they will not destroy data integrity, so we will not copy it and we just
* remove it from connection output queue.
*/
if (need_copy_residual_data) {
if (s->sent_buf_count > 0) {
do_replace = 1;
} else {
cur = s->nextb;
while (cur != &(conn->output)) {
ebuf = easy_list_entry(cur, easy_buf_t, node);
if (ebuf->args != s->pool) {
break;
}
if (ebuf->pos != ebuf->data) {
do_replace = 1;
break;
}
cur = cur->prev;
}
}
}
cur = s->nextb;
while (cur != &(conn->output)) {
ebuf = easy_list_entry(cur, easy_buf_t, node);
if (ebuf->args != s->pool) {
break;
}
prev = cur->prev;
if (do_replace) {
if (NULL == easy_copy_and_replace_residual_data_node(ebuf)) {
easy_list_del(cur);
discard_cnt++;
} else {
keep_cnt++;
}
} else {
easy_list_del(cur);
}
cur = prev;
}
s->nextb = NULL;
}
if (discard_cnt > 0 || keep_cnt > 0) {
conn->copied_buf_num += keep_cnt;
conn->discarded_buf_num += discard_cnt;
easy_debug_log("Totally %d easy_buf coppied, and %d discarded for timeout sessions "
"on connection(%p).\n", conn->copied_buf_num, conn->discarded_buf_num, conn);
}
if (s->callback) {
if (s->now) {
s->now = ev_now(s->c->loop) - s->now;
}
ret = (s->callback)(&s->r);
} else {
easy_error_log("session callback is null, s = %p\n", s);
easy_session_destroy(s);
}
return (discard_cnt > 0 ? EASY_ERROR : ret);
}
int easy_session_process(easy_session_t *s, int stop, int err)
{
s->error = err;
return easy_session_process_low_level(s, stop, 0);
}
int easy_session_process_keep_connection_resilient(easy_session_t *s, int stop, int err)
{
s->error = err;
return easy_session_process_low_level(s, stop, 1);
}
#ifndef EASY_MESSAGE_H_
#define EASY_MESSAGE_H_
#include <easy_define.h>
#include "easy_io_struct.h"
/**
* receive message
*/
EASY_CPP_START
easy_message_t *easy_message_create(easy_connection_t *c);
easy_message_t *easy_message_create_nlist(easy_connection_t *c);
int easy_message_destroy(easy_message_t *m, int del);
int easy_session_process(easy_session_t *s, int stop, int err);
int easy_session_process_keep_connection_resilient(easy_session_t* s, int stop, int err);
EASY_CPP_END
#endif
此差异已折叠。
#ifndef EASY_REQUEST_H_
#define EASY_REQUEST_H_
#include <easy_define.h>
#include "easy_io_struct.h"
EASY_CPP_START
void easy_request_server_done(easy_request_t *r);
void easy_request_client_done(easy_request_t *r);
void easy_request_set_cleanup(easy_request_t *r, easy_list_t *output);
void check_easy_request_rt(easy_session_t *s);
EASY_CPP_END
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
#ifndef EASY_TIME_H_
#define EASY_TIME_H_
#include "easy_define.h"
EASY_CPP_START
int easy_localtime(const time_t *t, struct tm *tp);
int64_t easy_time_now();
extern int64_t fast_current_time();
EASY_CPP_END
#endif
此差异已折叠。
#include "easy_define.h"
const char* easy_lbt();
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册