]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/MemObject.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / MemObject.cc
index e2e7c818efda66198c3a78e964c49556b3f433ec..00fc25589bceffcd8a17bceea98669de59e51d39 100644 (file)
@@ -1,45 +1,22 @@
-
 /*
- * DEBUG: section 19    Store Memory Primitives
- * AUTHOR: Robert Collins
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * 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.
+ * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
+/* DEBUG: section 19    Store Memory Primitives */
+
 #include "squid.h"
 #include "comm/Connection.h"
 #include "Generic.h"
 #include "globals.h"
 #include "HttpReply.h"
-#include "HttpRequest.h"
 #include "MemBuf.h"
 #include "MemObject.h"
 #include "profiler/Profiler.h"
+#include "SquidConfig.h"
 #include "Store.h"
 #include "StoreClient.h"
 
@@ -73,49 +50,73 @@ MemObject::inUseCount()
     return Pool().inUseCount();
 }
 
-void
-MemObject::resetUrls(char const *aUrl, char const *aLog_url)
+const char *
+MemObject::storeId() const
 {
-    safe_free(url);
-    safe_free(log_url);    /* XXX account log_url */
-    log_url = xstrdup(aLog_url);
-    url = xstrdup(aUrl);
+    if (!storeId_.size()) {
+        debugs(20, DBG_IMPORTANT, "Bug: Missing MemObject::storeId value");
+        dump();
+        storeId_ = "[unknown_URI]";
+    }
+    return storeId_.termedBuf();
 }
 
-MemObject::MemObject(char const *aUrl, char const *aLog_url)
+const char *
+MemObject::logUri() const
 {
-    debugs(20, 3, HERE << "new MemObject " << this);
-    HttpReply *rep = new HttpReply;
-
-    _reply  = HTTPMSGLOCK(rep);
-    url = xstrdup(aUrl);
+    return logUri_.size() ? logUri_.termedBuf() : storeId();
+}
 
-#if URL_CHECKSUM_DEBUG
+bool
+MemObject::hasUris() const
+{
+    return storeId_.size();
+}
 
-    chksum = url_checksum(url);
+void
+MemObject::setUris(char const *aStoreId, char const *aLogUri, const HttpRequestMethod &aMethod)
+{
+    if (hasUris())
+        return;
 
-#endif
+    storeId_ = aStoreId;
+    debugs(88, 3, this << " storeId: " << storeId_);
 
-    log_url = xstrdup(aLog_url);
+    // fast pointer comparison for a common storeCreateEntry(url,url,...) case
+    if (!aLogUri || aLogUri == aStoreId)
+        logUri_.clean(); // use storeId_ by default to minimize copying
+    else
+        logUri_ = aLogUri;
 
-    object_sz = -1;
+    method = aMethod;
 
-    /* XXX account log_url */
+#if URL_CHECKSUM_DEBUG
+    chksum = url_checksum(urlXXX());
+#endif
+}
 
-    swapout.decision = SwapOut::swNeedsCheck;
+MemObject::MemObject()
+{
+    debugs(20, 3, "MemObject constructed, this=" << this);
+    ping_reply_callback = nullptr;
+    memset(&start_ping, 0, sizeof(start_ping));
+    reply_ = new HttpReply;
 }
 
 MemObject::~MemObject()
 {
-    debugs(20, 3, HERE << "del MemObject " << this);
-    const Ctx ctx = ctx_enter(url);
-#if URL_CHECKSUM_DEBUG
+    debugs(20, 3, "MemObject destructed, this=" << this);
+    const Ctx ctx = ctx_enter(hasUris() ? urlXXX() : "[unknown_ctx]");
 
-    assert(chksum == url_checksum(url));
+#if URL_CHECKSUM_DEBUG
+    checkUrlChecksum();
 #endif
 
-    if (!shutting_down)
+    if (!shutting_down) { // Store::Root() is FATALly missing during shutdown
+        assert(xitTable.index < 0);
+        assert(memCache.index < 0);
         assert(swapout.sio == NULL);
+    }
 
     data_hdr.freeContent();
 
@@ -128,41 +129,36 @@ MemObject::~MemObject()
 
 #endif
 
-    HTTPMSGUNLOCK(_reply);
-
-    HTTPMSGUNLOCK(request);
-
     ctx_exit(ctx);              /* must exit before we free mem->url */
+}
 
-    safe_free(url);
-
-    safe_free(log_url);    /* XXX account log_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
-MemObject::write ( StoreIOBuffer writeBuffer, STMCB *callback, void *callbackData)
+MemObject::write(const StoreIOBuffer &writeBuffer)
 {
     PROF_start(MemObject_write);
     debugs(19, 6, "memWrite: offset " << writeBuffer.offset << " len " << writeBuffer.length);
 
-    /* the offset is into the content, not the headers */
-    writeBuffer.offset += (_reply ? _reply->hdr_sz : 0);
-
     /* We don't separate out mime headers yet, so ensure that the first
      * write is at offset 0 - where they start
      */
     assert (data_hdr.endOffset() || writeBuffer.offset == 0);
 
     assert (data_hdr.write (writeBuffer));
-    callback (callbackData, writeBuffer);
     PROF_stop(MemObject_write);
 }
 
