diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -214,6 +214,7 @@ Db *pdb; std::string strFile; DbTxn *activeTxn; + Dbc *m_cursor; bool fReadOnly; bool fFlushOnClose; BerkeleyEnvironment *env; @@ -287,8 +288,9 @@ return HasKey(ssKey); } - Dbc *GetCursor(); - int ReadAtCursor(Dbc *pcursor, CDataStream &ssKey, CDataStream &ssValue); + bool StartCursor(); + bool ReadAtCursor(CDataStream &ssKey, CDataStream &ssValue, bool &complete); + void CloseCursor(); bool TxnBegin(); bool TxnCommit(); bool TxnAbort(); diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -336,7 +336,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase &database, const char *pszMode, bool fFlushOnCloseIn) - : pdb(nullptr), activeTxn(nullptr) { + : pdb(nullptr), activeTxn(nullptr), m_cursor(nullptr) { fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fFlushOnClose = fFlushOnCloseIn; env = database.env.get(); @@ -461,6 +461,7 @@ } activeTxn = nullptr; pdb = nullptr; + CloseCursor(); if (fFlushOnClose) { Flush(); @@ -549,18 +550,17 @@ fSuccess = false; } - Dbc *pcursor = db.GetCursor(); - if (pcursor) { + if (db.StartCursor()) { while (fSuccess) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue); - if (ret1 == DB_NOTFOUND) { - pcursor->close(); + bool complete; + bool ret1 = + db.ReadAtCursor(ssKey, ssValue, complete); + if (complete) { break; } - if (ret1 != 0) { - pcursor->close(); + if (!ret1) { fSuccess = false; break; } @@ -583,6 +583,7 @@ fSuccess = false; } } + db.CloseCursor(); } if (fSuccess) { db.Close(); @@ -781,28 +782,32 @@ } } -Dbc *BerkeleyBatch::GetCursor() { +bool BerkeleyBatch::StartCursor() { + assert(!m_cursor); if (!pdb) { - return nullptr; - } - Dbc *pcursor = nullptr; - int ret = pdb->cursor(nullptr, &pcursor, 0); - if (ret != 0) { - return nullptr; + return false; } - return pcursor; + int ret = pdb->cursor(nullptr, &m_cursor, 0); + return ret == 0; } -int BerkeleyBatch::ReadAtCursor(Dbc *pcursor, CDataStream &ssKey, - CDataStream &ssValue) { +bool BerkeleyBatch::ReadAtCursor(CDataStream &ssKey, CDataStream &ssValue, + bool &complete) { + complete = false; + if (m_cursor == nullptr) { + return false; + } // Read at cursor SafeDbt datKey; SafeDbt datValue; - int ret = pcursor->get(datKey, datValue, DB_NEXT); + int ret = m_cursor->get(datKey, datValue, DB_NEXT); + if (ret == DB_NOTFOUND) { + complete = true; + } if (ret != 0) { - return ret; + return false; } else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr) { - return 99999; + return false; } // Convert to streams @@ -812,7 +817,15 @@ ssValue.SetType(SER_DISK); ssValue.clear(); ssValue.write((char *)datValue.get_data(), datValue.get_size()); - return 0; + return true; +} + +void BerkeleyBatch::CloseCursor() { + if (!m_cursor) { + return; + } + m_cursor->close(); + m_cursor = nullptr; } bool BerkeleyBatch::TxnBegin() { diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -775,8 +775,7 @@ } // Get cursor - Dbc *pcursor = m_batch.GetCursor(); - if (!pcursor) { + if (!m_batch.StartCursor()) { pwallet->WalletLogPrintf("Error getting wallet database cursor\n"); return DBErrors::CORRUPT; } @@ -785,12 +784,13 @@ // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue); - if (ret == DB_NOTFOUND) { + bool complete; + bool ret = m_batch.ReadAtCursor(ssKey, ssValue, complete); + if (complete) { break; } - - if (ret != 0) { + if (!ret) { + m_batch.CloseCursor(); pwallet->WalletLogPrintf( "Error reading next record from wallet database\n"); return DBErrors::CORRUPT; @@ -822,10 +822,10 @@ pwallet->WalletLogPrintf("%s\n", strErr); } } - pcursor->close(); } catch (...) { result = DBErrors::CORRUPT; } + m_batch.CloseCursor(); // Set the active ScriptPubKeyMans for (auto spk_man_pair : wss.m_active_external_spks) { @@ -954,8 +954,7 @@ } // Get cursor - Dbc *pcursor = m_batch.GetCursor(); - if (!pcursor) { + if (!m_batch.StartCursor()) { LogPrintf("Error getting wallet database cursor\n"); return DBErrors::CORRUPT; } @@ -964,12 +963,14 @@ // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue); - if (ret == DB_NOTFOUND) { + bool complete; + bool ret = m_batch.ReadAtCursor(ssKey, ssValue, complete); + if (complete) { break; } - if (ret != 0) { + if (!ret) { + m_batch.CloseCursor(); LogPrintf("Error reading next record from wallet database\n"); return DBErrors::CORRUPT; } @@ -984,10 +985,10 @@ ssValue >> vWtx.back(); } } - pcursor->close(); } catch (...) { result = DBErrors::CORRUPT; } + m_batch.CloseCursor(); return result; }