Steps toward multiple dbs available -- working

There will need to be some more refactoring for these changes to be
considered complete/correct, but for now it's working.

new daemon cli argument "--db-type", works for LMDB and BerkeleyDB.

A good deal of refactoring is also present in this commit, namely
Blockchain no longer instantiates BlockchainDB, but rather is passed a
pointer to an already-instantiated BlockchainDB on init().
This commit is contained in:
Thomas Winget 2015-03-25 11:41:30 -04:00
parent 874f48bc82
commit 7b14d4a17f
No known key found for this signature in database
GPG key ID: 58131A160789E630
13 changed files with 146 additions and 58 deletions

View file

@ -29,8 +29,10 @@
#pragma once #pragma once
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "cryptonote_core/blockchain.h" // BlockchainDB and LMDB #include "cryptonote_core/blockchain.h" // BlockchainDB
#include "cryptonote_core/blockchain_storage.h" // in-memory DB #include "cryptonote_core/blockchain_storage.h" // in-memory DB
#include "blockchain_db/blockchain_db.h"
#include "blockchain_db/lmdb/db_lmdb.h"
using namespace cryptonote; using namespace cryptonote;
@ -53,7 +55,27 @@ struct fake_core_lmdb
#endif #endif
{ {
m_pool.init(path.string()); m_pool.init(path.string());
m_storage.init(path.string(), use_testnet, mdb_flags);
BlockchainDB* db = new BlockchainLMDB();
boost::filesystem::path folder(path);
folder /= db->get_db_name();
LOG_PRINT_L0("Loading blockchain from folder " << folder.c_str() << " ...");
const std::string filename = folder.string();
try
{
db->open(filename, mdb_flags);
}
catch (const std::exception& e)
{
LOG_PRINT_L0("Error opening database: " << e.what());
throw;
}
m_storage.init(db, use_testnet);
if (do_batch) if (do_batch)
m_storage.get_db().set_batch_transactions(do_batch); m_storage.get_db().set_batch_transactions(do_batch);
support_batch = true; support_batch = true;

View file

@ -724,13 +724,6 @@ void BlockchainBDB::open(const std::string& filename, const int db_flags)
m_open = true; m_open = true;
} }
// unused for now, create will happen on open if doesn't exist
void BlockchainBDB::create(const std::string& filename)
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
throw DB_CREATE_FAILURE("create() is not implemented for this BlockchainDB, open() will create files if needed.");
}
void BlockchainBDB::close() void BlockchainBDB::close()
{ {
LOG_PRINT_L3("BlockchainBDB::" << __func__); LOG_PRINT_L3("BlockchainBDB::" << __func__);

View file

@ -95,8 +95,6 @@ public:
virtual void open(const std::string& filename, const int db_flags); virtual void open(const std::string& filename, const int db_flags);
virtual void create(const std::string& filename);
virtual void close(); virtual void close();
virtual void sync(); virtual void sync();
@ -279,7 +277,6 @@ private:
Db* m_spent_keys; Db* m_spent_keys;
bool m_open;
uint64_t m_height; uint64_t m_height;
uint64_t m_num_outputs; uint64_t m_num_outputs;
std::string m_folder; std::string m_folder;

View file

@ -129,6 +129,11 @@ void BlockchainDB::pop_block(block& blk, std::vector<transaction>& txs)
} }
} }
bool BlockchainDB::is_open()
{
return m_open;
}
void BlockchainDB::remove_transaction(const crypto::hash& tx_hash) void BlockchainDB::remove_transaction(const crypto::hash& tx_hash)
{ {
transaction tx = get_tx(tx_hash); transaction tx = get_tx(tx_hash);

View file

@ -62,6 +62,7 @@
* *
* General: * General:
* open() * open()
* is_open()
* close() * close()
* sync() * sync()
* reset() * reset()
@ -328,8 +329,8 @@ public:
// open the db at location <filename>, or create it if there isn't one. // open the db at location <filename>, or create it if there isn't one.
virtual void open(const std::string& filename, const int db_flags = 0) = 0; virtual void open(const std::string& filename, const int db_flags = 0) = 0;
// make sure implementation has a create function as well // returns true of the db is open/ready, else false
virtual void create(const std::string& filename) = 0; bool is_open();
// close and sync the db // close and sync the db
virtual void close() = 0; virtual void close() = 0;
@ -482,6 +483,7 @@ public:
// returns true if key image <img> is present in spent key images storage // returns true if key image <img> is present in spent key images storage
virtual bool has_key_image(const crypto::key_image& img) const = 0; virtual bool has_key_image(const crypto::key_image& img) const = 0;
bool m_open;
}; // class BlockchainDB }; // class BlockchainDB

View file

@ -0,0 +1,40 @@
// Copyright (c) 2015, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
namespace cryptonote
{
const std::unordered_set<std::string> blockchain_db_types =
{ "lmdb"
, "berkeley"
};
} // namespace cryptonote

View file

@ -733,13 +733,6 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
// from here, init should be finished // from here, init should be finished
} }
// unused for now, create will happen on open if doesn't exist
void BlockchainLMDB::create(const std::string& filename)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
throw DB_CREATE_FAILURE("create() is not implemented for this BlockchainDB, open() will create files if needed.");
}
void BlockchainLMDB::close() void BlockchainLMDB::close()
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);