@@ -179,22 +175,12 @@ MemObject::dump() const
     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->log_url: " << log_url << " " << checkNullString(log_url));
-}
-
-HttpReply const *
-MemObject::getReply() const
-{
-    return _reply;
-}
-
-void
-MemObject::replaceHttpReply(HttpReply *newrep)
-{
-    HTTPMSGUNLOCK(_reply);
-    _reply = HTTPMSGLOCK(newrep);
+    debugs(20, DBG_IMPORTANT, "MemObject->logUri: " << logUri_);
+    debugs(20, DBG_IMPORTANT, "MemObject->storeId: " << storeId_);
 }
 
 struct LowestMemReader : public unary_function<store_client, void> {
@@ -223,18 +209,22 @@ struct StoreClientStats : public unary_function<store_client, void> {
 void
 MemObject::stat(MemBuf * mb) const
 {
-    mb->Printf("\t%s %s\n",
-               RequestMethodStr(method), log_url);
-    if (vary_headers)
-        mb->Printf("\tvary_headers: %s\n", vary_headers);
-    mb->Printf("\tinmem_lo: %" PRId64 "\n", inmem_lo);
-    mb->Printf("\tinmem_hi: %" PRId64 "\n", data_hdr.endOffset());
-    mb->Printf("\tswapout: %" PRId64 " bytes queued\n",
-               swapout.queue_offset);
+    mb->appendf("\t" SQUIDSBUFPH " %s\n", SQUIDSBUFPRINT(method.image()), logUri());
+    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);
 
     if (swapout.sio.getRaw())
-        mb->Printf("\tswapout: %" PRId64 " bytes written\n",
-                   (int64_t) swapout.sio->offset());
+        mb->appendf("\tswapout: %" PRId64 " bytes written\n", (int64_t) swapout.sio->offset());
+
+    if (xitTable.index >= 0)
+        mb->appendf("\ttransient index: %d state: %d\n", xitTable.index, xitTable.io);
+    if (memCache.index >= 0)
+        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);
 
     StoreClientStats statsVisitor(mb);
 
@@ -252,8 +242,8 @@ MemObject::markEndOfReplyHeaders()
 {
     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
@@ -268,18 +258,27 @@ MemObject::size() const
 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;
+    }
 
-    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;
+    const auto hdr_sz = baseReply().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
@@ -289,6 +288,10 @@ MemObject::reset()
     data_hdr.freeContent();
     inmem_lo = 0;
     /* Should we check for clients? */
+    assert(reply_);
+    reply_->reset();
+    updatedReply_ = nullptr;
+    appliedUpdates = false;
 }
 
 int64_t
@@ -305,7 +308,16 @@ MemObject::lowestMemReaderOffset() const
 bool
 MemObject::readAheadPolicyCanRead() const
 {
-    return endOffset() - getReply()->hdr_sz < lowestMemReaderOffset() + Config.readAheadGap;
+    const auto savedHttpHeaders = baseReply().hdr_sz;
+    const bool canRead = endOffset() - savedHttpHeaders <
+                         lowestMemReaderOffset() + Config.readAheadGap;
+
+    if (!canRead) {
+        debugs(19, 5, "no: " << endOffset() << '-' << savedHttpHeaders <<
+               " < " << lowestMemReaderOffset() << '+' << Config.readAheadGap);
+    }
+
+    return canRead;
 }
 
 void
@@ -319,7 +331,7 @@ MemObject::addClient(store_client *aClient)
 void
 MemObject::checkUrlChecksum () const
 {
-    assert(chksum == url_checksum(url));
+    assert(chksum == url_checksum(urlXXX()));
 }
 
 #endif
@@ -388,7 +400,7 @@ MemObject::trimSwappable()
         new_mem_lo = on_disk - 1;
 
     if (new_mem_lo == -1)
-        new_mem_lo = 0;        /* the above might become -1 */
+        new_mem_lo = 0; /* the above might become -1 */
 
     data_hdr.freeDataUpto(new_mem_lo);
 
@@ -398,11 +410,11 @@ MemObject::trimSwappable()
 void
 MemObject::trimUnSwappable()
 {
-    int64_t new_mem_lo = policyLowestOffsetToKeep(0);
-    assert (new_mem_lo > 0);
-
-    data_hdr.freeDataUpto(new_mem_lo);
-    inmem_lo = new_mem_lo;
+    if (const int64_t new_mem_lo = policyLowestOffsetToKeep(false)) {
+        assert (new_mem_lo > 0);
+        data_hdr.freeDataUpto(new_mem_lo);
+        inmem_lo = new_mem_lo;
+    } // else we should not trim anything at this time
 }
 
 bool
@@ -444,6 +456,14 @@ MemObject::setNoDelay(bool const newValue)
 void
 MemObject::delayRead(DeferredRead const &aRead)
 {
+#if USE_DELAY_POOLS
+    if (readAheadPolicyCanRead()) {
+        if (DelayId mostAllowedId = mostBytesAllowed()) {
+            mostAllowedId.delayRead(aRead);
+            return;
+        }
+    }
+#endif
     deferredReads.delayRead(aRead);
 }
 
@@ -495,3 +515,4 @@ MemObject::availableForSwapOut() const
 {
     return endOffset() - swapout.queue_offset;
 }
+