Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dispatcher: Run zero-delay timeout timers on the next iteration of the event loop #11823

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d970d84
Run 0ms timeout timers on the next iteration of the event loop instea…
antoniovicente Jun 22, 2020
bdccb5b
Attempt to fix windows tests.
antoniovicente Jul 1, 2020
39abbba
Merge remote-tracking branch 'upstream/master' into activate_0ms_time…
antoniovicente Jul 6, 2020
24d2d71
Merge remote-tracking branch 'upstream/master' into activate_0ms_time…
antoniovicente Jul 7, 2020
0728c73
Merge remote-tracking branch 'upstream/master' into activate_0ms_time…
antoniovicente Jul 10, 2020
ae438b8
Merge remote-tracking branch 'upstream/master' into activate_0ms_time…
antoniovicente Jul 17, 2020
d915c0f
fix format and test
antoniovicente Jul 17, 2020
4e47f7c
Merge remote-tracking branch 'upstream/master' into activate_0ms_time…
antoniovicente Jul 20, 2020
66c95ce
update stats_integration_test
antoniovicente Jul 21, 2020
13b64fc
rollback changes to test, test is flaky upstream.
antoniovicente Jul 21, 2020
15557fa
address review comments
antoniovicente Jul 21, 2020
ecc60a4
Merge remote-tracking branch 'upstream/master' into activate_0ms_time…
antoniovicente Jul 22, 2020
ae6b211
update comment
antoniovicente Jul 23, 2020
dbe5e90
Only read runtime feature if singleton exists
antoniovicente Jul 30, 2020
965b647
Merge remote-tracking branch 'upstream/master' into activate_0ms_time…
antoniovicente Aug 3, 2020
1c46b17
release the simulated time lock before interacting with libevent
antoniovicente Aug 3, 2020
f91674f
remove simulated time ordering invariant checking for simulated timers.
antoniovicente Aug 3, 2020
01cb897
Kick CI
antoniovicente Aug 3, 2020
73abb34
Kick CI
antoniovicente Aug 4, 2020
4b40801
Merge remote-tracking branch 'upstream/master' into activate_0ms_time…
antoniovicente Aug 4, 2020
e8a4cb9
Use advanceLibeventTime instead of absl::Sleep in new test cases.
antoniovicente Aug 4, 2020
55da797
Kick CI
antoniovicente Aug 5, 2020
88fd249
Merge remote-tracking branch 'upstream/master' into activate_0ms_time…
antoniovicente Aug 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/common/event/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ envoy_cc_library(
":libevent_lib",
"//include/envoy/event:timer_interface",
"//source/common/common:scope_tracker",
"//source/common/runtime:runtime_features_lib",
],
)

