diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index 19b8557d78..44ae01cd19 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -908,7 +908,7 @@ true true - + true true true @@ -1764,11 +1764,11 @@ - + - + diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index bf1eaa7442..71a7cab512 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -270,9 +270,6 @@ [2] Old Ripple\ripple_core\functional - - [2] Old Ripple\ripple_core\functional - [2] Old Ripple\ripple_core\functional @@ -1059,6 +1056,9 @@ [1] Ripple\validators\impl + + [2] Old Ripple\ripple_core\functional + @@ -1100,9 +1100,6 @@ [2] Old Ripple\ripple_basics\utility - - [2] Old Ripple\ripple_core\functional - [2] Old Ripple\ripple_core\functional @@ -1112,9 +1109,6 @@ [2] Old Ripple\ripple_core\functional - - [2] Old Ripple\ripple_core\functional - [2] Old Ripple\ripple_core\functional @@ -2115,6 +2109,12 @@ [1] Ripple\validators\impl + + [2] Old Ripple\ripple_core\functional + + + [2] Old Ripple\ripple_core\functional + diff --git a/doc/todo/VFALCO_TODO.txt b/doc/todo/VFALCO_TODO.txt index d6ec4858b0..7a78ff1e2c 100644 --- a/doc/todo/VFALCO_TODO.txt +++ b/doc/todo/VFALCO_TODO.txt @@ -131,10 +131,6 @@ David Features: - Rename "fullBelow" to something like haveAllDescendants or haveAllChildren. -- Remove dependence on JobQueue, LoadFeeTrack, and NetworkOPs from LoadManager - by providing an observer (beast::ListenerList or Listeners). This way - LoadManager does not need stopThread() function. - - Rewrite Sustain to use Beast and work on Windows as well * Do not enable watchdog process if a debugger is attached diff --git a/src/BeastConfig.h b/src/BeastConfig.h index 50ee90542d..05dc73cdcc 100644 --- a/src/BeastConfig.h +++ b/src/BeastConfig.h @@ -171,7 +171,7 @@ // is being written. // #ifndef RIPPLE_USE_NEW_VALIDATORS -#define RIPPLE_USE_NEW_VALIDATORS 1 +#define RIPPLE_USE_NEW_VALIDATORS 0 #endif // Turning this on makes the Application object get destroyed, diff --git a/src/ripple/validators/impl/Logic.h b/src/ripple/validators/impl/Logic.h index c29635d937..5674fb0446 100644 --- a/src/ripple/validators/impl/Logic.h +++ b/src/ripple/validators/impl/Logic.h @@ -17,7 +17,6 @@ */ //============================================================================== - #ifndef RIPPLE_VALIDATORS_LOGIC_H_INCLUDED #define RIPPLE_VALIDATORS_LOGIC_H_INCLUDED @@ -36,7 +35,7 @@ enum // We check Source expirations on this time interval ,checkEverySeconds = 60 * 60 #else - secondsBetweenFetches = 5 * 60 + secondsBetweenFetches = 59 ,checkEverySeconds = 60 #endif diff --git a/src/ripple/validators/impl/Manager.cpp b/src/ripple/validators/impl/Manager.cpp index 9abd666c5c..dd9cdbf2e2 100644 --- a/src/ripple/validators/impl/Manager.cpp +++ b/src/ripple/validators/impl/Manager.cpp @@ -124,7 +124,7 @@ public: , m_store (m_journal) , m_logic (m_store, m_journal) , m_checkTimer (this) - , m_checkSources (true) + , m_checkSources (false) { #if BEAST_MSVC if (beast_isRunningUnderDebugger()) @@ -147,26 +147,35 @@ public: void onPrepare (Journal journal) { - journal.info << "Preparing Validators"; + journal.info << "Preparing"; addRPCHandlers(); } void onStart (Journal journal) { - journal.info << "Starting Validators"; + journal.info << "Starting"; + + // Do this late so the sources have a chance to be added. + m_queue.dispatch (bind (&ManagerImp::setCheckSources, this)); startThread(); } void onStop (Journal journal) { - journal.info << "Stopping Validators"; + journal.info << "Stopping"; if (this->Thread::isThreadRunning()) + { + m_journal.debug << "Signaling thread exit"; m_queue.dispatch (bind (&Thread::signalThreadShouldExit, this)); + } else + { + m_journal.debug << "Thread was never started"; stopped(); + } } //-------------------------------------------------------------------------- @@ -269,12 +278,12 @@ public: void init () { - m_journal.trace << "Initializing"; + m_journal.debug << "Initializing"; File const file (File::getSpecialLocation ( File::userDocumentsDirectory).getChildFile ("validators.sqlite")); - m_journal.trace << "Opening database at '" << file.getFullPathName() << "'"; + m_journal.debug << "Opening database at '" << file.getFullPathName() << "'"; Error error (m_store.open (file)); @@ -294,13 +303,14 @@ public: { if (timer == m_checkTimer) { - m_journal.trace << "Check timer signaled"; + m_journal.debug << "Check timer expired"; m_queue.dispatch (bind (&ManagerImp::setCheckSources, this)); } } void setCheckSources () { + m_journal.debug << "Checking sources"; m_checkSources = true; } @@ -308,18 +318,16 @@ public: { if (m_checkSources) { - m_journal.trace << "Checking sources"; - if (m_logic.fetch_one () == 0) { - m_journal.trace << "Finished checking sources"; + m_journal.debug << "All sources checked"; // Made it through the list without interruption! // Clear the flag and set the deadline timer again. // m_checkSources = false; - m_journal.trace << "Next check timer expires in " << + m_journal.debug << "Next check timer expires in " << RelativeTime::seconds (checkEverySeconds); m_checkTimer.setExpiration (checkEverySeconds); diff --git a/src/ripple_app/main/Application.cpp b/src/ripple_app/main/Application.cpp index 6bb55d5856..01cf0a1aa5 100644 --- a/src/ripple_app/main/Application.cpp +++ b/src/ripple_app/main/Application.cpp @@ -40,6 +40,8 @@ class RPCServiceManagerLog; template <> char const* LogPartition::getPartitionName () { return "RPCServiceManager"; } class HTTPServerLog; template <> char const* LogPartition::getPartitionName () { return "RPCServer"; } +class LoadManagerLog; +template <> char const* LogPartition::getPartitionName () { return "LoadManager"; } // //------------------------------------------------------------------------------ @@ -124,7 +126,7 @@ public: , mFeeVote (IFeeVote::New (10, 50 * SYSTEM_CURRENCY_PARTS, 12.5 * SYSTEM_CURRENCY_PARTS)) - , mFeeTrack (ILoadFeeTrack::New ()) + , mFeeTrack (LoadFeeTrack::New (LogJournal::get ())) , mHashRouter (IHashRouter::New (IHashRouter::getDefaultHoldTime ())) @@ -132,7 +134,7 @@ public: , mProofOfWorkFactory (ProofOfWorkFactory::New ()) - , m_loadManager (LoadManager::New ()) + , m_loadManager (LoadManager::New (*this, LogJournal::get ())) , mPeerFinder (PeerFinder::New (*this)) @@ -145,8 +147,6 @@ public: // VFALCO TODO remove these once the call is thread safe. HashMaps::getInstance ().initializeNonce (); - - initValidatorsConfig (); } ~ApplicationImp () @@ -163,28 +163,6 @@ public: //-------------------------------------------------------------------------- - // Initialize the Validators object with Config information. - void initValidatorsConfig () - { - { - std::vector const& strings (getConfig().validators); - if (! strings.empty ()) - m_validators->addStrings ("rippled.cfg", strings); - } - - if (! getConfig().getValidatorsURL().empty()) - { - m_validators->addURL (getConfig().getValidatorsURL()); - } - - if (getConfig().getValidatorsFile() != File::nonexistent ()) - { - m_validators->addFile (getConfig().getValidatorsFile()); - } - } - - //-------------------------------------------------------------------------- - RPC::Manager& getRPCServiceManager() { return *m_rpcServiceManager; @@ -270,7 +248,7 @@ public: return *mFeatures; } - ILoadFeeTrack& getFeeTrack () + LoadFeeTrack& getFeeTrack () { return *mFeeTrack; } @@ -388,10 +366,6 @@ public: // VFALCO NOTE: 0 means use heuristics to determine the thread count. m_jobQueue->setThreadCount (0, getConfig ().RUN_STANDALONE); - m_sweepTimer.setExpiration (10); - - m_loadManager->start (); - #if ! BEAST_WIN32 #ifdef SIGINT @@ -642,16 +616,54 @@ public: m_networkOPs->setStandAlone (); } } + + //-------------------------------------------------------------------------- + + // Initialize the Validators object with Config information. + void prepareValidators () + { + { + std::vector const& strings (getConfig().validators); + if (! strings.empty ()) + m_validators->addStrings ("rippled.cfg", strings); + } + + if (! getConfig().getValidatorsURL().empty()) + { + m_validators->addURL (getConfig().getValidatorsURL()); + } + + if (getConfig().getValidatorsFile() != File::nonexistent ()) + { + m_validators->addFile (getConfig().getValidatorsFile()); + } + } //-------------------------------------------------------------------------- // // Stoppable + // + + void onPrepare (Journal) + { + prepareValidators (); + } + + void onStart (Journal journal) + { + journal.debug << "Application starting"; + + m_sweepTimer.setExpiration (10); + } // Called to indicate shutdown. - void onStop (Journal) + void onStop (Journal journal) { + journal.debug << "Application stopping"; + m_sweepTimer.cancel(); + // VFALCO TODO get rid of this flag mShutdown = true; mValidations->flush (); @@ -717,7 +729,7 @@ public: // eliminate LoadManager's dependency inversions. // // This deletes the object and therefore, stops the thread. - m_loadManager = nullptr; + //m_loadManager = nullptr; m_journal.info << "Done."; @@ -844,7 +856,7 @@ private: ScopedPointer m_validators; ScopedPointer mFeatures; ScopedPointer mFeeVote; - ScopedPointer mFeeTrack; + ScopedPointer mFeeTrack; ScopedPointer mHashRouter; ScopedPointer mValidations; ScopedPointer mProofOfWorkFactory; diff --git a/src/ripple_app/main/Application.h b/src/ripple_app/main/Application.h index cbe0923aaf..5e7c08fca4 100644 --- a/src/ripple_app/main/Application.h +++ b/src/ripple_app/main/Application.h @@ -29,7 +29,7 @@ namespace RPC { class Manager; } class IFeatures; class IFeeVote; class IHashRouter; -class ILoadFeeTrack; +class LoadFeeTrack; class Peers; class UniqueNodeList; class JobQueue; @@ -98,7 +98,7 @@ public: virtual IFeatures& getFeatureTable () = 0; virtual IFeeVote& getFeeVote () = 0; virtual IHashRouter& getHashRouter () = 0; - virtual ILoadFeeTrack& getFeeTrack () = 0; + virtual LoadFeeTrack& getFeeTrack () = 0; virtual LoadManager& getLoadManager () = 0; virtual Peers& getPeers () = 0; virtual ProofOfWorkFactory& getProofOfWorkFactory () = 0; diff --git a/src/ripple_app/main/LoadManager.cpp b/src/ripple_app/main/LoadManager.cpp index 03bc055a5f..b792143adc 100644 --- a/src/ripple_app/main/LoadManager.cpp +++ b/src/ripple_app/main/LoadManager.cpp @@ -17,16 +17,11 @@ */ //============================================================================== - -SETUP_LOG (LoadManager) - -//------------------------------------------------------------------------------ - class LoadManagerImp : public LoadManager , public Thread { -private: +public: /* Entry mapping utilization to cost. The cost is expressed as a unitless relative quantity. These @@ -72,11 +67,33 @@ private: int m_resourceFlags; }; -public: - LoadManagerImp () - : Thread ("loadmgr") + //-------------------------------------------------------------------------- + + Journal m_journal; + typedef RippleMutex LockType; + typedef LockType::ScopedLockType ScopedLockType; + LockType mLock; + + BlackList mBlackList; + + 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 mArmed; + + int mDeadLock; // Detect server deadlocks + + std::vector mCosts; + + //-------------------------------------------------------------------------- + + LoadManagerImp (Stoppable& parent, Journal journal) + : LoadManager (parent) + , Thread ("loadmgr") + , m_journal (journal) , mLock (this, "LoadManagerImp", __FILE__, __LINE__) - , m_logThread ("loadmgr_log") , mCreditRate (100) , mCreditLimit (500) , mDebitWarn (-500) @@ -85,8 +102,6 @@ public: , mDeadLock (0) , mCosts (LT_MAX) { - m_logThread.start (); - /** Flags indicating the type of load. Utilization may include any combination of: @@ -128,7 +143,6 @@ public: UptimeTimer::getInstance ().beginManualUpdates (); } -private: ~LoadManagerImp () { UptimeTimer::getInstance ().endManualUpdates (); @@ -136,11 +150,36 @@ private: stopThread (); } - void start () + //-------------------------------------------------------------------------- + // + // Stoppable + // + + void onPrepare (Journal) { - startThread(); } + void onStart (Journal journal) + { + journal.debug << "Starting"; + startThread (); + } + + void onStop (Journal journal) + { + if (isThreadRunning ()) + { + journal.debug << "Stopping"; + stopThread (0); + } + else + { + stopped (); + } + } + + //-------------------------------------------------------------------------- + void canonicalize (LoadSource& source, int now) const { if (source.mLastUpdate != now) @@ -240,17 +279,17 @@ private: void logWarning (const std::string& source) const { if (source.empty ()) - WriteLog (lsDEBUG, LoadManager) << "Load warning from empty source"; + m_journal.debug << "Load warning from empty source"; else - WriteLog (lsINFO, LoadManager) << "Load warning: " << source; + m_journal.info << "Load warning: " << source; } void logDisconnect (const std::string& source) const { if (source.empty ()) - WriteLog (lsINFO, LoadManager) << "Disconnect for empty source"; + m_journal.info << "Disconnect for empty source"; else - WriteLog (lsWARNING, LoadManager) << "Disconnect for: " << source; + m_journal.warning << "Disconnect for: " << source; } Json::Value getBlackList (int threshold) @@ -282,9 +321,9 @@ private: mArmed = true; } - static void logDeadlock (int dlTime) + void logDeadlock (int dlTime) { - WriteLog (lsWARNING, LoadManager) << "Server stalled for " << dlTime << " seconds."; + m_journal.warning << "Server stalled for " << dlTime << " seconds."; #if RIPPLE_TRACK_MUTEXES StringArray report; @@ -298,59 +337,6 @@ private: #endif } -private: - // VFALCO TODO These used to be public but are apparently not used. Find out why. - /* - int getCreditRate () const - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - return mCreditRate; - } - - int getCreditLimit () const - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - return mCreditLimit; - } - - int getDebitWarn () const - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - return mDebitWarn; - } - - int getDebitLimit () const - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - return mDebitLimit; - } - - void setCreditRate (int r) - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - mCreditRate = r; - } - - void setCreditLimit (int r) - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - mCreditLimit = r; - } - - void setDebitWarn (int r) - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - mDebitWarn = r; - } - - void setDebitLimit (int r) - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - mDebitLimit = r; - } - */ - -private: void addCost (const Cost& c) { mCosts [static_cast (c.getLoadType ())] = c; @@ -393,9 +379,7 @@ private: // Report the deadlocked condition every 10 seconds if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0) { - // VFALCO TODO Replace this with a dedicated thread with call queue. - // - m_logThread.call (&logDeadlock, timeSpentDeadlocked); + logDeadlock (timeSpentDeadlocked); } // If we go over 500 seconds spent deadlocked, it means that the @@ -413,7 +397,7 @@ private: // Another option is using an observer pattern to invert the dependency. if (getApp().getJobQueue ().isOverloaded ()) { - WriteLog (lsINFO, LoadManager) << getApp().getJobQueue ().getJson (0); + m_journal.info << getApp().getJobQueue ().getJson (0); change = getApp().getFeeTrack ().raiseLocalFee (); } else @@ -432,7 +416,7 @@ private: if ((when.is_negative ()) || (when.total_seconds () > 1)) { - WriteLog (lsWARNING, LoadManager) << "time jump"; + m_journal.warning << "time jump"; t = boost::posix_time::microsec_clock::universal_time (); } else @@ -441,32 +425,18 @@ private: } } } - -private: - typedef RippleMutex LockType; - typedef LockType::ScopedLockType ScopedLockType; - LockType mLock; - - beast::ThreadWithCallQueue m_logThread; - - BlackList mBlackList; - - 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 mArmed; - - int mDeadLock; // Detect server deadlocks - - std::vector mCosts; }; //------------------------------------------------------------------------------ -LoadManager* LoadManager::New () +LoadManager::LoadManager (Stoppable& parent) + : Stoppable ("LoadManager", parent) { - ScopedPointer object (new LoadManagerImp); - return object.release (); +} + +//------------------------------------------------------------------------------ + +LoadManager* LoadManager::New (Stoppable& parent, Journal journal) +{ + return new LoadManagerImp (parent, journal); } diff --git a/src/ripple_app/main/LoadManager.h b/src/ripple_app/main/LoadManager.h index 9df1b3fced..067d07eca9 100644 --- a/src/ripple_app/main/LoadManager.h +++ b/src/ripple_app/main/LoadManager.h @@ -34,17 +34,18 @@ @see LoadSource, LoadType */ -class LoadManager +class LoadManager : public Stoppable { +protected: + explicit LoadManager (Stoppable& parent); + 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 (); + static LoadManager* New (Stoppable& parent, Journal journal); /** Destroy the manager. @@ -52,15 +53,6 @@ public: */ 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 start () = 0; - /** Turn on deadlock detection. The deadlock detector begins in a disabled state. After this function diff --git a/src/ripple_core/functional/ILoadFeeTrack.h b/src/ripple_core/functional/ILoadFeeTrack.h deleted file mode 100644 index 362ad994e8..0000000000 --- a/src/ripple_core/functional/ILoadFeeTrack.h +++ /dev/null @@ -1,67 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - - -#ifndef RIPPLE_ILOADFEETRACK_H_INCLUDED -#define RIPPLE_ILOADFEETRACK_H_INCLUDED - -/** Manages the current fee schedule. - - The "base" fee is the cost to send a reference transaction under no load, - expressed in millionths of one XRP. - - The "load" fee is how much the local server currently charges to send a - reference transaction. This fee fluctuates based on the load of the - server. -*/ -// VFALCO TODO Rename "load" to "current". -class ILoadFeeTrack -{ -public: - /** Create a new tracker. - */ - static ILoadFeeTrack* New (); - - virtual ~ILoadFeeTrack () { } - - // Scale from fee units to millionths of a ripple - virtual uint64 scaleFeeBase (uint64 fee, uint64 baseFee, uint32 referenceFeeUnits) = 0; - - // Scale using load as well as base rate - virtual uint64 scaleFeeLoad (uint64 fee, uint64 baseFee, uint32 referenceFeeUnits, bool bAdmin) = 0; - - virtual void setRemoteFee (uint32) = 0; - - virtual uint32 getRemoteFee () = 0; - virtual uint32 getLocalFee () = 0; - virtual uint32 getClusterFee () = 0; - - virtual uint32 getLoadBase () = 0; - virtual uint32 getLoadFactor () = 0; - - virtual Json::Value getJson (uint64 baseFee, uint32 referenceFeeUnits) = 0; - - virtual void setClusterFee (uint32) = 0; - virtual bool raiseLocalFee () = 0; - virtual bool lowerLocalFee () = 0; - virtual bool isLoadedLocal () = 0; - virtual bool isLoadedCluster () = 0; -}; - -#endif diff --git a/src/ripple_core/functional/LoadFeeTrack.h b/src/ripple_core/functional/LoadFeeTrack.h index e4f95200b1..5b230acfb8 100644 --- a/src/ripple_core/functional/LoadFeeTrack.h +++ b/src/ripple_core/functional/LoadFeeTrack.h @@ -17,217 +17,50 @@ */ //============================================================================== - #ifndef RIPPLE_LOADFEETRACK_H_INCLUDED #define RIPPLE_LOADFEETRACK_H_INCLUDED -// PRIVATE HEADER -class LoadManager; +/** Manages the current fee schedule. -class LoadFeeTrack : public ILoadFeeTrack + The "base" fee is the cost to send a reference transaction under no load, + expressed in millionths of one XRP. + + The "load" fee is how much the local server currently charges to send a + reference transaction. This fee fluctuates based on the load of the + server. +*/ +// VFALCO TODO Rename "load" to "current". +class LoadFeeTrack { public: - LoadFeeTrack () - : mLock (this, "LoadFeeTrack", __FILE__, __LINE__) - , mLocalTxnLoadFee (lftNormalFee) - , mRemoteTxnLoadFee (lftNormalFee) - , mClusterTxnLoadFee (lftNormalFee) - , raiseCount (0) - { - } + /** Create a new tracker. + */ + static LoadFeeTrack* New (Journal journal); - // Scale using load as well as base rate - uint64 scaleFeeLoad (uint64 fee, uint64 baseFee, uint32 referenceFeeUnits, bool bAdmin) - { - static uint64 midrange (0x00000000FFFFFFFF); - - bool big = (fee > midrange); - - if (big) // big fee, divide first to avoid overflow - fee /= baseFee; - else // normal fee, multiply first for accuracy - fee *= referenceFeeUnits; - - uint32 feeFactor = std::max (mLocalTxnLoadFee, mRemoteTxnLoadFee); - - // Let admins pay the normal fee until the local load exceeds four times the remote - uint32 uRemFee = std::max(mRemoteTxnLoadFee, mClusterTxnLoadFee); - if (bAdmin && (feeFactor > uRemFee) && (feeFactor < (4 * uRemFee))) - feeFactor = uRemFee; - - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - fee = mulDiv (fee, feeFactor, lftNormalFee); - } - - if (big) // Fee was big to start, must now multiply - fee *= referenceFeeUnits; - else // Fee was small to start, mst now divide - fee /= baseFee; - - return fee; - } + virtual ~LoadFeeTrack () { } // Scale from fee units to millionths of a ripple - uint64 scaleFeeBase (uint64 fee, uint64 baseFee, uint32 referenceFeeUnits) - { - return mulDiv (fee, referenceFeeUnits, baseFee); - } + virtual uint64 scaleFeeBase (uint64 fee, uint64 baseFee, uint32 referenceFeeUnits) = 0; - uint32 getRemoteFee () - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - return mRemoteTxnLoadFee; - } + // Scale using load as well as base rate + virtual uint64 scaleFeeLoad (uint64 fee, uint64 baseFee, uint32 referenceFeeUnits, bool bAdmin) = 0; - uint32 getLocalFee () - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - return mLocalTxnLoadFee; - } + virtual void setRemoteFee (uint32) = 0; - uint32 getLoadBase () - { - return lftNormalFee; - } + virtual uint32 getRemoteFee () = 0; + virtual uint32 getLocalFee () = 0; + virtual uint32 getClusterFee () = 0; - uint32 getLoadFactor () - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - return std::max(mClusterTxnLoadFee, std::max (mLocalTxnLoadFee, mRemoteTxnLoadFee)); - } + virtual uint32 getLoadBase () = 0; + virtual uint32 getLoadFactor () = 0; - void setClusterFee (uint32 fee) - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - mClusterTxnLoadFee = fee; - } + virtual Json::Value getJson (uint64 baseFee, uint32 referenceFeeUnits) = 0; - uint32 getClusterFee () - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - return mClusterTxnLoadFee; - } - - bool isLoadedLocal () - { - // VFALCO TODO This could be replaced with a SharedData and - // using a read/write lock instead of a critical section. - // - // NOTE This applies to all the locking in this class. - // - // - ScopedLockType sl (mLock, __FILE__, __LINE__); - return (raiseCount != 0) || (mLocalTxnLoadFee != lftNormalFee); - } - - bool isLoadedCluster () - { - // VFALCO TODO This could be replaced with a SharedData and - // using a read/write lock instead of a critical section. - // - // NOTE This applies to all the locking in this class. - // - // - ScopedLockType sl (mLock, __FILE__, __LINE__); - return (raiseCount != 0) || (mLocalTxnLoadFee != lftNormalFee) || (mClusterTxnLoadFee != lftNormalFee); - } - - void setRemoteFee (uint32 f) - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - mRemoteTxnLoadFee = f; - } - - bool raiseLocalFee () - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - - if (++raiseCount < 2) - return false; - - uint32 origFee = mLocalTxnLoadFee; - - if (mLocalTxnLoadFee < mRemoteTxnLoadFee) // make sure this fee takes effect - mLocalTxnLoadFee = mRemoteTxnLoadFee; - - mLocalTxnLoadFee += (mLocalTxnLoadFee / lftFeeIncFraction); // increment by 1/16th - - if (mLocalTxnLoadFee > lftFeeMax) - mLocalTxnLoadFee = lftFeeMax; - - if (origFee == mLocalTxnLoadFee) - return false; - - WriteLog (lsDEBUG, LoadManager) << "Local load fee raised from " << origFee << " to " << mLocalTxnLoadFee; - return true; - } - - bool lowerLocalFee () - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - uint32 origFee = mLocalTxnLoadFee; - raiseCount = 0; - - mLocalTxnLoadFee -= (mLocalTxnLoadFee / lftFeeDecFraction ); // reduce by 1/4 - - if (mLocalTxnLoadFee < lftNormalFee) - mLocalTxnLoadFee = lftNormalFee; - - if (origFee == mLocalTxnLoadFee) - return false; - - WriteLog (lsDEBUG, LoadManager) << "Local load fee lowered from " << origFee << " to " << mLocalTxnLoadFee; - return true; - } - - Json::Value getJson (uint64 baseFee, uint32 referenceFeeUnits) - { - Json::Value j (Json::objectValue); - - { - ScopedLockType sl (mLock, __FILE__, __LINE__); - - // base_fee = The cost to send a "reference" transaction under no load, in millionths of a Ripple - j["base_fee"] = Json::Value::UInt (baseFee); - - // load_fee = The cost to send a "reference" transaction now, in millionths of a Ripple - j["load_fee"] = Json::Value::UInt ( - mulDiv (baseFee, std::max (mLocalTxnLoadFee, mRemoteTxnLoadFee), lftNormalFee)); - } - - return j; - } - -private: - // VFALCO TODO Move this function to some "math utilities" file - // compute (value)*(mul)/(div) - avoid overflow but keep precision - uint64 mulDiv (uint64 value, uint32 mul, uint64 div) - { - // VFALCO TODO replace with beast::literal64bitUnsigned () - // - static uint64 boundary = (0x00000000FFFFFFFF); - - if (value > boundary) // Large value, avoid overflow - return (value / div) * mul; - else // Normal value, preserve accuracy - return (value * mul) / div; - } - -private: - static const int lftNormalFee = 256; // 256 is the minimum/normal load factor - static const int lftFeeIncFraction = 4; // increase fee by 1/4 - static const int lftFeeDecFraction = 4; // decrease fee by 1/4 - static const int lftFeeMax = lftNormalFee * 1000000; - - typedef RippleMutex LockType; - typedef LockType::ScopedLockType ScopedLockType; - LockType mLock; - - uint32 mLocalTxnLoadFee; // Scale factor, lftNormalFee = normal fee - uint32 mRemoteTxnLoadFee; // Scale factor, lftNormalFee = normal fee - uint32 mClusterTxnLoadFee; // Scale factor, lftNormalFee = normal fee - int raiseCount; + virtual void setClusterFee (uint32) = 0; + virtual bool raiseLocalFee () = 0; + virtual bool lowerLocalFee () = 0; + virtual bool isLoadedLocal () = 0; + virtual bool isLoadedCluster () = 0; }; #endif diff --git a/src/ripple_core/functional/LoadFeeTrack.cpp b/src/ripple_core/functional/LoadFeeTrackImp.cpp similarity index 95% rename from src/ripple_core/functional/LoadFeeTrack.cpp rename to src/ripple_core/functional/LoadFeeTrackImp.cpp index b71ca7bba2..8bf37d7aea 100644 --- a/src/ripple_core/functional/LoadFeeTrack.cpp +++ b/src/ripple_core/functional/LoadFeeTrackImp.cpp @@ -17,10 +17,9 @@ */ //============================================================================== - -ILoadFeeTrack* ILoadFeeTrack::New () +LoadFeeTrack* LoadFeeTrack::New (Journal journal) { - return new LoadFeeTrack; + return new LoadFeeTrackImp (journal); } //------------------------------------------------------------------------------ @@ -35,7 +34,7 @@ public: void runTest () { Config d; // get a default configuration object - LoadFeeTrack l; + LoadFeeTrackImp l; beginTestCase ("fee scaling"); diff --git a/src/ripple_core/functional/LoadFeeTrackImp.h b/src/ripple_core/functional/LoadFeeTrackImp.h new file mode 100644 index 0000000000..75dd0d361d --- /dev/null +++ b/src/ripple_core/functional/LoadFeeTrackImp.h @@ -0,0 +1,231 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_LOADFEETRACKIMP_H_INCLUDED +#define RIPPLE_LOADFEETRACKIMP_H_INCLUDED + +class LoadFeeTrackImp : public LoadFeeTrack +{ +public: + explicit LoadFeeTrackImp (Journal journal = Journal()) + : m_journal (journal) + , mLock (this, "LoadFeeTrackImp", __FILE__, __LINE__) + , mLocalTxnLoadFee (lftNormalFee) + , mRemoteTxnLoadFee (lftNormalFee) + , mClusterTxnLoadFee (lftNormalFee) + , raiseCount (0) + { + } + + // Scale using load as well as base rate + uint64 scaleFeeLoad (uint64 fee, uint64 baseFee, uint32 referenceFeeUnits, bool bAdmin) + { + static uint64 midrange (0x00000000FFFFFFFF); + + bool big = (fee > midrange); + + if (big) // big fee, divide first to avoid overflow + fee /= baseFee; + else // normal fee, multiply first for accuracy + fee *= referenceFeeUnits; + + uint32 feeFactor = std::max (mLocalTxnLoadFee, mRemoteTxnLoadFee); + + // Let admins pay the normal fee until the local load exceeds four times the remote + uint32 uRemFee = std::max(mRemoteTxnLoadFee, mClusterTxnLoadFee); + if (bAdmin && (feeFactor > uRemFee) && (feeFactor < (4 * uRemFee))) + feeFactor = uRemFee; + + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + fee = mulDiv (fee, feeFactor, lftNormalFee); + } + + if (big) // Fee was big to start, must now multiply + fee *= referenceFeeUnits; + else // Fee was small to start, mst now divide + fee /= baseFee; + + return fee; + } + + // Scale from fee units to millionths of a ripple + uint64 scaleFeeBase (uint64 fee, uint64 baseFee, uint32 referenceFeeUnits) + { + return mulDiv (fee, referenceFeeUnits, baseFee); + } + + uint32 getRemoteFee () + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + return mRemoteTxnLoadFee; + } + + uint32 getLocalFee () + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + return mLocalTxnLoadFee; + } + + uint32 getLoadBase () + { + return lftNormalFee; + } + + uint32 getLoadFactor () + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + return std::max(mClusterTxnLoadFee, std::max (mLocalTxnLoadFee, mRemoteTxnLoadFee)); + } + + void setClusterFee (uint32 fee) + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + mClusterTxnLoadFee = fee; + } + + uint32 getClusterFee () + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + return mClusterTxnLoadFee; + } + + bool isLoadedLocal () + { + // VFALCO TODO This could be replaced with a SharedData and + // using a read/write lock instead of a critical section. + // + // NOTE This applies to all the locking in this class. + // + // + ScopedLockType sl (mLock, __FILE__, __LINE__); + return (raiseCount != 0) || (mLocalTxnLoadFee != lftNormalFee); + } + + bool isLoadedCluster () + { + // VFALCO TODO This could be replaced with a SharedData and + // using a read/write lock instead of a critical section. + // + // NOTE This applies to all the locking in this class. + // + // + ScopedLockType sl (mLock, __FILE__, __LINE__); + return (raiseCount != 0) || (mLocalTxnLoadFee != lftNormalFee) || (mClusterTxnLoadFee != lftNormalFee); + } + + void setRemoteFee (uint32 f) + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + mRemoteTxnLoadFee = f; + } + + bool raiseLocalFee () + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + + if (++raiseCount < 2) + return false; + + uint32 origFee = mLocalTxnLoadFee; + + if (mLocalTxnLoadFee < mRemoteTxnLoadFee) // make sure this fee takes effect + mLocalTxnLoadFee = mRemoteTxnLoadFee; + + mLocalTxnLoadFee += (mLocalTxnLoadFee / lftFeeIncFraction); // increment by 1/16th + + if (mLocalTxnLoadFee > lftFeeMax) + mLocalTxnLoadFee = lftFeeMax; + + if (origFee == mLocalTxnLoadFee) + return false; + + m_journal.debug << "Local load fee raised from " << origFee << " to " << mLocalTxnLoadFee; + return true; + } + + bool lowerLocalFee () + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + uint32 origFee = mLocalTxnLoadFee; + raiseCount = 0; + + mLocalTxnLoadFee -= (mLocalTxnLoadFee / lftFeeDecFraction ); // reduce by 1/4 + + if (mLocalTxnLoadFee < lftNormalFee) + mLocalTxnLoadFee = lftNormalFee; + + if (origFee == mLocalTxnLoadFee) + return false; + + m_journal.debug << "Local load fee lowered from " << origFee << " to " << mLocalTxnLoadFee; + return true; + } + + Json::Value getJson (uint64 baseFee, uint32 referenceFeeUnits) + { + Json::Value j (Json::objectValue); + + { + ScopedLockType sl (mLock, __FILE__, __LINE__); + + // base_fee = The cost to send a "reference" transaction under no load, in millionths of a Ripple + j["base_fee"] = Json::Value::UInt (baseFee); + + // load_fee = The cost to send a "reference" transaction now, in millionths of a Ripple + j["load_fee"] = Json::Value::UInt ( + mulDiv (baseFee, std::max (mLocalTxnLoadFee, mRemoteTxnLoadFee), lftNormalFee)); + } + + return j; + } + +private: + // VFALCO TODO Move this function to some "math utilities" file + // compute (value)*(mul)/(div) - avoid overflow but keep precision + uint64 mulDiv (uint64 value, uint32 mul, uint64 div) + { + // VFALCO TODO replace with beast::literal64bitUnsigned () + // + static uint64 boundary = (0x00000000FFFFFFFF); + + if (value > boundary) // Large value, avoid overflow + return (value / div) * mul; + else // Normal value, preserve accuracy + return (value * mul) / div; + } + +private: + static const int lftNormalFee = 256; // 256 is the minimum/normal load factor + static const int lftFeeIncFraction = 4; // increase fee by 1/4 + static const int lftFeeDecFraction = 4; // decrease fee by 1/4 + static const int lftFeeMax = lftNormalFee * 1000000; + + Journal m_journal; + typedef RippleMutex LockType; + typedef LockType::ScopedLockType ScopedLockType; + LockType mLock; + + uint32 mLocalTxnLoadFee; // Scale factor, lftNormalFee = normal fee + uint32 mRemoteTxnLoadFee; // Scale factor, lftNormalFee = normal fee + uint32 mClusterTxnLoadFee; // Scale factor, lftNormalFee = normal fee + int raiseCount; +}; + +#endif diff --git a/src/ripple_core/ripple_core.cpp b/src/ripple_core/ripple_core.cpp index 081b624d74..1fc02db779 100644 --- a/src/ripple_core/ripple_core.cpp +++ b/src/ripple_core/ripple_core.cpp @@ -40,8 +40,8 @@ namespace ripple { #include "functional/Config.cpp" -# include "functional/LoadFeeTrack.h" // private -#include "functional/LoadFeeTrack.cpp" +# include "functional/LoadFeeTrackImp.h" // private +#include "functional/LoadFeeTrackImp.cpp" #include "functional/Job.cpp" #include "functional/JobQueue.cpp" #include "functional/LoadEvent.cpp" diff --git a/src/ripple_core/ripple_core.h b/src/ripple_core/ripple_core.h index b043554c9e..04fa71d3d0 100644 --- a/src/ripple_core/ripple_core.h +++ b/src/ripple_core/ripple_core.h @@ -36,7 +36,7 @@ namespace ripple # include "functional/ConfigSections.h" #include "functional/Config.h" -#include "functional/ILoadFeeTrack.h" +#include "functional/LoadFeeTrack.h" # include "functional/LoadEvent.h" # include "functional/LoadMonitor.h" # include "functional/Job.h"