RFC: リリースtarballにブロックチェーン1-74000を同梱する?

5 件のメッセージ サトシ・ナカモト 2010年11月25日 — 2010年12月1日

時間がかかるのはダウンロードではなく、検証とインデックス作成だ。

帯域幅の点では、アーカイブをダウンロードするよりも効率的だ。Bitcoinはblk0001.datのデータのみをダウンロードし、現在55MBで、blkindex.dat(47MB)は自分で構築する。blkindex.datの構築がすべてのディスクアクティビティの原因だ。

ブロックのダウンロード中は、500ブロックごとにのみデータベースをディスクにフラッシュする。ブロック数が??499や??999で一時停止するのが見えるかもしれない。それがフラッシュしている時だ。

自分で検証とインデックス作成を行うことが、インデックスデータの安全性を確保する唯一の方法だ。信頼できないソースからblk0001.datとblkindex.datをコピーした場合、その中身すべてを信頼できるかどうか知る方法はない。

Berkeley DBの設定を調整して、キャッシュメモリを有効化または増加できるかもしれない。

7年前の遅いドライブでテストしたが、帯域幅とCPUは明らかにボトルネックではなかった。初回ダウンロードは1時間20分かかった。

それよりはるかに長く、特に24時間もかかるなら、非常に遅いノードからダウンロードしているか、接続速度が約15KB/秒(120kbps)よりかなり遅いか、何か他に問題があるはずだ。そのような場合にボトルネックが何であるように見えるかわかると良いのだが。

最新のブロックが送信される10分程度ごとに、より速いノードに切り替える機会があるはずだ。最新のブロックがブロードキャストされると、他のノードに次の500ブロックを要求し、最も速く送信するノードからダウンロードを継続する。少なくとも、そのように動作するはずだ。

Quote from: jgarzik on November 26, 2010, 02:07:43 AMQuote from: satoshi on November 25, 2010, 05:51:39 PMBerkeley DBの設定を調整して、キャッシュメモリを有効化または増加できるかもしれません。 ダウンロード中に、ACIDプロパティのどれが必要ですか? より多くの読み取りキャッシュが役立つかもしれない。インデックスを作成するためにblk0001.datとblkindex.dat全体をランダムに読み取る必要がある。ファイルがメモリより小さいと仮定することはできないが、現在はまだそうだ。ほとんどの依存関係が最近のものなので、キャッシュは効果的だろう。

誰かが異なるBerkeley DB設定で実験して、ダウンロードを大幅に速くするものがないか確認すべきだ。大幅な改善が見つかれば、詳細を詰めることができる。

引用:BDBレコードの追加は、チェックポイントを発行するまで、単にログファイルに追記するだけだ。チェックポイントがメインデータベースファイルを更新する。500ブロックごとにチェックポイントしている。

他の議論にもかかわらず、現在の次のステップは: 引用:誰かが異なるBerkeley DB設定で実験して、ダウンロードを大幅に速くするものがないか確認すべきです。大幅な改善が見つかれば、詳細を詰めることができます。 特に、読み取りキャッシュを増やすと大いに役立つのではないかと思う。

Quote from: jgarzik on November 28, 2010, 02:33:29 AMIRCでまた新しいユーザーが、今度はLinuxで、1ブロックあたり4秒の速度でダウンロードしていました — 総ダウンロード時間の推定は約4日間。 それなら何かもっと具体的な問題があった。通常の初回ダウンロード時間によるものではない。より詳細がなければ診断できない。遅いダウンロードが原因だったなら、次のブロックブロードキャストでより速いソースに切り替わるはずの10〜20分後に速くなったか?debug.logに手がかりがあるかもしれない。インターネット接続はどのくらい速いか?一貫して遅かったのか、ある時点で遅くなっただけか?

