Skip to content

Commit a924f61

Browse files
author
MarcoFalke
committed
Merge #19325: wallet: Refactor BerkeleyDatabase to introduce DatabaseBatch abstract class
b82f0ca walletdb: Add MakeBatch function to BerkeleyDatabase and use it (Andrew Chow) eac9200 walletdb: Refactor DatabaseBatch abstract class from BerkeleyBatch (Andrew Chow) Pull request description: In order to support alternative database systems, we need to have a generic `Batch` class. This PR adds a `DatabaseBatch` abstract class which is implemented by `BerkeleyBatch`. `DatabaseBatch` is now the class that is used by `WalletBatch` to interact with the database. To be able to get the correct type of `DatabaseBatch`, `BerkeleyDatabase` now has a `MakeBatch` function which returns a newly constructed `std::unique_ptr<DatabaseBatch>`. For `BerkeleyDatabase`, that will be `std::unique_ptr<BerkeleyBatch>`. The `Read`, `Write`, `Erase`, and `Exists` template functions are moved from `BerkeleyBatch`. Part of #18971 Requires #19308 and #19324 ACKs for top commit: Sjors: re-utACK b82f0ca MarcoFalke: ACK b82f0ca 🌘 meshcollider: LGTM, utACK b82f0ca Tree-SHA512: 6d2d41631c0983391dbecd702e881c6775b155c90b275df97f7157e42608ed251744f9d7ce5173d02a6c5cc38d90b611880fac7fa635d3d8c4d590681f56ac6a
2 parents b26d62c + b82f0ca commit a924f61

File tree

5 files changed

+129
-90
lines changed

5 files changed

+129
-90
lines changed

src/wallet/bdb.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,3 +841,8 @@ bool BerkeleyBatch::HasKey(CDataStream&& key)
841841
int ret = pdb->exists(activeTxn, datKey, 0);
842842
return ret == 0;
843843
}
844+
845+
std::unique_ptr<BerkeleyBatch> BerkeleyDatabase::MakeBatch(const char* mode, bool flush_on_close)
846+
{
847+
return MakeUnique<BerkeleyBatch>(*this, mode, flush_on_close);
848+
}

src/wallet/bdb.h

Lines changed: 19 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, s
9393
/** Return whether a BDB wallet database is currently loaded. */
9494
bool IsBDBWalletLoaded(const fs::path& wallet_path);
9595

96+
class BerkeleyBatch;
97+
9698
/** An instance of this class represents one database.
9799
* For BerkeleyDB this is just a (env, strFile) tuple.
98100
**/
@@ -161,6 +163,9 @@ class BerkeleyDatabase
161163
/** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */
162164
std::unique_ptr<Db> m_db;
163165

166+
/** Make a BerkeleyBatch connected to this database */
167+
std::unique_ptr<BerkeleyBatch> MakeBatch(const char* mode, bool flush_on_close);
168+
164169
private:
165170
std::string strFile;
166171

@@ -172,7 +177,7 @@ class BerkeleyDatabase
172177
};
173178

174179
/** RAII class that provides access to a Berkeley database */
175-
class BerkeleyBatch
180+
class BerkeleyBatch : public DatabaseBatch
176181
{
177182
/** RAII class that automatically cleanses its data on destruction */
178183
class SafeDbt final
@@ -195,10 +200,10 @@ class BerkeleyBatch
195200
};
196201

197202
private:
198-
bool ReadKey(CDataStream&& key, CDataStream& value);
199-
bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite = true);
200-
bool EraseKey(CDataStream&& key);
201-
bool HasKey(CDataStream&& key);
203+
bool ReadKey(CDataStream&& key, CDataStream& value) override;
204+
bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite = true) override;
205+
bool EraseKey(CDataStream&& key) override;
206+
bool HasKey(CDataStream&& key) override;
202207

203208
protected:
204209
Db* pdb;
@@ -211,71 +216,20 @@ class BerkeleyBatch
211216

212217
public:
213218
explicit BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
214-
~BerkeleyBatch() { Close(); }
219+
~BerkeleyBatch() override { Close(); }
215220

216221
BerkeleyBatch(const BerkeleyBatch&) = delete;
217222
BerkeleyBatch& operator=(const BerkeleyBatch&) = delete;
218223

