Refactor LoadManager

This commit is contained in:
Vinnie Falco
2013-08-31 20:20:03 -07:00
parent 1ee8b3903c
commit e22c1c3495
13 changed files with 346 additions and 297 deletions

View File

@@ -1399,7 +1399,7 @@
<ClInclude Include="..\..\modules\ripple_app\main\ParameterTable.h" />
<ClInclude Include="..\..\modules\ripple_app\main\ripple_Application.h" />
<ClInclude Include="..\..\modules\ripple_app\main\ripple_FatalErrorReporter.h" />
<ClInclude Include="..\..\modules\ripple_app\main\ripple_ILoadManager.h" />
<ClInclude Include="..\..\modules\ripple_app\main\ripple_LoadManager.h" />
<ClInclude Include="..\..\modules\ripple_app\main\ripple_LocalCredentials.h" />
<ClInclude Include="..\..\modules\ripple_app\main\ripple_RippleMain.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\NetworkOPs.h" />
@@ -1506,6 +1506,8 @@
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_LoggedTimings.h" />
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_UptimeTimer.h" />
<ClInclude Include="..\..\modules\ripple_client\ripple_client.h" />
<ClInclude Include="..\..\modules\ripple_core\functional\LoadSource.h" />
<ClInclude Include="..\..\modules\ripple_core\functional\LoadType.h" />
<ClInclude Include="..\..\modules\ripple_core\functional\ripple_Config.h" />
<ClInclude Include="..\..\modules\ripple_core\functional\ripple_ConfigSections.h" />
<ClInclude Include="..\..\modules\ripple_core\functional\ripple_ILoadFeeTrack.h" />

View File

@@ -1436,9 +1436,6 @@
<ClInclude Include="..\..\modules\ripple_app\main\ripple_Application.h">
<Filter>[1] Ripple\ripple_app\main</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\main\ripple_ILoadManager.h">
<Filter>[1] Ripple\ripple_app\main</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\main\ripple_LocalCredentials.h">
<Filter>[1] Ripple\ripple_app\main</Filter>
</ClInclude>
@@ -1673,6 +1670,15 @@
<ClInclude Include="..\..\modules\ripple_app\peers\ripple_Peers.h">
<Filter>[1] Ripple\ripple_app\peers</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\functional\LoadSource.h">
<Filter>[1] Ripple\ripple_core\functional</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\functional\LoadType.h">
<Filter>[1] Ripple\ripple_core\functional</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\main\ripple_LoadManager.h">
<Filter>[1] Ripple\ripple_app\main</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\modules\ripple_data\protocol\ripple.proto">

View File

@@ -175,7 +175,7 @@ public:
, mValidations (IValidations::New ())
, mUNL (UniqueNodeList::New ())
, mProofOfWorkFactory (IProofOfWorkFactory::New ())
, m_loadManager (ILoadManager::New ())
, m_loadManager (LoadManager::New ())
// VFALCO End new stuff
// VFALCO TODO replace all NULL with nullptr
, mRpcDB (NULL)
@@ -267,7 +267,7 @@ public:
return mMasterLock;
}
ILoadManager& getLoadManager ()
LoadManager& getLoadManager ()
{
return *m_loadManager;
}
@@ -703,7 +703,7 @@ private:
ScopedPointer <UniqueNodeList> mUNL;
ScopedPointer <IProofOfWorkFactory> mProofOfWorkFactory;
ScopedPointer <Peers> m_peers;
ScopedPointer <ILoadManager> m_loadManager;
ScopedPointer <LoadManager> m_loadManager;
ScopedPointer <PeerDoor> m_peerDoor;
ScopedPointer <PeerDoor> m_peerProxyDoor;
ScopedPointer <WSDoor> m_wsPublicDoor;

View File

@@ -83,7 +83,7 @@ public:
virtual IFeeVote& getFeeVote () = 0;
virtual IHashRouter& getHashRouter () = 0;
virtual ILoadFeeTrack& getFeeTrack () = 0;
virtual ILoadManager& getLoadManager () = 0;
virtual LoadManager& getLoadManager () = 0;
virtual Peers& getPeers () = 0;
virtual IProofOfWorkFactory& getProofOfWorkFactory () = 0;
virtual UniqueNodeList& getUNL () = 0;

View File

