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

test infrastructure: inject time everywhere #4180

Merged
merged 23 commits into from
Aug 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
da7f24a
Remove singletons for time-sources and inject them instead.
jmarantz Aug 16, 2018
7d59de4
checkpoint with more stuff compiling, a few tests still fail due to c…
jmarantz Aug 16, 2018
10422d4
checkpoinging: all of //test/common/... compiles, 4 tests still fail …
jmarantz Aug 16, 2018
282307f
//test/common/... all pass.
jmarantz Aug 16, 2018
fa5c8c8
More of //test/... builds, some of it works.
jmarantz Aug 17, 2018
8d67f55
All tests compiling and working.
jmarantz Aug 17, 2018
c9a7d62
More comments and TODOs.
jmarantz Aug 17, 2018
2d9f2aa
Pass the TimeSource into the WorkerFactory's ctor rather than into Wo…
jmarantz Aug 17, 2018
1a84061
Fix race found in coverage tests due to order of destruction. Uncomme…
jmarantz Aug 17, 2018
eb2347e
Don't bother using a whole TimeSource for TokenBucketImpl -- all it n…
jmarantz Aug 17, 2018
21ac418
More API cleanups and TODOs.
jmarantz Aug 17, 2018
0a2514c
Kick CI
jmarantz Aug 17, 2018
c642dbc
Merge branch 'master' into inject-time-source
jmarantz Aug 22, 2018
646a500
formatting.
jmarantz Aug 22, 2018
e65a754
Add comment about preserving entropy in the future, when we move to m…
jmarantz Aug 22, 2018
50dbb33
Merge branch 'master' into inject-time-source
jmarantz Aug 22, 2018
be44f2d
Address review comments.
jmarantz Aug 23, 2018
1488d58
Kick CI
jmarantz Aug 23, 2018
44d880d
Merge branch 'master' into inject-time-source
jmarantz Aug 23, 2018
6d9fac6
Rename 'TestTime' to 'RealTestTime' and add TODO to change all tests …
jmarantz Aug 23, 2018
944d75b
Don't copy TimeSource objects; it's easier to make them pure virtual …
jmarantz Aug 24, 2018
28f41dd
Merge branch 'master' into inject-time-source
jmarantz Aug 24, 2018
a285196
Resolve nits.
jmarantz Aug 24, 2018
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
4 changes: 3 additions & 1 deletion include/envoy/api/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <memory>
#include <string>

