wallet: Add DatabaseBatch::ErasePrefix method

This new function is not used yet this commit, but next commit adds usages and
test coverage for both BDB and sqlite.
This commit is contained in:
Ryan Ofsky
2020-04-12 13:40:43 -04:00
parent cae0608ad4
commit 5938ad0bdb
6 changed files with 51 additions and 9 deletions

View File

@@ -665,12 +665,14 @@ void BerkeleyDatabase::ReloadDbEnv()
env->ReloadDbEnv();
}
BerkeleyCursor::BerkeleyCursor(BerkeleyDatabase& database)
BerkeleyCursor::BerkeleyCursor(BerkeleyDatabase& database, BerkeleyBatch* batch)
{
if (!database.m_db.get()) {
throw std::runtime_error(STR_INTERNAL_BUG("BerkeleyDatabase does not exist"));
}
int ret = database.m_db->cursor(nullptr, &m_cursor, 0);
// Transaction argument to cursor is only needed when using the cursor to
// write to the database. Read-only cursors do not need a txn pointer.
int ret = database.m_db->cursor(batch ? batch->txn() : nullptr, &m_cursor, 0);
if (ret != 0) {
throw std::runtime_error(STR_INTERNAL_BUG(strprintf("BDB Cursor could not be created. Returned %d", ret)));
}
@@ -817,6 +819,25 @@ bool BerkeleyBatch::HasKey(DataStream&& key)
return ret == 0;
}
bool BerkeleyBatch::ErasePrefix(Span<const std::byte> prefix)
{
if (!TxnBegin()) return false;
auto cursor{std::make_unique<BerkeleyCursor>(m_database, this)};
// const_cast is safe below even though prefix_key is an in/out parameter,
// because we are not using the DB_DBT_USERMEM flag, so BDB will allocate
// and return a different output data pointer
Dbt prefix_key{const_cast<std::byte*>(prefix.data()), static_cast<uint32_t>(prefix.size())}, prefix_value{};
int ret{cursor->dbc()->get(&prefix_key, &prefix_value, DB_SET_RANGE)};
for (int flag{DB_CURRENT}; ret == 0; flag = DB_NEXT) {
SafeDbt key, value;
ret = cursor->dbc()->get(key, value, flag);
if (ret != 0 || key.get_size() < prefix.size() || memcmp(key.get_data(), prefix.data(), prefix.size()) != 0) break;
ret = cursor->dbc()->del(0);
}
cursor.reset();
return TxnCommit() && (ret == 0 || ret == DB_NOTFOUND);
}
void BerkeleyDatabase::AddRef()
{
LOCK(cs_db);