12c593315Sopenharmony_ci/* 22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library 32c593315Sopenharmony_ci * 42c593315Sopenharmony_ci * Copyright (c) 2012 Tatsuhiro Tsujikawa 52c593315Sopenharmony_ci * 62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining 72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the 82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to 112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 122c593315Sopenharmony_ci * the following conditions: 132c593315Sopenharmony_ci * 142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be 152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software. 162c593315Sopenharmony_ci * 172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 242c593315Sopenharmony_ci */ 252c593315Sopenharmony_ci#include "shrpx_downstream_queue.h" 262c593315Sopenharmony_ci 272c593315Sopenharmony_ci#include <cassert> 282c593315Sopenharmony_ci#include <limits> 292c593315Sopenharmony_ci 302c593315Sopenharmony_ci#include "shrpx_downstream.h" 312c593315Sopenharmony_ci 322c593315Sopenharmony_cinamespace shrpx { 332c593315Sopenharmony_ci 342c593315Sopenharmony_ciDownstreamQueue::HostEntry::HostEntry(ImmutableString &&key) 352c593315Sopenharmony_ci : key(std::move(key)), num_active(0) {} 362c593315Sopenharmony_ci 372c593315Sopenharmony_ciDownstreamQueue::DownstreamQueue(size_t conn_max_per_host, bool unified_host) 382c593315Sopenharmony_ci : conn_max_per_host_(conn_max_per_host == 0 392c593315Sopenharmony_ci ? std::numeric_limits<size_t>::max() 402c593315Sopenharmony_ci : conn_max_per_host), 412c593315Sopenharmony_ci unified_host_(unified_host) {} 422c593315Sopenharmony_ci 432c593315Sopenharmony_ciDownstreamQueue::~DownstreamQueue() { 442c593315Sopenharmony_ci dlist_delete_all(downstreams_); 452c593315Sopenharmony_ci for (auto &p : host_entries_) { 462c593315Sopenharmony_ci auto &ent = p.second; 472c593315Sopenharmony_ci dlist_delete_all(ent.blocked); 482c593315Sopenharmony_ci } 492c593315Sopenharmony_ci} 502c593315Sopenharmony_ci 512c593315Sopenharmony_civoid DownstreamQueue::add_pending(std::unique_ptr<Downstream> downstream) { 522c593315Sopenharmony_ci downstream->set_dispatch_state(DispatchState::PENDING); 532c593315Sopenharmony_ci downstreams_.append(downstream.release()); 542c593315Sopenharmony_ci} 552c593315Sopenharmony_ci 562c593315Sopenharmony_civoid DownstreamQueue::mark_failure(Downstream *downstream) { 572c593315Sopenharmony_ci downstream->set_dispatch_state(DispatchState::FAILURE); 582c593315Sopenharmony_ci} 592c593315Sopenharmony_ci 602c593315Sopenharmony_ciDownstreamQueue::HostEntry & 612c593315Sopenharmony_ciDownstreamQueue::find_host_entry(const StringRef &host) { 622c593315Sopenharmony_ci auto itr = host_entries_.find(host); 632c593315Sopenharmony_ci if (itr == std::end(host_entries_)) { 642c593315Sopenharmony_ci auto key = ImmutableString{std::begin(host), std::end(host)}; 652c593315Sopenharmony_ci auto key_ref = StringRef{key}; 662c593315Sopenharmony_ci#ifdef HAVE_STD_MAP_EMPLACE 672c593315Sopenharmony_ci std::tie(itr, std::ignore) = 682c593315Sopenharmony_ci host_entries_.emplace(key_ref, HostEntry(std::move(key))); 692c593315Sopenharmony_ci#else // !HAVE_STD_MAP_EMPLACE 702c593315Sopenharmony_ci // for g++-4.7 712c593315Sopenharmony_ci std::tie(itr, std::ignore) = host_entries_.insert( 722c593315Sopenharmony_ci std::make_pair(key_ref, HostEntry(std::move(key)))); 732c593315Sopenharmony_ci#endif // !HAVE_STD_MAP_EMPLACE 742c593315Sopenharmony_ci } 752c593315Sopenharmony_ci return (*itr).second; 762c593315Sopenharmony_ci} 772c593315Sopenharmony_ci 782c593315Sopenharmony_ciStringRef DownstreamQueue::make_host_key(const StringRef &host) const { 792c593315Sopenharmony_ci return unified_host_ ? StringRef{} : host; 802c593315Sopenharmony_ci} 812c593315Sopenharmony_ci 822c593315Sopenharmony_ciStringRef DownstreamQueue::make_host_key(Downstream *downstream) const { 832c593315Sopenharmony_ci return make_host_key(downstream->request().authority); 842c593315Sopenharmony_ci} 852c593315Sopenharmony_ci 862c593315Sopenharmony_civoid DownstreamQueue::mark_active(Downstream *downstream) { 872c593315Sopenharmony_ci auto &ent = find_host_entry(make_host_key(downstream)); 882c593315Sopenharmony_ci ++ent.num_active; 892c593315Sopenharmony_ci 902c593315Sopenharmony_ci downstream->set_dispatch_state(DispatchState::ACTIVE); 912c593315Sopenharmony_ci} 922c593315Sopenharmony_ci 932c593315Sopenharmony_civoid DownstreamQueue::mark_blocked(Downstream *downstream) { 942c593315Sopenharmony_ci auto &ent = find_host_entry(make_host_key(downstream)); 952c593315Sopenharmony_ci 962c593315Sopenharmony_ci downstream->set_dispatch_state(DispatchState::BLOCKED); 972c593315Sopenharmony_ci 982c593315Sopenharmony_ci auto link = new BlockedLink{}; 992c593315Sopenharmony_ci downstream->attach_blocked_link(link); 1002c593315Sopenharmony_ci ent.blocked.append(link); 1012c593315Sopenharmony_ci} 1022c593315Sopenharmony_ci 1032c593315Sopenharmony_cibool DownstreamQueue::can_activate(const StringRef &host) const { 1042c593315Sopenharmony_ci auto itr = host_entries_.find(make_host_key(host)); 1052c593315Sopenharmony_ci if (itr == std::end(host_entries_)) { 1062c593315Sopenharmony_ci return true; 1072c593315Sopenharmony_ci } 1082c593315Sopenharmony_ci auto &ent = (*itr).second; 1092c593315Sopenharmony_ci return ent.num_active < conn_max_per_host_; 1102c593315Sopenharmony_ci} 1112c593315Sopenharmony_ci 1122c593315Sopenharmony_cinamespace { 1132c593315Sopenharmony_cibool remove_host_entry_if_empty(const DownstreamQueue::HostEntry &ent, 1142c593315Sopenharmony_ci DownstreamQueue::HostEntryMap &host_entries, 1152c593315Sopenharmony_ci const StringRef &host) { 1162c593315Sopenharmony_ci if (ent.blocked.empty() && ent.num_active == 0) { 1172c593315Sopenharmony_ci host_entries.erase(host); 1182c593315Sopenharmony_ci return true; 1192c593315Sopenharmony_ci } 1202c593315Sopenharmony_ci return false; 1212c593315Sopenharmony_ci} 1222c593315Sopenharmony_ci} // namespace 1232c593315Sopenharmony_ci 1242c593315Sopenharmony_ciDownstream *DownstreamQueue::remove_and_get_blocked(Downstream *downstream, 1252c593315Sopenharmony_ci bool next_blocked) { 1262c593315Sopenharmony_ci // Delete downstream when this function returns. 1272c593315Sopenharmony_ci auto delptr = std::unique_ptr<Downstream>(downstream); 1282c593315Sopenharmony_ci 1292c593315Sopenharmony_ci downstreams_.remove(downstream); 1302c593315Sopenharmony_ci 1312c593315Sopenharmony_ci auto host = make_host_key(downstream); 1322c593315Sopenharmony_ci auto &ent = find_host_entry(host); 1332c593315Sopenharmony_ci 1342c593315Sopenharmony_ci if (downstream->get_dispatch_state() == DispatchState::ACTIVE) { 1352c593315Sopenharmony_ci --ent.num_active; 1362c593315Sopenharmony_ci } else { 1372c593315Sopenharmony_ci // For those downstreams deleted while in blocked state 1382c593315Sopenharmony_ci auto link = downstream->detach_blocked_link(); 1392c593315Sopenharmony_ci if (link) { 1402c593315Sopenharmony_ci ent.blocked.remove(link); 1412c593315Sopenharmony_ci delete link; 1422c593315Sopenharmony_ci } 1432c593315Sopenharmony_ci } 1442c593315Sopenharmony_ci 1452c593315Sopenharmony_ci if (remove_host_entry_if_empty(ent, host_entries_, host)) { 1462c593315Sopenharmony_ci return nullptr; 1472c593315Sopenharmony_ci } 1482c593315Sopenharmony_ci 1492c593315Sopenharmony_ci if (!next_blocked || ent.num_active >= conn_max_per_host_) { 1502c593315Sopenharmony_ci return nullptr; 1512c593315Sopenharmony_ci } 1522c593315Sopenharmony_ci 1532c593315Sopenharmony_ci auto link = ent.blocked.head; 1542c593315Sopenharmony_ci 1552c593315Sopenharmony_ci if (!link) { 1562c593315Sopenharmony_ci return nullptr; 1572c593315Sopenharmony_ci } 1582c593315Sopenharmony_ci 1592c593315Sopenharmony_ci auto next_downstream = link->downstream; 1602c593315Sopenharmony_ci auto link2 = next_downstream->detach_blocked_link(); 1612c593315Sopenharmony_ci // This is required with --disable-assert. 1622c593315Sopenharmony_ci (void)link2; 1632c593315Sopenharmony_ci assert(link2 == link); 1642c593315Sopenharmony_ci ent.blocked.remove(link); 1652c593315Sopenharmony_ci delete link; 1662c593315Sopenharmony_ci remove_host_entry_if_empty(ent, host_entries_, host); 1672c593315Sopenharmony_ci 1682c593315Sopenharmony_ci return next_downstream; 1692c593315Sopenharmony_ci} 1702c593315Sopenharmony_ci 1712c593315Sopenharmony_ciDownstream *DownstreamQueue::get_downstreams() const { 1722c593315Sopenharmony_ci return downstreams_.head; 1732c593315Sopenharmony_ci} 1742c593315Sopenharmony_ci 1752c593315Sopenharmony_ci} // namespace shrpx 176