#include "envoy/common/time.h"
#include "envoy/event/dispatcher.h"
#include "envoy/filesystem/filesystem.h"
#include "envoy/stats/store.h"
Expand All @@ -20,9 +21,10 @@ class Api {

/**
* Allocate a dispatcher.
* @param time_source the time source.
* @return Event::DispatcherPtr which is owned by the caller.
*/
virtual Event::DispatcherPtr allocateDispatcher() PURE;
virtual Event::DispatcherPtr allocateDispatcher(TimeSource& time_source) PURE;

/**
* Create/open a local file that supports async appending.
Expand Down
49 changes: 48 additions & 1 deletion include/envoy/common/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ typedef std::chrono::time_point<std::chrono::steady_clock> MonotonicTime;

/**
* Abstraction for getting the current system time. Useful for testing.
*
* TODO(#4160): eliminate this class and pass TimeSource everywhere.
*/
class SystemTimeSource {
public:
Expand All @@ -28,7 +30,10 @@ class SystemTimeSource {
};

/**
* Abstraction for getting the current monotonically increasing time. Useful for testing.
* Abstraction for getting the current monotonically increasing time. Useful for
* testing.
*
* TODO(#4160): eliminate this class and pass TimeSource everywhere.
*/
class MonotonicTimeSource {
public:
Expand All @@ -39,4 +44,46 @@ class MonotonicTimeSource {
*/
virtual MonotonicTime currentTime() PURE;
};

/**
* Captures a system-time source, capable of computing both monotonically increasing
* and real time.
*
* TODO(#4160): currently this is just a container for SystemTimeSource and
* MonotonicTimeSource but we should clean that up and just have this as the
* base class. Once that's done, TimeSource will be a pure interface.
*/
class TimeSource {
public:
TimeSource(SystemTimeSource& system, MonotonicTimeSource& monotonic)
: system_(system), monotonic_(monotonic) {}

/**
* @return the current system time; not guaranteed to be monotonically increasing.
*/
SystemTime systemTime() { return system_.currentTime(); }

/**
* @return the current monotonic time.
*/
MonotonicTime monotonicTime() { return monotonic_.currentTime(); }

/**
* Compares two time-sources for equality; this is needed for mocks.
*/
bool operator==(const TimeSource& ts) const {
return &system_ == &ts.system_ && &monotonic_ == &ts.monotonic_;
}

// TODO(jmarantz): Eliminate these methods and the SystemTimeSource and MonotonicTimeSource
// classes, and change method calls to work directly off of TimeSource.
SystemTimeSource& system() { return system_; }
MonotonicTimeSource& monotonic() { return monotonic_; }

private:
// These are pointers rather than references in order to support assignment.
SystemTimeSource& system_;
MonotonicTimeSource& monotonic_;
};

} // namespace Envoy
10 changes: 10 additions & 0 deletions include/envoy/event/dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ class Dispatcher {
public:
virtual ~Dispatcher() {}

/**
* Returns a time-source to use with this dispatcher.
*
* TODO(#4160) the implementations currently manage timer events that
* ignore the time-source, and thus can't be mocked or faked. So it's
* difficult to mock time in an integration test without mocking out
* the dispatcher.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the only benefit here then of providing the timeSource() to allow for convenient threading of this object across any object that needs time and already has a dispatcher reference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the only benefit. I think the dispatcher needs to understand time to support timers in a manner consistent with that. I'm just not biting that off in this PR. This interface makes the injection significantly easier in this PR, and will be functionally needed in the future for the dispatcher to work properly with mocked or simulated time.

*/
virtual TimeSource& timeSource() PURE;

/**
* Clear any items in the deferred deletion queue.
*/
Expand Down
9 changes: 8 additions & 1 deletion include/envoy/server/filter_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,16 @@ class FactoryContext {
virtual const envoy::api::v2::core::Metadata& listenerMetadata() const PURE;

/**
* @return SystemTimeSource& a reference to the top-level SystemTime source.
* @return SystemTimeSource& a reference to the system time source.
* TODO(#4160): This method should be eliminated, and call-sites and mocks should
* be converted to work with timeSource() below.
*/
virtual SystemTimeSource& systemTimeSource() PURE;

/**
* @return TimeSource& a reference to the time source.
*/
virtual TimeSource& timeSource() PURE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't this be inferred from dispatcher() above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be, but I feel like it's reasonable from an API perspective that the FilterConfig should provide direct access to its time source, even if the impl delegates that as an implementation detail.

};

class ListenerFactoryContext : public FactoryContext {
Expand Down
5 changes: 5 additions & 0 deletions include/envoy/server/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ class Instance {
*/
virtual const LocalInfo::LocalInfo& localInfo() PURE;

/**
* @return the time source used for the server.
*/
virtual TimeSource& timeSource() PURE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that time is an essential interface property of a server, independent of whether it delegates ownership of the TimeSource itself to the dispatcher.


/**
* @return the flush interval of stats sinks.
*/
Expand Down
5 changes: 5 additions & 0 deletions include/envoy/upstream/cluster_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ class ClusterManager {
addThreadLocalClusterUpdateCallbacks(ClusterUpdateCallbacks& callbacks) PURE;

virtual ClusterManagerFactory& clusterManagerFactory() PURE;

/**
* @return TimeSource& the time-source used with the cluster manager.
*/
virtual TimeSource& timeSource() PURE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is time really an essential property of ClusterManager?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Offhand, I am not an expert in the class; this is the first I've touched it, IIRC.

However, it appears based on its API to care about load-balancing, which I think typically has a time-component implied, no?

From a practical perspective, I need to find a time-source from places that already have a ClusterManager plumbed in and not much else. E.g. AsyncClientImpl

IMO you don't need a lot of excuses to want to know about time. Even a pure algorithm may want to employ timeouts, etc. Something I'm not proud of here is that PerfAnnotation in this PR still needs its own prod time-source, but I can't solve all problems in this PR, and I'm not sure we have a TimeSource available everywhere I might want to measure perf.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AsyncClientImpl should have a dispatcher where it can infer TimeSource. Are there other cases where we need this?

In general, I'm of the persuasion that I agree with what you write above, but that doesn't necessitate making TimeSource a part of the interface. ClusterManagerImpl can take TimeSource as a constructor arg, it doesn't have to be in the business of exporting this out to the rest of the system.

Can you see if it's practical to avoid adding to the interface here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is practical but will enlarge the CL significantly from what I can tell. Can I suggest a compromise where I add a TODO to the interfaces where it doesn't make (IMO) obvious sense (Dispatcher, arguably Server) to remove them when we've got everything plumbed directly?

I think the scary one is filters; I didn't want to change how every filter gets instantiated, preferring instead to provide access to the TimeSource via FilterConfig. Happy to remove that, but it will require changing every filter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per IM I have a follow-up in progress to remove this: jmarantz@b9a9cee

};

typedef std::unique_ptr<ClusterManager> ClusterManagerPtr;
Expand Down
4 changes: 2 additions & 2 deletions source/common/api/api_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
namespace Envoy {
namespace Api {

Event::DispatcherPtr Impl::allocateDispatcher() {
return Event::DispatcherPtr{new Event::DispatcherImpl()};
Event::DispatcherPtr Impl::allocateDispatcher(TimeSource& time_source) {
return Event::DispatcherPtr{new Event::DispatcherImpl(time_source)};
}

Impl::Impl(std::chrono::milliseconds file_flush_interval_msec)
Expand Down
2 changes: 1 addition & 1 deletion source/common/api/api_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Impl : public Api::Api {
Impl(std::chrono::milliseconds file_flush_interval_msec);

// Api::Api
Event::DispatcherPtr allocateDispatcher() override;
Event::DispatcherPtr allocateDispatcher(TimeSource& time_source) override;
Filesystem::FileSharedPtr createFile(const std::string& path, Event::Dispatcher& dispatcher,
Thread::BasicLockable& lock,
Stats::Store& stats_store) override;
Expand Down
5 changes: 2 additions & 3 deletions source/common/common/perf_annotation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@
namespace Envoy {

PerfOperation::PerfOperation()
: start_time_(ProdMonotonicTimeSource::instance_.currentTime()),
context_(PerfAnnotationContext::getOrCreate()) {}
: context_(PerfAnnotationContext::getOrCreate()), start_time_(context_->currentTime()) {}

void PerfOperation::record(absl::string_view category, absl::string_view description) {
const MonotonicTime end_time = ProdMonotonicTimeSource::instance_.currentTime();
const MonotonicTime end_time = context_->currentTime();
const std::chrono::nanoseconds duration =
std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time_);
context_->record(duration, category, description);
Expand Down
6 changes: 5 additions & 1 deletion source/common/common/perf_annotation.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ class PerfAnnotationContext {
void record(std::chrono::nanoseconds duration, absl::string_view category,
absl::string_view description);

/** @return MonotonicTime the current time */
MonotonicTime currentTime() { return time_source_.currentTime(); }

/**
* Renders the aggregated statistics as a string.
* @return std::string the performance data as a formatted string.
Expand Down Expand Up @@ -138,6 +141,7 @@ class PerfAnnotationContext {
#else
DurationStatsMap duration_stats_map_;
#endif
ProdMonotonicTimeSource time_source_;
};

/**
Expand All @@ -162,8 +166,8 @@ class PerfOperation {
void record(absl::string_view category, absl::string_view description);

private:
MonotonicTime start_time_;
PerfAnnotationContext* context_;
MonotonicTime start_time_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: why reordering?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initializing context is needed (from a lazy-init static) prior to computing the start-time.

};

} // namespace Envoy
Expand Down
11 changes: 6 additions & 5 deletions source/common/common/token_bucket_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

namespace Envoy {

TokenBucketImpl::TokenBucketImpl(uint64_t max_tokens, double fill_rate,
MonotonicTimeSource& time_source)
TokenBucketImpl::TokenBucketImpl(uint64_t max_tokens, MonotonicTimeSource& monotonic_time_source,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: why reordering?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because fill_rate is optional, but time-source is not.

double fill_rate)
: max_tokens_(max_tokens), fill_rate_(std::abs(fill_rate)), tokens_(max_tokens),
last_fill_(time_source.currentTime()), time_source_(time_source) {}
last_fill_(monotonic_time_source.currentTime()),
monotonic_time_source_(monotonic_time_source) {}

bool TokenBucketImpl::consume(uint64_t tokens) {
if (tokens_ < max_tokens_) {
const auto time_now = time_source_.currentTime();
const auto time_now = monotonic_time_source_.currentTime();
tokens_ = std::min((std::chrono::duration<double>(time_now - last_fill_).count() * fill_rate_) +
tokens_,
max_tokens_);
Expand All @@ -26,4 +27,4 @@ bool TokenBucketImpl::consume(uint64_t tokens) {
return true;
}

} // namespace Envoy
} // namespace Envoy
8 changes: 4 additions & 4 deletions source/common/common/token_bucket_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ class TokenBucketImpl : public TokenBucket {
public:
/**
* @param max_tokens supplies the maximun number of tokens in the bucket.
* @param time_source supplies the time source.
* @param fill_rate supplies the number of tokens that will return to the bucket on each second.
* The default is 1.
* @param time_source supplies the time source. The default is ProdMonotonicTimeSource.
*/
explicit TokenBucketImpl(uint64_t max_tokens, double fill_rate = 1,
MonotonicTimeSource& time_source = ProdMonotonicTimeSource::instance_);
explicit TokenBucketImpl(uint64_t max_tokens, MonotonicTimeSource& time_source,
double fill_rate = 1);

bool consume(uint64_t tokens = 1) override;

Expand All @@ -28,7 +28,7 @@ class TokenBucketImpl : public TokenBucket {
const double fill_rate_;
double tokens_;
MonotonicTime last_fill_;
MonotonicTimeSource& time_source_;
MonotonicTimeSource& monotonic_time_source_;
};

} // namespace Envoy
3 changes: 0 additions & 3 deletions source/common/common/utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,6 @@ std::string DateFormatter::now() {
return fromTime(current_time_t);
}

ProdSystemTimeSource ProdSystemTimeSource::instance_;
ProdMonotonicTimeSource ProdMonotonicTimeSource::instance_;

ConstMemoryStreamBuffer::ConstMemoryStreamBuffer(const char* data, size_t size) {
// std::streambuf won't modify `data`, but the interface still requires a char* for convenience,
// so we need to const_cast.
Expand Down
4 changes: 0 additions & 4 deletions source/common/common/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ class ProdSystemTimeSource : public SystemTimeSource {
public:
// SystemTimeSource
SystemTime currentTime() override { return std::chrono::system_clock::now(); }

static ProdSystemTimeSource instance_;
};

/**
Expand All @@ -113,8 +111,6 @@ class ProdMonotonicTimeSource : public MonotonicTimeSource {
public:
// MonotonicTimeSource
MonotonicTime currentTime() override { return std::chrono::steady_clock::now(); }

static ProdMonotonicTimeSource instance_;
};

/**
Expand Down
10 changes: 6 additions & 4 deletions source/common/config/grpc_mux_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace Config {
GrpcMuxImpl::GrpcMuxImpl(const LocalInfo::LocalInfo& local_info, Grpc::AsyncClientPtr async_client,
Event::Dispatcher& dispatcher,
const Protobuf::MethodDescriptor& service_method,
Runtime::RandomGenerator& random, MonotonicTimeSource& time_source)
Runtime::RandomGenerator& random)
: local_info_(local_info), async_client_(std::move(async_client)),
service_method_(service_method), random_(random), time_source_(time_source) {
service_method_(service_method), random_(random), time_source_(dispatcher.timeSource()) {
Config::Utility::checkLocalInfo("ads", local_info);
retry_timer_ = dispatcher.createTimer([this]() -> void { establishNewStream(); });
backoff_strategy_ = std::make_unique<JitteredBackOffStrategy>(RETRY_INITIAL_DELAY_MS,
Expand Down Expand Up @@ -111,9 +111,11 @@ GrpcMuxWatchPtr GrpcMuxImpl::subscribe(const std::string& type_url,
// TODO(gsagula): move TokenBucketImpl params to a config.
if (!api_state_[type_url].subscribed_) {
// Bucket contains 100 tokens maximum and refills at 5 tokens/sec.
api_state_[type_url].limit_request_ = std::make_unique<TokenBucketImpl>(100, 5, time_source_);
api_state_[type_url].limit_request_ =
std::make_unique<TokenBucketImpl>(100, time_source_.monotonic(), 5);
// Bucket contains 1 token maximum and refills 1 token on every ~5 seconds.
api_state_[type_url].limit_log_ = std::make_unique<TokenBucketImpl>(1, 0.2, time_source_);
api_state_[type_url].limit_log_ =
std::make_unique<TokenBucketImpl>(1, time_source_.monotonic(), 0.2);
api_state_[type_url].request_.set_type_url(type_url);
api_state_[type_url].request_.mutable_node()->MergeFrom(local_info_.node());
api_state_[type_url].subscribed_ = true;
Expand Down
5 changes: 2 additions & 3 deletions source/common/config/grpc_mux_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ class GrpcMuxImpl : public GrpcMux,
public:
GrpcMuxImpl(const LocalInfo::LocalInfo& local_info, Grpc::AsyncClientPtr async_client,
Event::Dispatcher& dispatcher, const Protobuf::MethodDescriptor& service_method,
Runtime::RandomGenerator& random,
MonotonicTimeSource& time_source = ProdMonotonicTimeSource::instance_);
Runtime::RandomGenerator& random);
~GrpcMuxImpl();

void start() override;
Expand Down Expand Up @@ -104,7 +103,7 @@ class GrpcMuxImpl : public GrpcMux,
std::list<std::string> subscriptions_;
Event::TimerPtr retry_timer_;
Runtime::RandomGenerator& random_;
MonotonicTimeSource& time_source_;
TimeSource time_source_;
BackOffStrategyPtr backoff_strategy_;
};

Expand Down
2 changes: 1 addition & 1 deletion source/common/event/dispatched_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace Event {
*/
class DispatchedThreadImpl : Logger::Loggable<Envoy::Logger::Id::main> {
public:
DispatchedThreadImpl() : dispatcher_(new DispatcherImpl()) {}
DispatchedThreadImpl(TimeSource& time_source) : dispatcher_(new DispatcherImpl(time_source)) {}

/**
* Start the thread.
Expand Down
8 changes: 4 additions & 4 deletions source/common/event/dispatcher_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
namespace Envoy {
namespace Event {

DispatcherImpl::DispatcherImpl()
: DispatcherImpl(Buffer::WatermarkFactoryPtr{new Buffer::WatermarkBufferFactory}) {
DispatcherImpl::DispatcherImpl(TimeSource& time_source)
: DispatcherImpl(time_source, Buffer::WatermarkFactoryPtr{new Buffer::WatermarkBufferFactory}) {
// The dispatcher won't work as expected if libevent hasn't been configured to use threads.
RELEASE_ASSERT(Libevent::Global::initialized(), "");
}

DispatcherImpl::DispatcherImpl(Buffer::WatermarkFactoryPtr&& factory)
: buffer_factory_(std::move(factory)), base_(event_base_new()),
DispatcherImpl::DispatcherImpl(TimeSource& time_source, Buffer::WatermarkFactoryPtr&& factory)
: time_source_(time_source), buffer_factory_(std::move(factory)), base_(event_base_new()),
deferred_delete_timer_(createTimer([this]() -> void { clearDeferredDeleteList(); })),
post_timer_(createTimer([this]() -> void { runPostCallbacks(); })),
current_to_delete_(&to_delete_1_) {
Expand Down
7 changes: 5 additions & 2 deletions source/common/event/dispatcher_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <list>
#include <vector>

#include "envoy/common/time.h"
#include "envoy/event/deferred_deletable.h"
#include "envoy/event/dispatcher.h"
#include "envoy/network/connection_handler.h"
Expand All @@ -21,8 +22,8 @@ namespace Event {
*/
class DispatcherImpl : Logger::Loggable<Logger::Id::main>, public Dispatcher {
public:
DispatcherImpl();
DispatcherImpl(Buffer::WatermarkFactoryPtr&& factory);
explicit DispatcherImpl(TimeSource& time_source);
DispatcherImpl(TimeSource& time_source, Buffer::WatermarkFactoryPtr&& factory);
~DispatcherImpl();

/**
Expand All @@ -31,6 +32,7 @@ class DispatcherImpl : Logger::Loggable<Logger::Id::main>, public Dispatcher {
event_base& base() { return *base_; }

// Event::Dispatcher
TimeSource& timeSource() override { return time_source_; }
void clearDeferredDeleteList() override;
Network::ConnectionPtr
createServerConnection(Network::ConnectionSocketPtr&& socket,
Expand Down Expand Up @@ -66,6 +68,7 @@ class DispatcherImpl : Logger::Loggable<Logger::Id::main>, public Dispatcher {
return run_tid_ == 0 || run_tid_ == Thread::Thread::currentThreadId();
}

TimeSource time_source_;
Thread::ThreadId run_tid_{};
Buffer::WatermarkFactoryPtr buffer_factory_;
Libevent::BasePtr base_;
Expand Down
Loading