Hello,

    The attached patch contains three fixes related to Vary caching.
These fixes solve some but not all Vary-related problems. The fixes are
extracted from the unofficial bag5s branch on Launchpad but may apply to
trunk and/or v3.[34] as well. Sorry, I did not have the time to check
that and to update related bug reports yet (and I may not be able to do
it soon enough, so I wanted to post these now).

The comments quoted below (extracted from the branch commit log) explain
the details.


HTH,

Alex.


> revno: 12743
> branch nick: bag5s
>   Refuse to cache Vary-controlled objects in shared memory (for now).
>   
>   Shared memory cache code incorrectly assumed that it just needs to keep
>   the response and the STORE_META_STD entry details (because that is what
>   non-shared memory cache seemed to keep). However, non-shared memory
>   cache also keeps MemObject::vary_headers and possibly other meta information
>   that cannot be recovered from STORE_META_STD. Thus, we need to store and
>   load all serialized meta objects in shared memory, just like the disk
>   cache does.
>   
>   Until the above is implemented, we must disable Vary caching in shared 
> memory
>   to avoid "Vary object loop" errors and possibly other problems.


> revno: 12742
> branch nick: bag5s
>   Log failed (due to "Vary object loop" or "URL mismatch") hits as TCP_MISSes.


> revno: 12741
> branch nick: bag5s
>   Do not start storing the vary marker object until its key becomes public
>   or Squid will mark it as "impossible to cache" and will never cache it.

Various fixes making Vary caching work better.
More work is needed to re-enable shared memory caching of Vary responses.

bag5s r12741: Do not start storing the vary marker object until its key becomes public.
bag5s r12742: Log failed (due to "Vary object loop" or "URL mismatch") hits as TCP_MISSes.
bag5s r12743: Refuse to cache Vary-controlled objects in shared memory (for now).

=== modified file 'src/MemStore.cc'
--- src/MemStore.cc	2013-01-20 18:54:42 +0000
+++ src/MemStore.cc	2013-11-08 18:42:40 +0000
@@ -352,40 +352,46 @@ MemStore::considerKeeping(StoreEntry &e)
     }
 
     assert(e.mem_obj);
 
     const int64_t loadedSize = e.mem_obj->endOffset();
     const int64_t expectedSize = e.mem_obj->expectedReplySize();
 
     // objects of unknown size are not allowed into memory cache, for now
     if (expectedSize < 0) {
         debugs(20, 5, HERE << "Unknown expected size: " << e);
         return;
     }
 
     // since we copy everything at once, we can only keep fully loaded entries
     if (loadedSize != expectedSize) {
         debugs(20, 7, HERE << "partially loaded: " << loadedSize << " != " <<
                expectedSize);
         return;
     }
 
