提交 49238b42 编写于 作者: D Daniel Larimer

implement generic index framework

上级 19129a2d
...@@ -1047,6 +1047,7 @@ void chain_controller::_initialize_indexes() { ...@@ -1047,6 +1047,7 @@ void chain_controller::_initialize_indexes() {
_db.add_index<contracts::table_id_multi_index>(); _db.add_index<contracts::table_id_multi_index>();
_db.add_index<contracts::key_value_index>(); _db.add_index<contracts::key_value_index>();
_db.add_index<contracts::index64_index>(); _db.add_index<contracts::index64_index>();
_db.add_index<contracts::index128_index>();
_db.add_index<contracts::keystr_value_index>(); _db.add_index<contracts::keystr_value_index>();
......
...@@ -19,13 +19,196 @@ using contracts::key_value_object; ...@@ -19,13 +19,196 @@ using contracts::key_value_object;
class chain_controller; class chain_controller;
class apply_context { class apply_context {
private:
template<typename T>
class iterator_cache {
public:
typedef contracts::table_id_object table_id_object;
iterator_cache(){
_iterator_to_object.reserve(32);
}
void cache_table( const table_id_object& tobj ) {
_table_cache[tobj.id] = &tobj;
}
const table_id_object& get_table( table_id_object::id_type i ) {
auto itr = _table_cache.find(i);
FC_ASSERT( itr != _table_cache.end(), "an invariant was broken, table should be in cache" );
return *_table_cache[i];
}
const T& get( int iterator ) {
FC_ASSERT( iterator >= 0, "invalid iterator" );
FC_ASSERT( iterator < _iterator_to_object.size(), "iterator out of range" );
auto result = _iterator_to_object[iterator];
FC_ASSERT( result, "reference of deleted object" );
return *result;
}
void remove( int iterator, const T& obj ) {
_iterator_to_object[iterator] = nullptr;
_object_to_iterator.erase( &obj );
}
int add( const T& obj ) {
auto itr = _object_to_iterator.find( &obj );
if( itr != _object_to_iterator.end() )
return itr->second;
_iterator_to_object.push_back( &obj );
_object_to_iterator[&obj] = _iterator_to_object.size() - 1;
return _iterator_to_object.size() - 1;
}
private:
map<table_id_object::id_type, const table_id_object*> _table_cache;
vector<const T*> _iterator_to_object;
map<const T*,int> _object_to_iterator;
};
public: public:
template<typename ObjectType>
class generic_index
{
public:
typedef typename ObjectType::secondary_key_type secondary_key_type;
generic_index( apply_context& c ):context(c){}
int store( uint64_t scope, uint64_t table, const account_name& payer,
uint64_t id, const secondary_key_type& value )
{
FC_ASSERT( payer != account_name(), "must specify a valid account to pay for new record" );
context.require_write_lock( scope );
const auto& tab = context.find_or_create_table( scope, context.receiver, table );
const auto& obj = context.mutable_db.create<ObjectType>( [&]( auto& o ){
o.t_id = tab.id;
o.primary_key = id;
o.secondary_key = value;
o.payer = payer;
});
context.mutable_db.modify( tab, [&]( auto& t ) {
++t.count;
});
context.update_db_usage( payer, sizeof(secondary_key_type)+200 );
itr_cache.cache_table( tab );
return itr_cache.add( obj );
}
void remove( int iterator ) {
const auto& obj = itr_cache.get( iterator );
context.update_db_usage( obj.payer, -( sizeof(secondary_key_type)+200 ) );
const auto& table_obj = itr_cache.get_table( obj.t_id );
context.require_write_lock( table_obj.scope );
context.mutable_db.modify( table_obj, [&]( auto& t ) {
--t.count;
});
context.mutable_db.remove( obj );
itr_cache.remove( iterator, obj );
}
void update( int iterator, account_name payer, const secondary_key_type& secondary ) {
const auto& obj = itr_cache.get( iterator );
if( payer == account_name() ) payer = obj.payer;
if( obj.payer != payer ) {
context.update_db_usage( obj.payer, -(sizeof(secondary_key_type)+200) );
context.update_db_usage( payer, +(sizeof(secondary_key_type)+200) );
}
context.mutable_db.modify( obj, [&]( auto& o ) {
o.secondary_key = secondary;
o.payer = payer;
});
}
int find_secondary( uint64_t code, uint64_t scope, uint64_t table, const secondary_key_type& secondary ) {
auto tab = context.find_table( scope, context.receiver, table );
if( !tab ) return -1;
const auto* obj = context.db.find<ObjectType, contracts::by_secondary>( boost::make_tuple( tab->id, secondary ) );
if( !obj ) return -1;
itr_cache.cache_table( *tab );
return itr_cache.add( *obj );
}
int lowerbound_secondary( uint64_t code, uint64_t scope, uint64_t table, const secondary_key_type& secondary ) {
auto tab = context.find_table( scope, context.receiver, table );
if( !tab ) return -1;
const auto& idx = context.db.get_index< chainbase::get_index_type<ObjectType>::type, contracts::by_secondary >();
auto itr = idx.lower_bound( boost::make_tuple( tab->id, secondary ) );
if( itr == idx.end() ) return -1;
if( itr->t_id != tab.id ) return -1;
itr_cache.cache_table( *tab );
return itr_cache.add( *itr );
}
int upperbound_secondary( uint64_t code, uint64_t scope, uint64_t table, const secondary_key_type& secondary ) {
auto tab = context.find_table( scope, context.receiver, table );
if( !tab ) return -1;
const auto& idx = context.db.get_index< chainbase::get_index_type<ObjectType>::type, contracts::by_secondary >();
auto itr = idx.upper_bound( boost::make_tuple( tab->id, secondary ) );
if( itr == idx.end() ) return -1;
if( itr->t_id != tab.id ) return -1;
itr_cache.cache_table( *tab );
return itr_cache.add( *itr );
}
int find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary ) {
auto tab = context.find_table( scope, context.receiver, table );
if( !tab ) return -1;
const auto* obj = context.db.find<ObjectType, contracts::by_primary>( boost::make_tuple( tab->id, primary ) );
if( !obj ) return -1;
itr_cache.cache_table( *tab );
return itr_cache.add( *obj );
}
void get( int iterator, uint64_t& primary, secondary_key_type& secondary ) {
const auto& obj = itr_cache.get( iterator );
primary = obj.primary_key;
secondary = obj.secondary_key;
}
private:
apply_context& context;
iterator_cache<ObjectType> itr_cache;
};
apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta, uint32_t checktime_limit) apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta, uint32_t checktime_limit)
:controller(con), db(db), act(a), mutable_controller(con), :controller(con),
mutable_db(db), used_authorizations(act.authorization.size(), false), db(db),
trx_meta(trx_meta), _checktime_limit(checktime_limit) {} act(a),
mutable_controller(con),
mutable_db(db),
used_authorizations(act.authorization.size(), false),
trx_meta(trx_meta),
idx64(*this),
idx128(*this),
_checktime_limit(checktime_limit)
{}
void exec(); void exec();
...@@ -200,6 +383,8 @@ class apply_context { ...@@ -200,6 +383,8 @@ class apply_context {
const auto& tab = find_or_create_table( scope, receiver, table ); const auto& tab = find_or_create_table( scope, receiver, table );
auto tableid = tab.id; auto tableid = tab.id;
FC_ASSERT( payer != account_name(), "must specify a valid account to pay for new record" );
const auto& obj = mutable_db.create<key_value_object>( [&]( auto& o ) { const auto& obj = mutable_db.create<key_value_object>( [&]( auto& o ) {
o.t_id = tableid; o.t_id = tableid;
o.primary_key = id; o.primary_key = id;
...@@ -324,59 +509,13 @@ class apply_context { ...@@ -324,59 +509,13 @@ class apply_context {
return keyval_cache.add( *itr ); return keyval_cache.add( *itr );
} }
private:
template<typename T>
class iterator_cache {
public:
iterator_cache(){
_iterator_to_object.reserve(32);
}
void cache_table( const table_id_object& tobj ) { generic_index<contracts::index64_object> idx64;
_table_cache[tobj.id] = &tobj; generic_index<contracts::index128_object> idx128;
}
const table_id_object& get_table( table_id_object::id_type i ) {
auto itr = _table_cache.find(i);
FC_ASSERT( itr != _table_cache.end(), "an invariant was broken, table should be in cache" );
return *_table_cache[i];
}
const T& get( int iterator ) {
FC_ASSERT( iterator >= 0, "invalid iterator" );
FC_ASSERT( iterator < _iterator_to_object.size(), "iterator out of range" );
auto result = _iterator_to_object[iterator];
FC_ASSERT( result, "reference of deleted object" );
return *result;
}
void remove( int iterator, const T& obj ) {
_iterator_to_object[iterator] = nullptr;
_object_to_iterator.erase( &obj );
}
int add( const T& obj ) {
auto itr = _object_to_iterator.find( &obj );
if( itr != _object_to_iterator.end() )
return itr->second;
_iterator_to_object.push_back( &obj );
_object_to_iterator[&obj] = _iterator_to_object.size() - 1;
return _iterator_to_object.size() - 1;
}
private:
map<table_id_object::id_type, const table_id_object*> _table_cache;
vector<const T*> _iterator_to_object;
map<const T*,int> _object_to_iterator;
};
private:
iterator_cache<key_value_object> keyval_cache; iterator_cache<key_value_object> keyval_cache;
void append_results(apply_results &&other) { void append_results(apply_results &&other) {
fc::move_append(results.applied_actions, move(other.applied_actions)); fc::move_append(results.applied_actions, move(other.applied_actions));
fc::move_append(results.generated_transactions, move(other.generated_transactions)); fc::move_append(results.generated_transactions, move(other.generated_transactions));
......
...@@ -76,6 +76,52 @@ namespace eosio { namespace chain { namespace contracts { ...@@ -76,6 +76,52 @@ namespace eosio { namespace chain { namespace contracts {
> >
>; >;
struct by_primary;
struct by_secondary;
template<typename SecondaryKey, uint64_t ObjectTypeId>
struct secondary_index
{
struct index_object : public chainbase::object<ObjectTypeId,index_object> {
OBJECT_CTOR(index_object)
typedef SecondaryKey secondary_key_type;
typename chainbase::object<ObjectTypeId,index_object>::id_type id;
table_id t_id;
uint64_t primary_key;
SecondaryKey secondary_key;
account_name payer;
};
typedef chainbase::shared_multi_index_container<
index_object,
indexed_by<
ordered_unique<tag<by_id>, member<index_object, typename index_object::id_type, &index_object::id>>,
ordered_unique<tag<by_primary>,
composite_key< index_object,
member<index_object, table_id, &index_object::t_id>,
member<index_object, uint64_t, &index_object::primary_key>
>,
composite_key_compare< std::less<table_id>, std::less<uint64_t> >
>,
ordered_unique<tag<by_secondary>,
composite_key< index_object,
member<index_object, SecondaryKey, &index_object::secondary_key>,
member<index_object, uint64_t, &index_object::primary_key>
>
>
>
> index_index;
};
typedef secondary_index<uint64_t,index64_object_type>::index_object index64_object;
typedef secondary_index<uint64_t,index64_object_type>::index_index index64_index;
typedef secondary_index<uint128_t,index128_object_type>::index_object index128_object;
typedef secondary_index<uint128_t,index128_object_type>::index_index index128_index;
/*
struct index64_object : public chainbase::object<index64_object_type, index64_object> { struct index64_object : public chainbase::object<index64_object_type, index64_object> {
OBJECT_CTOR(index64_object) OBJECT_CTOR(index64_object)
...@@ -86,10 +132,9 @@ namespace eosio { namespace chain { namespace contracts { ...@@ -86,10 +132,9 @@ namespace eosio { namespace chain { namespace contracts {
table_id t_id; table_id t_id;
uint64_t primary_key; uint64_t primary_key;
uint64_t secondary_key; uint64_t secondary_key;
account_name payer;
}; };
struct by_primary;
struct by_secondary;
using index64_index = chainbase::shared_multi_index_container< using index64_index = chainbase::shared_multi_index_container<
index64_object, index64_object,
indexed_by< indexed_by<
...@@ -109,6 +154,7 @@ namespace eosio { namespace chain { namespace contracts { ...@@ -109,6 +154,7 @@ namespace eosio { namespace chain { namespace contracts {
> >
> >
>; >;
*/
...@@ -295,6 +341,7 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key64x64_value_object, eosio:: ...@@ -295,6 +341,7 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key64x64_value_object, eosio::
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key64x64x64_value_object, eosio::chain::contracts::key64x64x64_value_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key64x64x64_value_object, eosio::chain::contracts::key64x64x64_value_index)
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::index64_object, eosio::chain::contracts::index64_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::index64_object, eosio::chain::contracts::index64_index)
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::index128_object, eosio::chain::contracts::index128_index)
FC_REFLECT(eosio::chain::contracts::table_id_object, (id)(code)(scope)(table) ) FC_REFLECT(eosio::chain::contracts::table_id_object, (id)(code)(scope)(table) )
FC_REFLECT(eosio::chain::contracts::key_value_object, (id)(t_id)(primary_key)(value)(payer) ) FC_REFLECT(eosio::chain::contracts::key_value_object, (id)(t_id)(primary_key)(value)(payer) )
......
...@@ -122,6 +122,7 @@ namespace eosio { namespace chain { ...@@ -122,6 +122,7 @@ namespace eosio { namespace chain {
key128x128_value_object_type, key128x128_value_object_type,
key64x64_value_object_type, key64x64_value_object_type,
index64_object_type, index64_object_type,
index128_object_type,
action_permission_object_type, action_permission_object_type,
global_property_object_type, global_property_object_type,
dynamic_global_property_object_type, dynamic_global_property_object_type,
...@@ -176,6 +177,7 @@ FC_REFLECT_ENUM(eosio::chain::object_type, ...@@ -176,6 +177,7 @@ FC_REFLECT_ENUM(eosio::chain::object_type,
(key128x128_value_object_type) (key128x128_value_object_type)
(key64x64_value_object_type) (key64x64_value_object_type)
(index64_object_type) (index64_object_type)
(index128_object_type)
(action_permission_object_type) (action_permission_object_type)
(global_property_object_type) (global_property_object_type)
(dynamic_global_property_object_type) (dynamic_global_property_object_type)
......
...@@ -708,6 +708,27 @@ class database_api : public context_aware_api { ...@@ -708,6 +708,27 @@ class database_api : public context_aware_api {
int db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { int db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
return context.db_lowerbound_i64( code, scope, table, id ); return context.db_lowerbound_i64( code, scope, table, id );
} }
int db_idx64_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const uint64_t& secondary ) {
return context.idx64.store( scope, table, payer, id, secondary );
}
void db_idx64_update( int iterator, uint64_t payer, const uint64_t& secondary ) {
return context.idx64.update( iterator, payer, secondary );
}
void db_idx64_remove( int iterator ) {
return context.idx64.remove( iterator );
}
int db_idx128_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const uint128_t& secondary ) {
return context.idx128.store( scope, table, payer, id, secondary );
}
void db_idx128_update( int iterator, uint64_t payer, const uint128_t& secondary ) {
return context.idx128.update( iterator, payer, secondary );
}
void db_idx128_remove( int iterator ) {
return context.idx128.remove( iterator );
}
}; };
...@@ -944,6 +965,15 @@ REGISTER_INTRINSICS( database_api, ...@@ -944,6 +965,15 @@ REGISTER_INTRINSICS( database_api,
(db_next_i64, int(int)) (db_next_i64, int(int))
(db_find_i64, int(int64_t,int64_t,int64_t,int64_t)) (db_find_i64, int(int64_t,int64_t,int64_t,int64_t))
(db_lowerbound_i64, int(int64_t,int64_t,int64_t,int64_t)) (db_lowerbound_i64, int(int64_t,int64_t,int64_t,int64_t))
(db_idx64_store, int(int64_t,int64_t,int64_t,int64_t,int))
(db_idx64_remove, void(int))
(db_idx64_update, void(int,int64_t,int))
(db_idx128_store, int(int64_t,int64_t,int64_t,int64_t,int))
(db_idx128_remove, void(int))
(db_idx128_update, void(int,int64_t,int))
) )
REGISTER_INTRINSICS(crypto_api, REGISTER_INTRINSICS(crypto_api,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册