MySQL 是最为流行的开源关系型数据库之一,有关它的使用、优化和运维处理相关的文章汗牛充栋。我个人也写过《MySQL探秘》和《MySQL死锁》系列文章,详细介绍了诸如 MySQL 内存结构、持久化机制、锁和事务等多方面的知识。不过上述知识大多数都来自《高性能MysQL》、《MySQL技术内幕:InnoDB存储引擎》等书籍以及网上一些优秀博主的文章。
所以本人也希望更进一步,进入MySQL源码层面,从源码方面了解其具体实现,为自己累计数据库内核方面的开发经验。有关 MySQL 和 RocksDB 的源码阅读其实已经持续了半年左右,所以现在希望开一个新坑,从源码层面讲解一下 MySQL。
想要了解数据库内核开发,直接去阅读MySQL巨量的源码并不是一个最优的方法,读者们可以先从诸如 Pingcap Talent 和 CMU 15-445/645 课程入手。不过我也只是一个学习者,写系列文章更多是通过记录和输出来帮助学习,所以如有纰漏,还请各位读者指出。
阅读源码过程中,最好可以手动调试,重复了解代码的实现,所以编译和调试MySQL代码很重要,不过整个过程中还是遇到了一些坑,所以这里记录一下整个过程和遇到的坑。
操作系统环境
我把个人的台式机重装了 Ubuntu 20.04 ,内核版本是 5.13.0-44-generic,内存16G,磁盘240G,有关依赖的编译工具版本如下所示。
相关的安装命令是从 PolarDB-通过编译源码安装部署文档上来的,专门适配于 Ubuntu 20版本,Centos的版本可以具体去它文档中查看
代码语言:javascript复制 安装GCC7
apt install -y gcc-7 g -7
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60
--slave /usr/bin/g g /usr/bin/g -7
update-alternatives --config gcc
gcc --version
g --version
# 安装依赖
apt install make automake cmake git bison libaio-dev libncurses-dev libsasl2-dev libldap2-dev libssl-dev pkg-config
MySQL 源码下载
我们选择最新的 8.0.28版本,可以去 https://dev.mysql.com/downloads/mysql/ 直接下载带 Boost 第三方库依赖的源码。
Boost 是一个功能强大、构造精巧、跨平台、开源并且完全免费的 C 程序库,可以认为是半个C 标准库。MySQL 的代码依赖 Boost库,所以直接下载一个携带Boost库的源码比较省心,不需要再去下载对应的Boost库。
编译命令
我们首先需要使用 cmake 进行编译,可以直接使用命令行,也可以用 Clion 开发后,配置对应的cmake编译配置。
其中,有关 CMake Options 的部分参数如下所示:
代码语言:javascript复制-DWITH_BOOST=~/work/c /mysql-8.0.28/boost -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/home/homer/build -DMYSQL_DATADIR=/home/homer/build/data -DSYSCONFDIR=/home/homer/build -DMYSQL_UNIX_ADDR=/home/homer/build/data/mysql.sock -DMYSQL_MAINTAINER_MODE=false
其中比较重要的有:
- DWITH_BOOST: 指定 boost 路径,可以直接指向源码文件夹下的boost文件夹;
- DCMAKE_BUILD_TYPE: 表示是debug,方便后续代码调试;
- DCMAKE_INSTALL_PREFIX: 表示编译状态的路径,选择源码文件夹之外的一个自建的build文件夹
- DMYSQL_DATADIR:表示MySQL默认的数据目录,选择build文件夹下的data文件
然后执行命令进行编译,大概会花费数分钟的时间,并且可能会出现各类错误和问题。问题和错误会在本文后边进行记录。
Clion 调试
如果Clion的CMake执行成功后,就会出现对应的 Run / Debug Configurations 选项,里边会有名称为mysqld的选项,它就是 MySQL Server 启动的选项。可以先用该选项执行 MySQL 数据目录的初始化操作,生成对应的配置文件和用户名密码。然后再使用该选项来启动 MySQL Server。两个操作对应的参数不同。
第一步初始化数据目录时,也需要先创建对应的用户。
代码语言:javascript复制# 创建 MySQL 用户组和 MySQL 用户
groupadd mysql
useradd -r -g mysql -s /bin/false mysql
然后使用 clion 的 mysqld 执行选项,输入的 Program arguments 如下所示:
代码语言:javascript复制--basedir=/home/homer/build --datadir=/home/homer/build/data --lower_case_table_names=0 --initialize-insecure --user=mysql
其中 --initialize-insecure 表示非安全的初始化,可以设置无密码的用户。然后需要给对应的文件夹添加读写和执行权限。
代码语言:javascript复制chmod -R 777 /home/homer/build/data
初始化后,就可以继续使用 clion 的 mysqld 执行选项来启动 MySQL了。输入的 Program arguments 如下所示:
代码语言:javascript复制--basedir=/home/homer/build --datadir=/home/homer/build/data --lower_case_table_names=0 --user=mysql
然后我们可以在 /home/homer/build/bin 目录下执行 ./mysql -uroot -h127.0.0.1 -P3306 -p
来使用客户端连接 MySQL Server。登录时无需密码,直接回车。
然后就可以看到我们在clion中设置断点的代码逻辑被拦截,下面我们就可以进行调试和代码阅读了。
问题记录
在整个过程中,特别是编译阶段遇到了很多问题,这里也简单记录一下,相信不同的同学进行这个过程中都会遇到不同的问题,大家耐心解决。
一、default.cfg不存在
编译时会有如下报错:
代码语言:javascript复制CMake Error: File /home/homer/work/c /mysql-8.0.28/router/src/harness/tests/data/logger.d/default.cfg does not exist.
CMake Error at router/cmake/testing.cmake:211 (CONFIGURE_FILE):
可以在 cmake配置文件中找到如下片段,直接删除。
代码语言:javascript复制CONFIGURE_TEST_FILE_TEMPLATES(${CMAKE_CURRENT_SOURCE_DIR}/data
"tests-good-1.cfg.in;tests-good-2.cfg.in;tests-start-1.cfg.in")
SET(TEST_FILES
logger.cfg
magic-alt.cfg
tests-bad-1.cfg
tests-bad-2.cfg
tests-bad-3.cfg
)
二、编译警告作为错误处理
在编译过程中,发现编译器会把warning当做error处理,导致整个编译过程失败。具体报错如下所示。
代码语言:javascript复制cc1plus: all warnings being treated as errors
经过搜索最终在 https://dev.mysql.com/doc/mysql-sourcebuild-excerpt/8.0/en/compilation-problems.html 文档中找到了对应的解决版本,需要将DMYSQL_MAINTAINER_MODE设置为false,否则就会导致编译器将warning作为error处理。
嵌入可以理解为一种组合或者代理模式的自动语法糖。
三、编译cache
编译异常后,需要删除对应的 cmake cache 后再次进行编译,否则每次都会读取缓存进行相同的报错。
后记
我个人有关 MySQL 源码编译和调试的过程就如本文所示,后续就开始相关源码的阅读和学习了。