昨夜投稿された -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 書き込みを同じトランザクションでラップする)が望ましいかもしれない。