Files
NE_YuR/openflow/include/click/tokenbucket.hh

1022 lines
33 KiB
C++

// -*- c-basic-offset: 4 -*-
#ifndef CLICK_TOKENBUCKET_HH
#define CLICK_TOKENBUCKET_HH
#include <click/timestamp.hh>
#include <click/bigint.hh>
CLICK_DECLS
/** @file <click/tokenbucket.hh>
@brief Token bucket rate limiter templates.
Related template classes that support token bucket rate limiters.
The TokenRateX template class represents a token bucket rate: a refill
I<rate> in tokens per period, plus a I<capacity>, the maximum number of
tokens allowed to accumulate.
The TokenCounterX template class represents an active count of tokens.
Member functions are provided to update the count according to a particular
TokenRateX argument. The counter will fill up with tokens according to the
given rate, to a maximum of the capacity.
A TokenRateX object's state depends only on the rate and capacity, and thus
may be shared by several distinct TokenCounterX objects. But for the common
case that a single counter is paired with a unique rate, the TokenBucketX
template class combines a TokenRateX and a TokenCounterX.
The token bucket templates divide time into discrete units called I<ticks>.
Token counters are refilled up to once per tick. A tick may be less than a
full period. For example, if periods and ticks are 1 second and 1
millisecond, respectively, then a TokenCounterX with associated rate 1000
tokens per second would be refilled at 1 token per millisecond. The
TokenRateX template parameter P defines the time tick unit and frequency.
The provided TokenBucketJiffyParameters class is designed to be used as
TokenRateX's parameter; it measures ticks in units of jiffies.
@sa GapRate */
/** @class TokenRateX include/click/tokenbucket.hh <click/tokenbucket.hh>
@brief Token bucket rate template.
The TokenRateX class implements a token bucket rate. TokenBucketX is
initialized with a rate, in tokens per second, and a capacity in tokens.
Associated token buckets fill up with tokens at the given rate, to a maximum
of the capacity.
Two special types of rate are supported. An <em>unlimited</em> TokenRateX
always refills associated counters to full capacity. Its capacity() equals
token_max. An <em>idle</em> TokenRateX never refills.
Most users will be satisfied with the TokenRate type, which is equal to
TokenRateX<TokenBucketJiffyParameters<unsigned> >.
@sa TokenCounterX, TokenBucketX */
template <typename P> class TokenRateX;
template <typename P>
class TokenRateX : public P { public:
/** @brief The template parameter type. */
typedef P parameter_type;
/** @brief Unsigned type of token counts. */
typedef typename P::token_type token_type;
/** @brief Type of time points. */
typedef typename P::time_point_type time_point_type;
/** @brief Unsigned type of tick counts (differences between time points). */
typedef typename make_unsigned<typename P::duration_type>::type ticks_type;
enum {
max_tokens = (token_type) -1
};
/** @brief Construct an idle token rate. */
TokenRateX() {
assign();
}
/** @brief Construct an idle or unlimited token rate.
* @param unlimited idle if false, unlimited if true */
explicit TokenRateX(bool unlimited) {
assign(unlimited);
}
/** @brief Construct a token rate representing @a rate.
* @param rate refill rate in tokens per period
* @param capacity maximum token accumulation
*
* The rate is idle if either @a rate or @a capacity is 0.
*
* @sa assign(@a rate, @a capacity) */
TokenRateX(token_type rate, token_type capacity) {
assign(rate, capacity);
}
/** @brief Set the token rate to idle or unlimited.
* @param unlimited idle if false, unlimited if true */
inline void assign(bool unlimited = false);
/** @brief Set the token rate and capacity.
* @param rate refill rate in tokens per period
* @param capacity maximum token accumulation
*
* Sets the token bucket's rate to @a rate and capacity to @a capacity.
* If either @a rate or @a capacity is 0, the rate becomes idle. */
inline void assign(token_type rate, token_type capacity);
/** @brief Return true iff the token rate is unlimited. */
bool unlimited() const {
return _time_until_full == 0;
}
/** @brief Return true iff the token rate is idle. */
bool idle() const {
return _tokens_per_tick == 0;
}
/** @brief Return the rate in tokens per period.
*
* Returns max_tokens for unlimited rates. Imprecise computer arithmetic
* may cause the result to differ from the configured rate. */
token_type rate() const;
/** @brief Return the capacity in tokens.
*
* Returns max_tokens for unlimited rates. Imprecise computer arithmetic
* may cause the result to differ from the configured capacity. */
token_type capacity() const {
return max_tokens / _token_scale;
}
/** @brief Return the number of tokens per tick. */
token_type tokens_per_tick() const {
return _tokens_per_tick;
}
/** @brief Return the ratio of fractional tokens to real tokens. */
token_type token_scale() const {
return _token_scale;
}
/** @brief Return the number of ticks required to refill a counter to
* capacity.
*
* Returns (ticks_type) -1 for idle rates. */
ticks_type time_until_full() const {
return _time_until_full;
}
/** @brief Return the current time point.
*
* Implemented as P::now(). */
time_point_type now() const {
return P::now();
}
/** @brief Return the time point corresponding to the @a time parameter.
*
* May not be available for all U types. Implemented as P::time_point(@a
* time). */
template <typename U>
time_point_type time_point(U time) const {
return P::time_point(time);
}
/** @brief Return @a b - @a a, assuming that @a b was measured after @a a.
*
* Some time measurements can, in rare cases, appear to jump backwards,
* as timestamps do when the user changes the current time. If this
* happens (@a b < @a a), time_monotonic_difference returns 0.
* Implemented as P::time_monotonic_difference(@a a, @a b). */
ticks_type time_monotonic_difference(time_point_type a, time_point_type b) const {
return P::time_monotonic_difference(a, b);
}
/** @cond never */
typedef time_point_type epoch_type CLICK_DEPRECATED;
inline token_type tokens_per_epoch() const CLICK_DEPRECATED;
inline ticks_type epochs_until_full() const CLICK_DEPRECATED;
/** @endcond never */
private:
token_type _tokens_per_tick; // 0 iff idle()
token_type _token_scale;
ticks_type _time_until_full; // 0 iff unlimited()
};
template <typename P>
void TokenRateX<P>::assign(bool unlimited)
{
_token_scale = 1;
if (unlimited) {
_tokens_per_tick = max_tokens;
_time_until_full = 0;
} else {
_tokens_per_tick = 0;
_time_until_full = (ticks_type) -1;
}
}
template <typename P>
void TokenRateX<P>::assign(token_type rate, token_type capacity)
{
if (capacity == 0) {
rate = 0;
capacity = max_tokens;
}
token_type frequency = P::frequency();
if (rate != 0) {
// constrain capacity so _tokens_per_tick fits in 1 limb
unsigned min_capacity = (rate - 1) / frequency + 1;
if (capacity < min_capacity)
capacity = min_capacity;
}
_token_scale = max_tokens / capacity;
// XXX on non-32 bit types
static_assert(sizeof(bigint::limb_type) == sizeof(token_type),
"bigint::limb_type should have the same size as token_type.");
bigint::limb_type l[2] = { 0, 0 };
bigint::limb_type a[2] = { rate, 0 };
bigint::multiply_add(l, a, 2, _token_scale);
(void) bigint::divide(l, l, 2, frequency);
assert(l[1] == 0);
if (rate != 0) {
// constrain _tokens_per_tick to be at least 1
_tokens_per_tick = (l[0] != 0 ? l[0] : 1);
_time_until_full = (max_tokens - 1) / _tokens_per_tick + 1;
} else {
_tokens_per_tick = 0;
_time_until_full = (ticks_type) -1;
}
}
template <typename P>
typename P::token_type TokenRateX<P>::rate() const
{
static_assert(sizeof(bigint::limb_type) == sizeof(token_type),
"bigint::limb_type should have the same size as token_type.");
bigint::limb_type l[2] = { _tokens_per_tick / 2, 0 };
bigint::limb_type a[2] = { _tokens_per_tick, 0 };
bigint::multiply_add(l, a, 2, P::frequency());
(void) bigint::divide(l, l, 2, token_scale());
return l[1] ? (token_type) max_tokens : l[0];
}
/** @cond never */
template <typename P>
inline typename TokenRateX<P>::token_type TokenRateX<P>::tokens_per_epoch() const
{
return tokens_per_tick();
}
template <typename P>
inline typename TokenRateX<P>::ticks_type TokenRateX<P>::epochs_until_full() const
{
return time_until_full();
}
/** @endcond never */
/** @cond never */
/* TokenRateConverter safely scales token counts according to an input rate.
Template specializations let us make use of a fast int_multiply() when one
is available. */
template<typename rate_type, bool FM> struct TokenRateConverter {
};
template<typename rate_type> struct TokenRateConverter<rate_type, true> {
static bool cvt(const rate_type &rate, typename rate_type::token_type &t) {
typename rate_type::token_type high;
int_multiply(t, rate.token_scale(), t, high);
if (high)
t = rate_type::max_tokens;
return !high;
}
};
template<typename rate_type> struct TokenRateConverter<rate_type, false> {
static bool cvt(const rate_type &rate, typename rate_type::token_type &t) {
if (t <= rate.capacity()) {
t *= rate.token_scale();
return true;
} else {
t = rate_type::max_tokens;
return false;
}
}
};
/** @endcond never */
/** @class TokenCounterX include/click/tokenbucket.hh <click/tokenbucket.hh>
@brief Token bucket counter template.
The TokenCounterX class implements a token counter associated with a token
bucket rate. The rate type, normally a TokenRateX, is specified as a
template parameter. Most of its member functions take an explicit rate
argument. The contains() method reports whether the counter has at least a
given number of tokens. The counter is emptied by the remove() and
remove_if() methods and refilled by the refill() methods.
Often the token rate associated with a counter will not change during the
counter's lifetime. TokenCounterX will work correctly if the rate changes,
however. (See the adjust() method for details.)
TokenCounterX internally maintains fractional tokens, so it should be
relatively precise.
Idle and unlimited rates affect how TokenCounters are refilled. For idle
rates, refill() is a no-op. For unlimited rates, any refill() makes the
counter full(), containing max_tokens tokens. The set(), empty(), full(),
remove(), and similar functions act as normal for idle and unlimited rates.
Most users will be satisfied with the TokenCounter type, which is equal to
TokenCounterX<TokenRateX<TokenBucketJiffyParameters<unsigned> > >.
@sa TokenRateX, TokenBucketX */
template <typename R>
class TokenCounterX { public:
/** @brief The token rate type. */
typedef R rate_type;
/** @brief Unsigned type of token counts. */
typedef typename R::token_type token_type;
/** @brief Type of time points. */
typedef typename R::time_point_type time_point_type;
/** @brief Unsigned type of tick counts (differences between time points). */
typedef typename R::ticks_type ticks_type;
enum {
max_tokens = R::max_tokens
};
/** @brief Construct an empty TokenCounter.
*
* The initial time point is 0. */
TokenCounterX()
: _tokens(0), _time_point() {
}
/** @brief Construct a TokenCounter.
* @param full whether the counter is created full
*
* The counter is initially full() if @a full is true, otherwise it is
* empty. The initial time point is 0. */
explicit TokenCounterX(bool full)
: _tokens(full ? (token_type) max_tokens : 0), _time_point() {
}
/** @brief Return the number of tokens in the counter.
* @param rate associated token rate
*
* The return value is a lower bound on the number of tokens, since
* TokenCounterX keeps track of fractional tokens. */
token_type size(const rate_type &rate) const {
return _tokens / rate.token_scale();
}
/** @brief Return the counter's fullness fraction.
*
* The return value is a number between 0 and max_tokens, where max_tokens
* represents full capacity. */
token_type fraction() const {
return _tokens;
}
/** @brief Test if the token counter is completely empty. */
bool empty() const {
return _tokens == 0;
}
/** @brief Test if the token counter is at full capacity. */
bool full() const {
return _tokens == (token_type) max_tokens;
}
/** @brief Test if the token counter has at least @a t tokens.
* @param rate associated token rate
* @param t token count
*
* Returns false whenever @a t is greater than <em>rate</em>.@link
* TokenRateX::capacity capacity()@endlink. */
bool contains(const rate_type &rate, token_type t) const {
return cvt_type::cvt(rate, t) && contains_fraction(t);
}
/** @brief Test if the token counter is above a fraction of its capacity.
* @param f fullness fraction, where max_tokens is full capacity */
bool contains_fraction(token_type f) const {
return f <= _tokens;
}
/** @brief Clear the token counter.
*
* @sa set(), set_full() */
void clear() {
_tokens = 0;
}
/** @brief Fill the token counter to capacity.
*
* @sa clear(), set() */
void set_full() {
_tokens = max_tokens;
}
/** @brief Set the token counter to contain @a t tokens.
* @param rate associated token rate
* @param t number of tokens
*
* The result will never have more tokens than the associated capacity. */
void set(const rate_type &rate, token_type t) {
(void) cvt_type::cvt(rate, t);
_tokens = t;
}
/** @brief Set the token counter to a fraction of its capacity.
* @param f fullness fraction, where max_tokens is full capacity */
void set_fraction(token_type f) {
_tokens = f;
}
/** @brief Compensate the counter for a change of rate.
* @param old_rate old associated token rate
* @param new_rate new associated token rate
*
* TokenCounterX's internal representation stores the token count as a
* fraction of the rate's capacity. This means that if you change the
* associated rate to have a different capacity, the token count will
* appear to change. To keep the token count roughly the same, call
* adjust() with the old and new rates; TokenCounterX will as far as
* possible compensate for the rate change. */
void adjust(const rate_type &old_rate, const rate_type &new_rate) {
if (old_rate.token_scale() != new_rate.token_scale()) {
static_assert(sizeof(bigint::limb_type) == sizeof(token_type),
"bigint::limb_type should have the same size as token_type.");
bigint::limb_type l[2] = { 0, 0 };
bigint::limb_type a[2] = { _tokens, 0 };
bigint::multiply_add(l, a, 2, new_rate.token_scale());
(void) bigint::divide(l, l, 2, old_rate.token_scale());
_tokens = l[1] ? (token_type) max_tokens : l[0];
}
}
/** @brief Refill the token counter to time @a rate.now().
* @param rate associated token rate
*
* There are three refill() methods, useful for different methods of
* measuring time. This method calls @a rate.now(), which returns the
* current time. Other methods use an explicit time point and a @a
* rate.time_point(U) method.
*
* @sa set_time_point */
void refill(const rate_type &rate);
/** @brief Refill the token counter for @a time.
* @param rate associated token rate
* @param time new time point */
void refill(const rate_type &rate, time_point_type time);
/** @brief Refill the token counter for @a time.
* @param rate associated token rate
* @param time new time */
template <typename U> void refill(const rate_type &rate, U time);
/** @brief Set the token counter's internal time point to @a time.
* @param time new time point
*
* Unlike refill(), this method does not refill the counter.
*
* @sa refill */
void set_time_point(time_point_type time) {
_time_point = time;
}
/** @brief Remove @a t tokens from the counter.
* @param rate associated token rate
* @param t number of tokens
*
* If the token counter contains less than @a t tokens, the new token
* count is 0. */
void remove(const rate_type &rate, token_type t) {
(void) cvt_type::cvt(rate, t);
remove_fraction(t);
}
/** @brief Remove @a t tokens from the counter if it contains @a t tokens.
* @param rate associated token rate
* @param t number of tokens
* @return true if @a t tokens were removed, false otherwise
*
* If the counter contains @a t or more tokens, calls remove(@a t) and
* returns true. If it contains less than @a t tokens, returns false
* without removing any tokens. */
bool remove_if(const rate_type &rate, token_type t) {
return cvt_type::cvt(rate, t) && remove_fraction_if(t);
}
/** @brief Remove a fullness fraction from the counter.
* @param f fullness fraction, where max_tokens is full capacity
*
* If the token counter is less than @a f full, the new token count is 0. */
void remove_fraction(token_type f) {
_tokens = (f <= _tokens ? _tokens - f : 0);
}
/** @brief Remove a fullness fraction from the counter if it is full enough.
* @param f fullness fraction, where max_tokens is full capacity
* @return true if @a f was removed, false otherwise
*
* If fraction() is at least @a f, calls remove_fraction(@a f) and returns
* true. Otherwise, returns false without removing any tokens. */
bool remove_fraction_if(token_type f) {
if (f <= _tokens) {
_tokens -= f;
return true;
} else
return false;
}
/** @brief Return the number of ticks until contains(<em>rate</em>, <em>t</em>).
*
* @param rate associated token rate
* @param t token count
*
* Returns (ticks_type) -1 if passing time will never make
* @link contains() contains(<em>rate</em>, <em>t</em>)@endlink
* true. */
ticks_type time_until_contains(const rate_type &rate,
token_type t) const {
if (cvt_type::cvt(rate, t))
return time_until_contains_fraction(rate, t);
else
return (ticks_type) -1;
}
/** @brief Return the number of ticks until contains_fraction(<em>f</em>).
* @param rate associated token rate
* @param f fullness fraction, where max_tokens is full capacity
*
* Returns (ticks_type) -1 if passing time will never make
* @link contains_fraction() contains_fraction(<em>f</em>)@endlink
* true. */
ticks_type time_until_contains_fraction(const rate_type &rate,
token_type f) const {
if (f <= _tokens || rate.time_until_full() == 0)
return 0;
else if (rate.tokens_per_tick() == 0)
return (ticks_type) -1;
else
return (f - _tokens - 1) / rate.tokens_per_tick() + 1;
}
/** @cond never */
inline ticks_type epochs_until_contains(const rate_type &rate, token_type t) const CLICK_DEPRECATED;
inline ticks_type epochs_until_contains_fraction(const rate_type &rate, token_type f) const CLICK_DEPRECATED;
/** @endcond never */
private:
token_type _tokens;
time_point_type _time_point;
typedef TokenRateConverter<rate_type, has_fast_int_multiply<token_type>::value> cvt_type;
};
template <typename R>
void TokenCounterX<R>::refill(const rate_type &rate, time_point_type time)
{
ticks_type diff = rate.time_monotonic_difference(_time_point, time);
if (diff >= rate.time_until_full()) {
// ignore special case of idle rates -- we assume that
// rate.time_monotonic_difference() will never return (ticks_type) -1,
// and ensure that ticks_type is unsigned
_tokens = max_tokens;
} else if (diff > 0) {
token_type new_tokens = _tokens + diff * rate.tokens_per_tick();
_tokens = (new_tokens < _tokens ? (token_type) max_tokens : new_tokens);
}
_time_point = time;
}
template <typename R>
void TokenCounterX<R>::refill(const rate_type &rate)
{
refill(rate, rate.now());
}
template <typename R> template <typename U>
void TokenCounterX<R>::refill(const rate_type &rate, U time)
{
refill(rate, rate.time_point(time));
}
/** @cond never */
template <typename R>
inline typename TokenCounterX<R>::ticks_type TokenCounterX<R>::epochs_until_contains(const rate_type &rate, token_type t) const
{
return time_until_contains(rate, t);
}
template <typename R>
inline typename TokenCounterX<R>::ticks_type TokenCounterX<R>::epochs_until_contains_fraction(const rate_type &rate, token_type f) const
{
return time_until_contains_fraction(rate, f);
}
/** @endcond never */
/** @class TokenBucketJiffyParameters include/click/tokenbucket.hh <click/tokenbucket.hh>
@brief Helper class for token bucket rate limiter.
Pass this class as the parameter to TokenRateX. TokenBucketJiffyParameters
measures ticks in units of jiffies. The template parameter is the type of
tokens. */
template <typename T>
class TokenBucketJiffyParameters { public:
/** @brief The type of tokens. Always unsigned. */
typedef T token_type;
/** @brief The type of a time point. Always unsigned. */
typedef click_jiffies_t time_point_type;
/** @brief The type of a difference between time points. Always signed. */
typedef click_jiffies_difference_t duration_type;
/** @brief Return the current time point.
* @note TokenBucketJiffyParameters measures time points in jiffies. */
static time_point_type now() {
return click_jiffies();
}
static time_point_type time_point(time_point_type t) {
return t;
}
/** @brief Return @a b - @a a, assuming that @a b was measured after @a a.
*
* Some time measurements can, in rare cases, appear to jump backwards,
* as timestamps do when the user changes the current time. If this
* happens, and @a b < @a a (even though @a b happened after @a a),
* time_monotonic_difference must return 0. */
static duration_type time_monotonic_difference(time_point_type a, time_point_type b) {
#if CLICK_JIFFIES_MONOTONIC
return b - a;
#else
return (likely(a <= b) ? b - a : 0);
#endif
}
/** @brief Return true if @a a happened before @a b. */
static bool time_less(time_point_type a, time_point_type b) {
return click_jiffies_less(a, b);
}
/** @brief Return the number of time points per period.
*
* Here, this is the number of jiffies per second. */
static unsigned frequency() {
return CLICK_HZ;
}
/** @brief Return the Timestamp representing a given time point. */
static Timestamp timestamp(time_point_type x) {
return Timestamp::make_jiffies(x);
}
/** @brief Return the Timestamp representing a given tick count. */
static Timestamp timestamp(duration_type x) {
return Timestamp::make_jiffies(x);
}
};
/** @class TokenBucketX include/click/tokenbucket.hh <click/tokenbucket.hh>
@brief Token bucket rate limiter.
The TokenBucketX class implements a token bucket rate limiter. It is
implemented as a pair of TokenRateX and TokenCounterX.
Most users will be satisfied with the TokenBucket type, which is equal to
TokenBucketX<TokenBucketJiffyParameters<unsigned> >.
@sa GapRate */
template <typename P>
class TokenBucketX { public:
/** @brief The template parameter type. */
typedef P parameter_type;
/** @brief The token rate type. */
typedef TokenRateX<P> rate_type;
/** @brief The token counter type. */
typedef TokenCounterX<rate_type> counter_type;
/** @brief Unsigned type of token counts. */
typedef typename rate_type::token_type token_type;
/** @brief Type of time ticks. */
typedef typename rate_type::time_point_type time_point_type;
/** @brief Unsigned type of differences between time ticks. */
typedef typename rate_type::ticks_type ticks_type;
enum {
max_tokens = rate_type::max_tokens
};
/** @brief Construct an idle token bucket.
*
* The initial time point is 0. */
TokenBucketX() {
}
/** @brief Construct an idle or unlimited token bucket.
* @param unlimited idle if false, unlimited if true
*
* The initial time point is 0. */
explicit TokenBucketX(bool unlimited)
: _rate(unlimited), _bucket(unlimited) {
}
/** @brief Construct a token bucket representing @a rate.
* @param rate refill rate in tokens per period
* @param capacity maximum token accumulation
*
* The initial time point is 0 and the token bucket is initially full (the
* initial token count equals @a capacity). The rate is idle if either @a
* rate or @a capacity is 0.
*
* @sa assign(@a rate, @a capacity) */
TokenBucketX(token_type rate, token_type capacity)
: _rate(rate, capacity), _bucket(rate != 0 && capacity != 0) {
}
/** @brief Set the token bucket rate to idle or unlimited.
* @param unlimited idle if false, unlimited if true */
void assign(bool unlimited = false) {
_rate.assign(unlimited);
}
/** @brief Set the token bucket rate and capacity.
* @param rate refill rate in tokens per period
* @param capacity maximum token accumulation
*
* Sets the token bucket's rate to @a rate and capacity to @a capacity.
* If either @a rate or @a capacity is 0, the token bucket becomes idle.
* The time point is unchanged.
*
* The ratio of tokens/burst is unchanged by the assignment, so the actual
* number of tokens could go up or down, depending on how the rate is
* changed.
*
* @sa assign_adjust */
void assign(token_type rate, token_type capacity) {
_rate.assign(rate, capacity);
}
/** @brief Set the token bucket rate and capacity, preserving the
* token count.
* @param rate refill rate in tokens per period
* @param capacity maximum token accumulation
*
* This performs the same function as assign(), but additionally
* keeps the number of tokens roughly stable.
*
* @sa assign */
void assign_adjust(token_type rate, token_type capacity) {
rate_type old_rate(_rate);
_rate.assign(rate, capacity);
_bucket.adjust(old_rate, _rate);
}
/** @brief Return true iff the token rate is unlimited. */
bool unlimited() const {
return _rate.unlimited();
}
/** @brief Return true iff the token rate is idle. */
bool idle() const {
return _rate.idle();
}
/** @brief Return the rate in tokens per period.
*
* Returns max_tokens for unlimited rates. Imprecise computer arithmetic
* may cause the result to differ from the configured rate. */
token_type rate() const {
return _rate.rate();
}
/** @brief Return the capacity in tokens.
*
* Returns max_tokens for unlimited rates. Imprecise computer arithmetic
* may cause the result to differ from the configured capacity. */
token_type capacity() const {
return _rate.capacity();
}
/** @brief Return the number of tokens in the bucket.
*
* The return value is a lower bound on the number of tokens, since
* TokenBucketX keeps track of fractional tokens. */
token_type size() const {
return _bucket.size(_rate);
}
/** @brief Return the bucket's fullness fraction.
*
* The return value is a number between 0 and max_tokens, where max_tokens
* represents full capacity. */
token_type fraction() const {
return _bucket.fraction();
}
/** @brief Test if the token bucket is completely empty. */
bool empty() const {
return _bucket.empty();
}
/** @brief Test if the token bucket is at full capacity. */
bool full() const {
return _bucket.full();
}
/** @brief Test if the token bucket has at least @a t tokens.
*
* Returns true whenever @a t is zero or @a rate is unlimited. Returns
* false whenever @a t is greater than @a rate.capacity(). */
bool contains(token_type t) const {
return _bucket.contains(_rate, t);
}
/** @brief Test if the token bucket is above a fraction of its capacity.
* @param f fullness fraction, where max_tokens is full capacity */
bool contains_fraction(token_type f) const {
return _bucket.contains_fraction(f);
}
/** @brief Clear the token bucket.
*
* @sa set(), set_full() */
void clear() {
_bucket.clear();
}
/** @brief Fill the token bucket to capacity.
*
* @sa clear(), set() */
void set_full() {
_bucket.set_full();
}
/** @brief Set the token bucket to contain @a t tokens.
* @param t number of tokens
*
* The result will never have more tokens than the associated capacity. */
void set(token_type t) {
_bucket.set(_rate, t);
}
/** @brief Set the token bucket to a fraction of its capacity.
* @param f fullness fraction, where max_tokens is full capacity */
void set_fraction(token_type f) {
_bucket.set_fraction(f);
}
/** @brief Refill the token bucket to time P::now().
*
* There are three refill() methods, useful for different methods of
* measuring ticks. This method call parameter_type::now(), which returns
* the current time. Other methods use an explicit time point and a
* parameter_type::time(U) method.
*
* @sa set_time_point */
void refill() {
_bucket.refill(_rate);
}
/** @brief Refill the token bucket for @a time. */
void refill(time_point_type time) {
_bucket.refill(_rate, time);
}
/** @brief Refill the token bucket for time P::time_point(@a time). */
template <typename U> void refill(U time) {
_bucket.refill(_rate, time);
}
/** @brief Set the token bucket's internal time point to @a time.
*
* Unlike refill(), this method does not refill the counter.
*
* @sa refill */
void set_time_point(time_point_type time) {
_bucket.set_time_point(time);
}
/** @brief Remove @a t tokens from the bucket.
* @param t number of tokens
*
* If the token bucket contains less than @a t tokens, the new token
* count is 0. */
void remove(token_type t) {
_bucket.remove(_rate, t);
}
/** @brief Remove @a t tokens from the bucket if it contains @a t tokens.
* @param t number of tokens
* @return true if @a t tokens were removed, false otherwise
*
* If the token bucket contains @a t or more tokens, calls remove(@a t)
* and returns true. If it contains less than @a t tokens, returns false
* without removing any tokens. */
bool remove_if(token_type t) {
return _bucket.remove_if(_rate, t);
}
/** @brief Remove a fullness fraction from the bucket.
* @param f fullness fraction, where max_tokens is full capacity
*
* If the token counter is less than @a f full, the new token count is 0. */
void remove_fraction(token_type f) {
_bucket.remove_fraction(f);
}
/** @brief Remove a fullness fraction from the bucket if it is full enough.
* @param f fullness fraction, where max_tokens is full capacity
* @return true if @a f was removed, false otherwise
*
* If fraction() is at least @a f, calls remove_fraction(@a f) and returns
* true. Otherwise, returns false without removing any tokens. */
bool remove_fraction_if(token_type f) {
return _bucket.remove_fraction_if(f);
}
/** @brief Return the number of ticks until contains(@a t).
*
* Returns (ticks_type) -1 if passing time will never make contains(@a t)
* true. */
ticks_type time_until_contains(token_type t) const {
return _bucket.time_until_contains(_rate, t);
}
/** @brief Return the number of ticks until contains_fraction(@a f).
*
* Returns (ticks_type) -1 if passing time will never make
* contains_fraction(@a f) true. */
ticks_type time_until_contains_fraction(ticks_type f) const {
return _bucket.time_until_contains_fraction(_rate, f);
}
/** @cond never */
inline ticks_type epochs_until_contains(const rate_type &rate, token_type t) const CLICK_DEPRECATED;
inline ticks_type epochs_until_contains_fraction(const rate_type &rate, token_type f) const CLICK_DEPRECATED;
/** @endcond never */
private:
rate_type _rate;
counter_type _bucket;
};
/** @cond never */
template <typename P>
inline typename TokenBucketX<P>::ticks_type TokenBucketX<P>::epochs_until_contains(const rate_type &rate, token_type t) const
{
return time_until_contains(rate, t);
}
template <typename P>
inline typename TokenBucketX<P>::ticks_type TokenBucketX<P>::epochs_until_contains_fraction(const rate_type &rate, token_type f) const
{
return time_until_contains_fraction(rate, f);
}
/** @endcond never */
/** @class TokenRate include/click/tokenbucket.hh <click/tokenbucket.hh>
* @brief Jiffy-based token bucket rate
*
* Equivalent to
* @link TokenRateX TokenRateX<TokenBucketJiffyParameters<unsigned> >@endlink.
* @sa TokenRateX, TokenBucketJiffyParameters */
typedef TokenRateX<TokenBucketJiffyParameters<unsigned> > TokenRate;
/** @class TokenCounter include/click/tokenbucket.hh <click/tokenbucket.hh>
* @brief Jiffy-based token counter
*
* Equivalent to
* @link TokenCounterX TokenCounterX<TokenRate>@endlink.
* @sa TokenCounterX, TokenRate */
typedef TokenCounterX<TokenRate> TokenCounter;
/** @class TokenBucket include/click/tokenbucket.hh <click/tokenbucket.hh>
* @brief Jiffy-based token bucket rate limiter
*
* Equivalent to
* @link TokenBucketX TokenBucketX<TokenBucketJiffyParameters<unsigned> >@endlink.
* @sa TokenBucketX, TokenBucketJiffyParameters */
typedef TokenBucketX<TokenBucketJiffyParameters<unsigned> > TokenBucket;
CLICK_ENDDECLS
#endif