-
Notifications
You must be signed in to change notification settings - Fork 577
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
HttpServerConnection: Don't spawn useless coroutines #10214
base: master
Are you sure you want to change the base?
Conversation
f953b42
to
03cac8d
Compare
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.
The purpose of Atomic<> is not mixing atomic ops with not-atomic ones, including construction.
lib/remote/httpserverconnection.hpp
Outdated
|
||
private: | ||
ApiUser::Ptr m_ApiUser; | ||
Shared<AsioTlsStream>::Ptr m_Stream; | ||
double m_Seen; | ||
String m_PeerAddress; | ||
boost::asio::io_context::strand m_IoStrand; | ||
bool m_ShuttingDown; | ||
std::atomic<bool> m_ShuttingDown; |
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.
std::atomic<bool> m_ShuttingDown; | |
Atomic<bool> m_ShuttingDown; |
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.
As @julianbrost pointed out #10214 (comment), just using the default constructor of std::atomic
is problematic. Atomic
has no default constructor which enforces not (accidentally) using it (now and in future) at compile time (since #10215 🙈).
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.
Are you serious? I can't even believe we're still talking about this now.
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 is C++. If we can easily enforce something at compile time, we do it.
Honestly, this class is just useless and I don't even understand why it is there in the first place. If |
And it provides And that's utilized by |
Are you sure about that? https://en.cppreference.com/w/cpp/atomic/atomic/atomic:
If that was indeed a problem, wouldn't this imply that |
Damn!
No. As I said, (admittedly after
In the first place I think, the cost of
|
Can you please explain in a human readable way and not cryptically nor with a bunch of abbreviations what purpose you are trying to cover by using
No, I'm not going to do any of that. I haven't reviewed the PR it was introduced with, so it has nothing to do with this one, apart from the fact that I don't want to make use of it.
icinga2/lib/remote/jsonrpcconnection.cpp Line 42 in d894792
|
lib/remote/httpserverconnection.hpp
Outdated
|
||
private: | ||
ApiUser::Ptr m_ApiUser; | ||
Shared<AsioTlsStream>::Ptr m_Stream; | ||
double m_Seen; | ||
String m_PeerAddress; | ||
boost::asio::io_context::strand m_IoStrand; | ||
bool m_ShuttingDown; | ||
std::atomic<bool> m_ShuttingDown; |
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.
As @julianbrost pointed out #10214 (comment), just using the default constructor of std::atomic
is problematic. Atomic
has no default constructor which enforces not (accidentally) using it (now and in future) at compile time (since #10215 🙈).
As it felt like I had a déjà vu: #9991 actually did something quite similar, just to the |
Speaking of spawning useless coroutines: is spawning a coroutine inside |
Oh and I totally forgot while typing that last comment: there are a few other changes (moving around checks of |
lib/remote/httpserverconnection.hpp
Outdated
|
||
private: | ||
ApiUser::Ptr m_ApiUser; | ||
Shared<AsioTlsStream>::Ptr m_Stream; | ||
double m_Seen; | ||
String m_PeerAddress; | ||
boost::asio::io_context::strand m_IoStrand; | ||
bool m_ShuttingDown; | ||
std::atomic<bool> m_ShuttingDown; |
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.
Speaking of spawning useless coroutines: is spawning a coroutine inside
HttpServerConnection::Disconnect()
even necessary at all? After a quick look, all calls to that method seem to be from coroutines running on the same strand, so shouldn't they be able to do all of this directly?
Can't this then stay a regular bool?
03cac8d
to
64271cc
Compare
@@ -582,7 +580,7 @@ void HttpServerConnection::CheckLiveness(boost::asio::yield_context yc) | |||
Log(LogInformation, "HttpServerConnection") | |||
<< "No messages for HTTP connection have been received in the last 10 seconds."; | |||
|
|||
Disconnect(); | |||
Disconnect(yc); |
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.
None of these seem to block any destructors. 👍
@@ -28,7 +28,7 @@ class HttpServerConnection final : public Object | |||
HttpServerConnection(const String& identity, bool authenticated, const Shared<AsioTlsStream>::Ptr& stream); | |||
|
|||
void Start(); | |||
void Disconnect(); |
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.
That method can now be made private and a quick doc comment for it stating that it must be called from a coroutine running on m_IoStrand
would be very nice.
Currently, for each `Disconnect()` call, we spawn a coroutine, but every one of them is just usesless, except the first one. However, since all `Disconnect()` usages share the same asio strand and cannot interfere with each other, spawning another coroutine within `Disconnect()` isn't even necessary. When a coroutine calls `Disconnect()` now, it will immediately initiate an async shutdown of the socket, potentially causing the coroutine to yield and allowing the others to resume. Therefore, the `m_ShuttingDown` flag is still required by the coroutines to be checked regularly.
64271cc
to
c0cff9d
Compare
* It is important to note that this method should only be called from within a coroutine that uses `m_IoStrand`. | ||
* | ||
* @param yc boost::asio::yield_context The coroutine yield context which you are calling this method from. | ||
*/ |
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.
Aren't such above the function definitions and not the declarations like here?
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.
Are both of you waiting for a reaction from the other one now? ;)
Aren't such above the function definitions and not the declarations like here?
On that topic: yes, that seems to often be the case in the Icinga 2 code. (Though I don't really understand why actually, so if you know, please enlighten me.)
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.
"often" like there's a minority of locations like Yonas' one or like there's a minority(?) of locations w/o code doc at all?
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.
"often" like I did not do any exact statistics. I don't know how many exceptions there are or if there are exceptions to that at all.
Currently, for each
Disconnect()
call, we spawn a coroutine, but every one of them is just usesless, except the first one. However, since allDisconnect()
usages share the same asio strand and cannot interfere with each other, spawning another coroutine withinDisconnect()
isn't even necessary. When a coroutine callsDisconnect()
now, it will immediately initiate an async shutdown of the socket, potentially causing the coroutine to yield and allowing the others to resume. Therefore, them_ShuttingDown
flag is still required by the coroutines to be checked regularly.