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