1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/disk_cache/mem_backend_impl.h" 6 7 #include "base/logging.h" 8 #include "base/sys_info.h" 9 #include "net/base/net_errors.h" 10 #include "net/disk_cache/cache_util.h" 11 #include "net/disk_cache/mem_entry_impl.h" 12 13 using base::Time; 14 15 namespace { 16 17 const int kDefaultCacheSize = 10 * 1024 * 1024; 18 const int kCleanUpMargin = 1024 * 1024; 19 20 int LowWaterAdjust(int high_water) { 21 if (high_water < kCleanUpMargin) 22 return 0; 23 24 return high_water - kCleanUpMargin; 25 } 26 27 } // namespace 28 29 namespace disk_cache { 30 31 MemBackendImpl::MemBackendImpl(net::NetLog* net_log) 32 : max_size_(0), current_size_(0), net_log_(net_log) {} 33 34 MemBackendImpl::~MemBackendImpl() { 35 EntryMap::iterator it = entries_.begin(); 36 while (it != entries_.end()) { 37 it->second->Doom(); 38 it = entries_.begin(); 39 } 40 DCHECK(!current_size_); 41 } 42 43 // Static. 44 Backend* MemBackendImpl::CreateBackend(int max_bytes, net::NetLog* net_log) { 45 MemBackendImpl* cache = new MemBackendImpl(net_log); 46 cache->SetMaxSize(max_bytes); 47 if (cache->Init()) 48 return cache; 49 50 delete cache; 51 LOG(ERROR) << "Unable to create cache"; 52 return NULL; 53 } 54 55 bool MemBackendImpl::Init() { 56 #ifndef ANDROID 57 if (max_size_) 58 return true; 59 60 int64 total_memory = base::SysInfo::AmountOfPhysicalMemory(); 61 62 if (total_memory <= 0) { 63 max_size_ = kDefaultCacheSize; 64 return true; 65 } 66 67 // We want to use up to 2% of the computer's memory, with a limit of 50 MB, 68 // reached on systemd with more than 2.5 GB of RAM. 69 total_memory = total_memory * 2 / 100; 70 if (total_memory > kDefaultCacheSize * 5) 71 max_size_ = kDefaultCacheSize * 5; 72 else 73 max_size_ = static_cast<int32>(total_memory); 74 #else 75 max_size_ = kDefaultCacheSize*3; 76 #endif 77 return true; 78 } 79 80 bool MemBackendImpl::SetMaxSize(int max_bytes) { 81 COMPILE_ASSERT(sizeof(max_bytes) == sizeof(max_size_), unsupported_int_model); 82 if (max_bytes < 0) 83 return false; 84 85 // Zero size means use the default. 86 if (!max_bytes) 87 return true; 88 89 max_size_ = max_bytes; 90 return true; 91 } 92 93 void MemBackendImpl::InternalDoomEntry(MemEntryImpl* entry) { 94 // Only parent entries can be passed into this method. 95 DCHECK(entry->type() == MemEntryImpl::kParentEntry); 96 97 rankings_.Remove(entry); 98 EntryMap::iterator it = entries_.find(entry->GetKey()); 99 if (it != entries_.end()) 100 entries_.erase(it); 101 else 102 NOTREACHED(); 103 104 entry->InternalDoom(); 105 } 106 107 void MemBackendImpl::UpdateRank(MemEntryImpl* node) { 108 rankings_.UpdateRank(node); 109 } 110 111 void MemBackendImpl::ModifyStorageSize(int32 old_size, int32 new_size) { 112 if (old_size >= new_size) 113 SubstractStorageSize(old_size - new_size); 114 else 115 AddStorageSize(new_size - old_size); 116 } 117 118 int MemBackendImpl::MaxFileSize() const { 119 return max_size_ / 8; 120 } 121 122 void MemBackendImpl::InsertIntoRankingList(MemEntryImpl* entry) { 123 rankings_.Insert(entry); 124 } 125 126 void MemBackendImpl::RemoveFromRankingList(MemEntryImpl* entry) { 127 rankings_.Remove(entry); 128 } 129 130 int32 MemBackendImpl::GetEntryCount() const { 131 return static_cast<int32>(entries_.size()); 132 } 133 134 int MemBackendImpl::OpenEntry(const std::string& key, Entry** entry, 135 CompletionCallback* callback) { 136 if (OpenEntry(key, entry)) 137 return net::OK; 138 139 return net::ERR_FAILED; 140 } 141 142 int MemBackendImpl::CreateEntry(const std::string& key, Entry** entry, 143 CompletionCallback* callback) { 144 if (CreateEntry(key, entry)) 145 return net::OK; 146 147 return net::ERR_FAILED; 148 } 149 150 int MemBackendImpl::DoomEntry(const std::string& key, 151 CompletionCallback* callback) { 152 if (DoomEntry(key)) 153 return net::OK; 154 155 return net::ERR_FAILED; 156 } 157 158 int MemBackendImpl::DoomAllEntries(CompletionCallback* callback) { 159 if (DoomAllEntries()) 160 return net::OK; 161 162 return net::ERR_FAILED; 163 } 164 165 int MemBackendImpl::DoomEntriesBetween(const base::Time initial_time, 166 const base::Time end_time, 167 CompletionCallback* callback) { 168 if (DoomEntriesBetween(initial_time, end_time)) 169 return net::OK; 170 171 return net::ERR_FAILED; 172 } 173 174 int MemBackendImpl::DoomEntriesSince(const base::Time initial_time, 175 CompletionCallback* callback) { 176 if (DoomEntriesSince(initial_time)) 177 return net::OK; 178 179 return net::ERR_FAILED; 180 } 181 182 int MemBackendImpl::OpenNextEntry(void** iter, Entry** next_entry, 183 CompletionCallback* callback) { 184 if (OpenNextEntry(iter, next_entry)) 185 return net::OK; 186 187 return net::ERR_FAILED; 188 } 189 190 void MemBackendImpl::EndEnumeration(void** iter) { 191 *iter = NULL; 192 } 193 194 bool MemBackendImpl::OpenEntry(const std::string& key, Entry** entry) { 195 EntryMap::iterator it = entries_.find(key); 196 if (it == entries_.end()) 197 return false; 198 199 it->second->Open(); 200 201 *entry = it->second; 202 return true; 203 } 204 205 bool MemBackendImpl::CreateEntry(const std::string& key, Entry** entry) { 206 EntryMap::iterator it = entries_.find(key); 207 if (it != entries_.end()) 208 return false; 209 210 MemEntryImpl* cache_entry = new MemEntryImpl(this); 211 if (!cache_entry->CreateEntry(key, net_log_)) { 212 delete entry; 213 return false; 214 } 215 216 rankings_.Insert(cache_entry); 217 entries_[key] = cache_entry; 218 219 *entry = cache_entry; 220 return true; 221 } 222 223 bool MemBackendImpl::DoomEntry(const std::string& key) { 224 Entry* entry; 225 if (!OpenEntry(key, &entry)) 226 return false; 227 228 entry->Doom(); 229 entry->Close(); 230 return true; 231 } 232 233 bool MemBackendImpl::DoomAllEntries() { 234 TrimCache(true); 235 return true; 236 } 237 238 bool MemBackendImpl::DoomEntriesBetween(const Time initial_time, 239 const Time end_time) { 240 if (end_time.is_null()) 241 return DoomEntriesSince(initial_time); 242 243 DCHECK(end_time >= initial_time); 244 245 MemEntryImpl* next = rankings_.GetNext(NULL); 246 247 // rankings_ is ordered by last used, this will descend through the cache 248 // and start dooming items before the end_time, and will stop once it reaches 249 // an item used before the initial time. 250 while (next) { 251 MemEntryImpl* node = next; 252 next = rankings_.GetNext(next); 253 254 if (node->GetLastUsed() < initial_time) 255 break; 256 257 if (node->GetLastUsed() < end_time) 258 node->Doom(); 259 } 260 261 return true; 262 } 263 264 bool MemBackendImpl::DoomEntriesSince(const Time initial_time) { 265 for (;;) { 266 // Get the entry in the front. 267 Entry* entry = rankings_.GetNext(NULL); 268 269 // Break the loop when there are no more entries or the entry is too old. 270 if (!entry || entry->GetLastUsed() < initial_time) 271 return true; 272 entry->Doom(); 273 } 274 } 275 276 bool MemBackendImpl::OpenNextEntry(void** iter, Entry** next_entry) { 277 MemEntryImpl* current = reinterpret_cast<MemEntryImpl*>(*iter); 278 MemEntryImpl* node = rankings_.GetNext(current); 279 // We should never return a child entry so iterate until we hit a parent 280 // entry. 281 while (node && node->type() != MemEntryImpl::kParentEntry) { 282 node = rankings_.GetNext(node); 283 } 284 *next_entry = node; 285 *iter = node; 286 287 if (node) 288 node->Open(); 289 290 return NULL != node; 291 } 292 293 void MemBackendImpl::TrimCache(bool empty) { 294 MemEntryImpl* next = rankings_.GetPrev(NULL); 295 296 DCHECK(next); 297 298 int target_size = empty ? 0 : LowWaterAdjust(max_size_); 299 while (current_size_ > target_size && next) { 300 MemEntryImpl* node = next; 301 next = rankings_.GetPrev(next); 302 if (!node->InUse() || empty) { 303 node->Doom(); 304 } 305 } 306 307 return; 308 } 309 310 void MemBackendImpl::AddStorageSize(int32 bytes) { 311 current_size_ += bytes; 312 DCHECK(current_size_ >= 0); 313 314 if (current_size_ > max_size_) 315 TrimCache(false); 316 } 317 318 void MemBackendImpl::SubstractStorageSize(int32 bytes) { 319 current_size_ -= bytes; 320 DCHECK(current_size_ >= 0); 321 } 322 323 } // namespace disk_cache 324