Devirtualize LoadFeeTrack

This commit is contained in:
Edward Hennis
2015-07-10 16:51:05 -04:00
committed by Nik Bougalis
parent e45c1b238f
commit a7e6ecb5b3
10 changed files with 244 additions and 301 deletions

View File

@@ -2061,14 +2061,12 @@
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<ClCompile Include="..\..\src\ripple\core\impl\LoadFeeTrackImp.cpp">
<ClCompile Include="..\..\src\ripple\core\impl\LoadFeeTrack.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<ClInclude Include="..\..\src\ripple\core\impl\LoadFeeTrackImp.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\core\impl\LoadMonitor.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>

View File

@@ -2799,12 +2799,9 @@
<ClCompile Include="..\..\src\ripple\core\impl\LoadEvent.cpp">
<Filter>ripple\core\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\core\impl\LoadFeeTrackImp.cpp">
<ClCompile Include="..\..\src\ripple\core\impl\LoadFeeTrack.cpp">
<Filter>ripple\core\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\core\impl\LoadFeeTrackImp.h">
<Filter>ripple\core\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\core\impl\LoadMonitor.cpp">
<Filter>ripple\core\impl</Filter>
</ClCompile>

View File

@@ -414,7 +414,7 @@ public:
(weeks(2), MAJORITY_FRACTION,
m_logs.journal("AmendmentTable")))
, mFeeTrack (LoadFeeTrack::New (m_logs.journal("LoadManager")))
, mFeeTrack (std::make_unique<LoadFeeTrack>(m_logs.journal("LoadManager")))
, mHashRouter (IHashRouter::New (IHashRouter::getDefaultHoldTime ()))

View File

