]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/MemObject.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / MemObject.cc
index 7e8dabb94317d5cad31df073ff916317ce58b4a4..b35d26cae619f7c153c521851950940a2ebce921 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: MemObject.cc,v 1.4 2003/02/13 22:20:37 robertc Exp $
+ * $Id$
  *
  * DEBUG: section 19    Store Memory Primitives
  * AUTHOR: Robert Collins
  *  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.
  *
  */
 
-#include "squid.h"
+#include "squid-old.h"
+#include "comm/Connection.h"
 #include "MemObject.h"
 #include "HttpRequest.h"
 #include "HttpReply.h"
 #include "Store.h"
 #include "StoreClient.h"
 #include "Generic.h"
-#if DELAY_POOLS
+#if USE_DELAY_POOLS
 #include "DelayPools.h"
 #endif
+#include "MemBuf.h"
 
 /* TODO: make this global or private */
 #if URL_CHECKSUM_DEBUG
@@ -51,135 +53,134 @@ unsigned int
 url_checksum(const char *url)
 {
     unsigned int ck;
-    MD5_CTX M;
+    SquidMD5_CTX M;
     static unsigned char digest[16];
-    MD5Init(&M);
-    MD5Update(&M, (unsigned char *) url, strlen(url));
-    MD5Final(digest, &M);
-    xmemcpy(&ck, digest, sizeof(ck));
+    SquidMD5Init(&M);
+    SquidMD5Update(&M, (unsigned char *) url, strlen(url));
+    SquidMD5Final(digest, &M);
+    memcpy(&ck, digest, sizeof(ck));
     return ck;
 }
+
 #endif
 
-MemPool *MemObject::pool = NULL;
+RemovalPolicy * mem_policy = NULL;
 
-void *
-MemObject::operator new (size_t byteCount)
+size_t
+MemObject::inUseCount()
 {
-    /* derived classes with different sizes must implement their own new */
-    assert (byteCount == sizeof (MemObject));
-    if (!pool)
-       pool = memPoolCreate("MemObject", sizeof (MemObject));
-    return memPoolAlloc(pool);
+    return Pool().inUseCount();
 }
 
 void
-MemObject::operator delete (void *address)
+MemObject::resetUrls(char const *aUrl, char const *aLog_url)
 {
-    memPoolFree(pool, address);
+    safe_free(url);
+    safe_free(log_url);    /* XXX account log_url */
+    log_url = xstrdup(aLog_url);
+    url = xstrdup(aUrl);
 }
 
-size_t
-MemObject::inUseCount()
+MemObject::MemObject(char const *aUrl, char const *aLog_url)
 {
-    if (!pool)
-       return 0;
-    MemPoolStats stats;
-    memPoolGetStats (&stats, pool);
-    return stats.items_inuse;
-}
+    debugs(20, 3, HERE << "new MemObject " << this);
+    HttpReply *rep = new HttpReply;
 
