mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 12:33:44 +02:00
Add a concept of debt to RateLimiter, save a bit of RAM.
This commit is contained in:
parent
3af55f4423
commit
6a24ac4f00
4 changed files with 58 additions and 34 deletions
|
@ -274,12 +274,17 @@ error_no_ZT_ARCH_defined;
|
||||||
/**
|
/**
|
||||||
* Default balance preload for multicast rate limiters on a network
|
* Default balance preload for multicast rate limiters on a network
|
||||||
*/
|
*/
|
||||||
#define ZT_MULTICAST_DEFAULT_RATE_PRELOAD 25.0
|
#define ZT_MULTICAST_DEFAULT_RATE_PRELOAD 15000.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Absolute maximum balance for multicast rate limiters
|
* Default maximum balance for multicast rate limiters
|
||||||
*/
|
*/
|
||||||
#define ZT_MULTICAST_DEFAULT_RATE_MAX 75.0
|
#define ZT_MULTICAST_DEFAULT_RATE_MAX_BALANCE 15000.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default minimum balance for multicast rate limiters (max debt)
|
||||||
|
*/
|
||||||
|
#define ZT_MULTICAST_DEFAULT_RATE_MIN_BALANCE -15000.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay between scans of the topology active peer DB for peers that need ping
|
* Delay between scans of the topology active peer DB for peers that need ping
|
||||||
|
|
|
@ -140,6 +140,9 @@ SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t
|
||||||
// being constructed. C++ edge cases, how I love thee.
|
// being constructed. C++ edge cases, how I love thee.
|
||||||
SharedPtr<Network> nw(new Network());
|
SharedPtr<Network> nw(new Network());
|
||||||
nw->_r = renv;
|
nw->_r = renv;
|
||||||
|
nw->_rlLimit.bytesPerSecond = ZT_MULTICAST_DEFAULT_BYTES_PER_SECOND;
|
||||||
|
nw->_rlLimit.maxBalance = ZT_MULTICAST_DEFAULT_RATE_MAX_BALANCE;
|
||||||
|
nw->_rlLimit.minBalance = ZT_MULTICAST_DEFAULT_RATE_MIN_BALANCE;
|
||||||
nw->_tap = new EthernetTap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr());
|
nw->_tap = new EthernetTap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr());
|
||||||
nw->_id = id;
|
nw->_id = id;
|
||||||
nw->_lastConfigUpdate = 0;
|
nw->_lastConfigUpdate = 0;
|
||||||
|
|
|
@ -440,10 +440,10 @@ public:
|
||||||
std::map<Address,RateLimiter>::iterator rl(_multicastRateLimiters.find(addr));
|
std::map<Address,RateLimiter>::iterator rl(_multicastRateLimiters.find(addr));
|
||||||
if (rl == _multicastRateLimiters.end()) {
|
if (rl == _multicastRateLimiters.end()) {
|
||||||
RateLimiter &newrl = _multicastRateLimiters[addr];
|
RateLimiter &newrl = _multicastRateLimiters[addr];
|
||||||
newrl.init(ZT_MULTICAST_DEFAULT_BYTES_PER_SECOND,ZT_MULTICAST_DEFAULT_RATE_PRELOAD,ZT_MULTICAST_DEFAULT_RATE_MAX);
|
newrl.init(ZT_MULTICAST_DEFAULT_RATE_PRELOAD);
|
||||||
return newrl.gate((double)bytes);
|
return newrl.gate(_rlLimit,(double)bytes);
|
||||||
}
|
}
|
||||||
return rl->second.gate((double)bytes);
|
return rl->second.gate(_rlLimit,(double)bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -452,6 +452,9 @@ private:
|
||||||
|
|
||||||
const RuntimeEnvironment *_r;
|
const RuntimeEnvironment *_r;
|
||||||
|
|
||||||
|
// Rate limits for this network
|
||||||
|
RateLimiter::Limit _rlLimit;
|
||||||
|
|
||||||
// Tap and tap multicast memberships
|
// Tap and tap multicast memberships
|
||||||
EthernetTap *_tap;
|
EthernetTap *_tap;
|
||||||
std::set<MulticastGroup> _multicastGroups;
|
std::set<MulticastGroup> _multicastGroups;
|
||||||
|
|
|
@ -46,6 +46,31 @@ namespace ZeroTier {
|
||||||
class RateLimiter
|
class RateLimiter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Limits to apply to a rate limiter
|
||||||
|
*
|
||||||
|
* Since many rate limiters may share the same fixed limit values,
|
||||||
|
* save memory by breaking this out into a struct parameter that
|
||||||
|
* can be passed into RateLimiter's methods.
|
||||||
|
*/
|
||||||
|
struct Limit
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Speed in bytes per second, or rate of balance accrual
|
||||||
|
*/
|
||||||
|
double bytesPerSecond;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum balance that can ever be accrued (should be > 0.0)
|
||||||
|
*/
|
||||||
|
double maxBalance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum balance, or maximum allowable "debt" (should be <= 0.0)
|
||||||
|
*/
|
||||||
|
double minBalance;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an uninitialized rate limiter
|
* Create an uninitialized rate limiter
|
||||||
*
|
*
|
||||||
|
@ -54,70 +79,58 @@ public:
|
||||||
RateLimiter() throw() {}
|
RateLimiter() throw() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bytesPerSecond Bytes per second to permit (average)
|
|
||||||
* @param preload Initial balance to place in account
|
* @param preload Initial balance to place in account
|
||||||
* @param max Maximum balance to permit to ever accrue (max burst)
|
|
||||||
*/
|
*/
|
||||||
RateLimiter(double bytesPerSecond,double preload,double max)
|
RateLimiter(double preload)
|
||||||
throw()
|
throw()
|
||||||
{
|
{
|
||||||
init(bytesPerSecond,preload,max);
|
init(preload);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize or re-initialize rate limiter
|
* Initialize or re-initialize rate limiter
|
||||||
*
|
*
|
||||||
* @param bytesPerSecond Bytes per second to permit (average)
|
|
||||||
* @param preload Initial balance to place in account
|
* @param preload Initial balance to place in account
|
||||||
* @param max Maximum balance to permit to ever accrue (max burst)
|
|
||||||
*/
|
*/
|
||||||
inline void init(double bytesPerSecond,double preload,double max)
|
inline void init(double preload)
|
||||||
throw()
|
throw()
|
||||||
{
|
{
|
||||||
_bytesPerSecond = bytesPerSecond;
|
|
||||||
_lastTime = Utils::nowf();
|
_lastTime = Utils::nowf();
|
||||||
_balance = preload;
|
_balance = preload;
|
||||||
_max = max;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update balance based on current clock
|
* Update balance based on current clock and supplied Limits bytesPerSecond and maxBalance
|
||||||
*
|
|
||||||
* This can be called at any time to check the current balance without
|
|
||||||
* affecting the behavior of gate().
|
|
||||||
*
|
*
|
||||||
|
* @param lim Current limits in effect
|
||||||
* @return New balance
|
* @return New balance
|
||||||
*/
|
*/
|
||||||
inline double updateBalance()
|
inline double updateBalance(const Limit &lim)
|
||||||
throw()
|
throw()
|
||||||
{
|
{
|
||||||
double now = Utils::nowf();
|
double lt = _lastTime;
|
||||||
double b = _balance = fmin(_max,_balance + (_bytesPerSecond * (now - _lastTime)));
|
double now = _lastTime = Utils::nowf();
|
||||||
_lastTime = now;
|
return (_balance = fmin(lim.maxBalance,_balance + (lim.bytesPerSecond * (now - lt))));
|
||||||
return b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test balance and update / deduct if there is enough to transfer 'bytes'
|
* Update balance and test if a block of 'bytes' should be permitted to be transferred
|
||||||
*
|
*
|
||||||
|
* @param lim Current limits in effect
|
||||||
* @param bytes Number of bytes that we wish to transfer
|
* @param bytes Number of bytes that we wish to transfer
|
||||||
* @return True if balance was sufficient (balance is updated), false if not (balance unchanged)
|
* @return True if balance was sufficient
|
||||||
*/
|
*/
|
||||||
inline bool gate(double bytes)
|
inline bool gate(const Limit &lim,double bytes)
|
||||||
throw()
|
throw()
|
||||||
{
|
{
|
||||||
if (updateBalance() >= bytes) {
|
bool allow = (updateBalance(lim) >= bytes);
|
||||||
_balance -= bytes;
|
_balance = fmax(lim.minBalance,_balance - bytes);
|
||||||
return true;
|
return allow;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double _bytesPerSecond;
|
|
||||||
double _lastTime;
|
double _lastTime;
|
||||||
double _balance;
|
double _balance;
|
||||||
double _max;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
Loading…
Add table
Reference in a new issue