HTTPMSGLOCK(request);
serverDestinations.reserve(Config.forward_max_tries);
e->lock("FwdState");
- EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT);
flags.connected_okay = false;
flags.dont_retry = false;
flags.forward_completed = false;
}
#endif
} else {
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
entry->complete();
entry->releaseRequest();
}
debugs(17, 3, HERE << "server FD " << serverConnection()->fd << " not re-forwarding status " << entry->getReply()->sline.status());
else
debugs(17, 3, HERE << "server (FD closed) not re-forwarding status " << entry->getReply()->sline.status());
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
entry->complete();
if (!Comm::IsConnOpen(serverConn))
const int result = rep->httpMsgParseStep(mb.buf, buf.length, eof);
if (result > 0) {
assert(rep->pstate == psParsed);
- EBIT_CLR(e.flags, ENTRY_FWD_HDR_WAIT);
} else if (result < 0) {
debugs(20, DBG_IMPORTANT, "Corrupted mem-cached headers: " << e);
return false;
void
MemStore::copyToShm(StoreEntry &e)
{
- // prevents remote readers from getting ENTRY_FWD_HDR_WAIT entries and
- // not knowing when the wait is over
- if (EBIT_TEST(e.flags, ENTRY_FWD_HDR_WAIT)) {
- debugs(20, 5, "postponing copying " << e << " for ENTRY_FWD_HDR_WAIT");
- return;
- }
-
assert(map);
assert(e.mem_obj);
+ Must(!EBIT_TEST(e.flags, ENTRY_FWD_HDR_WAIT));
const int64_t eSize = e.mem_obj->endOffset();
if (e.mem_obj->memCache.offset >= eSize) {
assert(repContext);
repContext->createStoreEntry(request->method, request->flags);
- EBIT_CLR(storeEntry()->flags, ENTRY_FWD_HDR_WAIT);
request_satisfaction_mode = true;
request_satisfaction_offset = 0;
storeEntry()->replaceHttpReply(new_rep);
ferr.ftp.cwd_msg = xstrdup(cwd_message.size()? cwd_message.termedBuf() : "");
ferr.ftp.server_msg = ctrl.message;
ctrl.message = NULL;
- entry->replaceHttpReply( ferr.BuildHttpReply() );
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+ entry->replaceHttpReply(ferr.BuildHttpReply());
entry->flush();
entry->unlock("Ftp::Gateway");
}
assert(entry->isEmpty());
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
-
entry->buffer(); /* released when done processing current data payload */
SBuf urlPath = request->url.path();
const Http::StatusCode httpStatus = failedHttpStatus(error);
HttpReply *const reply = createHttpReply(httpStatus);
entry->replaceHttpReply(reply);
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
fwd->request->detailError(error, xerrno);
}
Ftp::Relay::forwardReply()
{
assert(entry->isEmpty());
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
HttpReply *const reply = createHttpReply(Http::scNoContent);
reply->sources |= HttpMsg::srcFtp;
HttpReply *const reply = createHttpReply(Http::scOkay, -1);
reply->sources |= HttpMsg::srcFtp;
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
setVirginReply(reply);
adaptOrFinalizeReply();
enum {
ENTRY_SPECIAL,
ENTRY_REVALIDATE_ALWAYS,
+
+ /// Tiny Store writes are likely. The writes should be aggregated together
+ /// before Squid announces the new content availability to the store
+ /// clients. For example, forming a cached HTTP response header may result
+ /// in dozens of StoreEntry::write() calls, many of which adding as little
+ /// as two bytes. Sharing those small writes with the store clients
+ /// increases overhead, especially because the client code can do nothing
+ /// useful with the written content until the whole response header is
+ /// stored. Might be combined with ENTRY_FWD_HDR_WAIT. TODO: Rename to
+ /// ENTRY_DELAY_WHILE_COALESCING to emphasize the difference from and
+ /// similarity with ENTRY_FWD_HDR_WAIT.
DELAY_SENDING,
RELEASE_REQUEST, ///< prohibits making the key public
REFRESH_REQUEST,
ENTRY_REVALIDATE_STALE,
ENTRY_DISPATCHED,
KEY_PRIVATE,
+
+ /// The current entry response may change. The contents of an entry in this
+ /// state must not be shared with its store clients. For example, Squid
+ /// receives (and buffers) an HTTP/504 response but may decide to retry that
+ /// transaction to receive a successful response from another server
+ /// instead. Might be combined with DELAY_SENDING. TODO: Rename to
+ /// ENTRY_DELAY_WHILE_WOBBLING to emphasize the difference from and
+ /// similarity with DELAY_SENDING.
ENTRY_FWD_HDR_WAIT,
ENTRY_NEGCACHED,
ENTRY_VALIDATED,
}
assert(entry->isEmpty());
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
HttpReply *reply = new HttpReply;
entry->buffer();
// TODO: check whether such responses are shareable.
// Do not share for now.
entry->makePrivate(false);
- if (!fwd->reforwardableStatus(rep->sline.status()))
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+ if (fwd->reforwardableStatus(rep->sline.status()))
+ EBIT_SET(entry->flags, ENTRY_FWD_HDR_WAIT);
varyFailure = true;
} else {
entry->mem_obj->vary_headers = vary;
* If its not a reply that we will re-forward, then
* allow the client to get it.
*/
- if (!fwd->reforwardableStatus(rep->sline.status()))
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+ if (fwd->reforwardableStatus(rep->sline.status()))
+ EBIT_SET(entry->flags, ENTRY_FWD_HDR_WAIT);
ReuseDecision decision(entry, statusCode);
{
debugs(54, 3, HERE);
request->requestId = 0;
- // Do not clear ENTRY_FWD_HDR_WAIT or do entry->complete() because
- // it will trigger our client side processing. Let job cleanup close.
+ // Do not do entry->complete() because it will trigger our client side
+ // processing when we no longer own the client-Squid connection.
+ // Let job cleanup close the client-Squid connection that Coordinator
+ // now owns.
}
/// Ipc::Forwarder::requestTimedOut wrapper
HTTPMSGLOCK(httpRequest);
entry->lock("Mgr::Forwarder");
- EBIT_SET(entry->flags, ENTRY_FWD_HDR_WAIT);
closer = asyncCall(16, 5, "Mgr::Forwarder::noteCommClosed",
CommCbMemFunT<Forwarder, CommCloseCbParams>(this, &Forwarder::noteCommClosed));
Must(entry != NULL);
Must(httpRequest != NULL);
- EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
entry->buffer();
entry->replaceHttpReply(error->BuildHttpReply());
entry->expires = squid_curtime;
storeGetMemSpace(writeBuffer.length);
mem_obj->write(writeBuffer);
- if (!EBIT_TEST(flags, DELAY_SENDING))
- invokeHandlers();
+ if (EBIT_TEST(flags, ENTRY_FWD_HDR_WAIT) && !mem_obj->readAheadPolicyCanRead()) {
+ debugs(20, 3, "allow Store clients to get entry content after buffering too much for " << *this);
+ EBIT_CLR(flags, ENTRY_FWD_HDR_WAIT);
+ }
+
+ invokeHandlers();
}
/* Append incoming data from a primary server to an entry. */
{
debugs(20, 3, "storeComplete: '" << getMD5Text() << "'");
+ // To preserve forwarding retries, call FwdState::complete() instead.
+ EBIT_CLR(flags, ENTRY_FWD_HDR_WAIT);
+
if (store_status != STORE_PENDING) {
/*
* if we're not STORE_PENDING, then probably we got aborted
EBIT_SET(flags, ENTRY_ABORTED);
+ // allow the Store clients to be told about the problem
+ EBIT_CLR(flags, ENTRY_FWD_HDR_WAIT);
+
setMemStatus(NOT_IN_MEMORY);
store_status = STORE_OK;
buffer();
rep->packHeadersInto(this);
mem_obj->markEndOfReplyHeaders();
- EBIT_CLR(flags, ENTRY_FWD_HDR_WAIT);
rep->body.packInto(this);
flush();
return;
}
- if (EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
- debugs(90, 5, "storeClientCopy2: returning because ENTRY_FWD_HDR_WAIT set");
- return;
- }
-
if (sc->flags.store_copying) {
sc->flags.copy_event_pending = true;
debugs(90, 3, "storeClientCopy2: Queueing storeClientCopyEvent()");
void
StoreEntry::invokeHandlers()
{
+ if (EBIT_TEST(flags, DELAY_SENDING)) {
+ debugs(90, 3, "DELAY_SENDING is on, exiting " << *this);
+ return;
+ }
+ if (EBIT_TEST(flags, ENTRY_FWD_HDR_WAIT)) {
+ debugs(90, 3, "ENTRY_FWD_HDR_WAIT is on, exiting " << *this);
+ return;
+ }
+
/* Commit what we can to disk, if appropriate */
swapOut();
int i = 0;