userver: userver/utils/token_bucket.hpp Source File
Loading...
Searching...
No Matches
token_bucket.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/token_bucket.hpp
4/// @brief @copybrief utils::TokenBucket
5
6#include <atomic>
7#include <chrono>
8
9#include <userver/utils/statistics/rate_counter.hpp>
10
11USERVER_NAMESPACE_BEGIN
12
13namespace utils {
14
15/// @ingroup userver_universal userver_concurrency
16///
17/// Thread safe ratelimiter
18class TokenBucket final {
19public:
20 using TimePoint = std::chrono::steady_clock::time_point;
21 using Duration = std::chrono::steady_clock::duration;
22
23 /// Token bucket refill policy
24 struct RefillPolicy {
25 /// Refill amount (zero disables refills)
26 size_t amount{1};
27 /// Refill interval (zero makes bucket to instantly refill)
28 Duration interval{Duration::max()};
29 };
30
31 /// Create an initially always empty token bucket
32 TokenBucket() noexcept;
33
34 /// Create a token bucket with max_size tokens and a specified refill policy
35 TokenBucket(size_t max_size, RefillPolicy policy);
36
37 /// Start with max_size tokens and add 1 token each
38 /// single_token_update_interval up to max_size.
39 /// Zero duration means "no limit".
40 [[deprecated]] TokenBucket(size_t max_size, Duration single_token_update_interval);
41
42 /// Create an initially unbounded token bucket (largest size, instant refill)
43 static TokenBucket MakeUnbounded() noexcept;
44
45 TokenBucket(const TokenBucket&) = delete;
46 TokenBucket(TokenBucket&&) noexcept;
47 TokenBucket& operator=(const TokenBucket&) = delete;
48 TokenBucket& operator=(TokenBucket&&) noexcept;
49
50 bool IsUnbounded() const;
51
52 /// Get current token limit (might be inaccurate as the result is stale)
53 size_t GetMaxSizeApprox() const;
54
55 /// Get current refill amount (might be inaccurate as the result is stale)
56 size_t GetRefillAmountApprox() const;
57
58 /// Get current refill interval (might be inaccurate as the result is stale)
59 Duration GetRefillIntervalApprox() const;
60
61 /// Get rate (tokens per second)
62 double GetRatePs() const;
63
64 /// Get current token count (might be inaccurate as the result is stale)
66
67 /// Set max token count
68 void SetMaxSize(size_t max_size);
69
70 /// Add 1 token each token_update_interval.
71 /// Zero duration means "no limit".
72 [[deprecated]] void SetUpdateInterval(Duration single_token_update_interval);
73
74 /// Set refill policy for the bucket
76
77 /// Set refill policy to "instant refill".
78 ///
79 /// Obtain does not deplete the bucket in this mode.
80 /// Equivalent to `amount=1, interval=zero()` policy.
82
83 /// @returns true if token was successfully obtained
84 [[nodiscard]] bool Obtain();
85
86 /// @return true if the requested number of tokens was successfully obtained
87 [[nodiscard]] bool ObtainAll(size_t count);
88
89 /// Get rate for specified update interval (updates per second)
90 static double GetRatePs(Duration interval);
91
92private:
93 friend void DumpMetric(statistics::Writer& writer, const TokenBucket& bucket);
94
95 void Update();
96
97 std::atomic<size_t> max_size_;
98 std::atomic<size_t> token_refill_amount_;
99 std::atomic<Duration> token_refill_interval_;
100 std::atomic<size_t> tokens_;
101 std::atomic<TimePoint> last_update_;
102
103 statistics::RateCounter obtain_failed_;
104};
105
106void DumpMetric(statistics::Writer& writer, const TokenBucket& bucket);
107
108} // namespace utils
109
110USERVER_NAMESPACE_END