219-
void Flush();
220-
void Close();
221-
222-
template <typename K, typename T>
223-
bool Read(const K& key, T& value)
224-
{
225-
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
226-
ssKey.reserve(1000);
227-
ssKey << key;
228-
229-
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
230-
if (!ReadKey(std::move(ssKey), ssValue)) return false;
231-
try {
232-
ssValue >> value;
233-
return true;
234-
} catch (const std::exception&) {
235-
return false;
236-
}
237-
}
238-
239-
template <typename K, typename T>
240-
bool Write(const K& key, const T& value, bool fOverwrite = true)
241-
{
242-
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
243-
ssKey.reserve(1000);
244-
ssKey << key;
245-
246-
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
247-
ssValue.reserve(10000);
248-
ssValue << value;
249-
250-
return WriteKey(std::move(ssKey), std::move(ssValue), fOverwrite);
251-
}
252-
253-
template <typename K>
254-
bool Erase(const K& key)
255-
{
256-
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
257-
ssKey.reserve(1000);
258-
ssKey << key;
259-
260-
return EraseKey(std::move(ssKey));
261-
}
262-
263-
template <typename K>
264-
bool Exists(const K& key)
265-
{
266-
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
267-
ssKey.reserve(1000);
268-
ssKey << key;
269-
270-
return HasKey(std::move(ssKey));
271-
}
224+
void Flush() override;
225+
void Close() override;
272226

273-
bool StartCursor();
274-
bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete);
275-
void CloseCursor();
276-
bool TxnBegin();
277-
bool TxnCommit();
278-
bool TxnAbort();
227+
bool StartCursor() override;
228+
bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) override;
229+
void CloseCursor() override;
230+
bool TxnBegin() override;
231+
bool TxnCommit() override;
232+
bool TxnAbort() override;
279233
};
280234

281235
std::string BerkeleyDatabaseVersion();

src/wallet/db.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,92 @@
66
#ifndef BITCOIN_WALLET_DB_H
77
#define BITCOIN_WALLET_DB_H
88

9+
#include <clientversion.h>
910
#include <fs.h>
11+
#include <streams.h>
1012

1113
#include <string>
1214

1315
/** Given a wallet directory path or legacy file path, return path to main data file in the wallet database. */
1416
fs::path WalletDataFilePath(const fs::path& wallet_path);
1517
void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename);
1618

19+
/** RAII class that provides access to a WalletDatabase */
20+
class DatabaseBatch
21+
{
22+
private:
23+
virtual bool ReadKey(CDataStream&& key, CDataStream& value) = 0;
24+
virtual bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite=true) = 0;
25+
virtual bool EraseKey(CDataStream&& key) = 0;
26+
virtual bool HasKey(CDataStream&& key) = 0;
27+
28+
public:
29+
explicit DatabaseBatch() {}
30+
virtual ~DatabaseBatch() {}
31+
32+
DatabaseBatch(const DatabaseBatch&) = delete;
33+
DatabaseBatch& operator=(const DatabaseBatch&) = delete;
34+
35+
virtual void Flush() = 0;
36+
virtual void Close() = 0;
37+
38+
template <typename K, typename T>
39+
bool Read(const K& key, T& value)
40+
{
41+
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
42+
ssKey.reserve(1000);
43+
ssKey << key;
44+
45+
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
46+
if (!ReadKey(std::move(ssKey), ssValue)) return false;
47+
try {
48+
ssValue >> value;
49+
return true;
50+
} catch (const std::exception&) {
51+
return false;
52+
}
53+
}
54+
55+
template <typename K, typename T>
56+
bool Write(const K& key, const T& value, bool fOverwrite = true)
57+
{
58+
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
59+
ssKey.reserve(1000);
60+
ssKey << key;
61+
62+
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
63+
ssValue.reserve(10000);
64+
ssValue << value;
65+
66+
return WriteKey(std::move(ssKey), std::move(ssValue), fOverwrite);
67+
}
68+
69+
template <typename K>
70+
bool Erase(const K& key)
71+
{
72+
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
73+
ssKey.reserve(1000);
74+
ssKey << key;
75+
76+
return EraseKey(std::move(ssKey));
77+
}
78+
79+
template <typename K>
80+
bool Exists(const K& key)
81+
{
82+
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
83+
ssKey.reserve(1000);
84+
ssKey << key;
85+
86+
return HasKey(std::move(ssKey));
87+
}
88+
89+
virtual bool StartCursor() = 0;
90+
virtual bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) = 0;
91+
virtual void CloseCursor() = 0;
92+
virtual bool TxnBegin() = 0;
93+
virtual bool TxnCommit() = 0;
94+
virtual bool TxnAbort() = 0;
95+
};
96+
1797
#endif // BITCOIN_WALLET_DB_H

