Merge #19308: wallet: BerkeleyBatch Handle cursor internally

ca24edfbc1 walletdb: Handle cursor internally (Andrew Chow)

Pull request description:

  Instead of returning a Dbc (BDB cursor object) and having the caller deal with the cursor, make BerkeleyBatch handle the cursor internally.

  Split from #18971

ACKs for top commit:
  ryanofsky:
    Code review ACK ca24edfbc1. Changes since last review: StartCursor rename, moving CloseCursor calls near returns
  promag:
    Code review ACK ca24edfbc1.

Tree-SHA512: f029b498c7f275aedca53ce7ade7cb99c82975fd6cad17346a4990fb3bcc54e2a5309b32053bd13def9ee464d331b036ac79abb8fc4fa561170c6cfc85283447
This commit is contained in:
Wladimir J. van der Laan 2020-07-01 15:47:36 +02:00
commit 26291745ae
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
3 changed files with 50 additions and 35 deletions

View file

@ -335,7 +335,7 @@ void BerkeleyEnvironment::CheckpointLSN(const std::string& strFile)
} }
BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr) BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr), m_cursor(nullptr)
{ {
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
fFlushOnClose = fFlushOnCloseIn; fFlushOnClose = fFlushOnCloseIn;
@ -442,6 +442,7 @@ void BerkeleyBatch::Close()
activeTxn->abort(); activeTxn->abort();
activeTxn = nullptr; activeTxn = nullptr;
pdb = nullptr; pdb = nullptr;
CloseCursor();
if (fFlushOnClose) if (fFlushOnClose)
Flush(); Flush();
@ -528,17 +529,15 @@ bool BerkeleyBatch::Rewrite(BerkeleyDatabase& database, const char* pszSkip)
fSuccess = false; fSuccess = false;
} }
Dbc* pcursor = db.GetCursor(); if (db.StartCursor()) {
if (pcursor)
while (fSuccess) { while (fSuccess) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue); bool complete;
if (ret1 == DB_NOTFOUND) { bool ret1 = db.ReadAtCursor(ssKey, ssValue, complete);
pcursor->close(); if (complete) {
break; break;
} else if (ret1 != 0) { } else if (!ret1) {
pcursor->close();
fSuccess = false; fSuccess = false;
break; break;
} }
@ -556,6 +555,8 @@ bool BerkeleyBatch::Rewrite(BerkeleyDatabase& database, const char* pszSkip)
if (ret2 > 0) if (ret2 > 0)
fSuccess = false; fSuccess = false;
} }
db.CloseCursor();
}
if (fSuccess) { if (fSuccess) {
db.Close(); db.Close();
env->CloseDb(strFile); env->CloseDb(strFile);
@ -738,27 +739,30 @@ void BerkeleyDatabase::ReloadDbEnv()
} }
} }
Dbc* BerkeleyBatch::GetCursor() bool BerkeleyBatch::StartCursor()
{ {
assert(!m_cursor);
if (!pdb) if (!pdb)
return nullptr; return false;
Dbc* pcursor = nullptr; int ret = pdb->cursor(nullptr, &m_cursor, 0);
int ret = pdb->cursor(nullptr, &pcursor, 0); return ret == 0;
if (ret != 0)
return nullptr;
return pcursor;
} }
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 // Read at cursor
SafeDbt datKey; SafeDbt datKey;
SafeDbt datValue; 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) if (ret != 0)
return ret; return false;
else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr) else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr)
return 99999; return false;
// Convert to streams // Convert to streams
ssKey.SetType(SER_DISK); ssKey.SetType(SER_DISK);
@ -767,7 +771,14 @@ int BerkeleyBatch::ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& s
ssValue.SetType(SER_DISK); ssValue.SetType(SER_DISK);
ssValue.clear(); ssValue.clear();
ssValue.write((char*)datValue.get_data(), datValue.get_size()); 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() bool BerkeleyBatch::TxnBegin()

View file

@ -198,6 +198,7 @@ protected:
Db* pdb; Db* pdb;
std::string strFile; std::string strFile;
DbTxn* activeTxn; DbTxn* activeTxn;
Dbc* m_cursor;
bool fReadOnly; bool fReadOnly;
bool fFlushOnClose; bool fFlushOnClose;
BerkeleyEnvironment *env; BerkeleyEnvironment *env;
@ -284,8 +285,9 @@ public:
return HasKey(ssKey); return HasKey(ssKey);
} }
Dbc* GetCursor(); bool StartCursor();
int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue); bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete);
void CloseCursor();
bool TxnBegin(); bool TxnBegin();
bool TxnCommit(); bool TxnCommit();
bool TxnAbort(); bool TxnAbort();

View file

@ -700,8 +700,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
} }
// Get cursor // Get cursor
Dbc* pcursor = m_batch.GetCursor(); if (!m_batch.StartCursor())
if (!pcursor)
{ {
pwallet->WalletLogPrintf("Error getting wallet database cursor\n"); pwallet->WalletLogPrintf("Error getting wallet database cursor\n");
return DBErrors::CORRUPT; return DBErrors::CORRUPT;
@ -712,11 +711,14 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
// Read next record // Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue); bool complete;
if (ret == DB_NOTFOUND) bool ret = m_batch.ReadAtCursor(ssKey, ssValue, complete);
if (complete) {
break; break;
else if (ret != 0) }
else if (!ret)
{ {
m_batch.CloseCursor();
pwallet->WalletLogPrintf("Error reading next record from wallet database\n"); pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
return DBErrors::CORRUPT; return DBErrors::CORRUPT;
} }
@ -743,10 +745,10 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
if (!strErr.empty()) if (!strErr.empty())
pwallet->WalletLogPrintf("%s\n", strErr); pwallet->WalletLogPrintf("%s\n", strErr);
} }
pcursor->close();
} catch (...) { } catch (...) {
result = DBErrors::CORRUPT; result = DBErrors::CORRUPT;
} }
m_batch.CloseCursor();
// Set the active ScriptPubKeyMans // Set the active ScriptPubKeyMans
for (auto spk_man_pair : wss.m_active_external_spks) { for (auto spk_man_pair : wss.m_active_external_spks) {
@ -850,8 +852,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
} }
// Get cursor // Get cursor
Dbc* pcursor = m_batch.GetCursor(); if (!m_batch.StartCursor())
if (!pcursor)
{ {
LogPrintf("Error getting wallet database cursor\n"); LogPrintf("Error getting wallet database cursor\n");
return DBErrors::CORRUPT; return DBErrors::CORRUPT;
@ -862,11 +863,12 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
// Read next record // Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = m_batch.ReadAtCursor(pcursor, ssKey, ssValue); bool complete;
if (ret == DB_NOTFOUND) bool ret = m_batch.ReadAtCursor(ssKey, ssValue, complete);
if (complete) {
break; break;
else if (ret != 0) } else if (!ret) {
{ m_batch.CloseCursor();
LogPrintf("Error reading next record from wallet database\n"); LogPrintf("Error reading next record from wallet database\n");
return DBErrors::CORRUPT; return DBErrors::CORRUPT;
} }
@ -881,10 +883,10 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
ssValue >> vWtx.back(); ssValue >> vWtx.back();
} }
} }
pcursor->close();
} catch (...) { } catch (...) {
result = DBErrors::CORRUPT; result = DBErrors::CORRUPT;
} }
m_batch.CloseCursor();
return result; return result;
} }