Skip to content

Commit

Permalink
overload: create scaled timers via the dispatcher (#14679)
Browse files Browse the repository at this point in the history
Refactor the existing pathway for creating scaled Timer objects away from the
ThreadLocalOverloadState and into the Dispatcher interface. This allows scaled
timers to be created without plumbing through a bunch of extra state.

Signed-off-by: Alex Konradi <akonradi@google.com>
  • Loading branch information
akonradi authored Jan 20, 2021
1 parent e899c7b commit 2562fbb
Show file tree
Hide file tree
Showing 37 changed files with 440 additions and 264 deletions.
1 change: 1 addition & 0 deletions include/envoy/api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ envoy_cc_library(
deps = [
"//include/envoy/common:random_generator_interface",
"//include/envoy/event:dispatcher_interface",
"//include/envoy/event:scaled_range_timer_manager_interface",
"//include/envoy/filesystem:filesystem_interface",
"//include/envoy/server:process_context_interface",
"//include/envoy/thread:thread_interface",
Expand Down
13 changes: 13 additions & 0 deletions include/envoy/api/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "envoy/common/random_generator.h"
#include "envoy/common/time.h"
#include "envoy/event/dispatcher.h"
#include "envoy/event/scaled_range_timer_manager.h"
#include "envoy/filesystem/filesystem.h"
#include "envoy/server/process_context.h"
#include "envoy/stats/store.h"
Expand All @@ -30,6 +31,18 @@ class Api {
*/
virtual Event::DispatcherPtr allocateDispatcher(const std::string& name) PURE;

/**
* Allocate a dispatcher.
* @param name the identity name for a dispatcher, e.g. "worker_2" or "main_thread".
* This name will appear in per-handler/worker statistics, such as
* "server.worker_2.watchdog_miss".
* @param scaled_timer_factory the factory to use when creating the scaled timer manager.
* @return Event::DispatcherPtr which is owned by the caller.
*/
virtual Event::DispatcherPtr
allocateDispatcher(const std::string& name,
const Event::ScaledRangeTimerManagerFactory& scaled_timer_factory) PURE;

/**
* Allocate a dispatcher.
* @param name the identity name for a dispatcher, e.g. "worker_2" or "main_thread".
Expand Down
9 changes: 5 additions & 4 deletions include/envoy/event/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ envoy_cc_library(
deps = [
":deferred_deletable",
":file_event_interface",
":scaled_timer",
":schedulable_cb_interface",
":signal_interface",
":timer_interface",
"//include/envoy/common:scope_tracker_interface",
"//include/envoy/common:time_interface",
"//include/envoy/event:timer_interface",
"//include/envoy/filesystem:watcher_interface",
"//include/envoy/network:connection_handler_interface",
"//include/envoy/network:connection_interface",
Expand All @@ -42,8 +43,8 @@ envoy_cc_library(
)

envoy_cc_library(
name = "scaled_timer_minimum",
hdrs = ["scaled_timer_minimum.h"],
name = "scaled_timer",
hdrs = ["scaled_timer.h"],
deps = [
"//source/common/common:interval_value",
],
Expand All @@ -53,7 +54,7 @@ envoy_cc_library(
name = "scaled_range_timer_manager_interface",
hdrs = ["scaled_range_timer_manager.h"],
deps = [
":scaled_timer_minimum",
":scaled_timer",
":timer_interface",
],
)
Expand Down
15 changes: 15 additions & 0 deletions include/envoy/event/dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "envoy/common/scope_tracker.h"
#include "envoy/common/time.h"
#include "envoy/event/file_event.h"
#include "envoy/event/scaled_timer.h"
#include "envoy/event/schedulable_cb.h"
#include "envoy/event/signal.h"
#include "envoy/event/timer.h"
Expand Down Expand Up @@ -77,6 +78,20 @@ class DispatcherBase {
*/
virtual Event::TimerPtr createTimer(TimerCb cb) PURE;

/**
* Allocates a scaled timer. @see Timer for docs on how to use the timer.
* @param timer_type the type of timer to create.
* @param cb supplies the callback to invoke when the timer fires.
*/
virtual Event::TimerPtr createScaledTimer(Event::ScaledTimerType timer_type, TimerCb cb) PURE;

/**
* Allocates a scaled timer. @see Timer for docs on how to use the timer.
* @param minimum the rule for computing the minimum value of the timer.
* @param cb supplies the callback to invoke when the timer fires.
*/
virtual Event::TimerPtr createScaledTimer(Event::ScaledTimerMinimum minimum, TimerCb cb) PURE;

/**
* Allocates a schedulable callback. @see SchedulableCallback for docs on how to use the wrapped
* callback.
Expand Down
11 changes: 10 additions & 1 deletion include/envoy/event/scaled_range_timer_manager.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "envoy/common/pure.h"
#include "envoy/event/scaled_timer_minimum.h"
#include "envoy/event/scaled_timer.h"
#include "envoy/event/timer.h"

#include "common/common/interval_value.h"
Expand Down Expand Up @@ -30,6 +30,12 @@ class ScaledRangeTimerManager {
*/
virtual TimerPtr createTimer(ScaledTimerMinimum minimum, TimerCb callback) PURE;

/**
* Creates a new timer backed by the manager using the provided timer type to
* determine the minimum.
*/
virtual TimerPtr createTimer(ScaledTimerType timer_type, TimerCb callback) PURE;

/**
* Sets the scale factor for all timers created through this manager. The value should be between
* 0 and 1, inclusive. The scale factor affects the amount of time timers spend in their target
Expand All @@ -43,5 +49,8 @@ class ScaledRangeTimerManager {

using ScaledRangeTimerManagerPtr = std::unique_ptr<ScaledRangeTimerManager>;

class Dispatcher;
using ScaledRangeTimerManagerFactory = std::function<ScaledRangeTimerManagerPtr(Dispatcher&)>;

} // namespace Event
} // namespace Envoy
84 changes: 84 additions & 0 deletions include/envoy/event/scaled_timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#pragma once

#include <chrono>

#include "common/common/interval_value.h"

#include "absl/container/flat_hash_map.h"
#include "absl/types/variant.h"

namespace Envoy {
namespace Event {

/**
* Describes a minimum timer value that is equal to a scale factor applied to the maximum.
*/
struct ScaledMinimum {
explicit constexpr ScaledMinimum(UnitFloat scale_factor) : scale_factor_(scale_factor) {}
inline bool operator==(const ScaledMinimum& other) const {
return other.scale_factor_.value() == scale_factor_.value();
}
const UnitFloat scale_factor_;
};

/**
* Describes a minimum timer value that is an absolute duration.
*/
struct AbsoluteMinimum {
explicit constexpr AbsoluteMinimum(std::chrono::milliseconds value) : value_(value) {}
inline bool operator==(const AbsoluteMinimum& other) const { return other.value_ == value_; }
const std::chrono::milliseconds value_;
};

/**
* Class that describes how to compute a minimum timeout given a maximum timeout value. It wraps
* ScaledMinimum and AbsoluteMinimum and provides a single computeMinimum() method.
*/
class ScaledTimerMinimum {
public:
// Forward arguments to impl_'s constructor.
constexpr ScaledTimerMinimum(AbsoluteMinimum arg) : impl_(arg) {}
constexpr ScaledTimerMinimum(ScaledMinimum arg) : impl_(arg) {}

// Computes the minimum value for a given maximum timeout. If this object was constructed with a
// - ScaledMinimum value:
// the return value is the scale factor applied to the provided maximum.
// - AbsoluteMinimum:
// the return value is that minimum, and the provided maximum is ignored.
std::chrono::milliseconds computeMinimum(std::chrono::milliseconds maximum) const {
struct Visitor {
explicit Visitor(std::chrono::milliseconds value) : value_(value) {}
std::chrono::milliseconds operator()(ScaledMinimum scale_factor) {
return std::chrono::duration_cast<std::chrono::milliseconds>(
scale_factor.scale_factor_.value() * value_);
}
std::chrono::milliseconds operator()(AbsoluteMinimum absolute_value) {
return absolute_value.value_;
}
const std::chrono::milliseconds value_;
};
return absl::visit(Visitor(maximum), impl_);
}

inline bool operator==(const ScaledTimerMinimum& other) const { return impl_ == other.impl_; }

private:
absl::variant<ScaledMinimum, AbsoluteMinimum> impl_;
};

enum class ScaledTimerType {
// Timers created with this type will never be scaled. This should only be used for testing.
UnscaledRealTimerForTest,
// The amount of time an HTTP connection to a downstream client can remain idle (no streams). This
// corresponds to the HTTP_DOWNSTREAM_CONNECTION_IDLE TimerType in overload.proto.
HttpDownstreamIdleConnectionTimeout,
// The amount of time an HTTP stream from a downstream client can remain idle. This corresponds to
// the HTTP_DOWNSTREAM_STREAM_IDLE TimerType in overload.proto.
HttpDownstreamIdleStreamTimeout,
};

using ScaledTimerTypeMap = absl::flat_hash_map<ScaledTimerType, ScaledTimerMinimum>;
using ScaledTimerTypeMapConstSharedPtr = std::shared_ptr<const ScaledTimerTypeMap>;

} // namespace Event
} // namespace Envoy
60 changes: 0 additions & 60 deletions include/envoy/event/scaled_timer_minimum.h

This file was deleted.

2 changes: 1 addition & 1 deletion include/envoy/server/overload/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ envoy_cc_library(
name = "thread_local_overload_state",
hdrs = ["thread_local_overload_state.h"],
deps = [
"//include/envoy/event:scaled_timer_minimum",
"//include/envoy/event:scaled_range_timer_manager_interface",
"//include/envoy/event:timer_interface",
"//include/envoy/thread_local:thread_local_object",
"//source/common/common:interval_value",
Expand Down
6 changes: 6 additions & 0 deletions include/envoy/server/overload/overload_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "envoy/common/pure.h"
#include "envoy/event/dispatcher.h"
#include "envoy/event/scaled_range_timer_manager.h"
#include "envoy/server/overload/thread_local_overload_state.h"

#include "common/singleton/const_singleton.h"
Expand Down Expand Up @@ -69,6 +70,11 @@ class OverloadManager {
* an alternative to registering a callback for overload action state changes.
*/
virtual ThreadLocalOverloadState& getThreadLocalOverloadState() PURE;

/**
* Get a factory for constructing scaled timer managers that respond to overload state.
*/
virtual Event::ScaledRangeTimerManagerFactory scaledTimerFactory() PURE;
};

} // namespace Server
Expand Down
21 changes: 1 addition & 20 deletions include/envoy/server/overload/thread_local_overload_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <string>

#include "envoy/common/pure.h"
#include "envoy/event/scaled_timer_minimum.h"
#include "envoy/event/scaled_range_timer_manager.h"
#include "envoy/event/timer.h"
#include "envoy/thread_local/thread_local_object.h"

Expand Down Expand Up @@ -40,32 +40,13 @@ class OverloadActionState {
*/
using OverloadActionCb = std::function<void(OverloadActionState)>;

enum class OverloadTimerType {
// Timers created with this type will never be scaled. This should only be used for testing.
UnscaledRealTimerForTest,
// The amount of time an HTTP connection to a downstream client can remain idle (no streams). This
// corresponds to the HTTP_DOWNSTREAM_CONNECTION_IDLE TimerType in overload.proto.
HttpDownstreamIdleConnectionTimeout,
// The amount of time an HTTP stream from a downstream client can remain idle. This corresponds to
// the HTTP_DOWNSTREAM_STREAM_IDLE TimerType in overload.proto.
HttpDownstreamIdleStreamTimeout,
};

/**
* Thread-local copy of the state of each configured overload action.
*/
class ThreadLocalOverloadState : public ThreadLocal::ThreadLocalObject {
public:
// Get a thread-local reference to the value for the given action key.
virtual const OverloadActionState& getState(const std::string& action) PURE;

// Get a scaled timer whose minimum corresponds to the configured value for the given timer type.
virtual Event::TimerPtr createScaledTimer(OverloadTimerType timer_type,
Event::TimerCb callback) PURE;

// Get a scaled timer whose minimum is determined by the given scaling rule.
virtual Event::TimerPtr createScaledTimer(Event::ScaledTimerMinimum minimum,
Event::TimerCb callback) PURE;
};

} // namespace Server
Expand Down
7 changes: 7 additions & 0 deletions source/common/api/api_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ Event::DispatcherPtr Impl::allocateDispatcher(const std::string& name) {
return std::make_unique<Event::DispatcherImpl>(name, *this, time_system_, watermark_factory_);
}

Event::DispatcherPtr
Impl::allocateDispatcher(const std::string& name,
const Event::ScaledRangeTimerManagerFactory& scaled_timer_factory) {
return std::make_unique<Event::DispatcherImpl>(name, *this, time_system_, scaled_timer_factory,
watermark_factory_);
}

Event::DispatcherPtr Impl::allocateDispatcher(const std::string& name,
Buffer::WatermarkFactoryPtr&& factory) {
return std::make_unique<Event::DispatcherImpl>(name, *this, time_system_, std::move(factory));
Expand Down
3 changes: 3 additions & 0 deletions source/common/api/api_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class Impl : public Api {

// Api::Api
Event::DispatcherPtr allocateDispatcher(const std::string& name) override;
Event::DispatcherPtr
allocateDispatcher(const std::string& name,
const Event::ScaledRangeTimerManagerFactory& scaled_timer_factory) override;
Event::DispatcherPtr allocateDispatcher(const std::string& name,
Buffer::WatermarkFactoryPtr&& watermark_factory) override;
Thread::ThreadFactory& threadFactory() override { return thread_factory_; }
Expand Down
1 change: 1 addition & 0 deletions source/common/event/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ envoy_cc_library(
":libevent_scheduler_lib",
":real_time_system_lib",
":signal_lib",
":scaled_range_timer_manager_lib",
"//include/envoy/common:scope_tracker_interface",
"//include/envoy/common:time_interface",
"//include/envoy/event:signal_interface",
Expand Down
Loading

0 comments on commit 2562fbb

Please sign in to comment.