aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/tvmauth/client/misc/exponential_backoff.h
diff options
context:
space:
mode:
Diffstat (limited to 'library/cpp/tvmauth/client/misc/exponential_backoff.h')
-rw-r--r--library/cpp/tvmauth/client/misc/exponential_backoff.h94
1 files changed, 94 insertions, 0 deletions
diff --git a/library/cpp/tvmauth/client/misc/exponential_backoff.h b/library/cpp/tvmauth/client/misc/exponential_backoff.h
new file mode 100644
index 0000000000..89a7a3c8ad
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/exponential_backoff.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/random/normal.h>
+#include <util/system/event.h>
+
+#include <atomic>
+
+namespace NTvmAuth {
+ // https://habr.com/ru/post/227225/
+ class TExponentialBackoff {
+ public:
+ struct TSettings {
+ TDuration Min;
+ TDuration Max;
+ double Factor = 1.001;
+ double Jitter = 0;
+
+ bool operator==(const TSettings& o) const {
+ return Min == o.Min &&
+ Max == o.Max &&
+ Factor == o.Factor &&
+ Jitter == o.Jitter;
+ }
+ };
+
+ TExponentialBackoff(const TSettings& settings, bool isEnabled = true)
+ : CurrentValue_(settings.Min)
+ , IsEnabled_(isEnabled)
+ {
+ UpdateSettings(settings);
+ }
+
+ void UpdateSettings(const TSettings& settings) {
+ Y_ENSURE(settings.Factor > 1, "factor=" << settings.Factor << ". Should be > 1");
+ Y_ENSURE(settings.Jitter >= 0 && settings.Jitter < 1, "jitter should be in range [0, 1)");
+
+ Min_ = settings.Min;
+ Max_ = settings.Max;
+ Factor_ = settings.Factor;
+ Jitter_ = settings.Jitter;
+ }
+
+ TDuration Increase() {
+ CurrentValue_ = std::min(CurrentValue_ * Factor_, Max_);
+
+ double rnd = StdNormalRandom<double>();
+ const bool isNegative = rnd < 0;
+ rnd = std::abs(rnd);
+
+ const TDuration diff = rnd * Jitter_ * CurrentValue_;
+ if (isNegative) {
+ CurrentValue_ -= diff;
+ } else {
+ CurrentValue_ += diff;
+ }
+
+ return CurrentValue_;
+ }
+
+ TDuration Decrease() {
+ CurrentValue_ = std::max(CurrentValue_ / Factor_, Min_);
+ return CurrentValue_;
+ }
+
+ void Sleep(TDuration add = TDuration()) {
+ if (IsEnabled_.load(std::memory_order_relaxed)) {
+ Ev_.WaitT(CurrentValue_ + add);
+ }
+ }
+
+ void Interrupt() {
+ Ev_.Signal();
+ }
+
+ TDuration GetCurrentValue() const {
+ return CurrentValue_;
+ }
+
+ void SetEnabled(bool val) {
+ IsEnabled_.store(val);
+ }
+
+ private:
+ TDuration Min_;
+ TDuration Max_;
+ double Factor_;
+ double Jitter_;
+ TDuration CurrentValue_;
+ std::atomic_bool IsEnabled_;
+
+ TAutoEvent Ev_;
+ };
+}