36 template<
typename CLOCK = std::chrono::high_resolution_clock,
typename DUR = std::chrono::seconds,
bool RENORMALIZE_RATE_CHANGES = true>
49 m_elapsedTimeFunction(elapsedTimeFunction),
53 m_accumulatorFraction(0),
54 m_accumulatorUpdated(),
55 m_replenishNumerator(0),
56 m_replenishDenominator(0),
61 static_assert(DUR::period::num > 0,
"Rate duration must have positive numerator");
62 static_assert(DUR::period::den > 0,
"Rate duration must have positive denominator");
63 static_assert(CLOCK::duration::period::num > 0,
"RateLimiter clock duration must have positive numerator");
64 static_assert(CLOCK::duration::period::den > 0,
"RateLimiter clock duration must have positive denominator");
76 std::lock_guard<std::recursive_mutex> lock(m_accumulatorLock);
78 auto now = m_elapsedTimeFunction();
79 auto elapsedTime = (now - m_accumulatorUpdated).count();
82 auto temp = elapsedTime * m_replenishNumerator + m_accumulatorFraction;
83 m_accumulator += temp / m_replenishDenominator;
84 m_accumulatorFraction = temp % m_replenishDenominator;
87 m_accumulator = std::min(m_accumulator, m_maxRate);
88 if (m_accumulator == m_maxRate)
90 m_accumulatorFraction = 0;
95 if (m_accumulator < 0)
97 delay =
DelayType(-m_accumulator * m_delayDenominator / m_delayNumerator);
101 m_accumulator -= cost;
102 m_accumulatorUpdated = now;
112 std::this_thread::sleep_for(
ApplyCost(cost));
118 virtual void SetRate(int64_t rate,
bool resetAccumulator =
false)
override 120 std::lock_guard<std::recursive_mutex> lock(m_accumulatorLock);
123 rate = std::max(static_cast<int64_t>(1), rate);
125 if (resetAccumulator)
127 m_accumulator = rate;
128 m_accumulatorFraction = 0;
129 m_accumulatorUpdated = m_elapsedTimeFunction();
136 if (ShouldRenormalizeAccumulatorOnRateChange())
144 m_accumulator = m_accumulator * rate / m_maxRate;
145 m_accumulatorFraction = m_accumulatorFraction * rate / m_maxRate;
152 m_replenishNumerator = m_maxRate * DUR::period::den * CLOCK::duration::period::num;
153 m_replenishDenominator = DUR::period::num * CLOCK::duration::period::den;
154 auto gcd = ComputeGCD(m_replenishNumerator, m_replenishDenominator);
155 m_replenishNumerator /= gcd;
156 m_replenishDenominator /= gcd;
159 m_delayNumerator = m_maxRate * DelayType::period::num * DUR::period::den;
160 m_delayDenominator = DelayType::period::den * DUR::period::num;
161 gcd = ComputeGCD(m_delayNumerator, m_delayDenominator);
162 m_delayNumerator /= gcd;
163 m_delayDenominator /= gcd;
168 int64_t ComputeGCD(int64_t num1, int64_t num2)
const 173 int64_t rem = num1 % num2;
181 bool ShouldRenormalizeAccumulatorOnRateChange()
const {
return RENORMALIZE_RATE_CHANGES; }
190 std::recursive_mutex m_accumulatorLock;
194 int64_t m_accumulator;
197 int64_t m_accumulatorFraction;
203 int64_t m_replenishNumerator;
204 int64_t m_replenishDenominator;
205 int64_t m_delayNumerator;
206 int64_t m_delayDenominator;
std::chrono::milliseconds DelayType
virtual void SetRate(int64_t rate, bool resetAccumulator=false) override
DefaultRateLimiter(int64_t maxRate, ElapsedTimeFunctionType elapsedTimeFunction=AWS_BUILD_FUNCTION(CLOCK::now))
virtual void ApplyAndPayForCost(int64_t cost) override
std::function< InternalTimePointType() > ElapsedTimeFunctionType
#define AWS_BUILD_FUNCTION(func)
virtual DelayType ApplyCost(int64_t cost) override
virtual ~DefaultRateLimiter()=default
std::chrono::time_point< CLOCK > InternalTimePointType
JSON (JavaScript Object Notation).