| tags: [ MySQL MariaDB ] categories: [ Development ]
魔改了下 MariaDB 支持 JSON binary
Oracle MySQL 的 JSON 数据类型在存储时用的紧凑的二进制格式,MariaDB 则傲娇的直接存原始的 JSON 文本串,从 MariaDB 10.2 开始兼容 MySQL 5.7,如今 MariaDB 10.4 稳定版都发布了,依然还是不支持 Oracle MySQL 的 JSON 类型:
- 使用 row based replication 时,不支持从 MySQL 5.7 复制包含 JSON 列的 binlog
- 不支持就地读取包含 MySQL JSON 列的数据文件
MariaDB 从 10.2 开始大爆发:
-
10.2:
- Window function
- Recursive Common Table Expressions
- WITH statement
- CHECK CONSTRAINT
- DML-only flashback
-
10.3:
- System-versioned tables (也被称为 Temporal table)
- Sequence
-
10.4:
- System-versioned table 支持 application-time period
- Galera 4
- 静态链接 WolfSSL (废了 OpenSSL 真好😄)
-
10.5 (还未正式发布):
- S3 storage engine
相比之下 MySQL 8.0 的步子真是太慢了,但是两家对于 JSON 数据类型的实现,恐怕是不指望双方主动做兼容层了。
由于非常馋 MariaDB 的 system-versioned table 功能以支持审计、调试、数据回滚、时序分析,因此魔改了下 MariaDB 10.4 分支,让其可以解析 MySQL 5.7 binlog 里的 MYSQL_TYPE_JSON 类型,这步依葫芦画瓢还是比较容易的,就是第一次看 MariaDB 代码,晕了好一阵子,还好有 GDB、LLDB 调试器在手,以及在 Wine 里跑 Source Insight 4(感谢这么好的源码阅读软件!),跌跌绊绊看明白了。
这一步搞定后,忽然想为啥不支持下就地读取包含 JSON 列的 MySQL 数据文件呢? 操起调试器大法,试验了几个小时,发现搞定了,还挺简单。。。然后又贪心不足,能不能支持就地写包含 JSON 列的 MySQL 数据文件了?花了十分钟 hack 了下,居然也可以了😂
MariaDB 代码里不少地方有一些疑问的注释,看的出来后来的代码维护者已经不知道为啥前人那么写了😓,但总的来说,MariaDB 代码做了些抽象和重构,比 MySQL 的源代码还是要规整些。
在 macOS 下很容易编译 MariaDB 的代码:
mkdir builddir &&
cd builddir &&
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_SSL=bundled -DWITH_PCRE=bundled \
-DWITH_UNIT_TESTS=OFF -DDEFAULT_CHARSET=utf8mb4 -DDEFAULT_COLLATION=utf8mb4_general_ci \
-DPLUGIN_TOKUDB=NO .. &&
make &&
make install DESTDIR=$HOME/tmp/mariadb
然后运行 MariaDB:
cd $HOME/tmp/mariadb/usr/local/mysql
bin/mysqld_safe --datadir=./data
macOS 下 clang 有个奇怪的行为,如果一次性的编译出可执行文件,那么 clang 会自动生产 xxx.dSYM 调试符号,而如果是先编译出 .o 再链接成可执行文件,则需要手动的搞一下:
dsymutil $HOME/tmp/mariadb/usr/local/mysql/bin/mysqld
然后就可以 lldb 调试了:
cd sources/mariadb-server
lldb -p PID
(lldb) breakpoint set -n FUNCTION
(lldb) continue
MySQL 8.0 加入了 JSON 的 partial update,默认没有开启,如果开启后,可能 binlog 格式有点变化,目前这个魔改的 MariaDB 版本没考虑这种情况,所以,MySQL 5.7 大法好!MariaDB 大法好!—— 哦,Percona 是谁啊?😄