-
Notifications
You must be signed in to change notification settings - Fork 847
Make HttpSM server reference a Transaction instead of a Session #7849
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
Conversation
|
|
||
| #include "HttpSessionManager.h" | ||
| class EThread; | ||
| class Continuation; |
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.
Needed to avoid pulling in unnecessary stuff to the unit test.
| { | ||
| return lhs == rhs; | ||
| } | ||
|
|
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.
Promoted the conntecting tracking calls to a super class.
| } | ||
|
|
||
| void | ||
| Http1ServerSession ::release_transaction() |
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.
Called from transaction_done to adjust the released_transacations count and cause any pending close or server session pool release to occur.
| HttpTunnelProducer *p = nullptr; | ||
|
|
||
| if (!server_entry || !server_entry->vc || !server_session || !server_session->get_netvc()) { | ||
| if (!server_txn || !server_txn->get_netvc()) { |
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.
May need to adjust this test, since server_txn will not be null at this point even if we did already call do_io_close on it. The get_netvc() may still be returning null, so it may still be ok.
|
[approve ci autest] |
|
[approve ci clang-analyzer] |
proxy/http/HttpSessionManager.cc
Outdated
| } | ||
|
|
||
| void | ||
| ServerSessionPool::testSession(PoolableSession *ss) |
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.
It seems like this functions is unnecessary. It's called by Http2ServerSession::test_session() on #7622, but Http2ServerSession::test_session() is not called.
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.
Yes, this one can be removed.
|
|
||
| sockaddr const *get_remote_addr() const; | ||
|
|
||
| virtual HTTPVersion get_version(HTTPHdr &hdr) const; |
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.
We don't need this at the moment.
SinceProxySession::get_version receives HTTPHdr, a proxy session can always return correct version. I wonder if there will be a session that has multiple versions of transactions. I'm not sure if we are allowed to use multiple versions on a traditional HTTP connection like below:
[Connect]
GET /a HTTP/1.0
GET /b HTTP/1.1
Host: example.com
[Close]
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 am not sure CONNECT makes my head hurt. I would think that only one nested method would be interpreted over the CONNECT method. And ATS would only interpret it if the CONNECT was made over a non-TLS connection. Otherwise ATS treats the body as a blind tunnel.
Will have to read the RFC tea leaves on this.
proxy/http/HttpSM.cc
Outdated
| } | ||
|
|
||
| void | ||
| HttpSM::create_server_txn(NetVConnection *netvc, PoolableSession *new_session) |
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 function is really confusing.
The name implies that we call this function whenever we want to create a server transaction, but that is probably incorrect. This function seems to be only used for the initial server transaction on a session.
Furthermore, this is a public function despite that HttpSM has to be the only caller. Anybody can accidentally call this function based on the wrong assumption above.
Can you make this a private function and rename it to create_initial_server_txn? I haven't understood why server transactions have to be created here and there, and I think it should be done at only one place, but the name would tell that is the current design.
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.
create_initial_server_txn is probably a better name. And it can be made private. The goal of the function is to wire in the netvc into a ProxyTransaction object (Http1ServerTransaction in this case). It is taking logic that was inline in the HttpSM::state_http_server_open function. It is called a bit later once H2 to origin is introduced because we need to wait to see what protocol is negotiated to create the correct subclass of ProxyTransaction.
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.
Reworked so create_server_txn is called in HttpSessionManager too instead of calling new_transaction directly
proxy/ProxyTransaction.cc
Outdated
| } | ||
|
|
||
| bool | ||
| ProxyTransaction::is_read_closed() const |
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.
Is this used in some subsequent PRs? Seems a little odd to have this "no-op" method, which is never called as far as I can tell.
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.
Probably leftover from the H2 to origin pull back.
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.
Removed for now. Will be added back with the H2 to origin logic.
| } else { | ||
| ink_assert(data && data == ka_vio); | ||
| ink_assert(read_state == HCS_KEEP_ALIVE); | ||
| if (data) { |
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.
Would this possibly read nicer as a switch statement?
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.
Cannot have variables as case elements.
| (int)http_origin_close_private, RecRawStatSyncCount); | ||
| RecRegisterRawStat(http_rsb, RECT_PROCESS, "proxy.process.http.origin.raw", RECD_INT, RECP_NON_PERSISTENT, (int)http_origin_raw, | ||
| RecRawStatSyncCount); | ||
|
|
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 great!
proxy/http/HttpSM.cc
Outdated
| void | ||
| HttpSM::set_server_txn(ProxyTransaction *txn) | ||
| { | ||
| ink_release_assert(server_txn == nullptr); |
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 would probably argue that this should be a debug assert, it kinda feels like we're too liberal sometimes with the release assert. Looking where this is called, it can't be nullptr (assuming that to_return->new_transaction() is not allowed to fail).
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.
Agree. I use the release_asserts liberally while debugging in production. Don't always get them cleaned up. Looking forward to using your enable-all asserts option.
|
|
||
| if (!try_reuse) { | ||
| HTTP_INCREMENT_DYN_STAT(http_origin_make_new); | ||
| if (TS_SERVER_SESSION_SHARING_MATCH_NONE == t_state.txn_conf->server_session_sharing_match) { |
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 code is slightly alarming; It feels like the server session would be in one of several conditions, as seen by which metric we increment. But, the logic to decide what "state" it is in is based on a number of conditions and member variables, rather than a single "state". That feels like e.g. someone could set "raw" and "is_private", and the session is now in a unknown state.
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 added these stats for debugging to solve my last issue before posting this PR. No doubt could be tidied up. Or removed entirely.
proxy/http/HttpSM.cc
Outdated
| server_session = nullptr; | ||
| if (server_entry) { | ||
| server_entry->vc = nullptr; | ||
| server_entry->read_vio = server_entry->write_vio = nullptr; |
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 would look a lot better if you don't do the double assignment on line 5541 :).
proxy/http/HttpSessionManager.cc
Outdated
| m_ip_pool.erase(to_return); | ||
| this->removeSession(to_return); | ||
| } else { | ||
| if (first != m_fqdn_pool.end()) { |
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.
Bike shedding, but for easier read, why not make this an } else if { ?
proxy/http/Http1ServerSession.cc
Outdated
| ts::LocalBufferWriter<256> w; | ||
| w.print("[{}] new connection, ip: {}, group ({}), count: {}\0", con_id, get_server_ip(), *group, group->_count); | ||
| Debug("http_ss", "%s", w.data()); | ||
| if (state == SSN_CLOSED) { // Already been closed |
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 prefer this way. It has less dup code.
if (state != SSN_CLOSED) {
state = SSN_CLOSED
release outbound connection tracking
close vc
decrement stats
}
if (transact_count == released_transactions) {
this->destroy();
}
maskit
left a comment
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.
Although I can't say this doesn't break things, but it looks good to me. I'm going to approve this when conflicts are resolved.
2e5a4ed to
7e9a61c
Compare
|
[approve ci autest] |
This is derived as a subset of the H2 to origin PR #7622. This PR adds no support for H2 to origin, but it performs the restructuring so the HttpSM refers to the server connection via a ProxyTransaction instead of a PoolableSession.
This was requested by @maskit in hopes this work would assist them in discovering the cause of the server session leak described in issue #7471. This restructuring should simplify server connection leaks because the server_txn object stays around until HttpSM::kill_this() when server_txn->transaction_done() is called. If the server session should be returned to the origin pool, it will have previously been marked so. Otherwise the server session will be closed. Similarly earlier calls to do_io_close on the server transaction will be held until transaction_done() is called.
In the case of an origin connection failure and subsequent retry, server_txn->transaction_done() is called in HttpSM::do_http_server_open() before another connection attempt is made.
The PR also includes some stats I added to help debug a pool buildup issue I ran into debugging this PR against our 9.1.x build in master.
I also pulled into the following commits to make the move to our 9.1.x branch from master easier.
PR #6241 - but I see that just got picked into 9.1.x already
PR #7571 - I think that one is there now too.
PR #7584 - which also just got pulled into 9.1.x
PR #7600