Skip to content

Commit a376d36

Browse files
authored
refactor: use unitfloat in more places (envoyproxy#14396)
Commit Message: Use UnitFloat in place of float in more locations Additional Description: UnitFloat represents a floating point value that is guaranteed to be in the range [0, 1]. Use it in place of floats that also have the same expectation in OverloadActionState and connection listeners. This PR introduces no functional changes. Risk Level: low Testing: ran affected tests Docs Changes: n/a Release Notes: n/a Platform Specific Features: n/a Signed-off-by: Alex Konradi <[email protected]>
1 parent ad7d36f commit a376d36

25 files changed

+102
-58
lines changed

include/envoy/common/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ envoy_cc_library(
3838
envoy_cc_library(
3939
name = "random_generator_interface",
4040
hdrs = ["random_generator.h"],
41+
deps = ["//source/common/common:interval_value"],
4142
)
4243

4344
envoy_cc_library(

include/envoy/common/random_generator.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#include "envoy/common/pure.h"
88

9+
#include "common/common/interval_value.h"
10+
911
namespace Envoy {
1012
namespace Random {
1113

@@ -50,13 +52,13 @@ class RandomGenerator {
5052
/**
5153
* @return a random boolean value, with probability `p` equaling true.
5254
*/
53-
bool bernoulli(float p) {
54-
if (p <= 0) {
55+
bool bernoulli(UnitFloat p) {
56+
if (p == UnitFloat::min()) {
5557
return false;
56-
} else if (p >= 1) {
58+
} else if (p == UnitFloat::max()) {
5759
return true;
5860
}
59-
return random() < static_cast<result_type>(p * static_cast<float>(max()));
61+
return random() < static_cast<result_type>(p.value() * static_cast<float>(max()));
6062
}
6163
};
6264

include/envoy/event/scaled_range_timer_manager.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "envoy/event/scaled_timer_minimum.h"
55
#include "envoy/event/timer.h"
66

7+
#include "common/common/interval_value.h"
8+
79
#include "absl/types/variant.h"
810

911
namespace Envoy {
@@ -36,7 +38,7 @@ class ScaledRangeTimerManager {
3638
* factor of 0.5 causes firing halfway between min and max, and a factor of 1 causes firing at
3739
* max.
3840
*/
39-
virtual void setScaleFactor(double scale_factor) PURE;
41+
virtual void setScaleFactor(UnitFloat scale_factor) PURE;
4042
};
4143

4244
using ScaledRangeTimerManagerPtr = std::unique_ptr<ScaledRangeTimerManager>;

include/envoy/network/BUILD

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ envoy_cc_library(
3838
":listen_socket_interface",
3939
":listener_interface",
4040
"//include/envoy/ssl:context_interface",
41+
"//source/common/common:interval_value",
4142
],
4243
)
4344

@@ -173,6 +174,7 @@ envoy_cc_library(
173174
"//include/envoy/common:resource_interface",
174175
"//include/envoy/init:manager_interface",
175176
"//include/envoy/stats:stats_interface",
177+
"//source/common/common:interval_value",
176178
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
177179
],
178180
)

include/envoy/network/connection_handler.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include "envoy/network/listener.h"
1010
#include "envoy/ssl/context.h"
1111

12+
#include "common/common/interval_value.h"
13+
1214
namespace Envoy {
1315
namespace Network {
1416

@@ -98,7 +100,7 @@ class ConnectionHandler {
98100
* Set the fraction of connections the listeners should reject.
99101
* @param reject_fraction a value between 0 (reject none) and 1 (reject all).
100102
*/
101-
virtual void setListenerRejectFraction(float reject_fraction) PURE;
103+
virtual void setListenerRejectFraction(UnitFloat reject_fraction) PURE;
102104

103105
/**
104106
* @return the stat prefix used for per-handler stats.

include/envoy/network/listener.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "envoy/network/udp_packet_writer_handler.h"
1717
#include "envoy/stats/scope.h"
1818

19+
#include "common/common/interval_value.h"
20+
1921
namespace Envoy {
2022
namespace Network {
2123

@@ -332,7 +334,7 @@ class Listener {
332334
* Set the fraction of incoming connections that will be closed immediately
333335
* after being opened.
334336
*/
335-
virtual void setRejectFraction(float reject_fraction) PURE;
337+
virtual void setRejectFraction(UnitFloat reject_fraction) PURE;
336338
};
337339

338340
using ListenerPtr = std::unique_ptr<Listener>;

include/envoy/server/overload/thread_local_overload_state.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class OverloadActionState {
2828

2929
explicit constexpr OverloadActionState(UnitFloat value) : action_value_(value) {}
3030

31-
float value() const { return action_value_.value(); }
31+
UnitFloat value() const { return action_value_; }
3232
bool isSaturated() const { return action_value_.value() == UnitFloat::max().value(); }
3333

3434
private:

source/common/common/interval_value.h

+20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@ template <typename T, typename Interval> class ClosedIntervalValue {
2222

2323
T value() const { return value_; }
2424

25+
// Returns a value that is as far from max as the original value is from min.
26+
// This guarantees that max().invert() == min() and min().invert() == max().
27+
ClosedIntervalValue invert() const {
28+
return ClosedIntervalValue(value_ == Interval::max_value
29+
? Interval::min_value
30+
: value_ == Interval::min_value
31+
? Interval::max_value
32+
: Interval::max_value - (value_ - Interval::min_value));
33+
}
34+
35+
// Comparisons are performed using the same operators on the underlying value
36+
// type, with the same exactness guarantees.
37+
38+
bool operator==(ClosedIntervalValue<T, Interval> other) const { return value_ == other.value(); }
39+
bool operator!=(ClosedIntervalValue<T, Interval> other) const { return value_ != other.value(); }
40+
bool operator<(ClosedIntervalValue<T, Interval> other) const { return value_ < other.value(); }
41+
bool operator<=(ClosedIntervalValue<T, Interval> other) const { return value_ <= other.value(); }
42+
bool operator>=(ClosedIntervalValue<T, Interval> other) const { return value_ >= other.value(); }
43+
bool operator>(ClosedIntervalValue<T, Interval> other) const { return value_ > other.value(); }
44+
2545
private:
2646
T value_;
2747
};

source/common/event/scaled_range_timer_manager_impl.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ TimerPtr ScaledRangeTimerManagerImpl::createTimer(ScaledTimerMinimum minimum, Ti
150150
return std::make_unique<RangeTimerImpl>(minimum, callback, *this);
151151
}
152152

153-
void ScaledRangeTimerManagerImpl::setScaleFactor(double scale_factor) {
153+
void ScaledRangeTimerManagerImpl::setScaleFactor(UnitFloat scale_factor) {
154154
const MonotonicTime now = dispatcher_.approximateMonotonicTime();
155-
scale_factor_ = UnitFloat(scale_factor);
155+
scale_factor_ = scale_factor;
156156
for (auto& queue : queues_) {
157157
resetQueueTimer(*queue, now);
158158
}

source/common/event/scaled_range_timer_manager_impl.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#pragma once
2+
13
#include <chrono>
24
#include <stack>
35

@@ -26,7 +28,7 @@ class ScaledRangeTimerManagerImpl : public ScaledRangeTimerManager {
2628

2729
// ScaledRangeTimerManager impl
2830
TimerPtr createTimer(ScaledTimerMinimum minimum, TimerCb callback) override;
29-
void setScaleFactor(double scale_factor) override;
31+
void setScaleFactor(UnitFloat scale_factor) override;
3032

3133
private:
3234
class RangeTimerImpl;

source/common/network/tcp_listener_impl.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ void TcpListenerImpl::enable() { socket_->ioHandle().enableFileEvents(Event::Fil
124124

125125
void TcpListenerImpl::disable() { socket_->ioHandle().enableFileEvents(0); }
126126

127-
void TcpListenerImpl::setRejectFraction(const float reject_fraction) {
128-
ASSERT(0 <= reject_fraction && reject_fraction <= 1);
127+
void TcpListenerImpl::setRejectFraction(const UnitFloat reject_fraction) {
129128
reject_fraction_ = reject_fraction;
130129
}
131130

source/common/network/tcp_listener_impl.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include "envoy/common/random_generator.h"
44
#include "envoy/runtime/runtime.h"
55

6+
#include "common/common/interval_value.h"
7+
68
#include "absl/strings/string_view.h"
79
#include "base_listener_impl.h"
810

@@ -20,7 +22,7 @@ class TcpListenerImpl : public BaseListenerImpl {
2022
~TcpListenerImpl() override { socket_->ioHandle().resetFileEvents(); }
2123
void disable() override;
2224
void enable() override;
23-
void setRejectFraction(float reject_fraction) override;
25+
void setRejectFraction(UnitFloat reject_fraction) override;
2426

2527
static const absl::string_view GlobalMaxCxRuntimeKey;
2628

@@ -38,7 +40,7 @@ class TcpListenerImpl : public BaseListenerImpl {
3840
static bool rejectCxOverGlobalLimit();
3941

4042
Random::RandomGenerator& random_;
41-
float reject_fraction_;
43+
UnitFloat reject_fraction_;
4244
};
4345

4446
} // namespace Network

source/common/network/udp_listener_impl.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class UdpListenerImpl : public BaseListenerImpl,
3030
// Network::Listener Interface
3131
void disable() override;
3232
void enable() override;
33-
void setRejectFraction(float) override {}
33+
void setRejectFraction(UnitFloat) override {}
3434

3535
// Network::UdpListener Interface
3636
Event::Dispatcher& dispatcher() override;

source/server/connection_handler_impl.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ void ConnectionHandlerImpl::enableListeners() {
153153
}
154154
}
155155

156-
void ConnectionHandlerImpl::setListenerRejectFraction(float reject_fraction) {
156+
void ConnectionHandlerImpl::setListenerRejectFraction(UnitFloat reject_fraction) {
157157
listener_reject_fraction_ = reject_fraction;
158158
for (auto& listener : listeners_) {
159159
listener.second.listener_->listener()->setRejectFraction(reject_fraction);

source/server/connection_handler_impl.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler,
8383
void stopListeners() override;
8484
void disableListeners() override;
8585
void enableListeners() override;
86-
void setListenerRejectFraction(float reject_fraction) override;
86+
void setListenerRejectFraction(UnitFloat reject_fraction) override;
8787
const std::string& statPrefix() const override { return per_handler_stat_prefix_; }
8888

8989
/**
@@ -361,7 +361,7 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler,
361361
std::list<std::pair<Network::Address::InstanceConstSharedPtr, ActiveListenerDetails>> listeners_;
362362
std::atomic<uint64_t> num_handler_connections_{};
363363
bool disable_listeners_;
364-
float listener_reject_fraction_{0};
364+
UnitFloat listener_reject_fraction_{UnitFloat::min()};
365365
};
366366

367367
class ActiveUdpListenerBase : public ConnectionHandlerImpl::ActiveListenerImplBase,

source/server/overload_manager_impl.cc

+11-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ class ThreadLocalOverloadStateImpl : public ThreadLocalOverloadState {
6060
void setState(NamedOverloadActionSymbolTable::Symbol action, OverloadActionState state) {
6161
actions_[action.index()] = state;
6262
if (scaled_timer_action_.has_value() && scaled_timer_action_.value() == action) {
63-
scaled_timer_manager_->setScaleFactor(1 - state.value());
63+
scaled_timer_manager_->setScaleFactor(
64+
// The action state is 0 for no overload up to 1 for maximal overload,
65+
// but the scale factor for timers is 1 for no scaling and 0 for
66+
// maximal scaling, so invert the value to pass in (1-value).
67+
state.value().invert());
6468
}
6569
}
6670

@@ -86,6 +90,8 @@ class ThresholdTriggerImpl final : public OverloadAction::Trigger {
8690
const OverloadActionState state = actionState();
8791
state_ =
8892
value >= threshold_ ? OverloadActionState::saturated() : OverloadActionState::inactive();
93+
// This is a floating point comparison, though state_ is always either
94+
// saturated or inactive so there's no risk due to floating point precision.
8995
return state.value() != actionState().value();
9096
}
9197

@@ -117,6 +123,9 @@ class ScaledTriggerImpl final : public OverloadAction::Trigger {
117123
state_ = OverloadActionState(
118124
UnitFloat((value - scaling_threshold_) / (saturated_threshold_ - scaling_threshold_)));
119125
}
126+
// All values of state_ are produced via this same code path. Even if
127+
// old_state and state_ should be approximately equal, there's no harm in
128+
// signaling for a small change if they're not float::operator== equal.
120129
return state_.value() != old_state.value();
121130
}
122131

@@ -258,7 +267,7 @@ bool OverloadAction::updateResourcePressure(const std::string& name, double pres
258267
}
259268
const auto trigger_new_state = it->second->actionState();
260269
active_gauge_.set(trigger_new_state.isSaturated() ? 1 : 0);
261-
scale_percent_gauge_.set(trigger_new_state.value() * 100);
270+
scale_percent_gauge_.set(trigger_new_state.value().value() * 100);
262271

263272
{
264273
// Compute the new state as the maximum over all trigger states.

source/server/worker_impl.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ void WorkerImpl::stopAcceptingConnectionsCb(OverloadActionState state) {
152152
}
153153

154154
void WorkerImpl::rejectIncomingConnectionsCb(OverloadActionState state) {
155-
handler_->setListenerRejectFraction(static_cast<float>(state.value()));
155+
handler_->setListenerRejectFraction(state.value());
156156
}
157157

158158
} // namespace Server

test/common/common/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ envoy_cc_test(
196196
name = "random_generator_test",
197197
srcs = ["random_generator_test.cc"],
198198
deps = [
199+
"//source/common/common:interval_value",
199200
"//source/common/common:random_generator_lib",
200201
"//test/mocks/runtime:runtime_mocks",
201202
"//test/test_common:environment_lib",

test/common/common/random_generator_test.cc

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <numeric>
22

3+
#include "common/common/interval_value.h"
34
#include "common/common/random_generator.h"
45

56
#include "gmock/gmock.h"
@@ -70,15 +71,13 @@ TEST(UUID, SanityCheckOfUniqueness) {
7071
TEST(Random, Bernoilli) {
7172
Random::RandomGeneratorImpl random;
7273

73-
EXPECT_FALSE(random.bernoulli(0));
74-
EXPECT_FALSE(random.bernoulli(-1));
75-
EXPECT_TRUE(random.bernoulli(1));
76-
EXPECT_TRUE(random.bernoulli(2));
74+
EXPECT_FALSE(random.bernoulli(UnitFloat(0.0f)));
75+
EXPECT_TRUE(random.bernoulli(UnitFloat(1.0f)));
7776

7877
int true_count = 0;
7978
static const auto num_rolls = 100000;
8079
for (size_t i = 0; i < num_rolls; ++i) {
81-
if (random.bernoulli(0.4)) {
80+
if (random.bernoulli(UnitFloat(0.4f))) {
8281
++true_count;
8382
}
8483
}

0 commit comments

Comments
 (0)