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
LowWaterAdjust(int high_water)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
MemBackendImpl(net::NetLog * net_log)31 MemBackendImpl::MemBackendImpl(net::NetLog* net_log)
32 : max_size_(0), current_size_(0), net_log_(net_log) {}
33
~MemBackendImpl()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.
CreateBackend(int max_bytes,net::NetLog * net_log)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
Init()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
SetMaxSize(int max_bytes)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
InternalDoomEntry(MemEntryImpl * entry)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
UpdateRank(MemEntryImpl * node)107 void MemBackendImpl::UpdateRank(MemEntryImpl* node) {
108 rankings_.UpdateRank(node);
109 }
110
ModifyStorageSize(int32 old_size,int32 new_size)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
MaxFileSize() const118 int MemBackendImpl::MaxFileSize() const {
119 return max_size_ / 8;
120 }
121
InsertIntoRankingList(MemEntryImpl * entry)122 void MemBackendImpl::InsertIntoRankingList(MemEntryImpl* entry) {
123 rankings_.Insert(entry);
124 }
125
RemoveFromRankingList(MemEntryImpl * entry)126 void MemBackendImpl::RemoveFromRankingList(MemEntryImpl* entry) {
127 rankings_.Remove(entry);
128 }
129
GetEntryCount() const130 int32 MemBackendImpl::GetEntryCount() const {
131 return static_cast<int32>(entries_.size());
132 }
133
OpenEntry(const std::string & key,Entry ** entry,CompletionCallback * callback)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
CreateEntry(const std::string & key,Entry ** entry,CompletionCallback * callback)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
DoomEntry(const std::string & key,CompletionCallback * callback)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
DoomAllEntries(CompletionCallback * callback)158 int MemBackendImpl::DoomAllEntries(CompletionCallback* callback) {
159 if (DoomAllEntries())
160 return net::OK;
161
162 return net::ERR_FAILED;
163 }
164
DoomEntriesBetween(const base::Time initial_time,const base::Time end_time,CompletionCallback * callback)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
DoomEntriesSince(const base::Time initial_time,CompletionCallback * callback)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
OpenNextEntry(void ** iter,Entry ** next_entry,CompletionCallback * callback)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
EndEnumeration(void ** iter)190 void MemBackendImpl::EndEnumeration(void** iter) {
191 *iter = NULL;
192 }
193
OpenEntry(const std::string & key,Entry ** entry)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
CreateEntry(const std::string & key,Entry ** entry)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
DoomEntry(const std::string & key)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
DoomAllEntries()233 bool MemBackendImpl::DoomAllEntries() {
234 TrimCache(true);
235 return true;
236 }
237
DoomEntriesBetween(const Time initial_time,const Time end_time)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
DoomEntriesSince(const Time initial_time)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
OpenNextEntry(void ** iter,Entry ** next_entry)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
TrimCache(bool empty)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
AddStorageSize(int32 bytes)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
SubstractStorageSize(int32 bytes)318 void MemBackendImpl::SubstractStorageSize(int32 bytes) {
319 current_size_ -= bytes;
320 DCHECK(current_size_ >= 0);
321 }
322
323 } // namespace disk_cache
324