Files
xahaud/modules/ripple_app/main/ripple_ILoadManager.h
2013-07-23 18:47:02 -07:00

277 lines
8.4 KiB
C++

//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_ILOADMANAGER_H
#define RIPPLE_ILOADMANAGER_H
// types of load that can be placed on the server
// VFALCO TODO replace LT_ with loadType in constants
enum LoadType
{
// Bad things
LT_InvalidRequest, // A request that we can immediately tell is invalid
LT_RequestNoReply, // A request that we cannot satisfy
LT_InvalidSignature, // An object whose signature we had to check and it failed
LT_UnwantedData, // Data we have no use for
LT_BadPoW, // Proof of work not valid
LT_BadData, // Data we have to verify before rejecting
// RPC loads
LT_RPCInvalid, // An RPC request that we can immediately tell is invalid.
LT_RPCReference, // A default "reference" unspecified load
LT_RPCException, // An RPC load that causes an exception
LT_RPCBurden, // A particularly burdensome RPC load
// Good things
LT_NewTrusted, // A new transaction/validation/proposal we trust
LT_NewTransaction, // A new, valid transaction
LT_NeededData, // Data we requested
// Requests
LT_RequestData, // A request that is hard to satisfy, disk access
LT_CheapQuery, // A query that is trivial, cached data
LT_MAX // MUST BE LAST
};
//------------------------------------------------------------------------------
/** Tracks the consumption of resources at an endpoint.
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 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 protcool.
The current "balance" of a LoadSource 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.
@note 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.
*/
class LoadSource
{
public:
// VFALCO TODO Use these dispositions
/*
enum Disposition
{
none,
shouldWarn,
shouldDrop,
};
*/
/** Construct a load source.
Sources with admin privileges have relaxed or no restrictions
on resource consumption.
@param admin `true` if the source should have admin privileges.
*/
// VFALCO TODO See who is constructing this with a parameter
explicit LoadSource (bool admin)
: mBalance (0)
, mFlags (admin ? lsfPrivileged : 0)
, mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ())
, mLastWarning (0)
, mLogged (false)
{
}
/** Construct a load source with a given name.
The endpoint is considered non-privileged.
*/
explicit LoadSource (std::string const& name)
: mName (name)
, mBalance (0)
, mFlags (0)
, mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ())
, mLastWarning (0)
, mLogged (false)
{
}
/** Change the name of the source.
An endpoint can be created before it's name is known. For example,
on an incoming connection before the IP and port have been determined.
*/
// VFALCO TODO Figure out a way to construct the LoadSource object with
// the proper name instead of renaming it later.
//
void rename (std::string const& name)
{
mName = name;
}
/** Retrieve the name of this endpoint.
*/
std::string const& getName () const
{
return mName;
}
/** Determine if this endpoint is privileged.
*/
bool isPrivileged () const
{
return (mFlags & lsfPrivileged) != 0;
}
/** Grant the privileged attribute on this endpoint.
*/
void setPrivileged ()
{
mFlags |= lsfPrivileged;
}
/** Retrieve the load debit or credit associated with the endpoint.
The balance is represented in a unitless relative quantity
indicating the heuristically weighted amount of resource consumption.
*/
int getBalance () const
{
return mBalance;
}
/** Returns true if the endpoint received a log warning.
*/
bool isLogged () const
{
return mLogged;
}
/** Reset the flag indicating the endpoint received a log warning.
*/
void clearLogged ()
{
mLogged = false;
}
/** Indicate that this endpoint is an outgoing connection.
*/
void setOutbound ()
{
mFlags |= lsfOutbound;
}
/** Returns true if this endpoint is an outgoing connection.
*/
bool isOutbound () const
{
return (mFlags & lsfOutbound) != 0;
}
private:
// VFALCO Make this not a friend
friend class LoadManager;
static const int lsfPrivileged = 1;
static const int lsfOutbound = 2;
private:
std::string mName;
int mBalance;
int mFlags;
int mLastUpdate;
int mLastWarning;
bool mLogged;
};
//------------------------------------------------------------------------------
/** Manages load sources.
This object creates an associated thread to maintain a clock.
When the server is overloaded by a particular peer it issues a warning
first. This allows friendly peers to reduce their consumption of resources,
or disconnect from the server.
The warning system is used instead of merely dropping, because hostile
peers can just reconnect anyway.
@see LoadSource, LoadType
*/
class ILoadManager
{
public:
/** Create a new manager.
The manager thread begins running immediately.
@note The thresholds for warnings and punishments are in
the ctor-initializer
*/
static ILoadManager* New ();
/** Destroy the manager.
The destructor returns only after the thread has stopped.
*/
virtual ~ILoadManager () { }
/** Start the associated thread.
This is here to prevent the deadlock detector from activating during
a lengthy program initialization.
*/
// VFALCO TODO Simplify the two stage initialization to one stage (construction).
// NOTE In stand-alone mode the load manager thread isn't started
virtual void startThread () = 0;
/** Turn on deadlock detection.
The deadlock detector begins in a disabled state. After this function
is called, it will report deadlocks using a separate thread whenever
the reset function is not called at least once per 10 seconds.
@see resetDeadlockDetector
*/
// VFALCO NOTE it seems that the deadlock detector has an "armed" state to prevent it
// from going off during program startup if there's a lengthy initialization
// operation taking place?
//
virtual void activateDeadlockDetector () = 0;
/** Reset the deadlock detection timer.
A dedicated thread monitors the deadlock timer, and if too much
time passes it will produce log warnings.
*/
virtual void resetDeadlockDetector () = 0;
/** Update an endpoint to reflect an imposed load.
The balance of the endpoint is adjusted based on the heuristic cost
of the indicated load.
@return `true` if the endpoint should be warned or punished.
*/
virtual bool applyLoadCharge (LoadSource& sourceToAdjust, LoadType loadToImpose) const = 0;
// VFALCO TODO Eliminate these two functions and just make applyLoadCharge()
// return a LoadSource::Disposition
//
virtual bool shouldWarn (LoadSource&) const = 0;
virtual bool shouldCutoff (LoadSource&) const = 0;
};
#endif