# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: henrik@henriknordstrom.net-20090813102833-\ # 32fj8b4jw78a2dph # target_branch: ../memcache # testament_sha1: e84887264655e8bf193f00129f45767b27d62958 # timestamp: 2009-08-13 12:35:48 +0200 # base_revision_id: henrik@henriknordstrom.net-20090813102809-\ # muiiiqhlgun9yi1w # # Begin patch === modified file 'src/MemObject.cc' --- src/MemObject.cc 2009-01-21 03:47:47 +0000 +++ src/MemObject.cc 2009-08-04 02:31:27 +0000 @@ -313,7 +313,7 @@ } int64_t -MemObject::policyLowestOffsetToKeep() const +MemObject::policyLowestOffsetToKeep(bool swap) const { /* * Careful. lowest_offset can be greater than endOffset(), such @@ -322,7 +322,8 @@ int64_t lowest_offset = lowestMemReaderOffset(); if (endOffset() < lowest_offset || - endOffset() - inmem_lo > (int64_t)Config.Store.maxInMemObjSize) + endOffset() - inmem_lo > (int64_t)Config.Store.maxInMemObjSize || + (swap && !Config.onoff.memory_cache_first)) return lowest_offset; return inmem_lo; @@ -331,7 +332,7 @@ void MemObject::trimSwappable() { - int64_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 @@ -356,7 +357,7 @@ void MemObject::trimUnSwappable() { - int64_t new_mem_lo = policyLowestOffsetToKeep(); + int64_t new_mem_lo = policyLowestOffsetToKeep(0); assert (new_mem_lo > 0); data_hdr.freeDataUpto(new_mem_lo); === modified file 'src/MemObject.h' --- src/MemObject.h 2009-03-31 12:39:30 +0000 +++ src/MemObject.h 2009-08-04 02:31:27 +0000 @@ -73,7 +73,7 @@ * better */ int64_t objectBytesOnDisk() const; - int64_t policyLowestOffsetToKeep() const; + int64_t policyLowestOffsetToKeep(bool swap) const; void trimSwappable(); void trimUnSwappable(); bool isContiguous() const; === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2009-08-01 09:48:37 +0000 +++ src/cache_cf.cc 2009-08-04 02:31:27 +0000 @@ -2771,6 +2771,50 @@ storeAppendPrintf(entry, "\n"); } +static void +free_memcachemode(SquidConfig * config) +{ + return; +} + +static void +parse_memcachemode(SquidConfig * config) +{ + char *token = strtok(NULL, w_space); + if (!token) + self_destruct(); + + if (strcmp(token, "always") == 0) { + Config.onoff.memory_cache_first = 1; + Config.onoff.memory_cache_disk = 1; + } else if (strcmp(token, "disk") == 0) { + Config.onoff.memory_cache_first = 0; + Config.onoff.memory_cache_disk = 1; + } else if (strncmp(token, "net", 3) == 0) { + Config.onoff.memory_cache_first = 1; + Config.onoff.memory_cache_disk = 0; + } else if (strcmp(token, "never") == 0) { + Config.onoff.memory_cache_first = 0; + Config.onoff.memory_cache_disk = 0; + } else + self_destruct(); +} + +static void +dump_memcachemode(StoreEntry * entry, const char *name, SquidConfig &config) +{ + storeAppendPrintf(entry, "%s ", name); + if (Config.onoff.memory_cache_first && Config.onoff.memory_cache_disk) + storeAppendPrintf(entry, "always"); + else if (!Config.onoff.memory_cache_first && Config.onoff.memory_cache_disk) + storeAppendPrintf(entry, "disk"); + else if (Config.onoff.memory_cache_first && !Config.onoff.memory_cache_disk) + storeAppendPrintf(entry, "network"); + else if (!Config.onoff.memory_cache_first && !Config.onoff.memory_cache_disk) + storeAppendPrintf(entry, "none"); + storeAppendPrintf(entry, "\n"); +} + #include "cf_parser.h" peer_t === modified file 'src/cf.data.depend' --- src/cf.data.depend 2009-07-13 01:20:26 +0000 +++ src/cf.data.depend 2009-08-04 02:07:56 +0000 @@ -36,6 +36,7 @@ kb_int64_t kb_size_t logformat +memcachemode onoff peer peer_access cache_peer acl === modified file 'src/cf.data.pre' --- src/cf.data.pre 2009-08-07 12:44:51 +0000 +++ src/cf.data.pre 2009-08-13 10:28:33 +0000 @@ -2085,6 +2085,22 @@ enough to keep larger objects from hoarding cache_mem. DOC_END +NAME: memory_cache_mode +TYPE: memcachemode +LOC: Config +DEFAULT: always +DOC_START + Controls which objects to keep in the memory cache (cache_mem) + + always Keep most recently fetched objects in memory (default) + + disk Only disk cache hits are kept in memory, which means + an object must first be cached on disk and then hit + a second time before cached in memory. + + network Only objects fetched from network is kept in memory +DOC_END + NAME: memory_replacement_policy TYPE: removalpolicy LOC: Config.memPolicy === modified file 'src/store.cc' --- src/store.cc 2009-08-01 21:20:37 +0000 +++ src/store.cc 2009-08-04 02:35:11 +0000 @@ -1414,7 +1414,13 @@ if (mem_obj->data_hdr.size() == 0) return 0; - return mem_obj->inmem_lo == 0; + if (mem_obj->inmem_lo != 0) + return 0; + + if (!Config.onoff.memory_cache_first && swap_status == SWAPOUT_DONE && refcount == 1) + return 0; + + return 1; } int @@ -1833,11 +1839,11 @@ if (mem_status == IN_MEMORY) return; - if (mem_obj->policyLowestOffsetToKeep() == 0) - /* Nothing to do */ - return; - if (!swapOutAble()) { + if (!EBIT_TEST(flags, KEY_PRIVATE) && mem_obj->policyLowestOffsetToKeep(0) == 0) { + /* Nothing to do */ + return; + } /* * Its not swap-able, and we're about to delete a chunk, * so we must make it PRIVATE. This is tricky/ugly because === modified file 'src/store_client.cc' --- src/store_client.cc 2009-07-27 21:48:18 +0000 +++ src/store_client.cc 2009-07-29 08:44:07 +0000 @@ -499,7 +499,7 @@ } const HttpReply *rep = entry->getReply(); - if (len > 0 && rep && entry->mem_obj->inmem_lo == 0 && entry->objectLen() <= (int64_t)Config.Store.maxInMemObjSize) { + if (len > 0 && rep && entry->mem_obj->inmem_lo == 0 && entry->objectLen() <= (int64_t)Config.Store.maxInMemObjSize && Config.onoff.memory_cache_disk) { storeGetMemSpace(len); // The above may start to free our object so we need to check again if (entry->mem_obj->inmem_lo == 0) { === modified file 'src/structs.h' --- src/structs.h 2009-07-12 22:56:47 +0000 +++ src/structs.h 2009-07-29 08:44:07 +0000 @@ -444,6 +444,8 @@ #endif /* FOLLOW_X_FORWARDED_FOR */ int WIN32_IpAddrChangeMonitor; + int memory_cache_first; + int memory_cache_disk; } onoff; int forward_max_tries; # Begin bundle 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 NQ6e0T3Mf5lO6Hz/avxGn+BdyRThQkOf8sFI