• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2016 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/backoff/backoff.h"
22 
23 #include <algorithm>
24 
25 #include "src/core/lib/gpr/useful.h"
26 
27 namespace grpc_core {
28 
29 namespace {
30 
31 /* Generate a random number between 0 and 1. We roll our own RNG because seeding
32  * rand() modifies a global variable we have no control over. */
generate_uniform_random_number(uint32_t * rng_state)33 double generate_uniform_random_number(uint32_t* rng_state) {
34   constexpr uint32_t two_raise_31 = uint32_t(1) << 31;
35   *rng_state = (1103515245 * *rng_state + 12345) % two_raise_31;
36   return *rng_state / static_cast<double>(two_raise_31);
37 }
38 
generate_uniform_random_number_between(uint32_t * rng_state,double a,double b)39 double generate_uniform_random_number_between(uint32_t* rng_state, double a,
40                                               double b) {
41   if (a == b) return a;
42   if (a > b) GPR_SWAP(double, a, b);  // make sure a < b
43   const double range = b - a;
44   return a + generate_uniform_random_number(rng_state) * range;
45 }
46 
47 }  // namespace
48 
BackOff(const Options & options)49 BackOff::BackOff(const Options& options)
50     : options_(options),
51       rng_state_(static_cast<uint32_t>(gpr_now(GPR_CLOCK_REALTIME).tv_nsec)) {
52   Reset();
53 }
54 
NextAttemptTime()55 grpc_millis BackOff::NextAttemptTime() {
56   if (initial_) {
57     initial_ = false;
58     return current_backoff_ + grpc_core::ExecCtx::Get()->Now();
59   }
60   current_backoff_ = static_cast<grpc_millis>(
61       std::min(current_backoff_ * options_.multiplier(),
62                static_cast<double>(options_.max_backoff())));
63   const double jitter = generate_uniform_random_number_between(
64       &rng_state_, -options_.jitter() * current_backoff_,
65       options_.jitter() * current_backoff_);
66   const grpc_millis next_timeout =
67       static_cast<grpc_millis>(current_backoff_ + jitter);
68   return next_timeout + grpc_core::ExecCtx::Get()->Now();
69 }
70 
Reset()71 void BackOff::Reset() {
72   current_backoff_ = options_.initial_backoff();
73   initial_ = true;
74 }
75 
SetRandomSeed(uint32_t seed)76 void BackOff::SetRandomSeed(uint32_t seed) { rng_state_ = seed; }
77 
78 }  // namespace grpc_core
79