diff --git a/libraries/chain/include/steem/chain/comment_object.hpp b/libraries/chain/include/steem/chain/comment_object.hpp index f13a29b018..ad5701c382 100644 --- a/libraries/chain/include/steem/chain/comment_object.hpp +++ b/libraries/chain/include/steem/chain/comment_object.hpp @@ -151,7 +151,6 @@ namespace steem { namespace chain { struct by_comment_voter; struct by_voter_comment; struct by_comment_weight_voter; - struct by_voter_last_update; typedef multi_index_container< comment_vote_object, indexed_by< @@ -162,20 +161,12 @@ namespace steem { namespace chain { member< comment_vote_object, account_id_type, &comment_vote_object::voter> > >, - ordered_unique< tag< by_voter_comment >, + ordered_non_unique< tag< by_voter_comment >, composite_key< comment_vote_object, member< comment_vote_object, account_id_type, &comment_vote_object::voter>, member< comment_vote_object, comment_id_type, &comment_vote_object::comment> > >, - ordered_unique< tag< by_voter_last_update >, - composite_key< comment_vote_object, - member< comment_vote_object, account_id_type, &comment_vote_object::voter>, - member< comment_vote_object, time_point_sec, &comment_vote_object::last_update>, - member< comment_vote_object, comment_id_type, &comment_vote_object::comment> - >, - composite_key_compare< std::less< account_id_type >, std::greater< time_point_sec >, std::less< comment_id_type > > - >, ordered_unique< tag< by_comment_weight_voter >, composite_key< comment_vote_object, member< comment_vote_object, comment_id_type, &comment_vote_object::comment>, diff --git a/libraries/chain/include/steem/chain/history_object.hpp b/libraries/chain/include/steem/chain/history_object.hpp index 4788510249..1c044666e6 100644 --- a/libraries/chain/include/steem/chain/history_object.hpp +++ b/libraries/chain/include/steem/chain/history_object.hpp @@ -44,15 +44,7 @@ namespace steem { namespace chain { operation_object, indexed_by< ordered_unique< tag< by_id >, member< operation_object, operation_id_type, &operation_object::id > >, - ordered_unique< tag< by_location >, - composite_key< operation_object, - member< operation_object, uint32_t, &operation_object::block>, - member< operation_object, uint32_t, &operation_object::trx_in_block>, - member< operation_object, uint16_t, &operation_object::op_in_trx>, - member< operation_object, uint64_t, &operation_object::virtual_op>, - member< operation_object, operation_id_type, &operation_object::id> - > - > + ordered_non_unique< tag< by_location >, member< operation_object, uint32_t, &operation_object::block > > #ifndef SKIP_BY_TX_ID , ordered_unique< tag< by_transaction_id >, diff --git a/libraries/plugins/apis/account_history_api/account_history_api.cpp b/libraries/plugins/apis/account_history_api/account_history_api.cpp index 7f0748c563..7782949920 100644 --- a/libraries/plugins/apis/account_history_api/account_history_api.cpp +++ b/libraries/plugins/apis/account_history_api/account_history_api.cpp @@ -5,6 +5,8 @@ namespace steem { namespace plugins { namespace account_history { +using boost::container::flat_set; + namespace detail { class abstract_account_history_api_impl @@ -37,6 +39,8 @@ DEFINE_API_IMPL( account_history_api_chainbase_impl, get_ops_in_block ) { return _db.with_read_lock( [&]() { + std::multiset< api_operation_object > tmp_result; + const auto& idx = _db.get_index< chain::operation_index, chain::by_location >(); auto itr = idx.lower_bound( args.block_num ); get_ops_in_block_return result; @@ -44,10 +48,21 @@ DEFINE_API_IMPL( account_history_api_chainbase_impl, get_ops_in_block ) { api_operation_object temp = *itr; if( !args.only_virtual || is_virtual_operation( temp.op ) ) - result.ops.push_back( temp ); + tmp_result.emplace( std::move( temp ) ); ++itr; } - return result; + + if( !tmp_result.empty() ) + { + get_ops_in_block_return result; + + result.ops.resize( tmp_result.size() ); + std::copy( tmp_result.begin(), tmp_result.end(), result.ops.begin() ); + + return result; + } + + return get_ops_in_block_return(); }); } diff --git a/libraries/plugins/apis/account_history_api/include/steem/plugins/account_history_api/account_history_api.hpp b/libraries/plugins/apis/account_history_api/include/steem/plugins/account_history_api/account_history_api.hpp index cff04e901b..4f7826089b 100644 --- a/libraries/plugins/apis/account_history_api/include/steem/plugins/account_history_api/account_history_api.hpp +++ b/libraries/plugins/apis/account_history_api/include/steem/plugins/account_history_api/account_history_api.hpp @@ -37,6 +37,11 @@ struct api_operation_object uint64_t virtual_op = 0; fc::time_point_sec timestamp; steem::protocol::operation op; + + bool operator<( const api_operation_object& obj ) const + { + return std::tie( block, trx_in_block, op_in_trx, virtual_op ) < std::tie( obj.block, obj.trx_in_block, obj.op_in_trx, obj.virtual_op ); + } }; diff --git a/libraries/plugins/apis/database_api/database_api.cpp b/libraries/plugins/apis/database_api/database_api.cpp index e781c12b2c..5ccd510395 100644 --- a/libraries/plugins/apis/database_api/database_api.cpp +++ b/libraries/plugins/apis/database_api/database_api.cpp @@ -71,8 +71,20 @@ class database_api_impl template< typename ResultType > static ResultType on_push_default( const ResultType& r ) { return r; } - template< typename IndexType, typename OrderType, typename ValueType, typename ResultType, typename OnPush > - void iterate_results( ValueType start, vector< ResultType >& result, uint32_t limit, OnPush&& on_push = &database_api_impl::on_push_default< ResultType > ) + template< typename ValueType > + void add( flat_set< ValueType >& c, const ValueType& val ) + { + c.insert( val ); + } + + template< typename ValueType > + void add( std::vector< ValueType >& c, const ValueType& val ) + { + c.push_back( val ); + } + + template< typename IndexType, typename OrderType, template< typename... > typename Collection, typename ValueType, typename ResultType, typename OnPush > + void iterate_results( ValueType start, Collection< ResultType >& result, uint32_t limit, OnPush&& on_push = &database_api_impl::on_push_default< ResultType > ) { const auto& idx = _db.get_index< IndexType, OrderType >(); auto itr = idx.lower_bound( start ); @@ -80,7 +92,7 @@ class database_api_impl while( result.size() < limit && itr != end ) { - result.push_back( on_push( *itr ) ); + add( result, on_push( *itr ) ); ++itr; } } @@ -1077,9 +1089,40 @@ DEFINE_API_IMPL( database_api_impl, find_comments ) return result; } +template< template< typename... > typename Collection, typename ResultType > +void votes_impl( database_api_impl& _impl, Collection< ResultType >& c, size_t nr_args, uint32_t limit, vector< fc::variant >& key ) +{ + FC_ASSERT( key.size() == nr_args, "by_comment_voter start requires ${nr_args} values. (account_name_type, ${desc}account_name_type, string)", ("nr_args", nr_args )("desc",( nr_args == 4 )?"time_point_sec, ":"" ) ); -/* Votes */ + auto voter = key[0].as< account_name_type >(); + account_id_type voter_id; + + if( voter != account_name_type() ) + { + auto account = _impl._db.find< chain::account_object, chain::by_name >( voter ); + FC_ASSERT( account != nullptr, "Could not find voter ${v}.", ("v", voter ) ); + voter_id = account->id; + } + + auto author = key[ nr_args - 2 ].as< account_name_type >(); + auto permlink = key[ nr_args - 1 ].as< string >(); + comment_id_type comment_id; + + if( author != account_name_type() || permlink.size() ) + { + auto comment = _impl._db.find< chain::comment_object, chain::by_permlink >( boost::make_tuple( author, permlink ) ); + FC_ASSERT( comment != nullptr, "Could not find comment ${a}/${p}.", ("a", author)("p", permlink) ); + comment_id = comment->id; + } + + _impl.iterate_results< chain::comment_vote_index, chain::by_voter_comment >( + boost::make_tuple( voter_id, comment_id ), + c, + limit, + [&]( const comment_vote_object& cv ){ return api_comment_vote_object( cv, _impl._db ); } ); +} +/* Votes */ DEFINE_API_IMPL( database_api_impl, list_votes ) { FC_ASSERT( args.limit <= DATABASE_API_SINGLE_QUERY_LIMIT ); @@ -1125,67 +1168,24 @@ DEFINE_API_IMPL( database_api_impl, list_votes ) case( by_voter_comment ): { auto key = args.start.as< vector< fc::variant > >(); - FC_ASSERT( key.size() == 3, "by_comment_voter start requires 3 values. (account_name_type, account_name_type, string)" ); - - auto voter = key[0].as< account_name_type >(); - account_id_type voter_id; - - if( voter != account_name_type() ) - { - auto account = _db.find< chain::account_object, chain::by_name >( voter ); - FC_ASSERT( account != nullptr, "Could not find voter ${v}.", ("v", voter ) ); - voter_id = account->id; - } - - auto author = key[1].as< account_name_type >(); - auto permlink = key[2].as< string >(); - comment_id_type comment_id; - - if( author != account_name_type() || permlink.size() ) - { - auto comment = _db.find< chain::comment_object, chain::by_permlink >( boost::make_tuple( author, permlink ) ); - FC_ASSERT( comment != nullptr, "Could not find comment ${a}/${p}.", ("a", author)("p", permlink) ); - comment_id = comment->id; - } - - iterate_results< chain::comment_vote_index, chain::by_voter_comment >( - boost::make_tuple( voter_id, comment_id ), - result.votes, - args.limit, - [&]( const comment_vote_object& cv ){ return api_comment_vote_object( cv, _db ); } ); + votes_impl( *this, result.votes, 3/*nr_args*/, args.limit, key ); break; } case( by_voter_last_update ): { - auto key = args.start.as< vector< fc::variant > >(); - FC_ASSERT( key.size() == 4, "by_comment_voter start requires 4 values. (account_name_type, time_point_sec, account_name_type, string)" ); - - auto voter = key[0].as< account_name_type >(); - account_id_type voter_id; + flat_set< api_comment_vote_object > tmp_votes; - if( voter != account_name_type() ) - { - auto account = _db.find< chain::account_object, chain::by_name >( voter ); - FC_ASSERT( account != nullptr, "Could not find voter ${v}.", ("v", voter ) ); - voter_id = account->id; - } + auto key = args.start.as< vector< fc::variant > >(); + votes_impl( *this, tmp_votes, 4/*nr_args*/, std::numeric_limits::max(), key ); - auto author = key[2].as< account_name_type >(); - auto permlink = key[3].as< string >(); - comment_id_type comment_id; + auto itr = tmp_votes.lower_bound( api_comment_vote_object( key[1].as< fc::time_point_sec >() ) ); + decltype( tmp_votes.rend() ) ritr( itr ); - if( author != account_name_type() || permlink.size() ) - { - auto comment = _db.find< chain::comment_object, chain::by_permlink >( boost::make_tuple( author, permlink ) ); - FC_ASSERT( comment != nullptr, "Could not find comment ${a}/${p}.", ("a", author)("p", permlink) ); - comment_id = comment->id; - } + size_t idx = 0; + votes_impl( *this, result.votes, 3/*nr_args*/, args.limit, key ); + while( idx++ < args.limit && ritr < tmp_votes.rend() ) + result.votes.push_back( *ritr ); - iterate_results< chain::comment_vote_index, chain::by_voter_last_update >( - boost::make_tuple( voter_id, key[1].as< fc::time_point_sec >(), comment_id ), - result.votes, - args.limit, - [&]( const comment_vote_object& cv ){ return api_comment_vote_object( cv, _db ); } ); break; } case( by_comment_weight_voter ): diff --git a/libraries/plugins/apis/database_api/include/steem/plugins/database_api/database_api_objects.hpp b/libraries/plugins/apis/database_api/include/steem/plugins/database_api/database_api_objects.hpp index c2646c010c..15e8d31a09 100644 --- a/libraries/plugins/apis/database_api/include/steem/plugins/database_api/database_api_objects.hpp +++ b/libraries/plugins/apis/database_api/include/steem/plugins/database_api/database_api_objects.hpp @@ -132,6 +132,11 @@ struct api_comment_object struct api_comment_vote_object { + api_comment_vote_object( const time_point_sec& _last_update ) : last_update( _last_update ) + { + + } + api_comment_vote_object( const comment_vote_object& cv, const database& db ) : id( cv.id ), weight( cv.weight ), @@ -156,6 +161,11 @@ struct api_comment_vote_object int16_t vote_percent = 0; time_point_sec last_update; int8_t num_changes = 0; + + bool operator<( const api_comment_vote_object& obj ) const + { + return last_update < obj.last_update; + } }; struct api_account_object