Ref T275, CTokenBucket further improvements

* allow to use extrenal timestamp for replenishment
* only replenish if there are not enough tokens "in stock"
This commit is contained in:
Klaus Basan
2018-06-07 01:16:24 +02:00
parent 0f931eeeb3
commit 4393bdeb77
2 changed files with 45 additions and 13 deletions

View File

@@ -24,16 +24,25 @@ namespace BlackMisc
: m_capacity(capacity), m_numTokensToRefill(numTokensToRefill), m_intervalMs(intervalMs)
{}
bool CTokenBucket::tryConsume(int numTokens)
bool CTokenBucket::tryConsume(int numTokens, qint64 msSinceEpoch)
{
Q_ASSERT(numTokens > 0 && numTokens < m_capacity);
// enough tokens in stock?
if (numTokens <= m_availableTokens)
{
m_availableTokens -= numTokens;
return true;
}
// Replenish maximal up to capacity
int replenishedTokens = qMin(m_capacity, this->getTokens());
const int tokens = this->getTokens(msSinceEpoch);
const int replenishedTokens = qMin(m_capacity, tokens);
// Take care of overflows
m_availableTokens = qMin(m_availableTokens + replenishedTokens, m_capacity);
// check again after replenishment
if (numTokens <= m_availableTokens)
{
m_availableTokens -= numTokens;
@@ -42,9 +51,9 @@ namespace BlackMisc
return false;
}
void CTokenBucket::setNumberOfTokensToRefill(int noTokens)
void CTokenBucket::setNumberOfTokensToRefill(int numTokens)
{
m_numTokensToRefill = noTokens;
m_numTokensToRefill = numTokens;
}
void CTokenBucket::setCapacity(int capacity)
@@ -52,9 +61,21 @@ namespace BlackMisc
m_capacity = capacity;
}
int CTokenBucket::getTokens()
void CTokenBucket::setCapacityAndTokensToRefill(int numTokens)
{
const qint64 now = QDateTime::currentMSecsSinceEpoch();
this->setCapacity(numTokens);
this->setNumberOfTokensToRefill(numTokens);
}
int CTokenBucket::getTokensPerSecond() const
{
if (m_intervalMs < 1) { return 0; }
return m_numTokensToRefill * 1000 / m_intervalMs;
}
int CTokenBucket::getTokens(qint64 msSinceEpoch)
{
const qint64 now = msSinceEpoch > 0 ? msSinceEpoch : QDateTime::currentMSecsSinceEpoch();
const qint64 deltaMs = now - m_lastReplenishmentTime;
const int numberOfTokens = static_cast<int>(m_numTokensToRefill * deltaMs / m_intervalMs);

View File

@@ -33,25 +33,36 @@ namespace BlackMisc
CTokenBucket(int capacity, qint64 intervalMs, int numTokensToRefill);
//! Try to consume a number of tokens
bool tryConsume(int numTokens = 1);
//! \remark if a current timestamp is already available, it can be passed
bool tryConsume(int numTokens = 1, qint64 msSinceEpoch = -1);
//! Number of tokens to refill
void setNumberOfTokensToRefill(int noTokens);
void setNumberOfTokensToRefill(int numTokens);
//! Set the capacity
void setCapacity(int capacity);
//! Tokens/capacity if both are same
void setCapacityAndTokensToRefill(int numTokens);
//! Set the interval
void setInterval(qint64 intervalMs) { m_intervalMs = intervalMs; }
//! Tokens per second
int getTokensPerSecond() const;
private:
//! Get available tokens since last replenishment.
//! \note Note that replenishment is implemented lazy.
//! This means, tokens will not replenished on regular basis via a running timer,
//! but they will be replenished while trying to consume them.
int getTokens();
//! \remark a timestamp can be passed, or "now" is taken
int getTokens(qint64 msSinceEpoch);
int m_capacity = 10; //!< Maximum capacity of tokens
int m_availableTokens = 10; //!< Currently available tokens. The initial value is 10
int m_numTokensToRefill; //!< Number of tokens to be refilled each interval
qint64 m_intervalMs = 5000; //!< Refill interval, e.g. every 5 secs
int m_capacity = 10; //!< Maximum capacity of tokens
int m_availableTokens = 10; //!< Currently available tokens. The initial value is 10
int m_numTokensToRefill = 1; //!< Number of tokens to be refilled each interval
qint64 m_intervalMs = 5000; //!< Refill interval, e.g. every 5 secs
qint64 m_lastReplenishmentTime = QDateTime::currentMSecsSinceEpoch(); //!< Last time
};
} // ns