@@ -94,50 +94,52 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
9494 return Read (DB_LAST_BLOCK, nFile);
9595}
9696
97- bool CCoinsViewDB::GetStats (CCoinsStats &stats) const {
97+ CCoinsViewCursor *CCoinsViewDB::Cursor () const
98+ {
99+ CCoinsViewDBCursor *i = new CCoinsViewDBCursor (const_cast <CDBWrapper*>(&db)->NewIterator (), GetBestBlock ());
98100 /* It seems that there are no "const iterators" for LevelDB. Since we
99101 only need read operations on it, use a const-cast to get around
100102 that restriction. */
101- boost::scoped_ptr<CDBIterator> pcursor (const_cast <CDBWrapper*>(&db)->NewIterator ());
102- pcursor->Seek (DB_COINS);
103+ i->pcursor ->Seek (DB_COINS);
104+ // Cache key of first record
105+ i->pcursor ->GetKey (i->keyTmp );
106+ return i;
107+ }
103108
104- CHashWriter ss (SER_GETHASH, PROTOCOL_VERSION);
105- stats.hashBlock = GetBestBlock ();
106- ss << stats.hashBlock ;
107- CAmount nTotalAmount = 0 ;
108- while (pcursor->Valid ()) {
109- boost::this_thread::interruption_point ();
110- std::pair<char , uint256> key;
111- CCoins coins;
112- if (pcursor->GetKey (key) && key.first == DB_COINS) {
113- if (pcursor->GetValue (coins)) {
114- stats.nTransactions ++;
115- for (unsigned int i=0 ; i<coins.vout .size (); i++) {
116- const CTxOut &out = coins.vout [i];
117- if (!out.IsNull ()) {
118- stats.nTransactionOutputs ++;
119- ss << VARINT (i+1 );
120- ss << out;
121- nTotalAmount += out.nValue ;
122- }
123- }
124- stats.nSerializedSize += 32 + pcursor->GetValueSize ();
125- ss << VARINT (0 );
126- } else {
127- return error (" CCoinsViewDB::GetStats() : unable to read value" );
128- }
129- } else {
130- break ;
131- }
132- pcursor->Next ();
109+ bool CCoinsViewDBCursor::GetKey (uint256 &key) const
110+ {
111+ // Return cached key
112+ if (keyTmp.first == DB_COINS) {
113+ key = keyTmp.second ;
114+ return true ;
133115 }
134- {
135- LOCK (cs_main);
136- stats.nHeight = mapBlockIndex.find (stats.hashBlock )->second ->nHeight ;
116+ return false ;
117+ }
118+
119+ bool CCoinsViewDBCursor::GetValue (CCoins &coins) const
120+ {
121+ return pcursor->GetValue (coins);
122+ }
123+
124+ unsigned int CCoinsViewDBCursor::GetValueSize () const
125+ {
126+ return pcursor->GetValueSize ();
127+ }
128+
129+ bool CCoinsViewDBCursor::Valid () const
130+ {
131+ return keyTmp.first == DB_COINS;
132+ }
133+
134+ void CCoinsViewDBCursor::Next ()
135+ {
136+ pcursor->Next ();
137+ if (pcursor->Valid ()) {
138+ bool ok = pcursor->GetKey (keyTmp);
139+ assert (ok); // If GetKey fails here something must be wrong with underlying database, we cannot handle that here
140+ } else {
141+ keyTmp.first = 0 ; // Invalidate cached key after last record so that Valid() and GetKey() return false
137142 }
138- stats.hashSerialized = ss.GetHash ();
139- stats.nTotalAmount = nTotalAmount;
140- return true ;
141143}
142144
143145bool CBlockTreeDB::WriteBatchSync (const std::vector<std::pair<int , const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
0 commit comments