Skip to content

Commit 98e9d8e

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#23732: refactor: Remove gArgs from bdb.h and sqlite.h
39b1763 Replace use of `ArgsManager` with `DatabaseOptions` (Kiminuo) Pull request description: Contributes to #21005. The goal of this PR is to remove `gArgs` from database classes (i.e. `bdb.h` and `sqlite.h`) so that they can be tested without relying on `gArgs` in tests. Notes: * My goal is to enable unit-testing without relying on `gArgs` as much as possible. Global variables are hard to reason about which in turn makes it slightly harder to contribute to this codebase. When the compiler does the heavy lifting for us and allows us only to construct an object (or call a method) with valid parameters, we may also save some time in code reviews. The cost for this is passing an argument which is not for free but the cost is very miniscule compared to benefits, I think. * GUI code is an exception because it seems fine to have `gArgs` there so I don't plan to make changes in `src/qt` folder, for example. * My approach to removal of `gArgs` uses is moving from lower levels to upper ones and pass `ArgsManager` as an argument as needed. The approach is very similar to what #20158. ACKs for top commit: achow101: ACK 39b1763 ryanofsky: Code review ACK 39b1763. Just the two small ReadDatabaseArgs and Berkeley open changes that were discussed since the last review Tree-SHA512: aa066b314db593e46c18698fe8cdd500f558b405dc04e4a9a3ff57b52b5b3a81a6cb090e0e661785d1d02c1bf18958c1f4cd715ff233aab63381e3f80960622d
2 parents cea230e + 39b1763 commit 98e9d8e

21 files changed

+93
-60
lines changed

src/wallet/bdb.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
6060
* erases the weak pointer from the g_dbenvs map.
6161
* @post A new BerkeleyEnvironment weak pointer is inserted into g_dbenvs if the directory path key was not already in the map.
6262
*/
63-
std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory)
63+
std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory, bool use_shared_memory)
6464
{
6565
LOCK(cs_db);
6666
auto inserted = g_dbenvs.emplace(fs::PathToString(env_directory), std::weak_ptr<BerkeleyEnvironment>());
6767
if (inserted.second) {
68-
auto env = std::make_shared<BerkeleyEnvironment>(env_directory);
68+
auto env = std::make_shared<BerkeleyEnvironment>(env_directory, use_shared_memory);
6969
inserted.first->second = env;
7070
return env;
7171
}
@@ -113,7 +113,7 @@ void BerkeleyEnvironment::Reset()
113113
fMockDb = false;
114114
}
115115

116-
BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(fs::PathToString(dir_path))
116+
BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path, bool use_shared_memory) : strPath(fs::PathToString(dir_path)), m_use_shared_memory(use_shared_memory)
117117
{
118118
Reset();
119119
}
@@ -145,8 +145,9 @@ bool BerkeleyEnvironment::Open(bilingual_str& err)
145145
LogPrintf("BerkeleyEnvironment::Open: LogDir=%s ErrorFile=%s\n", fs::PathToString(pathLogDir), fs::PathToString(pathErrorFile));
146146

147147
unsigned int nEnvFlags = 0;
148-
if (gArgs.GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB))
148+
if (!m_use_shared_memory) {
149149
nEnvFlags |= DB_PRIVATE;
150+
}
150151

151152
dbenv->set_lg_dir(fs::PathToString(pathLogDir).c_str());
152153
dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet
@@ -188,7 +189,7 @@ bool BerkeleyEnvironment::Open(bilingual_str& err)
188189
}
189190

