やっと簡単な問題だ。初期ダウンロードのような長い操作中に発生しうる原因が見えた。TryLock のバグは DB 関連の問題とは無関係だ。修正は test8 に含まれる。
32 ビット Linux 上で、絶え間ないリクエストの連続フラッドを送りつけることで、db::open/close 例外を 3回再現できた。wallet.dat データベースを定期的に閉じてフラッシュするだけでも db::close 例外が発生するようだ。Linux ではウォレットフラッシュ機能を無効にする。Linux 上では、終了する準備ができるまでデータベースハンドルを閉じないようにする。これを無効にしてからは、今のところ例外は発生していない。
初期ブロックダウンロードの秩序立った実装も進めている。すべてのブロックを一度にリクエストする素朴な方法ではなく、一度に 500件ずつバッチでリクエストするようにする。こうすることで、リトライタイムアウトの前にブロックを受信できるため、実際に受信できなかったり遅すぎたりしない限り、他のノードにリクエストすることはなくなるはずだ。変更はリクエストを受ける側にあるため、初期ブロックダウンロードの相手が新しいバージョンのノードになるまで、この機能は見えない。
test8 を送る前にもう少しテストを続ける。
NewLibertyStandardのメール(2009年11月18日 03:00 UTC)test7 を、新しいデータディレクトリで開始しました。ブロックのダウンロードが格段に速く始まりました。これまでの Linux ビルドでは数分かかっていましたが、今回は約 15 秒で済みました。ブロックをダウンロードしている間に 1 回クラッシュし、ターミナルに以下のメッセージが出ました。
../include/wx/thrimpl.cpp(50): assert “m_internal” failed in TryLock(): wxMutex::TryLock(): not initialized [in child thread] Trace/breakpoint trap
ログファイルを添付しますが、ビットコイン再起動の前にバックアップを取り忘れたので、ログのどの時点でクラッシュが起きたかは分かりません。
幸いセグメンテーション違反にはまだ遭遇していません。直前までのビルドでセグメンテーション違反の頻度には大きなばらつきがありましたので、引き続き動かして、問題があれば知らせます。
サトシ・ナカモトのメール(2009年11月17日 16:57 UTC)test 7:
念のため、実行前にデータディレクトリをバックアップしてほしい。
Db::open/Db::close「Bad file descriptor」例外の回避策だ。初期ブロックダウンロードも高速化される可能性がある。回避策は、データベースハンドルを開いたままプログラムの実行中ずっと保持しておくことで、実際これはより一般的なやり方でもある。常に閉じたり開いたりしなければ、エラーが発生する機会がなくなるはずだ。
唯一の例外は wallet.dat で、書き込み完了後にトランザクションログを dat ファイルにフラッシュするために閉じるようにしている。これにより、dat ファイルが単体で有効になる。Bitcoin の実行中に誰かがバックアップを取った場合、データベースのトランザクションログなしでもそれ自体で有効な wallet.dat を取得できる。
これはデータベース処理の再構成なので、新たなデッドロックが見つかるかもしれない。通常、デッドロックが発生すると、UI の再描画が止まるか、まだ Generating と表示されているにもかかわらず CPU を使用しなくなる。