MySQLのシグナル処理解説

概要

main関数→init_signals関数にて設定されます。いろんなシグナルをトラップしています。

プラットフォームによっていくつか異なるinit_signals関数実装がありますが、ここではWindowsLinuxについて説明します。

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`