@@ -23,6 +23,7 @@
#include <ripple/json/json_value.h>
#include <beast/utility/Journal.h>
#include <cstdint>
#include <mutex>
namespace ripple {
@@ -39,37 +40,99 @@ namespace ripple {
class LoadFeeTrack
{
public:
/** Create a new tracker.
*/
static LoadFeeTrack* New (beast::Journal journal);
explicit LoadFeeTrack (beast::Journal journal = beast::Journal())
: m_journal (journal)
, mLocalTxnLoadFee (lftNormalFee)
, mRemoteTxnLoadFee (lftNormalFee)
, mClusterTxnLoadFee (lftNormalFee)
, raiseCount (0)
{
}
virtual ~LoadFeeTrack () { }
// Scale from fee units to millionths of a ripple
virtual std::uint64_t scaleFeeBase (std::uint64_t fee, std::uint64_t baseFee,
std::uint32_t referenceFeeUnits) = 0;
std::uint64_t scaleFeeBase (std::uint64_t fee, std::uint64_t baseFee,
std::uint32_t referenceFeeUnits) const;
// Scale using load as well as base rate
virtual std::uint64_t scaleFeeLoad (std::uint64_t fee, std::uint64_t baseFee,
std::uint32_t referenceFeeUnits,
bool bAdmin) = 0;
std::uint64_t scaleFeeLoad (std::uint64_t fee, std::uint64_t baseFee,
std::uint32_t referenceFeeUnits, bool bAdmin) const;
virtual void setRemoteFee (std::uint32_t) = 0;
void setRemoteFee (std::uint32_t f)
{
ScopedLockType sl (mLock);
mRemoteTxnLoadFee = f;
}
virtual std::uint32_t getRemoteFee () = 0;
virtual std::uint32_t getLocalFee () = 0;
virtual std::uint32_t getClusterFee () = 0;
std::uint32_t getRemoteFee () const
{
ScopedLockType sl (mLock);
return mRemoteTxnLoadFee;
}
virtual std::uint32_t getLoadBase () = 0;
virtual std::uint32_t getLoadFactor () = 0;
std::uint32_t getLocalFee () const
{
ScopedLockType sl (mLock);
return mLocalTxnLoadFee;
}
virtual Json::Value getJson (std::uint64_t baseFee, std::uint32_t referenceFeeUnits) = 0;
std::uint32_t getClusterFee () const
{
ScopedLockType sl (mLock);
return mClusterTxnLoadFee;
}
virtual void setClusterFee (std::uint32_t) = 0;
virtual bool raiseLocalFee () = 0;
virtual bool lowerLocalFee () = 0;
virtual bool isLoadedLocal () = 0;
virtual bool isLoadedCluster () = 0;
std::uint32_t getLoadBase () const
{
return lftNormalFee;
}
std::uint32_t getLoadFactor () const
{
ScopedLockType sl (mLock);
return std::max({ mClusterTxnLoadFee, mLocalTxnLoadFee, mRemoteTxnLoadFee });
}
Json::Value getJson (std::uint64_t baseFee, std::uint32_t referenceFeeUnits) const;
void setClusterFee (std::uint32_t fee)
{
ScopedLockType sl (mLock);
mClusterTxnLoadFee = fee;
}
bool raiseLocalFee ();
bool lowerLocalFee ();
bool isLoadedLocal () const
{
ScopedLockType sl (mLock);
return (raiseCount != 0) || (mLocalTxnLoadFee != lftNormalFee);
}
bool isLoadedCluster () const
{
ScopedLockType sl (mLock);
return (raiseCount != 0) || (mLocalTxnLoadFee != lftNormalFee) || (mClusterTxnLoadFee != lftNormalFee);
}
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;
beast::Journal m_journal;
using LockType = std::mutex;
using ScopedLockType = std::lock_guard <LockType>;
LockType mutable mLock;
std::uint32_t mLocalTxnLoadFee; // Scale factor, lftNormalFee = normal fee
std::uint32_t mRemoteTxnLoadFee; // Scale factor, lftNormalFee = normal fee
std::uint32_t mClusterTxnLoadFee; // Scale factor, lftNormalFee = normal fee
int raiseCount;
};
} // ripple

View File

@@ -0,0 +1,154 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#include <BeastConfig.h>
#include <ripple/core/LoadFeeTrack.h>
#include <ripple/core/Config.h>
#include <ripple/protocol/STAmount.h>
#include <ripple/protocol/JsonFields.h>
namespace ripple {
// TODO REMOVE!
std::uint64_t mulDiv (std::uint64_t value,
std::uint32_t mul, std::uint64_t div)
{
static std::uint64_t boundary = (0x00000000FFFFFFFF);
if (value > boundary) // Large value, avoid overflow
return (value / div) * mul;
else // Normal value, preserve accuracy
return (value * mul) / div;
}
// Scale from fee units to millionths of a ripple
std::uint64_t
LoadFeeTrack::scaleFeeBase (std::uint64_t fee, std::uint64_t baseFee,
std::uint32_t referenceFeeUnits) const
{
return mulDiv (fee, baseFee, referenceFeeUnits);
}
// Scale using load as well as base rate
std::uint64_t
LoadFeeTrack::scaleFeeLoad (std::uint64_t fee, std::uint64_t baseFee,
std::uint32_t referenceFeeUnits, bool bAdmin) const
{
static std::uint64_t midrange (0x00000000FFFFFFFF);
bool big = (fee > midrange);
if (big) // big fee, divide first to avoid overflow
fee /= referenceFeeUnits;
else // normal fee, multiply first for accuracy
fee *= baseFee;
std::uint32_t feeFactor = std::max (mLocalTxnLoadFee, mRemoteTxnLoadFee);
// Let admins pay the normal fee until the local load exceeds four times the remote
std::uint32_t uRemFee = std::max(mRemoteTxnLoadFee, mClusterTxnLoadFee);
if (bAdmin && (feeFactor > uRemFee) && (feeFactor < (4 * uRemFee)))
feeFactor = uRemFee;
{
ScopedLockType sl (mLock);
fee = mulDiv (fee, feeFactor, lftNormalFee);
}
if (big) // Fee was big to start, must now multiply
fee *= baseFee;
else // Fee was small to start, mst now divide
fee /= referenceFeeUnits;
return fee;
}
Json::Value
LoadFeeTrack::getJson (std::uint64_t baseFee,
std::uint32_t referenceFeeUnits) const
{
Json::Value j (Json::objectValue);
{
ScopedLockType sl (mLock);
// base_fee = The cost to send a "reference" transaction under
// no load, in millionths of a Ripple
j[jss::base_fee] = Json::Value::UInt (baseFee);
// load_fee = The cost to send a "reference" transaction now,
// in millionths of a Ripple
j[jss::load_fee] = Json::Value::UInt (
mulDiv (baseFee, std::max (mLocalTxnLoadFee,
mRemoteTxnLoadFee), lftNormalFee));
}
return j;
}
bool
LoadFeeTrack::raiseLocalFee ()
{
ScopedLockType sl (mLock);
if (++raiseCount < 2)
return false;
std::uint32_t origFee = mLocalTxnLoadFee;
// make sure this fee takes effect
if (mLocalTxnLoadFee < mRemoteTxnLoadFee)
mLocalTxnLoadFee = mRemoteTxnLoadFee;
// Increase slowly
mLocalTxnLoadFee += (mLocalTxnLoadFee / lftFeeIncFraction);
if (mLocalTxnLoadFee > lftFeeMax)
mLocalTxnLoadFee = lftFeeMax;
if (origFee == mLocalTxnLoadFee)
return false;
m_journal.debug << "Local load fee raised from " <<
origFee << " to " << mLocalTxnLoadFee;
return true;
}
bool
LoadFeeTrack::lowerLocalFee ()
{
ScopedLockType sl (mLock);
std::uint32_t origFee = mLocalTxnLoadFee;
raiseCount = 0;
// Reduce slowly
mLocalTxnLoadFee -= (mLocalTxnLoadFee / lftFeeDecFraction );
if (mLocalTxnLoadFee < lftNormalFee)
mLocalTxnLoadFee = lftNormalFee;
if (origFee == mLocalTxnLoadFee)
return false;
m_journal.debug << "Local load fee lowered from " <<
origFee << " to " << mLocalTxnLoadFee;
return true;
}
} // ripple

View File

@@ -1,31 +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.
*/
//==============================================================================
#include <BeastConfig.h>
#include <ripple/core/impl/LoadFeeTrackImp.h>
#include <ripple/core/Config.h>
namespace ripple {
LoadFeeTrack* LoadFeeTrack::New (beast::Journal journal)
{
return new LoadFeeTrackImp (journal);
}
} // ripple

View File

@@ -1,238 +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_CORE_LOADFEETRACKIMP_H_INCLUDED
#define RIPPLE_CORE_LOADFEETRACKIMP_H_INCLUDED
#include <ripple/protocol/JsonFields.h>
#include <ripple/core/LoadFeeTrack.h>
#include <mutex>
namespace ripple {
class LoadFeeTrackImp : public LoadFeeTrack
{
public:
explicit LoadFeeTrackImp (beast::Journal journal = beast::Journal())
: m_journal (journal)
, mLocalTxnLoadFee (lftNormalFee)
, mRemoteTxnLoadFee (lftNormalFee)
, mClusterTxnLoadFee (lftNormalFee)
, raiseCount (0)
{
}
// Scale using load as well as base rate
std::uint64_t scaleFeeLoad (std::uint64_t fee, std::uint64_t baseFee, std::uint32_t referenceFeeUnits, bool bAdmin)
{
static std::uint64_t midrange (0x00000000FFFFFFFF);
bool big = (fee > midrange);
if (big) // big fee, divide first to avoid overflow
fee /= referenceFeeUnits;
else // normal fee, multiply first for accuracy
fee *= baseFee;
std::uint32_t feeFactor = std::max (mLocalTxnLoadFee, mRemoteTxnLoadFee);
// Let admins pay the normal fee until the local load exceeds four times the remote
std::uint32_t uRemFee = std::max(mRemoteTxnLoadFee, mClusterTxnLoadFee);
if (bAdmin && (feeFactor > uRemFee) && (feeFactor < (4 * uRemFee)))
feeFactor = uRemFee;
{
ScopedLockType sl (mLock);
fee = mulDiv (fee, feeFactor, lftNormalFee);
}
if (big) // Fee was big to start, must now multiply
fee *= baseFee;
else // Fee was small to start, mst now divide
fee /= referenceFeeUnits;
return fee;
}
// Scale from fee units to millionths of a ripple
std::uint64_t scaleFeeBase (std::uint64_t fee, std::uint64_t baseFee, std::uint32_t referenceFeeUnits)
{
return mulDiv (fee, baseFee, referenceFeeUnits);
}
std::uint32_t getRemoteFee ()
{
ScopedLockType sl (mLock);
return mRemoteTxnLoadFee;
}
std::uint32_t getLocalFee ()
{
ScopedLockType sl (mLock);
return mLocalTxnLoadFee;
}
std::uint32_t getLoadBase ()
{
return lftNormalFee;
}
std::uint32_t getLoadFactor ()
{
ScopedLockType sl (mLock);
return std::max(mClusterTxnLoadFee, std::max (mLocalTxnLoadFee, mRemoteTxnLoadFee));
}
void setClusterFee (std::uint32_t fee)
{
ScopedLockType sl (mLock);
mClusterTxnLoadFee = fee;
}
std::uint32_t getClusterFee ()
{
ScopedLockType sl (mLock);
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);
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);
return (raiseCount != 0) || (mLocalTxnLoadFee != lftNormalFee) || (mClusterTxnLoadFee != lftNormalFee);
}
void setRemoteFee (std::uint32_t f)
{
ScopedLockType sl (mLock);
mRemoteTxnLoadFee = f;
}
bool raiseLocalFee ()
{
ScopedLockType sl (mLock);
if (++raiseCount < 2)
return false;
std::uint32_t 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);
std::uint32_t 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 (std::uint64_t baseFee, std::uint32_t referenceFeeUnits)
{
Json::Value j (Json::objectValue);
{
ScopedLockType sl (mLock);
// base_fee = The cost to send a "reference" transaction under no load, in millionths of a Ripple
j[jss::base_fee] = Json::Value::UInt (baseFee);
// load_fee = The cost to send a "reference" transaction now, in millionths of a Ripple
j[jss::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
std::uint64_t mulDiv (std::uint64_t value, std::uint32_t mul, std::uint64_t div)
{
// VFALCO TODO replace with beast::literal64bitUnsigned ()
//
static std::uint64_t 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;
beast::Journal m_journal;
using LockType = std::mutex;
using ScopedLockType = std::lock_guard <LockType>;
LockType mLock;
std::uint32_t mLocalTxnLoadFee; // Scale factor, lftNormalFee = normal fee
std::uint32_t mRemoteTxnLoadFee; // Scale factor, lftNormalFee = normal fee
std::uint32_t mClusterTxnLoadFee; // Scale factor, lftNormalFee = normal fee
int raiseCount;
};
} // ripple
#endif

View File

@@ -18,7 +18,7 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/core/impl/LoadFeeTrackImp.h>
#include <ripple/core/LoadFeeTrack.h>
#include <ripple/core/Config.h>
#include <ripple/core/ConfigSections.h>
#include <ripple/basics/TestSuite.h>

View File

@@ -18,7 +18,7 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/core/impl/LoadFeeTrackImp.h>
#include <ripple/core/LoadFeeTrack.h>
#include <ripple/core/Config.h>
#include <beast/unit_test/suite.h>
@@ -30,7 +30,7 @@ public:
void run ()
{
Config d; // get a default configuration object
LoadFeeTrackImp l;
LoadFeeTrack l;
expect (l.scaleFeeBase (10000, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE) == 10000);
expect (l.scaleFeeLoad (10000, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE, false) == 10000);

View File

@@ -21,7 +21,7 @@
#include <ripple/core/impl/Config.cpp>
#include <ripple/core/impl/DatabaseCon.cpp>
#include <ripple/core/impl/LoadFeeTrackImp.cpp>
#include <ripple/core/impl/LoadFeeTrack.cpp>
#include <ripple/core/impl/LoadEvent.cpp>
#include <ripple/core/impl/LoadMonitor.cpp>
#include <ripple/core/impl/Job.cpp>