-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Dispatcher: keeps a stack of tracked objects. #14573
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
Changes from 1 commit
07e671b
918383d
41d85bf
cb43d8a
98d318c
0940f3a
0fe46db
3f8ba3e
265b3a7
3434c7b
7182e95
3885c7a
0724016
be52ed4
984ffc0
e760c57
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,15 +86,18 @@ class DispatcherBase { | |
| virtual Event::SchedulableCallbackPtr createSchedulableCallback(std::function<void()> cb) PURE; | ||
|
|
||
| /** | ||
| * Sets a tracked object, which is currently operating in this Dispatcher. | ||
| * This should be cleared with another call to setTrackedObject() when the object is done doing | ||
| * work. Calling setTrackedObject(nullptr) results in no object being tracked. | ||
| * Appends a tracked object to the current stack of tracked objects operating | ||
| * in the dispatcher. | ||
| * | ||
| * This is optimized for performance, to avoid allocation where we do scoped object tracking. | ||
| * | ||
| * @return The previously tracked object or nullptr if there was none. | ||
| * It's recommended to use ScopeTrackerScopeState to manage the object's tracking. If directly | ||
| * invoking, there needs to be a subsequent call to popTrackedObject(). | ||
| */ | ||
| virtual void appendTrackedObject(const ScopeTrackedObject* object) PURE; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For naming consistency with the stack pattern we are going for, I suggest pushTrackedObject
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
|
|
||
| /** | ||
| * Removes the top of the stack of tracked object and asserts that it was expected. | ||
| */ | ||
| virtual const ScopeTrackedObject* setTrackedObject(const ScopeTrackedObject* object) PURE; | ||
| virtual void popTrackedObject(const ScopeTrackedObject* expected_object) PURE; | ||
|
|
||
| /** | ||
| * Validates that an operation is thread-safe with respect to this dispatcher; i.e. that the | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| #pragma once | ||
|
|
||
| #include <memory> | ||
| #include <vector> | ||
|
|
||
| #include "envoy/common/pure.h" | ||
| #include "envoy/config/bootstrap/v3/bootstrap.pb.h" | ||
|
|
@@ -18,10 +19,9 @@ class FatalAction { | |
| virtual ~FatalAction() = default; | ||
| /** | ||
| * Callback function to run when we are crashing. | ||
| * @param current_object the object we were working on when we started | ||
| * crashing. | ||
| * @param objects a vector of objects we were working on when we started crashing. | ||
|
KBaichoo marked this conversation as resolved.
Outdated
|
||
| */ | ||
| virtual void run(const ScopeTrackedObject* current_object) PURE; | ||
| virtual void run(const std::vector<const ScopeTrackedObject*>& tracked_objects) PURE; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. virtual void run(const absl::Span<const ScopeTrackedObject*>& tracked_objects) PURE; To avoid tieing us to a vector implementation.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea. Done. |
||
|
|
||
| /** | ||
| * @return whether the action is async-signal-safe. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,10 +7,12 @@ | |
| #include <vector> | ||
|
|
||
| #include "envoy/api/api.h" | ||
| #include "envoy/common/scope_tracker.h" | ||
| #include "envoy/network/listen_socket.h" | ||
| #include "envoy/network/listener.h" | ||
|
|
||
| #include "common/buffer/buffer_impl.h" | ||
| #include "common/common/assert.h" | ||
| #include "common/common/lock_guard.h" | ||
| #include "common/common/thread.h" | ||
| #include "common/event/file_event_impl.h" | ||
|
|
@@ -36,6 +38,12 @@ | |
|
|
||
| namespace Envoy { | ||
| namespace Event { | ||
| namespace { | ||
| // Our tracked object stack likely won't grow larger than this initial | ||
|
KBaichoo marked this conversation as resolved.
Outdated
|
||
| // reservation; this should make appends constant time since we shouldn't | ||
| // have to grow the stack larger. | ||
| constexpr size_t ExpectedMaxTrackedObjectStackDepth = 10; | ||
| } // namespace | ||
|
|
||
| DispatcherImpl::DispatcherImpl(const std::string& name, Api::Api& api, | ||
| Event::TimeSystem& time_system, | ||
|
|
@@ -49,6 +57,7 @@ DispatcherImpl::DispatcherImpl(const std::string& name, Api::Api& api, | |
| post_cb_(base_scheduler_.createSchedulableCallback([this]() -> void { runPostCallbacks(); })), | ||
| current_to_delete_(&to_delete_1_) { | ||
| ASSERT(!name_.empty()); | ||
| tracked_object_stack_.reserve(ExpectedMaxTrackedObjectStackDepth); | ||
| FatalErrorHandler::registerFatalErrorHandler(*this); | ||
| updateApproximateMonotonicTimeInternal(); | ||
| base_scheduler_.registerOnPrepareCallback( | ||
|
|
@@ -287,6 +296,16 @@ void DispatcherImpl::runPostCallbacks() { | |
| } | ||
| } | ||
|
|
||
| void DispatcherImpl::onFatalError(std::ostream& os) const { | ||
| // Dump the state of the tracked objects in the dispatcher if thread safe. This generally | ||
| // results in dumping the active state only for the thread which caused the fatal error. | ||
| if (isThreadSafe()) { | ||
| for (auto iter = tracked_object_stack_.rbegin(); iter != tracked_object_stack_.rend(); ++iter) { | ||
| (*iter)->dumpState(os); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test that covers dumping of multiple tracked objects, including relative ordering of the dumps.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| } | ||
| } | ||
| } | ||
|
|
||
| void DispatcherImpl::runFatalActionsOnTrackedObject( | ||
| const FatalAction::FatalActionPtrList& actions) const { | ||
| // Only run if this is the dispatcher of the current thread and | ||
|
|
@@ -296,7 +315,7 @@ void DispatcherImpl::runFatalActionsOnTrackedObject( | |
| } | ||
|
|
||
| for (const auto& action : actions) { | ||
| action->run(current_object_); | ||
| action->run(tracked_object_stack_); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -306,5 +325,22 @@ void DispatcherImpl::touchWatchdog() { | |
| } | ||
| } | ||
|
|
||
| void DispatcherImpl::appendTrackedObject(const ScopeTrackedObject* object) { | ||
| tracked_object_stack_.push_back(object); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| } | ||
|
|
||
| void DispatcherImpl::popTrackedObject(const ScopeTrackedObject* expected_object) { | ||
|
antoniovicente marked this conversation as resolved.
|
||
| if (tracked_object_stack_.empty()) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should probably be
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before on release it'd just end up returning and suppressing, but this is a good point. Done. |
||
| ASSERT(!expected_object, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. Done. |
||
| "Tracked object stack is empty yet we expected a non-null tracked object on the top."); | ||
| return; | ||
| } | ||
|
|
||
| const ScopeTrackedObject* top = tracked_object_stack_.back(); | ||
| tracked_object_stack_.pop_back(); | ||
| ASSERT(top == expected_object, | ||
| "Popped the top of the tracked object stack, but it wasn't the expected object!"); | ||
| } | ||
|
|
||
| } // namespace Event | ||
| } // namespace Envoy | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,25 +74,13 @@ class DispatcherImpl : Logger::Loggable<Logger::Id::main>, | |
| void post(std::function<void()> callback) override; | ||
| void run(RunType type) override; | ||
| Buffer::WatermarkFactory& getWatermarkFactory() override { return *buffer_factory_; } | ||
| const ScopeTrackedObject* setTrackedObject(const ScopeTrackedObject* object) override { | ||
| const ScopeTrackedObject* return_object = current_object_; | ||
| current_object_ = object; | ||
| return return_object; | ||
| } | ||
| void appendTrackedObject(const ScopeTrackedObject* object) override; | ||
| void popTrackedObject(const ScopeTrackedObject* expected_object) override; | ||
| MonotonicTime approximateMonotonicTime() const override; | ||
| void updateApproximateMonotonicTime() override; | ||
|
|
||
| // FatalErrorInterface | ||
| void onFatalError(std::ostream& os) const override { | ||
| // Dump the state of the tracked object if it is in the current thread. This generally results | ||
| // in dumping the active state only for the thread which caused the fatal error. | ||
| if (isThreadSafe()) { | ||
| if (current_object_) { | ||
| current_object_->dumpState(os); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void onFatalError(std::ostream& os) const override; | ||
| void | ||
| runFatalActionsOnTrackedObject(const FatalAction::FatalActionPtrList& actions) const override; | ||
|
|
||
|
|
@@ -150,7 +138,7 @@ class DispatcherImpl : Logger::Loggable<Logger::Id::main>, | |
| std::vector<DeferredDeletablePtr>* current_to_delete_; | ||
| Thread::MutexBasicLockable post_lock_; | ||
| std::list<std::function<void()>> post_callbacks_ ABSL_GUARDED_BY(post_lock_); | ||
| const ScopeTrackedObject* current_object_{}; | ||
| std::vector<const ScopeTrackedObject*> tracked_object_stack_; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. absl::InlineVector?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| bool deferred_deleting_{}; | ||
| MonotonicTime approximate_monotonic_time_; | ||
| WatchdogRegistrationPtr watchdog_registration_; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -535,7 +535,9 @@ TEST_F(DispatcherImplTest, IsThreadSafe) { | |
|
|
||
| class TestFatalAction : public Server::Configuration::FatalAction { | ||
| public: | ||
| void run(const ScopeTrackedObject* /*current_object*/) override { ++times_ran_; } | ||
| void run(const std::vector<const ScopeTrackedObject*>& /*tracked_objects*/) override { | ||
| ++times_ran_; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add some tests that cover 0, 1, >1 entries in tracked_objects ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| } | ||
| bool isAsyncSignalSafe() const override { return true; } | ||
| int getNumTimesRan() { return times_ran_; } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.