昨夜投稿された -initblock=FILEパッチを使ってインポートを計装し、TxnBegin、TxnCommit、TxnAbort、Read、Writeにprintfのトレースポイントを入れた:
ProcessBlock: ACCEPTED
CDB::Write()
DB4: txn_begin
CDB::Write()
CDB::Write()
CDB::Write()
DB4: txn_commit
SetBestChain: new best=000000005b5c1859db19 height=1751 work=7524897523416
ProcessBlock: ACCEPTED
CDB::Write()
DB4: txn_begin
CDB::Write()
CDB::Write()
CDB::Write()
DB4: txn_commit
SetBestChain: new best=00000000f396ab6b62ba height=1752 work=7529192556249
ProcessBlock: ACCEPTED
CDB::Write()
DB4: txn_begin
CDB::Write()
CDB::Write()
CDB::Write()
DB4: txn_commit
SetBestChain: new best=000000000c6bcf972117 height=1753 work=7533487589082
つまり、トランザクションの外で発生するCDB::Write() があるようだ(vTxnが空??)。
txnid==NULLはdb4にとっては完全に合法だが、コールパスが ::TxnBegin() で設定されたDB_TXN_NOSYNCフラグの外で動作している可能性があるということでもある。したがって、トランザクション外のCDB::Write() はDB_AUTO_COMMITデータベースフラグの支配下で同期動作(DB_TXN_SYNC)になる可能性がある。
EDIT: WriteBlockIndex() をトランザクションでラップすると、ローカルディスクのインポート(-initblocks)が高速化されるようだ。
--- a/main.cpp
+++ b/main.cpp
@@ -1427,7 +1427,10 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned
pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork
CTxDB txdb;
+ txdb.TxnBegin();
txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
+ if (!txdb.TxnCommit())
+ return false;
もちろんこれはbegin+commit+begin+commitが立て続けに起きる(SetBestChain)ことを意味するので、もう少し素朴でないアプローチ(ネストしたトランザクションか、両方のdb4書き込みを同じトランザクションでラップする)が望ましいかもしれない。