Debugging MySQL/MariaDB (1): Build and Test
MySQL/MariaDB をデバッグする実践的方法を解説する。この記事ではデバッグを行うための準備を行い、具体的なデバッグの方法については (2) 以降の記事で説明する予定である。なお、一連の記事すべてにおいて MySQL 8.0.24 および MariaDB 10.5.9 を前提として解説する。
Building MySQL/MariaDB
MySQL/MariaDB のそれぞれについて、ビルドする方法を簡単にまとめておく。以下の記述は筆者の開発環境 (Vagrant Box bento/ubuntu-20.04) を前提としたものである。
MySQL
Boost 同梱版のソースを公式からダウンロードし展開する。GitHub から取得すると Boost のバージョンを合わせるのがかなり面倒なので、Boost 同梱版を使うのが吉である。
wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-8.0.24.tar.gz tar xfv mysql-boost-8.0.24.tar.gz
次に必要なパッケージをインストールし、デバッグビルドする。
apt-get install g++ cmake pkg-config # ビルドに必要 apt-get install libjson-perl zip unzip # テストに必要
mkdir -p mysql-8.0.24/bld && cd $_ cmake -DWITH_BOOST=../boost .. -DCMAKE_BUILD_TYPE=Debug cmake --build . --config Debug -j 4
MariaDB
Building MariaDB on Ubuntu に従って依存パッケージをインストールする。
apt-get install software-properties-common devscripts equivs
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8 add-apt-repository --update --yes --enable-source \ 'deb [arch=amd64] http://nyc2.mirrors.digitalocean.com/mariadb/repo/10.5/ubuntu '$(lsb_release -sc)' main'
apt-get build-dep mariadb-10.5
git clone -b mariadb-10.5.9 --depth=1 git@github.com:MariaDB/server.git mariadb-server
mkdir mariadb-server/bld && cd $_ cmake -DCMAKE_BUILD_TYPE=Debug .. cmake --build . --config Debug -j 4
デバッグビルドしようとすると、コンパイル時に1つでも警告が出るとコンパイルエラーになる (-Werror
)。HEAD で開発する場合はこの動作で問題ないが、例えば git-bisect のために古いバージョンをビルドする場合に邪魔になることがある。-DMYSQL_MAINTAINER_MODE=OFF
することで警告を警告のままにできる。
cmake -DCMAKE_BUILD_TYPE=Debug -DMYSQL_MAINTAINER_MODE=OFF ..
Testing MySQL/MariaDB
同じ SQL を何度も手で投入するのは苦痛であり効率も悪いので、デバッグを始める前にテストケースを作成しよう。MySQL Test Framework、特に mysql-test-run.pl を使えば、SQL を書く感覚で E2E テストを書くことができる。なお、筆者が知る限りにおいて、MySQL におけるテストは E2E テストが主体であり、ユニットテストを書くことはあまりないようだ。
Running Test Cases
まずは MySQL のテストについて簡単に説明しよう。以下、MySQL を例に取って説明するが、MariaDB の場合もほとんど同様である。
各々のテストケースは、suite という単位でまとめられている。mysql-test/suite/
のディレクトリ1つ1つが suite に一対一対応し、その中に個々のテストケースが配置されている。
> ls -A mysql-test/suite audit_null innodb_fts network_namespace auth_sec innodb_gis opt_trace binlog innodb_stress parts binlog_gtid innodb_undo perfschema binlog_nogtid innodb_zip query_rewrite_plugins clone interactive_utilities rpl collations jp rpl_gtid component_keyring_file json rpl_ndb connection_control json_ndb rpl_nogtid encryption large_tests secondary_engine engines lock_order service_status_var_registration federated max_parts service_sys_var_registration funcs_1 memcached service_udf_registration funcs_2 ndb special gcol ndb_big stress gcol_ndb ndb_binlog sys_vars gis ndb_ddl sysschema group_replication ndb_opt test_service_sql_api information_schema ndb_rpl test_services innodb ndbcluster x
※ MariaDB の場合もほぼ同様だが、main suite のみ mysql-test/
の直下に配置されている。main suite は特別扱いされているようで、他の suite とはやや扱いが異なるので注意すること。
MySQL Test Framework のテストは、様々な単位での実行が可能である。以下に例を示す。
cd bld/mysql-test/ ./mysql-test-run.pl # すべてのテストを実⾏ ./mysql-test-run.pl --suite innodb # innodb suite のテストをすべて実⾏ ./mysql-test-run.pl innodb.create_table # innodb suite の create_table を実⾏
複数のテストを同時に実行する場合は、--parallel
と --force
という2つのオプションを与えるのがオススメだ。--parallel
は読んで字の如く並列数を指定するもので、--force
はいくつかのテストケースが失敗しても最後までテストを実行するよう指示するものである。
./mysql-test-run.pl --parallel=8 --force
Writing Test Cases
新規にテストケースを作る方法を説明する。なお、同様にして既存のテストケースにテストを追加することもできるが、デバッグのしやすさを考えると新規に作成する方がよいだろう。
まず、適切な suite を選び、テストファイルと結果ファイルを作成する。例示のためなのでどこでもよいのだが、仮に innodb suite を使うこととしよう。
touch mysql-test/suite/innodb/t/example.test touch mysql-test/suite/innodb/r/example.result
テストファイルにはSQL と テストコマンド が書ける。結果ファイルにはテストファイルに書いた SQL とその望ましい返り値を書けばよい。以下に簡単な例を挙げる。
# mysql-test/suite/innodb/t/example.test CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1); SELECT * FROM t1; DROP TABLE t1; --error ER_BAD_TABLE_ERROR DROP TABLE t;
# mysql-test/suite/innodb/r/example.result CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1); SELECT * FROM t1; a 1 DROP TABLE t1; DROP TABLE t; ERROR 42S02: Unknown table 'test.t'
結果ファイルを手で書くのが面倒な場合は、結果ファイルは空のままテストを実行する。すると実⾏結果が結果ファイルと同じディレクトリに example.reject
という名前で生成されるので、それをベースにして結果ファイルを作ることができる。
テスト開始時にサーバーにオプションを渡したい場合や、特定の my.cnf を使わせたい場合は、*.opt および *.cnf ファイルを用いる。どのテストにどの設定ファイルが適用されるかの判定ルールはやや複雑なので、その説明はドキュメント に譲ることとする。
Running Server without Installation
mysql-test-run.pl の使い道はテストの実行だけではない。--start
オプションを与えることで、make install
せずとも、ビルド済みバイナリから MySQL/MariaDB サーバーを起動できる。これは、テストケースを作るために試行錯誤する段階で役に立つ。
例えば以下のようにすると、innodb suite の create_table.test の起動設定 (*.opt, *.cnf) で、サーバーを起動することができる。
./mysql-test-run.pl innodb.create_table --start
ソケットのパスが表示されるので、それを使って起動したサーバーに接続する。
mysql -u root -S ${SOCKET}