Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
resource_limits_private.hpp
Go to the documentation of this file.
1#pragma once
6
8
9
10namespace sysio { namespace chain { namespace resource_limits {
11
12 namespace impl {
13 template<typename T>
15 return ratio<T>{n, d};
16 }
17
18 template<typename T>
20 SYS_ASSERT(r.numerator == T(0) || std::numeric_limits<T>::max() / r.numerator >= value, rate_limiting_state_inconsistent, "Usage exceeds maximum value representable after extending for precision");
21 return (value * r.numerator) / r.denominator;
22 }
23
24 template<typename UnsignedIntType>
25 constexpr UnsignedIntType integer_divide_ceil(UnsignedIntType num, UnsignedIntType den ) {
26 return (num / den) + ((num % den) > 0 ? 1 : 0);
27 }
28
29
30 template<typename LesserIntType, typename GreaterIntType>
31 constexpr bool is_valid_downgrade_cast =
32 std::is_integral<LesserIntType>::value && // remove overloads where type is not integral
33 std::is_integral<GreaterIntType>::value && // remove overloads where type is not integral
34 (std::numeric_limits<LesserIntType>::max() <= std::numeric_limits<GreaterIntType>::max()); // remove overloads which are upgrades not downgrades
35
39 template<typename LesserIntType, typename GreaterIntType>
40 constexpr auto downgrade_cast(GreaterIntType val) ->
41 std::enable_if_t<is_valid_downgrade_cast<LesserIntType,GreaterIntType> && std::is_signed<LesserIntType>::value == std::is_signed<GreaterIntType>::value, LesserIntType>
42 {
43 const GreaterIntType max = std::numeric_limits<LesserIntType>::max();
44 const GreaterIntType min = std::numeric_limits<LesserIntType>::min();
45 SYS_ASSERT( val >= min && val <= max, rate_limiting_state_inconsistent, "Casting a higher bit integer value ${v} to a lower bit integer value which cannot contain the value, valid range is [${min}, ${max}]", ("v", val)("min", min)("max",max) );
46 return LesserIntType(val);
47 };
48
52 template<typename LesserIntType, typename GreaterIntType>
53 constexpr auto downgrade_cast(GreaterIntType val) ->
54 std::enable_if_t<is_valid_downgrade_cast<LesserIntType,GreaterIntType> && std::is_signed<LesserIntType>::value != std::is_signed<GreaterIntType>::value, LesserIntType>
55 {
56 const GreaterIntType max = std::numeric_limits<LesserIntType>::max();
57 const GreaterIntType min = 0;
58 SYS_ASSERT( val >= min && val <= max, rate_limiting_state_inconsistent, "Casting a higher bit integer value ${v} to a lower bit integer value which cannot contain the value, valid range is [${min}, ${max}]", ("v", val)("min", min)("max",max) );
59 return LesserIntType(val);
60 };
61
68 template<uint64_t Precision = config::rate_limiting_precision>
70 {
71 static_assert( Precision > 0, "Precision must be positive" );
72 static constexpr uint64_t max_raw_value = std::numeric_limits<uint64_t>::max() / Precision;
73
80
84
88 uint64_t average() const {
89 return integer_divide_ceil(value_ex, Precision);
90 }
91
92 void add( uint64_t units, uint32_t ordinal, uint32_t window_size /* must be positive */ )
93 {
94 // check for some numerical limits before doing any state mutations
95 SYS_ASSERT(units <= max_raw_value, rate_limiting_state_inconsistent, "Usage exceeds maximum value representable after extending for precision");
96 SYS_ASSERT(std::numeric_limits<decltype(consumed)>::max() - consumed >= units, rate_limiting_state_inconsistent, "Overflow in tracked usage when adding usage!");
97
98 auto value_ex_contrib = downgrade_cast<uint64_t>(integer_divide_ceil((uint128_t)units * Precision, (uint128_t)window_size));
99 SYS_ASSERT(std::numeric_limits<decltype(value_ex)>::max() - value_ex >= value_ex_contrib, rate_limiting_state_inconsistent, "Overflow in accumulated value when adding usage!");
100
101 if( last_ordinal != ordinal ) {
102 SYS_ASSERT( ordinal > last_ordinal, resource_limit_exception, "new ordinal cannot be less than the previous ordinal" );
103 if( (uint64_t)last_ordinal + window_size > (uint64_t)ordinal ) {
104 const auto delta = ordinal - last_ordinal; // clearly 0 < delta < window_size
105 const auto decay = make_ratio(
106 (uint64_t)window_size - delta,
107 (uint64_t)window_size
108 );
109
110 value_ex = value_ex * decay;
111 } else {
112 value_ex = 0;
113 }
114
115 last_ordinal = ordinal;
116 consumed = average();
117 }
118
119 consumed += units;
120 value_ex += value_ex_contrib;
121 }
122 };
123
130 template<uint64_t Precision = config::rate_limiting_precision>
132 {
133 static_assert( Precision > 0, "Precision must be positive" );
134 static constexpr uint64_t max_raw_value = std::numeric_limits<uint64_t>::max() / Precision;
135
137 : last_ordinal(0)
138 , value_ex(0)
139 {
140 }
141
144
148 uint64_t value_ex_at( uint32_t ordinal, uint32_t window_size ) const {
149 if( last_ordinal < ordinal ) {
150 if( (uint64_t)last_ordinal + window_size > (uint64_t)ordinal ) {
151 const auto delta = ordinal - last_ordinal; // clearly 0 < delta < window_size
152 const auto decay = make_ratio(
153 (uint128_t)window_size - delta,
154 (uint128_t)window_size
155 );
156
158 } else {
159 return 0;
160 }
161 } else {
162 return value_ex;
163 }
164 }
165
169 uint64_t value_at( uint32_t ordinal, uint32_t window_size ) const {
170 return integer_divide_ceil(value_ex_at(ordinal, window_size), Precision);
171 }
172
173 void add( uint64_t units, uint32_t ordinal, uint32_t window_size /* must be positive */ )
174 {
175 // check for some numerical limits before doing any state mutations
176 SYS_ASSERT(units <= max_raw_value, rate_limiting_state_inconsistent, "Usage exceeds maximum value representable after extending for precision");
177
178 uint128_t units_ex = (uint128_t)units * Precision;
179 if (last_ordinal < ordinal) {
180 value_ex = value_ex_at(ordinal, window_size);
181 last_ordinal = ordinal;
182 }
183
184 // saturate the value
185 uint128_t new_value_ex = std::min<uint128_t>(units_ex + (uint128_t)value_ex, std::numeric_limits<uint64_t>::max());
186 value_ex = downgrade_cast<uint64_t>(new_value_ex);
187 }
188 };
189 }
190
192
197 struct resource_limits_object : public chainbase::object<resource_limits_object_type, resource_limits_object> {
198
200
202 account_name owner; //< owner should not be changed within a chainbase modifier lambda
203 bool pending = false; //< pending should not be changed within a chainbase modifier lambda
204
208
209 };
210
211 struct by_owner;
212 struct by_dirty;
213
214 using resource_limits_index = chainbase::shared_multi_index_container<
216 indexed_by<
217 ordered_unique<tag<by_id>, member<resource_limits_object, resource_limits_object::id_type, &resource_limits_object::id>>,
218 ordered_unique<tag<by_owner>,
219 composite_key<resource_limits_object,
220 BOOST_MULTI_INDEX_MEMBER(resource_limits_object, bool, pending),
221 BOOST_MULTI_INDEX_MEMBER(resource_limits_object, account_name, owner)
222 >
223 >
224 >
225 >;
226
229
231 account_name owner; //< owner should not be changed within a chainbase modifier lambda
232
235
236 uint64_t ram_usage = 0;
237 };
238
239 using resource_usage_index = chainbase::shared_multi_index_container<
241 indexed_by<
242 ordered_unique<tag<by_id>, member<resource_usage_object, resource_usage_object::id_type, &resource_usage_object::id>>,
243 ordered_unique<tag<by_owner>, member<resource_usage_object, account_name, &resource_usage_object::owner> >
244 >
245 >;
246
249 id_type id;
250
251 static_assert( config::block_interval_ms > 0, "config::block_interval_ms must be positive" );
252 static_assert( config::block_cpu_usage_average_window_ms >= config::block_interval_ms,
253 "config::block_cpu_usage_average_window_ms cannot be less than config::block_interval_ms" );
254 static_assert( config::block_size_average_window_ms >= config::block_interval_ms,
255 "config::block_size_average_window_ms cannot be less than config::block_interval_ms" );
256
257
258 elastic_limit_parameters cpu_limit_parameters = {SYS_PERCENT(config::default_max_block_cpu_usage, config::default_target_block_cpu_usage_pct), config::default_max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}};
259 elastic_limit_parameters net_limit_parameters = {SYS_PERCENT(config::default_max_block_net_usage, config::default_target_block_net_usage_pct), config::default_max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}};
260
261 uint32_t account_cpu_usage_average_window = config::account_cpu_usage_average_window_ms / config::block_interval_ms;
262 uint32_t account_net_usage_average_window = config::account_net_usage_average_window_ms / config::block_interval_ms;
263 };
264
267 indexed_by<
268 ordered_unique<tag<by_id>, member<resource_limits_config_object, resource_limits_config_object::id_type, &resource_limits_config_object::id>>
269 >
270 >;
271
272 class resource_limits_state_object : public chainbase::object<resource_limits_state_object_type, resource_limits_state_object> {
274 id_type id;
275
279 usage_accumulator average_block_net_usage;
280
284 usage_accumulator average_block_cpu_usage;
285
286 void update_virtual_net_limit( const resource_limits_config_object& cfg );
287 void update_virtual_cpu_limit( const resource_limits_config_object& cfg );
288
289 uint64_t pending_net_usage = 0ULL;
290 uint64_t pending_cpu_usage = 0ULL;
291
292 uint64_t total_net_weight = 0ULL;
293 uint64_t total_cpu_weight = 0ULL;
294 uint64_t total_ram_bytes = 0ULL;
295
311 uint64_t virtual_net_limit = 0ULL;
312
316 uint64_t virtual_cpu_limit = 0ULL;
317
318 };
319
322 indexed_by<
323 ordered_unique<tag<by_id>, member<resource_limits_state_object, resource_limits_state_object::id_type, &resource_limits_state_object::id>>
324 >
325 >;
326
327} } }
328
333
334FC_REFLECT(sysio::chain::resource_limits::usage_accumulator, (last_ordinal)(value_ex)(consumed))
335
336// @ignore pending
337FC_REFLECT(sysio::chain::resource_limits::resource_limits_object, (owner)(net_weight)(cpu_weight)(ram_bytes))
338FC_REFLECT(sysio::chain::resource_limits::resource_usage_object, (owner)(net_usage)(cpu_usage)(ram_usage))
339FC_REFLECT(sysio::chain::resource_limits::resource_limits_config_object, (cpu_limit_parameters)(net_limit_parameters)(account_cpu_usage_average_window)(account_net_usage_average_window))
340FC_REFLECT(sysio::chain::resource_limits::resource_limits_state_object, (average_block_net_usage)(average_block_cpu_usage)(pending_net_usage)(pending_cpu_usage)(total_net_weight)(total_cpu_weight)(total_ram_bytes)(virtual_net_limit)(virtual_cpu_limit))
const mie::Vuint & r
Definition bn.cpp:28
constexpr uint64_t SYS_PERCENT(uint64_t value, uint32_t percentage)
Definition config.hpp:152
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
#define OBJECT_CTOR(...)
Definition types.hpp:39
#define CHAINBASE_SET_INDEX_TYPE(OBJECT_TYPE, INDEX_TYPE)
uint64_t id
Definition code_cache.cpp:0
boost::multi_index_container< Object, Args..., chainbase::node_allocator< Object > > shared_multi_index_container
const T & min(const T &a, const T &b)
Definition utility.hpp:140
constexpr UnsignedIntType integer_divide_ceil(UnsignedIntType num, UnsignedIntType den)
T operator*(T value, const ratio< T > &r)
constexpr auto downgrade_cast(GreaterIntType val) -> std::enable_if_t< is_valid_downgrade_cast< LesserIntType, GreaterIntType > &&std::is_signed< LesserIntType >::value==std::is_signed< GreaterIntType >::value, LesserIntType >
chainbase::shared_multi_index_container< resource_usage_object, indexed_by< ordered_unique< tag< by_id >, member< resource_usage_object, resource_usage_object::id_type, &resource_usage_object::id > >, ordered_unique< tag< by_owner >, member< resource_usage_object, account_name, &resource_usage_object::owner > > > > resource_usage_index
chainbase::shared_multi_index_container< resource_limits_object, indexed_by< ordered_unique< tag< by_id >, member< resource_limits_object, resource_limits_object::id_type, &resource_limits_object::id > >, ordered_unique< tag< by_owner >, composite_key< resource_limits_object, BOOST_MULTI_INDEX_MEMBER(resource_limits_object, bool, pending), > > > > resource_limits_index
chainbase::shared_multi_index_container< resource_limits_state_object, indexed_by< ordered_unique< tag< by_id >, member< resource_limits_state_object, resource_limits_state_object::id_type, &resource_limits_state_object::id > > > > resource_limits_state_index
chainbase::shared_multi_index_container< resource_limits_config_object, indexed_by< ordered_unique< tag< by_id >, member< resource_limits_config_object, resource_limits_config_object::id_type, &resource_limits_config_object::id > > > > resource_limits_config_index
@ resource_usage_object_type
Definition types.hpp:169
@ resource_limits_config_object_type
Definition types.hpp:171
unsigned __int128 uint128_t
Definition types.hpp:242
#define value
Definition pkcs11.h:157
#define T(meth, val, expected)
#define FC_REFLECT(TYPE, MEMBERS)
Specializes fc::reflector for TYPE.
Definition reflect.hpp:311
signed __int64 int64_t
Definition stdint.h:135
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
Immutable except for fc::from_variant.
Definition name.hpp:43
void add(uint64_t units, uint32_t ordinal, uint32_t window_size)
uint64_t value_at(uint32_t ordinal, uint32_t window_size) const
uint64_t value_ex
The current accumulated value pre-multiplied by Precision.
uint64_t value_ex_at(uint32_t ordinal, uint32_t window_size) const
uint32_t last_ordinal
The ordinal of the last period which has contributed to the accumulator.
uint64_t consumed
The last periods average + the current periods contribution so far.
uint32_t last_ordinal
The ordinal of the last period which has contributed to the average.
void add(uint64_t units, uint32_t ordinal, uint32_t window_size)
CK_ULONG d
struct @108 class