Understanding MySQL Internalsを読む(3)
前回の記事
gdbデバッグするときのお薦めbreakpoint個所
操作対象 | お薦めbreakpoint個所 | 見ると幸せになれるかもしれない変数 |
SELECT文を実行 | mysql_select() | *thd, thd->query, *tables, *join |
INSERT文を実行 | mysql_insert() | *thd, thd->query, *table, fields, values_list |
UPDATE文を実行 | mysql_update() | *thd, thd->query, *table_list, fields, values, *conds |
DELETE文を実行 | mysql_delete() | *thd, thd->query, *table_list, *conds |
クエリキャッシュから結果を返せるか確認 | Query_cache::send_result_to_client() | *this, *thd, sql |
クライアントからのパケットの読み込み | my_net_read() | *net |
クライアントへのパケットの書き込み | my_net_write() | *net, packet, len |
接続を認証 | check_connection() | *thd, thd->net |
マスタ側で更新処理をログ出力 | MYSQL_LOG::write(Log_event *) | *event_info, *event_info->thd, event_info->thd->query |
スレーブの開始 | start_slave_threads() | *mi |
スレーブのIOスレッドの実行 | handle_slave_io() | *mi |
スレーブのSQLスレッドの実行 | handle_slave_sql() | *rli |
テーブルを開く | open_table() | *thd, thd->query, db, table_name, alias |
frmファイルを読む | openfrm() | name, alias |
MyISAMテーブルを開く | ha_myisam::open() | *this, name |
InnoDBテーブルを開く | ha_innobase::open() | *this, name |
テーブルロックを要求する | mysql_lock_tables() | *thd, thd->query, **tables |
トランザクションをcommitする | ha_commit_trans() | *thd, *trans |
新しいソースファイルを追加したい場合(hacking)
新しくC/C++ファイルを追加したい場合は以下の手順に従うこと。
- ファイルを追加したディレクトリのMakefile.amをテキストエディタで開く。
- "SOURCES"というsuffixの変数を見つける。例えばsqlディレクトリなら"mysqld_SOURCES"、myisamディレクトリなら"libmyisam_a_SOURCES"となっている。
- SOURCES変数に追加したファイルの名前を追記する。
- "INCLUDES"という変数および"noinst_HEADERS"という変数を見つける。"make install"でincludeディレクトリに含めて欲しいヘッダファイルはINCLUDESに、そうでないヘッダファイルはnoinst_HEADERSに追記する。
これでおしまい。
安定性向上のためのCoding Tips
- スレッドセーフなプログラミングを行うこと。
- 多くのグローバル変数は変更時に使用すべきmutexが用意されているのでこれを使う。
- 利用可能なスタックサイズは非常に小さいことを意識する。100bytes以上のメモリを割り当てる場合はsql_alloc関数またはmy_malloc関数を使うこと。
- より少量のメモリ割当てでは、可能ならmy_malloc関数ではなくsql_alloc関数を使う。sql_alloc関数は事前にメモリを割り当てているメモリプールからメモリを割り当てるが、my_malloc関数はmalloc関数のwrapperであるため。sql_alloc関数はdo_command関数以後のスタックで呼出可能。sql_alloc関数で割り当てたメモリはクエリの実行が完了するまでの間のみ有効。それ以上の期間でのメモリの割り当てを行いたい場合はmy_malloc関数を使う。
- 大量のメモリを割り当てる場合はmy_malloc関数を使用し、なるべく短い時間でmy_free関数でメモリを解放する。
- sql_alloc関数で割り当てたポインタは解放してはいけない。メモリプールはクエリ実行の最後にfree_root関数により解放される。
- my_malloc関数で割り当てたポインタは、my_free関数で解放する。
- C++の例外は使用してはいけない。どんな場合でも、ビルド時に例外機構を無効化してビルドしている。
- C++のSTL、iostream等、libstdc++へのリンクを必要とするC++による拡張機能を利用してはいけない。
- 依存ライブラリを増やしてはいけない。
- 既存のMySQLのコードを可能な限り再利用する。
ポータビリティ向上のためのCoding Tips
- libcの関数を直接呼んではいけない。代わりにmysysディレクトリとstringsディレクトリに実装されているポータビリティ向上のためのWrapper関数を使用する。通常、そうしたWrapper関数はlibcの関数名にprefixとして"my_"が付けられている。
- プラットフォームによってbyte orderが異なることを意識し、int4storeやint4korrなどのマクロを使用することでbyte orderの違いを吸収する。
- メモリのアラインメントを意識する。ポインタに直接数字を代入してはいけない。
- 悪い例
*((char*)p+1) = n;
-
- 良い例
memcpy((char*)p+1, &n, 4);
-
- 移植性が高い最も良い例
int4store((char*)p+1, n);
パフォーマンス向上のためのCoding Tips
- パフォーマンスを自然と意識したコーディングを心がける習慣を身につける。CPUがどのように動作するのかを学び、自分が書いたC/C++のコードがアセンブラレベルでどのように実行されるのかを視覚化できるようにすること。
- 既存のMySQLのコードを可能な限り再利用する。
- 自分が書いたコードが呼び出す関数の先でどんな処理が行われるのかを意識すること。
- 不要なシステムコールの呼出は行わない。複数の呼出はひとつにまとめることができないかどうかを考える。例えば、my_read関数とmy_write関数の呼出の代わりにIO_CACHE関数を使用するなど。
- 不要なオブジェクトのインスタンス化は行わない。
- inline関数では大きな関数を書いてはいけない。
コーディングスタイルについてのTips
- internals.htmlで説明されているコーディングガイドラインに従うこと。
- コードを記述する際に、自分が書いたコード以外の部分をエディタが自動整形しないようにすること。
- 関数は処理が成功した場合は0を返し、失敗した場合は0以外の値を返すようにすること。
- 複数の関数を連続して呼び出し、エラーのチェックを行う場合は以下のようなスタイルで書くと良い。
if (a() || b() || c()) goto err;