Full Refactor of LoadManager

This commit is contained in:
Vinnie Falco
2013-06-23 21:26:44 -07:00
parent 5c21ce5b3c
commit 36ecca14d7
18 changed files with 1222 additions and 1027 deletions

View File

@@ -1762,7 +1762,7 @@
<ClInclude Include="..\..\src\cpp\ripple\LedgerMaster.h" />
<ClInclude Include="..\..\src\cpp\ripple\LedgerProposal.h" />
<ClInclude Include="..\..\src\cpp\ripple\LedgerTiming.h" />
<ClInclude Include="..\..\src\cpp\ripple\ripple_LoadManager.h" />
<ClInclude Include="..\..\src\cpp\ripple\ripple_ILoadManager.h" />
<ClInclude Include="..\..\src\cpp\ripple\ripple_InboundLedgers.h" />
<ClInclude Include="..\..\src\cpp\ripple\NetworkOPs.h" />
<ClInclude Include="..\..\src\cpp\ripple\ripple_NicknameState.h" />

View File

@@ -600,9 +600,6 @@
<ClCompile Include="..\..\src\cpp\ripple\ripple_NicknameState.cpp">
<Filter>1. Modules\ripple_app\refactored</Filter>
</ClCompile>
<ClCompile Include="..\..\src\cpp\ripple\ripple_LoadManager.cpp">
<Filter>1. Modules\ripple_app\refactored</Filter>
</ClCompile>
<ClCompile Include="..\..\src\cpp\ripple\ripple_Application.cpp">
<Filter>1. Modules\ripple_app\refactored</Filter>
</ClCompile>
@@ -900,6 +897,9 @@
<ClCompile Include="..\..\modules\ripple_core\functional\ripple_LoadFeeTrack.cpp">
<Filter>1. Modules\ripple_core\functional</Filter>
</ClCompile>
<ClCompile Include="..\..\src\cpp\ripple\ripple_LoadManager.cpp">
<Filter>1. Modules\ripple_app\refactored</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\cpp\protobuf\src\google\protobuf\service.h">
@@ -1409,9 +1409,6 @@
<ClInclude Include="..\..\src\cpp\ripple\ripple_NicknameState.h">
<Filter>1. Modules\ripple_app\refactored</Filter>
</ClInclude>
<ClInclude Include="..\..\src\cpp\ripple\ripple_LoadManager.h">
<Filter>1. Modules\ripple_app\refactored</Filter>
</ClInclude>
<ClInclude Include="..\..\src\cpp\ripple\ripple_IApplication.h">
<Filter>1. Modules\ripple_app\refactored</Filter>
</ClInclude>
@@ -1725,6 +1722,9 @@
<ClInclude Include="..\..\modules\ripple_core\functional\ripple_ILoadFeeTrack.h">
<Filter>1. Modules\ripple_core\functional</Filter>
</ClInclude>
<ClInclude Include="..\..\src\cpp\ripple\ripple_ILoadManager.h">
<Filter>1. Modules\ripple_app\refactored</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\src\cpp\protobuf\src\google\protobuf\descriptor.proto">

View File

@@ -135,7 +135,7 @@
#include "src/cpp/ripple/Ledger.h"
#include "src/cpp/ripple/SerializedValidation.h"
#include "src/cpp/ripple/ripple_LoadManager.h"
#include "src/cpp/ripple/ripple_ILoadManager.h"
// These have few dependencies
#include "src/cpp/ripple/ripple_DatabaseCon.h"

View File

