Merge pull request #101 from peerplays-network/GRPH-75

[GRPH-75] node restore improvments
This commit is contained in:
Alfredo Garcia 2019-09-17 21:45:42 -03:00 committed by GitHub
commit 96161db8a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 232 additions and 180 deletions

View file

@ -300,7 +300,6 @@ namespace detail {
~application_impl() ~application_impl()
{ {
fc::remove_all(_data_dir / "blockchain/dblock");
} }
void set_dbg_init_key( genesis_state_type& genesis, const std::string& init_key ) void set_dbg_init_key( genesis_state_type& genesis, const std::string& init_key )
@ -314,8 +313,7 @@ namespace detail {
void startup() void startup()
{ try { { try {
bool clean = !fc::exists(_data_dir / "blockchain/dblock"); fc::create_directories(_data_dir / "blockchain");
fc::create_directories(_data_dir / "blockchain/dblock");
auto initial_state = [&] { auto initial_state = [&] {
ilog("Initializing database..."); ilog("Initializing database...");
@ -381,64 +379,17 @@ namespace detail {
bool replay = false; bool replay = false;
std::string replay_reason = "reason not provided"; std::string replay_reason = "reason not provided";
// never replay if data dir is empty if( _options->count("replay-blockchain") )
if( fc::exists( _data_dir ) && fc::directory_iterator( _data_dir ) != fc::directory_iterator() ) _chain_db->wipe( _data_dir / "blockchain", false );
{
if( _options->count("replay-blockchain") )
{
replay = true;
replay_reason = "replay-blockchain argument specified";
}
else if( !clean )
{
replay = true;
replay_reason = "unclean shutdown detected";
}
else if( !fc::exists( _data_dir / "db_version" ) )
{
replay = true;
replay_reason = "db_version file not found";
}
else
{
std::string version_string;
fc::read_file_contents( _data_dir / "db_version", version_string );
if( version_string != GRAPHENE_CURRENT_DB_VERSION ) try
{ {
replay = true; _chain_db->open( _data_dir / "blockchain", initial_state, GRAPHENE_CURRENT_DB_VERSION );
replay_reason = "db_version file content mismatch";
}
}
} }
catch( const fc::exception& e )
if( !replay )
{ {
try elog( "Caught exception ${e} in open(), you might want to force a replay", ("e", e.to_detail_string()) );
{ throw;
_chain_db->open( _data_dir / "blockchain", initial_state );
}
catch( const fc::exception& e )
{
ilog( "Caught exception ${e} in open()", ("e", e.to_detail_string()) );
replay = true;
replay_reason = "exception in open()";
}
}
if( replay )
{
ilog( "Replaying blockchain due to: ${reason}", ("reason", replay_reason) );
fc::remove_all( _data_dir / "db_version" );
_chain_db->reindex( _data_dir / "blockchain", initial_state() );
const auto mode = std::ios::out | std::ios::binary | std::ios::trunc;
std::ofstream db_version( (_data_dir / "db_version").generic_string().c_str(), mode );
std::string version_string = GRAPHENE_CURRENT_DB_VERSION;
db_version.write( version_string.c_str(), version_string.size() );
db_version.close();
} }
if( _options->count("force-validate") ) if( _options->count("force-validate") )

View file

@ -45,14 +45,15 @@ void block_database::open( const fc::path& dbdir )
_block_num_to_pos.exceptions(std::ios_base::failbit | std::ios_base::badbit); _block_num_to_pos.exceptions(std::ios_base::failbit | std::ios_base::badbit);
_blocks.exceptions(std::ios_base::failbit | std::ios_base::badbit); _blocks.exceptions(std::ios_base::failbit | std::ios_base::badbit);
if( !fc::exists( dbdir/"index" ) ) _index_filename = dbdir / "index";
if( !fc::exists( _index_filename ) )
{ {
_block_num_to_pos.open( (dbdir/"index").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc); _block_num_to_pos.open( _index_filename.generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc);
_blocks.open( (dbdir/"blocks").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc); _blocks.open( (dbdir/"blocks").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc);
} }
else else
{ {
_block_num_to_pos.open( (dbdir/"index").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out ); _block_num_to_pos.open( _index_filename.generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out );
_blocks.open( (dbdir/"blocks").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out ); _blocks.open( (dbdir/"blocks").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out );
} }
} FC_CAPTURE_AND_RETHROW( (dbdir) ) } } FC_CAPTURE_AND_RETHROW( (dbdir) ) }
@ -121,7 +122,7 @@ bool block_database::contains( const block_id_type& id )const
index_entry e; index_entry e;
auto index_pos = sizeof(e)*block_header::num_from_id(id); auto index_pos = sizeof(e)*block_header::num_from_id(id);
_block_num_to_pos.seekg( 0, _block_num_to_pos.end ); _block_num_to_pos.seekg( 0, _block_num_to_pos.end );
if ( _block_num_to_pos.tellg() <= index_pos ) if ( _block_num_to_pos.tellg() < index_pos + sizeof(e) )
return false; return false;
_block_num_to_pos.seekg( index_pos ); _block_num_to_pos.seekg( index_pos );
_block_num_to_pos.read( (char*)&e, sizeof(e) ); _block_num_to_pos.read( (char*)&e, sizeof(e) );
@ -206,34 +207,47 @@ optional<signed_block> block_database::fetch_by_number( uint32_t block_num )cons
return optional<signed_block>(); return optional<signed_block>();
} }
optional<signed_block> block_database::last()const optional<index_entry> block_database::last_index_entry()const {
{
try try
{ {
index_entry e; index_entry e;
_block_num_to_pos.seekg( 0, _block_num_to_pos.end ); _block_num_to_pos.seekg( 0, _block_num_to_pos.end );
std::streampos pos = _block_num_to_pos.tellg();
if( pos < sizeof(index_entry) )
return optional<index_entry>();
if( _block_num_to_pos.tellp() < sizeof(index_entry) ) pos -= pos % sizeof(index_entry);
return optional<signed_block>();
_block_num_to_pos.seekg( -sizeof(index_entry), _block_num_to_pos.end ); _blocks.seekg( 0, _block_num_to_pos.end );
_block_num_to_pos.read( (char*)&e, sizeof(e) ); const std::streampos blocks_size = _blocks.tellg();
uint64_t pos = _block_num_to_pos.tellg(); while( pos > 0 )
while( e.block_size == 0 && pos > 0 )
{ {
pos -= sizeof(index_entry); pos -= sizeof(index_entry);
_block_num_to_pos.seekg( pos ); _block_num_to_pos.seekg( pos );
_block_num_to_pos.read( (char*)&e, sizeof(e) ); _block_num_to_pos.read( (char*)&e, sizeof(e) );
if( _block_num_to_pos.gcount() == sizeof(e) && e.block_size > 0
&& e.block_pos + e.block_size <= blocks_size )
try
{
vector<char> data( e.block_size );
_blocks.seekg( e.block_pos );
_blocks.read( data.data(), e.block_size );
if( _blocks.gcount() == e.block_size )
{
const signed_block block = fc::raw::unpack<signed_block>(data);
if( block.id() == e.block_id )
return e;
}
}
catch (const fc::exception&)
{
}
catch (const std::exception&)
{
}
fc::resize_file( _index_filename, pos );
} }
if( e.block_size == 0 )
return optional<signed_block>();
vector<char> data( e.block_size );
_blocks.seekg( e.block_pos );
_blocks.read( data.data(), e.block_size );
auto result = fc::raw::unpack<signed_block>(data);
return result;
} }
catch (const fc::exception&) catch (const fc::exception&)
{ {
@ -241,42 +255,21 @@ optional<signed_block> block_database::last()const
catch (const std::exception&) catch (const std::exception&)
{ {
} }
return optional<index_entry>();
}
optional<signed_block> block_database::last()const
{
optional<index_entry> entry = last_index_entry();
if( entry.valid() ) return fetch_by_number( block_header::num_from_id(entry->block_id) );
return optional<signed_block>(); return optional<signed_block>();
} }
optional<block_id_type> block_database::last_id()const optional<block_id_type> block_database::last_id()const
{ {
try optional<index_entry> entry = last_index_entry();
{ if( entry.valid() ) return entry->block_id;
index_entry e;
_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
if( _block_num_to_pos.tellp() < sizeof(index_entry) )
return optional<block_id_type>();
_block_num_to_pos.seekg( -sizeof(index_entry), _block_num_to_pos.end );
_block_num_to_pos.read( (char*)&e, sizeof(e) );
uint64_t pos = _block_num_to_pos.tellg();
while( e.block_size == 0 && pos > 0 )
{
pos -= sizeof(index_entry);
_block_num_to_pos.seekg( pos );
_block_num_to_pos.read( (char*)&e, sizeof(e) );
}
if( e.block_size == 0 )
return optional<block_id_type>();
return e.block_id;
}
catch (const fc::exception&)
{
}
catch (const std::exception&)
{
}
return optional<block_id_type>(); return optional<block_id_type>();
} }
} } } }

View file

@ -515,7 +515,6 @@ void database::pop_block()
GRAPHENE_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" ); GRAPHENE_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" );
_fork_db.pop_block(); _fork_db.pop_block();
_block_id_to_block.remove( head_id );
pop_undo(); pop_undo();
_popped_tx.insert( _popped_tx.begin(), head_block->transactions.begin(), head_block->transactions.end() ); _popped_tx.insert( _popped_tx.begin(), head_block->transactions.begin(), head_block->transactions.end() );