-MemObject::MemObject(char const *aUrl, char const *aLog_url) :
-_reply (httpReplyCreate())
-{
+    _reply  = HTTPMSGLOCK(rep);
     url = xstrdup(aUrl);
+
 #if URL_CHECKSUM_DEBUG
+
     chksum = url_checksum(url);
+
 #endif
+
     log_url = xstrdup(aLog_url);
+
     object_sz = -1;
-    fd = -1;
+
     /* XXX account log_url */
-    debug(20, 3) ("MemObject::MemObject: initialized %p\n", this);
+
+    swapout.decision = SwapOut::swNeedsCheck;
 }
 
 MemObject::~MemObject()
 {
+    debugs(20, 3, HERE << "del MemObject " << this);
     const Ctx ctx = ctx_enter(url);
-    debug(20, 3) ("destroy_MemObject: destroying %p\n", this);
 #if URL_CHECKSUM_DEBUG
+
     assert(chksum == url_checksum(url));
 #endif
+
     if (!shutting_down)
         assert(swapout.sio == NULL);
+
     data_hdr.freeContent();
+
+#if 0
     /*
      * There is no way to abort FD-less clients, so they might
-     * still have mem->clients set if mem->fd == -1
+     * still have mem->clients set.
      */
-    assert(fd == -1 || clients.head == NULL);
-    httpReplyDestroy((HttpReply *)_reply);
-    requestUnlink(request);
-    request = NULL;
+    assert(clients.head == NULL);
+
+#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);
 }
 
 void
 MemObject::unlinkRequest()
 {
-    /* XXX Should we assert(request)? */
-    requestUnlink(request);
-    request = NULL;
+    HTTPMSGUNLOCK(request);
 }
 
 void
 MemObject::write ( StoreIOBuffer writeBuffer, STMCB *callback, void *callbackData)
 {
-    debug(19, 6) ("memWrite: offset %lu len %ld\n", (unsigned long)writeBuffer.offset, (long)writeBuffer.length);
+    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 
+     * 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);
 }
 
 void
 MemObject::dump() const
 {
-    debug(20, 1) ("MemObject->data.head: %p\n",
-       data_hdr.head);
-    debug(20, 1) ("MemObject->data.tail: %p\n",
-       data_hdr.tail);
+    data_hdr.dump();
 #if 0
     /* do we want this one? */
-    debug(20, 1) ("MemObject->data.origin_offset: %d\n",
-       data_hdr.head ? data_hdr.head->nodeBuffer.offset : 0);
+    debugs(20, 1, "MemObject->data.origin_offset: " << (data_hdr.head ? data_hdr.head->nodeBuffer.offset : 0));
 #endif
-    debug(20, 1) ("MemObject->start_ping: %d.%06d\n",
-       (int) start_ping.tv_sec,
-       (int) start_ping.tv_usec);
-    debug(20, 1) ("MemObject->inmem_hi: %d\n",
-       (int) data_hdr.endOffset());
-    debug(20, 1) ("MemObject->inmem_lo: %d\n",
-       (int) inmem_lo);
-    debug(20, 1) ("MemObject->nclients: %d\n",
-       nclients);
-    debug(20, 1) ("MemObject->reply: %p\n",
-       _reply);
-    debug(20, 1) ("MemObject->request: %p\n",
-       request);
-    debug(20, 1) ("MemObject->log_url: %p %s\n",
-       log_url,
-       checkNullString(log_url));
+
+    debugs(20, 1, "MemObject->start_ping: " << start_ping.tv_sec  << "."<< std::setfill('0') << std::setw(6) << start_ping.tv_usec);
+    debugs(20, 1, "MemObject->inmem_hi: " << data_hdr.endOffset());
+    debugs(20, 1, "MemObject->inmem_lo: " << inmem_lo);
+    debugs(20, 1, "MemObject->nclients: " << nclients);
+    debugs(20, 1, "MemObject->reply: " << _reply);
+    debugs(20, 1, "MemObject->request: " << request);
+    debugs(20, 1, "MemObject->log_url: " << log_url << " " << checkNullString(log_url));
 }
 
 HttpReply const *
@@ -188,56 +189,97 @@ MemObject::getReply() const
     return _reply;
 }
 
-struct LowestMemReader : public unary_function<store_client, void>
+void
+MemObject::replaceHttpReply(HttpReply *newrep)
 {
-    LowestMemReader(off_t seed):current(seed){}
-    void operator() (store_client const &x) 
-      { 
-       if (x.memReaderHasLowerOffset(current))
-           current = x.copyInto.offset; }
-    off_t current;
+    HTTPMSGUNLOCK(_reply);
+    _reply = HTTPMSGLOCK(newrep);
+}
+
+struct LowestMemReader : public unary_function<store_client, void> {
+    LowestMemReader(int64_t seed):current(seed) {}
+
+    void operator() (store_client const &x) {
+        if (x.memReaderHasLowerOffset(current))
+            current = x.copyInto.offset;
+    }
+
+    int64_t current;
 };
 
-struct StoreClientStats : public unary_function<store_client, void>
-{
-    StoreClientStats(StoreEntry *anEntry):where(anEntry),index(0){}
+struct StoreClientStats : public unary_function<store_client, void> {
+    StoreClientStats(MemBuf *anEntry):where(anEntry),index(0) {}
+
     void operator()(store_client const &x) {
-       x.dumpStats(where, index++);
+        x.dumpStats(where, index++);
     }
-    StoreEntry *where;
+
+    MemBuf *where;
     size_t index;
 };
 
 void
-MemObject::stat (StoreEntry *s) const
+MemObject::stat(MemBuf * mb) const
 {
-    storeAppendPrintf(s, "\t%s %s\n",
-       RequestMethodStr[method], log_url);
-    storeAppendPrintf(s, "\tinmem_lo: %d\n", (int) inmem_lo);
-    storeAppendPrintf(s, "\tinmem_hi: %d\n", (int) data_hdr.endOffset());
-    storeAppendPrintf(s, "\tswapout: %d bytes queued\n",
-       (int) swapout.queue_offset);
+    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);
+
     if (swapout.sio.getRaw())
-       storeAppendPrintf(s, "\tswapout: %d bytes written\n",
-           (int) swapout.sio->offset());
-    StoreClientStats statsVisitor(s);
-    for_each(clients, statsVisitor);
+        mb->Printf("\tswapout: %"PRId64" bytes written\n",
+                   (int64_t) swapout.sio->offset());
+
+    StoreClientStats statsVisitor(mb);
+
+    for_each<StoreClientStats>(clients, statsVisitor);
 }
 