View file

@ -24,6 +24,7 @@
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include "blockchain_db/blockchain_db.h" #include "blockchain_db/blockchain_db.h"
#include "cryptonote_protocol/blobdatatype.h" // for type blobdata #include "cryptonote_protocol/blobdatatype.h" // for type blobdata
@ -116,8 +117,6 @@ public:
virtual void open(const std::string& filename, const int mdb_flags=0); virtual void open(const std::string& filename, const int mdb_flags=0);
virtual void create(const std::string& filename);
virtual void close(); virtual void close();
virtual void sync(); virtual void sync();
@ -302,7 +301,6 @@ private:
MDB_dbi m_spent_keys; MDB_dbi m_spent_keys;
bool m_open;
uint64_t m_height; uint64_t m_height;
uint64_t m_num_outputs; uint64_t m_num_outputs;
std::string m_folder; std::string m_folder;

View file

@ -39,7 +39,6 @@
#include "tx_pool.h" #include "tx_pool.h"
#include "blockchain.h" #include "blockchain.h"
#include "blockchain_db/blockchain_db.h" #include "blockchain_db/blockchain_db.h"
#include "blockchain_db/lmdb/db_lmdb.h"
#include "cryptonote_format_utils.h" #include "cryptonote_format_utils.h"
#include "cryptonote_boost_serialization.h" #include "cryptonote_boost_serialization.h"
#include "cryptonote_config.h" #include "cryptonote_config.h"
@ -65,8 +64,7 @@ using epee::string_tools::pod_to_hex;
DISABLE_VS_WARNINGS(4267) DISABLE_VS_WARNINGS(4267)
//------------------------------------------------------------------ //------------------------------------------------------------------
// TODO: initialize m_db with a concrete implementation of BlockchainDB Blockchain::Blockchain(tx_memory_pool& tx_pool):m_db(), m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false), m_enforce_dns_checkpoints(false)
Blockchain::Blockchain(tx_memory_pool& tx_pool):m_db(), m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false), m_testnet(false), m_enforce_dns_checkpoints(false)
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
} }
@ -226,43 +224,24 @@ uint64_t Blockchain::get_current_blockchain_height() const
//------------------------------------------------------------------ //------------------------------------------------------------------
//FIXME: possibly move this into the constructor, to avoid accidentally //FIXME: possibly move this into the constructor, to avoid accidentally
// dereferencing a null BlockchainDB pointer // dereferencing a null BlockchainDB pointer
bool Blockchain::init(const std::string& config_folder, const bool testnet, const int db_flags) bool Blockchain::init(BlockchainDB* db, const bool testnet)
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock); CRITICAL_REGION_LOCAL(m_blockchain_lock);
// TODO: make this configurable if (db == nullptr)
m_db = new BlockchainLMDB();
m_config_folder = config_folder;
m_testnet = testnet;
boost::filesystem::path folder(m_config_folder);
folder /= m_db->get_db_name();
LOG_PRINT_L0("Loading blockchain from folder " << folder.c_str() << " ...");
const std::string filename = folder.string();
try
{ {
m_db->open(filename, db_flags); LOG_ERROR("Attempted to init Blockchain with null DB");
return false;
} }
catch (const DB_OPEN_FAILURE& e) if (!db->is_open())
{ {
LOG_PRINT_L0("No blockchain file found, attempting to create one."); LOG_ERROR("Attempted to init Blockchain with unopened DB");
try return false;
{
m_db->create(filename);
}
catch (const DB_CREATE_FAILURE& db_create_error)
{
LOG_PRINT_L0("Unable to create BlockchainDB! This is not good...");
//TODO: make sure whatever calls this handles the return value properly
return false;
}
} }
m_db = db;
// if the blockchain is new, add the genesis block // if the blockchain is new, add the genesis block
// this feels kinda kludgy to do it this way, but can be looked at later. // this feels kinda kludgy to do it this way, but can be looked at later.
// TODO: add function to create and store genesis block, // TODO: add function to create and store genesis block,

View file

