本文将介绍两种方式的构建方法,可根据实际情况选择手动构建或直接使用 Dockerfile 构建。
前提条件:系统上已经安装了 Make 等编译工具。
使用 MiniOB 需要具备以下两个条件。
-
CMake:3.10 版本以上。
-
GCC/Clang:GCC 建议 8.3 版本以上,编译器需要支持 C++20 等新标准。
需要安装 3.10 版本或 3.10 以上版本的 CMake,在 CMake官网 下载对应系统的 CMake。
wget https://github.com/Kitware/CMake/releases/download/v3.24.0/cmake-3.24.0-linux-x86_64.sh
bash cmake-3.24.0-linux-x86_64.sh
如果是 MAC 系统,执行以下命令安装。
brew install cmake
如果是个人学习使用,Clang 通常没有问题,如果想参加比赛或使用 OceanBase 官网训练营,建议安装 GCC。因为 Clang 某些情况下的表现会与 GCC 不一致。
另外,如果 GCC 的版本比较旧,需要安装较新版本的 GCC。有些比较旧的操作系统(如 CentOS 7),自带的编译器是 4.8.5 版本,该版本对 C++20 等新标准支持不友好,建议升级 GCC。
在 Linux 系统上,通常使用 yum install gcc gcc-g++
就可以安装 GCC,但是有些时候安装的编译器版本比较旧,需要手动安装。
-
如何查看 GCC 版本
gcc --version
-
下载 GCC 源码
可以在 GCC 官网浏览,找到镜像入口,选择速度比较快的镜像,如 Russia, Novosibirsk GCC 镜像链接。
建议选择 8.3 或以上版本。MiniOB 是为了学习使用,可以选择较新版本的 GCC,不要求稳定。
-
编译 GCC 源码
编译高版本的 GCC 时,需要本地也有一个稍高一点版本的 GCC。比如编译 GCC 11,本地的 GCC 需要能够支持 stdc++11 才能编译,可以先编译 GCC 5.4,然后再编译高版本。
# 解压 tar xzvf gcc-11.3.0.tar.gz cd gcc-11.3.0 # 下载依赖 ./contrib/download_prerequisites # 配置。可以通过 prefix 参数设置编译完成的 GCC 的安装目录,如果不指定,会安装在 /usr/local下 # 可以配置为当前用户的某个目录 ./configure --prefix=/your/new/gcc/path --enable-threads=posix --disable-checking \ --enable--long-long --with-system-zlib --enable-languages=c,c++ # 开始编译 make -j # 安装 # 编译产生物会安装到 configure --prefix 指定的目录中,或系统默认目录下 make install # 修改环境变量 # 可以将下面的配置写到 .bashrc 或 .bash_profile 中,这样每次登录都会自动生效 export PATH=/your/new/gcc/path/bin:$PATH export LD_LIBRARY_PATH=/your/new/gcc/path/lib64:$LD_LIBRARY_PATH export CC=/your/new/gcc/path/bin/gcc export CXX=/your/new/gcc/path/bin/g++ # NOTE: 上面的环境变量 CC 和 CXX 是告诉 CMake 能够找到我们的编译器。CMake 优先查找的 # 编译器是 CC 而不是 GCC,而一般系统中会默认带 CC,所以使用环境变量告诉 CMake。 # 也可以使用 CMake 参数 # `-DCMAKE_C_COMPILER=/your/new/gcc/path/bin/gcc -DCMAKE_CXX_COMPILER=/your/new/gcc/path/bin/g++` # 来指定编译器
如果
./contrib/download_prerequisites
下载时特别慢或下载失败,可以手动从官网上下载依赖,解压相应的包到 GCC 的目录下。ftp://ftp.gnu.org/gnu/gmp https://mpfr.loria.fr/mpfr-current/#download https://www.multiprecision.org/mpc/download.html
-
下载源码
git clone https://github.com/oceanbase/miniob.git
-
环境初始化
如果是第一次在这个环境上编译 MiniOB,需要执行如下命令安装 MiniOB 的依赖库。
cd miniob bash build.sh init
命令执行后,脚本会自动拉取依赖库,并编译安装到系统目录。
如果使用 GitPod 开发,可以跳过这步,GitPod 会自动执行。
-
编译
执行如下命令将编译 debug 版本的 MiniOB。
bash build.sh
执行如下命令将编译 release 版本的 MiniOB。
bash build.sh release
详细使用方法可执行
bash build.sh -h
查看帮助信息。
编译完成后,可在 build 目录(build_debug 或 build_release)下找到 bin/observer
目录,这是 MiniOB 的服务端进程,bin/obclient
是自带的客户端进程,当前服务端程序启动已经支持了多种模式,可以以 TCP、unix socket 方式启动,这时需要启动客户端以发起命令。observer 还支持直接执行命令的模式,这时不需要启动客户端,直接在命令行输入命令即可。
observer 提供的参数可通过 ./bin/observer -h
命令查看帮助。
您可执行如下命令以直接执行命令的方式启动服务端程序,这种情况下可以直接输入命令,不需要启动客户端,所有请求都会以单线程的方式运行,配置项中的线程数不再有实际意义。
./bin/observer -f ../etc/observer.ini -P cli
您可执行如下命令以监听端口的方式启动服务端程序,此处以 6789 端口为例。
./bin/observer -f ../etc/observer.ini -p 6789
这种情况下需执行如下命令启动客户端程序,启动后客户端会连接到服务端的 6789 端口。
./bin/obclient -p 6789
您可执行如下命令以监听 unix socket 的方式启动服务端程序。
./bin/observer -f ../etc/observer.ini -s miniob.sock
这种情况下需执行如下命令启动客户端程序,启动后客户端会连接到服务端的 miniob.sock 文件。
./bin/obclient -s miniob.sock
默认情况下,编译后的程序不支持并发操作,如若需要支持并发,需要在编译时增加 -DCONCURRENCY=ON
选项,示例如下。
cmake -DCONCURRENCY=ON ..
或执行如下命令。
bash build.sh -DCONCURRENCY=ON
之后使用上述命令启动服务端进程,即可支持并发操作。
问题现象:在启动服务端进程时出现报错找不到链接库 A。
可能原因:安装依赖时,默认安装在 /usr/local/
目录下,而环境变量中没有将目录包含到动态链接库查找路径。
解决方法:
您可将如下命令添加到 HOME 目录的 .bashrc
中,之后执行 source ~/.bashrc
命令加载环境变量后重新启动程序。
export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH
LD_LIBRARY_PATH
是 Linux 环境中运行时查找动态链接库的路径,路径之间以冒号(:
)分隔。
将数据写入 bashrc 或其它文件中,下次启动程序时会自动加载,而不需要再次执行 source 命令加载。
如果你的终端脚本使用的不是 bash,而是 zsh,那么就需要修改 .zshrc
。
调试 C/C++ 程序,常用的有两种方式,一是通过打印日志进行调试,二是借助 GDB 调试器进行调试。通过调试程序,可以熟悉程序执行的每一步细节,不仅可以定位问题,也可以用来熟悉代码,增加编程能力。
parse_def.h:
struct Selects; //查询相关
struct CreateTable; //建表相关
struct DropTable; //删表相关
enum SqlCommandFlag; //SQL 语句对应的 command 枚举
union Queries; //各类 DML 和 DDL 操作的联合
table.h
class Table;
db.h
class Db;
RC parse(const char *st, Query *sqln); //sql parse 入口
ExecuteStage::handle_request
ExecuteStage::do_select
DefaultStorageStage::handle_event
DefaultHandler::create_index
DefaultHandler::insert_record
DefaultHandler::delete_record
DefaultHandler::update_record
Db::create_table
Db::find_table
Table::create
Table::scan_record
Table::insert_record
Table::update_record
Table::delete_record
Table::scan_record
Table::create_index
MiniOB 提供的日志接口
deps/common/log/log.h:
#define LOG_PANIC(fmt, ...)
#define LOG_ERROR(fmt, ...)
#define LOG_WARN(fmt, ...)
#define LOG_INFO(fmt, ...)
#define LOG_DEBUG(fmt, ...)
#define LOG_TRACE(fmt, ...)
日志相关配置项 observer.ini
LOG_FILE_NAME = observer.log
# LOG_LEVEL_PANIC = 0,
# LOG_LEVEL_ERR = 1,
# LOG_LEVEL_WARN = 2,
# LOG_LEVEL_INFO = 3,
# LOG_LEVEL_DEBUG = 4,
# LOG_LEVEL_TRACE = 5,
# LOG_LEVEL_LAST
LOG_FILE_LEVEL=5
LOG_CONSOLE_LEVEL=1
-
Attach 进程
[admin@localhost run]$ gdb -p `pidof observer` GNU gdb (GDB) Red Hat Enterprise Linux 8.2-15.el8 Copyright (C) 2018 Free Software Foundation, Inc. (gdb)
-
设置断点
(gdb) break do_select Breakpoint 1 at 0x44b636: file /home/admin/source/stunning-engine/src/observer/sql/executor/execute_stage.cpp, line 526. (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x000000000044b636 in ExecuteStage::do_select(char const*, Query*, SessionEvent*) at /home/admin/source/stunning-engine/src/observer/sql/executor/execute_stage.cpp:526
(gdb) break Table::scan_record Breakpoint 2 at 0x50b82b: Table::scan_record. (2 locations) (gdb) inf b Num Type Disp Enb Address What 1 breakpoint keep y 0x000000000044b636 in ExecuteStage::do_select(char const*, Query*, SessionEvent*) at /home/admin/source/stunning-engine/src/observer/sql/executor/execute_stage.cpp:526 2 breakpoint keep y <MULTIPLE> 2.1 y 0x000000000050b82b in Table::scan_record(Trx*, ConditionFilter*, int, void*, void (*)(char const*, void*)) at /home/admin/source/stunning-engine/src/observer/storage/common/table.cpp:421 2.2 y 0x000000000050ba00 in Table::scan_record(Trx*, ConditionFilter*, int, void*, RC (*)(Record*, void*)) at /home/admin/source/stunning-engine/src/observer/storage/common/table.cpp:426 (gdb)
-
继续执行
(gdb) c Continuing.
-
触发断点
执行:miniob > select * from t1;
[Switching to Thread 0x7f51345f9700 (LWP 54706)] Thread 8 "observer" hit Breakpoint 1, ExecuteStage::do_select (this=0x611000000540, db=0x6040000005e0 "sys", sql=0x620000023080, session_event=0x608000003d20) at /home/admin/source/stunning-engine/src/observer/sql/executor/execute_stage.cpp:526 526 RC rc = RC::SUCCESS; (gdb)
-
单步调试(跳过函数调用)
575 std::vector<TupleSet> tuple_sets; (gdb) next 576 for (SelectExeNode *&node: select_nodes) { (gdb) n 577 TupleSet tuple_set; (gdb) 578 rc = node->execute(tuple_set); (gdb)
-
单步调试(进入函数调用的内部)
(gdb) s SelectExeNode::execute (this=0x60700002ce80, tuple_set=...) at /home/admin/source/stunning-engine/src/observer/sql/executor/execution_node.cpp:43 43 CompositeConditionFilter condition_filter; (gdb)
-
打印变量
(gdb) p tuple_set $3 = (TupleSet &) @0x7f51345f1760: {tuples_ = std::vector of length 0, capacity 0, schema_ = { fields_ = std::vector of length 0, capacity 0}} (gdb)
-
watch 变量
(gdb) n 443 RC rc = RC::SUCCESS; (gdb) n 444 RecordFileScanner scanner; (gdb) n 445 rc = scanner.open_scan(*data_buffer_pool_, file_id_, filter); (gdb) watch -l rc Hardware watchpoint 3: -location rc (gdb) c Continuing. Thread 8 "observer" hit Hardware watchpoint 3: -location rc Old value = SUCCESS New value = RECORD_EOF 0x000000000050c2de in Table::scan_record (this=0x60f000007840, trx=0x606000009920, filter=0x7f51345f12a0, limit=2147483647, context=0x7f51345f11c0, record_reader=0x50b74a <scan_record_reader_adapter(Record*, void*)>) at /home/admin/source/stunning-engine/src/observer/storage/common/table.cpp:454 454 for ( ; RC::SUCCESS == rc && record_count < limit; rc = scanner.get_next_record(&record)) { (gdb)
-
结束函数调用
(gdb) finish Run till exit from #0 0x000000000050c2de in Table::scan_record (this=0x60f000007840, trx=0x606000009920, filter=0x7f51345f12a0, limit=2147483647, context=0x7f51345f11c0, record_reader=0x50b74a <scan_record_reader_adapter(Record*, void*)>) at /home/admin/source/stunning-engine/src/observer/storage/common/table.cpp:454
-
结束调试
(gdb) quit A debugging session is active. Inferior 1 [process 54699] will be detached. Quit anyway? (y or n) y Detaching from program: /home/admin/local/bin/observer, process 54699 [Inferior 1 (process 54699) detached]
MiniOB 镜像文件基于 CentOS:7 制作,镜像包含:
-
jsoncpp
-
google test
-
libevent
-
flex
-
bison(3.7)
-
gcc/g++ (version=11)
-
MiniOB 源码(/root/source/miniob)
在 Docker 中 /root/source/miniob
目录下载了 GitHub 的源码,可以根据个人需要,下载自己仓库的源代码,也可以直接使用 git pull 拉取最新代码。 /root/source/miniob/build.sh
提供了一个编译脚本,以 DEBUG 模式编译 MiniOB。
首先要确保本地已经安装了 Docker。
-
使用 Dockerfile 构建。
Dockerfile: https://github.com/oceanbase/miniob/blob/main/Dockerfile
# build docker build -t miniob . docker run -d --name='miniob' miniob:latest # 进入容器,开发调试 docker exec -it miniob bash
-
使用 docker hub 镜像运行。
docker run oceanbase/miniob