+    if (e.mem_obj->vary_headers) {
+        // XXX: We must store/load SerialisedMetaData to cache Vary in RAM
+        debugs(20, 5, "Vary not yet supported: " << e.mem_obj->vary_headers);
+        return;
+    }
+
     keep(e); // may still fail
 }
 
 /// locks map anchor and calls copyToShm to store the entry in shared memory
 void
 MemStore::keep(StoreEntry &e)
 {
     if (!map) {
         debugs(20, 5, HERE << "No map to mem-cache " << e);
         return;
     }
 
     sfileno index = 0;
     Ipc::StoreMapAnchor *slot = map->openForWriting(reinterpret_cast<const cache_key *>(e.key), index);
     if (!slot) {
         debugs(20, 5, HERE << "No room in mem-cache map to index " << e);
         return;
     }
 
     try {

=== modified file 'src/client_side_reply.cc'
--- src/client_side_reply.cc	2013-03-21 21:06:48 +0000
+++ src/client_side_reply.cc	2013-11-08 18:04:33 +0000
@@ -482,71 +482,73 @@ clientReplyContext::cacheHit(StoreIOBuff
         /* the store couldn't get enough data from the file for us to id the
          * object
          */
         /* treat as a miss */
         http->logType = LOG_TCP_MISS;
         processMiss();
         return;
     }
 
     assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));
     /* update size of the request */
     reqsize = result.length + reqofs;
 
     /*
      * Got the headers, now grok them
      */
     assert(http->logType == LOG_TCP_HIT);
 
     if (strcmp(e->mem_obj->url, http->request->storeId()) != 0) {
         debugs(33, DBG_IMPORTANT, "clientProcessHit: URL mismatch, '" << e->mem_obj->url << "' != '" << http->request->storeId() << "'");
+        http->logType = LOG_TCP_MISS; // we lack a more precise LOG_*_MISS code
         processMiss();
         return;
     }
 
     switch (varyEvaluateMatch(e, r)) {
 
     case VARY_NONE:
         /* No variance detected. Continue as normal */
         break;
 
     case VARY_MATCH:
         /* This is the correct entity for this request. Continue */
         debugs(88, 2, "clientProcessHit: Vary MATCH!");
         break;
 
     case VARY_OTHER:
         /* This is not the correct entity for this request. We need
          * to requery the cache.
          */
         removeClientStoreReference(&sc, http);
         e = NULL;
         /* Note: varyEvalyateMatch updates the request with vary information
          * so we only get here once. (it also takes care of cancelling loops)
          */
         debugs(88, 2, "clientProcessHit: Vary detected!");
         clientGetMoreData(ourNode, http);
         return;
 
     case VARY_CANCEL:
         /* varyEvaluateMatch found a object loop. Process as miss */
         debugs(88, DBG_IMPORTANT, "clientProcessHit: Vary object loop!");
+        http->logType = LOG_TCP_MISS; // we lack a more precise LOG_*_MISS code
         processMiss();
         return;
     }
 
     if (r->method == Http::METHOD_PURGE) {
         removeClientStoreReference(&sc, http);
         e = NULL;
         purgeRequest();
         return;
     }
 
     if (e->checkNegativeHit()
             && !r->flags.noCacheHack()
        ) {
         http->logType = LOG_TCP_NEGATIVE_HIT;
         sendMoreData(result);
     } else if (!http->flags.internal && refreshCheckHTTP(e, r)) {
         debugs(88, 5, "clientCacheHit: in refreshCheck() block");
         /*
          * We hold a stale copy; it needs to be validated

=== modified file 'src/store.cc'
--- src/store.cc	2013-03-21 21:06:48 +0000
+++ src/store.cc	2013-11-08 17:50:49 +0000
@@ -772,46 +772,48 @@ StoreEntry::setPublicKey()
             HttpReply *rep = new HttpReply;
             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()) {
                 /* Again, we own this structure layout */
                 rep->header.putStr(HDR_VARY, vary.termedBuf());
                 vary.clean();
             }
 
 #if X_ACCELERATOR_VARY
             vary = mem_obj->getReply()->header.getList(HDR_X_ACCELERATOR_VARY);
 
             if (vary.defined()) {
                 /* Again, we own this structure layout */
                 rep->header.putStr(HDR_X_ACCELERATOR_VARY, vary.termedBuf());
                 vary.clean();
             }
 
 #endif
-            pe->replaceHttpReply(rep);
+            pe->replaceHttpReply(rep, false); // no write until key is public
 
             pe->timestampsSet();
 
             pe->makePublic();
 
+            pe->startWriting(); // after makePublic()
+
             pe->complete();
 
             pe->unlock();
         }
 
         newkey = storeKeyPublicByRequest(mem_obj->request);
     } else
         newkey = storeKeyPublic(mem_obj->url, mem_obj->method);
 
     if ((e2 = (StoreEntry *) hash_lookup(store_table, newkey))) {
         debugs(20, 3, "StoreEntry::setPublicKey: Making old '" << mem_obj->url << "' private.");
         e2->setPrivateKey();
         e2->release();
 
         if (mem_obj->request)
             newkey = storeKeyPublicByRequest(mem_obj->request);
         else
             newkey = storeKeyPublic(mem_obj->url, mem_obj->method);
     }
 

Reply via email to