@@ -10,6 +10,7 @@
@ingroup ripple_client
*/
/*
#include <set>
#include <boost/unordered_set.hpp>
@@ -22,6 +23,8 @@
#include "../ripple_data/ripple_data.h"
*/
/*
#include "src/cpp/ripple/ripple_InfoSub.h"
@@ -44,7 +47,7 @@
#include "src/cpp/ripple/Ledger.h"
#include "src/cpp/ripple/ripple_LedgerEntrySet.h"
#include "src/cpp/ripple/TransactionEngine.h"
#include "src/cpp/ripple/ripple_LoadManager.h"
#include "src/cpp/ripple/ripple_ILoadManager.h"
#include "src/cpp/ripple/ripple_Peer.h"
#include "src/cpp/ripple/ripple_PeerSet.h"
#include "src/cpp/ripple/ripple_InboundLedger.h"

View File

@@ -616,6 +616,9 @@ void NetworkOPs::checkState (const boost::system::error_code& result)
if ((result == boost::asio::error::operation_aborted) || theConfig.RUN_STANDALONE)
{
// VFALCO NOTE Should never get here. This is probably dead code.
// If RUN_STANDALONE is set then this function isn't called.
//
WriteLog (lsFATAL, NetworkOPs) << "Network state timer error: " << result;
return;
}
@@ -623,7 +626,7 @@ void NetworkOPs::checkState (const boost::system::error_code& result)
{
ScopedLock sl (theApp->getMasterLock ());
theApp->getLoadManager ().noDeadLock ();
theApp->getLoadManager ().resetDeadlockDetector ();
std::vector<Peer::pointer> peerList = theApp->getPeers ().getPeerVector ();

File diff suppressed because it is too large Load Diff

View File

@@ -15,13 +15,34 @@
class NetworkOPs;
class InfoSub;
// VFALCO TODO Refactor to abstract interface IRPCHandler
//
class RPCHandler
{
NetworkOPs* mNetOps;
InfoSub::pointer mInfoSub;
int mRole;
public:
enum
{
GUEST,
USER,
ADMIN,
FORBID
};
typedef Json::Value (RPCHandler::*doFuncPtr) (Json::Value params, int& cost, ScopedLock& MasterLockHolder);
explicit RPCHandler (NetworkOPs* netOps);
RPCHandler (NetworkOPs* netOps, InfoSub::pointer infoSub);
Json::Value doCommand (const Json::Value& jvRequest, int role, LoadType* loadType);
Json::Value doRpcCommand (const std::string& strCommand, Json::Value& jvParams, int iRole, LoadType* loadType);
private:
typedef Json::Value (RPCHandler::*doFuncPtr) (
Json::Value params,
LoadType* loadType,
ScopedLock& MasterLockHolder);
// VFALCO TODO Document these and give the enumeration a label.
enum
{
optNone = 0,
@@ -31,102 +52,115 @@ class RPCHandler
};
// Utilities
void addSubmitPath (Json::Value& txJSON);
boost::unordered_set<RippleAddress> parseAccountIds (const Json::Value& jvArray);
boost::unordered_set <RippleAddress> parseAccountIds (const Json::Value& jvArray);
Json::Value transactionSign (Json::Value jvRequest, bool bSubmit, bool bFailHard, ScopedLock& mlh);
Json::Value lookupLedger (Json::Value jvRequest, Ledger::pointer& lpLedger);
Json::Value getMasterGenerator (Ledger::ref lrLedger, const RippleAddress& naRegularSeed, RippleAddress& naMasterGenerator);
Json::Value authorize (Ledger::ref lrLedger, const RippleAddress& naRegularSeed, const RippleAddress& naSrcAccountID,
RippleAddress& naAccountPublic, RippleAddress& naAccountPrivate,
STAmount& saSrcBalance, const STAmount& saFee, AccountState::pointer& asSrc,
const RippleAddress& naVerifyGenerator);
Json::Value accounts (Ledger::ref lrLedger, const RippleAddress& naMasterGenerator);
Json::Value getMasterGenerator (
Ledger::ref lrLedger,
const RippleAddress& naRegularSeed,
RippleAddress& naMasterGenerator);
Json::Value accountFromString (Ledger::ref lrLedger, RippleAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex, const bool bStrict);
Json::Value authorize (
Ledger::ref lrLedger,
const RippleAddress& naRegularSeed,
const RippleAddress& naSrcAccountID,
RippleAddress& naAccountPublic,
RippleAddress& naAccountPrivate,
STAmount& saSrcBalance,
const STAmount& saFee,
AccountState::pointer& asSrc,
const RippleAddress& naVerifyGenerator);
Json::Value doAccountInfo (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountLines (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountOffers (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountTransactions (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doBookOffers (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doConnect (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doConsensusInfo (Json::Value params, int& cost, ScopedLock& mlh);
#if ENABLE_INSECURE
Json::Value doDataDelete (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doDataFetch (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doDataStore (Json::Value params, int& cost, ScopedLock& mlh);
#endif
Json::Value doFeature (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doGetCounts (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doInternal (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedger (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLogLevel (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLogRotate (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doNicknameInfo (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doOwnerInfo (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doPeers (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doPathFind (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doPing (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProfile (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProofCreate (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProofSolve (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doProofVerify (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doRandom (Json::Value jvRequest, int& cost, ScopedLock& mlh);
Json::Value doRipplePathFind (Json::Value jvRequest, int& cost, ScopedLock& mlh);
Json::Value doServerInfo (Json::Value params, int& cost, ScopedLock& mlh); // for humans
Json::Value doServerState (Json::Value params, int& cost, ScopedLock& mlh); // for machines
Json::Value doSessionClose (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSessionOpen (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSMS (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doStop (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSign (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doSubmit (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doTx (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doTxHistory (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlAdd (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlDelete (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlFetch (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlList (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlLoad (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlNetwork (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlReset (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnlScore (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value accounts (
Ledger::ref lrLedger,
const RippleAddress& naMasterGenerator);
Json::Value doValidationCreate (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doValidationSeed (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value accountFromString (
Ledger::ref lrLedger,
RippleAddress& naAccount,
bool& bIndex,
const std::string& strIdent,
const int iIndex,
const bool bStrict);
Json::Value doWalletAccounts (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletLock (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletPropose (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletSeed (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletUnlock (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doWalletVerify (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doAccountInfo (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doAccountLines (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doAccountOffers (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doAccountTransactions (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doBookOffers (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doConnect (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doConsensusInfo (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doFeature (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doGetCounts (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doInternal (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doLedger (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doLedgerAccept (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doLedgerClosed (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doLedgerCurrent (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doLedgerEntry (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doLedgerHeader (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doLogLevel (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doLogRotate (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doNicknameInfo (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doOwnerInfo (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doPathFind (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doPeers (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doPing (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doProfile (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doProofCreate (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doProofSolve (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doProofVerify (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doRandom (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doRipplePathFind (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doSMS (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doServerInfo (Json::Value params, LoadType* loadType, ScopedLock& mlh); // for humans
Json::Value doServerState (Json::Value params, LoadType* loadType, ScopedLock& mlh); // for machines
Json::Value doSessionClose (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doSessionOpen (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doSign (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doStop (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doSubmit (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doSubscribe (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doTransactionEntry (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doTx (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doTxHistory (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doUnlAdd (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doUnlDelete (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doUnlFetch (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doUnlList (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doUnlLoad (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doUnlNetwork (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doUnlReset (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doUnlScore (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doUnsubscribe (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doValidationCreate (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doValidationSeed (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doWalletAccounts (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doWalletLock (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doWalletPropose (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doWalletSeed (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doWalletUnlock (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doWalletVerify (Json::Value params, LoadType* loadType, ScopedLock& mlh);
#if ENABLE_INSECURE
Json::Value doLogin (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doDataDelete (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doDataFetch (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doDataStore (Json::Value params, LoadType* loadType, ScopedLock& mlh);
Json::Value doLogin (Json::Value params, LoadType* loadType, ScopedLock& mlh);
#endif
Json::Value doLedgerAccept (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerClosed (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerCurrent (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerEntry (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doLedgerHeader (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doTransactionEntry (Json::Value params, int& cost, ScopedLock& mlh);
private:
NetworkOPs* mNetOps;
InfoSub::pointer mInfoSub;
Json::Value doSubscribe (Json::Value params, int& cost, ScopedLock& mlh);
Json::Value doUnsubscribe (Json::Value params, int& cost, ScopedLock& mlh);
public:
enum { GUEST, USER, ADMIN, FORBID };
RPCHandler (NetworkOPs* netOps);
RPCHandler (NetworkOPs* netOps, InfoSub::pointer infoSub);
Json::Value doCommand (const Json::Value& jvRequest, int role, int& cost);
Json::Value doRpcCommand (const std::string& strCommand, Json::Value& jvParams, int iRole, int& cost);
// VFALCO TODO Create an enumeration for this.
int mRole;
};
class RPCInternalHandler

View File

@@ -153,8 +153,11 @@ std::string RPCServer::handleRequest (const std::string& requestStr)
RPCHandler mRPCHandler (mNetOps);
WriteLog (lsINFO, RPCServer) << valParams;
int cost = 10;
Json::Value result = mRPCHandler.doRpcCommand (strMethod, valParams, mRole, cost);
LoadType loadType = LT_RPCReference;
Json::Value result = mRPCHandler.doRpcCommand (strMethod, valParams, mRole, &loadType);
// VFALCO NOTE We discard loadType since there is no endpoint to punish
WriteLog (lsINFO, RPCServer) << result;
std::string strReply = JSONRPCReply (result, Json::Value (), id);

View File

@@ -86,6 +86,8 @@ public:
{
if (theApp->getLoadManager ().shouldCutoff (mLoadSource))
{
// VFALCO TODO This must be implemented before open sourcing
#if SHOULD_DISCONNECT
// FIXME: Must dispatch to strand
connection_ptr ptr = mConnection.lock ();
@@ -97,6 +99,8 @@ public:
#endif
}
// Requests without "command" are invalid.
//
if (!jvRequest.isMember ("command"))
{
Json::Value jvResult (Json::objectValue);
@@ -111,11 +115,12 @@ public:
jvResult["id"] = jvRequest["id"];
}
theApp->getLoadManager ().adjust (mLoadSource, -5);
theApp->getLoadManager ().applyLoadCharge (mLoadSource, LT_RPCInvalid);
return jvResult;
}
int cost = 10;
LoadType loadType = LT_RPCReference;
RPCHandler mRPCHandler (&mNetwork, boost::dynamic_pointer_cast<InfoSub> (this->shared_from_this ()));
Json::Value jvResult (Json::objectValue);
@@ -129,11 +134,16 @@ public:
}
else
{
jvResult["result"] = mRPCHandler.doCommand (jvRequest, iRole, cost);
jvResult["result"] = mRPCHandler.doCommand (jvRequest, iRole, &loadType);
}
if (theApp->getLoadManager ().adjust (mLoadSource, -cost) && theApp->getLoadManager ().shouldWarn (mLoadSource))
// Debit/credit the load and see if we should include a warning.
//
if (theApp->getLoadManager ().applyLoadCharge (mLoadSource, loadType) &&
theApp->getLoadManager ().shouldWarn (mLoadSource))
{
jvResult["warning"] = "load";
}
// Currently we will simply unwrap errors returned by the RPC
// API, in the future maybe we can make the responses

View File

@@ -35,8 +35,9 @@ void startServer ()
RPCHandler rhHandler (&theApp->getOPs ());
int cost = 10;
Json::Value jvResult = rhHandler.doCommand (jvCommand, RPCHandler::ADMIN, cost);
// VFALCO TODO Clean up this magic number
LoadType loadType = LT_RPCReference;
Json::Value jvResult = rhHandler.doCommand (jvCommand, RPCHandler::ADMIN, &loadType);
if (!theConfig.QUIET)
std::cerr << "Result: " << jvResult << std::endl;

View File

@@ -4,8 +4,11 @@
*/
//==============================================================================
// VFALCO TODO Wrap this up in something neater. Replace NULL with nullptr
IApplication* theApp = NULL;
// VFALCO TODO Clean this global up
volatile bool doShutdown = false;
// VFALCO TODO Wrap this up in something neater.
IApplication* theApp = nullptr;
class Application;
@@ -73,9 +76,9 @@ public:
return mMasterLock;
}
LoadManager& getLoadManager ()
ILoadManager& getLoadManager ()
{
return mLoadMgr;
return *m_loadManager;
}
TXQueue& getTxnQueue ()
@@ -218,7 +221,6 @@ private:
SLECache mSLECache;
SNTPClient mSNTPClient;
JobQueue mJobQueue;
LoadManager mLoadMgr;
TXQueue mTxnQueue;
OrderBookDB mOrderBookDB;
@@ -231,6 +233,7 @@ private:
beast::ScopedPointer <IUniqueNodeList> mUNL;
beast::ScopedPointer <IProofOfWorkFactory> mProofOfWorkFactory;
beast::ScopedPointer <IPeers> mPeers;
beast::ScopedPointer <ILoadManager> m_loadManager;
// VFALCO End Clean stuff
DatabaseCon* mRpcDB;
@@ -274,6 +277,7 @@ Application::Application ()
, mUNL (IUniqueNodeList::New (mIOService))
, mProofOfWorkFactory (IProofOfWorkFactory::New ())
, mPeers (IPeers::New (mIOService))
, m_loadManager (ILoadManager::New ())
// VFALCO End new stuff
// VFALCO TODO replace all NULL with nullptr
, mRpcDB (NULL)
@@ -296,7 +300,8 @@ Application::Application ()
HashMaps::getInstance ().initializeNonce <size_t> ();
}
// VFALCO TODO Tidy these up into some class with accessors.
//
extern const char* RpcDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[],
*NetNodeDBInit[], *PathFindDBInit[];
extern int RpcDBCount, TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount,
@@ -327,8 +332,6 @@ static void InitDB (DatabaseCon** dbCon, const char* fileName, const char* dbIni
*dbCon = new DatabaseCon (fileName, dbInit, dbCount);
}
volatile bool doShutdown = false;
#ifdef SIGINT
void sigIntHandler (int)
{
@@ -349,6 +352,10 @@ static void runIO (boost::asio::io_service& io)
io.run ();
}
// VFALCO TODO Break this function up into many small initialization segments.
// Or better yet refactor these initializations into RAII classes
// which are members of the Application object.
//
void Application::setup ()
{
// VFALCO NOTE: 0 means use heuristics to determine the thread count.
@@ -356,7 +363,8 @@ void Application::setup ()
mSweepTimer.expires_from_now (boost::posix_time::seconds (10));
mSweepTimer.async_wait (boost::bind (&Application::sweep, this));
mLoadMgr.init ();
m_loadManager->startThread ();
#ifndef WIN32
#ifdef SIGINT
@@ -617,6 +625,8 @@ void Application::setup ()
}
else
{
// VFALCO NOTE the state timer resets the deadlock detector.
//
mNetOps.setStateTimer ();
}
}
@@ -629,7 +639,12 @@ void Application::run ()
}
if (!theConfig.RUN_STANDALONE)
theApp->getLoadManager ().arm ();
{
// VFALCO NOTE This seems unnecessary. If we properly refactor the load
// manager then the deadlock detector can just always be "armed"
//
theApp->getLoadManager ().activateDeadlockDetector ();
}
mIOService.run (); // This blocks

