diff options
author | 2017-11-22 16:31:01 -0800 | |
---|---|---|
committer | 2017-11-22 16:31:01 -0800 | |
commit | dde6afc0c01d2ebac5c5532aaf35e416c72a4245 (patch) | |
tree | c96b87aa0d2250aef8200489b5c1cd7bbbcd1ea1 /src/core/lib/backoff | |
parent | 070a14f0cdf079ecc622bce54d0a58c34fb5ff69 (diff) |
C++-ize backoff
Diffstat (limited to 'src/core/lib/backoff')
-rw-r--r-- | src/core/lib/backoff/backoff.cc | 83 | ||||
-rw-r--r-- | src/core/lib/backoff/backoff.h | 132 |
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 */ |