1 /*
2 Copyright (c) DataStax, Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 #include "reconnection_policy.hpp"
18 #include "utils.hpp"
19
20 #include <algorithm>
21 #include <limits>
22
23 using namespace datastax::internal::core;
24
25 namespace datastax { namespace internal { namespace core {
26
calculate_max_attempts(uint64_t base_delay_ms)27 unsigned calculate_max_attempts(uint64_t base_delay_ms) {
28 assert(base_delay_ms > 0 && "Base delay cannot be zero");
29 return 63u - num_leading_zeros(std::numeric_limits<uint64_t>::max() / base_delay_ms);
30 }
31
~ReconnectionSchedule()32 ReconnectionSchedule::~ReconnectionSchedule() {}
33
ReconnectionPolicy(Type type)34 ReconnectionPolicy::ReconnectionPolicy(Type type)
35 : type_(type) {}
36
~ReconnectionPolicy()37 ReconnectionPolicy::~ReconnectionPolicy() {}
38
type() const39 ReconnectionPolicy::Type ReconnectionPolicy::type() const { return type_; }
40
ConstantReconnectionPolicy(uint64_t delay_ms)41 ConstantReconnectionPolicy::ConstantReconnectionPolicy(uint64_t delay_ms)
42 : ReconnectionPolicy(CONSTANT)
43 , delay_ms_(delay_ms) {}
44
delay_ms() const45 uint64_t ConstantReconnectionPolicy::delay_ms() const { return delay_ms_; }
46
name() const47 const char* ConstantReconnectionPolicy::name() const { return "constant"; }
48
new_reconnection_schedule()49 ReconnectionSchedule* ConstantReconnectionPolicy::new_reconnection_schedule() {
50 return new ConstantReconnectionSchedule(delay_ms_);
51 }
52
ConstantReconnectionSchedule(uint64_t delay_ms)53 ConstantReconnectionSchedule::ConstantReconnectionSchedule(uint64_t delay_ms)
54 : delay_ms_(delay_ms) {}
55
next_delay_ms()56 uint64_t ConstantReconnectionSchedule::next_delay_ms() { return delay_ms_; }
57
ExponentialReconnectionPolicy(uint64_t base_delay_ms,uint64_t max_delay_ms)58 ExponentialReconnectionPolicy::ExponentialReconnectionPolicy(uint64_t base_delay_ms,
59 uint64_t max_delay_ms)
60 : ReconnectionPolicy(EXPONENTIAL)
61 , base_delay_ms_(base_delay_ms)
62 , max_delay_ms_(max_delay_ms)
63 , max_attempts_(calculate_max_attempts(base_delay_ms)) {}
64
base_delay_ms() const65 uint64_t ExponentialReconnectionPolicy::base_delay_ms() const { return base_delay_ms_; }
66
max_delay_ms() const67 uint64_t ExponentialReconnectionPolicy::max_delay_ms() const { return max_delay_ms_; }
68
name() const69 const char* ExponentialReconnectionPolicy::name() const { return "exponential"; }
70
new_reconnection_schedule()71 ReconnectionSchedule* ExponentialReconnectionPolicy::new_reconnection_schedule() {
72 return new ExponentialReconnectionSchedule(base_delay_ms_, max_delay_ms_, max_attempts_,
73 &random_);
74 }
75
ExponentialReconnectionSchedule(uint64_t base_delay_ms,uint64_t max_delay_ms,unsigned max_attempts,Random * random)76 ExponentialReconnectionSchedule::ExponentialReconnectionSchedule(uint64_t base_delay_ms,
77 uint64_t max_delay_ms,
78 unsigned max_attempts,
79 Random* random)
80 : base_delay_ms_(base_delay_ms)
81 , max_delay_ms_(max_delay_ms)
82 , max_attempts_(max_attempts)
83 , attempt_(0)
84 , random_(random) {}
85
next_delay_ms()86 uint64_t ExponentialReconnectionSchedule::next_delay_ms() {
87 uint64_t delay_ms = max_delay_ms_;
88 if (attempt_ <= max_attempts_) {
89 // Calculate the delay and add +/- 15% jitter
90 delay_ms = std::min(base_delay_ms_ * (static_cast<uint64_t>(1) << attempt_++), max_delay_ms_);
91 uint64_t jitter = random_->next(30) + 85; // 85 - 115 range
92 delay_ms = (jitter * delay_ms) / 100;
93
94 // Ensure the delay is not less than the base and not greater than the max delay
95 delay_ms = std::min(std::max(base_delay_ms_, delay_ms), max_delay_ms_);
96 assert(delay_ms > 0);
97 }
98 return delay_ms;
99 }
100
101 }}} // namespace datastax::internal::core
102