blob: c3d3a266d4e8b6092b7bad15090a7c5bf554eaec [file] [log] [blame]
[email protected]658c1732009-06-15 20:41:301// Copyright (c) 2006-2009 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]408d35f52008-08-13 18:30:229#include "net/disk_cache/cache_util.h"
initial.commit586acc5fe2008-07-26 22:42:5210#include "net/disk_cache/mem_entry_impl.h"
11
[email protected]e1acf6f2008-10-27 20:43:3312using base::Time;
13
initial.commit586acc5fe2008-07-26 22:42:5214namespace {
15
16const int kDefaultCacheSize = 10 * 1024 * 1024;
17const int kCleanUpMargin = 1024 * 1024;
18
19int LowWaterAdjust(int high_water) {
20 if (high_water < kCleanUpMargin)
21 return 0;
22
23 return high_water - kCleanUpMargin;
24}
25
26} // namespace
27
28namespace disk_cache {
29
30Backend* CreateInMemoryCacheBackend(int max_bytes) {
31 MemBackendImpl* cache = new MemBackendImpl();
32 cache->SetMaxSize(max_bytes);
33 if (cache->Init())
34 return cache;
35
36 delete cache;
37 LOG(ERROR) << "Unable to create cache";
38 return NULL;
39}
40
41// ------------------------------------------------------------------------
42
43bool 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
102bool MemBackendImpl::CreateEntry(const std::string& key, Entry** entry) {
103 EntryMap::iterator it = entries_.find(key);
104 if (it != entries_.end())
105 return false;
106
107 MemEntryImpl* cache_entry = new MemEntryImpl(this);
108 if (!cache_entry->CreateEntry(key)) {
109 delete entry;
110 return false;
111 }
112
113 rankings_.Insert(cache_entry);
114 entries_[key] = cache_entry;
115
116 *entry = cache_entry;
117 return true;
118}
119
120bool MemBackendImpl::DoomEntry(const std::string& key) {
121 Entry* entry;
122 if (!OpenEntry(key, &entry))
123 return false;
124
125 entry->Doom();
126 entry->Close();
127 return true;
128}
129
130void MemBackendImpl::InternalDoomEntry(MemEntryImpl* entry) {
[email protected]658c1732009-06-15 20:41:30131 // Only parent entries can be passed into this method.
132 DCHECK(entry->type() == MemEntryImpl::kParentEntry);
133
initial.commit586acc5fe2008-07-26 22:42:52134 rankings_.Remove(entry);
135 EntryMap::iterator it = entries_.find(entry->GetKey());
136 if (it != entries_.end())
137 entries_.erase(it);
138 else
139 NOTREACHED();
140
141 entry->InternalDoom();
142}
143
144bool MemBackendImpl::DoomAllEntries() {
145 TrimCache(true);
146 return true;
147}
148
149bool MemBackendImpl::DoomEntriesBetween(const Time initial_time,
150 const Time end_time) {
151 if (end_time.is_null())
152 return DoomEntriesSince(initial_time);
153
154 DCHECK(end_time >= initial_time);
155
156 MemEntryImpl* next = rankings_.GetNext(NULL);
157
158 // rankings_ is ordered by last used, this will descend through the cache
159 // and start dooming items before the end_time, and will stop once it reaches
160 // an item used before the initial time.
161 while (next) {
162 MemEntryImpl* node = next;
163 next = rankings_.GetNext(next);
164
165 if (node->GetLastUsed() < initial_time)
166 break;
167
[email protected]658c1732009-06-15 20:41:30168 if (node->GetLastUsed() < end_time)
initial.commit586acc5fe2008-07-26 22:42:52169 node->Doom();
initial.commit586acc5fe2008-07-26 22:42:52170 }
171
172 return true;
173}
174
initial.commit586acc5fe2008-07-26 22:42:52175bool MemBackendImpl::DoomEntriesSince(const Time initial_time) {
176 for (;;) {
[email protected]658c1732009-06-15 20:41:30177 // Get the entry in the front.
178 Entry* entry = rankings_.GetNext(NULL);
initial.commit586acc5fe2008-07-26 22:42:52179
[email protected]658c1732009-06-15 20:41:30180 // Break the loop when there are no more entries or the entry is too old.
181 if (!entry || entry->GetLastUsed() < initial_time)
initial.commit586acc5fe2008-07-26 22:42:52182 return true;
initial.commit586acc5fe2008-07-26 22:42:52183 entry->Doom();
initial.commit586acc5fe2008-07-26 22:42:52184 }
185}
186
187bool MemBackendImpl::OpenNextEntry(void** iter, Entry** next_entry) {
188 MemEntryImpl* current = reinterpret_cast<MemEntryImpl*>(*iter);
189 MemEntryImpl* node = rankings_.GetNext(current);
[email protected]658c1732009-06-15 20:41:30190 // We should never return a child entry so iterate until we hit a parent
191 // entry.
192 while (node && node->type() != MemEntryImpl::kParentEntry) {
193 node = rankings_.GetNext(node);
194 }
initial.commit586acc5fe2008-07-26 22:42:52195 *next_entry = node;
196 *iter = node;
197
198 if (node)
199 node->Open();
200
201 return NULL != node;
202}
203
204void MemBackendImpl::EndEnumeration(void** iter) {
205 *iter = NULL;
206}
207
208void MemBackendImpl::TrimCache(bool empty) {
209 MemEntryImpl* next = rankings_.GetPrev(NULL);
210
211 DCHECK(next);
212
213 int target_size = empty ? 0 : LowWaterAdjust(max_size_);
214 while (current_size_ > target_size && next) {
215 MemEntryImpl* node = next;
216 next = rankings_.GetPrev(next);
217 if (!node->InUse() || empty) {
218 node->Doom();
219 }
220 }
221
222 return;
223}
224
225void MemBackendImpl::AddStorageSize(int32 bytes) {
226 current_size_ += bytes;
227 DCHECK(current_size_ >= 0);
228
229 if (current_size_ > max_size_)
230 TrimCache(false);
231}
232
233void MemBackendImpl::SubstractStorageSize(int32 bytes) {
234 current_size_ -= bytes;
235 DCHECK(current_size_ >= 0);
236}
237
238void MemBackendImpl::ModifyStorageSize(int32 old_size, int32 new_size) {
239 if (old_size >= new_size)
240 SubstractStorageSize(old_size - new_size);
241 else
242 AddStorageSize(new_size - old_size);
243}
244
245void MemBackendImpl::UpdateRank(MemEntryImpl* node) {
246 rankings_.UpdateRank(node);
247}
248
249int MemBackendImpl::MaxFileSize() const {
250 return max_size_ / 8;
251}
252
[email protected]658c1732009-06-15 20:41:30253void MemBackendImpl::InsertIntoRankingList(MemEntryImpl* entry) {
254 rankings_.Insert(entry);
255}
256
257void MemBackendImpl::RemoveFromRankingList(MemEntryImpl* entry) {
258 rankings_.Remove(entry);
259}
260
initial.commit586acc5fe2008-07-26 22:42:52261} // namespace disk_cache