Understanding MySQL Internalsを読む

『Understanding MySQL Internals』なるMySQLソースコード解説本が発売されました! たぶん現存する書籍(洋書含む)の中ではもっともコード寄りの本だろうと思います。著者曰く『Understanding the Linux Kernel』とか『Linux Device Drivers』のMySQL版となることをコンセプトに執筆した、とのことです。

Understanding MySQL Internals: Discovering and Improving a Great Database

Understanding MySQL Internals: Discovering and Improving a Great Database

日本でも(この洋書が)発売されたという話を耳にして以来、キニナルキニナルと思っていたところなんと、id:tasukuchanさんが「mirさんどぞー」と貸してくれました!!ありがとうございます!

MySQLソースコードは、これまで既にソコソコ読んで来ましたし、改造したりもしてきましたが、こういう教科書的なものを題材に体系的に勉強したことはなかったです。読みはじめた頃、MySQL Internals Manual(http://forge.mysql.com/wiki/MySQL_Internals)を良く読んでいた気がしますが、これには主要クラスのメンバ解説とかまでは無かった気がします。

主要モジュール一覧

まずは概要から。

  • Server Initialization Module(サーバ初期化)
  • Connection Manager(接続管理)
  • Thread Manager(スレッド管理)
  • Connection Thread(接続スレッド)
  • User Authentication Module(ユーザ認証)
  • Access Control Module(アクセス制御)
  • Parser(SQL解析)
  • Command Dispatcher(コマンドの割り振り)
  • Query Cache Module(クエリキャッシュ)
  • Optimizer(最適化)
  • Table Manager(テーブル管理)
  • Table Modification Module(テーブル更新)
  • Table Maintenance Module(テーブル保守)
  • Status Reporting Module(ステータス報告)
  • Abstracted Storage Engine Interface、Table Handler(ストレージエンジン抽象インタフェース、テーブルハンドラ)
  • Storage Engine Implementations(ストレージエンジン実装)
  • Logging Module(ログ出力モジュール)
  • Replication Master Module(レプリケーションマスタモジュール)
  • Replication Slave Module(レプリケーションスレーブモジュール)
  • Client/Server Protocol API(クライアント/サーバプロトコルAPI)
  • Low-Level Network I/O API(低レベルネットワークI/O API)
  • Core API(コアAPI)

という感じ。ふむふむ。これくらいの粒度で分けてソース解析したらいいかも確かに。

Server Initialization Module

mysqld起動時にサーバの初期化を行う。

  • sql/mysqld.cc: main()
  • sql/mysqld.cc: init_common_variables()
  • sql/mysqld.cc: init_thread_environtment()
  • sql/mysqld.cc: init_server_components()
  • sql/mysqld.cc: get_options()
  • sql/sql_acl.cc: grant_init()
  • sql/slave.cc: init_slave()

MySQL 5.1ではinit_server_components()の中でplugin(ストレージエンジン)の初期化が行われている。

Connection Manager

クライアントからの接続要求を待ち受けて、"Thread Manager"へ渡す。

  • sql/mysqld.cc: handle_connections_sockets()

Thread Manager

各接続要求に対して確実に、新しいスレッドを生成して割当、あるいはスレッドキャッシュから割当を行う。

  • sql/mysqld.cc: create_new_thread()
  • sql/mysqld.cc: start_cached_thread()

start_cached_thread()関数はMySQL 5.0以上ではcreate_new_thread()に統合されていて存在しない。

重要なクラスのひとつ。多くの関数の第一引数にこのクラスへのポインタが使用されている。

  • sql/sql_class.h: class THD()

MySQL 4.1から5.0にかけてリファクタリングが行われ、THDクラスは以下のクラスを継承する形となっている。

  • sql/sql_class.h: class Query_arena()
  • sql/sql_class.h: class Statement()
  • sql/sql_class.h: class Open_tables_state()

Connection Thread

各接続に応対する。

  • sql/sql_parse.cc: handle_one_connection()

User Authentication Module

接続ユーザの認証、当該ユーザの権限に関する構造体の初期化などを行う。sql_acl.ccに実装された関数が多い。

MySQL 4.1で改変されて以来あまりコードの変更は行われていないものの、MySQL 5.1で導入されたplugin機構を使ったPAM (Pluggable Authentication Modules)を実装するために今後またコードの変更が行われるかも、という話。

Access Control Module

要求された処理を行うのに必要な権限があるかどうかをチェックする。sql_acl.ccに実装された関数が多い。

MySQL 3.22以来ほとんどコードの変更はないけれども、roleをサポートする時に大幅に変更されるかも、との話。

Parser

クエリ文字列を解析して、パース木を作成する。

sql/sql_yacc.ccはsql/sql_yacc.yyを入力ファイルとしてGNU Bisonにより自動生成されたファイル。MySQLの(人間が読んで意味の分かる)SQL構文はsql_yacc.yyに定義されている。

MySQLはlexを使うのでは無く、独自の語彙走査コード(lexical scanner)を使用している。以下のファイル群に実装されている。

さらなる高速化のために、yacc/bisonを使う代わりに独自の実装を行おうという議論があるけれども、今のところ着手はされていないという話。

Command Dispatcher

クライアントから送られた処理要求を、それぞれ担当するモジュールへ振り分ける。

  • sql/sql_parse.cc: do_command()
  • sql/sql_parse.cc: dispatch_command()

Query Cache Module

SELECT結果をキャッシュしておき、同じSELECTが新たに来た場合、検索を行うのではなくキャッシュから返す。

  • sql/sql_cache.cc: Query_cache::store_query()
  • sql/sql_cache.cc: Query_cache::send_result_to_client()

Optimizer

クエリを実行するための最良な戦略を作成し、結果をクライアントへ返す。最も複雑な実装のモジュール。

  • sql/sql_select.cc: mysql_select()
  • sql/sql_select.cc: JOIN::prepare()
  • sql/sql_select.cc: JOIN::optimize()
  • sql/sql_select.cc: JOIN::exec()
  • sql/sql_select.cc: make_join_statistics()
  • sql/sql_select.cc: find_best_combination()
  • sql/sql_select.cc: optimize_cond()

Optimizer本体とは切り離された形で、range optimizerというOpitimizerも実装されている。これは「キーが一定の範囲にある場合」というような条件での検索を行うような場合に使用されるOptimizerで、以下のファイル/関数に実装されている。

  • sql/opt_range.cc: SQL_SELECT::test_quick_select()

ソースコードコード中にquick_selectとか出てくるのはこいつ。

Table Manager

テーブル定義ファイル(拡張子.frmファイル)の生成/読み込み/変更、テーブルキャッシュの保守、テーブルロックの管理を行う。sql/sql_base.cc、sql/table.cc、sql/unireg.cc、sql/lock.ccなどに実装されている。

Tritonnでfrm対応を行う場合にはこれらを改造すればいいっすね。

Table Modification Modules

テーブルの作成、名前変更、テーブルの削除、テーブルへのデータの追加/更新/削除を行うモジュールの集合。

Table Maintenance Module

テーブルのcheck、repair、back up、restore、optimize、analyzeを行う。

このmysql_admin_table()関数はさらにストレージエンジンの関数呼出を行う。

以下はmysql_admin_table()関数に対するwrapper関数。