3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/UnorderedContainers.h>
5#include <xrpl/basics/chrono.h>
6#include <xrpl/beast/clock/abstract_clock.h>
7#include <xrpl/beast/core/List.h>
8#include <xrpl/beast/insight/Collector.h>
9#include <xrpl/beast/net/IPEndpoint.h>
10#include <xrpl/beast/utility/Journal.h>
11#include <xrpl/beast/utility/PropertyStream.h>
12#include <xrpl/beast/utility/instrumentation.h>
13#include <xrpl/json/json_value.h>
14#include <xrpl/protocol/jss.h>
15#include <xrpl/resource/Charge.h>
16#include <xrpl/resource/Consumer.h>
17#include <xrpl/resource/Disposition.h>
18#include <xrpl/resource/Fees.h>
19#include <xrpl/resource/Gossip.h>
20#include <xrpl/resource/detail/Import.h>
41 warn = collector->makeMeter(
"warn");
42 drop = collector->makeMeter(
"drop");
101 Entry* entry(
nullptr);
105 auto [resultIt, resultInserted] =
table_.emplace(
110 entry = &resultIt->second;
111 entry->key = &resultIt->first;
113 if (entry->refcount == 1)
123 JLOG(
journal_.debug()) <<
"New inbound endpoint " << *entry;
131 Entry* entry(
nullptr);
135 auto [resultIt, resultInserted] =
table_.emplace(
140 entry = &resultIt->second;
141 entry->key = &resultIt->first;
143 if (entry->refcount == 1)
151 JLOG(
journal_.debug()) <<
"New outbound endpoint " << *entry;
164 Entry* entry(
nullptr);
168 auto [resultIt, resultInserted] =
table_.emplace(
173 entry = &resultIt->second;
174 entry->key = &resultIt->first;
176 if (entry->refcount == 1)
184 JLOG(
journal_.debug()) <<
"New unlimited endpoint " << *entry;
208 int const localBalance = inboundEntry.localBalance.value(now);
209 if ((localBalance + inboundEntry.remoteBalance) >= threshold)
212 entry[jss::local] = localBalance;
213 entry[jss::remote] = inboundEntry.remoteBalance;
214 entry[jss::type] =
"inbound";
219 int const localBalance = outboundEntry.localBalance.value(now);
220 if ((localBalance + outboundEntry.remoteBalance) >= threshold)
223 entry[jss::local] = localBalance;
224 entry[jss::remote] = outboundEntry.remoteBalance;
225 entry[jss::type] =
"outbound";
228 for (
auto& adminEntry :
admin_)
230 int const localBalance = adminEntry.localBalance.value(now);
231 if ((localBalance + adminEntry.remoteBalance) >= threshold)
234 entry[jss::local] = localBalance;
235 entry[jss::remote] = adminEntry.remoteBalance;
236 entry[jss::type] =
"admin";
256 item.
balance = inboundEntry.localBalance.value(now);
260 gossip.
items.push_back(item);
272 auto const elapsed =
clock_.now();
283 Import& next(resultIt->second);
285 next.items.reserve(gossip.
items.size());
287 for (
auto const& gossipItem : gossip.
items)
290 item.
balance = gossipItem.balance;
293 next.items.push_back(item);
303 next.items.reserve(gossip.
items.size());
304 for (
auto const& gossipItem : gossip.
items)
307 item.
balance = gossipItem.balance;
310 next.items.push_back(item);
313 Import& prev(resultIt->second);
314 for (
auto& item : prev.items)
316 item.consumer.entry().remoteBalance -= item.balance;
333 auto const elapsed =
clock_.now();
337 if (iter->whenExpires <= elapsed)
339 JLOG(
journal_.debug()) <<
"Expired " << *iter;
340 auto tableIter =
table_.find(*iter->key);
353 Import&
import(iter->second);
354 if (iter->second.whenExpires <= elapsed)
356 for (
auto& item :
import.items)
358 item.consumer.entry().remoteBalance -= item.balance;
389 Entry& entry(iter->second);
390 XRPL_ASSERT(entry.refcount == 0,
"xrpl::resource::Logic::erase : entry not used");
406 if (--entry.refcount == 0)
408 JLOG(
journal_.debug()) <<
"Inactive " << entry;
410 switch (entry.key->kind)
424 "xrpl::resource::Logic::release : invalid entry "
441 kFeeLogAsWarn > kFeeLogAsInfo && kFeeLogAsInfo > kFeeLogAsDebug && kFeeLogAsDebug > 10);
444 if (cost >= kFeeLogAsWarn)
445 return journal.warn();
446 if (cost >= kFeeLogAsInfo)
447 return journal.info();
448 if (cost >= kFeeLogAsDebug)
449 return journal.debug();
450 return journal.trace();
453 if (!context.empty())
454 context =
" (" + context +
")";
459 JLOG(kGetStream(fee.
cost(),
journal_)) <<
"Charging " << entry <<
" for " << fee << context;
466 if (entry.isUnlimited())
471 auto const elapsed =
clock_.now();
476 entry.lastWarningTime = elapsed;
480 JLOG(
journal_.info()) <<
"Load warning: " << entry;
489 if (entry.isUnlimited())
495 int const balance(entry.balance(now));
498 JLOG(
journal_.warn()) <<
"Consumer entry " << entry <<
" dropped with balance "
515 return entry.balance(
clock_.now());
526 for (
auto& entry : list)
529 if (entry.refcount != 0)
530 item[
"count"] = entry.refcount;
531 item[
"name"] = entry.toString();
532 item[
"balance"] = entry.balance(now);
533 if (entry.remoteBalance != 0)
534 item[
"remote_balance"] = entry.remoteBalance;
std::chrono::steady_clock::time_point time_point
virtual time_point now() const =0
Returns the current time.
A generic endpoint for log messages.
Intrusive doubly linked list.
std::shared_ptr< Collector > ptr
A metric for measuring an integral value.
A version-independent IP address and port combination.
Endpoint atPort(Port port) const
Returns a new Endpoint with a different port.
Address const & address() const
Returns the address portion of this endpoint.
int value_type
The type used to hold a consumption charge.
value_type cost() const
Return the cost of the charge in resource::Manager units.
An endpoint that consumes resources.
void release(Entry &entry)
Logic(beast::insight::Collector::ptr const &collector, clock_type &clock, beast::Journal journal)
bool disconnect(Entry &entry)
Disposition charge(Entry &entry, Charge const &fee, std::string context={})
json::Value getJson(int threshold)
Returns a json::ValueType::Object.
void erase(Table::iterator iter)
Consumer newInboundEndpoint(beast::ip::Endpoint const &address)
void onWrite(beast::PropertyStream::Map &map)
static Disposition disposition(int balance)
Consumer newOutboundEndpoint(beast::ip::Endpoint const &address)
void acquire(Entry &entry)
EntryIntrusiveList inactive_
hash_map< std::string, Import > Imports
hash_map< Key, Entry, Key::Hasher, Key::KeyEqual > Table
std::recursive_mutex lock_
EntryIntrusiveList inbound_
EntryIntrusiveList admin_
static void writeList(clock_type::time_point const now, beast::PropertyStream::Set &items, EntryIntrusiveList &list)
Consumer newUnlimitedEndpoint(beast::ip::Endpoint const &address)
Create endpoint that should not have resource limits applied.
int balance(Entry &entry)
beast::List< Entry > EntryIntrusiveList
void importConsumers(std::string const &origin, Gossip const &gossip)
EntryIntrusiveList outbound_
@ Object
object value (collection of name/value pairs).
static constexpr auto kMinimumGossipBalance
static constexpr std::chrono::seconds kSecondsUntilExpiration
static constexpr auto kWarningThreshold
Tunable constants.
Disposition
The disposition of a consumer after applying a load charge.
@ Warn
Consumer should be disconnected for excess consumption.
static constexpr auto kDropThreshold
static constexpr std::chrono::seconds kGossipExpirationSeconds
beast::AbstractClock< std::chrono::steady_clock > Stopwatch
A clock for measuring elapsed time.
std::unordered_map< Key, Value, Hash, Pred, Allocator > hash_map
Describes a single consumer.
beast::ip::Endpoint address
Data format for exchanging consumption information across peers.
std::vector< Item > items
A set of imported consumer data from a gossip origin.
beast::insight::Meter drop
Stats(beast::insight::Collector::ptr const &collector)
beast::insight::Meter warn