src/wallet/walletdb.cpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
121121
if (!WriteIC(key, std::make_pair(vchCryptedSecret, checksum), false)) {
122122
// It may already exist, so try writing just the checksum
123123
std::vector<unsigned char> val;
124-
if (!m_batch.Read(key, val)) {
124+
if (!m_batch->Read(key, val)) {
125125
return false;
126126
}
127127
if (!WriteIC(key, std::make_pair(val, checksum), true)) {
@@ -166,8 +166,8 @@ bool WalletBatch::WriteBestBlock(const CBlockLocator& locator)
166166

167167
bool WalletBatch::ReadBestBlock(CBlockLocator& locator)
168168
{
169-
if (m_batch.Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true;
170-
return m_batch.Read(DBKeys::BESTBLOCK_NOMERKLE, locator);
169+
if (m_batch->Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true;
170+
return m_batch->Read(DBKeys::BESTBLOCK_NOMERKLE, locator);
171171
}
172172

173173
bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
@@ -177,7 +177,7 @@ bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
177177

178178
bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool)
179179
{
180-
return m_batch.Read(std::make_pair(DBKeys::POOL, nPool), keypool);
180+
return m_batch->Read(std::make_pair(DBKeys::POOL, nPool), keypool);
181181
}
182182

183183
bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool)
@@ -690,14 +690,14 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
690690
LOCK(pwallet->cs_wallet);
691691
try {
692692
int nMinVersion = 0;
693-
if (m_batch.Read(DBKeys::MINVERSION, nMinVersion)) {
693+
if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
694694
if (nMinVersion > FEATURE_LATEST)
695695
return DBErrors::TOO_NEW;
696696
pwallet->LoadMinVersion(nMinVersion);
697697
}
698698

699699
// Get cursor
700-
if (!m_batch.StartCursor())
700+
if (!m_batch->StartCursor())
701701
{
702702
pwallet->WalletLogPrintf("Error getting wallet database cursor\n");
703703
return DBErrors::CORRUPT;
@@ -709,13 +709,13 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
709709
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
710710
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
711711
bool complete;
712-
bool ret = m_batch.ReadAtCursor(ssKey, ssValue, complete);
712+
bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
713713
if (complete) {
714714
break;
715715
}
716716
else if (!ret)
717717
{
718-
m_batch.CloseCursor();
718+
m_batch->CloseCursor();
719719
pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
720720
return DBErrors::CORRUPT;
721721
}
@@ -745,7 +745,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
745745
} catch (...) {
746746
result = DBErrors::CORRUPT;
747747
}
748-
m_batch.CloseCursor();
748+
m_batch->CloseCursor();
749749

750750
// Set the active ScriptPubKeyMans
751751
for (auto spk_man_pair : wss.m_active_external_spks) {
@@ -782,7 +782,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
782782

783783
// Last client version to open this wallet, was previously the file version number
784784
int last_client = CLIENT_VERSION;
785-
m_batch.Read(DBKeys::VERSION, last_client);
785+
m_batch->Read(DBKeys::VERSION, last_client);
786786

787787
int wallet_version = pwallet->GetVersion();
788788
pwallet->WalletLogPrintf("Wallet File Version = %d\n", wallet_version > 0 ? wallet_version : last_client);
@@ -807,7 +807,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
807807
return DBErrors::NEED_REWRITE;
808808

809809
if (last_client < CLIENT_VERSION) // Update
810-
m_batch.Write(DBKeys::VERSION, CLIENT_VERSION);
810+
m_batch->Write(DBKeys::VERSION, CLIENT_VERSION);
811811

812812
if (wss.fAnyUnordered)
813813
result = pwallet->ReorderTransactions();
@@ -843,13 +843,13 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
843843

844844
try {
845845
int nMinVersion = 0;
846-
if (m_batch.Read(DBKeys::MINVERSION, nMinVersion)) {
846+
if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
847847
if (nMinVersion > FEATURE_LATEST)
848848
return DBErrors::TOO_NEW;
849849
}
850850

851851
// Get cursor
852-
if (!m_batch.StartCursor())
852+
if (!m_batch->StartCursor())
853853
{
854854
LogPrintf("Error getting wallet database cursor\n");
855855
return DBErrors::CORRUPT;
@@ -861,11 +861,11 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
861861
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
862862
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
863863
bool complete;
864-
bool ret = m_batch.ReadAtCursor(ssKey, ssValue, complete);
864+
bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
865865
if (complete) {
866866
break;
867867
} else if (!ret) {
868-
m_batch.CloseCursor();
868+
m_batch->CloseCursor();
869869
LogPrintf("Error reading next record from wallet database\n");
870870
return DBErrors::CORRUPT;
871871
}
@@ -883,7 +883,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
883883
} catch (...) {
884884
result = DBErrors::CORRUPT;
885885
}
886-
m_batch.CloseCursor();
886+
m_batch->CloseCursor();
887887

888888
return result;
889889
}
@@ -993,17 +993,17 @@ bool WalletBatch::WriteWalletFlags(const uint64_t flags)
993993

994994
bool WalletBatch::TxnBegin()
995995
{
996-
return m_batch.TxnBegin();
996+
return m_batch->TxnBegin();
997997
}
998998

999999
bool WalletBatch::TxnCommit()
10001000
{
1001-
return m_batch.TxnCommit();
1001+
return m_batch->TxnCommit();
10021002
}
10031003

10041004
bool WalletBatch::TxnAbort()
10051005
{
1006-
return m_batch.TxnAbort();
1006+
return m_batch->TxnAbort();
10071007
}
10081008

10091009
bool IsWalletLoaded(const fs::path& wallet_path)

0 commit comments

Comments
 (0)