-off_t
+int64_t
 MemObject::endOffset () const
 {
     return data_hdr.endOffset();
 }
 
-size_t
+void
+MemObject::markEndOfReplyHeaders()
+{
+    const int hdr_sz = endOffset();
+    assert(hdr_sz >= 0);
+    assert(_reply);
+    _reply->hdr_sz = hdr_sz;
+}
+
+int64_t
 MemObject::size() const
 {
-    if (object_sz < 0) 
-       return endOffset();
+    if (object_sz < 0)
+        return endOffset();
+
     return object_sz;
 }
 
+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
+        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;
+    }
+
+    return -1; // not enough information to predict
+}
+
 void
 MemObject::reset()
 {
@@ -248,13 +290,13 @@ MemObject::reset()
 }
 
 
-off_t
+int64_t
 MemObject::lowestMemReaderOffset() const
 {
     LowestMemReader lowest (endOffset() + 1);
 
-    for_each (clients, lowest);
-    
+    for_each <LowestMemReader>(clients, lowest);
+
     return lowest.current;
 }
 
@@ -262,7 +304,7 @@ MemObject::lowestMemReaderOffset() const
 bool
 MemObject::readAheadPolicyCanRead() const
 {
-    return (size_t)endOffset() - getReply()->hdr_sz < lowestMemReaderOffset() + Config.readAheadGap;
+    return endOffset() - getReply()->hdr_sz < lowestMemReaderOffset() + Config.readAheadGap;
 }
 
 void
@@ -278,18 +320,19 @@ MemObject::checkUrlChecksum () const
 {
     assert(chksum == url_checksum(url));
 }
+
 #endif
 
 /*
  * How much of the object data is on the disk?
  */
-size_t
+int64_t
 MemObject::objectBytesOnDisk() const
 {
     /*
      * NOTE: storeOffset() represents the disk file size,
      * not the amount of object data on disk.
-     * 
+     *
      * If we don't have at least 'swap_hdr_sz' bytes
      * then none of the object data is on disk.
      *
@@ -297,54 +340,64 @@ MemObject::objectBytesOnDisk() const
      * meaning we haven't even opened the swapout file
      * yet.
      */
+
     if (swapout.sio.getRaw() == NULL)
-       return 0;
-    off_t nwritten = swapout.sio->offset();
-    if (nwritten <= (off_t)swap_hdr_sz)
-       return 0;
-    return (size_t) (nwritten - swap_hdr_sz);
+        return 0;
+
+    int64_t nwritten = swapout.sio->offset();
+
+    if (nwritten <= (int64_t)swap_hdr_sz)
+        return 0;
+
+    return (nwritten - swap_hdr_sz);
 }
 
