-
Notifications
You must be signed in to change notification settings - Fork 7
Wait methods fixes [part 2] #145
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
base: master
Are you sure you want to change the base?
Wait methods fixes [part 2] #145
Conversation
ee2f9f0 to
de1843a
Compare
`Connection`s model shared pointers on `ConnectionImpl` and are intended for external usage by library consumers. Using them internally in the Connector can cause bugs. For instance, we internally store `Connection` objects in the LibevNetProvider, which adds an additional reference to them and prevents them from being deleted, even when all user objects are dead. To avoid this, let's internally use `ConnectionImpl` to model weak pointers. We rely on the fact that the lifetime of these weak pointers is tied to the lifetime of the shared user objects. The ideal solution would be to remove the `Connection`<-`ConnectionImpl` constructor, but we still need to return new Connection objects in methods like waitAny, so let's just enforce as a rule that we should not use `Connection` objects internally. While we are here, let's also fix all the formating issues that the linter is reporting for the refactored code. Closes tarantool#140
Currently, to avoid double-close of a connection we check for the `SS_DEAD` status on its stream. However, the `SS_DEAD` status can be set for a multitude of reasons without the connection being closed or even connected. For instance, we set it if a send/recv failed unrecoverably. To fix this, let's rely on the fact that a connection is open iff the file descriptor of its stream is a valid (i.e., not -1). This approach seems to be portable to the Windows platform too. Closes tarantool#142
Currently, all connection bookkeeping is done opaquely through the network providers which, in turn, also do this bookkeeping opaquely using system interfaces (e.g., libev, epoll). Because of this, we cannot handle cases when waitAny is called and there are no connections (tarantoolgh-51) or when a connection has ready responses (tarantoolgh-132). In order to improve `waitAny` robustness, we need to add connection bookkeeping to Connector. We should move the timer start to the beginning of the waiting loop, since the preceding checking overhead should not be accounted for the waiting time. Closes tarantool#51 Needed for tarantool#132
de1843a to
214c640
Compare
Currently, `waitAny` does not account for connections that already have ready responses. Let's handle this by going through the set of owned connections and checking them for ready responses. We should do this before the timer start, since the checking overhead should not be accounted for the waiting time. Closes tarantool#132
214c640 to
aa5e506
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.
Thank you for the patch! I believe it improves connector usability quite a lot.
| { | ||
| assert(refs == 0); | ||
| if (!strm.has_status(SS_DEAD)) { | ||
| if (strm.get_fd() != -1) { |
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.
Nit: We rely here that closed connection always had fd equal to -1. We should describe it in UnixStream class (to fixate this behavior) or introduce new stem.is_closed() method.
| Timer timer{timeout}; | ||
| timer.start(); | ||
| while (m_ReadyToDecode.empty()) { | ||
| bool any_conn_has_no_err = false; |
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.
Nit: wouldn't has_alive_conn be better? Too many logical negations with this name :)
| bool any_conn_has_no_err = false; | ||
| for (auto *conn : m_Connections) { | ||
| if (!conn->hasError()) | ||
| any_conn_has_no_err = true; |
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.
I believe we should break here.
| LOG_DEBUG("waitAny() called on connector without connections"); | ||
| return std::nullopt; | ||
| } | ||
| for (auto *conn : m_Connections) { |
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.
I think waitAny still should trigger net provider to send pending requests (m_NetProvider.wait(0)).
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.
Shouldn't this change be tested somehow?
This patchset performs a major refactoring of the client code to replace all internal
Connectionusage withConnectionImpl, and fixes several related bugs.Closes #51
Closes #132
Closes #140
Closes #142