]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/store.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / store.cc
index 9e9cb3b3bb3e267b1975b00a5173e6aa46c872b7..b4a9939f6a54eb75b62f219cd18e28d342744a8f 100644 (file)
@@ -1,7 +1,5 @@
 
 /*
- * $Id$
- *
  * DEBUG: section 20    Storage Manager
  * AUTHOR: Harvest Derived
  *
  */
 
 #include "squid.h"
+#include "CacheDigest.h"
 #include "CacheManager.h"
 #include "comm/Connection.h"
 #include "ETag.h"
 #include "event.h"
 #include "fde.h"
-#include "Store.h"
-#include "mgr/Registration.h"
-#include "StoreClient.h"
-#include "stmem.h"
+#include "globals.h"
+#include "http.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
-#include "MemObject.h"
 #include "mem_node.h"
+#include "MemObject.h"
+#include "mgr/Registration.h"
+#include "mgr/StoreIoAction.h"
+#include "profiler/Profiler.h"
+#include "repl_modules.h"
+#include "RequestFlags.h"
+#include "SquidConfig.h"
+#include "SquidTime.h"
+#include "Stack.h"
 #include "StatCounters.h"
+#include "stmem.h"
+#include "Store.h"
+#include "store_digest.h"
+#include "store_key_md5.h"
+#include "store_key_md5.h"
+#include "store_log.h"
+#include "store_rebuild.h"
+#include "StoreClient.h"
+#include "StoreIOState.h"
 #include "StoreMeta.h"
+#include "StrList.h"
+#include "swap_log_op.h"
 #include "SwapDir.h"
-#include "StoreIOState.h"
+#include "tools.h"
 #if USE_DELAY_POOLS
 #include "DelayPools.h"
 #endif
-#include "Stack.h"
-#include "SquidTime.h"
-#include "swap_log_op.h"
-#include "mgr/StoreIoAction.h"
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
 
 static STMCB storeWriteComplete;
 
@@ -65,7 +80,6 @@ static STMCB storeWriteComplete;
 
 #define STORE_IN_MEM_BUCKETS            (229)
 
