https://bugs.mysql.com/bug.php?id=32917 の 5a587b6d2897e786b515d05a09b37ef81695dab7
の和訳
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()
を呼び出すことでビットをクリアする。
この問題は一時テーブルを作成する間に以下のような時間窓で誤った条件が成立した場合に引き起こされ得ると報告されている。
- THD1: エラーにより
free_tmp_table
が呼び出され、一時テーブルのスロット番号をクリアする - THD2: ビットマップの中で利用されていないスロット番号を使うことで一時テーブルを作成する処理中
- THD1:
free_tmp_table
の呼び出しが完了した後、bitmap_lock_clear_bit()
を呼び出すことでTHD2が使っているスロット番号をクリアする - 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
の中の同じスロット番号を使った試行は失敗に終わってしまう。
- 誤った条件下でビットをクリアするために
bitmap_lock_clear_bit()
関数を呼ぶのは、free_tmp_table()
がテーブルとファイルを削除しビットをクリアするため不必要である。したがってcreate_tmp_table()
内の冗長なbitmap_lock_clear_bit()
呼び出しを削除した。これにより本件が報告された時間窓を防ぐ。 - 一時テーブルを開くのに失敗した場合、ファイルを削除する。これにより
temp-pool
のスロット番号が今後の一時テーブルで利用できるようになる。 - 既にファイルが存在することにより一時テーブルの作成試行に失敗した場合、
temp-pool
のスロットを利用中としてマークする。これにより問題が再発することを防ぐ。