/*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
/* ========== IdleConnList ============================================ */
-IdleConnList::IdleConnList(const char *key, PconnPool *thePool) :
+IdleConnList::IdleConnList(const char *aKey, PconnPool *thePool) :
capacity_(PCONN_FDS_SZ),
size_(0),
parent_(thePool)
{
- hash.key = xstrdup(key);
- hash.next = NULL;
+ //Initialize hash_link members
+ key = xstrdup(aKey);
+ next = NULL;
+
theList_ = new Comm::ConnectionPointer[capacity_];
+
+ registerRunner();
+
// TODO: re-attach to MemPools. WAS: theList = (?? *)pconn_fds_pool->alloc();
}
delete[] theList_;
- xfree(hash.key);
+ xfree(key);
}
/** Search the list. Matches by FD socket number.
if (parent_) {
parent_->noteConnectionRemoved();
if (size_ == 0) {
- debugs(48, 3, HERE << "deleting " << hashKeyStr(&hash));
+ debugs(48, 3, "deleting " << hashKeyStr(this));
delete this;
}
}
}
if (parent_ && size_ == 0) {
- debugs(48, 3, HERE << "deleting " << hashKeyStr(&hash));
+ debugs(48, 3, "deleting " << hashKeyStr(this));
delete this;
}
}
* quite a bit of CPU. Just keep it in mind.
*/
Comm::ConnectionPointer
-IdleConnList::findUseable(const Comm::ConnectionPointer &key)
+IdleConnList::findUseable(const Comm::ConnectionPointer &aKey)
{
assert(size_);
// small optimization: do the constant bool tests only once.
- const bool keyCheckAddr = !key->local.isAnyAddr();
- const bool keyCheckPort = key->local.port() > 0;
+ const bool keyCheckAddr = !aKey->local.isAnyAddr();
+ const bool keyCheckPort = aKey->local.port() > 0;
for (int i=size_-1; i>=0; --i) {
if (!isAvailable(i))
continue;
- // local end port is required, but dont match.
- if (keyCheckPort && key->local.port() != theList_[i]->local.port())
+ // local end port is required, but do not match.
+ if (keyCheckPort && aKey->local.port() != theList_[i]->local.port())
continue;
// local address is required, but does not match.
- if (keyCheckAddr && key->local.matchIPAddr(theList_[i]->local) != 0)
+ if (keyCheckAddr && aKey->local.matchIPAddr(theList_[i]->local) != 0)
continue;
// our connection timeout handler is scheduled to run already. unsafe for now.
list->findAndClose(io.conn);
}
+void
+IdleConnList::endingShutdown()
+{
+ closeN(size_);
+}
+
/* ========== PconnPool PRIVATE FUNCTIONS ============================================ */
const char *
LOCAL_ARRAY(char, buf, SQUIDHOSTNAMELEN * 3 + 10);
destLink->remote.toUrl(buf, SQUIDHOSTNAMELEN * 3 + 10);
+
+ // when connecting through a cache_peer, ignore the final destination
+ if (destLink->getPeer())
+ domain = nullptr;
+
if (domain) {
const int used = strlen(buf);
snprintf(buf+used, SQUIDHOSTNAMELEN * 3 + 10-used, "/%s", domain);
static void
DeleteIdleConnList(void *hashItem)
{
- delete reinterpret_cast<IdleConnList*>(hashItem);
+ delete static_cast<IdleConnList*>(hashItem);
}
PconnPool::~PconnPool()
if (list == NULL) {
list = new IdleConnList(aKey, this);
- debugs(48, 3, HERE << "new IdleConnList for {" << hashKeyStr(&list->hash) << "}" );
- hash_join(table, &list->hash);
+ debugs(48, 3, "new IdleConnList for {" << hashKeyStr(list) << "}" );
+ hash_join(table, list);
} else {
- debugs(48, 3, HERE << "found IdleConnList for {" << hashKeyStr(&list->hash) << "}" );
+ debugs(48, 3, "found IdleConnList for {" << hashKeyStr(list) << "}" );
}
list->push(conn);
Comm::ConnectionPointer
PconnPool::pop(const Comm::ConnectionPointer &dest, const char *domain, bool keepOpen)
{
+ // always call shared pool first because we need to close an idle
+ // connection there if we have to use a standby connection.
+ if (const auto direct = popStored(dest, domain, keepOpen))
+ return direct;
+
+ // either there was no pconn to pop or this is not a retriable xaction
+ if (const auto peer = dest->getPeer()) {
+ if (peer->standby.pool)
+ return peer->standby.pool->popStored(dest, domain, true);
+ }
+
+ return nullptr;
+}
+/// implements pop() API while disregarding peer standby pools
+/// \returns an open connection or nil
+Comm::ConnectionPointer
+PconnPool::popStored(const Comm::ConnectionPointer &dest, const char *domain, const bool keepOpen)
+{
const char * aKey = key(dest, domain);
IdleConnList *list = (IdleConnList *)hash_lookup(table, aKey);
if (list == NULL) {
debugs(48, 3, HERE << "lookup for key {" << aKey << "} failed.");
// failure notifications resume standby conn creation after fdUsageHigh
- notifyManager("pop failure");
+ notifyManager("pop lookup failure");
return Comm::ConnectionPointer();
} else {
- debugs(48, 3, HERE << "found " << hashKeyStr(&list->hash) <<
+ debugs(48, 3, "found " << hashKeyStr(list) <<
(keepOpen ? " to use" : " to kill"));
}
- /* may delete list */
- Comm::ConnectionPointer popped = list->findUseable(dest);
- if (!keepOpen && Comm::IsConnOpen(popped))
+ if (const auto popped = list->findUseable(dest)) { // may delete list
+ // successful pop notifications replenish standby connections pool
+ notifyManager("pop");
+
+ if (keepOpen)
+ return popped;
+
popped->close();
+ return Comm::ConnectionPointer();
+ }
- // successful pop notifications replenish standby connections pool
- notifyManager("pop");
- return popped;
+ // failure notifications resume standby conn creation after fdUsageHigh
+ notifyManager("pop usability failure");
+ return Comm::ConnectionPointer();
}
void
}
// may delete current
- reinterpret_cast<IdleConnList*>(current)->closeN(1);
+ static_cast<IdleConnList*>(current)->closeN(1);
}
}
{
theCount -= list->count();
assert(theCount >= 0);
- hash_remove_link(table, &list->hash);
+ hash_remove_link(table, list);
}
void