MySQLのシグナル処理解説
概要
main関数→init_signals関数にて設定されます。いろんなシグナルをトラップしています。
プラットフォームによっていくつか異なるinit_signals関数実装がありますが、ここではWindowsとLinuxについて説明します。
Windows版でのシグナル処理
sql/mysqld.cc (init_signals関数全文)
#if defined(__WIN__) || defined(OS2) static void init_signals(void) { int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ; for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++) signal(signals[i], kill_server) ; #if defined(__WIN__) signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT #else signal(SIGBREAK, kill_server); #endif }
以下のシグナル受信時に、kill_server関数が呼ばれます。
- SIGINT (ctrl+c)
- SIGILL (無効命令)
- SIGFPE (浮動小数点数例外)
- SIGSEGV (セグメンテーション違反)
- SIGTERM (終了要求)
- SIGABORT (異常終了)
kill_server関数では以下の処理を行います。
- SIGTERMであれば正常終了開始のログ、それ以外はシグナル受信によるエラー終了開始のログ
- クライアントからの接続を全て切断(shutdown関数、closesocket関数を呼び強制切断)
- 全てのクライアントスレッドにKILLマークを付ける(動作中のスレッドはこれで停止する)
- slaveスレッドを停止
- 待機中のクライアントスレッドを全て終了させる
- SIGTERM以外ではAbortingのログ出力
- リソースの解放(ログファイルを閉じる、メモリを解放するなど)
SIGSEGVの時にもちゃんとレプリケーションとかログとかの後始末を試みるんですね。
Linux版でのシグナル処理
Linuxでは以下のシグナル受信時に、handle_segfault関数が呼ばれます。
- SIGSEGV
- SIGABORT
- SIGBUS
- SIGILL
- SIGFPE
handle_segfault関数では以下の処理を行います。
- エラーログにメッセージを出力
- エラーログにいくつかのサーバ変数(key_buffer_sizeなど)情報を出力
- エラーログにstacktraceを出力
- 直前まで実行していたSQL文をエラーログに出力
- その他ライブラリ関連の情報をエラーログに出力
- coreファイル出力設定が行われていればcoreファイルを出力
Linuxではこのパタンだととにかくエラーログに情報を出して終わりという感じですね。
上記以外のシグナルについては、起動時に作成されるシグナル処理用のスレッドにて処理されます。
シグナル処理用のスレッドはsigwait関数を呼び出し、シグナルの受信まで待機します。受信したシグナルが以下である場合には、ログに情報を出力し、kill_server関数が呼ばれます。
- SIGTERM
- SIGQUIT
- SIGKILL
kill_server関数の振る舞いはWindowsと共通です。
受信したシグナルが以下である場合には、ステータス情報を標準出力し、様々なキャッシュのクリアやログのフラッシュを行います。
- SIGHUP
クリア/フラッシュされるもの
- ログファイルの再オープン
- テーブルキャッシュ
- 権限テーブル
- スレッドキャッシュ
- ホストキャッシュ
このSIGHUP受信時の動作ですが、なかなか面白いです。MySQLサーバを起動し、以下のコマンドを実行してみてください。
kill -SIGHUP `pgrep -x mysqld`