13namespace sysio {
namespace chain {
16class transaction_context;
21 class iterator_cache {
24 _end_iterator_to_table.reserve(8);
25 _iterator_to_object.reserve(32);
30 auto itr = _table_cache.find(tobj.id);
31 if( itr != _table_cache.end() )
32 return itr->second.second;
34 auto ei = index_to_end_iterator(_end_iterator_to_table.size());
35 _end_iterator_to_table.push_back( &tobj );
36 _table_cache.emplace( tobj.id, make_pair(&tobj, ei) );
41 auto itr = _table_cache.find(i);
42 SYS_ASSERT( itr != _table_cache.end(), table_not_in_cache,
"an invariant was broken, table should be in cache" );
43 return *itr->second.first;
47 auto itr = _table_cache.find(i);
48 SYS_ASSERT( itr != _table_cache.end(), table_not_in_cache,
"an invariant was broken, table should be in cache" );
49 return itr->second.second;
53 SYS_ASSERT( ei < -1, invalid_table_iterator,
"not an end iterator" );
54 auto indx = end_iterator_to_index(ei);
55 if( indx >= _end_iterator_to_table.size() )
return nullptr;
56 return _end_iterator_to_table[indx];
59 const T& get(
int iterator ) {
60 SYS_ASSERT( iterator != -1, invalid_table_iterator,
"invalid iterator" );
61 SYS_ASSERT( iterator >= 0, table_operation_not_permitted,
"dereference of end iterator" );
62 SYS_ASSERT( (
size_t)iterator < _iterator_to_object.size(), invalid_table_iterator,
"iterator out of range" );
63 auto result = _iterator_to_object[iterator];
64 SYS_ASSERT( result, table_operation_not_permitted,
"dereference of deleted object" );
68 void remove(
int iterator ) {
69 SYS_ASSERT( iterator != -1, invalid_table_iterator,
"invalid iterator" );
70 SYS_ASSERT( iterator >= 0, table_operation_not_permitted,
"cannot call remove on end iterators" );
71 SYS_ASSERT( (
size_t)iterator < _iterator_to_object.size(), invalid_table_iterator,
"iterator out of range" );
73 auto obj_ptr = _iterator_to_object[iterator];
74 if( !obj_ptr )
return;
75 _iterator_to_object[iterator] =
nullptr;
76 _object_to_iterator.erase( obj_ptr );
79 int add(
const T& obj ) {
80 auto itr = _object_to_iterator.find( &obj );
81 if( itr != _object_to_iterator.end() )
84 _iterator_to_object.push_back( &obj );
85 _object_to_iterator[&obj] = _iterator_to_object.size() - 1;
87 return _iterator_to_object.size() - 1;
91 map<table_id_object::id_type, pair<const table_id_object*, int>> _table_cache;
94 map<const T*,int> _object_to_iterator;
98 inline size_t end_iterator_to_index(
int ei )
const {
return (-ei - 2); }
100 inline int index_to_end_iterator(
size_t indx )
const {
return -(indx + 2); }
106 template<
typename T,
size_t N>
107 struct array_size<
std::
array<T,N> > {
108 static constexpr size_t size =
N;
111 template <
typename SecondaryKey,
typename SecondaryKeyProxy,
typename SecondaryKeyProxyConst,
typename Enable =
void>
112 class secondary_key_helper;
114 template<
typename SecondaryKey,
typename SecondaryKeyProxy,
typename SecondaryKeyProxyConst>
115 class secondary_key_helper<SecondaryKey, SecondaryKeyProxy, SecondaryKeyProxyConst,
116 typename
std::enable_if<std::is_same<SecondaryKey, typename std::decay<SecondaryKeyProxy>::type>::value>::type >
119 typedef SecondaryKey secondary_key_type;
121 static void set(secondary_key_type& sk_in_table,
const secondary_key_type& sk_from_wasm) {
122 sk_in_table = sk_from_wasm;
125 static void get(secondary_key_type& sk_from_wasm,
const secondary_key_type& sk_in_table ) {
126 sk_from_wasm = sk_in_table;
129 static auto create_tuple(
const table_id_object& tab,
const secondary_key_type& secondary) {
130 return boost::make_tuple( tab.id, secondary );
134 template<
typename SecondaryKey,
typename SecondaryKeyProxy,
typename SecondaryKeyProxyConst>
135 class secondary_key_helper<SecondaryKey, SecondaryKeyProxy, SecondaryKeyProxyConst,
136 typename
std::enable_if<!std::is_same<SecondaryKey, typename std::decay<SecondaryKeyProxy>::type>::value &&
137 std::is_pointer<typename std::decay<SecondaryKeyProxy>::type>::value>::type >
140 typedef SecondaryKey secondary_key_type;
141 typedef SecondaryKeyProxy secondary_key_proxy_type;
142 typedef SecondaryKeyProxyConst secondary_key_proxy_const_type;
144 static constexpr size_t N = array_size<SecondaryKey>::size;
146 static void set(secondary_key_type& sk_in_table, secondary_key_proxy_const_type sk_from_wasm) {
147 std::copy(sk_from_wasm, sk_from_wasm +
N, sk_in_table.begin());
150 static void get(secondary_key_proxy_type sk_from_wasm,
const secondary_key_type& sk_in_table) {
151 std::copy(sk_in_table.begin(), sk_in_table.end(), sk_from_wasm);
154 static auto create_tuple(
const table_id_object& tab, secondary_key_proxy_const_type sk_from_wasm) {
155 secondary_key_type secondary;
156 std::copy(sk_from_wasm, sk_from_wasm +
N, secondary.begin());
157 return boost::make_tuple( tab.id, secondary );
162 template<
typename ObjectType,
163 typename SecondaryKeyProxy =
typename std::add_lvalue_reference<typename ObjectType::secondary_key_type>::type,
164 typename SecondaryKeyProxyConst =
typename std::add_lvalue_reference<
165 typename std::add_const<typename ObjectType::secondary_key_type>::type>::type >
173 using secondary_key_helper_t = secondary_key_helper<secondary_key_type, secondary_key_proxy_type, secondary_key_proxy_const_type>;
180 SYS_ASSERT( payer !=
account_name(), invalid_table_payer,
"must specify a valid account to pay for new record" );
186 const auto& obj =
context.db.create<ObjectType>( [&](
auto& o ){
189 secondary_key_helper_t::set(o.secondary_key,
value);
193 context.db.modify( tab, [&](
auto& t ) {
196 if (
auto dm_logger =
context.control.get_deep_mind_logger()) {
197 std::string event_id =
RAM_EVENT_ID(
"${code}:${scope}:${table}:${index_name}",
201 (
"index_name",
name(
id))
203 dm_logger->on_ram_trace(std::move(event_id),
"secondary_index",
"add",
"secondary_index_add");
209 itr_cache.cache_table( tab );
210 return itr_cache.add( obj );
214 const auto& obj = itr_cache.get( iterator );
216 const auto& table_obj = itr_cache.get_table( obj.t_id );
217 SYS_ASSERT( table_obj.code ==
context.receiver, table_access_violation,
"db access violation" );
219 if (
auto dm_logger =
context.control.get_deep_mind_logger()) {
220 std::string event_id =
RAM_EVENT_ID(
"${code}:${scope}:${table}:${index_name}",
221 (
"code", table_obj.code)
222 (
"scope", table_obj.scope)
223 (
"table", table_obj.table)
224 (
"index_name",
name(obj.primary_key))
226 dm_logger->on_ram_trace(std::move(event_id),
"secondary_index",
"remove",
"secondary_index_remove");
233 context.db.modify( table_obj, [&](
auto& t ) {
238 if (table_obj.count == 0) {
239 context.remove_table(table_obj);
242 itr_cache.remove( iterator );
246 const auto& obj = itr_cache.get( iterator );
248 const auto& table_obj = itr_cache.get_table( obj.t_id );
249 SYS_ASSERT( table_obj.code ==
context.receiver, table_access_violation,
"db access violation" );
257 std::string event_id;
258 if (
context.control.get_deep_mind_logger() !=
nullptr) {
259 event_id =
RAM_EVENT_ID(
"${code}:${scope}:${table}:${index_name}",
260 (
"code", table_obj.code)
261 (
"scope", table_obj.scope)
262 (
"table", table_obj.table)
263 (
"index_name",
name(obj.primary_key))
267 if( obj.payer != payer ) {
268 if (
auto dm_logger =
context.control.get_deep_mind_logger())
270 dm_logger->on_ram_trace(std::string(event_id),
"secondary_index",
"remove",
"secondary_index_remove");
272 context.update_db_usage( obj.payer, -(billing_size) );
273 if (
auto dm_logger =
context.control.get_deep_mind_logger())
275 dm_logger->on_ram_trace(std::move(event_id),
"secondary_index",
"add",
"secondary_index_update_add_new_payer");
277 context.update_db_usage( payer, +(billing_size) );
280 context.db.modify( obj, [&](
auto& o ) {
281 secondary_key_helper_t::set(o.secondary_key, secondary);
288 if( !tab )
return -1;
290 auto table_end_itr = itr_cache.cache_table( *tab );
292 const auto* obj =
context.db.find<ObjectType,
by_secondary>( secondary_key_helper_t::create_tuple( *tab, secondary ) );
293 if( !obj )
return table_end_itr;
295 primary = obj->primary_key;
297 return itr_cache.add( *obj );
302 if( !tab )
return -1;
304 auto table_end_itr = itr_cache.cache_table( *tab );
307 auto itr = idx.lower_bound( secondary_key_helper_t::create_tuple( *tab, secondary ) );
308 if( itr == idx.end() )
return table_end_itr;
309 if( itr->t_id != tab->id )
return table_end_itr;
311 primary = itr->primary_key;
312 secondary_key_helper_t::get(secondary, itr->secondary_key);
314 return itr_cache.add( *itr );
319 if( !tab )
return -1;
321 auto table_end_itr = itr_cache.cache_table( *tab );
324 auto itr = idx.upper_bound( secondary_key_helper_t::create_tuple( *tab, secondary ) );
325 if( itr == idx.end() )
return table_end_itr;
326 if( itr->t_id != tab->id )
return table_end_itr;
328 primary = itr->primary_key;
329 secondary_key_helper_t::get(secondary, itr->secondary_key);
331 return itr_cache.add( *itr );
336 if( !tab )
return -1;
338 return itr_cache.cache_table( *tab );
342 if( iterator < -1 )
return -1;
344 const auto& obj = itr_cache.get(iterator);
347 auto itr = idx.iterator_to(obj);
350 if( itr == idx.end() || itr->t_id != obj.t_id )
return itr_cache.get_end_iterator_by_table_id(obj.t_id);
352 primary = itr->primary_key;
353 return itr_cache.add(*itr);
361 auto tab = itr_cache.find_table_by_end_iterator(iterator);
362 SYS_ASSERT( tab, invalid_table_iterator,
"not a valid end iterator" );
364 auto itr = idx.upper_bound(tab->id);
365 if( idx.begin() == idx.end() || itr == idx.begin() )
return -1;
369 if( itr->t_id != tab->id )
return -1;
371 primary = itr->primary_key;
372 return itr_cache.add(*itr);
375 const auto& obj = itr_cache.get(iterator);
377 auto itr = idx.iterator_to(obj);
378 if( itr == idx.begin() )
return -1;
382 if( itr->t_id != obj.t_id )
return -1;
384 primary = itr->primary_key;
385 return itr_cache.add(*itr);
390 if( !tab )
return -1;
392 auto table_end_itr = itr_cache.cache_table( *tab );
394 const auto* obj =
context.db.find<ObjectType, by_primary>( boost::make_tuple( tab->id, primary ) );
395 if( !obj )
return table_end_itr;
396 secondary_key_helper_t::get(secondary, obj->secondary_key);
398 return itr_cache.add( *obj );
405 auto table_end_itr = itr_cache.cache_table( *tab );
408 auto itr = idx.lower_bound(boost::make_tuple(tab->id, primary));
409 if (itr == idx.end())
return table_end_itr;
410 if (itr->t_id != tab->id)
return table_end_itr;
412 return itr_cache.add(*itr);
417 if ( !tab )
return -1;
419 auto table_end_itr = itr_cache.cache_table( *tab );
422 auto itr = idx.upper_bound(boost::make_tuple(tab->id, primary));
423 if (itr == idx.end())
return table_end_itr;
424 if (itr->t_id != tab->id)
return table_end_itr;
426 itr_cache.cache_table(*tab);
427 return itr_cache.add(*itr);
431 if( iterator < -1 )
return -1;
433 const auto& obj = itr_cache.get(iterator);
436 auto itr = idx.iterator_to(obj);
439 if( itr == idx.end() || itr->t_id != obj.t_id )
return itr_cache.get_end_iterator_by_table_id(obj.t_id);
441 primary = itr->primary_key;
442 return itr_cache.add(*itr);
450 auto tab = itr_cache.find_table_by_end_iterator(iterator);
451 SYS_ASSERT( tab, invalid_table_iterator,
"not a valid end iterator" );
453 auto itr = idx.upper_bound(tab->id);
454 if( idx.begin() == idx.end() || itr == idx.begin() )
return -1;
458 if( itr->t_id != tab->id )
return -1;
460 primary = itr->primary_key;
461 return itr_cache.add(*itr);
464 const auto& obj = itr_cache.get(iterator);
466 auto itr = idx.iterator_to(obj);
467 if( itr == idx.begin() )
return -1;
471 if( itr->t_id != obj.t_id )
return -1;
473 primary = itr->primary_key;
474 return itr_cache.add(*itr);
478 const auto& obj = itr_cache.get( iterator );
479 primary = obj.primary_key;
480 secondary_key_helper_t::get(secondary, obj.secondary_key);
485 iterator_cache<ObjectType> itr_cache;
548 _pending_console_output += val;
559 int db_get_i64(
int iterator,
char* buffer,
size_t buffer_size );
606 const action* act =
nullptr;
610 uint32_t first_receiver_action_ordinal = 0;
612 bool privileged =
false;
613 bool context_free =
false;
625 iterator_cache<key_value_object> keyval_cache;
629 std::string _pending_console_output;
630 flat_set<account_delta> _account_ram_deltas;
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
void get(int iterator, uint64_t &primary, secondary_key_proxy_type secondary)
void update(int iterator, account_name payer, secondary_key_proxy_const_type secondary)
ObjectType::secondary_key_type secondary_key_type
int upperbound_secondary(uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_type secondary, uint64_t &primary)
secondary_key_helper< secondary_key_type, secondary_key_proxy_type, secondary_key_proxy_const_type > secondary_key_helper_t
int lowerbound_primary(uint64_t code, uint64_t scope, uint64_t table, uint64_t primary)
int end_secondary(uint64_t code, uint64_t scope, uint64_t table)
int lowerbound_secondary(uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_type secondary, uint64_t &primary)
int previous_primary(int iterator, uint64_t &primary)
int find_primary(uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_type secondary, uint64_t primary)
int upperbound_primary(uint64_t code, uint64_t scope, uint64_t table, uint64_t primary)
int find_secondary(uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_const_type secondary, uint64_t &primary)
SecondaryKeyProxyConst secondary_key_proxy_const_type
int previous_secondary(int iterator, uint64_t &primary)
generic_index(apply_context &c)
int next_primary(int iterator, uint64_t &primary)
SecondaryKeyProxy secondary_key_proxy_type
int store(uint64_t scope, uint64_t table, const account_name &payer, uint64_t id, secondary_key_proxy_const_type value)
int next_secondary(int iterator, uint64_t &primary)
void remove(int iterator)
void require_recipient(account_name account)
bool cancel_deferred_transaction(const uint128_t &sender_id)
uint32_t schedule_action(uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free)
void add_ram_usage(account_name account, int64_t ram_delta)
std::vector< char > action_return_value
vector< account_name > get_active_producers() const
bool cancel_deferred_transaction(const uint128_t &sender_id, account_name sender)
int db_lowerbound_i64(name code, name scope, name table, uint64_t id)
const action & get_action() const
uint64_t next_global_sequence()
generic_index< index_long_double_object > idx_long_double
void exec_one()
Execution methods:
bool is_privileged() const
void update_db_usage(const account_name &payer, int64_t delta)
Database methods:
int db_find_i64(name code, name scope, name table, uint64_t id)
int get_context_free_data(uint32_t index, char *buffer, size_t buffer_size) const
int db_store_i64(name scope, name table, const account_name &payer, uint64_t id, const char *buffer, size_t buffer_size)
generic_index< index_double_object > idx_double
int db_get_i64(int iterator, char *buffer, size_t buffer_size)
controller & control
Fields:
int db_upperbound_i64(name code, name scope, name table, uint64_t id)
bool is_context_free() const
int db_next_i64(int iterator, uint64_t &primary)
void require_authorization(const account_name &account)
Authorization methods:
apply_context(controller &con, transaction_context &trx_ctx, uint32_t action_ordinal, uint32_t depth=0)
class generic_index
bool has_authorization(const account_name &account) const
void finalize_trace(action_trace &trace, const fc::time_point &start)
generic_index< index128_object > idx128
void execute_inline(action &&a)
bool is_account(const account_name &account) const
exec()
transaction_context & trx_context
transaction context in which the action is running
uint64_t next_auth_sequence(account_name actor)
void db_update_i64(int iterator, account_name payer, const char *buffer, size_t buffer_size)
action_name get_sender() const
int db_previous_i64(int iterator, uint64_t &primary)
void db_remove_i64(int iterator)
void schedule_deferred_transaction(const uint128_t &sender_id, account_name payer, transaction &&trx, bool replace_existing)
chainbase::database & db
database where state is stored
uint64_t next_recv_sequence(const account_metadata_object &receiver_account)
action_name get_receiver() const
int db_end_i64(name code, name scope, name table)
bool has_recipient(account_name account) const
void console_append(std::string_view val)
Console methods:
void execute_context_free_inline(action &&a)
generic_index< index256_object, uint128_t *, const uint128_t * > idx256
generic_index< index64_object > idx64
The table_id_object class tracks the mapping of (scope, code, table) to an opaque identifier.
#define RAM_EVENT_ID(FORMAT,...)
constexpr uint64_t billable_size_v
sysio::chain::action_name action_name
unsigned __int128 uint128_t
std::function< void(apply_context &)> apply_handler
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
#define T(meth, val, expected)
unsigned __int64 uint64_t
Immutable except for fc::from_variant.