@ -81,7 +81,7 @@ namespace cryptonote
Blockchain(tx_memory_pool& tx_pool); Blockchain(tx_memory_pool& tx_pool);
bool init(const std::string& config_folder, const bool testnet = false, const int db_flags = 0); bool init(BlockchainDB* db, const bool testnet = false);
bool deinit(); bool deinit();
void set_checkpoints(checkpoints&& chk_pts) { m_checkpoints = chk_pts; } void set_checkpoints(checkpoints&& chk_pts) { m_checkpoints = chk_pts; }
@ -180,11 +180,9 @@ namespace cryptonote
outputs_container m_outputs; outputs_container m_outputs;
std::string m_config_folder;
checkpoints m_checkpoints; checkpoints m_checkpoints;
std::atomic<bool> m_is_in_checkpoint_zone; std::atomic<bool> m_is_in_checkpoint_zone;
std::atomic<bool> m_is_blockchain_storing; std::atomic<bool> m_is_blockchain_storing;
bool m_testnet;
bool m_enforce_dns_checkpoints; bool m_enforce_dns_checkpoints;
bool switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::iterator>& alt_chain, bool discard_disconnected_chain); bool switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::iterator>& alt_chain, bool discard_disconnected_chain);

View file

@ -44,6 +44,9 @@ using namespace epee;
#include <csignal> #include <csignal>
#include "daemon/command_line_args.h" #include "daemon/command_line_args.h"
#include "cryptonote_core/checkpoints_create.h" #include "cryptonote_core/checkpoints_create.h"
#include "blockchain_db/blockchain_db.h"
#include "blockchain_db/lmdb/db_lmdb.h"
#include "blockchain_db/berkeleydb/db_bdb.h"
DISABLE_VS_WARNINGS(4355) DISABLE_VS_WARNINGS(4355)
@ -194,7 +197,45 @@ namespace cryptonote
r = m_mempool.init(m_config_folder); r = m_mempool.init(m_config_folder);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool"); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
#if BLOCKCHAIN_DB == DB_LMDB
std::string db_type = command_line::get_arg(vm, daemon_args::arg_db_type);
BlockchainDB* db = nullptr;
if (db_type == "lmdb")
{
db = new BlockchainLMDB();
}
else if (db_type == "berkeley")
{
db = new BlockchainBDB();
}
else
{
LOG_ERROR("Attempted to use non-existant database type");
return false;
}
boost::filesystem::path folder(m_config_folder);
folder /= db->get_db_name();
LOG_PRINT_L0("Loading blockchain from folder " << folder.c_str() << " ...");
const std::string filename = folder.string();
try
{
db->open(filename);
}
catch (const DB_ERROR& e)
{
LOG_PRINT_L0("Error opening database: " << e.what());
return false;
}
r = m_blockchain_storage.init(db, m_testnet);
#else
r = m_blockchain_storage.init(m_config_folder, m_testnet); r = m_blockchain_storage.init(m_config_folder, m_testnet);
#endif
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
// load json & DNS checkpoints, and verify them // load json & DNS checkpoints, and verify them

View file

@ -70,6 +70,11 @@ namespace daemon_args
, "checkpoints from DNS server will be enforced" , "checkpoints from DNS server will be enforced"
, false , false
}; };
const command_line::arg_descriptor<std::string> arg_db_type = {
"db-type"
, "Specify database type"
, "lmdb"
};
} // namespace daemon_args } // namespace daemon_args

View file

@ -42,6 +42,7 @@
#include "rpc/core_rpc_server.h" #include "rpc/core_rpc_server.h"
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include "daemon/command_line_args.h" #include "daemon/command_line_args.h"
#include "blockchain_db/db_types.h"
namespace po = boost::program_options; namespace po = boost::program_options;
namespace bf = boost::filesystem; namespace bf = boost::filesystem;
@ -78,6 +79,7 @@ int main(int argc, char const * argv[])
command_line::add_arg(core_settings, daemon_args::arg_log_level); command_line::add_arg(core_settings, daemon_args::arg_log_level);
command_line::add_arg(core_settings, daemon_args::arg_testnet_on); command_line::add_arg(core_settings, daemon_args::arg_testnet_on);
command_line::add_arg(core_settings, daemon_args::arg_dns_checkpoints); command_line::add_arg(core_settings, daemon_args::arg_dns_checkpoints);
command_line::add_arg(core_settings, daemon_args::arg_db_type);
daemonizer::init_options(hidden_options, visible_options); daemonizer::init_options(hidden_options, visible_options);
daemonize::t_executor::init_options(core_settings); daemonize::t_executor::init_options(core_settings);
@ -128,6 +130,19 @@ int main(int argc, char const * argv[])
return 0; return 0;
} }
std::string db_type = command_line::get_arg(vm, daemon_args::arg_db_type);
// verify that blockchaindb type is valid
if(cryptonote::blockchain_db_types.count(db_type) == 0)
{
std::cout << "Invalid database type (" << db_type << "), available types are:" << std::endl;
for (const auto& type : cryptonote::blockchain_db_types)
{
std::cout << "\t" << type << std::endl;
}
return 0;
}
bool testnet_mode = command_line::get_arg(vm, daemon_args::arg_testnet_on); bool testnet_mode = command_line::get_arg(vm, daemon_args::arg_testnet_on);
auto data_dir_arg = testnet_mode ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; auto data_dir_arg = testnet_mode ? command_line::arg_testnet_data_dir : command_line::arg_data_dir;