-
 /** \todo Convert these string constants to enum string-arrays generated */
 
 const char *memStatusStr[] = {
@@ -90,7 +104,6 @@ const char *swapStatusStr[] = {
     "SWAPOUT_DONE"
 };
 
-
 /*
  * This defines an repl type
  */
@@ -104,7 +117,6 @@ struct _storerepl_entry {
 
 static storerepl_entry_t *storerepl_list = NULL;
 
-
 /*
  * local function prototypes
  */
@@ -272,12 +284,10 @@ StoreEntry::delayAwareRead(const Comm::ConnectionPointer &conn, char *buf, int l
 }
 
 size_t
-StoreEntry::bytesWanted (Range<size_t> const aRange) const
+StoreEntry::bytesWanted (Range<size_t> const aRange, bool ignoreDelayPools) const
 {
-    assert (aRange.size());
-
     if (mem_obj == NULL)
-        return aRange.end - 1;
+        return aRange.end;
 
 #if URL_CHECKSUM_DEBUG
 
@@ -285,14 +295,10 @@ StoreEntry::bytesWanted (Range<size_t> const aRange) const
 
 #endif
 
-    /* Always read *something* here - we haven't got the header yet */
-    if (EBIT_TEST(flags, ENTRY_FWD_HDR_WAIT))
-        return aRange.end - 1;
-
     if (!mem_obj->readAheadPolicyCanRead())
         return 0;
 
-    return mem_obj->mostBytesWanted(aRange.end - 1);
+    return mem_obj->mostBytesWanted(aRange.end, ignoreDelayPools);
 }
 
 bool
@@ -329,7 +335,7 @@ StoreEntry::storeClientType() const
 
     if (EBIT_TEST(flags, ENTRY_ABORTED)) {
         /* I don't think we should be adding clients to aborted entries */
-        debugs(20, 1, "storeClientType: adding to ENTRY_ABORTED entry");
+        debugs(20, DBG_IMPORTANT, "storeClientType: adding to ENTRY_ABORTED entry");
         return STORE_MEM_CLIENT;
     }
 
@@ -374,32 +380,47 @@ StoreEntry::storeClientType() const
     return STORE_DISK_CLIENT;
 }
 
-StoreEntry::StoreEntry():
+StoreEntry::StoreEntry() :
+        mem_obj(NULL),
         hidden_mem_obj(NULL),
-        swap_file_sz(0)
+        timestamp(-1),
+        lastref(-1),
+        expires(-1),
+        lastmod(-1),
+        swap_file_sz(0),
+        refcount(0),
+        flags(0),
+        swap_filen(-1),
+        swap_dirn(-1),
+        lock_count(0),
+        mem_status(NOT_IN_MEMORY),
+        ping_status(PING_NONE),
+        store_status(STORE_PENDING),
+        swap_status(SWAPOUT_NONE)
 {
     debugs(20, 3, HERE << "new StoreEntry " << this);
-    mem_obj = NULL;
-
-    expires = lastmod = lastref = timestamp = -1;
-
-    swap_status = SWAPOUT_NONE;
-    swap_filen = -1;
-    swap_dirn = -1;
 }
 
-StoreEntry::StoreEntry(const char *aUrl, const char *aLogUrl):
+StoreEntry::StoreEntry(const char *aUrl, const char *aLogUrl) :
+        mem_obj(NULL),
         hidden_mem_obj(NULL),
-        swap_file_sz(0)
+        timestamp(-1),
+        lastref(-1),
+        expires(-1),
+        lastmod(-1),
+        swap_file_sz(0),
+        refcount(0),
+        flags(0),
+        swap_filen(-1),
+        swap_dirn(-1),
+        lock_count(0),
+        mem_status(NOT_IN_MEMORY),
+        ping_status(PING_NONE),
+        store_status(STORE_PENDING),
+        swap_status(SWAPOUT_NONE)
 {
     debugs(20, 3, HERE << "new StoreEntry " << this);
     mem_obj = new MemObject(aUrl, aLogUrl);
-
-    expires = lastmod = lastref = timestamp = -1;
-
-    swap_status = SWAPOUT_NONE;
-    swap_filen = -1;
-    swap_dirn = -1;
 }
 
 StoreEntry::~StoreEntry()
@@ -493,7 +514,6 @@ StoreEntry::hashDelete()
 
 /* -------------------------------------------------------------------------- */
 
-
 /* get rid of memory copy of the object */
 void
 StoreEntry::purgeMem()
@@ -520,7 +540,7 @@ void
 
 StoreEntry::lock()
 {
-    lock_count++;
+    ++lock_count;
     debugs(20, 3, "StoreEntry::lock: key '" << getMD5Text() <<"' count=" <<
            lock_count  );
     lastref = squid_curtime;
@@ -561,7 +581,7 @@ StoreEntry::releaseRequest()
 int
 StoreEntry::unlock()
 {
-    lock_count--;
+    --lock_count;
     debugs(20, 3, "StoreEntry::unlock: key '" << getMD5Text() << "' count=" << lock_count);
 
     if (lock_count)
@@ -578,7 +598,7 @@ StoreEntry::unlock()
     }
 
     if (EBIT_TEST(flags, KEY_PRIVATE))
-        debugs(20, 1, "WARNING: " << __FILE__ << ":" << __LINE__ << ": found KEY_PRIVATE");
+        debugs(20, DBG_IMPORTANT, "WARNING: " << __FILE__ << ":" << __LINE__ << ": found KEY_PRIVATE");
 
     Store::Root().handleIdleEntry(*this); // may delete us
     return 0;
@@ -637,9 +657,9 @@ storeGetPublicByRequest(HttpRequest * req)
 {
     StoreEntry *e = storeGetPublicByRequestMethod(req, req->method);
 
-    if (e == NULL && req->method == METHOD_HEAD)
+    if (e == NULL && req->method == Http::METHOD_HEAD)
         /* We can generate a HEAD reply from a cached GET object */
-        e = storeGetPublicByRequestMethod(req, METHOD_GET);
+        e = storeGetPublicByRequestMethod(req, Http::METHOD_GET);
 
     return e;
 }
@@ -683,7 +703,7 @@ StoreEntry::setPrivateKey()
         mem_obj->id = getKeyCounter();
         newkey = storeKeyPrivate(mem_obj->url, mem_obj->method, mem_obj->id);
     } else {
-        newkey = storeKeyPrivate("JUNK", METHOD_NONE, getKeyCounter());
+        newkey = storeKeyPrivate("JUNK", Http::METHOD_NONE, getKeyCounter());
     }
 
     assert(hash_lookup(store_table, newkey) == NULL);
@@ -715,7 +735,7 @@ StoreEntry::setPublicKey()
 #if MORE_DEBUG_OUTPUT
 
     if (EBIT_TEST(flags, RELEASE_REQUEST))
-        debugs(20, 1, "assertion failed: RELEASE key " << key << ", url " << mem_obj->url);
+        debugs(20, DBG_IMPORTANT, "assertion failed: RELEASE key " << key << ", url " << mem_obj->url);
 
 #endif
 
@@ -756,7 +776,7 @@ StoreEntry::setPublicKey()
             StoreEntry *pe = storeCreateEntry(mem_obj->url, mem_obj->log_url, request->flags, request->method);
             /* We are allowed to do this typecast */
             HttpReply *rep = new HttpReply;
-            rep->setHeaders(HTTP_OK, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000);
+            rep->setHeaders(Http::scOkay, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000);
             vary = mem_obj->getReply()->header.getList(HDR_VARY);
 
             if (vary.size()) {
@@ -813,7 +833,7 @@ StoreEntry::setPublicKey()
 }
 
 StoreEntry *
-storeCreateEntry(const char *url, const char *log_url, request_flags flags, const HttpRequestMethod& method)
+storeCreateEntry(const char *url, const char *log_url, const RequestFlags &flags, const HttpRequestMethod& method)
 {
     StoreEntry *e = NULL;
     MemObject *mem = NULL;
@@ -903,7 +923,6 @@ StoreEntry::append(char const *buf, int len)
     write(tempBuffer);
 }
 
-
 void
 storeAppendPrintf(StoreEntry * e, const char *fmt,...)
 {
@@ -978,36 +997,32 @@ StoreEntry::checkCachable()
 {
 #if CACHE_ALL_METHODS
 
-    if (mem_obj->method != METHOD_GET) {
+    if (mem_obj->method != Http::METHOD_GET) {
         debugs(20, 2, "StoreEntry::checkCachable: NO: non-GET method");
-        store_check_cachable_hist.no.non_get++;
+        ++store_check_cachable_hist.no.non_get;
     } else
 #endif
         if (store_status == STORE_OK && EBIT_TEST(flags, ENTRY_BAD_LENGTH)) {
             debugs(20, 2, "StoreEntry::checkCachable: NO: wrong content-length");
-            store_check_cachable_hist.no.wrong_content_length++;
+            ++store_check_cachable_hist.no.wrong_content_length;
         } else if (!EBIT_TEST(flags, ENTRY_CACHABLE)) {
             debugs(20, 2, "StoreEntry::checkCachable: NO: not cachable");
-            store_check_cachable_hist.no.not_entry_cachable++;
+            ++store_check_cachable_hist.no.not_entry_cachable;
         } else if (EBIT_TEST(flags, ENTRY_NEGCACHED)) {
             debugs(20, 3, "StoreEntry::checkCachable: NO: negative cached");
-            store_check_cachable_hist.no.negative_cached++;
+            ++store_check_cachable_hist.no.negative_cached;
             return 0;           /* avoid release call below */
         } else if ((getReply()->content_length > 0 &&
-                    getReply()->content_length
-                    > Config.Store.maxObjectSize) ||
-                   mem_obj->endOffset() > Config.Store.maxObjectSize) {
-            debugs(20, 2, "StoreEntry::checkCachable: NO: too big");
-            store_check_cachable_hist.no.too_big++;
-        } else if (getReply()->content_length > Config.Store.maxObjectSize) {
+                    getReply()->content_length > store_maxobjsize) ||
+                   mem_obj->endOffset() > store_maxobjsize) {
             debugs(20, 2, "StoreEntry::checkCachable: NO: too big");
-            store_check_cachable_hist.no.too_big++;
+            ++store_check_cachable_hist.no.too_big;
         } else if (checkTooSmall()) {
             debugs(20, 2, "StoreEntry::checkCachable: NO: too small");
-            store_check_cachable_hist.no.too_small++;
+            ++store_check_cachable_hist.no.too_small;
         } else if (EBIT_TEST(flags, KEY_PRIVATE)) {
             debugs(20, 3, "StoreEntry::checkCachable: NO: private key");
-            store_check_cachable_hist.no.private_key++;
+            ++store_check_cachable_hist.no.private_key;
         } else if (swap_status != SWAPOUT_NONE) {
             /*
              * here we checked the swap_status because the remaining
@@ -1017,12 +1032,12 @@ StoreEntry::checkCachable()
             return 1;
         } else if (storeTooManyDiskFilesOpen()) {
             debugs(20, 2, "StoreEntry::checkCachable: NO: too many disk files open");
-            store_check_cachable_hist.no.too_many_open_files++;
+            ++store_check_cachable_hist.no.too_many_open_files;
         } else if (fdNFree() < RESERVED_FD) {
             debugs(20, 2, "StoreEntry::checkCachable: NO: too many FD's open");
-            store_check_cachable_hist.no.too_many_open_fds++;
+            ++store_check_cachable_hist.no.too_many_open_fds;
         } else {
-            store_check_cachable_hist.yes.Default++;
+            ++store_check_cachable_hist.yes.Default;
             return 1;
         }
 
@@ -1113,7 +1128,7 @@ StoreEntry::complete()
 void
 StoreEntry::abort()
 {
-    statCounter.aborted_requests++;
+    ++statCounter.aborted_requests;
     assert(store_status == STORE_PENDING);
     assert(mem_obj != NULL);
     debugs(20, 6, "storeAbort: " << getMD5Text());
@@ -1137,7 +1152,7 @@ StoreEntry::abort()
      */
     if (mem_obj->abort.callback) {
         if (!cbdataReferenceValid(mem_obj->abort.data))
-            debugs(20,1,HERE << "queueing event when abort.data is not valid");
+            debugs(20, DBG_IMPORTANT,HERE << "queueing event when abort.data is not valid");
         eventAdd("mem_obj->abort.callback",
                  mem_obj->abort.callback,
                  mem_obj->abort.data,
@@ -1193,7 +1208,7 @@ storeGetMemSpace(int size)
 
     while ((e = walker->Next(walker))) {
         e->purgeMem();
-        released++;
+        ++released;
 
         if (mem_node::InUseCount() + pages_needed < store_pages_max)
             break;
@@ -1206,7 +1221,6 @@ storeGetMemSpace(int size)
     PROF_stop(storeGetMemSpace);
 }
 
-
 /* thunk through to Store::Root().maintain(). Note that this would be better still
  * if registered against the root store itself, but that requires more complex
  * update logic - bigger fish to fry first. Long term each store when
@@ -1282,7 +1296,7 @@ StoreEntry::release()
              * Fake a call to StoreEntry->lock()  When rebuilding is done,
              * we'll just call StoreEntry->unlock() on these.
              */
-            lock_count++;
+            ++lock_count;
             setReleaseFlag();
             LateReleaseStack.push_back(this);
         } else {
@@ -1321,17 +1335,17 @@ storeLateRelease(void *unused)
         return;
     }
 
-    for (i = 0; i < 10; i++) {
+    for (i = 0; i < 10; ++i) {
         e = LateReleaseStack.count ? LateReleaseStack.pop() : NULL;
 
         if (e == NULL) {
             /* done! */
-            debugs(20, 1, "storeLateRelease: released " << n << " objects");
+            debugs(20, DBG_IMPORTANT, "storeLateRelease: released " << n << " objects");
             return;
         }
 
         e->unlock();
-        n++;
+        ++n;
     }
 
     eventAdd("storeLateRelease", storeLateRelease, NULL, 0.0, 1);
@@ -1383,15 +1397,15 @@ StoreEntry::validLength() const
         return 1;
     }
 
-    if (mem_obj->method == METHOD_HEAD) {
+    if (mem_obj->method == Http::METHOD_HEAD) {
         debugs(20, 5, "storeEntryValidLength: HEAD request: " << getMD5Text());
         return 1;
     }
 
-    if (reply->sline.status == HTTP_NOT_MODIFIED)
+    if (reply->sline.status() == Http::scNotModified)
         return 1;
 
-    if (reply->sline.status == HTTP_NO_CONTENT)
+    if (reply->sline.status() == Http::scNoContent)
         return 1;
 
     diff = reply->hdr_sz + reply->content_length - objectLen();
@@ -1452,14 +1466,6 @@ StoreEntry::memoryCachable() const
     if (!Config.onoff.memory_cache_first && swap_status == SWAPOUT_DONE && refcount == 1)
         return 0;
 
-    if (Config.memShared && IamWorkerProcess()) {
-        const int64_t expectedSize = mem_obj->expectedReplySize();
-        // objects of unknown size are not allowed into memory cache, for now
-        if (expectedSize < 0 ||
-                expectedSize > static_cast<int64_t>(Config.Store.maxInMemObjSize))
-            return 0;
-    }
-
     return 1;
 }
 
@@ -1637,7 +1643,8 @@ StoreEntry::setMemStatus(mem_status_t new_status)
 
     // are we using a shared memory cache?
     if (Config.memShared && IamWorkerProcess()) {
-        assert(new_status != IN_MEMORY); // we do not call this otherwise
+        // enumerate calling cases if shared memory is enabled
+        assert(new_status != IN_MEMORY || EBIT_TEST(flags, ENTRY_SPECIAL));
         // This method was designed to update replacement policy, not to
         // actually purge something from the memory cache (TODO: rename?).
         // Shared memory cache does not have a policy that needs updates.
@@ -1657,7 +1664,7 @@ StoreEntry::setMemStatus(mem_status_t new_status)
             debugs(20, 4, "StoreEntry::setMemStatus: inserted mem node " << mem_obj->url << " key: " << getMD5Text());
         }
 
-        hot_obj_count++; // TODO: maintain for the shared hot cache as well
+        ++hot_obj_count; // TODO: maintain for the shared hot cache as well
     } else {
         if (EBIT_TEST(flags, ENTRY_SPECIAL)) {
             debugs(20, 4, "StoreEntry::setMemStatus: special entry " << mem_obj->url);
@@ -1666,7 +1673,7 @@ StoreEntry::setMemStatus(mem_status_t new_status)
             debugs(20, 4, "StoreEntry::setMemStatus: removed mem node " << mem_obj->url);
         }
 
-        hot_obj_count--;
+        --hot_obj_count;
     }
 
     mem_status = new_status;
@@ -1686,6 +1693,8 @@ StoreEntry::url() const
 void
 StoreEntry::createMemObject(const char *aUrl, const char *aLogUrl)
 {
+    debugs(20, 3, "A mem_obj create attempted using : " << aUrl);
+
     if (mem_obj)
         return;
 
@@ -1774,9 +1783,9 @@ storeReplAdd(const char *type, REMOVALPOLICYCREATE * create)
     int i;
 
     /* find the number of currently known repl types */
-    for (i = 0; storerepl_list && storerepl_list[i].typestr; i++) {
+    for (i = 0; storerepl_list && storerepl_list[i].typestr; ++i) {
         if (strcmp(storerepl_list[i].typestr, type) == 0) {
-            debugs(20, 1, "WARNING: Trying to load store replacement policy " << type << " twice.");
+            debugs(20, DBG_IMPORTANT, "WARNING: Trying to load store replacement policy " << type << " twice.");
             return;
         }
     }
@@ -1799,14 +1808,14 @@ createRemovalPolicy(RemovalPolicySettings * settings)
 {
     storerepl_entry_t *r;
 
-    for (r = storerepl_list; r && r->typestr; r++) {
+    for (r = storerepl_list; r && r->typestr; ++r) {
         if (strcmp(r->typestr, settings->type) == 0)
             return r->create(settings->args);
     }
 
-    debugs(20, 1, "ERROR: Unknown policy " << settings->type);
-    debugs(20, 1, "ERROR: Be sure to have set cache_replacement_policy");
-    debugs(20, 1, "ERROR:   and memory_replacement_policy in squid.conf!");
+    debugs(20, DBG_IMPORTANT, "ERROR: Unknown policy " << settings->type);
+    debugs(20, DBG_IMPORTANT, "ERROR: Be sure to have set cache_replacement_policy");
+    debugs(20, DBG_IMPORTANT, "ERROR:   and memory_replacement_policy in squid.conf!");
     fatalf("ERROR: Unknown policy %s\n", settings->type);
     return NULL;                /* NOTREACHED */
 }
@@ -1832,7 +1841,6 @@ storeSwapFileNumberSet(StoreEntry * e, sfileno filn)
 
 #endif
 
-
 /*
  * Replace a store entry with
  * a new reply. This eats the reply.
@@ -1843,7 +1851,7 @@ StoreEntry::replaceHttpReply(HttpReply *rep, bool andStartWriting)
     debugs(20, 3, "StoreEntry::replaceHttpReply: " << url());
 
     if (!mem_obj) {
-        debugs(20, 0, "Attempt to replace object with no in-memory representation");
+        debugs(20, DBG_CRITICAL, "Attempt to replace object with no in-memory representation");
         return;
     }
 
@@ -1853,7 +1861,6 @@ StoreEntry::replaceHttpReply(HttpReply *rep, bool andStartWriting)
         startWriting();
 }
 
-
 void
 StoreEntry::startWriting()
 {
@@ -1878,7 +1885,6 @@ StoreEntry::startWriting()
     packerClean(&p);
 }
 
-
 char const *
 StoreEntry::getSerialisedMetaData()
 {
@@ -1891,95 +1897,8 @@ StoreEntry::getSerialisedMetaData()
     return result;
 }
 
-bool
-StoreEntry::swapoutPossible()
-{
-    if (!Config.cacheSwap.n_configured)
-        return false;
-
-    /* should we swap something out to disk? */
-    debugs(20, 7, "storeSwapOut: " << url());
-    debugs(20, 7, "storeSwapOut: store_status = " << storeStatusStr[store_status]);
-
-    assert(mem_obj);
-    MemObject::SwapOut::Decision &decision = mem_obj->swapout.decision;
-
-    // if we decided that swapout is not possible, do not repeat same checks
-    if (decision == MemObject::SwapOut::swImpossible) {
-        debugs(20, 3, "storeSwapOut: already rejected");
-        return false;
-    }
-
-    // this flag may change so we must check it even if we already said "yes"
-    if (EBIT_TEST(flags, ENTRY_ABORTED)) {
-        assert(EBIT_TEST(flags, RELEASE_REQUEST));
-        // StoreEntry::abort() already closed the swap out file, if any
-        decision = MemObject::SwapOut::swImpossible;
-        return false;
-    }
-
-    // if we decided that swapout is possible, do not repeat same checks
-    if (decision == MemObject::SwapOut::swPossible) {
-        debugs(20, 3, "storeSwapOut: already allowed");
-        return true;
-    }
-
-    // if we are swapping out already, do not repeat same checks
-    if (swap_status != SWAPOUT_NONE) {
-        debugs(20, 3, "storeSwapOut: already started");
-        decision = MemObject::SwapOut::swPossible;
-        return true;
-    }
-
-    if (!checkCachable()) {
-        debugs(20, 3, "storeSwapOut: not cachable");
-        decision = MemObject::SwapOut::swImpossible;
-        return false;
-    }
-
-    if (EBIT_TEST(flags, ENTRY_SPECIAL)) {
-        debugs(20, 3, "storeSwapOut: " << url() << " SPECIAL");
-        decision = MemObject::SwapOut::swImpossible;
-        return false;
-    }
-
-    // check cache_dir max-size limit if all cache_dirs have it
-    if (store_maxobjsize >= 0) {
-        // TODO: add estimated store metadata size to be conservative
-
-        // use guaranteed maximum if it is known
-        const int64_t expectedEnd = mem_obj->expectedReplySize();
-        debugs(20, 7, "storeSwapOut: expectedEnd = " << expectedEnd);
-        if (expectedEnd > store_maxobjsize) {
-            debugs(20, 3, "storeSwapOut: will not fit: " << expectedEnd <<
-                   " > " << store_maxobjsize);
-            decision = MemObject::SwapOut::swImpossible;
-            return false; // known to outgrow the limit eventually
-        }
-
-        // use current minimum (always known)
-        const int64_t currentEnd = mem_obj->endOffset();
-        if (currentEnd > store_maxobjsize) {
-            debugs(20, 3, "storeSwapOut: does not fit: " << currentEnd <<
-                   " > " << store_maxobjsize);
-            decision = MemObject::SwapOut::swImpossible;
-            return false; // already does not fit and may only get bigger
-        }
-
-        // prevent default swPossible answer for yet unknown length
-        if (expectedEnd < 0) {
-            debugs(20, 3, "storeSwapOut: wait for more info: " <<
-                   store_maxobjsize);
-            return false; // may fit later, but will be rejected now
-        }
-    }
-
-    decision = MemObject::SwapOut::swPossible;
-    return true;
-}
-
 void
-StoreEntry::trimMemory()
+StoreEntry::trimMemory(const bool preserveSwappable)
 {
     /*
      * DPW 2007-05-09
@@ -1989,7 +1908,10 @@ StoreEntry::trimMemory()
     if (mem_status == IN_MEMORY)
         return;
 
-    if (!swapOutAble()) {
+    if (EBIT_TEST(flags, ENTRY_SPECIAL))
+        return; // cannot trim because we do not load them again
+
+    if (!preserveSwappable) {
         if (mem_obj->policyLowestOffsetToKeep(0) == 0) {
             /* Nothing to do */
             return;
@@ -2046,6 +1968,17 @@ StoreEntry::modifiedSince(HttpRequest * request) const
     }
 }
 
+bool
+StoreEntry::hasEtag(ETag &etag) const
+{
+    if (const HttpReply *reply = getReply()) {
+        etag = reply->header.getETag(HDR_ETAG);
+        if (etag.str)
+            return true;
+    }
+    return false;
+}
+
 bool
 StoreEntry::hasIfMatchEtag(const HttpRequest &request) const
 {
@@ -2058,8 +1991,8 @@ StoreEntry::hasIfNoneMatchEtag(const HttpRequest &request) const
 {
     const String reqETags = request.header.getList(HDR_IF_NONE_MATCH);
     // weak comparison is allowed only for HEAD or full-body GET requests
-    const bool allowWeakMatch = !request.flags.range &&
-                                (request.method == METHOD_GET || request.method == METHOD_HEAD);
+    const bool allowWeakMatch = !request.flags.isRanged &&
+                                (request.method == Http::METHOD_GET || request.method == Http::METHOD_HEAD);
     return hasOneOfEtags(reqETags, allowWeakMatch);
 }