Removing unnecessary indexing from account history plugin, it can now focus on just tracking operation history

This commit is contained in:
Daniel Larimer 2015-06-24 16:38:56 -04:00
parent 23a633bea1
commit a0765e2cf2
3 changed files with 4 additions and 351 deletions

View file

@ -34,69 +34,15 @@ namespace graphene { namespace account_history {
namespace detail
{
class account_create_observer : public graphene::chain::evaluation_observer
{
public:
account_create_observer( account_history_plugin& plugin )
: _plugin( plugin ) {}
virtual ~account_create_observer();
virtual void post_evaluate(
const transaction_evaluation_state& eval_state,
const operation& op,
bool apply,
generic_evaluator* ge,
const operation_result& result ) override;
account_history_plugin& _plugin;
};
class account_update_observer : public graphene::chain::evaluation_observer
{
public:
account_update_observer( account_history_plugin& plugin )
: _plugin( plugin )
{
_pre_account_keys.reserve( GRAPHENE_DEFAULT_MAX_AUTHORITY_MEMBERSHIP * 2 + 2 );
}
virtual ~account_update_observer();
virtual void pre_evaluate(
const transaction_evaluation_state& eval_state,
const operation& op,
bool apply,
generic_evaluator* ge ) override;
virtual void post_evaluate(
const transaction_evaluation_state& eval_state,
const operation& op,
bool apply,
generic_evaluator* ge,
const operation_result& result ) override;
virtual void evaluation_failed(
const transaction_evaluation_state& eval_state,
const operation& op,
bool apply,
generic_evaluator* ge,
const operation_result& result ) override;
account_history_plugin& _plugin;
flat_set< key_id_type > _pre_account_keys;
};
class account_history_plugin_impl
{
public:
account_history_plugin_impl(account_history_plugin& _plugin)
: _self( _plugin ),
_create_observer( _plugin ),
_update_observer( _plugin )
: _self( _plugin )
{ }
virtual ~account_history_plugin_impl();
void rebuild_key_account_index();
flat_set<key_id_type> get_keys_for_account(
const account_id_type& account_id );
@ -104,7 +50,6 @@ class account_history_plugin_impl
* and will process/index all operations that were applied in the block.
*/
void update_account_histories( const signed_block& b );
void index_account_keys( const account_id_type& account_id );
graphene::chain::database& database()
{
@ -112,8 +57,6 @@ class account_history_plugin_impl
}
account_history_plugin& _self;
account_create_observer _create_observer;
account_update_observer _update_observer;
flat_set<account_id_type> _tracked_accounts;
};
@ -248,271 +191,13 @@ struct operation_get_impacted_accounts
{}
};
account_create_observer::~account_create_observer()
{
return;
}
void account_create_observer::post_evaluate(
const transaction_evaluation_state& eval_state,
const operation& op,
bool apply,
generic_evaluator* ge,
const operation_result& result
)
{
assert( op.which() == operation::tag<account_create_operation>::value );
if( !apply )
return;
// if we only care about given accounts, then key -> account mapping
// is not maintained
if( _plugin.my->_tracked_accounts.size() > 0 )
return;
account_id_type account_id = result.get< object_id_type >();
_plugin.my->index_account_keys( account_id );
return;
}
account_update_observer::~account_update_observer()
{
return;
}
void account_update_observer::pre_evaluate(
const transaction_evaluation_state& eval_state,
const operation& op,
bool apply,
generic_evaluator* ge
)
{
assert( op.which() == operation::tag<account_update_operation>::value );
if( !apply )
return;
// if we only care about given accounts, then key -> account mapping
// is not maintained
if( _plugin.my->_tracked_accounts.size() > 0 )
return;
// is this a tx which affects a key?
// switch( op.which() )
// {
// see note in configure() why account_create_operation handling is unnecessary
// case operation::tag<account_create_operation>::value:
// const account_create_operation& create_op = op.get< account_create_operation >();
// break;
// case operation::tag<account_update_operation>::value:
// const account_update_operation& update_op = op.get< account_update_operation >();
// _pre_account_keys.clear();
// get_updatable_account_keys( update_op, _pre_account_keys );
// break;
// default:
// FC_ASSERT( false, "account_update_observer got unexpected operation type" );
//}
const account_update_operation& update_op = op.get< account_update_operation >();
_pre_account_keys = _plugin.my->get_keys_for_account( update_op.account );
return;
}
void account_update_observer::post_evaluate(
const transaction_evaluation_state& eval_state,
const operation& op,
bool apply,
generic_evaluator* ge,
const operation_result& result
)
{
assert( op.which() == operation::tag<account_update_operation>::value );
if( !apply )
return;
graphene::chain::database& db = _plugin.my->database();
// if we only care about given accounts, then key -> account mapping
// is not maintained
if( _plugin.my->_tracked_accounts.size() > 0 )
return;
// wild back-of-envelope heuristic: most account update ops
// don't add more than two keys
flat_set<key_id_type> post_account_keys;
post_account_keys.reserve( _pre_account_keys.size() + 2 );
vector<key_id_type> removed_account_keys;
removed_account_keys.reserve( _pre_account_keys.size() );
const account_update_operation& update_op = op.get< account_update_operation >();
post_account_keys = _plugin.my->get_keys_for_account( update_op.account );
std::set_difference(
_pre_account_keys.begin(), _pre_account_keys.end(),
post_account_keys.begin(), post_account_keys.end(),
std::back_inserter( removed_account_keys )
);
//
// If a key_id is in _pre_account_keys but not in post_account_keys,
// then it is placed in removed_account_keys by set_difference().
//
// Note, the *address* corresponding to this key may still exist
// in the account, because it may be aliased to multiple key_id's.
//
// We delete the key_account_object for all removed_account_keys.
// This correctly deletes addresses which were removed
// from the account by the update_op.
//
// Unfortunately, in the case of aliased keys, it deletes
// key_account_object if *any* of the aliases was removed from
// the account. We want it to delete only if *all* of the aliases
// were removed from the account.
//
// However, we need to run index_account_keys() afterwards anyway.
// It will re-add to the index any addresses which had been
// deleted -- but only if they still exist in the account under
// at least one alias.
//
// This is precisely the correct behavior.
//
for( const key_id_type& key_id : removed_account_keys )
{
auto& index = db.get_index_type<key_account_index>().indices().get<by_key>();
auto it = index.find( key_id(db).key_address() );
assert( it != index.end() );
db.modify<key_account_object>( *it, [&]( key_account_object& ka )
{
ka.account_ids.erase( update_op.account );
});
}
_plugin.my->index_account_keys( update_op.account );
return;
}
void account_update_observer::evaluation_failed(
const transaction_evaluation_state& eval_state,
const operation& op,
bool apply,
generic_evaluator* ge,
const operation_result& result
)
{
if( !apply )
return;
// if we only care about given accounts, then key -> account mapping
// is not maintained
if( _plugin.my->_tracked_accounts.size() > 0 )
return;
// cleaning up here is not strictly necessary, but good "hygiene"
_pre_account_keys.clear();
return;
}
account_history_plugin_impl::~account_history_plugin_impl()
{
return;
}
void account_history_plugin_impl::rebuild_key_account_index()
{
// TODO: We should really delete the index before we re-create it.
// TODO: Building and sorting a vector of tuples is probably more efficient
const graphene::chain::database& db = database();
vector< pair< account_id_type, address > > tuples_from_db;
const auto& primary_account_idx = db.get_index_type<account_index>().indices().get<by_id>();
for( const account_object& acct : primary_account_idx )
index_account_keys( acct.id );
return;
}
flat_set<key_id_type> account_history_plugin_impl::get_keys_for_account( const account_id_type& account_id )
{
const graphene::chain::database& db = database();
const account_object& acct = account_id(db);
const flat_map<object_id_type, weight_type>& owner_auths =
acct.owner.auths;
const flat_map<object_id_type, weight_type>& active_auths =
acct.active.auths;
flat_set<key_id_type> key_id_set;
key_id_set.reserve(owner_auths.size() + active_auths.size() + 2);
key_id_set.insert(acct.options.memo_key);
// we don't use get_keys() here to avoid an intermediate copy operation
for( const pair<object_id_type, weight_type>& item : active_auths )
{
if( item.first.type() == key_object_type )
key_id_set.insert( item.first );
}
for( const pair<object_id_type, weight_type>& item : owner_auths )
{
if( item.first.type() == key_object_type )
key_id_set.insert( item.first );
}
return key_id_set;
}
void account_history_plugin_impl::index_account_keys( const account_id_type& account_id )
{
// for each key in account authority... get address, modify(..)
graphene::chain::database& db = database();
flat_set<key_id_type> key_id_set = get_keys_for_account( account_id );
flat_set<address> address_set;
//
// we pass the addresses through another flat_set because the
// blockchain doesn't force de-duplication of addresses
// (multiple key_id's might refer to the same address)
//
address_set.reserve( key_id_set.size() );
for( const key_id_type& key_id : key_id_set )
address_set.insert( key_id(db).key_address() );
// add mappings for the given account
for( const address& addr : address_set )
{
auto& idx = db.get_index_type<key_account_index>().indices().get<by_key>();
auto it = idx.find( addr );
if( it == idx.end() )
{
// if unknown, we need to create a new object
db.create<key_account_object>( [&]( key_account_object& ka )
{
ka.key = addr;
ka.account_ids.insert( account_id );
});
}
else
{
// if known, we need to add to existing object
db.modify<key_account_object>( *it,
[&]( key_account_object& ka )
{
ka.account_ids.insert( account_id );
});
}
}
return;
}
void account_history_plugin_impl::update_account_histories( const signed_block& b )
{
@ -555,8 +240,6 @@ void account_history_plugin_impl::update_account_histories( const signed_block&
{
if( impacted.find( account_id ) != impacted.end() )
{
index_account_keys( account_id );
// add history
const auto& stats_obj = account_id(db).statistics(db);
const auto& ath = db.create<account_transaction_history_object>( [&]( account_transaction_history_object& obj ){
@ -603,17 +286,12 @@ void account_history_plugin::plugin_initialize(const boost::program_options::var
database().applied_block.connect( [&]( const signed_block& b){ my->update_account_histories(b); } );
database().add_index< primary_index< simple_index< operation_history_object > > >();
database().add_index< primary_index< simple_index< account_transaction_history_object > > >();
database().add_index< primary_index< key_account_index >>();
database().register_evaluation_observer<account_create_evaluator>( my->_create_observer );
database().register_evaluation_observer< graphene::chain::account_update_evaluator >( my->_update_observer );
LOAD_VALUE_SET(options, "tracked-accounts", my->_tracked_accounts, graphene::chain::account_id_type);
}
void account_history_plugin::plugin_startup()
{
my->rebuild_key_account_index();
}
flat_set<account_id_type> account_history_plugin::tracked_accounts() const

View file

@ -45,29 +45,6 @@ enum account_history_object_type
bucket_object_type = 1 ///< used in market_history_plugin
};
class key_account_object : public abstract_object<key_account_object>
{
public:
static const uint8_t space_id = ACCOUNT_HISTORY_SPACE_ID;
static const uint8_t type_id = key_account_object_type;
key_account_object() {}
key_account_object( const address& a ) : key(a) {}
address key;
flat_set<account_id_type> account_ids;
};
struct by_key{};
typedef multi_index_container<
key_account_object,
indexed_by<
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
ordered_unique< tag<by_key>, member< key_account_object, address, &key_account_object::key > >
>
> key_account_object_multi_index_type;
typedef generic_index<key_account_object, key_account_object_multi_index_type> key_account_index;
namespace detail
{
@ -95,8 +72,3 @@ class account_history_plugin : public graphene::app::plugin
} } //graphene::account_history
FC_REFLECT_DERIVED( graphene::account_history::key_account_object,
(graphene::db::object),
(key)
(account_ids)
)

View file

@ -188,6 +188,7 @@ void database_fixture::verify_asset_supplies( )const
void database_fixture::verify_account_history_plugin_index( )const
{
return;
if( skip_key_index_test )
return;
@ -219,6 +220,7 @@ void database_fixture::verify_account_history_plugin_index( )const
tuples_from_db.emplace_back( account_id, addr );
}
/*
vector< pair< account_id_type, address > > tuples_from_index;
tuples_from_index.reserve( tuples_from_db.size() );
const auto& key_account_idx =
@ -263,6 +265,7 @@ void database_fixture::verify_account_history_plugin_index( )const
bool account_history_plugin_index_ok = is_equal;
BOOST_CHECK( account_history_plugin_index_ok );
*/
}
return;
}