Skip to content

Commit

Permalink
wallet: sqlite migration, write multi
Browse files Browse the repository at this point in the history
  • Loading branch information
furszy committed Feb 14, 2024
1 parent 3346b0c commit 506b738
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/wallet/bdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class BerkeleyBatch : public DatabaseBatch
bool TxnCommit() override;
bool TxnAbort() override;
DbTxn* txn() const { return activeTxn; }
bool WriteMulti(const std::vector<std::pair<SerializeData, SerializeData>>& records) override { return false; }
};

std::string BerkeleyDatabaseVersion();
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class DatabaseBatch
virtual bool TxnBegin() = 0;
virtual bool TxnCommit() = 0;
virtual bool TxnAbort() = 0;

virtual bool WriteMulti(const std::vector<std::pair<SerializeData, SerializeData>>& records) = 0;
};

/** An instance of this class represents one database.
Expand Down
1 change: 1 addition & 0 deletions src/wallet/salvage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class DummyBatch : public DatabaseBatch
bool TxnBegin() override { return true; }
bool TxnCommit() override { return true; }
bool TxnAbort() override { return true; }
bool WriteMulti(const std::vector<std::pair<SerializeData, SerializeData>>& records) override { return false; }
};

/** A dummy WalletDatabase that does nothing and never fails. Only used by salvage.
Expand Down
43 changes: 43 additions & 0 deletions src/wallet/sqlite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,49 @@ std::unique_ptr<DatabaseCursor> SQLiteBatch::GetNewPrefixCursor(Span<const std::
return cursor;
}

bool SQLiteBatch::WriteMulti(const std::vector<std::pair<SerializeData, SerializeData>>& records)
{
LogPrintf("###### WriteMulti, records size %d #######\n", records.size());
// Prepare statement
std::string multi_line_insert = "INSERT INTO main VALUES(?, ?)";
for (size_t i=1; i<records.size(); i++) multi_line_insert += ", (?, ?)";
multi_line_insert += ";";

sqlite3_stmt* stmt{nullptr};
int res = sqlite3_prepare_v2(m_database.m_db, multi_line_insert.c_str(), -1, &stmt, nullptr);
if (res != SQLITE_OK) {
LogPrintf("Failed to prepare multi insert statement\n");
return false;
}

// Bind data
int pos = 0;
for (size_t i = 0; i < records.size(); i++) {
const auto& [key, value] = records.at(i);
assert(BindBlobToStatement(stmt, ++pos, key, "key"));
assert(BindBlobToStatement(stmt, ++pos, value, "value"));
}

// Execute
res = sqlite3_step(stmt);
sqlite3_clear_bindings(stmt);
sqlite3_reset(stmt);
if (res != SQLITE_DONE) {
LogPrintf("Failed to insert multi insert statement, res: %s, code %d\n", sqlite3_errstr(res), res);
return false;
}

// Clear
res = sqlite3_finalize(stmt);
if (res != SQLITE_OK) {
LogPrintf("Failed to finalize multi insert statement\n");
return false;
}
stmt = nullptr;

return true;
}

bool SQLiteBatch::TxnBegin()
{
if (!m_database.m_db || m_txn) return false;
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/sqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ class SQLiteBatch : public DatabaseBatch
bool TxnBegin() override;
bool TxnCommit() override;
bool TxnAbort() override;

bool WriteMulti(const std::vector<std::pair<SerializeData, SerializeData>>& records) override;
};

/** An instance of this class represents one SQLite3 database.
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/test/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ class MockableBatch : public DatabaseBatch
bool TxnBegin() override { return m_pass; }
bool TxnCommit() override { return m_pass; }
bool TxnAbort() override { return m_pass; }
bool WriteMulti(const std::vector<std::pair<SerializeData, SerializeData>>& records) override { return false; }

};

/** A WalletDatabase whose contents and return values can be modified as needed for testing
Expand Down
12 changes: 5 additions & 7 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3907,13 +3907,11 @@ bool CWallet::MigrateToSQLite(bilingual_str& error)
batch = m_database->MakeBatch();
bool began = batch->TxnBegin();
assert(began); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
for (const auto& [key, value] : records) {
if (!batch->Write(Span{key}, Span{value})) {
batch->TxnAbort();
m_database->Close();
fs::remove(m_database->Filename());
assert(false); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
}
if (!batch->WriteMulti(records)) {
batch->TxnAbort();
m_database->Close();
fs::remove(m_database->Filename());
assert(false); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
}
bool committed = batch->TxnCommit();
assert(committed); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
Expand Down

0 comments on commit 506b738

Please sign in to comment.