引用:ジェネシスブロックからブロック74000までのハッシュがbitcoinにハードコード(コンパイル)されているので、ブロックデータベースの圧縮zipファイルをどこからでも自動的にダウンロードし、展開し、検証し、実行を開始できない理由はないはずです。 74000チェックポイントは保護に十分ではなく、ダウンロードがすでに74000を過ぎていれば何もしない。-checkblocksはより多くのことをするが、依然として簡単に突破される。zipファイルの提供者を信頼しなければならない。

「検証する」ステップがあれば、現在の通常の初回ダウンロードと同じくらい時間がかかるだろう。データダウンロードではなく、インデックス作成がボトルネックなのだ。

Quote from: jgarzik on November 28, 2010, 07:33:55 AMおそらくいずれブロックヘッダのみをダウンロードする軽量クライアントが登場するでしょうが、それでも数十万のヘッダがあるでしょう… ヘッダあたり80バイトでインデックス作成作業なし。1分程度で済むかもしれない。

引用:一括データ転送用に設計されていないプロトコル(bitcoin P2P)を使用した非圧縮データ。 データの大部分はハッシュ、鍵、署名で、圧縮不可能だ。

初回ダウンロードの速度は、プロトコルの一括データ転送レートを反映していない。制限要因はダウンロード中のインデックス作成だ。

実際よりも、すべてが間違っていると想定する傾向があるようだね。

ブロックインデックスの書き込みは軽い作業だ。txインデックスの構築は1ブロックあたりのランダムアクセスがはるかに多い。すべてのprev txinの読み取りが遅い原因ではないかと疑っている。読み取りキャッシュが役立つだろう。DBがそれを行うのが最善だ。キャッシュメモリの使用量の設定があるかもしれない。

引用:1) bitcoinはプログラムの起動時に環境だけでなくデータベースを開き、プログラムのシャットダウン時にデータベースを閉じるべきです。 すでにそうしている。CDBを参照してくれ。(例えば)CTxDBオブジェクトの寿命は、データベーストランザクションのサポートと、シャットダウン時にまだデータベースを使用しているものがあるかどうかを知るためだけだ。

引用:そして、さらにbitcoinはデータベースのチェックポイントを強制し、すべてのトランザクションをログからメインデータベースにプッシュします。 そうしていたらはるかに遅くなるだろう。1分または500ブロックに1回のみのはずだ:

    if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
        nMinutes = 1;
    dbenv.txn_checkpoint(0, nMinutes, 0);

おそらくこれを追加すべきだ:

    if (!fReadOnly)
        dbenv.txn_checkpoint(0, nMinutes, 0);

引用:2) 初回ブロックダウンロードでは、txnコミットはレコードごとではなくN件ごとに行うべきです。N=1000を提案します。 トランザクションコミットはフラッシュを意味するのか?それは驚きだ。トランザクションでラップされたデータベース操作は、他のデータベース操作と同様にログに記録されると思う。多くのデータベースアプリケーションでは、ほぼすべての操作のペアをトランザクションでラップする必要がある。例えば、あるアカウントから別のアカウントへの送金(aを借方、bを貸方)などだ。すべてを自分でバッチ処理することが求められるとは想像できない。

以下のケースで、ケース1は1回フラッシュし、ケース2は2回フラッシュするのだろうか?

ケース1: write write write write checkpoint

ケース2: begin transaction write write commit transaction begin transaction write write commit transaction checkpoint

データベースの使用方法を歪めるのは正しいアプローチではないだろう。BDBの設定とキャッシュで対応すべきだ。

良い最適化だ。次にSVNを更新する際に追加する。

より一般的には、これも検討できるだろう:

        dbenv.set_lk_max_objects(10000);
        dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
        dbenv.set_flags(DB_AUTO_COMMIT, 1);
+       dbenv.set_flags(DB_TXN_NOSYNC, 1);
        ret = dbenv.open(strDataDir.c_str(),
                         DB_CREATE     |
                         DB_INIT_LOCK  |
                         DB_INIT_LOG   |

そうすれば、ウォレット書き込み後のフラッシュにはCDB::Close()のdbenv.txn_checkpoint(0, 0, 0)に依存することになる。