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