View File

@@ -65,6 +65,7 @@ public:
virtual IFeeVote& getFeeVote () = 0;
virtual IHashRouter& getHashRouter () = 0;
virtual ILoadFeeTrack& getFeeTrack () = 0;
virtual ILoadManager& getLoadManager () = 0;
virtual IPeers& getPeers () = 0;
virtual IProofOfWorkFactory& getProofOfWorkFactory () = 0;
virtual IUniqueNodeList& getUNL () = 0;
@@ -72,22 +73,23 @@ public:
virtual HashedObjectStore& getHashedObjectStore () = 0;
virtual JobQueue& getJobQueue () = 0;
virtual InboundLedgers& getInboundLedgers () = 0;
virtual InboundLedgers& getInboundLedgers () = 0;
virtual LedgerMaster& getLedgerMaster () = 0;
virtual LoadManager& getLoadManager () = 0;
virtual NetworkOPs& getOPs () = 0;
virtual OrderBookDB& getOrderBookDB () = 0;
virtual PeerDoor& getPeerDoor () = 0;
virtual TransactionMaster& getMasterTransaction () = 0;
virtual TXQueue& getTxnQueue () = 0;
virtual LocalCredentials& getLocalCredentials () = 0;
virtual LocalCredentials& getLocalCredentials () = 0;
virtual DatabaseCon* getRpcDB () = 0;
virtual DatabaseCon* getTxnDB () = 0;
virtual DatabaseCon* getLedgerDB () = 0;
virtual DatabaseCon* getWalletDB () = 0;
virtual DatabaseCon* getNetNodeDB () = 0;
virtual DatabaseCon* getPathFindDB () = 0;
// VFALCO NOTE It looks like this isn't used...
//virtual DatabaseCon* getNetNodeDB () = 0;
// VFALCO NOTE It looks like this isn't used...
//virtual DatabaseCon* getPathFindDB () = 0;
virtual DatabaseCon* getHashNodeDB () = 0;
virtual leveldb::DB* getHashNodeLDB () = 0;

View File