View file

@ -47,33 +47,86 @@ database::~database()
clear_pending(); clear_pending();
} }
void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation) // Right now, we leave undo_db enabled when replaying when the bookie plugin is
{ try { // enabled. It depends on new/changed/removed object notifications, and those are
ilog( "reindexing blockchain" ); // only fired when the undo_db is enabled.
wipe(data_dir, false); // So we use this helper object to disable undo_db only if it is not forbidden
open(data_dir, [&initial_allocation]{return initial_allocation;}); // with _slow_replays flag.
class auto_undo_enabler
{
const bool _slow_replays;
undo_database& _undo_db;
bool _disabled;
public:
auto_undo_enabler(bool slow_replays, undo_database& undo_db) :
_slow_replays(slow_replays),
_undo_db(undo_db),
_disabled(false)
{
}
auto start = fc::time_point::now(); ~auto_undo_enabler()
{
try{
enable();
} FC_CAPTURE_AND_LOG(("undo_db enabling crash"))
}
void enable()
{
if(!_disabled)
return;
_undo_db.enable();
_disabled = false;
}
void disable()
{
if(_disabled)
return;
if(_slow_replays)
return;
_undo_db.disable();
_disabled = true;
}
};
void database::reindex( fc::path data_dir )
{ try {
auto last_block = _block_id_to_block.last(); auto last_block = _block_id_to_block.last();
if( !last_block ) { if( !last_block ) {
elog( "!no last block" ); elog( "!no last block" );
edump((last_block)); edump((last_block));
return; return;
} }
if( last_block->block_num() <= head_block_num()) return;
ilog( "reindexing blockchain" );
auto start = fc::time_point::now();
const auto last_block_num = last_block->block_num(); const auto last_block_num = last_block->block_num();
uint32_t flush_point = last_block_num < 10000 ? 0 : last_block_num - 10000;
uint32_t undo_point = last_block_num < 50 ? 0 : last_block_num - 50;
ilog( "Replaying blocks..." ); ilog( "Replaying blocks, starting at ${next}...", ("next",head_block_num() + 1) );
// Right now, we leave undo_db enabled when replaying when the bookie plugin is auto_undo_enabler undo(_slow_replays, _undo_db);
// enabled. It depends on new/changed/removed object notifications, and those are if( head_block_num() >= undo_point )
// only fired when the undo_db is enabled
if (!_slow_replays)
_undo_db.disable();
for( uint32_t i = 1; i <= last_block_num; ++i )
{ {
if( i == 1 || if( head_block_num() > 0 )
i % 10000 == 0 ) _fork_db.start_block( *fetch_block_by_number( head_block_num() ) );
std::cerr << " " << double(i*100)/last_block_num << "% "<< i << " of " <<last_block_num<<" \n"; }
else
{
undo.disable();
}
for( uint32_t i = head_block_num() + 1; i <= last_block_num; ++i )
{
if( i % 10000 == 0 ) std::cerr << " " << double(i*100)/last_block_num << "% "<<i << " of " <<last_block_num<<" \n";
if( i == flush_point )
{
ilog( "Writing database to disk at block ${i}", ("i",i) );
flush();
ilog( "Done" );
}
fc::optional< signed_block > block = _block_id_to_block.fetch_by_number(i); fc::optional< signed_block > block = _block_id_to_block.fetch_by_number(i);
if( !block.valid() ) if( !block.valid() )
{ {
@ -94,24 +147,27 @@ void database::reindex(fc::path data_dir, const genesis_state_type& initial_allo
wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) ); wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) );
break; break;
} }
if (_slow_replays) if( i < undo_point && !_slow_replays)
push_block(*block, skip_fork_db | {
skip_witness_signature |
skip_transaction_signatures |
skip_transaction_dupe_check |
skip_tapos_check |
skip_witness_schedule_check |
skip_authority_check);
else
apply_block(*block, skip_witness_signature | apply_block(*block, skip_witness_signature |
skip_transaction_signatures | skip_transaction_signatures |
skip_transaction_dupe_check | skip_transaction_dupe_check |
skip_tapos_check | skip_tapos_check |
skip_witness_schedule_check | skip_witness_schedule_check |
skip_authority_check); skip_authority_check);
}
else
{
undo.enable();
push_block(*block, skip_witness_signature |
skip_transaction_signatures |
skip_transaction_dupe_check |
skip_tapos_check |
skip_witness_schedule_check |
skip_authority_check);
}
} }
if (!_slow_replays) undo.enable();
_undo_db.enable();
auto end = fc::time_point::now(); auto end = fc::time_point::now();
ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) ); ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) } } FC_CAPTURE_AND_RETHROW( (data_dir) ) }
@ -129,10 +185,29 @@ void database::wipe(const fc::path& data_dir, bool include_blocks)
void database::open( void database::open(
const fc::path& data_dir, const fc::path& data_dir,
std::function<genesis_state_type()> genesis_loader) std::function<genesis_state_type()> genesis_loader,
const std::string& db_version)
{ {
try try
{ {
bool wipe_object_db = false;
if( !fc::exists( data_dir / "db_version" ) )
wipe_object_db = true;
else
{
std::string version_string;
fc::read_file_contents( data_dir / "db_version", version_string );
wipe_object_db = ( version_string != db_version );
}
if( wipe_object_db ) {
ilog("Wiping object_database due to missing or wrong version");
object_database::wipe( data_dir );
std::ofstream version_file( (data_dir / "db_version").generic_string().c_str(),
std::ios::out | std::ios::binary | std::ios::trunc );
version_file.write( db_version.c_str(), db_version.size() );
version_file.close();
}
object_database::open(data_dir); object_database::open(data_dir);
_block_id_to_block.open(data_dir / "database" / "block_num_to_block"); _block_id_to_block.open(data_dir / "database" / "block_num_to_block");
@ -140,15 +215,13 @@ void database::open(
if( !find(global_property_id_type()) ) if( !find(global_property_id_type()) )
init_genesis(genesis_loader()); init_genesis(genesis_loader());
fc::optional<signed_block> last_block = _block_id_to_block.last(); fc::optional<block_id_type> last_block = _block_id_to_block.last_id();
if( last_block.valid() ) if( last_block.valid() )
{ {
_fork_db.start_block( *last_block ); FC_ASSERT( *last_block >= head_block_id(),
if( last_block->id() != head_block_id() ) "last block ID does not match current chain state",
{ ("last_block->id", last_block)("head_block_id",head_block_num()) );
FC_ASSERT( head_block_num() == 0, "last block ID does not match current chain state", reindex( data_dir );
("last_block->id", last_block->id())("head_block_num",head_block_num()) );
}
} }
_opened = true; _opened = true;
} }
@ -173,17 +246,9 @@ void database::close(bool rewind)
while( head_block_num() > cutoff ) while( head_block_num() > cutoff )
{ {
// elog("pop");
block_id_type popped_block_id = head_block_id(); block_id_type popped_block_id = head_block_id();
pop_block(); pop_block();
_fork_db.remove(popped_block_id); // doesn't throw on missing _fork_db.remove(popped_block_id); // doesn't throw on missing
try
{
_block_id_to_block.remove(popped_block_id);
}
catch (const fc::key_not_found_exception&)
{
}
} }
} }
catch ( const fc::exception& e ) catch ( const fc::exception& e )

View file

@ -26,6 +26,8 @@
#include <graphene/chain/protocol/block.hpp> #include <graphene/chain/protocol/block.hpp>
namespace graphene { namespace chain { namespace graphene { namespace chain {
class index_entry;
class block_database class block_database
{ {
public: public:
@ -44,6 +46,8 @@ namespace graphene { namespace chain {
optional<signed_block> last()const; optional<signed_block> last()const;
optional<block_id_type> last_id()const; optional<block_id_type> last_id()const;
private: private:
optional<index_entry> last_index_entry()const;
fc::path _index_filename;
mutable std::fstream _blocks; mutable std::fstream _blocks;
mutable std::fstream _block_num_to_pos; mutable std::fstream _block_num_to_pos;
}; };

View file

@ -91,10 +91,12 @@ namespace graphene { namespace chain {
* *
* @param data_dir Path to open or create database in * @param data_dir Path to open or create database in
* @param genesis_loader A callable object which returns the genesis state to initialize new databases on * @param genesis_loader A callable object which returns the genesis state to initialize new databases on
* @param db_version a version string that changes when the internal database format and/or logic is modified
*/ */
void open( void open(
const fc::path& data_dir, const fc::path& data_dir,
std::function<genesis_state_type()> genesis_loader ); std::function<genesis_state_type()> genesis_loader,
const std::string& db_version );
/** /**
* @brief Rebuild object graph from block history and open detabase * @brief Rebuild object graph from block history and open detabase
@ -102,7 +104,7 @@ namespace graphene { namespace chain {
* This method may be called after or instead of @ref database::open, and will rebuild the object graph by * This method may be called after or instead of @ref database::open, and will rebuild the object graph by
* replaying blockchain history. When this method exits successfully, the database will be open. * replaying blockchain history. When this method exits successfully, the database will be open.
*/ */
void reindex(fc::path data_dir, const genesis_state_type& initial_allocation = genesis_state_type()); void reindex(fc::path data_dir);
/** /**
* @brief wipe Delete database from disk, and potentially the raw chain as well. * @brief wipe Delete database from disk, and potentially the raw chain as well.

View file

@ -71,14 +71,20 @@ index& object_database::get_mutable_index(uint8_t space_id, uint8_t type_id)
void object_database::flush() void object_database::flush()
{ {
// ilog("Save object_database in ${d}", ("d", _data_dir)); // ilog("Save object_database in ${d}", ("d", _data_dir));
fc::create_directories( _data_dir / "object_database.tmp" / "lock" );
for( uint32_t space = 0; space < _index.size(); ++space ) for( uint32_t space = 0; space < _index.size(); ++space )
{ {
fc::create_directories( _data_dir / "object_database" / fc::to_string(space) ); fc::create_directories( _data_dir / "object_database.tmp" / fc::to_string(space) );
const auto types = _index[space].size(); const auto types = _index[space].size();
for( uint32_t type = 0; type < types; ++type ) for( uint32_t type = 0; type < types; ++type )
if( _index[space][type] ) if( _index[space][type] )
_index[space][type]->save( _data_dir / "object_database" / fc::to_string(space)/fc::to_string(type) ); _index[space][type]->save( _data_dir / "object_database.tmp" / fc::to_string(space)/fc::to_string(type) );
} }
fc::remove_all( _data_dir / "object_database.tmp" / "lock" );
if( fc::exists( _data_dir / "object_database" ) )
fc::rename( _data_dir / "object_database", _data_dir / "object_database.old" );
fc::rename( _data_dir / "object_database.tmp", _data_dir / "object_database" );
fc::remove_all( _data_dir / "object_database.old" );
} }
void object_database::wipe(const fc::path& data_dir) void object_database::wipe(const fc::path& data_dir)
@ -91,8 +97,13 @@ void object_database::wipe(const fc::path& data_dir)
void object_database::open(const fc::path& data_dir) void object_database::open(const fc::path& data_dir)
{ try { { try {
ilog("Opening object database from ${d} ...", ("d", data_dir));
_data_dir = data_dir; _data_dir = data_dir;
if( fc::exists( _data_dir / "object_database" / "lock" ) )
{
wlog("Ignoring locked object_database");
return;
}
ilog("Opening object database from ${d} ...", ("d", data_dir));
for( uint32_t space = 0; space < _index.size(); ++space ) for( uint32_t space = 0; space < _index.size(); ++space )
for( uint32_t type = 0; type < _index[space].size(); ++type ) for( uint32_t type = 0; type < _index[space].size(); ++type )
if( _index[space][type] ) if( _index[space][type] )

View file

@ -118,8 +118,6 @@ void undo_database::undo()
_db.insert( std::move(*item.second) ); _db.insert( std::move(*item.second) );
_stack.pop_back(); _stack.pop_back();
if( _stack.empty() )
_stack.emplace_back();
enable(); enable();
--_active_sessions; --_active_sessions;
} FC_CAPTURE_AND_RETHROW() } } FC_CAPTURE_AND_RETHROW() }
@ -127,6 +125,12 @@ void undo_database::undo()
void undo_database::merge() void undo_database::merge()
{ {
FC_ASSERT( _active_sessions > 0 ); FC_ASSERT( _active_sessions > 0 );
if( _active_sessions == 1 && _stack.size() == 1 )
{
_stack.pop_back();
--_active_sessions;
return;
}
FC_ASSERT( _stack.size() >=2 ); FC_ASSERT( _stack.size() >=2 );
auto& state = _stack.back(); auto& state = _stack.back();
auto& prev_state = _stack[_stack.size()-2]; auto& prev_state = _stack[_stack.size()-2];

View file

@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE( genesis_and_persistence_bench )
{ {
database db; database db;
db.open(data_dir.path(), [&]{return genesis_state;}); db.open(data_dir.path(), [&]{return genesis_state;}, "test");
for( int i = 11; i < account_count + 11; ++i) for( int i = 11; i < account_count + 11; ++i)
BOOST_CHECK(db.get_balance(account_id_type(i), asset_id_type()).amount == GRAPHENE_MAX_SHARE_SUPPLY / account_count); BOOST_CHECK(db.get_balance(account_id_type(i), asset_id_type()).amount == GRAPHENE_MAX_SHARE_SUPPLY / account_count);
@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE( genesis_and_persistence_bench )
database db; database db;
fc::time_point start_time = fc::time_point::now(); fc::time_point start_time = fc::time_point::now();
db.open(data_dir.path(), [&]{return genesis_state;}); db.open(data_dir.path(), [&]{return genesis_state;}, "test");
ilog("Opened database in ${t} milliseconds.", ("t", (fc::time_point::now() - start_time).count() / 1000)); ilog("Opened database in ${t} milliseconds.", ("t", (fc::time_point::now() - start_time).count() / 1000));
for( int i = 11; i < account_count + 11; ++i) for( int i = 11; i < account_count + 11; ++i)
@ -116,7 +116,7 @@ BOOST_AUTO_TEST_CASE( genesis_and_persistence_bench )
auto start_time = fc::time_point::now(); auto start_time = fc::time_point::now();
wlog( "about to start reindex..." ); wlog( "about to start reindex..." );
db.reindex(data_dir.path(), genesis_state); db.open(data_dir.path(), [&]{return genesis_state;}, "force_wipe");
ilog("Replayed database in ${t} milliseconds.", ("t", (fc::time_point::now() - start_time).count() / 1000)); ilog("Replayed database in ${t} milliseconds.", ("t", (fc::time_point::now() - start_time).count() / 1000));
for( int i = 0; i < blocks_to_produce; ++i ) for( int i = 0; i < blocks_to_produce; ++i )

View file

@ -373,7 +373,7 @@ void database_fixture::open_database()
{ {
if( !data_dir ) { if( !data_dir ) {
data_dir = fc::temp_directory( graphene::utilities::temp_directory_path() ); data_dir = fc::temp_directory( graphene::utilities::temp_directory_path() );
db.open(data_dir->path(), [this]{return genesis_state;}); db.open(data_dir->path(), [this]{return genesis_state;}, "test");
} }
} }

View file

@ -124,7 +124,7 @@ int main( int argc, char** argv )
database db; database db;
fc::path db_path = data_dir / "db"; fc::path db_path = data_dir / "db";
db.open(db_path, [&]() { return genesis; } ); db.open(db_path, [&]() { return genesis; }, "TEST" );
uint32_t slot = 1; uint32_t slot = 1;
uint32_t missed = 0; uint32_t missed = 0;

View file

@ -137,9 +137,10 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks )
// TODO: Don't generate this here // TODO: Don't generate this here
auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
signed_block cutoff_block; signed_block cutoff_block;
uint32_t last_block;
{ {
database db; database db;
db.open(data_dir.path(), make_genesis ); db.open(data_dir.path(), make_genesis, "TEST" );
b = db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1), init_account_priv_key, database::skip_nothing); b = db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1), init_account_priv_key, database::skip_nothing);
// TODO: Change this test when we correct #406 // TODO: Change this test when we correct #406
@ -156,6 +157,7 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks )
if( cutoff_height >= 200 ) if( cutoff_height >= 200 )
{ {
cutoff_block = *(db.fetch_block_by_number( cutoff_height )); cutoff_block = *(db.fetch_block_by_number( cutoff_height ));
last_block = db.head_block_num();
break; break;
} }
} }
@ -163,8 +165,10 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks )
} }
{ {
database db; database db;
db.open(data_dir.path(), []{return genesis_state_type();}); db.open(data_dir.path(), []{return genesis_state_type();}, "TEST");
BOOST_CHECK_EQUAL( db.head_block_num(), cutoff_block.block_num() ); BOOST_CHECK_EQUAL( db.head_block_num(), last_block );
while( db.head_block_num() > cutoff_block.block_num() )
db.pop_block();
b = cutoff_block; b = cutoff_block;
for( uint32_t i = 0; i < 200; ++i ) for( uint32_t i = 0; i < 200; ++i )
{ {
@ -188,7 +192,7 @@ BOOST_AUTO_TEST_CASE( undo_block )
fc::temp_directory data_dir( graphene::utilities::temp_directory_path() ); fc::temp_directory data_dir( graphene::utilities::temp_directory_path() );
{ {
database db; database db;
db.open(data_dir.path(), make_genesis); db.open(data_dir.path(), make_genesis, "TEST");
fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP );
std::vector< time_point_sec > time_stack; std::vector< time_point_sec > time_stack;
@ -237,9 +241,9 @@ BOOST_AUTO_TEST_CASE( fork_blocks )
fc::temp_directory data_dir2( graphene::utilities::temp_directory_path() ); fc::temp_directory data_dir2( graphene::utilities::temp_directory_path() );
database db1; database db1;
db1.open(data_dir1.path(), make_genesis); db1.open(data_dir1.path(), make_genesis, "TEST");
database db2; database db2;
db2.open(data_dir2.path(), make_genesis); db2.open(data_dir2.path(), make_genesis, "TEST");
BOOST_CHECK( db1.get_chain_id() == db2.get_chain_id() ); BOOST_CHECK( db1.get_chain_id() == db2.get_chain_id() );
auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
@ -437,7 +441,7 @@ BOOST_AUTO_TEST_CASE( undo_pending )
fc::temp_directory data_dir( graphene::utilities::temp_directory_path() ); fc::temp_directory data_dir( graphene::utilities::temp_directory_path() );
{ {
database db; database db;
db.open(data_dir.path(), make_genesis); db.open(data_dir.path(), make_genesis, "TEST");
auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
public_key_type init_account_pub_key = init_account_priv_key.get_public_key(); public_key_type init_account_pub_key = init_account_priv_key.get_public_key();
@ -502,8 +506,8 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create )
dir2( graphene::utilities::temp_directory_path() ); dir2( graphene::utilities::temp_directory_path() );
database db1, database db1,
db2; db2;
db1.open(dir1.path(), make_genesis); db1.open(dir1.path(), make_genesis, "TEST");
db2.open(dir2.path(), make_genesis); db2.open(dir2.path(), make_genesis, "TEST");
BOOST_CHECK( db1.get_chain_id() == db2.get_chain_id() ); BOOST_CHECK( db1.get_chain_id() == db2.get_chain_id() );
auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
@ -561,8 +565,8 @@ BOOST_AUTO_TEST_CASE( duplicate_transactions )
dir2( graphene::utilities::temp_directory_path() ); dir2( graphene::utilities::temp_directory_path() );
database db1, database db1,
db2; db2;
db1.open(dir1.path(), make_genesis); db1.open(dir1.path(), make_genesis, "TEST");
db2.open(dir2.path(), make_genesis); db2.open(dir2.path(), make_genesis, "TEST");
BOOST_CHECK( db1.get_chain_id() == db2.get_chain_id() ); BOOST_CHECK( db1.get_chain_id() == db2.get_chain_id() );
auto skip_sigs = database::skip_transaction_signatures | database::skip_authority_check; auto skip_sigs = database::skip_transaction_signatures | database::skip_authority_check;
@ -611,7 +615,7 @@ BOOST_AUTO_TEST_CASE( tapos )
try { try {
fc::temp_directory dir1( graphene::utilities::temp_directory_path() ); fc::temp_directory dir1( graphene::utilities::temp_directory_path() );
database db1; database db1;
db1.open(dir1.path(), make_genesis); db1.open(dir1.path(), make_genesis, "TEST");
const account_object& init1 = *db1.get_index_type<account_index>().indices().get<by_name>().find("init1"); const account_object& init1 = *db1.get_index_type<account_index>().indices().get<by_name>().find("init1");
@ -1162,7 +1166,7 @@ BOOST_FIXTURE_TEST_CASE( transaction_invalidated_in_cache, database_fixture )
fc::temp_directory data_dir2( graphene::utilities::temp_directory_path() ); fc::temp_directory data_dir2( graphene::utilities::temp_directory_path() );
database db2; database db2;
db2.open(data_dir2.path(), make_genesis); db2.open(data_dir2.path(), make_genesis, "TEST");
BOOST_CHECK( db.get_chain_id() == db2.get_chain_id() ); BOOST_CHECK( db.get_chain_id() == db2.get_chain_id() );
while( db2.head_block_num() < db.head_block_num() ) while( db2.head_block_num() < db.head_block_num() )
@ -1325,7 +1329,7 @@ BOOST_AUTO_TEST_CASE( genesis_reserve_ids )
genesis_state.initial_assets.push_back( usd ); genesis_state.initial_assets.push_back( usd );
return genesis_state; return genesis_state;
} ); }, "TEST" );
const auto& acct_idx = db.get_index_type<account_index>().indices().get<by_name>(); const auto& acct_idx = db.get_index_type<account_index>().indices().get<by_name>();
auto acct_itr = acct_idx.find("init0"); auto acct_itr = acct_idx.find("init0");

View file

@ -62,6 +62,25 @@ BOOST_AUTO_TEST_CASE( undo_test )
} }
} }
BOOST_AUTO_TEST_CASE( merge_test )
{
try {
database db;
auto ses = db._undo_db.start_undo_session();
const auto& bal_obj1 = db.create<account_balance_object>( [&]( account_balance_object& obj ){
obj.balance = 42;
});
ses.merge();
auto balance = db.get_balance( account_id_type(), asset_id_type() );
BOOST_CHECK_EQUAL( 42, balance.amount.value );
} catch ( const fc::exception& e )
{
edump( (e.to_detail_string()) );
throw;
}
}
BOOST_AUTO_TEST_CASE( flat_index_test ) BOOST_AUTO_TEST_CASE( flat_index_test )
{ {
ACTORS((sam)); ACTORS((sam));

View file

@ -1111,7 +1111,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test )
auto _sign = [&]( signed_transaction& tx, const private_key_type& key ) auto _sign = [&]( signed_transaction& tx, const private_key_type& key )
{ tx.sign( key, db.get_chain_id() ); }; { tx.sign( key, db.get_chain_id() ); };
db.open(td.path(), [this]{return genesis_state;}); db.open(td.path(), [this]{return genesis_state;}, "TEST");
const balance_object& balance = balance_id_type()(db); const balance_object& balance = balance_id_type()(db);
BOOST_CHECK_EQUAL(balance.balance.amount.value, 1); BOOST_CHECK_EQUAL(balance.balance.amount.value, 1);
BOOST_CHECK_EQUAL(balance_id_type(1)(db).balance.amount.value, 1); BOOST_CHECK_EQUAL(balance_id_type(1)(db).balance.amount.value, 1);