190191
//! Construct an in-memory mock Berkeley environment for testing
191-
BerkeleyEnvironment::BerkeleyEnvironment()
192+
BerkeleyEnvironment::BerkeleyEnvironment() : m_use_shared_memory(false)
192193
{
193194
Reset();
194195

@@ -377,7 +378,7 @@ void BerkeleyBatch::Flush()
377378
nMinutes = 1;
378379

379380
if (env) { // env is nullptr for dummy databases (i.e. in tests). Don't actually flush if env is nullptr so we don't segfault
380-
env->dbenv->txn_checkpoint(nMinutes ? gArgs.GetIntArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
381+
env->dbenv->txn_checkpoint(nMinutes ? m_database.m_max_log_mb * 1024 : 0, nMinutes, 0);
381382
}
382383
}
383384

@@ -831,13 +832,13 @@ std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, con
831832
{
832833
LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
833834
std::string data_filename = fs::PathToString(data_file.filename());
834-
std::shared_ptr<BerkeleyEnvironment> env = GetBerkeleyEnv(data_file.parent_path());
835+
std::shared_ptr<BerkeleyEnvironment> env = GetBerkeleyEnv(data_file.parent_path(), options.use_shared_memory);
835836
if (env->m_databases.count(data_filename)) {
836837
error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", fs::PathToString(env->Directory() / data_filename)));
837838
status = DatabaseStatus::FAILED_ALREADY_LOADED;
838839
return nullptr;
839840
}
840-
db = std::make_unique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
841+
db = std::make_unique<BerkeleyDatabase>(std::move(env), std::move(data_filename), options);
841842
}
842843

843844
if (options.verify && !db->Verify(error)) {

src/wallet/bdb.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
struct bilingual_str;
3333

3434
namespace wallet {
35-
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
36-
static const bool DEFAULT_WALLET_PRIVDB = true;
3735

3836
struct WalletDatabaseFileId {
3937
u_int8_t value[DB_FILE_ID_LEN];
@@ -56,8 +54,9 @@ class BerkeleyEnvironment
5654
std::map<std::string, std::reference_wrapper<BerkeleyDatabase>> m_databases;
5755
std::unordered_map<std::string, WalletDatabaseFileId> m_fileids;
5856
std::condition_variable_any m_db_in_use;
57+
bool m_use_shared_memory;
5958

60-
explicit BerkeleyEnvironment(const fs::path& env_directory);
59+
explicit BerkeleyEnvironment(const fs::path& env_directory, bool use_shared_memory);
6160
BerkeleyEnvironment();
6261
~BerkeleyEnvironment();
6362
void Reset();
@@ -85,7 +84,7 @@ class BerkeleyEnvironment
8584
};
8685

8786
/** Get BerkeleyEnvironment given a directory path. */
88-
std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory);
87+
std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory, bool use_shared_memory);
8988

9089
class BerkeleyBatch;
9190

@@ -98,8 +97,8 @@ class BerkeleyDatabase : public WalletDatabase
9897
BerkeleyDatabase() = delete;
9998

10099
/** Create DB handle to real database */
101-
BerkeleyDatabase(std::shared_ptr<BerkeleyEnvironment> env, std::string filename) :
102-
WalletDatabase(), env(std::move(env)), strFile(std::move(filename))
100+
BerkeleyDatabase(std::shared_ptr<BerkeleyEnvironment> env, std::string filename, const DatabaseOptions& options) :
101+
WalletDatabase(), env(std::move(env)), strFile(std::move(filename)), m_max_log_mb(options.max_log_mb)
103102
{
104103
auto inserted = this->env->m_databases.emplace(strFile, std::ref(*this));
105104
assert(inserted.second);
@@ -160,6 +159,7 @@ class BerkeleyDatabase : public WalletDatabase
160159
std::unique_ptr<Db> m_db;
161160

162161
std::string strFile;
162+
int64_t m_max_log_mb;
163163

164164
/** Make a BerkeleyBatch connected to this database */
165165
std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override;

src/wallet/db.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <chainparams.h>
77
#include <fs.h>
88
#include <logging.h>
9+
#include <util/system.h>
910
#include <wallet/db.h>
1011

1112
#include <exception>
@@ -137,4 +138,13 @@ bool IsSQLiteFile(const fs::path& path)
137138
// Check the application id matches our network magic
138139
return memcmp(Params().MessageStart(), app_id, 4) == 0;
139140
}
141+
142+
void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options)
143+
{
144+
// Override current options with args values, if any were specified
145+
options.use_unsafe_sync = args.GetBoolArg("-unsafesqlitesync", options.use_unsafe_sync);
146+
options.use_shared_memory = !args.GetBoolArg("-privdb", !options.use_shared_memory);
147+
options.max_log_mb = args.GetIntArg("-dblogsize", options.max_log_mb);
148+
}
149+
140150
} // namespace wallet

