2012/04/19

Firebirdで壊れたDBの修復

Firebirdを使ってブックマークを管理するアプリケーションを作っていた時のこと。 気がついたらFast CGIがエラーを返していました。 最初はコーディングのミスかと思ったものの、その周辺は変更していないのでquery自体に失敗しているのに気づくのに時間が少しばかりかかりました。

今回は、そんなデータベースファイルの修復過程のログです。

まずは、エラーメッセージ

普通にqueryを発行してエラーが出たところまでは、つきとめました。

 $ isql-fb -u sysdba -p masterkey ~/lib/fb/bkmkapp.fdb

isql-fbで SELECT * FROM INFO; といった感じのSQLを実行した時のメッセージ

Statement failed, SQLCODE = -902
database file appears corrupt (/home/user1/lib/fb/bkmkapp.fdb)
-wrong page type
-page 3100 is of wrong type (expected 5, found 0)

定番の修復方法

Webを検索したり、手元の焼き鳥本をみて方法を探しました。 gfixとgbakコマンドで壊れたDBの修復を試みて、最終的にはデータを取り出し、正常なDBに取り出せた正常なデータを書き戻すという方法が一般的なようです。

まずはgfixを使って修復を試みてみます。

 $ cd ~/lib/fb
 $ gfix -v -full bkmkapp.fdb

出力されたメッセージ

Your user name and password are not defined. Ask your database administrator to set up a Firebird login.

DBに接続する時にもユーザー、パスワードが必要そうですが、コマンドラインはisql-fbとは少し違うようです。

 $ gfix -v -f -user sysdba -password masterkey bkmkapp.fdb
Summary of validation errors
	Number of Blob page errors	: 149
	Number of data page errors	: 120
	Number of index page errors	: 8
	Number of database page errors	: 3915

なんだか壊れたページ数が多すぎるんじゃないかという気もしますが、とりあえずデータを取り出してみます。 まずは壊れた部分を取り出さないようにマーキングしておきます。

 $ gfix -m -user sysdba -password masterkey bkmkapp.fdb

それから修復用に-e -gオプションを追加して、newdb.fdbにexportします。

 $ gbak -b -e -g -user sysdba -password masterkey bkmkapp.fdb newdb.fdb

newdb.fdbが作られなかった時のエラー

gbak: ERROR:invalid request BLR at offset 13
gbak: ERROR:    table id 138 is not defined
gbak: ERROR:gds_$compile_request failed
gbak:Exiting before completion due to errors

通常であれば、newdb.fdbが作成されるので、gbakのオプションを-rにして解決しますが、 今回はどうにも手がありません。

Ubuntu 10.04 LTSへのFirebird 2.5.1のインストール

まぁパッケージで提供されているFirebirdを2.5.1にして悪あがきをしてみます。

既存パッケージの削除

$ dpkg -l | grep firebird で表示されるパッケージを$ sudo apt-get removeの引数に指定して消してしまいます。

 $ sudo /etc/init.d/firebird2.1-super stop
 $ sudo apt-get remove firebird2.1-server-common firebird2.1-examples firebird2.1-common-doc firebird2.1-common
 $ sudo dpkg --purge firebird2.1-common firebird2.1-server-common firebird2.1-super

purgeをすると、設定を残すかデータベースファイルを消すか、質問されるので適当に答えておきます。

FirebirdCS-2.5.1.26351-0.amd64.tar.gzの導入

公式サイトのdownloadセクションからLinux AMD64版のFirebirdCS-2.5.1.26351-0.amd64.tar.gzをダウンロードしてきました。

展開するとディレクトリができるので、その中のinstall.shを実行します。

 $ cd FirebirdCS-2.5.1.26351-0.amd64
 $ sudo ./install.sh
Firebird classic 2.5.1.26351-0.amd64 Installation

Press Enter to start installation or ^C to abort
Extracting install data
Updated /etc/services
Please enter new password for SYSDBA user: masterkey
Install completed

sysdbaのパスワードは教科書と同じにしておきました。

この方法で導入すると、/opt/firebirdが作成され必要なファイルが導入されます。 ps auxwwで確認するとfirebirdプロセスはないように見えますが、/etc/inetd.confに/opt/firebird/bin/fb_inet_serverが追加されていて3050ポートはLISTEN状態になっています。

ここら辺をふまえて、同じ事をやってみます。

isqlからのSELECT文による問題の再現

ファイルのパスが変ってくるので、注意が必要です。 それと明示的にサーバー経由でアクセスするようにlocalhost:と絶対パスで指定しています。

$ /opt/firebird/bin/isql -u sysdba -p masterkey localhost:/home/user1/lib/fb/bkmkapp.fdb
...
...
SQL> 

…。普通に正常終了してしまいました。止まっていたFast CGIも動いてしまったのでサービス自体は継続できています。 しかし、というかもちろん、gfixでは問題は解決していません。 -mオプションでマークをつけた個所を無視しているだけなのかもしれないけれど、真相は不明です。

サーバーのバージョンアップで引き続き動き続ける事はできそうですが、引き伸ばしただけで有益とはいえなさそうです。問題の解決には商用のツールを使わざるを得ないようです。

原因について

いろいろ調べてみると、どうやら稼働中のDBに対してCREATE TABLEなどのメタデータに関連する操作を行なうと、特にDB破損の可能性が高まるようです。

さいごに

実は開発中のDBなのでテーブル定義後やデータ挿入後のファイルはコピーを取っていたり、壊れても問題ないようにはしているのですが、本番運用を想定して直し方を経験する事にしました。

RDBMSの管理方法はメーカーに依らずだいたい同じ、基本はオンライン or オフラインデータの書き戻しとヒストリーログからの書き戻しをする以外にはありません。

実際にはバックアップファイルやヒストリデータを確実にあるタイミングで取得するために、ZFSのスナップショットのような機能があると便利になるわけです。

今回はけっきょく解決しなかったわけですが、本番では、こういう事態に備えて考慮していく事になりそうです。 ユーザーが接続していたりサーバーを稼働させたままRECREATE TABLEするような事を避ければ、滅多に出ないとは思いますけどね。

この記事で取り上げた品々

0 件のコメント: