aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/backoff
diff options
context:
space:
mode:
authorGravatar Craig Tiller <ctiller@google.com>2017-11-08 09:42:32 -0800
committerGravatar Craig Tiller <ctiller@google.com>2017-11-08 09:42:32 -0800
commit660d4aa2d281dbfbc6c3a3e3349b3e4b6a444285 (patch)
tree592cecc1d6670bb12b9af81c19cd3cb98cc0eeef /src/core/lib/backoff
parent48d26966646e910f7dd63d428ef831178ca9315e (diff)
parentd9da7387b8057f3bd99a417a5ee905377bce9296 (diff)
Merge github.com:grpc/grpc into tfix2
Diffstat (limited to 'src/core/lib/backoff')
-rw-r--r--src/core/lib/backoff/backoff.cc77
-rw-r--r--src/core/lib/backoff/backoff.h57
2 files changed, 79 insertions, 55 deletions
diff --git a/src/core/lib/backoff/backoff.cc b/src/core/lib/backoff/backoff.cc
index fe0a751817..dc754ddd82 100644
--- a/src/core/lib/backoff/backoff.cc
+++ b/src/core/lib/backoff/backoff.cc
@@ -20,54 +20,61 @@
#include <grpc/support/useful.h>
-void grpc_backoff_init(grpc_backoff *backoff,
- grpc_millis initial_connect_timeout, double multiplier,
- double jitter, grpc_millis min_timeout_millis,
- grpc_millis max_timeout_millis) {
- backoff->initial_connect_timeout = initial_connect_timeout;
+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_timeout_millis = min_timeout_millis;
- backoff->max_timeout_millis = max_timeout_millis;
+ backoff->min_connect_timeout = min_connect_timeout;
+ backoff->max_backoff = max_backoff;
backoff->rng_state = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
}
-grpc_millis grpc_backoff_begin(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff) {
- backoff->current_timeout_millis = backoff->initial_connect_timeout;
- const grpc_millis first_timeout =
- GPR_MAX(backoff->current_timeout_millis, backoff->min_timeout_millis);
- return grpc_exec_ctx_now(exec_ctx) + first_timeout;
+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;
}
/* Generate a random number between 0 and 1. */
-static double generate_uniform_random_number(uint32_t *rng_state) {
+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);
}
-grpc_millis grpc_backoff_step(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff) {
- const double new_timeout_millis =
- backoff->multiplier * (double)backoff->current_timeout_millis;
- backoff->current_timeout_millis =
- GPR_MIN((grpc_millis)new_timeout_millis, backoff->max_timeout_millis);
-
- const double jitter_range_width = backoff->jitter * new_timeout_millis;
- const double jitter =
- (2 * generate_uniform_random_number(&backoff->rng_state) - 1) *
- jitter_range_width;
-
- backoff->current_timeout_millis =
- (grpc_millis)((double)(backoff->current_timeout_millis) + jitter);
-
- const grpc_millis current_deadline =
- grpc_exec_ctx_now(exec_ctx) + backoff->current_timeout_millis;
-
- const grpc_millis min_deadline =
- grpc_exec_ctx_now(exec_ctx) + backoff->min_timeout_millis;
+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;
+}
- return GPR_MAX(current_deadline, min_deadline);
+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));
+ 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);
+ const grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+ const grpc_backoff_result result = {now + current_timeout,
+ now + next_timeout};
+ return result;
}
-void grpc_backoff_reset(grpc_backoff *backoff) {
- backoff->current_timeout_millis = backoff->initial_connect_timeout;
+void grpc_backoff_reset(grpc_backoff* backoff) {
+ backoff->current_backoff = backoff->initial_backoff;
}
diff --git a/src/core/lib/backoff/backoff.h b/src/core/lib/backoff/backoff.h
index 80e49ea52a..1067281403 100644
--- a/src/core/lib/backoff/backoff.h
+++ b/src/core/lib/backoff/backoff.h
@@ -27,37 +27,54 @@ extern "C" {
typedef struct {
/// const: how long to wait after the first failure before retrying
- grpc_millis initial_connect_timeout;
+ 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 in milliseconds
- grpc_millis min_timeout_millis;
- /// const: maximum time between retries in milliseconds
- grpc_millis max_timeout_millis;
+
+ /// const: minimum time between retries
+ grpc_millis min_connect_timeout;
+
+ /// const: maximum time between retries
+ grpc_millis max_backoff;
+
+ /// current delay before retries
+ grpc_millis current_backoff;
/// random number generator
uint32_t rng_state;
-
- /// current retry timeout in milliseconds
- grpc_millis current_timeout_millis;
} 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_connect_timeout, double multiplier,
- double jitter, grpc_millis min_timeout_millis,
- grpc_millis max_timeout_millis);
-
-/// Begin retry loop: returns a timespec for the NEXT retry
-grpc_millis grpc_backoff_begin(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff);
-/// Step a retry loop: returns a timespec for the NEXT retry
-grpc_millis grpc_backoff_step(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff);
+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);
+
/// Reset the backoff, so the next grpc_backoff_step will be a
-/// grpc_backoff_begin
-/// instead
-void grpc_backoff_reset(grpc_backoff *backoff);
+/// grpc_backoff_begin.
+void grpc_backoff_reset(grpc_backoff* backoff);
#ifdef __cplusplus
}