現象
しばらくXAMPPを起動しなかったら、MySQLが起動しなくなった。
(rails/sqlite3とか、djangoとかごちゃごちゃ別の環境を使ったりしていたので、へそを曲げたのか・・・理由がわかれば苦労しないんだけど、ポートがぶつかったりもしていたのかな?)
XAMPPのManage Serverで、MySQL Databaseを選んで"Start"を押しても、数十秒悩んだ後Stoppedになってしまって、Runningにならない。
うっかりポートが被っているDBを走らせていて、そこにXAMPPを起動した後などは、全部を「停止」してもXAMPPのMySQLが起動してくれない場合もあったけれど、Macを再起動すればだいたい機嫌を直してくれていた。(ここで、再起動が必要な場合と、再起動しなくても動く場合の違いが、実はよくわかっていない。)
いずれにせよ、前回と違ったやり方で対応してみたのでメモ。(二通りのやり方をメモっておきます。)
環境
Mac OS X El Capitan (10.11.5)
XAMPP 5.6.11-0
(mysql Ver 14.14 Distrib 5.6.25, for osx)
(WindowsのXAMPPでも、基本的に同じアプローチになると思う。)
エラーログ
XAMPPの[Configure]ボタンから、[Open Log]をクリックして表示。
または、
/Application/XAMPP/xamppfiles/var/(マシン名).local.err
2016-07-XX XX:XX:XX 7fff7519c000 InnoDB: Operating system error number 2 in a file operation.
InnoDB: The error means the system cannot find the path specified.
InnoDB: If you are installing InnoDB, remember that you must create
InnoDB: directories yourself, InnoDB does not create them.
InnoDB: Error: could not open single-table tablespace file ./foobardb/zot.ibd
InnoDB: We do not continue the crash recovery, because the table may become
InnoDB: corrupt if we cannot apply the log records in the InnoDB log to it.
InnoDB: To fix the problem and start mysqld:
InnoDB: 1) If there is a permission problem in the file and mysqld cannot
InnoDB: open the file, you should modify the permissions.
InnoDB: 2) If the table is not needed, or you can restore it from a backup,
InnoDB: then you can remove the .ibd file, and InnoDB will do a normal
InnoDB: crash recovery and ignore that table.
InnoDB: 3) If the file system or the disk is broken, and you cannot remove
InnoDB: the .ibd file, you can set innodb_force_recovery > 0 in my.cnf
InnoDB: and force InnoDB to continue crash recovery here.
解決策その1
実は、今回が最初じゃない。前回はエラーログにある(3)のやり方:
you can set innodb_force_recovery > 0 in my.cnf
and force InnoDB to continue crash recovery here
の部分を試して、だいたいうまくいっていた。
/Application/XAMPP/etc/my.cnf
に、
...
# Comment the following if you are using InnoDB tables
#skip-innodb
innodb_data_home_dir=/Applications/XAMPP/xamppfiles/var/mysql/
innodb_data_file_path=ibdata1:10M:autoextend
innodb_log_group_home_dir=/Applications/XAMPP/xamppfiles/var/mysql/
innodb_force_recovery=1
...
という感じで、1行追記して、無事解決。
解決策その2
妙に、拡張子がibdのファイルが気になったので、検索してみたら、以下の記述を見つけた。(他のバージョンの記述は、なぜか出てこない。)
MySQL.com(https://dev.mysql.com/doc/mysql-enterprise-backup/3.11/ja/partial.restoring.single.html "MySQL Enterprise Backup ユーザーズガイド (バージョン 3.11) / ... / 単一の .ibd ファイルのバックアップとリストア")
ibdファイルをとりあえずrenameしてみたらどうだろうか、と思って試してみる。
データファイルのパスは、上記のmy.cnfにある通り
/Applications/XAMPP/xamppfiles/var/mysql
この下にある、./foobardb/zot.ibd が問題のファイルということになる。suで強引にスーパーユーザになり、cd foobardbでカレントディレクトリを移動。
mv cache_menu.ibd cache_menu.ibdremoved
で、renameする。最初は、cache_menu.ibdが開けない、とか言っていたのが、いざrenameしてみると今度はcache_update.ibdが開けない、といってくる。もともと設計していたテーブルではない、おそらくInnoDB自体が管理しているテーブルのibdがことごとく引っ掛かっている感じだったので、試しに、全部ibdをrenameしたらどうなるか、試した。
システム管理?のibdファイル
このバージョンでは、ibdは以下のように大量に作られている。
access.ibd actions.ibd actions_aid.ibd authmap.ibd batch.ibd blocks.ibd blocks_roles.ibd boxes.ibd cache.ibd cache_block.ibd cache_filter.ibd cache_form.ibd cache_page.ibd comments.ibd files.ibd filter_formats.ibd filters.ibd flood.ibd history.ibd languages.ibd locales_source.ibd locales_target.ibd menu_custom.ibd menu_links.ibd menu_router.ibd node.ibd node_access.ibd node_comment_statistics.ibd node_counter.ibd node_revisions.ibd node_type.ibd permission.ibd role.ibd semaphore.ibd sessions.ibd studylogs.ibd system.ibd term_data.ibd term_hierarchy.ibd term_node.ibd term_relation.ibd term_synonym.ibd url_alias.ibd users_roles.ibd variable.ibd vocabulary.ibd vocabulary_node_types.ibd watchdog.ibd
いいのかなぁ、やっちゃえ、ってな訳で、以下のようなスクリプトを書いた。
#!/bin/bash
arr=( `ls *.ibd` )
for n in ${arr[@]}; do
# echo $n
new_name=$n"removed"
mv $n $new_name
done
上記の全ての拡張子 .ibd が .ibdremovedに・・・
大丈夫かなぁ、と思いつつ、MySQLを起動したら無事Runningになりました。
めでたしめでたし。
で、ごちゃごちゃして気持ち悪いので、suになった勢いで
rm *.ibdremoved
で、renameしたファイルを消したことは言うまでもありません。
ということは、(2)にあった
2) If the table is not needed, or you can restore it from a backup, then you can remove the .ibd file, and InnoDB will do a normal crash recovery and ignore that table.
の通り、最初からrenameせずにrmする、つまり
#!/bin/bash
arr=( `ls *.ibd` )
for n in ${arr[@]}; do
# echo $n
rm $n
done
でもよかったのかなぁ、って、結局全部削除するなら、スクリプトなんか書かずに
rm *.ibd
でいいじゃん。なんて回りくどいことをしたんだ orz。
でも、削除一瞬怪我一生ですから・・・つい慎重になっただけです・・・
結果について
もっと丁寧に、InnoDBの挙動を確認してから、とは思ったのですが、そして、「解決策1」が一番「間違いのない」やり方かもしれないとは思いましたが、ibdの存在が妙に気になったので、force_recoveryではないやり方を試してみた次第です。
何かのご参考になれば・・・