MySQL - VirtualBoxのホスト共有フォルダをdatadirにしたらはまった
ことの発端
これはWindows上のVirtualBoxのお話。
datadirがVirtualBoxのホスト共有フォルダに「なってしまっていた」。 必要なファイルをまとめてホストにおいてまるっとDockerで適当にマウントしたのが諸悪の根源だったりする。
気になるので非Docker環境で試してみた。
2020-01-17T13:59:10.540801Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 b ecause file system for /vagrant/mysql/ is case insensitive 2020-01-17T13:59:11.246091Z 0 [ERROR] [MY-012592] [InnoDB] Operating system error number 95 in a file operation. 2020-01-17T13:59:11.246215Z 0 [ERROR] [MY-012596] [InnoDB] Error number 95 means 'Operation not supported' 2020-01-17T13:59:11.246374Z 0 [ERROR] [MY-012646] [InnoDB] File ./undo_001: 'Linux aio' returne d OS error 195. Cannot continue operation 2020-01-17T13:59:11.246445Z 0 [ERROR] [MY-012981] [InnoDB] Cannot continue operation.
^q^
(ログのタイムスタンプはUTCだから仕事サボってたわけじゃないよ)
対策
innodb_use_native_aio=0
で回避可能。
細かい話は続きから。
細かい話
今回試した環境は Win10 64bit / VirtualBox 6.0.14 / CnetOS 8 / MySQL 8.0.19 です。
Operating system error number 95
似てる事象の記事はだいたい22っぽい*1*2。MySQLリファレンスマニュアルのエラーコード一覧*3を見ると22は「無効な引数」ですが,95はここには載っていないのでLinuxのヘッダを見ます。95はEOPNOTSUPPで,確かに「Operation not supported」ですね。
追記:そもそもこれらの記事はWindows環境だったので,下記のようにファイルシステムの差によるもののようです。
EOPNOTSUPPでLinuxカーネルのソースをgrepすると,システムコールの関数ではなくファイルシステムの実装側で返す値のようです。ここらへんみると,本当にサポートされていないオペレーションのときに返ってくるらしい(ちなみに記事執筆時点ではext4に大きめの変更が入ってる最中らしいのでmasterブランチだと300行くらいずれます)。
ということで,共有フォルダはVirtualBoxのvboxsfなのでコードを落としてきてみてみます regops.c。
/* * Now now we reject async I/O requests. */ if (!is_sync_kiocb(kio)) { SFLOGFLOW(("vbsf_reg_read_iter: async I/O not yet supported\n")); /** @todo extend FsPerf with AIO tests. */ return -EOPNOTSUPP; }
とのこと。native aioは使えないらしい。
InnoDB
せっかくなのでInnoDBのコードもチラ見してnative aioが無効になるのか確認します。 ログのメッセージは「Linux aio」なので一応aio_readとかでgrepしてみましたが使われておらず,native aioのようです。
storage/innobase/os/os0file.ccをみると,Linux向け,Win向けのaioのコードがたくさん書いてあります。実行環境がnative aioに対応しているかをチェックする処理もありますが,今回は環境は対応していてdatadirのファイルシステムだけ対応していないという状況だったのでスルーされていたみたいです。
handlerを見ると,srv_use_native_aio
がフラグらしい。
もう一度os0file.ccを見てみます。
dberr_t os_aio_handler(ulint segment, fil_node_t **m1, void **m2, IORequest *request) { dberr_t err; if (srv_use_native_aio) { srv_set_io_thread_op_info(segment, "native aio handle"); // 略 } else { srv_set_io_thread_op_info(segment, "simulated aio handle"); // 略 } return (err); }
おっ!それっぽいですね!これで安心して使えそうです*4。
本当は細かいI/Oの仕組みまで追いかけたいですが,それはまた別のお話。
まとめ
ちゃらっと調べるつもりがLinuxとVirtualBoxのソースとにらめっこする羽目になりました*5。夜ふかしには注意しましょう。
*1:Docker 18.03でMySQL5.7コンテナ起動時に[File ./ib_logfile101: 'aio write' returned OS error 122.]メッセージが表示されたときの対処法
*2:Issues with Docker db images on Windows 10 Home · Issue #55 · farmOS/farmOS · GitHub
*3:MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.19.6 オペレーティングシステムのエラーコード
*4:ログにも出ていますが大文字小文字が区別されないファイルシステムなのでlower_case_table_names=2に気をつけてください
*5:ちゃんと調べればドキュメントに書いてありそう。