-off_t
-MemObject::policyLowestOffsetToKeep() const
+int64_t
+MemObject::policyLowestOffsetToKeep(bool swap) const
 {
     /*
      * Careful.  lowest_offset can be greater than endOffset(), such
      * as in the case of a range request.
      */
-    off_t lowest_offset = lowestMemReaderOffset();
+    int64_t lowest_offset = lowestMemReaderOffset();
+
     if (endOffset() < lowest_offset ||
-       endOffset() - inmem_lo > (ssize_t)Config.Store.maxInMemObjSize)
-       return lowest_offset;
-    
+            endOffset() - inmem_lo > (int64_t)Config.Store.maxInMemObjSize ||
+            (swap && !Config.onoff.memory_cache_first))
+        return lowest_offset;
+
     return inmem_lo;
 }
 
 void
 MemObject::trimSwappable()
 {
-    off_t new_mem_lo = policyLowestOffsetToKeep();
+    int64_t new_mem_lo = policyLowestOffsetToKeep(1);
     /*
      * We should only free up to what we know has been written
      * to disk, not what has been queued for writing.  Otherwise
      * there will be a chunk of the data which is not in memory
      * and is not yet on disk.
      * The -1 makes sure the page isn't freed until storeSwapOut has
-     * walked to the next page. (mem->swapout.memnode)
+     * walked to the next page.
      */
-    off_t on_disk;
+    int64_t on_disk;
+
     if ((on_disk = objectBytesOnDisk()) - 1 < new_mem_lo)
-       new_mem_lo = on_disk - 1;
+        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);
+
     inmem_lo = new_mem_lo;
 }
 
 void
 MemObject::trimUnSwappable()
 {
-    off_t new_mem_lo = policyLowestOffsetToKeep();
+    int64_t new_mem_lo = policyLowestOffsetToKeep(0);
     assert (new_mem_lo > 0);
 
     data_hdr.freeDataUpto(new_mem_lo);
@@ -355,67 +408,93 @@ MemObject::trimUnSwappable()
 bool
 MemObject::isContiguous() const
 {
-    bool result = data_hdr.hasContigousContentRange (inmem_lo, endOffset());
+    bool result = data_hdr.hasContigousContentRange (Range<int64_t>(inmem_lo, endOffset()));
     /* XXX : make this higher level */
-    debug (19, result ? 2 : 1) ("MemObject::isContiguous: Returning %s\n",
-                               result ? "true" : "false");
+    debugs (19, result ? 4 :3, "MemObject::isContiguous: Returning " << (result ? "true" : "false"));
     return result;
 }
 
 int
 MemObject::mostBytesWanted(int max) const
 {
-#if DELAY_POOLS
-#if 0
-    int i = -1;
-    for (dlink_node *node = clients.head; node; node = node->next) {
-       store_client *sc = (store_client *) node->data;
-       if (!sc->callbackPending())
-           /* not waiting for more data */
-           continue;
-       if (sc->getType() != STORE_MEM_CLIENT)
-           continue;
-       i = sc->delayId.bytesWanted(i, XMIN(sc->copyInto.length, (size_t)max));
-    }
-    return XMAX(i, 0);
-#endif
+#if USE_DELAY_POOLS
     /* identify delay id with largest allowance */
     DelayId largestAllowance = mostBytesAllowed ();
     return largestAllowance.bytesWanted(0, max);
 #else
+
     return max;
 #endif
 }
 
-#if DELAY_POOLS
+void
+MemObject::setNoDelay(bool const newValue)
+{
+#if USE_DELAY_POOLS
+
+    for (dlink_node *node = clients.head; node; node = node->next) {
+        store_client *sc = (store_client *) node->data;
+        sc->delayId.setNoDelay(newValue);
+    }
+
+#endif
+}
+
+void
+MemObject::delayRead(DeferredRead const &aRead)
+{
+    deferredReads.delayRead(aRead);
+}
+
+void
+MemObject::kickReads()
+{
+    deferredReads.kickReads(-1);
+}
+
+#if USE_DELAY_POOLS
 DelayId
 MemObject::mostBytesAllowed() const
 {
     int j;
     int jmax = -1;
     DelayId result;
+
     for (dlink_node *node = clients.head; node; node = node->next) {
-       store_client *sc = (store_client *) node->data;
+        store_client *sc = (store_client *) node->data;
 #if 0
-       /* This test is invalid because the client may be writing data
-        * and thus will want data immediately.
-        * If we include the test, there is a race condition when too much
-        * data is read - if all sc's are writing when a read is scheduled.
-        * XXX: fixme.
-        */
-       if (!sc->callbackPending())
-           /* not waiting for more data */
-           continue;
+        /* This test is invalid because the client may be writing data
+         * and thus will want data immediately.
+         * If we include the test, there is a race condition when too much
+         * data is read - if all sc's are writing when a read is scheduled.
+         * XXX: fixme.
+         */
+
+        if (!sc->callbackPending())
+            /* not waiting for more data */
+            continue;
+
 #endif
-       if (sc->getType() != STORE_MEM_CLIENT)
-           /* reading off disk */
-           continue;
-       j = sc->delayId.bytesWanted(0, sc->copyInto.length);
-       if (j > jmax) {
-           jmax = j;
-           result = sc->delayId;
-       }
+
+        if (sc->getType() != STORE_MEM_CLIENT)
+            /* reading off disk */
+            continue;
+
+        j = sc->delayId.bytesWanted(0, sc->copyInto.length);
+
+        if (j > jmax) {
+            jmax = j;
+            result = sc->delayId;
+        }
     }
+
     return result;
 }
+
 #endif
+
+int64_t
+MemObject::availableForSwapOut() const
+{
+    return endOffset() - swapout.queue_offset;
+}