Skip to content

Instantly share code, notes, and snippets.

@limitusus
Last active October 25, 2017 03:09
Show Gist options
  • Save limitusus/2e0b5a77d564789556dd908d560575e4 to your computer and use it in GitHub Desktop.
Save limitusus/2e0b5a77d564789556dd908d560575e4 to your computer and use it in GitHub Desktop.
MySQL Bug:32917

https://bugs.mysql.com/bug.php?id=329175a587b6d2897e786b515d05a09b37ef81695dab7 の和訳

分析

temp-pool が有効になっている場合、本質的に一時テーブルを使うある種のクエリは一時テーブル用ファイル名の衝突によりクラッシュする可能性がある。

temp-pool はLinuxにカーネルにおいて発生する問題を回避するため、一時テーブルのための異なるファイル名を減らすため、<tmp_file_prefix>_<pid>_<temp_pool_slot_num> の3部分から成るファイル名を使った小さなプールから確保しようとする。ファイル名として使ったとき、temp_pool_slot_num に一致するビットが temp-pool のために管理されたビットマップにセットされる。再利用のため一時テーブルが削除された後にこれはクリアされる。

誤った条件下で create_tmp_table() 関数呼び出しが行われると、 free_tmp_table()bitmap_lock_clear_bit() を呼び出してしまい、同じビットを2回クリアしてしまう。free_tmp_table() はテーブルとファイルを削除し、同じ関数である bitmap_lock_clear_bit() を呼び出すことでビットをクリアする。

この問題は一時テーブルを作成する間に以下のような時間窓で誤った条件が成立した場合に引き起こされ得ると報告されている。

  1. THD1: エラーにより free_tmp_table が呼び出され、一時テーブルのスロット番号をクリアする
  2. THD2: ビットマップの中で利用されていないスロット番号を使うことで一時テーブルを作成する処理中
  3. THD1: free_tmp_table の呼び出しが完了した後、 bitmap_lock_clear_bit() を呼び出すことでTHD2が使っているスロット番号をクリアする
  4. THD3: THD1により解放されてしまっているため、THD2が使っているスロット番号を使う。このスロット番号を使って一時テーブルを作成しようとした際、これは現在THD2により利用されているためエラーが発生する。 [The error: Error 'Can't create/write to file '/tmp/#sql_277e_0.MYD' (Errcode: 17)']

5.6とtrunkで起こり得るもう1つの問題: 開いている一時テーブルが作成後に(ulimitやOOM errorにより)失敗した場合、このファイルは削除されない。その後の temp-pool の中の同じスロット番号を使った試行は失敗に終わってしまう。

修正

  1. 誤った条件下でビットをクリアするために bitmap_lock_clear_bit() 関数を呼ぶのは、free_tmp_table() がテーブルとファイルを削除しビットをクリアするため不必要である。したがってcreate_tmp_table()内の冗長な bitmap_lock_clear_bit() 呼び出しを削除した。これにより本件が報告された時間窓を防ぐ。
  2. 一時テーブルを開くのに失敗した場合、ファイルを削除する。これにより temp-poolのスロット番号が今後の一時テーブルで利用できるようになる。
  3. 既にファイルが存在することにより一時テーブルの作成試行に失敗した場合、temp-poolのスロットを利用中としてマークする。これにより問題が再発することを防ぐ。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment