dncurrency/nano/lib/rate_limiting.cpp
clemahieu 08ea15a2d8 Fixes an issue where last_refill would update even if there were no tokens to add.
Adds a constant for the unlimited rate sentinel.
2023-02-06 22:16:27 +00:00

64 lines
1.9 KiB
C++

#include <nano/lib/locks.hpp>
#include <nano/lib/rate_limiting.hpp>
#include <nano/lib/utility.hpp>
#include <limits>
nano::rate::token_bucket::token_bucket (std::size_t max_token_count_a, std::size_t refill_rate_a)
{
reset (max_token_count_a, refill_rate_a);
}
bool nano::rate::token_bucket::try_consume (unsigned tokens_required_a)
{
debug_assert (tokens_required_a <= 1e9);
nano::lock_guard<nano::mutex> guard{ mutex };
refill ();
bool possible = current_size >= tokens_required_a;
if (possible)
{
current_size -= tokens_required_a;
}
else if (tokens_required_a == 1e9)
{
current_size = 0;
}
// Keep track of smallest observed bucket size so burst size can be computed (for tests and stats)
smallest_size = std::min (smallest_size, current_size);
return possible || refill_rate == unlimited_rate_sentinel;
}
void nano::rate::token_bucket::refill ()
{
auto now (std::chrono::steady_clock::now ());
std::size_t tokens_to_add = static_cast<std::size_t> (std::chrono::duration_cast<std::chrono::nanoseconds> (now - last_refill).count () / 1e9 * refill_rate);
// Only update if there are any tokens to add
if (tokens_to_add > 0)
{
current_size = std::min (current_size + tokens_to_add, max_token_count);
last_refill = std::chrono::steady_clock::now ();
}
}
std::size_t nano::rate::token_bucket::largest_burst () const
{
nano::lock_guard<nano::mutex> guard{ mutex };
return max_token_count - smallest_size;
}
void nano::rate::token_bucket::reset (std::size_t max_token_count_a, std::size_t refill_rate_a)
{
nano::lock_guard<nano::mutex> guard{ mutex };
// A token count of 0 indicates unlimited capacity. We use 1e9 as
// a sentinel, allowing largest burst to still be computed.
if (max_token_count_a == 0 || refill_rate_a == 0)
{
refill_rate_a = max_token_count_a = unlimited_rate_sentinel;
}
max_token_count = smallest_size = current_size = max_token_count_a;
refill_rate = refill_rate_a;
last_refill = std::chrono::steady_clock::now ();
}