userver: userver/utils/aimd_limiter.hpp Source File
Loading...
Searching...
No Matches
aimd_limiter.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/aimd_limiter.hpp
4/// @brief @copybrief utils::AimdLimiter
5
6#include <atomic>
7#include <cstddef>
8
9USERVER_NAMESPACE_BEGIN
10
11namespace utils {
12
13/// @ingroup userver_universal userver_concurrency
14///
15/// @brief Thread safe AIMD (Additive Increase Multiplicative Decrease) limiter
16///
17/// Keeps an adaptive limit within `[min_limit, max_limit]`:
18///
19/// * on success the limit is additively increased:
20/// `limit = min(max_limit, limit + alpha / limit)`;
21/// * on failure the limit is multiplicatively decreased:
22/// `limit = max(min_limit, limit * beta)`.
23///
24/// If `max_limit` is set below `Policy::min_limit`, `max_limit` wins and
25/// GetCurrentLimit() returns `max_limit`.
26class AimdLimiter final {
27public:
28 /// AIMD limit update policy
29 struct Policy {
30 /// Lower bound for the limit, must be positive
31 std::size_t min_limit{2};
32 /// Additive increase coefficient, must be positive and finite
33 double alpha{1.0};
34 /// Multiplicative decrease coefficient, must be in range (0, 1)
35 double beta{0.5};
36 };
37
38 /// Create a limiter with the current limit set to `max_limit`
39 /// @throws std::runtime_error if the policy is invalid
40 AimdLimiter(std::size_t max_limit, Policy policy);
41
42 AimdLimiter(const AimdLimiter&) = delete;
43 AimdLimiter(AimdLimiter&&) = delete;
44 AimdLimiter& operator=(const AimdLimiter&) = delete;
45 AimdLimiter& operator=(AimdLimiter&&) = delete;
46
47 /// Set the upper bound for the limit, clamping down the current limit if needed
48 void SetMaxLimit(std::size_t max_limit) noexcept;
49
50 /// Set limit update policy
51 /// @throws std::runtime_error if the policy is invalid
52 void SetPolicy(Policy policy);
53
54 /// Get the upper bound for the limit (might be inaccurate as the result is stale)
55 std::size_t GetMaxLimit() const noexcept;
56
57 /// Get current limit (might be inaccurate as the result is stale)
58 std::size_t GetCurrentLimit() const noexcept;
59
60 /// Additively increase the limit up to the max limit
61 void OnSuccess() noexcept;
62
63 /// Multiplicatively decrease the limit down to the min limit
64 void OnFailure() noexcept;
65
66private:
67 std::atomic<std::size_t> max_limit_;
68 std::atomic<std::size_t> min_limit_;
69 std::atomic<double> alpha_;
70 std::atomic<double> beta_;
71 std::atomic<double> current_limit_;
72};
73
74} // namespace utils
75
76USERVER_NAMESPACE_END