@@ -0,0 +1,265 @@
//------------------------------------------------------------------------------
/*
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 Why even bother with a warning? Why can't we just drop?
// 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.
@see LoadSource, LoadType
*/
class ILoadManager
{
public:
/** Create a new manager.
@note The thresholds for warnings and punishments are in
the ctor-initializer
*/
static ILoadManager* New ();
virtual ~ILoadManager () { }
/** Start the associated thread.
This is here to prevent the deadlock detector from activating during
a lengthy program initialization.
@note In stand-alone mode, this might not get called.
*/
// VFALCO TODO Simplify the two stage initialization to one stage (construction).
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

@@ -90,7 +90,7 @@ void InboundLedgers::gotLedgerData (Job&, uint256 hash,
WriteLog (lsTRACE, InboundLedger) << "Got data for ledger we're not acquiring";
if (peer)
peer->punishPeer (LT_InvalidRequest);
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -105,14 +105,14 @@ void InboundLedgers::gotLedgerData (Job&, uint256 hash,
if (packet.nodes_size () < 1)
{
WriteLog (lsWARNING, InboundLedger) << "Got empty base data";
peer->punishPeer (LT_InvalidRequest);
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
if (!ledger->takeBase (packet.nodes (0).nodedata ()))
{
WriteLog (lsWARNING, InboundLedger) << "Got invalid base data";
peer->punishPeer (LT_InvalidRequest);
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -147,7 +147,7 @@ void InboundLedgers::gotLedgerData (Job&, uint256 hash,
if (packet.nodes ().size () <= 0)
{
WriteLog (lsINFO, InboundLedger) << "Got response with no nodes";
peer->punishPeer (LT_InvalidRequest);
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -158,7 +158,7 @@ void InboundLedgers::gotLedgerData (Job&, uint256 hash,
if (!node.has_nodeid () || !node.has_nodedata ())
{
WriteLog (lsWARNING, InboundLedger) << "Got bad node";
peer->punishPeer (LT_InvalidRequest);
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -185,7 +185,7 @@ void InboundLedgers::gotLedgerData (Job&, uint256 hash,
}
WriteLog (lsWARNING, InboundLedger) << "Not sure what ledger data we got";
peer->punishPeer (LT_InvalidRequest);
peer->applyLoadCharge (LT_InvalidRequest);
}
void InboundLedgers::sweep ()

View File

@@ -6,302 +6,426 @@
SETUP_LOG (LoadManager)
LoadManager::LoadManager (int creditRate, int creditLimit, int debitWarn, int debitLimit)
: mCreditRate (creditRate)
, mCreditLimit (creditLimit)
, mDebitWarn (debitWarn)
, mDebitLimit (debitLimit)
, mShutdown (false)
, mArmed (false)
, mDeadLock (0)
, mCosts (LT_MAX)
//------------------------------------------------------------------------------
class LoadManager : public ILoadManager
{
addCost (Cost (LT_InvalidRequest, -10, LC_CPU | LC_Network));
addCost (Cost (LT_RequestNoReply, -1, LC_CPU | LC_Disk));
addCost (Cost (LT_InvalidSignature, -100, LC_CPU));
addCost (Cost (LT_UnwantedData, -5, LC_CPU | LC_Network));
addCost (Cost (LT_BadData, -20, LC_CPU));
private:
/* Entry mapping utilization to cost.
addCost (Cost (LT_NewTrusted, -10, 0));
addCost (Cost (LT_NewTransaction, -2, 0));
addCost (Cost (LT_NeededData, -10, 0));
addCost (Cost (LT_RequestData, -5, LC_Disk | LC_Network));
addCost (Cost (LT_CheapQuery, -1, LC_CPU));
}
void LoadManager::init ()
{
UptimeTimer::getInstance ().beginManualUpdates ();
boost::thread (boost::bind (&LoadManager::threadEntry, this)).detach ();
}
LoadManager::~LoadManager ()
{
UptimeTimer::getInstance ().endManualUpdates ();
// VFALCO What is this loop? it doesn't seem to do anything useful.
do
The cost is expressed as a unitless relative quantity. These
mappings are statically loaded at startup with heuristic values.
*/
class Cost
{
boost::this_thread::sleep (boost::posix_time::milliseconds (100));
public:
// VFALCO TODO Eliminate this default ctor somehow
Cost ()
: m_loadType ()
, m_cost (0)
, m_resourceFlags (0)
{
boost::mutex::scoped_lock sl (mLock);
if (!mShutdown)
return;
}
}
while (1);
}
void LoadManager::noDeadLock ()
{
boost::mutex::scoped_lock sl (mLock);
//mDeadLock = mUptime;
mDeadLock = UptimeTimer::getInstance ().getElapsedSeconds ();
}
int LoadManager::getCreditRate () const
{
boost::mutex::scoped_lock sl (mLock);
return mCreditRate;
}
int LoadManager::getCreditLimit () const
{
boost::mutex::scoped_lock sl (mLock);
return mCreditLimit;
}
int LoadManager::getDebitWarn () const
{
boost::mutex::scoped_lock sl (mLock);
return mDebitWarn;
}
int LoadManager::getDebitLimit () const
{
boost::mutex::scoped_lock sl (mLock);
return mDebitLimit;
}
void LoadManager::setCreditRate (int r)
{
boost::mutex::scoped_lock sl (mLock);
mCreditRate = r;
}
void LoadManager::setCreditLimit (int r)
{
boost::mutex::scoped_lock sl (mLock);
mCreditLimit = r;
}
void LoadManager::setDebitWarn (int r)
{
boost::mutex::scoped_lock sl (mLock);
mDebitWarn = r;
}
void LoadManager::setDebitLimit (int r)
{
boost::mutex::scoped_lock sl (mLock);
mDebitLimit = r;
}
void LoadManager::canonicalize (LoadSource& source, int now) const
{
if (source.mLastUpdate != now)
{
if (source.mLastUpdate < now)
Cost (LoadType loadType, int cost, int resourceFlags)
: m_loadType (loadType)
, m_cost (cost)
, m_resourceFlags (resourceFlags)
{
source.mBalance += mCreditRate * (now - source.mLastUpdate);
if (source.mBalance > mCreditLimit)
{
source.mBalance = mCreditLimit;
source.mLogged = false;
}
}
source.mLastUpdate = now;
}
}
bool LoadManager::shouldWarn (LoadSource& source) const
{
{
boost::mutex::scoped_lock sl (mLock);
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
if (source.isPrivileged () || (source.mBalance > mDebitWarn) || (source.mLastWarning == now))
return false;
source.mLastWarning = now;
}
logWarning (source.getName ());
return true;
}
bool LoadManager::shouldCutoff (LoadSource& source) const
{
{
boost::mutex::scoped_lock sl (mLock);
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
if (source.isPrivileged () || (source.mBalance > mDebitLimit))
return false;
if (source.mLogged)
return true;
source.mLogged = true;
}
logDisconnect (source.getName ());
return true;
}
bool LoadManager::adjust (LoadSource& source, LoadType t) const
{
// FIXME: Scale by category
Cost cost = mCosts[static_cast<int> (t)];
return adjust (source, cost.mCost);
}
bool LoadManager::adjust (LoadSource& source, int credits) const
{
// return: true = need to warn/cutoff
// We do it this way in case we want to add exponential decay later
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
source.mBalance += credits;
if (source.mBalance > mCreditLimit)
source.mBalance = mCreditLimit;
if (source.isPrivileged ()) // privileged sources never warn/cutoff
return false;
if ((source.mBalance >= mDebitLimit) && (source.mLastWarning == now)) // no need to warn
return false;
return true;
}
static void LogDeadLock (int dlTime)
{
WriteLog (lsWARNING, LoadManager) << "Server stalled for " << dlTime << " seconds.";
}
void LoadManager::threadEntry ()
{
setCallingThreadName ("loadmgr");
// VFALCO TODO replace this with a beast Time object?
//
// Initialize the clock to the current time.
boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time ();
for (;;)
{
LoadType getLoadType () const
{
// VFALCO NOTE What is this lock protecting?
boost::mutex::scoped_lock sl (mLock);
return m_loadType;
}
// Check for the shutdown flag.
if (mShutdown)
int getCost () const
{
return m_cost;
}
int getResourceFlags () const
{
return m_resourceFlags;
}
public:
// VFALCO TODO Make these private and const
LoadType m_loadType;
int m_cost;
int m_resourceFlags;
};
public:
LoadManager ()
: mCreditRate (100)
, mCreditLimit (500)
, mDebitWarn (-500)
, mDebitLimit (-1000)
, mShutdown (false)
, mArmed (false)
, mDeadLock (0)
, mCosts (LT_MAX)
{
/** Flags indicating the type of load.
Utilization may include any combination of:
- CPU
- Storage space
- Network transfer
*/
// VFALCO NOTE These flags are not used...
enum
{
flagDisk = 1,
flagCpu = 2,
flagNet = 4
};
// VFALCO TODO Replace this with a function that uses a simple switch statement...
//
addCost (Cost (LT_InvalidRequest, -10, flagCpu | flagNet));
addCost (Cost (LT_RequestNoReply, -1, flagCpu | flagDisk));
addCost (Cost (LT_InvalidSignature, -100, flagCpu));
addCost (Cost (LT_UnwantedData, -5, flagCpu | flagNet));
addCost (Cost (LT_BadData, -20, flagCpu));
addCost (Cost (LT_RPCInvalid, -10, flagCpu | flagNet));
addCost (Cost (LT_RPCReference, -10, flagCpu | flagNet));
addCost (Cost (LT_RPCException, -20, flagCpu | flagNet));
addCost (Cost (LT_RPCBurden, -50, flagCpu | flagNet));
// VFALCO NOTE Why do these supposedly "good" load types still have a negative cost?
//
addCost (Cost (LT_NewTrusted, -10, 0));
addCost (Cost (LT_NewTransaction, -2, 0));
addCost (Cost (LT_NeededData, -10, 0));
addCost (Cost (LT_RequestData, -5, flagDisk | flagNet));
addCost (Cost (LT_CheapQuery, -1, flagCpu));
}
private:
~LoadManager ()
{
UptimeTimer::getInstance ().endManualUpdates ();
// VFALCO TODO What is the purpose of this loop? Figure out
// a better way to do it.
for (;;)
{
boost::this_thread::sleep (boost::posix_time::milliseconds (100));
{
// VFALCO NOTE Why clear the flag now?
mShutdown = false;
return;
boost::mutex::scoped_lock sl (mLock);
if (!mShutdown)
return;
}
}
}
// VFALCO NOTE I think this is to reduce calls to the operating system
// for retrieving the current time.
//
// TODO Instead of incrementing can't we just retrieve the current
// time again?
//
// Manually update the timer.
UptimeTimer::getInstance ().incrementElapsedTime ();
void startThread ()
{
UptimeTimer::getInstance ().beginManualUpdates ();
// Measure the amount of time we have been deadlocked, in seconds.
//
// VFALCO NOTE mDeadLock is a canary for detecting the condition.
int const timeSpentDeadlocked = UptimeTimer::getInstance ().getElapsedSeconds () - mDeadLock;
boost::thread (boost::bind (&LoadManager::threadEntry, this)).detach ();
}
if (mArmed && (timeSpentDeadlocked >= 10))
void canonicalize (LoadSource& source, int now) const
{
if (source.mLastUpdate != now)
{
if (source.mLastUpdate < now)
{
// Report the deadlocked condition every 10 seconds
if ((timeSpentDeadlocked % 10) == 0)
source.mBalance += mCreditRate * (now - source.mLastUpdate);
if (source.mBalance > mCreditLimit)
{
// VFALCO TODO Replace this with a dedicated thread with call queue.
//
boost::thread (BIND_TYPE (&LogDeadLock, timeSpentDeadlocked)).detach ();
source.mBalance = mCreditLimit;
source.mLogged = false;
}
}
source.mLastUpdate = now;
}
}
bool shouldWarn (LoadSource& source) const
{
{
boost::mutex::scoped_lock sl (mLock);
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
if (source.isPrivileged () || (source.mBalance > mDebitWarn) || (source.mLastWarning == now))
return false;
source.mLastWarning = now;
}
logWarning (source.getName ());
return true;
}
bool shouldCutoff (LoadSource& source) const
{
{
boost::mutex::scoped_lock sl (mLock);
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
if (source.isPrivileged () || (source.mBalance > mDebitLimit))
return false;
if (source.mLogged)
return true;
source.mLogged = true;
}
logDisconnect (source.getName ());
return true;
}
bool applyLoadCharge (LoadSource& source, LoadType loadType) const
{
// FIXME: Scale by category
Cost cost = mCosts[static_cast<int> (loadType)];
return adjust (source, cost.m_cost);
}
bool adjust (LoadSource& source, int credits) const
{
// return: true = need to warn/cutoff
// We do it this way in case we want to add exponential decay later
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
source.mBalance += credits;
if (source.mBalance > mCreditLimit)
source.mBalance = mCreditLimit;
if (source.isPrivileged ()) // privileged sources never warn/cutoff
return false;
if ((source.mBalance >= mDebitLimit) && (source.mLastWarning == now)) // no need to warn
return false;
return true;
}
void logWarning (const std::string& source) const
{
if (source.empty ())
WriteLog (lsDEBUG, LoadManager) << "Load warning from empty source";
else
WriteLog (lsINFO, LoadManager) << "Load warning: " << source;
}
void logDisconnect (const std::string& source) const
{
if (source.empty ())
WriteLog (lsINFO, LoadManager) << "Disconnect for empty source";
else
WriteLog (lsWARNING, LoadManager) << "Disconnect for: " << source;
}
// VFALCO TODO Implement this and stop accessing the vector directly
//Cost const& getCost (LoadType loadType) const;
int getCost (LoadType t) const
{
return mCosts [static_cast <int> (t)].getCost ();
}
void resetDeadlockDetector ()
{
boost::mutex::scoped_lock sl (mLock);
mDeadLock = UptimeTimer::getInstance ().getElapsedSeconds ();
}
void activateDeadlockDetector ()
{
mArmed = true;
}
static void logDeadlock (int dlTime)
{
WriteLog (lsWARNING, LoadManager) << "Server stalled for " << dlTime << " seconds.";
}
private:
// VFALCO TODO These used to be public but are apparently not used. Find out why.
/*
int getCreditRate () const
{
boost::mutex::scoped_lock sl (mLock);
return mCreditRate;
}
int getCreditLimit () const
{
boost::mutex::scoped_lock sl (mLock);
return mCreditLimit;
}
int getDebitWarn () const
{
boost::mutex::scoped_lock sl (mLock);
return mDebitWarn;
}
int getDebitLimit () const
{
boost::mutex::scoped_lock sl (mLock);
return mDebitLimit;
}
void setCreditRate (int r)
{
boost::mutex::scoped_lock sl (mLock);
mCreditRate = r;
}
void setCreditLimit (int r)
{
boost::mutex::scoped_lock sl (mLock);
mCreditLimit = r;
}
void setDebitWarn (int r)
{
boost::mutex::scoped_lock sl (mLock);
mDebitWarn = r;
}
void setDebitLimit (int r)
{
boost::mutex::scoped_lock sl (mLock);
mDebitLimit = r;
}
*/
private:
void addCost (const Cost& c)
{
mCosts [static_cast <int> (c.getLoadType ())] = c;
}
// VFALCO NOTE Where's the thread object? It's not a data member...
//
void threadEntry ()
{
setCallingThreadName ("loadmgr");
// VFALCO TODO replace this with a beast Time object?
//
// Initialize the clock to the current time.
boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time ();
for (;;)
{
{
// VFALCO NOTE What is this lock protecting?
boost::mutex::scoped_lock sl (mLock);
// Check for the shutdown flag.
if (mShutdown)
{
// VFALCO NOTE Why clear the flag now?
mShutdown = false;
return;
}
// If we go over 500 seconds spent deadlocked, it means that the
// deadlock resolution code has failed, which qualifies as undefined
// behavior.
// VFALCO NOTE I think this is to reduce calls to the operating system
// for retrieving the current time.
//
assert (timeSpentDeadlocked < 500);
// TODO Instead of incrementing can't we just retrieve the current
// time again?
//
// Manually update the timer.
UptimeTimer::getInstance ().incrementElapsedTime ();
// Measure the amount of time we have been deadlocked, in seconds.
//
// VFALCO NOTE mDeadLock is a canary for detecting the condition.
int const timeSpentDeadlocked = UptimeTimer::getInstance ().getElapsedSeconds () - mDeadLock;
// VFALCO NOTE I think that "armed" refers to the deadlock detector
//
if (mArmed && (timeSpentDeadlocked >= 10))
{
// Report the deadlocked condition every 10 seconds
if ((timeSpentDeadlocked % 10) == 0)
{
// VFALCO TODO Replace this with a dedicated thread with call queue.
//
boost::thread (BIND_TYPE (&logDeadlock, timeSpentDeadlocked)).detach ();
}
// If we go over 500 seconds spent deadlocked, it means that the
// deadlock resolution code has failed, which qualifies as undefined
// behavior.
//
assert (timeSpentDeadlocked < 500);
}
}
}
bool change;
bool change;
// VFALCO TODO Eliminate the dependence on the Application object.
// Choices include constructing with the job queue / feetracker.
// Another option is using an observer pattern to invert the dependency.
if (theApp->getJobQueue ().isOverloaded ())
{
WriteLog (lsINFO, LoadManager) << theApp->getJobQueue ().getJson (0);
change = theApp->getFeeTrack ().raiseLocalFee ();
}
else
{
change = theApp->getFeeTrack ().lowerLocalFee ();
}
// VFALCO TODO Eliminate the dependence on the Application object.
// Choices include constructing with the job queue / feetracker.
// Another option is using an observer pattern to invert the dependency.
if (theApp->getJobQueue ().isOverloaded ())
{
WriteLog (lsINFO, LoadManager) << theApp->getJobQueue ().getJson (0);
change = theApp->getFeeTrack ().raiseLocalFee ();
}
else
{
change = theApp->getFeeTrack ().lowerLocalFee ();
}
if (change)
{
// VFALCO TODO replace this with a Listener / observer and subscribe in NetworkOPs or Application
theApp->getOPs ().reportFeeChange ();
}
if (change)
{
// VFALCO TODO replace this with a Listener / observer and subscribe in NetworkOPs or Application
theApp->getOPs ().reportFeeChange ();
}
t += boost::posix_time::seconds (1);
boost::posix_time::time_duration when = t - boost::posix_time::microsec_clock::universal_time ();
t += boost::posix_time::seconds (1);
boost::posix_time::time_duration when = t - boost::posix_time::microsec_clock::universal_time ();
if ((when.is_negative ()) || (when.total_seconds () > 1))
{
WriteLog (lsWARNING, LoadManager) << "time jump";
t = boost::posix_time::microsec_clock::universal_time ();
if ((when.is_negative ()) || (when.total_seconds () > 1))
{
WriteLog (lsWARNING, LoadManager) << "time jump";
t = boost::posix_time::microsec_clock::universal_time ();
}
else
boost::this_thread::sleep (when);
}
else
boost::this_thread::sleep (when);
}
}
void LoadManager::logWarning (const std::string& source) const
private:
int mCreditRate; // credits gained/lost per second
int mCreditLimit; // the most credits a source can have
int mDebitWarn; // when a source drops below this, we warn
int mDebitLimit; // when a source drops below this, we cut it off (should be negative)
bool mShutdown;
bool mArmed;
int mDeadLock; // Detect server deadlocks
mutable boost::mutex mLock; // VFALCO TODO Replace with juce::Mutex and remove the mutable attribute
std::vector <Cost> mCosts;
};
//------------------------------------------------------------------------------
ILoadManager* ILoadManager::New ()
{
if (source.empty ())
WriteLog (lsDEBUG, LoadManager) << "Load warning from empty source";
else
WriteLog (lsINFO, LoadManager) << "Load warning: " << source;
return new LoadManager;
}
void LoadManager::logDisconnect (const std::string& source) const
{
if (source.empty ())
WriteLog (lsINFO, LoadManager) << "Disconnect for empty source";
else
WriteLog (lsWARNING, LoadManager) << "Disconnect for: " << source;
}
// vim:ts=4

View File

@@ -1,257 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LOADMANAGER_H
#define RIPPLE_LOADMANAGER_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
// 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
};
// load categories
// VFALCO NOTE These look like bit flags, name them accordingly
enum
{
LC_Disk = 1,
LC_CPU = 2,
LC_Network = 4
};
/** 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
- Peer connections
@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
{
private:
// VFALCO Make this not a friend
friend class LoadManager;
public:
// load source flags
static const int lsfPrivileged = 1;
static const int lsfOutbound = 2; // outbound connection
public:
/** Construct a load source.
Sources with admin privileges have relaxed or no restrictions
on resource consumption.
@param admin `true` if the source has admin privileges.
*/
explicit LoadSource (bool admin)
: mBalance (0)
, mFlags (admin ? lsfPrivileged : 0)
, mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ())
, mLastWarning (0)
, mLogged (false)
{
}
explicit LoadSource (std::string const& name)
: mName (name)
, mBalance (0)
, mFlags (0)
, mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ())
, mLastWarning (0)
, mLogged (false)
{
}
// 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;
}
std::string const& getName () const
{
return mName;
}
bool isPrivileged () const
{
return (mFlags & lsfPrivileged) != 0;
}
void setPrivileged ()
{
mFlags |= lsfPrivileged;
}
int getBalance () const
{
return mBalance;
}
bool isLogged () const
{
return mLogged;
}
void clearLogged ()
{
mLogged = false;
}
void setOutbound ()
{
mFlags |= lsfOutbound;
}
bool isOutbound () const
{
return (mFlags & lsfOutbound) != 0;
}
private:
std::string mName;
int mBalance;
int mFlags;
int mLastUpdate;
int mLastWarning;
bool mLogged;
};
// a collection of load sources
class LoadManager
{
public:
LoadManager (int creditRate = 100,
int creditLimit = 500,
int debitWarn = -500,
int debitLimit = -1000);
~LoadManager ();
void init ();
bool shouldWarn (LoadSource&) const;
bool shouldCutoff (LoadSource&) const;
bool adjust (LoadSource&, int credits) const; // return value: false=balance okay, true=warn/cutoff
bool adjust (LoadSource&, LoadType l) const;
void logWarning (const std::string&) const;
void logDisconnect (const std::string&) const;
int getCost (LoadType t) const
{
return mCosts [static_cast <int> (t)].mCost;
}
void noDeadLock ();
void arm ()
{
mArmed = true;
}
private:
// VFALCO TODO These used to be public but are apparently not used. Find out why.
int getCreditRate () const;
int getCreditLimit () const;
int getDebitWarn () const;
int getDebitLimit () const;
void setCreditRate (int);
void setCreditLimit (int);
void setDebitWarn (int);
void setDebitLimit (int);
private:
class Cost
{
public:
Cost ()
: mType ()
, mCost (0)
, mCategories (0)
{
}
Cost (LoadType typeOfLoad, int cost, int category)
: mType (typeOfLoad)
, mCost (cost)
, mCategories (category)
{
}
public:
// VFALCO TODO Make these private and const
LoadType mType;
int mCost;
int mCategories;
};
void canonicalize (LoadSource&, int upTime) const;
void addCost (const Cost& c)
{
mCosts [static_cast <int> (c.mType)] = c;
}
// VFALCO NOTE Where's the thread object? It's not a data member...
//
void threadEntry ();
private:
int mCreditRate; // credits gained/lost per second
int mCreditLimit; // the most credits a source can have
int mDebitWarn; // when a source drops below this, we warn
int mDebitLimit; // when a source drops below this, we cut it off (should be negative)
bool mShutdown;
bool mArmed;
int mDeadLock; // Detect server deadlocks
mutable boost::mutex mLock; // VFALCO TODO Replace with juce::Mutex and remove the mutable attribute
std::vector <Cost> mCosts;
};
#endif
// vim:ts=4

View File

@@ -63,7 +63,7 @@ public:
void sendGetPeers ();
void punishPeer (LoadType);
void applyLoadCharge (LoadType);
Json::Value getJson ();
bool isConnected () const
@@ -1070,7 +1070,7 @@ static void checkTransaction (Job&, int flags, SerializedTransaction::pointer st
if (tx->getStatus () == INVALID)
{
theApp->getHashRouter ().setFlag (stx->getTransactionID (), SF_BAD);
Peer::punishPeer (peer, LT_InvalidSignature);
Peer::applyLoadCharge (peer, LT_InvalidSignature);
return;
}
else
@@ -1083,7 +1083,7 @@ static void checkTransaction (Job&, int flags, SerializedTransaction::pointer st
catch (...)
{
theApp->getHashRouter ().setFlags (stx->getTransactionID (), SF_BAD);
punishPeer (peer, LT_InvalidRequest);
applyLoadCharge (peer, LT_InvalidRequest);
}
#endif
@@ -1109,7 +1109,7 @@ void PeerImp::recvTransaction (protocol::TMTransaction& packet, ScopedLock& Mast
// we have seen this transaction recently
if (isSetBit (flags, SF_BAD))
{
punishPeer (LT_InvalidSignature);
applyLoadCharge (LT_InvalidSignature);
return;
}
@@ -1166,7 +1166,7 @@ static void checkPropose (Job& job, boost::shared_ptr<protocol::TMProposeSet> pa
Peer::pointer p = peer.lock ();
WriteLog (lsWARNING, Peer) << "proposal with previous ledger fails signature check: " <<
(p ? p->getIP () : std::string ("???"));
Peer::punishPeer (peer, LT_InvalidSignature);
Peer::applyLoadCharge (peer, LT_InvalidSignature);
return;
}
else
@@ -1210,14 +1210,14 @@ void PeerImp::recvPropose (const boost::shared_ptr<protocol::TMProposeSet>& pack
(set.signature ().size () < 56) || (set.nodepubkey ().size () > 128) || (set.signature ().size () > 128))
{
WriteLog (lsWARNING, Peer) << "Received proposal is malformed";
punishPeer (LT_InvalidSignature);
applyLoadCharge (LT_InvalidSignature);
return;
}
if (set.has_previousledger () && (set.previousledger ().size () != 32))
{
WriteLog (lsWARNING, Peer) << "Received proposal is malformed";
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -1278,7 +1278,7 @@ void PeerImp::recvHaveTxSet (protocol::TMHaveTransactionSet& packet)
if (packet.hash ().size () != (256 / 8))
{
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -1289,7 +1289,7 @@ void PeerImp::recvHaveTxSet (protocol::TMHaveTransactionSet& packet)
addTxSet (hash);
if (!theApp->getOPs ().hasTXSet (shared_from_this (), hash, packet.status ()))
punishPeer (LT_UnwantedData);
applyLoadCharge (LT_UnwantedData);
}
static void checkValidation (Job&, SerializedValidation::pointer val, uint256 signingHash,
@@ -1303,7 +1303,7 @@ static void checkValidation (Job&, SerializedValidation::pointer val, uint256 si
if (!isCluster && !val->isValid (signingHash))
{
WriteLog (lsWARNING, Peer) << "Validation is invalid";
Peer::punishPeer (peer, LT_InvalidRequest);
Peer::applyLoadCharge (peer, LT_InvalidRequest);
return;
}
@@ -1329,7 +1329,7 @@ static void checkValidation (Job&, SerializedValidation::pointer val, uint256 si
catch (...)
{
WriteLog (lsWARNING, Peer) << "Exception processing validation";
Peer::punishPeer (peer, LT_InvalidRequest);
Peer::applyLoadCharge (peer, LT_InvalidRequest);
}
#endif
@@ -1342,7 +1342,7 @@ void PeerImp::recvValidation (const boost::shared_ptr<protocol::TMValidation>& p
if (packet->validation ().size () < 50)
{
WriteLog (lsWARNING, Peer) << "Too small validation from peer";
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -1376,7 +1376,7 @@ void PeerImp::recvValidation (const boost::shared_ptr<protocol::TMValidation>& p
catch (...)
{
WriteLog (lsWARNING, Peer) << "Exception processing validation";
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
}
#endif
@@ -1591,7 +1591,7 @@ void PeerImp::recvProofWork (protocol::TMProofWork& packet)
// this is an answer to a proof of work we requested
if (packet.response ().size () != (256 / 8))
{
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -1609,7 +1609,7 @@ void PeerImp::recvProofWork (protocol::TMProofWork& packet)
// return error message
// WRITEME
if (r != powTOOEASY)
punishPeer (LT_BadPoW);
applyLoadCharge (LT_BadPoW);
return;
}
@@ -1629,7 +1629,7 @@ void PeerImp::recvProofWork (protocol::TMProofWork& packet)
if ((packet.challenge ().size () != (256 / 8)) || (packet.target ().size () != (256 / 8)))
{
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -1640,7 +1640,7 @@ void PeerImp::recvProofWork (protocol::TMProofWork& packet)
if (!pow->isValid ())
{
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -1731,7 +1731,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, ScopedLock& MasterLo
if ((!packet.has_ledgerhash () || packet.ledgerhash ().size () != 32))
{
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
WriteLog (lsWARNING, Peer) << "invalid request for TX candidate set data";
return;
}
@@ -1766,7 +1766,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, ScopedLock& MasterLo
}
WriteLog (lsERROR, Peer) << "We do not have the map our peer wants " << getIP ();
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -1788,7 +1788,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, ScopedLock& MasterLo
if (packet.ledgerhash ().size () != 32)
{
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
WriteLog (lsWARNING, Peer) << "Invalid request";
return;
}
@@ -1844,14 +1844,14 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, ScopedLock& MasterLo
}
else
{
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
WriteLog (lsWARNING, Peer) << "Can't figure out what ledger they want";
return;
}
if ((!ledger) || (packet.has_ledgerseq () && (packet.ledgerseq () != ledger->getLedgerSeq ())))
{
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
if (ShouldLog (lsWARNING, Peer))
{
@@ -1931,7 +1931,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, ScopedLock& MasterLo
if ((!map) || (packet.nodeids_size () == 0))
{
WriteLog (lsWARNING, Peer) << "Can't find map or empty request";
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -1944,7 +1944,7 @@ void PeerImp::recvGetLedger (protocol::TMGetLedger& packet, ScopedLock& MasterLo
if (!mn.isValid ())
{
WriteLog (lsWARNING, Peer) << "Request for invalid node: " << logMe;
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -2005,7 +2005,7 @@ void PeerImp::recvLedger (const boost::shared_ptr<protocol::TMLedgerData>& packe
if (packet.nodes ().size () <= 0)
{
WriteLog (lsWARNING, Peer) << "Ledger/TXset data with no nodes";
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -2021,7 +2021,7 @@ void PeerImp::recvLedger (const boost::shared_ptr<protocol::TMLedgerData>& packe
else
{
WriteLog (lsINFO, Peer) << "Unable to route TX/ledger data reply";
punishPeer (LT_UnwantedData);
applyLoadCharge (LT_UnwantedData);
}
return;
@@ -2032,7 +2032,7 @@ void PeerImp::recvLedger (const boost::shared_ptr<protocol::TMLedgerData>& packe
if (packet.ledgerhash ().size () != 32)
{
WriteLog (lsWARNING, Peer) << "TX candidate reply with invalid hash size";
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -2051,7 +2051,7 @@ void PeerImp::recvLedger (const boost::shared_ptr<protocol::TMLedgerData>& packe
if (!node.has_nodeid () || !node.has_nodedata () || (node.nodeid ().size () != 33))
{
WriteLog (lsWARNING, Peer) << "LedgerData request with invalid node ID";
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -2062,7 +2062,7 @@ void PeerImp::recvLedger (const boost::shared_ptr<protocol::TMLedgerData>& packe
SHAMapAddNode san = theApp->getOPs ().gotTXData (shared_from_this (), hash, nodeIDs, nodeData);
if (san.isInvalid ())
punishPeer (LT_UnwantedData);
applyLoadCharge (LT_UnwantedData);
return;
}
@@ -2072,7 +2072,7 @@ void PeerImp::recvLedger (const boost::shared_ptr<protocol::TMLedgerData>& packe
BIND_TYPE (&InboundLedgers::gotLedgerData, &theApp->getInboundLedgers (),
P_1, hash, packet_ptr, boost::weak_ptr<Peer> (shared_from_this ())));
else
punishPeer (LT_UnwantedData);
applyLoadCharge (LT_UnwantedData);
}
bool PeerImp::hasLedger (uint256 const& hash, uint32 seq) const
@@ -2203,11 +2203,13 @@ void PeerImp::sendGetPeers ()
sendPacket (packet, true);
}
void PeerImp::punishPeer (LoadType l)
void PeerImp::applyLoadCharge (LoadType loadType)
{
if (theApp->getLoadManager ().adjust (mLoad, l))
if (theApp->getLoadManager ().applyLoadCharge (mLoad, loadType))
{
// WRITEME
// UNIMPLEMENTED
// VFALCO TODO This needs to implemented before open sourcing.
}
}
@@ -2251,7 +2253,7 @@ void PeerImp::doFetchPack (const boost::shared_ptr<protocol::TMGetObjectByHash>&
if (packet->ledgerhash ().size () != 32)
{
WriteLog (lsWARNING, Peer) << "FetchPack hash size malformed";
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -2263,14 +2265,14 @@ void PeerImp::doFetchPack (const boost::shared_ptr<protocol::TMGetObjectByHash>&
if (!haveLedger)
{
WriteLog (lsINFO, Peer) << "Peer requests fetch pack for ledger we don't have: " << hash;
punishPeer (LT_RequestNoReply);
applyLoadCharge (LT_RequestNoReply);
return;
}
if (!haveLedger->isClosed ())
{
WriteLog (lsWARNING, Peer) << "Peer requests fetch pack from open ledger: " << hash;
punishPeer (LT_InvalidRequest);
applyLoadCharge (LT_InvalidRequest);
return;
}
@@ -2279,7 +2281,7 @@ void PeerImp::doFetchPack (const boost::shared_ptr<protocol::TMGetObjectByHash>&
if (!wantLedger)
{
WriteLog (lsINFO, Peer) << "Peer requests fetch pack for ledger whose predecessor we don't have: " << hash;
punishPeer (LT_RequestNoReply);
applyLoadCharge (LT_RequestNoReply);
return;
}
@@ -2374,12 +2376,12 @@ Peer::pointer Peer::New (boost::asio::io_service& io_service,
return Peer::pointer (new PeerImp (io_service, ctx, id, inbound));
}
void Peer::punishPeer (const boost::weak_ptr<Peer>& wp, LoadType l)
void Peer::applyLoadCharge (const boost::weak_ptr<Peer>& wp, LoadType l)
{
Peer::pointer p = wp.lock ();
if (p)
p->punishPeer (l);
p->applyLoadCharge (l);
}
// vim:ts=4

View File

@@ -57,10 +57,10 @@ public:
virtual void sendGetPeers () = 0;
virtual void punishPeer (LoadType) = 0;
virtual void applyLoadCharge (LoadType) = 0;
// VFALCO NOTE what's with this odd parameter passing? Why the static member?
static void punishPeer (const boost::weak_ptr<Peer>&, LoadType);
static void applyLoadCharge (const boost::weak_ptr<Peer>&, LoadType);
virtual Json::Value getJson () = 0;