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.
5 #include "net/disk_cache/mem_backend_impl.h"
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"
17 const int kDefaultInMemoryCacheSize
= 10 * 1024 * 1024;
18 const int kCleanUpMargin
= 1024 * 1024;
20 int LowWaterAdjust(int high_water
) {
21 if (high_water
< kCleanUpMargin
)
24 return high_water
- kCleanUpMargin
;
29 namespace disk_cache
{
31 MemBackendImpl::MemBackendImpl(net::NetLog
* net_log
)
32 : max_size_(0), current_size_(0), net_log_(net_log
) {}
34 MemBackendImpl::~MemBackendImpl() {
35 EntryMap::iterator it
= entries_
.begin();
36 while (it
!= entries_
.end()) {
38 it
= entries_
.begin();
40 DCHECK(!current_size_
);
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
);
49 return cache
.PassAs
<Backend
>();
51 LOG(ERROR
) << "Unable to create cache";
52 return scoped_ptr
<Backend
>();
55 bool MemBackendImpl::Init() {
59 int64 total_memory
= base::SysInfo::AmountOfPhysicalMemory();
61 if (total_memory
<= 0) {
62 max_size_
= kDefaultInMemoryCacheSize
;
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;
72 max_size_
= static_cast<int32
>(total_memory
);
77 bool MemBackendImpl::SetMaxSize(int max_bytes
) {
78 COMPILE_ASSERT(sizeof(max_bytes
) == sizeof(max_size_
), unsupported_int_model
);
82 // Zero size means use the default.
86 max_size_
= max_bytes
;
90 void MemBackendImpl::InternalDoomEntry(MemEntryImpl
* entry
) {
91 // Only parent entries can be passed into this method.
92 DCHECK(entry
->type() == MemEntryImpl::kParentEntry
);
94 rankings_
.Remove(entry
);
95 EntryMap::iterator it
= entries_
.find(entry
->GetKey());
96 if (it
!= entries_
.end())
101 entry
->InternalDoom();
104 void MemBackendImpl::UpdateRank(MemEntryImpl
* node
) {
105 rankings_
.UpdateRank(node
);
108 void MemBackendImpl::ModifyStorageSize(int32 old_size
, int32 new_size
) {
109 if (old_size
>= new_size
)
110 SubstractStorageSize(old_size
- new_size
);
112 AddStorageSize(new_size
- old_size
);
115 int MemBackendImpl::MaxFileSize() const {
116 return max_size_
/ 8;
119 void MemBackendImpl::InsertIntoRankingList(MemEntryImpl
* entry
) {
120 rankings_
.Insert(entry
);
123 void MemBackendImpl::RemoveFromRankingList(MemEntryImpl
* entry
) {
124 rankings_
.Remove(entry
);
127 net::CacheType
MemBackendImpl::GetCacheType() const {
128 return net::MEMORY_CACHE
;
131 int32
MemBackendImpl::GetEntryCount() const {
132 return static_cast<int32
>(entries_
.size());
135 int MemBackendImpl::OpenEntry(const std::string
& key
, Entry
** entry
,
136 const CompletionCallback
& callback
) {
137 if (OpenEntry(key
, entry
))
140 return net::ERR_FAILED
;
143 int MemBackendImpl::CreateEntry(const std::string
& key
, Entry
** entry
,
144 const CompletionCallback
& callback
) {
145 if (CreateEntry(key
, entry
))
148 return net::ERR_FAILED
;
151 int MemBackendImpl::DoomEntry(const std::string
& key
,
152 const CompletionCallback
& callback
) {
156 return net::ERR_FAILED
;
159 int MemBackendImpl::DoomAllEntries(const CompletionCallback
& callback
) {
160 if (DoomAllEntries())
163 return net::ERR_FAILED
;
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
))
172 return net::ERR_FAILED
;
175 int MemBackendImpl::DoomEntriesSince(const base::Time initial_time
,
176 const CompletionCallback
& callback
) {
177 if (DoomEntriesSince(initial_time
))
180 return net::ERR_FAILED
;
183 int MemBackendImpl::OpenNextEntry(void** iter
, Entry
** next_entry
,
184 const CompletionCallback
& callback
) {
185 if (OpenNextEntry(iter
, next_entry
))
188 return net::ERR_FAILED
;
191 void MemBackendImpl::EndEnumeration(void** iter
) {
195 void MemBackendImpl::OnExternalCacheHit(const std::string
& key
) {
196 EntryMap::iterator it
= entries_
.find(key
);
197 if (it
!= entries_
.end()) {
198 UpdateRank(it
->second
);
202 bool MemBackendImpl::OpenEntry(const std::string
& key
, Entry
** entry
) {
203 EntryMap::iterator it
= entries_
.find(key
);
204 if (it
== entries_
.end())
213 bool MemBackendImpl::CreateEntry(const std::string
& key
, Entry
** entry
) {
214 EntryMap::iterator it
= entries_
.find(key
);
215 if (it
!= entries_
.end())
218 MemEntryImpl
* cache_entry
= new MemEntryImpl(this);
219 if (!cache_entry
->CreateEntry(key
, net_log_
)) {
224 rankings_
.Insert(cache_entry
);
225 entries_
[key
] = cache_entry
;
227 *entry
= cache_entry
;
231 bool MemBackendImpl::DoomEntry(const std::string
& key
) {
233 if (!OpenEntry(key
, &entry
))
241 bool MemBackendImpl::DoomAllEntries() {
246 bool MemBackendImpl::DoomEntriesBetween(const Time initial_time
,
247 const Time end_time
) {
248 if (end_time
.is_null())
249 return DoomEntriesSince(initial_time
);
251 DCHECK(end_time
>= initial_time
);
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
;
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.
265 if (node
->GetLastUsed() < initial_time
)
268 if (node
->GetLastUsed() < end_time
)
272 node
= rankings_
.GetNext(last_valid
);
278 bool MemBackendImpl::DoomEntriesSince(const Time initial_time
) {
280 // Get the entry in the front.
281 Entry
* entry
= rankings_
.GetNext(NULL
);
283 // Break the loop when there are no more entries or the entry is too old.
284 if (!entry
|| entry
->GetLastUsed() < initial_time
)
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
295 while (node
&& node
->type() != MemEntryImpl::kParentEntry
) {
296 node
= rankings_
.GetNext(node
);
307 void MemBackendImpl::TrimCache(bool empty
) {
308 MemEntryImpl
* next
= rankings_
.GetPrev(NULL
);
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
) {
324 void MemBackendImpl::AddStorageSize(int32 bytes
) {
325 current_size_
+= bytes
;
326 DCHECK_GE(current_size_
, 0);
328 if (current_size_
> max_size_
)
332 void MemBackendImpl::SubstractStorageSize(int32 bytes
) {
333 current_size_
-= bytes
;
334 DCHECK_GE(current_size_
, 0);
337 } // namespace disk_cache