src/wallet/db.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <optional>
1717
#include <string>
1818

19+
class ArgsManager;
1920
struct bilingual_str;
2021

2122
namespace wallet {
@@ -207,7 +208,12 @@ struct DatabaseOptions {
207208
std::optional<DatabaseFormat> require_format;
208209
uint64_t create_flags = 0;
209210
SecureString create_passphrase;
210-
bool verify = true;
211+
212+
// Specialized options. Not every option is supported by every backend.
213+
bool verify = true; //!< Check data integrity on load.
214+
bool use_unsafe_sync = false; //!< Disable file sync for faster performance.
215+
bool use_shared_memory = false; //!< Let other processes access the database.
216+
int64_t max_log_mb = 100; //!< Max log size to allow before consolidating.
211217
};
212218

213219
enum class DatabaseStatus {
@@ -227,6 +233,7 @@ enum class DatabaseStatus {
227233
/** Recursively list database paths in directory. */
228234
std::vector<fs::path> ListDatabases(const fs::path& path);
229235

236+
void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options);
230237
std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
231238

232239
fs::path BDBDataFile(const fs::path& path);

src/wallet/dump.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ namespace wallet {
1919
static const std::string DUMP_MAGIC = "BITCOIN_CORE_WALLET_DUMP";
2020
uint32_t DUMP_VERSION = 1;
2121

22-
bool DumpWallet(CWallet& wallet, bilingual_str& error)
22+
bool DumpWallet(const ArgsManager& args, CWallet& wallet, bilingual_str& error)
2323
{
2424
// Get the dumpfile
25-
std::string dump_filename = gArgs.GetArg("-dumpfile", "");
25+
std::string dump_filename = args.GetArg("-dumpfile", "");
2626
if (dump_filename.empty()) {
2727
error = _("No dump file provided. To use dump, -dumpfile=<filename> must be provided.");
2828
return false;
@@ -114,10 +114,10 @@ static void WalletToolReleaseWallet(CWallet* wallet)
114114
delete wallet;
115115
}
116116

117-
bool CreateFromDump(const std::string& name, const fs::path& wallet_path, bilingual_str& error, std::vector<bilingual_str>& warnings)
117+
bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::path& wallet_path, bilingual_str& error, std::vector<bilingual_str>& warnings)
118118
{
119119
// Get the dumpfile
120-
std::string dump_filename = gArgs.GetArg("-dumpfile", "");
120+
std::string dump_filename = args.GetArg("-dumpfile", "");
121121
if (dump_filename.empty()) {
122122
error = _("No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.");
123123
return false;
@@ -171,7 +171,7 @@ bool CreateFromDump(const std::string& name, const fs::path& wallet_path, biling
171171
return false;
172172
}
173173
// Get the data file format with format_value as the default
174-
std::string file_format = gArgs.GetArg("-format", format_value);
174+
std::string file_format = args.GetArg("-format", format_value);
175175
if (file_format.empty()) {
176176
error = _("No wallet file format provided. To use createfromdump, -format=<format> must be provided.");
177177
return false;
@@ -193,6 +193,7 @@ bool CreateFromDump(const std::string& name, const fs::path& wallet_path, biling
193193

194194
DatabaseOptions options;
195195
DatabaseStatus status;
196+
ReadDatabaseArgs(args, options);
196197
options.require_create = true;
197198
options.require_format = data_format;
198199
std::unique_ptr<WalletDatabase> database = MakeDatabase(wallet_path, options, status, error);

src/wallet/dump.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
#include <vector>
1212

1313
struct bilingual_str;
14+
class ArgsManager;
1415

1516
namespace wallet {
1617
class CWallet;
17-
bool DumpWallet(CWallet& wallet, bilingual_str& error);
18-
bool CreateFromDump(const std::string& name, const fs::path& wallet_path, bilingual_str& error, std::vector<bilingual_str>& warnings);
18+
bool DumpWallet(const ArgsManager& args, CWallet& wallet, bilingual_str& error);
19+
bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::path& wallet_path, bilingual_str& error, std::vector<bilingual_str>& warnings);
1920
} // namespace wallet
2021

2122
#endif // BITCOIN_WALLET_DUMP_H

src/wallet/init.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
8080
argsman.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
8181

8282
#ifdef USE_BDB
83-
argsman.AddArg("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
83+
argsman.AddArg("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DatabaseOptions().max_log_mb), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
8484
argsman.AddArg("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
85-
argsman.AddArg("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
85+
argsman.AddArg("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", !DatabaseOptions().use_shared_memory), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
8686
#else
8787
argsman.AddHiddenArgs({"-dblogsize", "-flushwallet", "-privdb"});
8888
#endif

src/wallet/interfaces.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ class WalletLoaderImpl : public WalletLoader
544544
std::shared_ptr<CWallet> wallet;
545545
DatabaseOptions options;
546546
DatabaseStatus status;
547+
ReadDatabaseArgs(*m_context.args, options);
547548
options.require_create = true;
548549
options.create_flags = wallet_creation_flags;
549550
options.create_passphrase = passphrase;
@@ -553,6 +554,7 @@ class WalletLoaderImpl : public WalletLoader
553554
{
554555
DatabaseOptions options;
555556
DatabaseStatus status;
557+
ReadDatabaseArgs(*m_context.args, options);
556558
options.require_existing = true;
557559
return MakeWallet(m_context, LoadWallet(m_context, name, true /* load_on_start */, options, status, error, warnings));
558560
}

src/wallet/load.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ bool VerifyWallets(WalletContext& context)
5757
if (!args.IsArgSet("wallet")) {
5858
DatabaseOptions options;
5959
DatabaseStatus status;
60+
ReadDatabaseArgs(args, options);
6061
bilingual_str error_string;
6162
options.require_existing = true;
6263
options.verify = false;
@@ -84,6 +85,7 @@ bool VerifyWallets(WalletContext& context)
8485

8586
DatabaseOptions options;
8687
DatabaseStatus status;
88+
ReadDatabaseArgs(args, options);
8789
options.require_existing = true;
8890
options.verify = true;
8991
bilingual_str error_string;
@@ -112,6 +114,7 @@ bool LoadWallets(WalletContext& context)
112114
}
113115
DatabaseOptions options;
114116
DatabaseStatus status;
117+
ReadDatabaseArgs(*context.args, options);
115118
options.require_existing = true;
116119
options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets()
117120
bilingual_str error;

src/wallet/rpc/wallet.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <rpc/server.h>
99
#include <rpc/util.h>
1010
#include <util/translation.h>
11+
#include <wallet/context.h>
1112
#include <wallet/receive.h>
1213
#include <wallet/rpc/wallet.h>
1314
#include <wallet/rpc/util.h>
@@ -220,6 +221,7 @@ static RPCHelpMan loadwallet()
220221

221222
DatabaseOptions options;
222223
DatabaseStatus status;
224+
ReadDatabaseArgs(*context.args, options);
223225
options.require_existing = true;
224226
bilingual_str error;
225227
std::vector<bilingual_str> warnings;
@@ -381,6 +383,7 @@ static RPCHelpMan createwallet()
381383

382384
DatabaseOptions options;
383385
DatabaseStatus status;
386+
ReadDatabaseArgs(*context.args, options);
384387
options.require_create = true;
385388
options.create_flags = flags;
386389
options.create_passphrase = passphrase;

0 commit comments

Comments
 (0)