Skip to content

Commit e7b16f9

Browse files
committed
Implement MigrateToSQLite
1 parent 5b62f09 commit e7b16f9

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

src/wallet/wallet.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3654,4 +3654,76 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
36543654

36553655
return spk_man;
36563656
}
3657+
3658+
bool CWallet::MigrateToSQLite(bilingual_str& error)
3659+
{
3660+
AssertLockHeld(cs_wallet);
3661+
3662+
WalletLogPrintf("Migrating wallet storage database from BerkeleyDB to SQLite.\n");
3663+
3664+
if (m_database->Format() == "sqlite") {
3665+
error = _("Error: This wallet already uses SQLite");
3666+
return false;
3667+
}
3668+
3669+
// Get all of the records for DB type migration
3670+
std::unique_ptr<DatabaseBatch> batch = m_database->MakeBatch();
3671+
std::vector<std::pair<SerializeData, SerializeData>> records;
3672+
if (!batch->StartCursor()) {
3673+
error = _("Error: Unable to begin reading all records in the database");
3674+
return false;
3675+
}
3676+
bool complete = false;
3677+
while (true) {
3678+
CDataStream ss_key(SER_DISK, CLIENT_VERSION);
3679+
CDataStream ss_value(SER_DISK, CLIENT_VERSION);
3680+
bool ret = batch->ReadAtCursor(ss_key, ss_value, complete);
3681+
if (!ret) {
3682+
break;
3683+
}
3684+
SerializeData key(ss_key.begin(), ss_key.end());
3685+
SerializeData value(ss_value.begin(), ss_value.end());
3686+
records.emplace_back(key, value);
3687+
}
3688+
batch->CloseCursor();
3689+
batch.reset();
3690+
if (!complete) {
3691+
error = _("Error: Unable to read all records in the database");
3692+
return false;
3693+
}
3694+
3695+
// Close this database and delete the file
3696+
fs::path db_path = fs::PathFromString(m_database->Filename());
3697+
fs::path db_dir = db_path.parent_path();
3698+
m_database->Close();
3699+
fs::remove(db_path);
3700+
3701+
// Make new DB
3702+
DatabaseOptions opts;
3703+
opts.require_create = true;
3704+
opts.require_format = DatabaseFormat::SQLITE;
3705+
DatabaseStatus db_status;
3706+
std::unique_ptr<WalletDatabase> new_db = MakeDatabase(db_dir, opts, db_status, error);
3707+
assert(new_db); // This is to prevent doing anything further with this wallet. The original file was deleted, but a backup exists.
3708+
m_database.reset();
3709+
m_database = std::move(new_db);
3710+
3711+
// Write existing records into the new DB
3712+
batch = m_database->MakeBatch();
3713+
bool began = batch->TxnBegin();
3714+
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.
3715+
for (const auto& [key, value] : records) {
3716+
CDataStream ss_key(key, SER_DISK, CLIENT_VERSION);
3717+
CDataStream ss_value(value, SER_DISK, CLIENT_VERSION);
3718+
if (!batch->Write(ss_key, ss_value)) {
3719+
batch->TxnAbort();
3720+
m_database->Close();
3721+
fs::remove(m_database->Filename());
3722+
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.
3723+
}
3724+
}
3725+
bool committed = batch->TxnCommit();
3726+
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.
3727+
return true;
3728+
}
36573729
} // namespace wallet

src/wallet/wallet.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
316316
std::string m_name;
317317

318318
/** Internal database handle. */
319-
std::unique_ptr<WalletDatabase> const m_database;
319+
std::unique_ptr<WalletDatabase> m_database;
320320

321321
/**
322322
* The following is used to keep track of how far behind the wallet is
@@ -920,6 +920,13 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
920920

921921
//! Add a descriptor to the wallet, return a ScriptPubKeyMan & associated output type
922922
ScriptPubKeyMan* AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
923+
924+
/** Move all records from the BDB database to a new SQLite database for storage.
925+
* The original BDB file will be deleted and replaced with a new SQLite file.
926+
* A backup is not created.
927+
* May crash if something unexpected happens in the filesystem.
928+
*/
929+
bool MigrateToSQLite(bilingual_str& error) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
923930
};
924931

925932
/**

0 commit comments

Comments
 (0)