Expand Down
43 changes: 43 additions & 0 deletions source/common/event/libevent_scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,49 @@ namespace Envoy {
namespace Event {

// Implements Scheduler based on libevent.
//
// Here is a rough summary of operations that libevent performs in each event loop iteration, in
// order. Note that the invocation order for "same-iteration" operations that execute as a group
// can be surprising and invocation order of expired timers is non-deterministic.
antoniovicente marked this conversation as resolved.
Show resolved Hide resolved
// Whenever possible, it is preferable to avoid making event invocation ordering assumptions.
//
// 1. Calculate the poll timeout by comparing the current time to the deadline of the closest
// timer (the one at head of the priority queue).
// 2. Run registered "prepare" callbacks.
// 3. Poll for fd events using the closest timer as timeout, add active fds to the work list.
// 4. Run registered "check" callbacks.
// 5. Check timer deadlines against current time and move expired timers from the timer priority
// queue to the work list. Expired timers are moved to the work list is a non-deterministic order.
antoniovicente marked this conversation as resolved.
Show resolved Hide resolved
// 6. Execute items in the work list until the list is empty. Note that additional work
// items could be added to the work list during execution of this step, more details below.
// 7. Goto 1 if the loop termination condition has not been reached
//
// The following "same-iteration" work items are added directly to the work list when they are
// scheduled so they execute in the current iteration of the event loop. Note that there are no
// ordering guarantees when mixing the mechanisms below. Specifically, it is unsafe to assume that
// calling post followed by deferredDelete will result in the post callback being invoked before the
// deferredDelete; deferredDelete will run first if there is a pending deferredDeletion at the time
// the post callback is scheduled because deferredDelete invocation is grouped.
antoniovicente marked this conversation as resolved.
Show resolved Hide resolved
// - Event::Dispatcher::post(cb). Post callbacks are invoked as a group.
// - Event::Dispatcher::deferredDelete(object) and Event::DeferredTaskUtil::deferredRun(...).
// The same mechanism implements both of these operations, so they are invoked as a group.
// - Event::SchedulableCallback::scheduleCallbackCurrentIteration(). Each of these callbacks is
// scheduled and invoked independently.
// - Event::FileEvent::activate() if "envoy.reloadable_features.activate_fds_next_event_loop"
// runtime feature is disabled.
// - Event::Timer::enableTimer(0) if "envoy.reloadable_features.activate_timers_next_event_loop"
// runtime feature is disabled.
//
// Event::FileEvent::activate and Event::SchedulableCallback::scheduleCallbackNextIteration are
// implemented as libevent timers with a deadline of 0. Both of these actions are moved to the work
// list while checking for expired timers during step 5.
//
// Events execute in the following order, derived from the order in which items were added to the
// work list:
// 0. Events added via event_active prior to the start of the event loop (in tests)
// 1. Fd events
// 2. Timers, FileEvent::activate and SchedulableCallback::scheduleCallbackNextIteration
// 3. "Same-iteration" work items described above, including Event::Dispatcher::post callbacks
class LibeventScheduler : public Scheduler, public CallbackScheduler {
public:
using OnPrepareCallback = std::function<void()>;
Expand Down
8 changes: 6 additions & 2 deletions source/common/event/timer_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
#include <chrono>

#include "common/common/assert.h"
#include "common/runtime/runtime_features.h"

#include "event2/event.h"

namespace Envoy {
namespace Event {

TimerImpl::TimerImpl(Libevent::BasePtr& libevent, TimerCb cb, Dispatcher& dispatcher)
: cb_(cb), dispatcher_(dispatcher) {
: cb_(cb), dispatcher_(dispatcher),
activate_timers_next_event_loop_(Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.activate_timers_next_event_loop")) {
ASSERT(cb_);
evtimer_assign(
&raw_event_, libevent.get(),
Expand Down Expand Up @@ -44,7 +47,8 @@ void TimerImpl::enableHRTimer(const std::chrono::microseconds& d,

void TimerImpl::internalEnableTimer(const timeval& tv, const ScopeTrackedObject* object) {
object_ = object;
if (tv.tv_sec == 0 && tv.tv_usec == 0) {

if (!activate_timers_next_event_loop_ && tv.tv_sec == 0 && tv.tv_usec == 0) {
event_active(&raw_event_, EV_TIMEOUT, 0);
} else {
event_add(&raw_event_, &tv);
Expand Down
5 changes: 5 additions & 0 deletions source/common/event/timer_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ class TimerImpl : public Timer, ImplBase {
// example if the DispatcherImpl::post is called by two threads, they race to
// both set this to null.
std::atomic<const ScopeTrackedObject*> object_{};

// Latched "envoy.reloadable_features.activate_timers_next_event_loop" runtime feature. If true,
// timers scheduled with a 0 time delta are evaluated in the next iteration of the event loop
// after polling and activating new fd events.
const bool activate_timers_next_event_loop_;
};

} // namespace Event
Expand Down
1 change: 1 addition & 0 deletions source/common/runtime/runtime_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ constexpr const char* runtime_features[] = {
"envoy.reloadable_features.connection_header_sanitization",
// Begin alphabetically sorted section.
"envoy.reloadable_features.activate_fds_next_event_loop",
"envoy.reloadable_features.activate_timers_next_event_loop",
"envoy.reloadable_features.allow_500_after_100",
"envoy.deprecated_features.allow_deprecated_extension_names",
"envoy.reloadable_features.consume_all_retry_headers",
Expand Down
3 changes: 2 additions & 1 deletion source/extensions/quic_listeners/quiche/envoy_quic_alarm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ void EnvoyQuicAlarm::SetImpl() {
// loop. QUICHE alarm is not expected to be scheduled in current event loop. This bit is a bummer
// in QUICHE, and we are working on the fix. Once QUICHE is fixed of expecting this behavior, we
// no longer need to round up the duration.
// TODO(antoniovicente) improve the timer behavior in such case.
// TODO(antoniovicente) Remove the std::max(1, ...) when decommissioning the
// envoy.reloadable_features.activate_timers_next_event_loop runtime flag.
timer_->enableHRTimer(
std::chrono::microseconds(std::max(static_cast<int64_t>(1), duration.ToMicroseconds())));
}
Expand Down
1 change: 1 addition & 0 deletions test/common/event/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ envoy_cc_test(
"//test/mocks:common_lib",
"//test/mocks/stats:stats_mocks",
"//test/test_common:simulated_time_system_lib",
"//test/test_common:test_runtime_lib",
"//test/test_common:utility_lib",
],
)
Expand Down
Loading