mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-09-27 17:47:43 +02:00
refactor: Consolidate redundant wallet database path and exists functions
No change in behavior. Just remove a little bit of code, reduce macro usage, remove duplicative functions, and make BDB and SQLite implementations more consistent with each other.
This commit is contained in:
@@ -53,16 +53,13 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param[in] wallet_path Path to wallet directory. Or (for backwards compatibility only) a path to a berkeley btree data file inside a wallet directory.
|
* @param[in] env_directory Path to environment directory
|
||||||
* @param[out] database_filename Filename of berkeley btree data file inside the wallet directory.
|
|
||||||
* @return A shared pointer to the BerkeleyEnvironment object for the wallet directory, never empty because ~BerkeleyEnvironment
|
* @return A shared pointer to the BerkeleyEnvironment object for the wallet directory, never empty because ~BerkeleyEnvironment
|
||||||
* erases the weak pointer from the g_dbenvs map.
|
* erases the weak pointer from the g_dbenvs map.
|
||||||
* @post A new BerkeleyEnvironment weak pointer is inserted into g_dbenvs if the directory path key was not already in the map.
|
* @post A new BerkeleyEnvironment weak pointer is inserted into g_dbenvs if the directory path key was not already in the map.
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename)
|
std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory)
|
||||||
{
|
{
|
||||||
fs::path env_directory;
|
|
||||||
SplitWalletPath(wallet_path, env_directory, database_filename);
|
|
||||||
LOCK(cs_db);
|
LOCK(cs_db);
|
||||||
auto inserted = g_dbenvs.emplace(env_directory.string(), std::weak_ptr<BerkeleyEnvironment>());
|
auto inserted = g_dbenvs.emplace(env_directory.string(), std::weak_ptr<BerkeleyEnvironment>());
|
||||||
if (inserted.second) {
|
if (inserted.second) {
|
||||||
@@ -808,21 +805,14 @@ std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(bool flush_on_close)
|
|||||||
return MakeUnique<BerkeleyBatch>(*this, false, flush_on_close);
|
return MakeUnique<BerkeleyBatch>(*this, false, flush_on_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExistsBerkeleyDatabase(const fs::path& path)
|
|
||||||
{
|
|
||||||
fs::path env_directory;
|
|
||||||
std::string data_filename;
|
|
||||||
SplitWalletPath(path, env_directory, data_filename);
|
|
||||||
return IsBDBFile(env_directory / data_filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
|
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
|
||||||
{
|
{
|
||||||
|
fs::path data_file = BDBDataFile(path);
|
||||||
std::unique_ptr<BerkeleyDatabase> db;
|
std::unique_ptr<BerkeleyDatabase> db;
|
||||||
{
|
{
|
||||||
LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
|
LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
|
||||||
std::string data_filename;
|
std::string data_filename = data_file.filename().string();
|
||||||
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(path, data_filename);
|
std::shared_ptr<BerkeleyEnvironment> env = GetBerkeleyEnv(data_file.parent_path());
|
||||||
if (env->m_databases.count(data_filename)) {
|
if (env->m_databases.count(data_filename)) {
|
||||||
error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string()));
|
error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string()));
|
||||||
status = DatabaseStatus::FAILED_ALREADY_LOADED;
|
status = DatabaseStatus::FAILED_ALREADY_LOADED;
|
||||||
|
@@ -83,8 +83,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Get BerkeleyEnvironment and database filename given a wallet path. */
|
/** Get BerkeleyEnvironment given a directory path. */
|
||||||
std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
|
std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory);
|
||||||
|
|
||||||
class BerkeleyBatch;
|
class BerkeleyBatch;
|
||||||
|
|
||||||
@@ -223,9 +223,6 @@ public:
|
|||||||
|
|
||||||
std::string BerkeleyDatabaseVersion();
|
std::string BerkeleyDatabaseVersion();
|
||||||
|
|
||||||
//! Check if Berkeley database exists at specified path.
|
|
||||||
bool ExistsBerkeleyDatabase(const fs::path& path);
|
|
||||||
|
|
||||||
//! Return object giving access to Berkeley database at specified path.
|
//! Return object giving access to Berkeley database at specified path.
|
||||||
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
|
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
|
||||||
|
|
||||||
|
@@ -10,17 +10,6 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#ifdef USE_BDB
|
|
||||||
bool ExistsBerkeleyDatabase(const fs::path& path);
|
|
||||||
#else
|
|
||||||
# define ExistsBerkeleyDatabase(path) (false)
|
|
||||||
#endif
|
|
||||||
#ifdef USE_SQLITE
|
|
||||||
bool ExistsSQLiteDatabase(const fs::path& path);
|
|
||||||
#else
|
|
||||||
# define ExistsSQLiteDatabase(path) (false)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
|
std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
|
||||||
{
|
{
|
||||||
const size_t offset = wallet_dir.string().size() + 1;
|
const size_t offset = wallet_dir.string().size() + 1;
|
||||||
@@ -39,10 +28,10 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
|
|||||||
const fs::path path = it->path().string().substr(offset);
|
const fs::path path = it->path().string().substr(offset);
|
||||||
|
|
||||||
if (it->status().type() == fs::directory_file &&
|
if (it->status().type() == fs::directory_file &&
|
||||||
(ExistsBerkeleyDatabase(it->path()) || ExistsSQLiteDatabase(it->path()))) {
|
(IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) {
|
||||||
// Found a directory which contains wallet.dat btree file, add it as a wallet.
|
// Found a directory which contains wallet.dat btree file, add it as a wallet.
|
||||||
paths.emplace_back(path);
|
paths.emplace_back(path);
|
||||||
} else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && ExistsBerkeleyDatabase(it->path())) {
|
} else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && IsBDBFile(it->path())) {
|
||||||
if (it->path().filename() == "wallet.dat") {
|
if (it->path().filename() == "wallet.dat") {
|
||||||
// Found top-level wallet.dat btree file, add top level directory ""
|
// Found top-level wallet.dat btree file, add top level directory ""
|
||||||
// as a wallet.
|
// as a wallet.
|
||||||
@@ -64,24 +53,31 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
|
|||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename)
|
fs::path BDBDataFile(const fs::path& wallet_path)
|
||||||
{
|
{
|
||||||
if (fs::is_regular_file(wallet_path)) {
|
if (fs::is_regular_file(wallet_path)) {
|
||||||
// Special case for backwards compatibility: if wallet path points to an
|
// Special case for backwards compatibility: if wallet path points to an
|
||||||
// existing file, treat it as the path to a BDB data file in a parent
|
// existing file, treat it as the path to a BDB data file in a parent
|
||||||
// directory that also contains BDB log files.
|
// directory that also contains BDB log files.
|
||||||
env_directory = wallet_path.parent_path();
|
return wallet_path;
|
||||||
database_filename = wallet_path.filename().string();
|
|
||||||
} else {
|
} else {
|
||||||
// Normal case: Interpret wallet path as a directory path containing
|
// Normal case: Interpret wallet path as a directory path containing
|
||||||
// data and log files.
|
// data and log files.
|
||||||
env_directory = wallet_path;
|
return wallet_path / "wallet.dat";
|
||||||
database_filename = "wallet.dat";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs::path SQLiteDataFile(const fs::path& path)
|
||||||
|
{
|
||||||
|
return path / "wallet.dat";
|
||||||
|
}
|
||||||
|
|
||||||
bool IsBDBFile(const fs::path& path)
|
bool IsBDBFile(const fs::path& path)
|
||||||
{
|
{
|
||||||
|
#ifndef USE_BDB
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!fs::exists(path)) return false;
|
if (!fs::exists(path)) return false;
|
||||||
|
|
||||||
// A Berkeley DB Btree file has at least 4K.
|
// A Berkeley DB Btree file has at least 4K.
|
||||||
@@ -107,6 +103,10 @@ bool IsBDBFile(const fs::path& path)
|
|||||||
|
|
||||||
bool IsSQLiteFile(const fs::path& path)
|
bool IsSQLiteFile(const fs::path& path)
|
||||||
{
|
{
|
||||||
|
#ifndef USE_SQLITE
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!fs::exists(path)) return false;
|
if (!fs::exists(path)) return false;
|
||||||
|
|
||||||
// A SQLite Database file is at least 512 bytes.
|
// A SQLite Database file is at least 512 bytes.
|
||||||
|
@@ -228,6 +228,8 @@ std::vector<fs::path> ListDatabases(const fs::path& path);
|
|||||||
|
|
||||||
std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
|
std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
|
||||||
|
|
||||||
|
fs::path BDBDataFile(const fs::path& path);
|
||||||
|
fs::path SQLiteDataFile(const fs::path& path);
|
||||||
bool IsBDBFile(const fs::path& path);
|
bool IsBDBFile(const fs::path& path);
|
||||||
bool IsSQLiteFile(const fs::path& path);
|
bool IsSQLiteFile(const fs::path& path);
|
||||||
|
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
static const char* const DATABASE_FILENAME = "wallet.dat";
|
|
||||||
static constexpr int32_t WALLET_SCHEMA_VERSION = 0;
|
static constexpr int32_t WALLET_SCHEMA_VERSION = 0;
|
||||||
|
|
||||||
static Mutex g_sqlite_mutex;
|
static Mutex g_sqlite_mutex;
|
||||||
@@ -568,17 +567,11 @@ bool SQLiteBatch::TxnAbort()
|
|||||||
return res == SQLITE_OK;
|
return res == SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExistsSQLiteDatabase(const fs::path& path)
|
|
||||||
{
|
|
||||||
const fs::path file = path / DATABASE_FILENAME;
|
|
||||||
return fs::symlink_status(file).type() == fs::regular_file && IsSQLiteFile(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
|
std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
|
||||||
{
|
{
|
||||||
const fs::path file = path / DATABASE_FILENAME;
|
|
||||||
try {
|
try {
|
||||||
auto db = MakeUnique<SQLiteDatabase>(path, file);
|
fs::path data_file = SQLiteDataFile(path);
|
||||||
|
auto db = MakeUnique<SQLiteDatabase>(data_file.parent_path(), data_file);
|
||||||
if (options.verify && !db->Verify(error)) {
|
if (options.verify && !db->Verify(error)) {
|
||||||
status = DatabaseStatus::FAILED_VERIFY;
|
status = DatabaseStatus::FAILED_VERIFY;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@@ -113,7 +113,6 @@ public:
|
|||||||
sqlite3* m_db{nullptr};
|
sqlite3* m_db{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ExistsSQLiteDatabase(const fs::path& path);
|
|
||||||
std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
|
std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
|
||||||
|
|
||||||
std::string SQLiteDatabaseVersion();
|
std::string SQLiteDatabaseVersion();
|
||||||
|
@@ -13,6 +13,13 @@
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup)
|
BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup)
|
||||||
|
|
||||||
|
static std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& path, std::string& database_filename)
|
||||||
|
{
|
||||||
|
fs::path data_file = BDBDataFile(path);
|
||||||
|
database_filename = data_file.filename().string();
|
||||||
|
return GetBerkeleyEnv(data_file.parent_path());
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(getwalletenv_file)
|
BOOST_AUTO_TEST_CASE(getwalletenv_file)
|
||||||
{
|
{
|
||||||
std::string test_name = "test_name.dat";
|
std::string test_name = "test_name.dat";
|
||||||
|
@@ -1013,13 +1013,10 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
|
|||||||
|
|
||||||
Optional<DatabaseFormat> format;
|
Optional<DatabaseFormat> format;
|
||||||
if (exists) {
|
if (exists) {
|
||||||
#ifdef USE_BDB
|
if (IsBDBFile(BDBDataFile(path))) {
|
||||||
if (ExistsBerkeleyDatabase(path)) {
|
|
||||||
format = DatabaseFormat::BERKELEY;
|
format = DatabaseFormat::BERKELEY;
|
||||||
}
|
}
|
||||||
#endif
|
if (IsSQLiteFile(SQLiteDataFile(path))) {
|
||||||
#ifdef USE_SQLITE
|
|
||||||
if (ExistsSQLiteDatabase(path)) {
|
|
||||||
if (format) {
|
if (format) {
|
||||||
error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", path.string()));
|
error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", path.string()));
|
||||||
status = DatabaseStatus::FAILED_BAD_FORMAT;
|
status = DatabaseStatus::FAILED_BAD_FORMAT;
|
||||||
@@ -1027,7 +1024,6 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
|
|||||||
}
|
}
|
||||||
format = DatabaseFormat::SQLITE;
|
format = DatabaseFormat::SQLITE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
} else if (options.require_existing) {
|
} else if (options.require_existing) {
|
||||||
error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
|
error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
|
||||||
status = DatabaseStatus::FAILED_NOT_FOUND;
|
status = DatabaseStatus::FAILED_NOT_FOUND;
|
||||||
|
Reference in New Issue
Block a user