aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/backoff
diff options
context:
space:
mode:
authorGravatar David Garcia Quintas <dgq@google.com>2017-11-22 16:31:01 -0800
committerGravatar David Garcia Quintas <dgq@google.com>2017-11-22 16:31:01 -0800
commitdde6afc0c01d2ebac5c5532aaf35e416c72a4245 (patch)
treec96b87aa0d2250aef8200489b5c1cd7bbbcd1ea1 /src/core/lib/backoff
parent070a14f0cdf079ecc622bce54d0a58c34fb5ff69 (diff)
C++-ize backoff
Diffstat (limited to 'src/core/lib/backoff')
-rw-r--r--src/core/lib/backoff/backoff.cc83
-rw-r--r--src/core/lib/backoff/backoff.h132
2 files changed, 113 insertions, 102 deletions
diff --git a/src/core/lib/backoff/backoff.cc b/src/core/lib/backoff/backoff.cc
index dc754ddd82..7376ed6d91 100644
--- a/src/core/lib/backoff/backoff.cc
+++ b/src/core/lib/backoff/backoff.cc
@@ -18,63 +18,52 @@
#include "src/core/lib/backoff/backoff.h"
+#include <algorithm>
+#include <cstdlib>
+
#include <grpc/support/useful.h>
-void grpc_backoff_init(grpc_backoff* backoff, grpc_millis initial_backoff,
- double multiplier, double jitter,
- grpc_millis min_connect_timeout,
- grpc_millis max_backoff) {
- backoff->initial_backoff = initial_backoff;
- backoff->multiplier = multiplier;
- backoff->jitter = jitter;
- backoff->min_connect_timeout = min_connect_timeout;
- backoff->max_backoff = max_backoff;
- backoff->rng_state = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
-}
+namespace grpc_core {
-grpc_backoff_result grpc_backoff_begin(grpc_exec_ctx* exec_ctx,
- grpc_backoff* backoff) {
- backoff->current_backoff = backoff->initial_backoff;
- const grpc_millis initial_timeout =
- GPR_MAX(backoff->initial_backoff, backoff->min_connect_timeout);
- const grpc_millis now = grpc_exec_ctx_now(exec_ctx);
- const grpc_backoff_result result = {now + initial_timeout,
- now + backoff->current_backoff};
- return result;
+namespace {
+static double generate_uniform_random_number_between(double a, double b) {
+ if (a == b) return a;
+ if (a > b) GPR_SWAP(double, a, b); // make sure a < b
+ const double range = b - a;
+ const double zero_to_one_rand = rand() / (double)RAND_MAX;
+ return a + zero_to_one_rand * range;
}
+} // namespace
-/* Generate a random number between 0 and 1. */
-static double generate_uniform_random_number(uint32_t* rng_state) {
- *rng_state = (1103515245 * *rng_state + 12345) % ((uint32_t)1 << 31);
- return *rng_state / (double)((uint32_t)1 << 31);
+Backoff::Backoff(const Options& options) : options_(options) {
+ seed = (unsigned int)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
}
-static double generate_uniform_random_number_between(uint32_t* rng_state,
- double a, double b) {
- if (a == b) return a;
- if (a > b) GPR_SWAP(double, a, b); // make sure a < b
- const double range = b - a;
- return a + generate_uniform_random_number(rng_state) * range;
+Backoff::Result Backoff::Begin(grpc_exec_ctx* exec_ctx) {
+ current_backoff_ = options_.initial_backoff();
+ const grpc_millis initial_timeout =
+ std::max(options_.initial_backoff(), options_.min_connect_timeout());
+ const grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+ return Backoff::Result{now + initial_timeout, now + current_backoff_};
}
-grpc_backoff_result grpc_backoff_step(grpc_exec_ctx* exec_ctx,
- grpc_backoff* backoff) {
- backoff->current_backoff = (grpc_millis)(GPR_MIN(
- backoff->current_backoff * backoff->multiplier, backoff->max_backoff));
+Backoff::Result Backoff::Step(grpc_exec_ctx* exec_ctx) {
+ current_backoff_ =
+ (grpc_millis)(std::min(current_backoff_ * options_.multiplier(),
+ (double)options_.max_backoff()));
const double jitter = generate_uniform_random_number_between(
- &backoff->rng_state, -backoff->jitter * backoff->current_backoff,
- backoff->jitter * backoff->current_backoff);
- const grpc_millis current_timeout =
- GPR_MAX((grpc_millis)(backoff->current_backoff + jitter),
- backoff->min_connect_timeout);
- const grpc_millis next_timeout = GPR_MIN(
- (grpc_millis)(backoff->current_backoff + jitter), backoff->max_backoff);
+ -options_.jitter() * current_backoff_,
+ options_.jitter() * current_backoff_);
+ const grpc_millis current_timeout = std::max(
+ (grpc_millis)(current_backoff_ + jitter), options_.min_connect_timeout());
+ const grpc_millis next_timeout = std::min(
+ (grpc_millis)(current_backoff_ + jitter), options_.max_backoff());
const grpc_millis now = grpc_exec_ctx_now(exec_ctx);
- const grpc_backoff_result result = {now + current_timeout,
- now + next_timeout};
- return result;
+ return Backoff::Result{now + current_timeout, now + next_timeout};
}
-void grpc_backoff_reset(grpc_backoff* backoff) {
- backoff->current_backoff = backoff->initial_backoff;
-}
+void Backoff::Reset() { current_backoff_ = options_.initial_backoff(); }
+
+void Backoff::SetRandomSeed(uint32_t seed) { srand(seed); }
+
+} // namespace grpc_core
diff --git a/src/core/lib/backoff/backoff.h b/src/core/lib/backoff/backoff.h
index 1067281403..ab644b979a 100644
--- a/src/core/lib/backoff/backoff.h
+++ b/src/core/lib/backoff/backoff.h
@@ -21,63 +21,85 @@
#include "src/core/lib/iomgr/exec_ctx.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- /// const: how long to wait after the first failure before retrying
- grpc_millis initial_backoff;
-
- /// const: factor with which to multiply backoff after a failed retry
- double multiplier;
-
- /// const: amount to randomize backoffs
- double jitter;
-
- /// const: minimum time between retries
- grpc_millis min_connect_timeout;
-
- /// const: maximum time between retries
- grpc_millis max_backoff;
-
+namespace grpc_core {
+
+class Backoff {
+ public:
+ class Options;
+ struct Result;
+
+ /// Initialize backoff machinery - does not need to be destroyed
+ explicit Backoff(const Options& options);
+
+ /// Begin retry loop: returns the deadlines to be used for the current attempt
+ /// and the subsequent retry, if any.
+ Result Begin(grpc_exec_ctx* exec_ctx);
+ /// Step a retry loop: returns the deadlines to be used for the current
+ /// attempt and the subsequent retry, if any.
+ Result Step(grpc_exec_ctx* exec_ctx);
+ /// Reset the backoff, so the next grpc_backoff_step will be a
+ /// grpc_backoff_begin.
+ void Reset();
+
+ void SetRandomSeed(unsigned int seed);
+
+ class Options {
+ public:
+ Options& set_initial_backoff(grpc_millis initial_backoff) {
+ initial_backoff_ = initial_backoff;
+ return *this;
+ }
+ Options& set_multiplier(double multiplier) {
+ multiplier_ = multiplier;
+ return *this;
+ }
+ Options& set_jitter(double jitter) {
+ jitter_ = jitter;
+ return *this;
+ }
+ Options& set_min_connect_timeout(grpc_millis min_connect_timeout) {
+ min_connect_timeout_ = min_connect_timeout;
+ return *this;
+ }
+ Options& set_max_backoff(grpc_millis max_backoff) {
+ max_backoff_ = max_backoff;
+ return *this;
+ }
+ /// how long to wait after the first failure before retrying
+ grpc_millis initial_backoff() const { return initial_backoff_; }
+ /// factor with which to multiply backoff after a failed retry
+ double multiplier() const { return multiplier_; }
+ /// amount to randomize backoffs
+ double jitter() const { return jitter_; }
+ /// minimum time between retries
+ grpc_millis min_connect_timeout() const { return min_connect_timeout_; }
+ /// maximum time between retries
+ grpc_millis max_backoff() const { return max_backoff_; }
+
+ private:
+ grpc_millis initial_backoff_;
+ double multiplier_;
+ double jitter_;
+ grpc_millis min_connect_timeout_;
+ grpc_millis max_backoff_;
+ }; // class Options
+
+ struct Result {
+ /// Deadline to be used for the current attempt.
+ grpc_millis current_deadline;
+ /// Deadline to be used for the next attempt, following the backoff
+ /// strategy.
+ grpc_millis next_attempt_start_time;
+ };
+
+ private:
+ const Options options_;
/// current delay before retries
- grpc_millis current_backoff;
-
- /// random number generator
- uint32_t rng_state;
-} grpc_backoff;
-
-typedef struct {
- /// Deadline to be used for the current attempt.
- grpc_millis current_deadline;
-
- /// Deadline to be used for the next attempt, following the backoff strategy.
- grpc_millis next_attempt_start_time;
-} grpc_backoff_result;
-
-/// Initialize backoff machinery - does not need to be destroyed
-void grpc_backoff_init(grpc_backoff* backoff, grpc_millis initial_backoff,
- double multiplier, double jitter,
- grpc_millis min_connect_timeout,
- grpc_millis max_backoff);
-
-/// Begin retry loop: returns the deadlines to be used for the current attempt
-/// and the subsequent retry, if any.
-grpc_backoff_result grpc_backoff_begin(grpc_exec_ctx* exec_ctx,
- grpc_backoff* backoff);
-
-/// Step a retry loop: returns the deadlines to be used for the current attempt
-/// and the subsequent retry, if any.
-grpc_backoff_result grpc_backoff_step(grpc_exec_ctx* exec_ctx,
- grpc_backoff* backoff);
+ grpc_millis current_backoff_;
-/// Reset the backoff, so the next grpc_backoff_step will be a
-/// grpc_backoff_begin.
-void grpc_backoff_reset(grpc_backoff* backoff);
+ unsigned int seed;
+};
-#ifdef __cplusplus
-}
-#endif
+} // namespace grpc_core
#endif /* GRPC_CORE_LIB_BACKOFF_BACKOFF_H */