/*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
#include "Generic.h"
#include "globals.h"
#include "HttpReply.h"
-#include "HttpRequest.h"
#include "MemBuf.h"
#include "MemObject.h"
#include "profiler/Profiler.h"
void
MemObject::setUris(char const *aStoreId, char const *aLogUri, const HttpRequestMethod &aMethod)
{
+ if (hasUris())
+ return;
+
storeId_ = aStoreId;
+ debugs(88, 3, this << " storeId: " << storeId_);
// fast pointer comparison for a common storeCreateEntry(url,url,...) case
if (!aLogUri || aLogUri == aStoreId)
#endif
}
-MemObject::MemObject() :
- inmem_lo(0),
- nclients(0),
- smpCollapsed(false),
- request(NULL),
- ping_reply_callback(NULL),
- ircb_data(NULL),
- id(0),
- object_sz(-1),
- swap_hdr_sz(0),
-#if URL_CHECKSUM_DEBUG
- chksum(0),
-#endif
- vary_headers(NULL)
+MemObject::MemObject()
{
- debugs(20, 3, "new MemObject " << this);
+ debugs(20, 3, "MemObject constructed, this=" << this);
+ ping_reply_callback = nullptr;
memset(&start_ping, 0, sizeof(start_ping));
- memset(&abort, 0, sizeof(abort));
- _reply = new HttpReply;
- HTTPMSGLOCK(_reply);
+ reply_ = new HttpReply;
}
MemObject::~MemObject()
{
- debugs(20, 3, "del MemObject " << this);
+ debugs(20, 3, "MemObject destructed, this=" << this);
const Ctx ctx = ctx_enter(hasUris() ? urlXXX() : "[unknown_ctx]");
#if URL_CHECKSUM_DEBUG
#endif
- HTTPMSGUNLOCK(_reply);
-
- HTTPMSGUNLOCK(request);
-
ctx_exit(ctx); /* must exit before we free mem->url */
+}
- safe_free(vary_headers);
+HttpReply &
+MemObject::adjustableBaseReply()
+{
+ assert(!updatedReply_);
+ return *reply_;
}
void
-MemObject::unlinkRequest()
+MemObject::replaceBaseReply(const HttpReplyPointer &r)
{
- HTTPMSGUNLOCK(request);
+ assert(r);
+ reply_ = r;
+ updatedReply_ = nullptr;
}
void
debugs(20, DBG_IMPORTANT, "MemObject->inmem_hi: " << data_hdr.endOffset());
debugs(20, DBG_IMPORTANT, "MemObject->inmem_lo: " << inmem_lo);
debugs(20, DBG_IMPORTANT, "MemObject->nclients: " << nclients);
- debugs(20, DBG_IMPORTANT, "MemObject->reply: " << _reply);
+ debugs(20, DBG_IMPORTANT, "MemObject->reply: " << reply_);
+ debugs(20, DBG_IMPORTANT, "MemObject->updatedReply: " << updatedReply_);
+ debugs(20, DBG_IMPORTANT, "MemObject->appliedUpdates: " << appliedUpdates);
debugs(20, DBG_IMPORTANT, "MemObject->request: " << request);
debugs(20, DBG_IMPORTANT, "MemObject->logUri: " << logUri_);
debugs(20, DBG_IMPORTANT, "MemObject->storeId: " << storeId_);
}
-HttpReply const *
-MemObject::getReply() const
-{
- return _reply;
-}
-
-void
-MemObject::replaceHttpReply(HttpReply *newrep)
-{
- HTTPMSGUNLOCK(_reply);
- _reply = newrep;
- HTTPMSGLOCK(_reply);
-}
-
struct LowestMemReader : public unary_function<store_client, void> {
LowestMemReader(int64_t seed):current(seed) {}
MemObject::stat(MemBuf * mb) const
{
mb->appendf("\t" SQUIDSBUFPH " %s\n", SQUIDSBUFPRINT(method.image()), logUri());
- if (vary_headers)
- mb->appendf("\tvary_headers: %s\n", vary_headers);
+ if (!vary_headers.isEmpty())
+ mb->appendf("\tvary_headers: " SQUIDSBUFPH "\n", SQUIDSBUFPRINT(vary_headers));
mb->appendf("\tinmem_lo: %" PRId64 "\n", inmem_lo);
mb->appendf("\tinmem_hi: %" PRId64 "\n", data_hdr.endOffset());
mb->appendf("\tswapout: %" PRId64 " bytes queued\n", swapout.queue_offset);
mb->appendf("\tmem-cache index: %d state: %d offset: %" PRId64 "\n", memCache.index, memCache.io, memCache.offset);
if (object_sz >= 0)
mb->appendf("\tobject_sz: %" PRId64 "\n", object_sz);
- if (smpCollapsed)
- mb->appendf("\tsmp-collapsed\n");
StoreClientStats statsVisitor(mb);
{
const int hdr_sz = endOffset();
assert(hdr_sz >= 0);
- assert(_reply);
- _reply->hdr_sz = hdr_sz;
+ assert(reply_);
+ reply_->hdr_sz = hdr_sz;
}
int64_t
int64_t
MemObject::expectedReplySize() const
{
- debugs(20, 7, HERE << "object_sz: " << object_sz);
- if (object_sz >= 0) // complete() has been called; we know the exact answer
+ if (object_sz >= 0) {
+ debugs(20, 7, object_sz << " frozen by complete()");
return object_sz;
+ }
+
+ const auto hdr_sz = baseReply().hdr_sz;
- if (_reply) {
- const int64_t clen = _reply->bodySize(method);
- debugs(20, 7, HERE << "clen: " << clen);
- if (clen >= 0 && _reply->hdr_sz > 0) // yuck: HttpMsg sets hdr_sz to 0
- return clen + _reply->hdr_sz;
+ // Cannot predict future length using an empty/unset or HTTP/0 reply.
+ // For any HTTP/1 reply, hdr_sz is positive -- status-line cannot be empty.
+ if (hdr_sz <= 0)
+ return -1;
+
+ const auto clen = baseReply().bodySize(method);
+ if (clen < 0) {
+ debugs(20, 7, "unknown; hdr: " << hdr_sz);
+ return -1;
}
- return -1; // not enough information to predict
+ const auto messageSize = clen + hdr_sz;
+ debugs(20, 7, messageSize << " hdr: " << hdr_sz << " clen: " << clen);
+ return messageSize;
}
void
data_hdr.freeContent();
inmem_lo = 0;
/* Should we check for clients? */
+ assert(reply_);
+ reply_->reset();
+ updatedReply_ = nullptr;
+ appliedUpdates = false;
}
int64_t
bool
MemObject::readAheadPolicyCanRead() const
{
- const bool canRead = endOffset() - getReply()->hdr_sz <
+ const auto savedHttpHeaders = baseReply().hdr_sz;
+ const bool canRead = endOffset() - savedHttpHeaders <
lowestMemReaderOffset() + Config.readAheadGap;
if (!canRead) {
- debugs(19, 9, "no: " << endOffset() << '-' << getReply()->hdr_sz <<
+ debugs(19, 5, "no: " << endOffset() << '-' << savedHttpHeaders <<
" < " << lowestMemReaderOffset() << '+' << Config.readAheadGap);
}
void
MemObject::delayRead(DeferredRead const &aRead)
{
+#if USE_DELAY_POOLS
+ if (readAheadPolicyCanRead()) {
+ if (DelayId mostAllowedId = mostBytesAllowed()) {
+ mostAllowedId.delayRead(aRead);
+ return;
+ }
+ }
+#endif
deferredReads.delayRead(aRead);
}