db: Change DatabaseCursor::Next to return status enum

Next()'s result is a tri-state - failed, more to go, complete. Replace
the way that this is returned with an enum with values FAIL, MORE, and
DONE rather than with two booleans.
This commit is contained in:
Andrew Chow 2022-11-29 22:34:26 -05:00
parent d79e8dcf29
commit 4aebd832a4
11 changed files with 49 additions and 55 deletions

View File

@ -481,11 +481,10 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip)
while (fSuccess) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
bool complete;
bool ret1 = cursor->Next(ssKey, ssValue, complete);
if (complete) {
DatabaseCursor::Status ret1 = cursor->Next(ssKey, ssValue);
if (ret1 == DatabaseCursor::Status::DONE) {
break;
} else if (!ret1) {
} else if (ret1 == DatabaseCursor::Status::FAIL) {
fSuccess = false;
break;
}
@ -668,21 +667,19 @@ BerkeleyCursor::BerkeleyCursor(BerkeleyDatabase& database)
}
}
bool BerkeleyCursor::Next(CDataStream& ssKey, CDataStream& ssValue, bool& complete)
DatabaseCursor::Status BerkeleyCursor::Next(CDataStream& ssKey, CDataStream& ssValue)
{
complete = false;
if (m_cursor == nullptr) return false;
if (m_cursor == nullptr) return Status::FAIL;
// Read at cursor
SafeDbt datKey;
SafeDbt datValue;
int ret = m_cursor->get(datKey, datValue, DB_NEXT);
if (ret == DB_NOTFOUND) {
complete = true;
return Status::DONE;
}
if (ret != 0 || datKey.get_data() == nullptr || datValue.get_data() == nullptr) {
return Status::FAIL;
}
if (ret != 0)
return false;
else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr)
return false;
// Convert to streams
ssKey.SetType(SER_DISK);
@ -691,7 +688,7 @@ bool BerkeleyCursor::Next(CDataStream& ssKey, CDataStream& ssValue, bool& comple
ssValue.SetType(SER_DISK);
ssValue.clear();
ssValue.write({AsBytePtr(datValue.get_data()), datValue.get_size()});
return true;
return Status::MORE;
}
BerkeleyCursor::~BerkeleyCursor()

View File

@ -194,7 +194,7 @@ public:
explicit BerkeleyCursor(BerkeleyDatabase& database);
~BerkeleyCursor() override;
bool Next(CDataStream& key, CDataStream& value, bool& complete) override;
Status Next(CDataStream& key, CDataStream& value) override;
};
/** RAII class that provides access to a Berkeley database */

View File

@ -31,7 +31,14 @@ public:
DatabaseCursor(const DatabaseCursor&) = delete;
DatabaseCursor& operator=(const DatabaseCursor&) = delete;
virtual bool Next(CDataStream& key, CDataStream& value, bool& complete) { return false; }
enum class Status
{
FAIL,
MORE,
DONE,
};
virtual Status Next(CDataStream& key, CDataStream& value) { return Status::FAIL; }
};
/** RAII class that provides access to a WalletDatabase */
@ -168,7 +175,7 @@ public:
class DummyCursor : public DatabaseCursor
{
bool Next(CDataStream& key, CDataStream& value, bool& complete) override { return false; }
Status Next(CDataStream& key, CDataStream& value) override { return Status::FAIL; }
};
/** RAII class that provides access to a DummyDatabase. Never fails. */

View File

@ -69,13 +69,13 @@ bool DumpWallet(const ArgsManager& args, CWallet& wallet, bilingual_str& error)
while (true) {
CDataStream ss_key(SER_DISK, CLIENT_VERSION);
CDataStream ss_value(SER_DISK, CLIENT_VERSION);
bool complete;
ret = cursor->Next(ss_key, ss_value, complete);
if (complete) {
DatabaseCursor::Status status = cursor->Next(ss_key, ss_value);
if (status == DatabaseCursor::Status::DONE) {
ret = true;
break;
} else if (!ret) {
} else if (status == DatabaseCursor::Status::FAIL) {
error = _("Error reading next record from wallet database");
ret = false;
break;
}
std::string key_str = HexStr(ss_key);

View File

@ -470,18 +470,15 @@ bool SQLiteBatch::HasKey(CDataStream&& key)
return res == SQLITE_ROW;
}
bool SQLiteCursor::Next(CDataStream& key, CDataStream& value, bool& complete)
DatabaseCursor::Status SQLiteCursor::Next(CDataStream& key, CDataStream& value)
{
complete = false;
int res = sqlite3_step(m_cursor_stmt);
if (res == SQLITE_DONE) {
complete = true;
return true;
return Status::DONE;
}
if (res != SQLITE_ROW) {
LogPrintf("%s: Unable to execute cursor step: %s\n", __func__, sqlite3_errstr(res));
return false;
return Status::FAIL;
}
// Leftmost column in result is index 0
@ -491,7 +488,7 @@ bool SQLiteCursor::Next(CDataStream& key, CDataStream& value, bool& complete)
const std::byte* value_data{AsBytePtr(sqlite3_column_blob(m_cursor_stmt, 1))};
size_t value_data_size(sqlite3_column_bytes(m_cursor_stmt, 1));
value.write({value_data, value_data_size});
return true;
return Status::MORE;
}
SQLiteCursor::~SQLiteCursor()

View File

@ -22,7 +22,7 @@ public:
explicit SQLiteCursor() {}
~SQLiteCursor() override;
bool Next(CDataStream& key, CDataStream& value, bool& complete) override;
Status Next(CDataStream& key, CDataStream& value) override;
};
/** RAII class that provides access to a WalletDatabase */

