-
Notifications
You must be signed in to change notification settings - Fork 85
python: keep stream and engine alive for callbacks #1379
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 2 commits
3b7f3e7
0b50c2f
c2f38d9
eb31f6f
c9d2f8e
e4b383e
b60f955
7587157
a8e1c5c
e01d9be
e5cdc91
ebe61a8
6f2076a
d2c5d41
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 |
|---|---|---|
|
|
@@ -6,52 +6,26 @@ | |
| namespace Envoy { | ||
| namespace Platform { | ||
|
|
||
| namespace { | ||
|
|
||
| void c_on_engine_running(void* context) { | ||
| EngineCallbacks* engine_callbacks = static_cast<EngineCallbacks*>(context); | ||
| engine_callbacks->on_engine_running(); | ||
| } | ||
|
|
||
| void c_on_exit(void* context) { | ||
| // NOTE: this function is intentionally empty | ||
| // as we don't actually do any post-processing on exit. | ||
| (void)context; | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| Engine::Engine(envoy_engine_t engine, const std::string& configuration, LogLevel log_level, | ||
| EngineCallbacksSharedPtr callbacks) | ||
| : engine_(engine), callbacks_(callbacks), terminated_(false) { | ||
| envoy_engine_callbacks envoy_callbacks{ | ||
| .on_engine_running = &c_on_engine_running, | ||
| .on_exit = &c_on_exit, | ||
| .context = this->callbacks_.get(), | ||
| }; | ||
|
|
||
| envoy_logger null_logger{ | ||
| .log = nullptr, | ||
| .release = envoy_noop_release, | ||
| .context = nullptr, | ||
| }; | ||
|
|
||
| run_engine(this->engine_, envoy_callbacks, null_logger, configuration.c_str(), | ||
| log_level_to_string(log_level).c_str()); | ||
|
|
||
| this->stream_client_ = std::make_shared<StreamClient>(this->engine_); | ||
| this->pulse_client_ = std::make_shared<PulseClient>(); | ||
| Engine::Engine(envoy_engine_t engine) : engine_(engine), terminated_(false) {} | ||
|
|
||
| // we lazily construct the stream and pulse clients | ||
| // because they either require or will require a weak ptr | ||
| // which can't be provided from inside of the constructor | ||
| // because of how std::enable_shared_from_this works | ||
| StreamClientSharedPtr Engine::stream_client() { | ||
| if (!this->stream_client_) { | ||
| this->stream_client_ = std::make_shared<StreamClient>(this->weak_from_this()); | ||
|
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. I think StreamClient should probably take a shared reference to the Engine rather than a weak one. We made stats weak so that all the stats objects that might be distributed around a program wouldn't all be retaining the engine... but then again, it's up for debate whether they should be, as well.
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. (Also FWIW, it does effectively take a shared ref in the other platforms.)
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. This is a weak ptr to avoid a cycle ( I can address this comment along with the earlier comment at the same time, I think, by just removing the |
||
| } | ||
| return this->stream_client_; | ||
| } | ||
|
|
||
| Engine::~Engine() { | ||
| if (!this->terminated_) { | ||
| terminate_engine(this->engine_); | ||
| PulseClientSharedPtr Engine::pulse_client() { | ||
| if (!this->pulse_client_) { | ||
| this->pulse_client_ = std::make_shared<PulseClient>(); | ||
| } | ||
| return this->pulse_client_; | ||
| } | ||
|
|
||
| StreamClientSharedPtr Engine::stream_client() { return this->stream_client_; } | ||
| PulseClientSharedPtr Engine::pulse_client() { return this->pulse_client_; } | ||
|
|
||
| void Engine::terminate() { | ||
| if (this->terminated_) { | ||
| throw std::runtime_error("attempting to double terminate Engine"); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,7 @@ EngineBuilder::EngineBuilder() : EngineBuilder(std::string(config_template)) {} | |
|
|
||
| EngineBuilder& EngineBuilder::add_log_level(LogLevel log_level) { | ||
| this->log_level_ = log_level; | ||
| this->callbacks_ = std::make_shared<EngineCallbacks>(); | ||
| this->callbacks_ = std::make_unique<EngineCallbacks>(); | ||
| return *this; | ||
| } | ||
|
|
||
|
|
@@ -89,8 +89,23 @@ EngineSharedPtr EngineBuilder::build() { | |
| } | ||
| } | ||
|
|
||
| Engine* engine = new Engine(init_engine(), config_str, this->log_level_, this->callbacks_); | ||
| return EngineSharedPtr(engine); | ||
| auto envoy_engine = init_engine(); | ||
| Engine* engine = new Engine(envoy_engine); | ||
| auto engine_ptr = EngineSharedPtr(engine); | ||
|
|
||
| auto callbacks = this->callbacks_.release(); | ||
| callbacks->parent = engine_ptr; | ||
|
|
||
| envoy_logger null_logger{ | ||
| .log = nullptr, | ||
| .release = envoy_noop_release, | ||
| .context = nullptr, | ||
| }; | ||
|
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. Would need to verify, but by convention, it should be safe to simply calloc this (or any other envoy mobile struct) if you're not going to use it. |
||
|
|
||
| run_engine(envoy_engine, callbacks->as_envoy_engine_callbacks(), null_logger, config_str.c_str(), | ||
| log_level_to_string(this->log_level_).c_str()); | ||
|
|
||
| return engine_ptr; | ||
| } | ||
|
|
||
| } // namespace Platform | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| #include "engine_callbacks.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Platform { | ||
|
|
||
| namespace { | ||
|
|
||
| void c_on_engine_running(void* context) { | ||
| EngineCallbacks* engine_callbacks = static_cast<EngineCallbacks*>(context); | ||
| engine_callbacks->on_engine_running(); | ||
| } | ||
|
|
||
| void c_on_exit(void* context) { | ||
| EngineCallbacks* engine_callbacks = static_cast<EngineCallbacks*>(context); | ||
| delete engine_callbacks; | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| envoy_engine_callbacks EngineCallbacks::as_envoy_engine_callbacks() { | ||
| return envoy_engine_callbacks{ | ||
| .on_engine_running = &c_on_engine_running, | ||
| .on_exit = &c_on_exit, | ||
| .context = this, | ||
| }; | ||
| } | ||
|
|
||
| } // namespace Platform | ||
| } // namespace Envoy |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #pragma once | ||
|
|
||
| #include <functional> | ||
|
|
||
| #include "engine.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Platform { | ||
|
|
||
| struct EngineCallbacks { | ||
| std::function<void()> on_engine_running; | ||
| // unused: | ||
| // std::function<void()> on_exit; | ||
|
|
||
| envoy_engine_callbacks as_envoy_engine_callbacks(); | ||
|
|
||
| EngineSharedPtr parent; | ||
| }; | ||
|
|
||
| using EngineCallbacksPtr = std::unique_ptr<EngineCallbacks>; | ||
|
|
||
| } // namespace Platform | ||
| } // namespace Envoy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like it's not going to be thread-safe. If we need to use lazy clients, we should maybe just create a new one every time someone asks for one. It's not an especially heavyweight object anyways.