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