Skip to content

Commit 524087b

Browse files
committed
Put back in the IntrusiveHashMap::insert ordering
Reverting back IntrusiveHashMap::insert ordering so that it puts things at the end of the list when there is a colision. Fix HttpSessionManager to walk the connection pool backwards.
1 parent 3a25c0d commit 524087b

File tree

3 files changed

+66
-21
lines changed

3 files changed

+66
-21
lines changed

lib/swoc/include/swoc/IntrusiveHashMap.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,15 @@ IntrusiveHashMap<H>::insert(value_type *v) {
514514
if (spot != bucket->_v) {
515515
mixed_p = true; // found some other key, it's going to be mixed.
516516
}
517+
if (spot != limit) {
518+
// If an equal key was found, walk past those to insert at the upper end of the range.
519+
do {
520+
spot = H::next_ptr(spot);
521+
} while (spot != limit && H::equal(key, H::key_of(spot)));
522+
if (spot != limit) { // something not equal past last equivalent, it's going to be mixed.
523+
mixed_p = true;
524+
}
525+
}
517526

518527
_list.insert_before(spot, v);
519528
if (spot == bucket->_v) { // added before the bucket start, update the start.

lib/swoc/unit_tests/test_IntrusiveHashMap.cc

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020

2121
#include <iostream>
22+
#include <iterator>
2223
#include <string_view>
2324
#include <string>
2425
#include <bitset>
@@ -114,17 +115,38 @@ TEST_CASE("IntrusiveHashMap", "[libts][IntrusiveHashMap]") {
114115
map.insert(new Thing("dup"sv, 81));
115116

116117
auto r = map.equal_range("dup"sv);
118+
119+
// Verify the range is correct and that accessing them one at a time works in
120+
// FIFO order.
121+
REQUIRE(r.begin()->_payload == "dup"sv);
122+
REQUIRE(r.begin()->_n == 79);
117123
REQUIRE(r.first != r.second);
124+
REQUIRE(r.first == r.begin());
125+
REQUIRE(r.second == r.end());
118126
REQUIRE(r.first->_payload == "dup"sv);
127+
REQUIRE(r.first->_n == 79);
128+
REQUIRE((++r.first)->_payload == "dup"sv);
129+
REQUIRE(r.first->_n == 80);
130+
REQUIRE((++r.first)->_payload == "dup"sv);
119131
REQUIRE(r.first->_n == 81);
120132

133+
// Verify you can walk backwards, accessing the elements in a LIFO order.
134+
r = map.equal_range("dup"sv);
135+
auto reverse_it = std::make_reverse_iterator(r.end());
136+
REQUIRE(reverse_it->_payload == "dup"sv);
137+
REQUIRE(reverse_it->_n == 81);
138+
REQUIRE((++reverse_it)->_payload == "dup"sv);
139+
REQUIRE(reverse_it->_n == 80);
140+
REQUIRE((++reverse_it)->_payload == "dup"sv);
141+
REQUIRE(reverse_it->_n == 79);
142+
REQUIRE((++reverse_it) == std::make_reverse_iterator(r.begin()));
143+
121144
Map::iterator idx;
122145

123146
// Erase all the non-"dup" and see if the range is still correct.
124147
map.apply([&map](Thing &thing) {
125-
if (thing._payload != "dup"sv) {
148+
if (thing._payload != "dup"sv)
126149
map.erase(map.iterator_for(&thing));
127-
}
128150
});
129151
r = map.equal_range("dup"sv);
130152
REQUIRE(r.first != r.second);
@@ -138,6 +160,14 @@ TEST_CASE("IntrusiveHashMap", "[libts][IntrusiveHashMap]") {
138160
REQUIRE(idx->_n != r.first->_n);
139161
REQUIRE(idx->_n == 81);
140162
REQUIRE(++idx == map.end());
163+
164+
// Now verify we can go backwards.
165+
REQUIRE((--idx)->_payload == "dup"sv);
166+
REQUIRE(idx->_n != r.first->_n);
167+
REQUIRE(idx->_n == 81);
168+
REQUIRE((--idx)->_payload == "dup"sv);
169+
REQUIRE(idx->_n != r.first->_n);
170+
REQUIRE(idx->_n == 80);
141171
// Verify only the "dup" items are left.
142172
for (auto &&elt : map) {
143173
REQUIRE(elt._payload == "dup"sv);

src/proxy/http/HttpSessionManager.cc

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "proxy/ProxySession.h"
3535
#include "proxy/http/HttpSM.h"
3636
#include "proxy/http/HttpDebugNames.h"
37+
#include <iterator>
3738

3839
// Initialize a thread to handle HTTP session management
3940
void
@@ -151,47 +152,52 @@ ServerSessionPool::acquireSession(sockaddr const *addr, CryptoHash const &hostna
151152
// This is broken out because only in this case do we check the host hash first. The range must be checked
152153
// to verify an upstream that matches port and SNI name is selected. Walk backwards to select oldest.
153154
in_port_t port = ats_ip_port_cast(addr);
154-
auto first = m_fqdn_pool.find(hostname_hash);
155-
while (first != m_fqdn_pool.end() && first->hostname_hash == hostname_hash) {
156-
Debug("http_ss", "Compare port 0x%x against 0x%x", port, ats_ip_port_cast(first->get_remote_addr()));
157-
if (port == ats_ip_port_cast(first->get_remote_addr()) &&
158-
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_SNI) || validate_sni(sm, first->get_netvc())) &&
159-
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_HOSTSNISYNC) || validate_host_sni(sm, first->get_netvc())) &&
160-
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_CERT) || validate_cert(sm, first->get_netvc()))) {
155+
auto range = m_fqdn_pool.equal_range(hostname_hash);
156+
auto iter = std::make_reverse_iterator(range.end());
157+
auto const end = std::make_reverse_iterator(range.begin());
158+
while (iter != end) {
159+
Debug("http_ss", "Compare port 0x%x against 0x%x", port, ats_ip_port_cast(iter->get_remote_addr()));
160+
if (port == ats_ip_port_cast(iter->get_remote_addr()) &&
161+
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_SNI) || validate_sni(sm, iter->get_netvc())) &&
162+
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_HOSTSNISYNC) || validate_host_sni(sm, iter->get_netvc())) &&
163+
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_CERT) || validate_cert(sm, iter->get_netvc()))) {
161164
zret = HSM_DONE;
162165
break;
163166
}
164-
++first;
167+
++iter;
165168
}
166169
if (zret == HSM_DONE) {
167-
to_return = first;
170+
to_return = iter.base();
168171
if (!to_return->is_multiplexing()) {
169172
this->removeSession(to_return);
170173
}
171-
} else if (first != m_fqdn_pool.end()) {
174+
} else if (iter != end) {
172175
Debug("http_ss", "Failed find entry due to name mismatch %s", sm->t_state.current.server->name);
173176
}
174177
} else if (TS_SERVER_SESSION_SHARING_MATCH_MASK_IP & match_style) { // matching is not disabled.
175-
auto first = m_ip_pool.find(addr);
178+
auto range = m_ip_pool.equal_range(addr);
179+
// We want to access the sessions in LIFO order, so start from the back of the list.
180+
auto iter = std::make_reverse_iterator(range.end());
181+
auto const end = std::make_reverse_iterator(range.begin());
176182
// The range is all that is needed in the match IP case, otherwise need to scan for matching fqdn
177183
// And matches the other constraints as well
178184
// Note the port is matched as part of the address key so it doesn't need to be checked again.
179185
if (match_style & (~TS_SERVER_SESSION_SHARING_MATCH_MASK_IP)) {
180-
while (first != m_ip_pool.end() && ats_ip_addr_port_eq(first->get_remote_addr(), addr)) {
181-
if ((!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_HOSTONLY) || first->hostname_hash == hostname_hash) &&
182-
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_SNI) || validate_sni(sm, first->get_netvc())) &&
183-
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_HOSTSNISYNC) || validate_host_sni(sm, first->get_netvc())) &&
184-
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_CERT) || validate_cert(sm, first->get_netvc()))) {
186+
while (iter != end) {
187+
if ((!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_HOSTONLY) || iter->hostname_hash == hostname_hash) &&
188+
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_SNI) || validate_sni(sm, iter->get_netvc())) &&
189+
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_HOSTSNISYNC) || validate_host_sni(sm, iter->get_netvc())) &&
190+
(!(match_style & TS_SERVER_SESSION_SHARING_MATCH_MASK_CERT) || validate_cert(sm, iter->get_netvc()))) {
185191
zret = HSM_DONE;
186192
break;
187193
}
188-
++first;
194+
++iter;
189195
}
190-
} else if (first != m_ip_pool.end()) {
196+
} else if (iter != end) {
191197
zret = HSM_DONE;
192198
}
193199
if (zret == HSM_DONE) {
194-
to_return = first;
200+
to_return = iter.base();
195201
if (!to_return->is_multiplexing()) {
196202
this->removeSession(to_return);
197203
}

0 commit comments

Comments
 (0)