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(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); }