aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lib')
-rw-r--r--src/core/lib/backoff/backoff.cc83
-rw-r--r--src/core/lib/backoff/backoff.h132
-rw-r--r--src/core/lib/support/alloc_new.h30
3 files changed, 143 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 */
diff --git a/src/core/lib/support/alloc_new.h b/src/core/lib/support/alloc_new.h
new file mode 100644
index 0000000000..314c114cd9
--- /dev/null
+++ b/src/core/lib/support/alloc_new.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_SUPPORT_ALLOC_NEW_H
+#define GRPC_SUPPORT_ALLOC_NEW_H
+
+#include <grpc/support/alloc.h>
+
+#define GPR_NEW(expr) new (gpr_zalloc) expr
+
+inline void* operator new(size_t sz, void* (*alloc_fn)(size_t)) {
+ return alloc_fn(sz);
+}
+
+#endif /* GRPC_SUPPORT_ALLOC_NEW_H */