mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-30 07:55:51 +00:00
Rearrange sources (#4997)
This commit is contained in:
committed by
John Freeman
parent
2e902dee53
commit
e416ee72ca
70
include/xrpl/resource/Charge.h
Normal file
70
include/xrpl/resource/Charge.h
Normal file
@@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_CHARGE_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_CHARGE_H_INCLUDED
|
||||
|
||||
#include <ios>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
/** A consumption charge. */
|
||||
class Charge
|
||||
{
|
||||
public:
|
||||
/** The type used to hold a consumption charge. */
|
||||
using value_type = int;
|
||||
|
||||
// A default constructed Charge has no way to get a label. Delete
|
||||
Charge() = delete;
|
||||
|
||||
/** Create a charge with the specified cost and name. */
|
||||
Charge(value_type cost, std::string const& label = std::string());
|
||||
|
||||
/** Return the human readable label associated with the charge. */
|
||||
std::string const&
|
||||
label() const;
|
||||
|
||||
/** Return the cost of the charge in Resource::Manager units. */
|
||||
value_type
|
||||
cost() const;
|
||||
|
||||
/** Converts this charge into a human readable string. */
|
||||
std::string
|
||||
to_string() const;
|
||||
|
||||
bool
|
||||
operator==(Charge const&) const;
|
||||
bool
|
||||
operator!=(Charge const&) const;
|
||||
|
||||
private:
|
||||
value_type m_cost;
|
||||
std::string m_label;
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, Charge const& v);
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
101
include/xrpl/resource/Consumer.h
Normal file
101
include/xrpl/resource/Consumer.h
Normal file
@@ -0,0 +1,101 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_CONSUMER_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_CONSUMER_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/resource/Charge.h>
|
||||
#include <ripple/resource/Disposition.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
struct Entry;
|
||||
class Logic;
|
||||
|
||||
/** An endpoint that consumes resources. */
|
||||
class Consumer
|
||||
{
|
||||
private:
|
||||
friend class Logic;
|
||||
Consumer(Logic& logic, Entry& entry);
|
||||
|
||||
public:
|
||||
Consumer();
|
||||
~Consumer();
|
||||
Consumer(Consumer const& other);
|
||||
Consumer&
|
||||
operator=(Consumer const& other);
|
||||
|
||||
/** Return a human readable string uniquely identifying this consumer. */
|
||||
std::string
|
||||
to_string() const;
|
||||
|
||||
/** Returns `true` if this is a privileged endpoint. */
|
||||
bool
|
||||
isUnlimited() const;
|
||||
|
||||
/** Raise the Consumer's privilege level to a Named endpoint.
|
||||
The reference to the original endpoint descriptor is released.
|
||||
*/
|
||||
void
|
||||
elevate(std::string const& name);
|
||||
|
||||
/** Returns the current disposition of this consumer.
|
||||
This should be checked upon creation to determine if the consumer
|
||||
should be disconnected immediately.
|
||||
*/
|
||||
Disposition
|
||||
disposition() const;
|
||||
|
||||
/** Apply a load charge to the consumer. */
|
||||
Disposition
|
||||
charge(Charge const& fee);
|
||||
|
||||
/** Returns `true` if the consumer should be warned.
|
||||
This consumes the warning.
|
||||
*/
|
||||
bool
|
||||
warn();
|
||||
|
||||
/** Returns `true` if the consumer should be disconnected. */
|
||||
bool
|
||||
disconnect(beast::Journal const& j);
|
||||
|
||||
/** Returns the credit balance representing consumption. */
|
||||
int
|
||||
balance();
|
||||
|
||||
// Private: Retrieve the entry associated with the consumer
|
||||
Entry&
|
||||
entry();
|
||||
|
||||
private:
|
||||
Logic* m_logic;
|
||||
Entry* m_entry;
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, Consumer const& v);
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
43
include/xrpl/resource/Disposition.h
Normal file
43
include/xrpl/resource/Disposition.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_DISPOSITION_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_DISPOSITION_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
/** The disposition of a consumer after applying a load charge. */
|
||||
enum Disposition {
|
||||
/** No action required. */
|
||||
ok
|
||||
|
||||
/** Consumer should be warned that consumption is high. */
|
||||
,
|
||||
warn
|
||||
|
||||
/** Consumer should be disconnected for excess consumption. */
|
||||
,
|
||||
drop
|
||||
};
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
69
include/xrpl/resource/Fees.h
Normal file
69
include/xrpl/resource/Fees.h
Normal file
@@ -0,0 +1,69 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_FEES_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_FEES_H_INCLUDED
|
||||
|
||||
#include <ripple/resource/Charge.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
/** Schedule of fees charged for imposing load on the server. */
|
||||
/** @{ */
|
||||
extern Charge const
|
||||
feeInvalidRequest; // A request that we can immediately tell is invalid
|
||||
extern Charge const feeRequestNoReply; // A request that we cannot satisfy
|
||||
extern Charge const feeInvalidSignature; // An object whose signature we had to
|
||||
// check and it failed
|
||||
extern Charge const feeUnwantedData; // Data we have no use for
|
||||
extern Charge const feeBadData; // Data we have to verify before rejecting
|
||||
|
||||
// RPC loads
|
||||
extern Charge const
|
||||
feeInvalidRPC; // An RPC request that we can immediately tell is invalid.
|
||||
extern Charge const feeReferenceRPC; // A default "reference" unspecified load
|
||||
extern Charge const feeExceptionRPC; // An RPC load that causes an exception
|
||||
extern Charge const feeLightRPC; // A normal RPC command
|
||||
extern Charge const feeLowBurdenRPC; // A slightly burdensome RPC load
|
||||
extern Charge const feeMediumBurdenRPC; // A somewhat burdensome RPC load
|
||||
extern Charge const feeHighBurdenRPC; // A very burdensome RPC load
|
||||
extern Charge const feePathFindUpdate; // An update to an existing PF request
|
||||
|
||||
// Peer loads
|
||||
extern Charge const feeLightPeer; // Requires no reply
|
||||
extern Charge const feeLowBurdenPeer; // Quick/cheap, slight reply
|
||||
extern Charge const feeMediumBurdenPeer; // Requires some work
|
||||
extern Charge const feeHighBurdenPeer; // Extensive work
|
||||
|
||||
// Good things
|
||||
extern Charge const
|
||||
feeNewTrustedNote; // A new transaction/validation/proposal we trust
|
||||
extern Charge const feeNewValidTx; // A new, valid transaction
|
||||
extern Charge const feeSatisfiedRequest; // Data we requested
|
||||
|
||||
// Administrative
|
||||
extern Charge const feeWarning; // The cost of receiving a warning
|
||||
extern Charge const feeDrop; // The cost of being dropped for excess load
|
||||
/** @} */
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
48
include/xrpl/resource/Gossip.h
Normal file
48
include/xrpl/resource/Gossip.h
Normal file
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_GOSSIP_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_GOSSIP_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
/** Data format for exchanging consumption information across peers. */
|
||||
struct Gossip
|
||||
{
|
||||
explicit Gossip() = default;
|
||||
|
||||
/** Describes a single consumer. */
|
||||
struct Item
|
||||
{
|
||||
explicit Item() = default;
|
||||
|
||||
int balance;
|
||||
beast::IP::Endpoint address;
|
||||
};
|
||||
|
||||
std::vector<Item> items;
|
||||
};
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
77
include/xrpl/resource/README.md
Normal file
77
include/xrpl/resource/README.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Resource::Manager #
|
||||
|
||||
The ResourceManager module has these responsibilities:
|
||||
|
||||
- Uniquely identify endpoints which impose load.
|
||||
- Track the load used across endpoints.
|
||||
- Provide an interface to share load information in a cluster.
|
||||
- Warn and/or disconnect endpoints for imposing load.
|
||||
|
||||
## Description ##
|
||||
|
||||
To prevent monopolization of server resources or attacks on servers,
|
||||
resource consumption is monitored at each endpoint. When consumption
|
||||
exceeds certain thresholds, costs are imposed. Costs could include charging
|
||||
additional XRP for transactions, requiring a proof of work to be
|
||||
performed, or simply disconnecting the endpoint.
|
||||
|
||||
Currently, consumption endpoints include websocket connections used to
|
||||
service clients, and peer connections used to create the peer to peer
|
||||
overlay network implementing the Ripple protocol.
|
||||
|
||||
The current "balance" of a Consumer represents resource consumption
|
||||
debt or credit. Debt is accrued when bad loads are imposed. Credit is
|
||||
granted when good loads are imposed. When the balance crosses heuristic
|
||||
thresholds, costs are increased on the endpoint. The balance is
|
||||
represented as a unitless relative quantity. This balance is currently
|
||||
held by the Entry struct in the impl/Entry.h file.
|
||||
|
||||
Costs associated with specific transactions are defined in the
|
||||
impl/Fees files.
|
||||
|
||||
Although RPC connections consume resources, they are transient and
|
||||
cannot be rate limited. It is advised not to expose RPC interfaces
|
||||
to the general public.
|
||||
|
||||
## Consumer Types ##
|
||||
|
||||
Consumers are placed into three classifications (as identified by the
|
||||
Resource::Kind enumeration):
|
||||
|
||||
- InBound,
|
||||
- OutBound, and
|
||||
- Admin
|
||||
|
||||
Each caller determines for itself the classification of the Consumer it is
|
||||
creating.
|
||||
|
||||
## Resource Loading ##
|
||||
|
||||
It is expected that a client will impose a higher load on the server
|
||||
when it first connects: the client may need to catch up on transactions
|
||||
it has missed, or get trust lines, or transfer fees. The Manager must
|
||||
expect this initial peak load, but not allow that high load to continue
|
||||
because over the long term that would unduly stress the server.
|
||||
|
||||
If a client places a sustained high load on the server, that client
|
||||
is initially given a warning message. If that high load continues
|
||||
the Manager may tell the heavily loaded server to drop the connection
|
||||
entirely and not allow re-connection for some amount of time.
|
||||
|
||||
Each load is monitored by capturing peaks and then decaying those peak
|
||||
values over time: this is implemented by the DecayingSample class.
|
||||
|
||||
## Gossip ##
|
||||
|
||||
Each server in a cluster creates a list of IP addresses of end points
|
||||
that are imposing a significant load. This list is called Gossip, which
|
||||
is passed to other nodes in that cluster. Gossip helps individual
|
||||
servers in the cluster identify IP addreses that might be unduly loading
|
||||
the entire cluster. Again the recourse of the individual servers is to
|
||||
drop connections to those IP addresses that occur commonly in the gossip.
|
||||
|
||||
## Access ##
|
||||
|
||||
In rippled, the Application holds a unique instance of Resource::Manager,
|
||||
which may be retrieved by calling the method
|
||||
`Application::getResourceManager()`.
|
||||
89
include/xrpl/resource/ResourceManager.h
Normal file
89
include/xrpl/resource/ResourceManager.h
Normal file
@@ -0,0 +1,89 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_MANAGER_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_MANAGER_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/Collector.h>
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/beast/utility/PropertyStream.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/resource/Consumer.h>
|
||||
#include <ripple/resource/Gossip.h>
|
||||
#include <boost/utility/string_view.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
/** Tracks load and resource consumption. */
|
||||
class Manager : public beast::PropertyStream::Source
|
||||
{
|
||||
protected:
|
||||
Manager();
|
||||
|
||||
public:
|
||||
virtual ~Manager() = 0;
|
||||
|
||||
/** Create a new endpoint keyed by inbound IP address or the forwarded
|
||||
* IP if proxied. */
|
||||
virtual Consumer
|
||||
newInboundEndpoint(beast::IP::Endpoint const& address) = 0;
|
||||
virtual Consumer
|
||||
newInboundEndpoint(
|
||||
beast::IP::Endpoint const& address,
|
||||
bool const proxy,
|
||||
std::string_view forwardedFor) = 0;
|
||||
|
||||
/** Create a new endpoint keyed by outbound IP address and port. */
|
||||
virtual Consumer
|
||||
newOutboundEndpoint(beast::IP::Endpoint const& address) = 0;
|
||||
|
||||
/** Create a new unlimited endpoint keyed by forwarded IP. */
|
||||
virtual Consumer
|
||||
newUnlimitedEndpoint(beast::IP::Endpoint const& address) = 0;
|
||||
|
||||
/** Extract packaged consumer information for export. */
|
||||
virtual Gossip
|
||||
exportConsumers() = 0;
|
||||
|
||||
/** Extract consumer information for reporting. */
|
||||
virtual Json::Value
|
||||
getJson() = 0;
|
||||
virtual Json::Value
|
||||
getJson(int threshold) = 0;
|
||||
|
||||
/** Import packaged consumer information.
|
||||
@param origin An identifier that unique labels the origin.
|
||||
*/
|
||||
virtual void
|
||||
importConsumers(std::string const& origin, Gossip const& gossip) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::unique_ptr<Manager>
|
||||
make_Manager(
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
beast::Journal journal);
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
32
include/xrpl/resource/Types.h
Normal file
32
include/xrpl/resource/Types.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_TYPES_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_TYPES_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
struct Key;
|
||||
struct Entry;
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
114
include/xrpl/resource/detail/Entry.h
Normal file
114
include/xrpl/resource/detail/Entry.h
Normal file
@@ -0,0 +1,114 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_ENTRY_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_ENTRY_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/DecayingSample.h>
|
||||
#include <ripple/beast/clock/abstract_clock.h>
|
||||
#include <ripple/beast/core/List.h>
|
||||
#include <ripple/resource/impl/Key.h>
|
||||
#include <ripple/resource/impl/Tuning.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
|
||||
|
||||
// An entry in the table
|
||||
// VFALCO DEPRECATED using boost::intrusive list
|
||||
struct Entry : public beast::List<Entry>::Node
|
||||
{
|
||||
Entry() = delete;
|
||||
|
||||
/**
|
||||
@param now Construction time of Entry.
|
||||
*/
|
||||
explicit Entry(clock_type::time_point const now)
|
||||
: refcount(0)
|
||||
, local_balance(now)
|
||||
, remote_balance(0)
|
||||
, lastWarningTime()
|
||||
, whenExpires()
|
||||
{
|
||||
}
|
||||
|
||||
std::string
|
||||
to_string() const
|
||||
{
|
||||
return key->address.to_string();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if this connection should have no
|
||||
* resource limits applied--it is still possible for certain RPC commands
|
||||
* to be forbidden, but that depends on Role.
|
||||
*/
|
||||
bool
|
||||
isUnlimited() const
|
||||
{
|
||||
return key->kind == kindUnlimited;
|
||||
}
|
||||
|
||||
// Balance including remote contributions
|
||||
int
|
||||
balance(clock_type::time_point const now)
|
||||
{
|
||||
return local_balance.value(now) + remote_balance;
|
||||
}
|
||||
|
||||
// Add a charge and return normalized balance
|
||||
// including contributions from imports.
|
||||
int
|
||||
add(int charge, clock_type::time_point const now)
|
||||
{
|
||||
return local_balance.add(charge, now) + remote_balance;
|
||||
}
|
||||
|
||||
// Back pointer to the map key (bit of a hack here)
|
||||
Key const* key;
|
||||
|
||||
// Number of Consumer references
|
||||
int refcount;
|
||||
|
||||
// Exponentially decaying balance of resource consumption
|
||||
DecayingSample<decayWindowSeconds, clock_type> local_balance;
|
||||
|
||||
// Normalized balance contribution from imports
|
||||
int remote_balance;
|
||||
|
||||
// Time of the last warning
|
||||
clock_type::time_point lastWarningTime;
|
||||
|
||||
// For inactive entries, time after which this entry will be erased
|
||||
clock_type::time_point whenExpires;
|
||||
};
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, Entry const& v)
|
||||
{
|
||||
os << v.to_string();
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
55
include/xrpl/resource/detail/Import.h
Normal file
55
include/xrpl/resource/detail/Import.h
Normal file
@@ -0,0 +1,55 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_IMPORT_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_IMPORT_H_INCLUDED
|
||||
|
||||
#include <ripple/resource/Consumer.h>
|
||||
#include <ripple/resource/impl/Entry.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
/** A set of imported consumer data from a gossip origin. */
|
||||
struct Import
|
||||
{
|
||||
struct Item
|
||||
{
|
||||
explicit Item() = default;
|
||||
|
||||
int balance;
|
||||
Consumer consumer;
|
||||
};
|
||||
|
||||
// Dummy argument required for zero-copy construction
|
||||
Import(int = 0) : whenExpires()
|
||||
{
|
||||
}
|
||||
|
||||
// When the imported data expires
|
||||
clock_type::time_point whenExpires;
|
||||
|
||||
// List of remote entries
|
||||
std::vector<Item> items;
|
||||
};
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
71
include/xrpl/resource/detail/Key.h
Normal file
71
include/xrpl/resource/detail/Key.h
Normal file
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_KEY_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_KEY_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <ripple/resource/impl/Kind.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
// The consumer key
|
||||
struct Key
|
||||
{
|
||||
Kind kind;
|
||||
beast::IP::Endpoint address;
|
||||
|
||||
Key() = delete;
|
||||
|
||||
Key(Kind k, beast::IP::Endpoint const& addr) : kind(k), address(addr)
|
||||
{
|
||||
}
|
||||
|
||||
struct hasher
|
||||
{
|
||||
std::size_t
|
||||
operator()(Key const& v) const
|
||||
{
|
||||
return m_addr_hash(v.address);
|
||||
}
|
||||
|
||||
private:
|
||||
beast::uhash<> m_addr_hash;
|
||||
};
|
||||
|
||||
struct key_equal
|
||||
{
|
||||
explicit key_equal() = default;
|
||||
|
||||
bool
|
||||
operator()(Key const& lhs, Key const& rhs) const
|
||||
{
|
||||
return lhs.kind == rhs.kind && lhs.address == rhs.address;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
39
include/xrpl/resource/detail/Kind.h
Normal file
39
include/xrpl/resource/detail/Kind.h
Normal file
@@ -0,0 +1,39 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_KIND_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_KIND_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
/**
|
||||
* Kind of consumer.
|
||||
* kindInbound: Inbound connection.
|
||||
* kindOutbound: Outbound connection.
|
||||
* kindUnlimited: Inbound connection with no resource limits, but could be
|
||||
* subjected to administrative restrictions, such as
|
||||
* use of some RPC commands like "stop".
|
||||
*/
|
||||
enum Kind { kindInbound, kindOutbound, kindUnlimited };
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
563
include/xrpl/resource/detail/Logic.h
Normal file
563
include/xrpl/resource/detail/Logic.h
Normal file
@@ -0,0 +1,563 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_LOGIC_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_LOGIC_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/UnorderedContainers.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/beast/clock/abstract_clock.h>
|
||||
#include <ripple/beast/insight/Insight.h>
|
||||
#include <ripple/beast/utility/PropertyStream.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/resource/Fees.h>
|
||||
#include <ripple/resource/Gossip.h>
|
||||
#include <ripple/resource/impl/Import.h>
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
class Logic
|
||||
{
|
||||
private:
|
||||
using clock_type = Stopwatch;
|
||||
using Imports = hash_map<std::string, Import>;
|
||||
using Table = hash_map<Key, Entry, Key::hasher, Key::key_equal>;
|
||||
using EntryIntrusiveList = beast::List<Entry>;
|
||||
|
||||
struct Stats
|
||||
{
|
||||
Stats(beast::insight::Collector::ptr const& collector)
|
||||
{
|
||||
warn = collector->make_meter("warn");
|
||||
drop = collector->make_meter("drop");
|
||||
}
|
||||
|
||||
beast::insight::Meter warn;
|
||||
beast::insight::Meter drop;
|
||||
};
|
||||
|
||||
Stats m_stats;
|
||||
Stopwatch& m_clock;
|
||||
beast::Journal m_journal;
|
||||
|
||||
std::recursive_mutex lock_;
|
||||
|
||||
// Table of all entries
|
||||
Table table_;
|
||||
|
||||
// Because the following are intrusive lists, a given Entry may be in
|
||||
// at most list at a given instant. The Entry must be removed from
|
||||
// one list before placing it in another.
|
||||
|
||||
// List of all active inbound entries
|
||||
EntryIntrusiveList inbound_;
|
||||
|
||||
// List of all active outbound entries
|
||||
EntryIntrusiveList outbound_;
|
||||
|
||||
// List of all active admin entries
|
||||
EntryIntrusiveList admin_;
|
||||
|
||||
// List of all inactve entries
|
||||
EntryIntrusiveList inactive_;
|
||||
|
||||
// All imported gossip data
|
||||
Imports importTable_;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
public:
|
||||
Logic(
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
clock_type& clock,
|
||||
beast::Journal journal)
|
||||
: m_stats(collector), m_clock(clock), m_journal(journal)
|
||||
{
|
||||
}
|
||||
|
||||
~Logic()
|
||||
{
|
||||
// These have to be cleared before the Logic is destroyed
|
||||
// since their destructors call back into the class.
|
||||
// Order matters here as well, the import table has to be
|
||||
// destroyed before the consumer table.
|
||||
//
|
||||
importTable_.clear();
|
||||
table_.clear();
|
||||
}
|
||||
|
||||
Consumer
|
||||
newInboundEndpoint(beast::IP::Endpoint const& address)
|
||||
{
|
||||
Entry* entry(nullptr);
|
||||
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
auto [resultIt, resultInserted] = table_.emplace(
|
||||
std::piecewise_construct,
|
||||
std::make_tuple(kindInbound, address.at_port(0)), // Key
|
||||
std::make_tuple(m_clock.now())); // Entry
|
||||
|
||||
entry = &resultIt->second;
|
||||
entry->key = &resultIt->first;
|
||||
++entry->refcount;
|
||||
if (entry->refcount == 1)
|
||||
{
|
||||
if (!resultInserted)
|
||||
{
|
||||
inactive_.erase(inactive_.iterator_to(*entry));
|
||||
}
|
||||
inbound_.push_back(*entry);
|
||||
}
|
||||
}
|
||||
|
||||
JLOG(m_journal.debug()) << "New inbound endpoint " << *entry;
|
||||
|
||||
return Consumer(*this, *entry);
|
||||
}
|
||||
|
||||
Consumer
|
||||
newOutboundEndpoint(beast::IP::Endpoint const& address)
|
||||
{
|
||||
Entry* entry(nullptr);
|
||||
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
auto [resultIt, resultInserted] = table_.emplace(
|
||||
std::piecewise_construct,
|
||||
std::make_tuple(kindOutbound, address), // Key
|
||||
std::make_tuple(m_clock.now())); // Entry
|
||||
|
||||
entry = &resultIt->second;
|
||||
entry->key = &resultIt->first;
|
||||
++entry->refcount;
|
||||
if (entry->refcount == 1)
|
||||
{
|
||||
if (!resultInserted)
|
||||
inactive_.erase(inactive_.iterator_to(*entry));
|
||||
outbound_.push_back(*entry);
|
||||
}
|
||||
}
|
||||
|
||||
JLOG(m_journal.debug()) << "New outbound endpoint " << *entry;
|
||||
|
||||
return Consumer(*this, *entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create endpoint that should not have resource limits applied. Other
|
||||
* restrictions, such as permission to perform certain RPC calls, may be
|
||||
* enabled.
|
||||
*/
|
||||
Consumer
|
||||
newUnlimitedEndpoint(beast::IP::Endpoint const& address)
|
||||
{
|
||||
Entry* entry(nullptr);
|
||||
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
auto [resultIt, resultInserted] = table_.emplace(
|
||||
std::piecewise_construct,
|
||||
std::make_tuple(kindUnlimited, address.at_port(1)), // Key
|
||||
std::make_tuple(m_clock.now())); // Entry
|
||||
|
||||
entry = &resultIt->second;
|
||||
entry->key = &resultIt->first;
|
||||
++entry->refcount;
|
||||
if (entry->refcount == 1)
|
||||
{
|
||||
if (!resultInserted)
|
||||
inactive_.erase(inactive_.iterator_to(*entry));
|
||||
admin_.push_back(*entry);
|
||||
}
|
||||
}
|
||||
|
||||
JLOG(m_journal.debug()) << "New unlimited endpoint " << *entry;
|
||||
|
||||
return Consumer(*this, *entry);
|
||||
}
|
||||
|
||||
Json::Value
|
||||
getJson()
|
||||
{
|
||||
return getJson(warningThreshold);
|
||||
}
|
||||
|
||||
/** Returns a Json::objectValue. */
|
||||
Json::Value
|
||||
getJson(int threshold)
|
||||
{
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
|
||||
Json::Value ret(Json::objectValue);
|
||||
std::lock_guard _(lock_);
|
||||
|
||||
for (auto& inboundEntry : inbound_)
|
||||
{
|
||||
int localBalance = inboundEntry.local_balance.value(now);
|
||||
if ((localBalance + inboundEntry.remote_balance) >= threshold)
|
||||
{
|
||||
Json::Value& entry =
|
||||
(ret[inboundEntry.to_string()] = Json::objectValue);
|
||||
entry[jss::local] = localBalance;
|
||||
entry[jss::remote] = inboundEntry.remote_balance;
|
||||
entry[jss::type] = "inbound";
|
||||
}
|
||||
}
|
||||
for (auto& outboundEntry : outbound_)
|
||||
{
|
||||
int localBalance = outboundEntry.local_balance.value(now);
|
||||
if ((localBalance + outboundEntry.remote_balance) >= threshold)
|
||||
{
|
||||
Json::Value& entry =
|
||||
(ret[outboundEntry.to_string()] = Json::objectValue);
|
||||
entry[jss::local] = localBalance;
|
||||
entry[jss::remote] = outboundEntry.remote_balance;
|
||||
entry[jss::type] = "outbound";
|
||||
}
|
||||
}
|
||||
for (auto& adminEntry : admin_)
|
||||
{
|
||||
int localBalance = adminEntry.local_balance.value(now);
|
||||
if ((localBalance + adminEntry.remote_balance) >= threshold)
|
||||
{
|
||||
Json::Value& entry =
|
||||
(ret[adminEntry.to_string()] = Json::objectValue);
|
||||
entry[jss::local] = localBalance;
|
||||
entry[jss::remote] = adminEntry.remote_balance;
|
||||
entry[jss::type] = "admin";
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Gossip
|
||||
exportConsumers()
|
||||
{
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
|
||||
Gossip gossip;
|
||||
std::lock_guard _(lock_);
|
||||
|
||||
gossip.items.reserve(inbound_.size());
|
||||
|
||||
for (auto& inboundEntry : inbound_)
|
||||
{
|
||||
Gossip::Item item;
|
||||
item.balance = inboundEntry.local_balance.value(now);
|
||||
if (item.balance >= minimumGossipBalance)
|
||||
{
|
||||
item.address = inboundEntry.key->address;
|
||||
gossip.items.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
return gossip;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
importConsumers(std::string const& origin, Gossip const& gossip)
|
||||
{
|
||||
auto const elapsed = m_clock.now();
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
auto [resultIt, resultInserted] = importTable_.emplace(
|
||||
std::piecewise_construct,
|
||||
std::make_tuple(origin), // Key
|
||||
std::make_tuple(
|
||||
m_clock.now().time_since_epoch().count())); // Import
|
||||
|
||||
if (resultInserted)
|
||||
{
|
||||
// This is a new import
|
||||
Import& next(resultIt->second);
|
||||
next.whenExpires = elapsed + gossipExpirationSeconds;
|
||||
next.items.reserve(gossip.items.size());
|
||||
|
||||
for (auto const& gossipItem : gossip.items)
|
||||
{
|
||||
Import::Item item;
|
||||
item.balance = gossipItem.balance;
|
||||
item.consumer = newInboundEndpoint(gossipItem.address);
|
||||
item.consumer.entry().remote_balance += item.balance;
|
||||
next.items.push_back(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Previous import exists so add the new remote
|
||||
// balances and then deduct the old remote balances.
|
||||
|
||||
Import next;
|
||||
next.whenExpires = elapsed + gossipExpirationSeconds;
|
||||
next.items.reserve(gossip.items.size());
|
||||
for (auto const& gossipItem : gossip.items)
|
||||
{
|
||||
Import::Item item;
|
||||
item.balance = gossipItem.balance;
|
||||
item.consumer = newInboundEndpoint(gossipItem.address);
|
||||
item.consumer.entry().remote_balance += item.balance;
|
||||
next.items.push_back(item);
|
||||
}
|
||||
|
||||
Import& prev(resultIt->second);
|
||||
for (auto& item : prev.items)
|
||||
{
|
||||
item.consumer.entry().remote_balance -= item.balance;
|
||||
}
|
||||
|
||||
std::swap(next, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Called periodically to expire entries and groom the table.
|
||||
//
|
||||
void
|
||||
periodicActivity()
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
|
||||
auto const elapsed = m_clock.now();
|
||||
|
||||
for (auto iter(inactive_.begin()); iter != inactive_.end();)
|
||||
{
|
||||
if (iter->whenExpires <= elapsed)
|
||||
{
|
||||
JLOG(m_journal.debug()) << "Expired " << *iter;
|
||||
auto table_iter = table_.find(*iter->key);
|
||||
++iter;
|
||||
erase(table_iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto iter = importTable_.begin();
|
||||
while (iter != importTable_.end())
|
||||
{
|
||||
Import& import(iter->second);
|
||||
if (iter->second.whenExpires <= elapsed)
|
||||
{
|
||||
for (auto item_iter(import.items.begin());
|
||||
item_iter != import.items.end();
|
||||
++item_iter)
|
||||
{
|
||||
item_iter->consumer.entry().remote_balance -=
|
||||
item_iter->balance;
|
||||
}
|
||||
|
||||
iter = importTable_.erase(iter);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Returns the disposition based on the balance and thresholds
|
||||
static Disposition
|
||||
disposition(int balance)
|
||||
{
|
||||
if (balance >= dropThreshold)
|
||||
return Disposition::drop;
|
||||
|
||||
if (balance >= warningThreshold)
|
||||
return Disposition::warn;
|
||||
|
||||
return Disposition::ok;
|
||||
}
|
||||
|
||||
void
|
||||
erase(Table::iterator iter)
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
Entry& entry(iter->second);
|
||||
assert(entry.refcount == 0);
|
||||
inactive_.erase(inactive_.iterator_to(entry));
|
||||
table_.erase(iter);
|
||||
}
|
||||
|
||||
void
|
||||
acquire(Entry& entry)
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
++entry.refcount;
|
||||
}
|
||||
|
||||
void
|
||||
release(Entry& entry)
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
if (--entry.refcount == 0)
|
||||
{
|
||||
JLOG(m_journal.debug()) << "Inactive " << entry;
|
||||
|
||||
switch (entry.key->kind)
|
||||
{
|
||||
case kindInbound:
|
||||
inbound_.erase(inbound_.iterator_to(entry));
|
||||
break;
|
||||
case kindOutbound:
|
||||
outbound_.erase(outbound_.iterator_to(entry));
|
||||
break;
|
||||
case kindUnlimited:
|
||||
admin_.erase(admin_.iterator_to(entry));
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
inactive_.push_back(entry);
|
||||
entry.whenExpires = m_clock.now() + secondsUntilExpiration;
|
||||
}
|
||||
}
|
||||
|
||||
Disposition
|
||||
charge(Entry& entry, Charge const& fee)
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
int const balance(entry.add(fee.cost(), now));
|
||||
JLOG(m_journal.trace()) << "Charging " << entry << " for " << fee;
|
||||
return disposition(balance);
|
||||
}
|
||||
|
||||
bool
|
||||
warn(Entry& entry)
|
||||
{
|
||||
if (entry.isUnlimited())
|
||||
return false;
|
||||
|
||||
std::lock_guard _(lock_);
|
||||
bool notify(false);
|
||||
auto const elapsed = m_clock.now();
|
||||
if (entry.balance(m_clock.now()) >= warningThreshold &&
|
||||
elapsed != entry.lastWarningTime)
|
||||
{
|
||||
charge(entry, feeWarning);
|
||||
notify = true;
|
||||
entry.lastWarningTime = elapsed;
|
||||
}
|
||||
if (notify)
|
||||
{
|
||||
JLOG(m_journal.info()) << "Load warning: " << entry;
|
||||
++m_stats.warn;
|
||||
}
|
||||
return notify;
|
||||
}
|
||||
|
||||
bool
|
||||
disconnect(Entry& entry)
|
||||
{
|
||||
if (entry.isUnlimited())
|
||||
return false;
|
||||
|
||||
std::lock_guard _(lock_);
|
||||
bool drop(false);
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
int const balance(entry.balance(now));
|
||||
if (balance >= dropThreshold)
|
||||
{
|
||||
JLOG(m_journal.warn())
|
||||
<< "Consumer entry " << entry << " dropped with balance "
|
||||
<< balance << " at or above drop threshold " << dropThreshold;
|
||||
|
||||
// Adding feeDrop at this point keeps the dropped connection
|
||||
// from re-connecting for at least a little while after it is
|
||||
// dropped.
|
||||
charge(entry, feeDrop);
|
||||
++m_stats.drop;
|
||||
drop = true;
|
||||
}
|
||||
return drop;
|
||||
}
|
||||
|
||||
int
|
||||
balance(Entry& entry)
|
||||
{
|
||||
std::lock_guard _(lock_);
|
||||
return entry.balance(m_clock.now());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
writeList(
|
||||
clock_type::time_point const now,
|
||||
beast::PropertyStream::Set& items,
|
||||
EntryIntrusiveList& list)
|
||||
{
|
||||
for (auto& entry : list)
|
||||
{
|
||||
beast::PropertyStream::Map item(items);
|
||||
if (entry.refcount != 0)
|
||||
item["count"] = entry.refcount;
|
||||
item["name"] = entry.to_string();
|
||||
item["balance"] = entry.balance(now);
|
||||
if (entry.remote_balance != 0)
|
||||
item["remote_balance"] = entry.remote_balance;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
onWrite(beast::PropertyStream::Map& map)
|
||||
{
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
|
||||
std::lock_guard _(lock_);
|
||||
|
||||
{
|
||||
beast::PropertyStream::Set s("inbound", map);
|
||||
writeList(now, s, inbound_);
|
||||
}
|
||||
|
||||
{
|
||||
beast::PropertyStream::Set s("outbound", map);
|
||||
writeList(now, s, outbound_);
|
||||
}
|
||||
|
||||
{
|
||||
beast::PropertyStream::Set s("admin", map);
|
||||
writeList(now, s, admin_);
|
||||
}
|
||||
|
||||
{
|
||||
beast::PropertyStream::Set s("inactive", map);
|
||||
writeList(now, s, inactive_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
56
include/xrpl/resource/detail/Tuning.h
Normal file
56
include/xrpl/resource/detail/Tuning.h
Normal file
@@ -0,0 +1,56 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RESOURCE_TUNING_H_INCLUDED
|
||||
#define RIPPLE_RESOURCE_TUNING_H_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace ripple {
|
||||
namespace Resource {
|
||||
|
||||
/** Tunable constants. */
|
||||
enum {
|
||||
// Balance at which a warning is issued
|
||||
warningThreshold = 5000
|
||||
|
||||
// Balance at which the consumer is disconnected
|
||||
,
|
||||
dropThreshold = 15000
|
||||
|
||||
// The number of seconds in the exponential decay window
|
||||
// (This should be a power of two)
|
||||
,
|
||||
decayWindowSeconds = 32
|
||||
|
||||
// The minimum balance required in order to include a load source in gossip
|
||||
,
|
||||
minimumGossipBalance = 1000
|
||||
};
|
||||
|
||||
// The number of seconds until an inactive table item is removed
|
||||
std::chrono::seconds constexpr secondsUntilExpiration{300};
|
||||
|
||||
// Number of seconds until imported gossip expires
|
||||
std::chrono::seconds constexpr gossipExpirationSeconds{30};
|
||||
|
||||
} // namespace Resource
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user