提交 352fa9b4 编写于 作者: D Daniel Larimer

add new iterator based db api

上级 df878838
......@@ -1040,8 +1040,14 @@ void chain_controller::_initialize_indexes() {
_db.add_index<permission_usage_index>();
_db.add_index<permission_link_index>();
_db.add_index<action_permission_index>();
_db.add_index<contracts::table_id_multi_index>();
_db.add_index<contracts::key_value_index>();
_db.add_index<contracts::index64_index>();
_db.add_index<contracts::keystr_value_index>();
_db.add_index<contracts::key128x128_value_index>();
_db.add_index<contracts::key64x64_value_index>();
......
......@@ -14,6 +14,8 @@ namespace chainbase { class database; }
namespace eosio { namespace chain {
using contracts::key_value_object;
class chain_controller;
class apply_context {
......@@ -185,7 +187,196 @@ class apply_context {
void checktime() const;
void update_db_usage( const account_name& payer, int64_t delta ) {
require_write_lock( payer );
if( (delta > 0) && payer != account_name(receiver) ) {
require_authorization( payer );
}
}
int db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) {
require_write_lock( scope );
const auto& tab = find_or_create_table( scope, receiver, table );
auto tableid = tab.id;
const auto& obj = mutable_db.create<key_value_object>( [&]( auto& o ) {
o.t_id = tableid;
o.primary_key = id;
o.value.resize( buffer_size );
o.payer = payer;
memcpy( o.value.data(), buffer, buffer_size );
});
mutable_db.modify( tab, [&]( auto& t ) {
++t.count;
});
update_db_usage( payer, buffer_size + 200 );
keyval_cache.cache_table( tab );
return keyval_cache.add( obj );
}
void db_update_i64( int iterator, account_name payer, const char* buffer, size_t buffer_size ) {
const key_value_object& obj = keyval_cache.get( iterator );
require_write_lock( keyval_cache.get_table( obj.t_id ).scope );
int64_t old_size = obj.value.size();
if( payer == account_name() ) payer = obj.payer;
if( account_name(obj.payer) == payer ) {
update_db_usage( obj.payer, buffer_size + 200 - old_size );
} else {
update_db_usage( obj.payer, -(old_size+200) );
update_db_usage( payer, (buffer_size+200) );
}
mutable_db.modify( obj, [&]( auto& o ) {
o.value.resize( buffer_size );
memcpy( o.value.data(), buffer, buffer_size );
o.payer = payer;
});
}
void db_remove_i64( int iterator ) {
const key_value_object& obj = keyval_cache.get( iterator );
update_db_usage( obj.payer, -(obj.value.size()+200) );
const auto& table_obj = keyval_cache.get_table( obj.t_id );
require_write_lock( table_obj.scope );
mutable_db.modify( table_obj, [&]( auto& t ) {
--t.count;
});
mutable_db.remove( obj );
keyval_cache.remove( iterator, obj );
}
int db_get_i64( int iterator, uint64_t& id, char* buffer, size_t buffer_size ) {
const key_value_object& obj = keyval_cache.get( iterator );
if( buffer_size >= obj.value.size() ) {
memcpy( buffer, obj.value.data(), obj.value.size() );
}
id = obj.primary_key;
return obj.value.size();
}
int db_next_i64( int iterator ) {
const auto& obj = keyval_cache.get( iterator );
const auto& idx = db.get_index<contracts::key_value_index, contracts::by_scope_primary>();
auto itr = idx.iterator_to( obj );
++itr;
if( itr == idx.end() ) return -1;
if( itr->t_id != obj.t_id ) return -1;
return keyval_cache.add( *itr );
}
int db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
require_read_lock( code, scope );
const auto* tab = find_table( scope, code, table );
if( !tab ) return -1;
const key_value_object* obj = db.find<key_value_object, contracts::by_scope_primary>( boost::make_tuple( tab->id, id ) );
if( !obj ) return -1;
keyval_cache.cache_table( *tab );
return keyval_cache.add( *obj );
}
int db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
require_read_lock( code, scope );
const auto* tab = find_table( scope, code, table );
if( !tab ) return -1;
const auto& idx = db.get_index<contracts::key_value_index, contracts::by_scope_primary>();
auto itr = idx.lower_bound( boost::make_tuple( tab->id, id ) );
if( itr == idx.end() ) return -1;
if( itr->t_id != tab->id ) return -1;
keyval_cache.cache_table( *tab );
return keyval_cache.add( *itr );
}
int db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
require_read_lock( code, scope );
const auto* tab = find_table( scope, code, table );
if( !tab ) return -1;
const auto& idx = db.get_index<contracts::key_value_index, contracts::by_scope_primary>();
auto itr = idx.upper_bound( boost::make_tuple( tab->id, id ) );
if( itr == idx.end() ) return -1;
if( itr->t_id != tab->id ) return -1;
keyval_cache.cache_table( *tab );
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 ) {
_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;
};
iterator_cache<key_value_object> keyval_cache;
void append_results(apply_results &&other) {
fc::move_append(results.applied_actions, move(other.applied_actions));
fc::move_append(results.generated_transactions, move(other.generated_transactions));
......
......@@ -21,6 +21,7 @@ namespace eosio { namespace chain { namespace contracts {
scope_name scope;
account_name code;
table_name table;
uint32_t count = 0; /// the number of elements in the table
};
struct by_scope_code_table;
......@@ -57,6 +58,7 @@ namespace eosio { namespace chain { namespace contracts {
table_id t_id;
uint64_t primary_key;
shared_string value;
uint64_t payer = 0;
};
using key_value_index = chainbase::shared_multi_index_container<
......@@ -73,6 +75,44 @@ namespace eosio { namespace chain { namespace contracts {
>
>;
struct index64_object : public chainbase::object<index64_object_type, index64_object> {
OBJECT_CTOR(index64_object)
typedef uint64_t key_type;
static const int number_of_keys = 1;
id_type id;
table_id t_id;
uint64_t primary_key;
uint64_t secondary_key;
};
struct by_primary;
struct by_secondary;
using index64_index = chainbase::shared_multi_index_container<
index64_object,
indexed_by<
ordered_unique<tag<by_id>, member<index64_object, index64_object::id_type, &index64_object::id>>,
ordered_unique<tag<by_primary>,
composite_key< index64_object,
member<index64_object, table_id, &index64_object::t_id>,
member<index64_object, uint64_t, &index64_object::primary_key>
>,
composite_key_compare< std::less<table_id>, std::less<uint64_t> >
>,
ordered_unique<tag<by_secondary>,
composite_key< index64_object,
member<index64_object, uint64_t, &index64_object::secondary_key>,
member<index64_object, uint64_t, &index64_object::primary_key>
>
>
>
>;
struct shared_string_less {
bool operator()( const char* a, const char* b )const {
return less(a, b);
......@@ -249,8 +289,12 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key128x128_value_object, eosio
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key64x64_value_object, eosio::chain::contracts::key64x64_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)
FC_REFLECT(eosio::chain::contracts::table_id_object, (id)(scope)(code)(table) )
FC_REFLECT(eosio::chain::contracts::key_value_object, (id)(t_id)(primary_key)(value) )
FC_REFLECT(eosio::chain::contracts::index64_object, (id)(t_id)(primary_key)(secondary_key) )
FC_REFLECT(eosio::chain::contracts::keystr_value_object, (id)(t_id)(primary_key)(value) )
FC_REFLECT(eosio::chain::contracts::key128x128_value_object, (id)(t_id)(primary_key)(secondary_key)(value) )
FC_REFLECT(eosio::chain::contracts::key64x64_value_object, (id)(t_id)(primary_key)(secondary_key)(value) )
......
......@@ -121,6 +121,7 @@ namespace eosio { namespace chain {
key_value_object_type,
key128x128_value_object_type,
key64x64_value_object_type,
index64_object_type,
action_permission_object_type,
global_property_object_type,
dynamic_global_property_object_type,
......@@ -174,6 +175,7 @@ FC_REFLECT_ENUM(eosio::chain::object_type,
(key_value_object_type)
(key128x128_value_object_type)
(key64x64_value_object_type)
(index64_object_type)
(action_permission_object_type)
(global_property_object_type)
(dynamic_global_property_object_type)
......
......@@ -680,6 +680,36 @@ class console_api : public context_aware_api {
}
};
class database_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
int db_store_i64( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, array_ptr<const char> buffer, size_t buffer_size ) {
return context.db_store_i64( scope, table, payer, id, buffer, buffer_size );
}
void db_update_i64( int itr, uint64_t payer, array_ptr<const char> buffer, size_t buffer_size ) {
context.db_update_i64( itr, payer, buffer, buffer_size );
}
void db_remove_i64( int itr ) {
context.db_remove_i64( itr );
}
int db_get_i64( int itr, uint64_t& id, array_ptr<char> buffer, size_t buffer_size ) {
return context.db_get_i64( itr, id, buffer, buffer_size );
}
int db_next_i64( int itr ) { return context.db_next_i64(itr); }
int db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
return context.db_find_i64( code, scope, table, id );
}
int db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) {
return context.db_lowerbound_i64( code, scope, table, 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 );
}
};
template<typename ObjectType>
class db_api : public context_aware_api {
using KeyType = typename ObjectType::key_type;
......@@ -905,6 +935,16 @@ REGISTER_INTRINSICS(producer_api,
(get_active_producers, int(int, int))
);
REGISTER_INTRINSICS( database_api,
(db_store_i64, int(int64_t,int64_t,int64_t,int64_t,int,int))
(db_update_i64, void(int,int64_t,int,int))
(db_remove_i64, void(int))
(db_get_i64, int(int, int, int, int))
(db_next_i64, int(int))
(db_find_i64, int(int64_t,int64_t,int64_t,int64_t))
(db_lowerbound_i64, int(int64_t,int64_t,int64_t,int64_t))
)
REGISTER_INTRINSICS(crypto_api,
(assert_recover_key, void(int, int, int, int, int))
(recover_key, int(int, int, int, int, int))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册