Issue #68 - created simple secondary index for accounts

This commit is contained in:
Daniel Larimer 2015-06-23 13:33:13 -04:00
parent b5b9d6d053
commit 8e9b2e8ebb
5 changed files with 165 additions and 4 deletions

View file

@ -153,4 +153,87 @@ void account_object::options_type::validate() const
"May not specify fewer witnesses or committee members than the number voted for.");
}
set<object_id_type> account_member_index::get_members( const account_object& a )const
{
set<object_id_type> result;
for( auto auth : a.owner.auths )
result.insert(auth.first);
for( auto auth : a.active.auths )
result.insert(auth.first);
return result;
}
void account_member_index::object_inserted( const object& obj )
{
assert( dynamic_cast<const account_object*>(&obj) ); // for debug only
const account_object& a = static_cast<const account_object&>(obj);
set<object_id_type> members = get_members(a);
for( auto item : members )
account_to_memberships[item].insert( obj.id );
}
void account_member_index::object_removed( const object& obj )
{
assert( dynamic_cast<const account_object*>(&obj) ); // for debug only
const account_object& a = static_cast<const account_object&>(obj);
set<object_id_type> members = get_members(a);
for( auto item : members )
account_to_memberships[item].erase( obj.id );
}
void account_member_index::about_to_modify( const object& before )
{
before_members.clear();
assert( dynamic_cast<const account_object*>(&before) ); // for debug only
const account_object& a = static_cast<const account_object&>(before);
before_members = get_members(a);
}
void account_member_index::object_modified( const object& after )
{
assert( dynamic_cast<const account_object*>(&after) ); // for debug only
const account_object& a = static_cast<const account_object&>(after);
set<object_id_type> after_members = get_members(a);
vector<object_id_type> removed; removed.reserve(before_members.size());
std::set_difference( before_members.begin(), before_members.end(),
after_members.begin(), after_members.end(),
std::inserter( removed, removed.end() ) );
for( auto itr = removed.begin(); itr != removed.end(); ++itr )
account_to_memberships[*itr].erase( after.id );
vector<object_id_type> added; added.reserve(after_members.size());
auto add_end = std::set_difference( after_members.begin(), after_members.end(),
before_members.begin(), before_members.end(),
std::inserter( added, added.end()) );
for( auto itr = added.begin(); itr != added.end(); ++itr )
account_to_memberships[*itr].insert( after.id );
}
void account_referrer_index::object_inserted( const object& obj )
{
}
void account_referrer_index::object_removed( const object& obj )
{
}
void account_referrer_index::about_to_modify( const object& before )
{
}
void account_referrer_index::object_modified( const object& after )
{
}
} } // graphene::chain

View file

@ -103,7 +103,10 @@ void database::initialize_indexes()
//Protocol object indexes
add_index< primary_index<asset_index> >();
add_index< primary_index<force_settlement_index> >();
add_index< primary_index<account_index> >();
auto acnt_index = add_index< primary_index<account_index> >();
acnt_index->add_secondary_index<account_member_index>();
acnt_index->add_secondary_index<account_referrer_index>();
add_index< primary_index<simple_index<key_object>> >();
add_index< primary_index<delegate_index> >();
add_index< primary_index<witness_index> >();

View file

@ -256,6 +256,44 @@ class database;
delegate_id_type delegate_id; // optional
};
/**
* @brief This secondary index will allow a reverse lookup of all accounts that a particular key or account
* is an potential signing authority.
*/
class account_member_index : public secondary_index
{
public:
virtual void object_inserted( const object& obj ) override;
virtual void object_removed( const object& obj ) override;
virtual void about_to_modify( const object& before ) override;
virtual void object_modified( const object& after ) override;
/** given an account or key, map it to the set of accounts that reference it in an active or owner authority */
map< object_id_type, set<account_id_type> > account_to_memberships;
protected:
set<object_id_type> get_members( const account_object& a )const;
set<object_id_type> before_members;
};
/**
* @brief This secondary index will allow a reverse lookup of all accounts that have been referred by
* a particular account.
*/
class account_referrer_index : public secondary_index
{
public:
virtual void object_inserted( const object& obj ) override;
virtual void object_removed( const object& obj ) override;
virtual void about_to_modify( const object& before ) override;
virtual void object_modified( const object& after ) override;
/** maps the referrer to the set of accounts that they have referred */
map< account_id_type, set<account_id_type> > referred_by;
};
struct by_asset;
struct by_account;
struct by_balance;

View file

@ -123,6 +123,16 @@ namespace graphene { namespace db {
};
class secondary_index
{
public:
virtual ~secondary_index(){};
virtual void object_inserted( const object& obj ){};
virtual void object_removed( const object& obj ){};
virtual void about_to_modify( const object& before ){};
virtual void object_modified( const object& after ){};
};
/**
* Defines the common implementation
*/
@ -143,13 +153,32 @@ namespace graphene { namespace db {
/** called just after obj is modified */
void on_modify( const object& obj );
template<typename T>
void add_secondary_index()
{
_sindex.emplace_back( new T() );
}
template<typename T>
const T& get_secondary_index()const
{
for( const auto& item : _sindex )
{
const T* result = dynamic_cast<const T*>(item.get());
if( result != nullptr ) return *result;
}
assert( !"invalid index type" );
}
protected:
vector< shared_ptr<index_observer> > _observers;
vector< shared_ptr<index_observer> > _observers;
vector< unique_ptr<secondary_index> > _sindex;
private:
object_database& _db;
};
/**
* @class primary_index
* @brief Wraps a derived index to intercept calls to create, modify, and remove so that
@ -215,12 +244,16 @@ namespace graphene { namespace db {
virtual const object& create(const std::function<void(object&)>& constructor )override
{
const auto& result = DerivedIndex::create( constructor );
for( const auto& item : _sindex )
item->object_inserted( result );
on_add( result );
return result;
}
virtual void remove( const object& obj ) override
{
for( const auto& item : _sindex )
item->object_removed( obj );
on_remove(obj);
DerivedIndex::remove(obj);
}
@ -228,7 +261,11 @@ namespace graphene { namespace db {
virtual void modify( const object& obj, const std::function<void(object&)>& m )override
{
save_undo( obj );
for( const auto& item : _sindex )
item->about_to_modify( obj );
DerivedIndex::modify( obj, m );
for( const auto& item : _sindex )
item->object_modified( obj );
on_modify( obj );
}

View file

@ -122,7 +122,7 @@ namespace graphene { namespace db {
const T& get( object_id<SpaceID,TypeID,T> id )const { return get<T>(id); }
template<typename IndexType>
const IndexType* add_index()
IndexType* add_index()
{
typedef typename IndexType::object_type ObjectType;
if( _index[ObjectType::space_id].size() <= ObjectType::type_id )
@ -130,7 +130,7 @@ namespace graphene { namespace db {
assert(!_index[ObjectType::space_id][ObjectType::type_id]);
unique_ptr<index> indexptr( new IndexType(*this) );
_index[ObjectType::space_id][ObjectType::type_id] = std::move(indexptr);
return static_cast<const IndexType*>(_index[ObjectType::space_id][ObjectType::type_id].get());
return static_cast<IndexType*>(_index[ObjectType::space_id][ObjectType::type_id].get());
}
void pop_undo();