View File

@ -59,9 +59,9 @@ std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database,
while (true) {
CDataStream key(SER_DISK, CLIENT_VERSION);
CDataStream value(SER_DISK, CLIENT_VERSION);
bool complete;
cursor->Next(key, value, complete);
if (complete) break;
DatabaseCursor::Status status = cursor->Next(key, value);
assert(status != DatabaseCursor::Status::FAIL);
if (status == DatabaseCursor::Status::DONE) break;
new_batch->Write(key, value);
}

View File

@ -870,7 +870,7 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup)
class FailCursor : public DatabaseCursor
{
public:
bool Next(CDataStream& key, CDataStream& value, bool& complete) override { return false; }
Status Next(CDataStream& key, CDataStream& value) override { return Status::FAIL; }
};
/** RAII class that provides access to a FailDatabase. Which fails if needed. */

View File

@ -60,9 +60,9 @@ bool HasAnyRecordOfType(WalletDatabase& db, const std::string& key)
while (true) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
bool complete;
BOOST_CHECK(cursor->Next(ssKey, ssValue, complete));
if (complete) break;
DatabaseCursor::Status status = cursor->Next(ssKey, ssValue);
assert(status != DatabaseCursor::Status::FAIL);
if (status == DatabaseCursor::Status::DONE) break;
std::string type;
ssKey >> type;
if (type == key) return true;

View File

@ -3776,12 +3776,12 @@ bool CWallet::MigrateToSQLite(bilingual_str& error)
error = _("Error: Unable to begin reading all records in the database");
return false;
}
bool complete = false;
DatabaseCursor::Status status = DatabaseCursor::Status::FAIL;
while (true) {
CDataStream ss_key(SER_DISK, CLIENT_VERSION);
CDataStream ss_value(SER_DISK, CLIENT_VERSION);
bool ret = cursor->Next(ss_key, ss_value, complete);
if (complete || !ret) {
status = cursor->Next(ss_key, ss_value);
if (status != DatabaseCursor::Status::MORE) {
break;
}
SerializeData key(ss_key.begin(), ss_key.end());
@ -3790,7 +3790,7 @@ bool CWallet::MigrateToSQLite(bilingual_str& error)
}
cursor.reset();
batch.reset();
if (!complete) {
if (status != DatabaseCursor::Status::DONE) {
error = _("Error: Unable to read all records in the database");
return false;
}

View File

@ -824,13 +824,10 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
bool complete;
bool ret = cursor->Next(ssKey, ssValue, complete);
if (complete) {
DatabaseCursor::Status status = cursor->Next(ssKey, ssValue);
if (status == DatabaseCursor::Status::DONE) {
break;
}
else if (!ret)
{
} else if (status == DatabaseCursor::Status::FAIL) {
cursor.reset();
pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
return DBErrors::CORRUPT;
@ -998,11 +995,10 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
bool complete;
bool ret = cursor->Next(ssKey, ssValue, complete);
if (complete) {
DatabaseCursor::Status status = cursor->Next(ssKey, ssValue);
if (status == DatabaseCursor::Status::DONE) {
break;
} else if (!ret) {
} else if (status == DatabaseCursor::Status::FAIL) {
LogPrintf("Error reading next record from wallet database\n");
return DBErrors::CORRUPT;
}
@ -1125,13 +1121,10 @@ bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
// Read next record
CDataStream key(SER_DISK, CLIENT_VERSION);
CDataStream value(SER_DISK, CLIENT_VERSION);
bool complete;
bool ret = cursor->Next(key, value, complete);
if (complete) {
DatabaseCursor::Status status = cursor->Next(key, value);
if (status == DatabaseCursor::Status::DONE) {
break;
}
else if (!ret)
{
} else if (status == DatabaseCursor::Status::FAIL) {
return false;
}