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/memory/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/memory/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
), weak_factory_(this) {
35 MemBackendImpl::~MemBackendImpl() {
36 EntryMap::iterator it
= entries_
.begin();
37 while (it
!= entries_
.end()) {
39 it
= entries_
.begin();
41 DCHECK(!current_size_
);
45 scoped_ptr
<Backend
> MemBackendImpl::CreateBackend(int max_bytes
,
46 net::NetLog
* net_log
) {
47 scoped_ptr
<MemBackendImpl
> cache(new MemBackendImpl(net_log
));
48 cache
->SetMaxSize(max_bytes
);
52 LOG(ERROR
) << "Unable to create cache";
56 bool MemBackendImpl::Init() {
60 int64 total_memory
= base::SysInfo::AmountOfPhysicalMemory();
62 if (total_memory
<= 0) {
63 max_size_
= kDefaultInMemoryCacheSize
;
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
> kDefaultInMemoryCacheSize
* 5)
71 max_size_
= kDefaultInMemoryCacheSize
* 5;
73 max_size_
= static_cast<int32
>(total_memory
);
78 bool MemBackendImpl::SetMaxSize(int max_bytes
) {
79 static_assert(sizeof(max_bytes
) == sizeof(max_size_
),
80 "unsupported int model");
84 // Zero size means use the default.
88 max_size_
= max_bytes
;
92 void MemBackendImpl::InternalDoomEntry(MemEntryImpl
* entry
) {
93 // Only parent entries can be passed into this method.
94 DCHECK(entry
->type() == MemEntryImpl::kParentEntry
);
96 rankings_
.Remove(entry
);
97 EntryMap::iterator it
= entries_
.find(entry
->GetKey());
98 if (it
!= entries_
.end())
103 entry
->InternalDoom();
106 void MemBackendImpl::UpdateRank(MemEntryImpl
* node
) {
107 rankings_
.UpdateRank(node
);
110 void MemBackendImpl::ModifyStorageSize(int32 old_size
, int32 new_size
) {
111 if (old_size
>= new_size
)
112 SubstractStorageSize(old_size
- new_size
);
114 AddStorageSize(new_size
- old_size
);
117 int MemBackendImpl::MaxFileSize() const {
118 return max_size_
/ 8;
121 void MemBackendImpl::InsertIntoRankingList(MemEntryImpl
* entry
) {
122 rankings_
.Insert(entry
);
125 void MemBackendImpl::RemoveFromRankingList(MemEntryImpl
* entry
) {
126 rankings_
.Remove(entry
);
129 net::CacheType
MemBackendImpl::GetCacheType() const {
130 return net::MEMORY_CACHE
;
133 int32
MemBackendImpl::GetEntryCount() const {
134 return static_cast<int32
>(entries_
.size());
137 int MemBackendImpl::OpenEntry(const std::string
& key
, Entry
** entry
,
138 const CompletionCallback
& callback
) {
139 if (OpenEntry(key
, entry
))
142 return net::ERR_FAILED
;
145 int MemBackendImpl::CreateEntry(const std::string
& key
, Entry
** entry
,
146 const CompletionCallback
& callback
) {
147 if (CreateEntry(key
, entry
))
150 return net::ERR_FAILED
;
153 int MemBackendImpl::DoomEntry(const std::string
& key
,
154 const CompletionCallback
& callback
) {
158 return net::ERR_FAILED
;
161 int MemBackendImpl::DoomAllEntries(const CompletionCallback
& callback
) {
162 if (DoomAllEntries())
165 return net::ERR_FAILED
;
168 int MemBackendImpl::DoomEntriesBetween(const base::Time initial_time
,
169 const base::Time end_time
,
170 const CompletionCallback
& callback
) {
171 if (DoomEntriesBetween(initial_time
, end_time
))
174 return net::ERR_FAILED
;
177 int MemBackendImpl::DoomEntriesSince(const base::Time initial_time
,
178 const CompletionCallback
& callback
) {
179 if (DoomEntriesSince(initial_time
))
182 return net::ERR_FAILED
;
185 class MemBackendImpl::MemIterator
: public Backend::Iterator
{
187 explicit MemIterator(base::WeakPtr
<MemBackendImpl
> backend
)
188 : backend_(backend
), current_(NULL
) {
191 int OpenNextEntry(Entry
** next_entry
,
192 const CompletionCallback
& callback
) override
{
194 return net::ERR_FAILED
;
196 MemEntryImpl
* node
= backend_
->rankings_
.GetNext(current_
);
197 // We should never return a child entry so iterate until we hit a parent
199 while (node
&& node
->type() != MemEntryImpl::kParentEntry
)
200 node
= backend_
->rankings_
.GetNext(node
);
208 return net::ERR_FAILED
;
212 base::WeakPtr
<MemBackendImpl
> backend_
;
213 MemEntryImpl
* current_
;
216 scoped_ptr
<Backend::Iterator
> MemBackendImpl::CreateIterator() {
217 return scoped_ptr
<Backend::Iterator
>(
218 new MemIterator(weak_factory_
.GetWeakPtr()));
221 void MemBackendImpl::OnExternalCacheHit(const std::string
& key
) {
222 EntryMap::iterator it
= entries_
.find(key
);
223 if (it
!= entries_
.end()) {
224 UpdateRank(it
->second
);
228 bool MemBackendImpl::OpenEntry(const std::string
& key
, Entry
** entry
) {
229 EntryMap::iterator it
= entries_
.find(key
);
230 if (it
== entries_
.end())
239 bool MemBackendImpl::CreateEntry(const std::string
& key
, Entry
** entry
) {
240 EntryMap::iterator it
= entries_
.find(key
);
241 if (it
!= entries_
.end())
244 MemEntryImpl
* cache_entry
= new MemEntryImpl(this);
245 if (!cache_entry
->CreateEntry(key
, net_log_
)) {
250 rankings_
.Insert(cache_entry
);
251 entries_
[key
] = cache_entry
;
253 *entry
= cache_entry
;
257 bool MemBackendImpl::DoomEntry(const std::string
& key
) {
259 if (!OpenEntry(key
, &entry
))
267 bool MemBackendImpl::DoomAllEntries() {
272 bool MemBackendImpl::DoomEntriesBetween(const Time initial_time
,
273 const Time end_time
) {
274 if (end_time
.is_null())
275 return DoomEntriesSince(initial_time
);
277 DCHECK(end_time
>= initial_time
);
279 MemEntryImpl
* node
= rankings_
.GetNext(NULL
);
280 // Last valid entry before |node|.
281 // Note, that entries after |node| may become invalid during |node| doom in
282 // case when they are child entries of it. It is guaranteed that
283 // parent node will go prior to it childs in ranking list (see
284 // InternalReadSparseData and InternalWriteSparseData).
285 MemEntryImpl
* last_valid
= NULL
;
287 // rankings_ is ordered by last used, this will descend through the cache
288 // and start dooming items before the end_time, and will stop once it reaches
289 // an item used before the initial time.
291 if (node
->GetLastUsed() < initial_time
)
294 if (node
->GetLastUsed() < end_time
)
298 node
= rankings_
.GetNext(last_valid
);
304 bool MemBackendImpl::DoomEntriesSince(const Time initial_time
) {
306 // Get the entry in the front.
307 Entry
* entry
= rankings_
.GetNext(NULL
);
309 // Break the loop when there are no more entries or the entry is too old.
310 if (!entry
|| entry
->GetLastUsed() < initial_time
)
316 void MemBackendImpl::TrimCache(bool empty
) {
317 MemEntryImpl
* next
= rankings_
.GetPrev(NULL
);
321 int target_size
= empty
? 0 : LowWaterAdjust(max_size_
);
322 while (current_size_
> target_size
&& next
) {
323 MemEntryImpl
* node
= next
;
324 next
= rankings_
.GetPrev(next
);
325 if (!node
->InUse() || empty
) {
333 void MemBackendImpl::AddStorageSize(int32 bytes
) {
334 current_size_
+= bytes
;
335 DCHECK_GE(current_size_
, 0);
337 if (current_size_
> max_size_
)
341 void MemBackendImpl::SubstractStorageSize(int32 bytes
) {
342 current_size_
-= bytes
;
343 DCHECK_GE(current_size_
, 0);
346 } // namespace disk_cache