学習記録:12月16日(日):【MySQL】frmファイル欠損、ibdファイル存在、テーブル構成を推測したい【リストア不能】
これは 俺のインプットアウトプット記録 Advent Calendar 2018 の16日目のエントリーです。
結論から言ってしまうと、テーブル修復でエラーになっていたのは .ibdファイル
がそもそもなかったからでした。おそらく、MacBookのストレージ容量不足でファイルを退避させた際に、なぜか .frmファイル
を一緒に退避させなかったみたいですね(遠い目)
というわけで、振り返りつつ、どうにか .ibdファイル
を直接読むことはできないものか、ともがいてみます。
昨日まで
昨日は MySQL 5.7.19 の環境をマイナーバージョン指定で作ろう、と思い立ったものの、おそらくソースからの make install じゃないと無理では…ということで、もともと使っていた環境に、エラーのあったテーブルをリストアし、mysql_upgradeを再実行すればいいかな、と思っていました。
なんと .frmファイル欠損
が、いざリストアしてみると肝心のテーブルがない…。あ、テーブル個別でバックアップ取っていたな、と思ってzipファイルを開くと…なんと .ibdファイルそのもの
。
.frmファイル
がテーブル構造を表すファイルで、 .ibdファイル
が実データを表すファイル。これではテーブル構造がわからぬ…しかも前回、公式にしたがって DROP TABLE しているので構造がわからない。
うーむ困った…。
`.ibdファイルを直接読んで、レコードの状態をみることはできないものか。
と探していると、 innodb_ruby というツールを提供しているかたを発見。
wiki に書かれている通りにインストールし、使ってみました。
innodb_ruby
以下の手順でインストールしました。
インストール
# バックアップを取っていたと思ったらibdファイルだけだったディレクトリで作業 $ pwd /Users/mamy1326/dev/vagrant/mysql57/var/lib/mysql/mamy1326/innodb_ruby $ sudo gem install innodb_ruby Password: Fetching: bindata-2.4.4.gem (100%) Successfully installed bindata-2.4.4 Fetching: digest-crc-0.4.1.gem (100%) Successfully installed digest-crc-0.4.1 Fetching: innodb_ruby-0.9.15.gem (100%) Successfully installed innodb_ruby-0.9.15 Parsing documentation for bindata-2.4.4 Installing ri documentation for bindata-2.4.4 Parsing documentation for digest-crc-0.4.1 Installing ri documentation for digest-crc-0.4.1 Parsing documentation for innodb_ruby-0.9.15 Installing ri documentation for innodb_ruby-0.9.15 Done installing documentation for bindata, digest-crc, innodb_ruby after 3 seconds 3 gems installed
GitHubから諸々取得
$ git clone https://github.com/jeremycole/innodb_ruby.git Cloning into 'innodb_ruby'... remote: Enumerating objects: 2663, done. remote: Total 2663 (delta 0), reused 0 (delta 0), pack-reused 2663 Receiving objects: 100% (2663/2663), 16.79 MiB | 483.00 KiB/s, done. Resolving deltas: 100% (1451/1451), done. naosama-mac:mamy1326 mamy1326$ cd innodb_ruby naosama-mac:innodb_ruby mamy1326$ innodb_space -s ../ c_log.ibd innodb_ruby/ naosama-mac:innodb_ruby mamy1326$ innodb_space -s ../c_log.ibd system-spaces name pages indexes /Library/Ruby/Gems/2.3.0/gems/innodb_ruby-0.9.15/bin/innodb_space:206:in `block in system_spaces': undefined method `pages' for nil:NilClass (NoMethodError) from /Library/Ruby/Gems/2.3.0/gems/innodb_ruby-0.9.15/bin/innodb_space:211:in `system_spaces' from /Library/Ruby/Gems/2.3.0/gems/innodb_ruby-0.9.15/bin/innodb_space:1976:in `<top (required)>' from /usr/local/bin/innodb_space:22:in `load' from /usr/local/bin/innodb_space:22:in `<main>' $ cd innodb_ruby
innodb_space 実行
藁をもすがる気持ちで実行してみます。 なお、実行コマンドは wiki と、 日々の覚書 mysqlディレクトリーに知らない.ibdファイルがある in MySQL 8.0.0 を参考にさせていただきました。
-f
オプション- 対象はibdata1ではなく、テーブル個別のibd
- 対象ファイル
c_log.ibd
ファイルに対し読み込みを実行する
- page-dump
-T
オプション- 指定されたテーブル名を使用します、とのこと。データベース名とテーブル名を指定します
で、dumpした結果。正直よくわかりませんな(遠い目
$ innodb_space -f ../c_log.ibd -T mamy1326/c_log -p 5 page-dump | less #<Innodb::Page::Index:0x00007fe6b10dcb78>: fil header: {:checksum=>816151722, :offset=>5, :prev=>nil, :next=>nil, :lsn=>42947405534, :type=>:INDEX, :flush_lsn=>0, :space_id=>139} fil trailer: {:checksum=>816151722, :lsn_low32=>4292699870} page header: {:n_dir_slots=>3, :heap_top=>274, :garbage_offset=>0, :garbage_size=>0, :last_insert_offset=>265, :direction=>:right, :n_direction=>4, :n_recs=>11, :max_trx_id=>0, :level=>2, :index_id=>106, :n_heap=>13, :format=>:compact} fseg header: {:leaf=> <Innodb::Inode space=<Innodb::Space file="../c_log.ibd", page_size=16384, pages=559616>, fseg=6>, :internal=> <Innodb::Inode space=<Innodb::Space file="../c_log.ibd", page_size=16384, pages=559616>, fseg=5>} sizes: header 120 trailer 8 directory 6 free 16096 used 288 record 154 per record 14.00 page directory: [99, 181, 112] system records: {:offset=>99, :header=> {:next=>125, :type=>:infimum, :heap_number=>0, :n_owned=>1, :min_rec=>false, :deleted=>false, :length=>5}, :next=>125, :data=>"infimum\x00", :length=>8} {:offset=>112, :header=> {:next=>112, :type=>:supremum, :heap_number=>1, :n_owned=>8, :min_rec=>false, :deleted=>false, :length=>5}, :next=>112, :data=>"supremum", :length=>8} garbage records: records: {:format=>:compact, :offset=>125, :header=> {:next=>139, :type=>:node_pointer, :heap_number=>2, :n_owned=>0, :min_rec=>true, :deleted=>false, :length=>5}, :next=>139} {:format=>:compact, :offset=>139, :header=> {:next=>167, :type=>:node_pointer, :heap_number=>3, :n_owned=>0, :min_rec=>false, :deleted=>false, :length=>5}, :next=>167} {:format=>:compact, :offset=>167, :header=> {:next=>181, :type=>:node_pointer, :heap_number=>5, :n_owned=>0, :min_rec=>false, :deleted=>false, :length=>5}, :next=>181} {:format=>:compact, :offset=>181, :header=> {:next=>195, :type=>:node_pointer, :heap_number=>6, :n_owned=>4, :min_rec=>false, :deleted=>false, :length=>5}, :next=>195} {:format=>:compact, :offset=>195, :header=> {:next=>209, :type=>:node_pointer, :heap_number=>7, :n_owned=>0, :min_rec=>false, :deleted=>false, :length=>5}, :next=>209} {:format=>:compact, :offset=>209, :header=> {:next=>223, :type=>:node_pointer, :heap_number=>8, :n_owned=>0, :min_rec=>false, :deleted=>false, :length=>5}, :next=>223} {:format=>:compact, :offset=>223, :header=> {:next=>237, :type=>:node_pointer, :heap_number=>9, :n_owned=>0, :min_rec=>false, :deleted=>false, :length=>5}, :next=>237} {:format=>:compact, :offset=>237, :header=> {:next=>251, :type=>:node_pointer, :heap_number=>10, :n_owned=>0, :min_rec=>false, :deleted=>false, :length=>5}, :next=>251} {:format=>:compact, :offset=>251, :header=> {:next=>265, :type=>:node_pointer, :heap_number=>11, :n_owned=>0, :min_rec=>false, :deleted=>false, :length=>5}, :next=>265} {:format=>:compact, :offset=>265, :header=> {:next=>153, :type=>:node_pointer, :heap_number=>12, :n_owned=>0, :min_rec=>false, :deleted=>false, :length=>5}, :next=>153} {:format=>:compact, :offset=>153, :header=> {:next=>112, :type=>:node_pointer, :heap_number=>4, :n_owned=>0, :min_rec=>false, :deleted=>false, :length=>5}, :next=>112}
次の課題
まずもってテーブル構造を、レコードから推測できないことにはリストアは不可能そうです。
しかしせっかく .ibdファイル
を読み込むところまできたので、できる限りのことをしてみようと思います。
これで自由にレコード読めるようになったら面白いじゃん?
せっかく便利なツールを作ってくれている人がいるし、個人的に中身を直接読んでみたいと常々思っていたので、趣味的に願ったり叶ったり。
アップグレードはしばし棚上げして、 .ibdファイル
の読み方を学習してみたいと思います。
もしこのエントリを読んでくださっているかたがいらしたならば、おそらく面白くないんじゃないかなあ…と思いながらも、自分自身はやっていて楽しいのでこうしてエントリにしているわけでございます。
1歩ずつ地道に進めてみて、結果までたどり着き、誰かしらの有益な情報になればいいなあ、と思いながら、やれるところまでやってみようと思います。
で、もしダメなら諦めて、くだんのテーブルは捨ててアップグレードを進めたいと思います。
アップグレード時にテーブル修復が失敗していたのも、そもそも .ibdファイル
がなかったからで、ないならないで、消して進めれば本題はクリアできると思いますので。
というわけで、明日も引き続き .ibdファイル
と戯れたいと思います!