@@ -1,276 +0,0 @@
//------------------------------------------------------------------------------
/*
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

View File

@@ -8,8 +8,8 @@ SETUP_LOG (LoadManager)
//------------------------------------------------------------------------------
class LoadManager
: public ILoadManager
class LoadManagerImp
: public LoadManager
, public beast::InterruptibleThread::EntryPoint
{
private:
@@ -59,8 +59,8 @@ private:
};
public:
LoadManager ()
: mLock (this, "LoadManager", __FILE__, __LINE__)
LoadManagerImp ()
: mLock (this, "LoadManagerImp", __FILE__, __LINE__)
, m_thread ("loadmgr")
, m_logThread ("loadmgr_log")
, mCreditRate (100)
@@ -115,7 +115,7 @@ public:
}
private:
~LoadManager ()
~LoadManagerImp ()
{
UptimeTimer::getInstance ().endManualUpdates ();
@@ -430,7 +430,8 @@ private:
//------------------------------------------------------------------------------
ILoadManager* ILoadManager::New ()
LoadManager* LoadManager::New ()
{
return new LoadManager;
ScopedPointer <LoadManager> object (new LoadManagerImp);
return object.release ();
}

View File

@@ -0,0 +1,87 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LOADMANAGER_H_INCLUDEd
#define RIPPLE_LOADMANAGER_H_INCLUDEd
/** 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 LoadManager
{
public:
/** Create a new manager.
The manager thread begins running immediately.
@note The thresholds for warnings and punishments are in
the ctor-initializer
*/
static LoadManager* New ();
/** Destroy the manager.
The destructor returns only after the thread has stopped.
*/
virtual ~LoadManager () { }
/** 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

View File

@@ -78,7 +78,7 @@ void NetworkOPs::processHeartbeatTimer ()
// VFALCO NOTE This is for diagnosing a crash on exit
Application& app (getApp ());
ILoadManager& mgr (app.getLoadManager ());
LoadManager& mgr (app.getLoadManager ());
mgr.resetDeadlockDetector ();
std::size_t const numPeers = getApp().getPeers ().getPeerVector ().size ();

View File

@@ -126,7 +126,7 @@ namespace ripple
#include "misc/ripple_NicknameState.h"
#include "ledger/Ledger.h"
#include "ledger/SerializedValidation.h"
#include "main/ripple_ILoadManager.h"
#include "main/ripple_LoadManager.h"
#include "misc/ripple_ProofOfWork.h"
#include "misc/ripple_InfoSub.h"
#include "misc/ripple_OrderBook.h"

View File

@@ -11,9 +11,7 @@
*/
/** Core classes.
This module contains the Ripple core instance object and related objects.
@defgroup ripple_app
*/

View File

@@ -0,0 +1,165 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_CORE_FUNCTIONAL_LOADSOURCE_H_INCLUDED
#define RIPPLE_CORE_FUNCTIONAL_LOADSOURCE_H_INCLUDED
/** 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) noexcept
{
mName = name;
}
/** Retrieve the name of this endpoint.
*/
std::string const& getName () const noexcept
{
return mName;
}
/** Determine if this endpoint is privileged.
*/
bool isPrivileged () const noexcept
{
return (mFlags & lsfPrivileged) != 0;
}
/** Grant the privileged attribute on this endpoint.
*/
void setPrivileged () noexcept
{
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 noexcept
{
return mBalance;
}
/** Returns true if the endpoint received a log warning.
*/
bool isLogged () const noexcept
{
return mLogged;
}
/** Reset the flag indicating the endpoint received a log warning.
*/
void clearLogged () noexcept
{
mLogged = false;
}
/** Indicate that this endpoint is an outgoing connection.
*/
void setOutbound () noexcept
{
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 LoadManagerImp;
// VFALCO TODO Rename these for clarity
static const int lsfPrivileged = 1;
static const int lsfOutbound = 2;
private:
std::string mName;
int mBalance;
int mFlags;
int mLastUpdate;
int mLastWarning;
bool mLogged;
};
#endif

View File

@@ -0,0 +1,64 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_CORE_FUNCTIONAL_LOADTYPE_H_INCLUDED
#define RIPPLE_CORE_FUNCTIONAL_LOADTYPE_H_INCLUDED
// types of load that can be placed on the server
/** The type of load placed on the server.
*/
/* VFALCO TODO
- Remove LT_ from each enum
- Put LoadType into a struct like this:
(Note this is modeled after boost::system::error_code::err_c)
struct LoadType
{
enum load_c
{
invalidRequest,
//...
}
};
// For parameters
typedef LoadType::load_c LoadTypeParam;
// Example of passing a LoadType:
peer->applyLoadCharge (LoadType::newTransaction);
// Example function prototype
void applyLoadCharge (LoadTypeParam loadType);
*/
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
};
#endif

View File

@@ -28,8 +28,8 @@
namespace ripple
{
// VFALCO NOTE Indentation shows dependency hierarchy
//
// Order matters
/***/#include "functional/ripple_ConfigSections.h"
/**/#include "functional/ripple_Config.h"
/**/#include "functional/ripple_ILoadFeeTrack.h"
@@ -37,6 +37,8 @@ namespace ripple
/*..*/#include "functional/ripple_LoadMonitor.h"
/*.*/#include "functional/ripple_Job.h"
/**/#include "functional/ripple_JobQueue.h"
/*.*/#include "functional/LoadType.h"
/**/#include "functional/LoadSource.h"
#include "validator/ripple_Validator.h"
#include "validator/ripple_ValidatorList.h"