entry = e;
clientConn = client;
request = HTTPMSGLOCK(r);
+ pconnRace = raceImpossible;
start_t = squid_curtime;
serverDestinations.reserve(Config.forward_max_tries);
e->lock();
if (!errorState->request)
errorState->request = HTTPMSGLOCK(request);
+ if (pconnRace == racePossible && err->type == ERR_ZERO_SIZE_OBJECT) {
+ debugs(17, 5, HERE << "pconn race happened");
+ pconnRace = raceHappened;
+ }
+
#if USE_SSL
if (errorState->type == ERR_SECURE_CONNECT_FAIL && errorState->detail)
request->detailError(errorState->type, errorState->detail->errorNo());
{
if (checkRetry()) {
debugs(17, 3, HERE << "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
- serverDestinations.shift(); // last one failed. try another.
+ // we should retry the same destination if it failed due to pconn race
+ if (pconnRace == raceHappened)
+ debugs(17, 4, HERE << "retrying the same destination");
+ else
+ serverDestinations.shift(); // last one failed. try another.
startConnectionOrFail();
return;
}
// XXX: also, logs will now lie if pinning is broken and leads to an error message.
if (serverDestinations[0]->peerType == PINNED) {
ConnStateData *pinned_connection = request->pinnedConnection();
- assert(pinned_connection);
- serverConn = pinned_connection->validatePinnedConnection(request, serverDestinations[0]->getPeer());
+ // pinned_connection may become nil after a pconn race
+ if (pinned_connection)
+ serverConn = pinned_connection->validatePinnedConnection(request, serverDestinations[0]->getPeer());
+ else
+ serverConn = NULL;
if (Comm::IsConnOpen(serverConn)) {
#if 0
if (!serverConn->getPeer())
request->flags.pinned = 1;
if (pinned_connection->pinnedAuth())
request->flags.auth = 1;
+ // the server may close the pinned connection before this request
+ pconnRace = racePossible;
dispatch();
return;
}
} else {
host = request->GetHost();
}
- Comm::ConnectionPointer temp = fwdPconnPool->pop(serverDestinations[0], host, checkRetriable());
+
+ Comm::ConnectionPointer temp;
+ // Avoid pconns after races so that the same client does not suffer twice.
+ // This does not increase the total number of connections because we just
+ // closed the connection that failed the race. And re-pinning assumes this.
+ if (pconnRace != raceHappened)
+ temp = fwdPconnPool->pop(serverDestinations[0], host, checkRetriable());
+
+ const bool openedPconn = Comm::IsConnOpen(temp);
+ pconnRace = openedPconn ? racePossible : raceImpossible;
// if we found an open persistent connection to use. use it.
- if (Comm::IsConnOpen(temp)) {
+ if (openedPconn) {
serverConn = temp;
debugs(17, 3, HERE << "reusing pconn " << serverConnection());
n_tries++;
return;
}
+ // We will try to open a new connection, possibly to the same destination.
+ // We reset serverDestinations[0] in case we are using it again because
+ // ConnOpener modifies its destination argument.
+ serverDestinations[0]->local.SetPort(0);
+ serverConn = NULL;
+
#if URL_CHECKSUM_DEBUG
entry->mem_obj->checkUrlChecksum();
#endif