OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/disk_cache/simple/simple_index.h" | 5 #include "net/disk_cache/simple/simple_index.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
14 #include "base/pickle.h" | 14 #include "base/pickle.h" |
15 #include "base/task_runner.h" | 15 #include "base/task_runner.h" |
16 #include "base/threading/worker_pool.h" | 16 #include "base/threading/worker_pool.h" |
17 #include "net/base/net_errors.h" | 17 #include "net/base/net_errors.h" |
18 #include "net/disk_cache/simple/simple_entry_format.h" | 18 #include "net/disk_cache/simple/simple_entry_format.h" |
19 #include "net/disk_cache/simple/simple_index_file.h" | 19 #include "net/disk_cache/simple/simple_index_file.h" |
20 #include "net/disk_cache/simple/simple_util.h" | 20 #include "net/disk_cache/simple/simple_util.h" |
21 | 21 |
22 namespace { | |
23 | |
24 // How many seconds we delay writing the index to disk since the last cache | |
25 // operation has happened. | |
26 const int kWriteToDiskDelaySecs = 20; | |
27 | |
28 // WriteToDisk at lest every 5 minutes. | |
Philippe
2013/04/17 15:39:18
Nit: least.
| |
29 const int kMaxWriteToDiskDelaySecs = 300; | |
30 | |
31 } // namespace | |
32 | |
22 namespace disk_cache { | 33 namespace disk_cache { |
23 | 34 |
24 EntryMetadata::EntryMetadata() : | 35 EntryMetadata::EntryMetadata() : |
25 hash_key_(0), | 36 hash_key_(0), |
26 last_used_time_(0), | 37 last_used_time_(0), |
27 entry_size_(0) | 38 entry_size_(0) |
28 {} | 39 {} |
29 | 40 |
30 | |
31 EntryMetadata::EntryMetadata(uint64 hash_key, | 41 EntryMetadata::EntryMetadata(uint64 hash_key, |
32 base::Time last_used_time, | 42 base::Time last_used_time, |
33 uint64 entry_size) : | 43 uint64 entry_size) : |
34 hash_key_(hash_key), | 44 hash_key_(hash_key), |
35 last_used_time_(last_used_time.ToInternalValue()), | 45 last_used_time_(last_used_time.ToInternalValue()), |
36 entry_size_(entry_size) | 46 entry_size_(entry_size) |
37 {} | 47 {} |
38 | 48 |
39 base::Time EntryMetadata::GetLastUsedTime() const { | 49 base::Time EntryMetadata::GetLastUsedTime() const { |
40 return base::Time::FromInternalValue(last_used_time_); | 50 return base::Time::FromInternalValue(last_used_time_); |
(...skipping 29 matching lines...) Expand all Loading... | |
70 } | 80 } |
71 | 81 |
72 SimpleIndex::SimpleIndex( | 82 SimpleIndex::SimpleIndex( |
73 const scoped_refptr<base::TaskRunner>& cache_thread, | 83 const scoped_refptr<base::TaskRunner>& cache_thread, |
74 const scoped_refptr<base::TaskRunner>& io_thread, | 84 const scoped_refptr<base::TaskRunner>& io_thread, |
75 const base::FilePath& path) | 85 const base::FilePath& path) |
76 : cache_size_(0), | 86 : cache_size_(0), |
77 initialized_(false), | 87 initialized_(false), |
78 index_filename_(path.AppendASCII("simple-index")), | 88 index_filename_(path.AppendASCII("simple-index")), |
79 cache_thread_(cache_thread), | 89 cache_thread_(cache_thread), |
80 io_thread_(io_thread) {} | 90 io_thread_(io_thread) { |
91 } | |
81 | 92 |
82 SimpleIndex::~SimpleIndex() { | 93 SimpleIndex::~SimpleIndex() { |
83 DCHECK(io_thread_checker_.CalledOnValidThread()); | 94 DCHECK(io_thread_checker_.CalledOnValidThread()); |
84 | 95 |
85 } | 96 } |
86 | 97 |
87 void SimpleIndex::Initialize() { | 98 void SimpleIndex::Initialize() { |
88 DCHECK(io_thread_checker_.CalledOnValidThread()); | 99 DCHECK(io_thread_checker_.CalledOnValidThread()); |
89 IndexCompletionCallback merge_callback = | 100 IndexCompletionCallback merge_callback = |
90 base::Bind(&SimpleIndex::MergeInitializingSet, AsWeakPtr()); | 101 base::Bind(&SimpleIndex::MergeInitializingSet, AsWeakPtr()); |
91 base::WorkerPool::PostTask(FROM_HERE, | 102 base::WorkerPool::PostTask(FROM_HERE, |
92 base::Bind(&SimpleIndex::LoadFromDisk, | 103 base::Bind(&SimpleIndex::LoadFromDisk, |
93 index_filename_, | 104 index_filename_, |
94 io_thread_, | 105 io_thread_, |
95 merge_callback), | 106 merge_callback), |
96 true); | 107 true); |
97 } | 108 } |
98 | 109 |
99 void SimpleIndex::Insert(const std::string& key) { | 110 void SimpleIndex::Insert(const std::string& key) { |
100 DCHECK(io_thread_checker_.CalledOnValidThread()); | 111 DCHECK(io_thread_checker_.CalledOnValidThread()); |
101 // Upon insert we don't know yet the size of the entry. | 112 // Upon insert we don't know yet the size of the entry. |
102 // It will be updated later when the SimpleEntryImpl finishes opening or | 113 // It will be updated later when the SimpleEntryImpl finishes opening or |
103 // creating the new entry, and then UpdateEntrySize will be called. | 114 // creating the new entry, and then UpdateEntrySize will be called. |
104 const uint64 hash_key = simple_util::GetEntryHashKey(key); | 115 const uint64 hash_key = simple_util::GetEntryHashKey(key); |
105 InsertInEntrySet(EntryMetadata(hash_key, base::Time::Now(), 0), | 116 InsertInEntrySet(EntryMetadata(hash_key, base::Time::Now(), 0), |
106 &entries_set_); | 117 &entries_set_); |
107 if (!initialized_) | 118 if (!initialized_) |
108 removed_entries_.erase(hash_key); | 119 removed_entries_.erase(hash_key); |
120 PostponeWritingToDisk(); | |
109 } | 121 } |
110 | 122 |
111 void SimpleIndex::Remove(const std::string& key) { | 123 void SimpleIndex::Remove(const std::string& key) { |
112 DCHECK(io_thread_checker_.CalledOnValidThread()); | 124 DCHECK(io_thread_checker_.CalledOnValidThread()); |
113 UpdateEntrySize(key, 0); | 125 UpdateEntrySize(key, 0); |
114 const uint64 hash_key = simple_util::GetEntryHashKey(key); | 126 const uint64 hash_key = simple_util::GetEntryHashKey(key); |
115 entries_set_.erase(hash_key); | 127 entries_set_.erase(hash_key); |
116 | 128 |
117 if (!initialized_) | 129 if (!initialized_) |
118 removed_entries_.insert(hash_key); | 130 removed_entries_.insert(hash_key); |
131 PostponeWritingToDisk(); | |
119 } | 132 } |
120 | 133 |
121 bool SimpleIndex::Has(const std::string& key) const { | 134 bool SimpleIndex::Has(const std::string& key) const { |
122 DCHECK(io_thread_checker_.CalledOnValidThread()); | 135 DCHECK(io_thread_checker_.CalledOnValidThread()); |
123 // If not initialized, always return true, forcing it to go to the disk. | 136 // If not initialized, always return true, forcing it to go to the disk. |
124 return !initialized_ || | 137 return !initialized_ || |
125 entries_set_.count(simple_util::GetEntryHashKey(key)) != 0; | 138 entries_set_.count(simple_util::GetEntryHashKey(key)) != 0; |
126 } | 139 } |
127 | 140 |
128 bool SimpleIndex::UseIfExists(const std::string& key) { | 141 bool SimpleIndex::UseIfExists(const std::string& key) { |
129 DCHECK(io_thread_checker_.CalledOnValidThread()); | 142 DCHECK(io_thread_checker_.CalledOnValidThread()); |
130 // Always update the last used time, even if it is during initialization. | 143 // Always update the last used time, even if it is during initialization. |
131 // It will be merged later. | 144 // It will be merged later. |
132 EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key)); | 145 EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key)); |
133 if (it == entries_set_.end()) | 146 if (it == entries_set_.end()) |
134 // If not initialized, always return true, forcing it to go to the disk. | 147 // If not initialized, always return true, forcing it to go to the disk. |
135 return !initialized_; | 148 return !initialized_; |
136 it->second.SetLastUsedTime(base::Time::Now()); | 149 it->second.SetLastUsedTime(base::Time::Now()); |
150 PostponeWritingToDisk(); | |
137 return true; | 151 return true; |
138 } | 152 } |
139 | 153 |
140 bool SimpleIndex::UpdateEntrySize(const std::string& key, uint64 entry_size) { | 154 bool SimpleIndex::UpdateEntrySize(const std::string& key, uint64 entry_size) { |
141 DCHECK(io_thread_checker_.CalledOnValidThread()); | 155 DCHECK(io_thread_checker_.CalledOnValidThread()); |
142 EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key)); | 156 EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key)); |
143 if (it == entries_set_.end()) | 157 if (it == entries_set_.end()) |
144 return false; | 158 return false; |
145 | 159 |
146 // Update the total cache size with the new entry size. | 160 // Update the total cache size with the new entry size. |
147 cache_size_ -= it->second.GetEntrySize(); | 161 cache_size_ -= it->second.GetEntrySize(); |
148 cache_size_ += entry_size; | 162 cache_size_ += entry_size; |
149 it->second.SetEntrySize(entry_size); | 163 it->second.SetEntrySize(entry_size); |
150 | 164 PostponeWritingToDisk(); |
151 return true; | 165 return true; |
152 } | 166 } |
153 | 167 |
154 // static | 168 // static |
155 void SimpleIndex::InsertInEntrySet( | 169 void SimpleIndex::InsertInEntrySet( |
156 const disk_cache::EntryMetadata& entry_metadata, | 170 const disk_cache::EntryMetadata& entry_metadata, |
157 EntrySet* entry_set) { | 171 EntrySet* entry_set) { |
158 DCHECK(entry_set); | 172 DCHECK(entry_set); |
159 entry_set->insert( | 173 entry_set->insert( |
160 std::make_pair(entry_metadata.GetHashKey(), entry_metadata)); | 174 std::make_pair(entry_metadata.GetHashKey(), entry_metadata)); |
161 } | 175 } |
162 | 176 |
177 void SimpleIndex::PostponeWritingToDisk() { | |
178 const base::TimeDelta file_age = base::Time::Now() - last_write_to_disk_; | |
179 if (file_age > base::TimeDelta::FromSeconds(kMaxWriteToDiskDelaySecs) && | |
180 write_to_disk_timer_.IsRunning()) { | |
181 // If the index file is too old and there is a timer programmed to run a | |
182 // WriteToDisk soon, we don't postpone it, so we always WriteToDisk | |
183 // approximately every kMaxWriteToDiskDelaySecs. | |
184 return; | |
185 } | |
186 | |
187 // If the timer is already active, Start() will just Reset it, postponing it. | |
188 write_to_disk_timer_.Start( | |
189 FROM_HERE, | |
190 base::TimeDelta::FromSeconds(kWriteToDiskDelaySecs), | |
191 base::Bind(&SimpleIndex::WriteToDisk, AsWeakPtr())); | |
192 } | |
193 | |
163 // static | 194 // static |
164 void SimpleIndex::LoadFromDisk( | 195 void SimpleIndex::LoadFromDisk( |
165 const base::FilePath& index_filename, | 196 const base::FilePath& index_filename, |
166 const scoped_refptr<base::TaskRunner>& io_thread, | 197 const scoped_refptr<base::TaskRunner>& io_thread, |
167 const IndexCompletionCallback& completion_callback) { | 198 const IndexCompletionCallback& completion_callback) { |
168 scoped_ptr<EntrySet> index_file_entries = | 199 scoped_ptr<EntrySet> index_file_entries = |
169 SimpleIndexFile::LoadFromDisk(index_filename); | 200 SimpleIndexFile::LoadFromDisk(index_filename); |
170 | 201 |
171 if (!index_file_entries.get()) | 202 bool force_index_flush = false; |
172 index_file_entries = SimpleIndex::RestoreFromDisk(index_filename); | 203 if (!index_file_entries.get()) { |
204 index_file_entries = SimpleIndex::RestoreFromDisk(index_filename); | |
205 // When we restore from disk we write the merged index file to disk right | |
206 // away, this might save us from having to restore again next time. | |
207 force_index_flush = true; | |
208 } | |
173 | 209 |
174 io_thread->PostTask(FROM_HERE, | 210 io_thread->PostTask(FROM_HERE, |
175 base::Bind(completion_callback, | 211 base::Bind(completion_callback, |
176 base::Passed(&index_file_entries))); | 212 base::Passed(&index_file_entries), |
213 force_index_flush)); | |
177 } | 214 } |
178 | 215 |
179 // static | 216 // static |
180 scoped_ptr<SimpleIndex::EntrySet> SimpleIndex::RestoreFromDisk( | 217 scoped_ptr<SimpleIndex::EntrySet> SimpleIndex::RestoreFromDisk( |
181 const base::FilePath& index_filename) { | 218 const base::FilePath& index_filename) { |
182 using file_util::FileEnumerator; | 219 using file_util::FileEnumerator; |
183 LOG(INFO) << "Simple Cache Index is being restored from disk."; | 220 LOG(INFO) << "Simple Cache Index is being restored from disk."; |
184 | 221 |
185 file_util::Delete(index_filename, /* recursive = */ false); | 222 file_util::Delete(index_filename, /* recursive = */ false); |
186 scoped_ptr<EntrySet> index_file_entries(new EntrySet()); | 223 scoped_ptr<EntrySet> index_file_entries(new EntrySet()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
236 return index_file_entries.Pass(); | 273 return index_file_entries.Pass(); |
237 } | 274 } |
238 | 275 |
239 | 276 |
240 // static | 277 // static |
241 void SimpleIndex::WriteToDiskInternal(const base::FilePath& index_filename, | 278 void SimpleIndex::WriteToDiskInternal(const base::FilePath& index_filename, |
242 scoped_ptr<Pickle> pickle) { | 279 scoped_ptr<Pickle> pickle) { |
243 SimpleIndexFile::WriteToDisk(index_filename, *pickle); | 280 SimpleIndexFile::WriteToDisk(index_filename, *pickle); |
244 } | 281 } |
245 | 282 |
246 void SimpleIndex::MergeInitializingSet( | 283 void SimpleIndex::MergeInitializingSet(scoped_ptr<EntrySet> index_file_entries, |
247 scoped_ptr<EntrySet> index_file_entries) { | 284 bool force_index_flush) { |
248 DCHECK(io_thread_checker_.CalledOnValidThread()); | 285 DCHECK(io_thread_checker_.CalledOnValidThread()); |
249 // First, remove the entries that are in the |removed_entries_| from both | 286 // First, remove the entries that are in the |removed_entries_| from both |
250 // sets. | 287 // sets. |
251 for (base::hash_set<uint64>::const_iterator it = | 288 for (base::hash_set<uint64>::const_iterator it = |
252 removed_entries_.begin(); it != removed_entries_.end(); ++it) { | 289 removed_entries_.begin(); it != removed_entries_.end(); ++it) { |
253 entries_set_.erase(*it); | 290 entries_set_.erase(*it); |
254 index_file_entries->erase(*it); | 291 index_file_entries->erase(*it); |
255 } | 292 } |
256 | 293 |
257 // Recalculate the cache size while merging the two sets. | 294 // Recalculate the cache size while merging the two sets. |
258 cache_size_ = 0; | 295 cache_size_ = 0; |
259 for (EntrySet::const_iterator it = index_file_entries->begin(); | 296 for (EntrySet::const_iterator it = index_file_entries->begin(); |
260 it != index_file_entries->end(); ++it) { | 297 it != index_file_entries->end(); ++it) { |
261 // If there is already an entry in the current entries_set_, we need to | 298 // If there is already an entry in the current entries_set_, we need to |
262 // merge the new data there with the data loaded in the initialization. | 299 // merge the new data there with the data loaded in the initialization. |
263 EntrySet::iterator current_entry = entries_set_.find(it->first); | 300 EntrySet::iterator current_entry = entries_set_.find(it->first); |
264 if (current_entry != entries_set_.end()) { | 301 if (current_entry != entries_set_.end()) { |
265 // When Merging, existing valid data in the |current_entry| will prevail. | 302 // When Merging, existing valid data in the |current_entry| will prevail. |
266 current_entry->second.MergeWith(it->second); | 303 current_entry->second.MergeWith(it->second); |
267 cache_size_ += current_entry->second.GetEntrySize(); | 304 cache_size_ += current_entry->second.GetEntrySize(); |
268 } else { | 305 } else { |
269 InsertInEntrySet(it->second, &entries_set_); | 306 InsertInEntrySet(it->second, &entries_set_); |
270 cache_size_ += it->second.GetEntrySize(); | 307 cache_size_ += it->second.GetEntrySize(); |
271 } | 308 } |
272 } | 309 } |
310 last_write_to_disk_ = base::Time::Now(); | |
pasko-google - do not use
2013/04/17 15:38:16
it is already in SimpleIndex::WriteToDisk(), updat
felipeg
2013/04/17 16:00:51
Done.
| |
311 initialized_ = true; | |
312 removed_entries_.clear(); | |
273 | 313 |
274 initialized_ = true; | 314 // The actual IO is asynchronous, so calling WriteToDisk() shouldn't slow down |
315 // much the merge. | |
316 if (force_index_flush) | |
317 WriteToDisk(); | |
275 } | 318 } |
276 | 319 |
277 void SimpleIndex::WriteToDisk() { | 320 void SimpleIndex::WriteToDisk() { |
278 DCHECK(io_thread_checker_.CalledOnValidThread()); | 321 DCHECK(io_thread_checker_.CalledOnValidThread()); |
322 if (!initialized_) | |
323 return; | |
324 last_write_to_disk_ = base::Time::Now(); | |
Philippe
2013/04/17 15:39:18
Do you need this given that you already set the fi
pasko-google - do not use
2013/04/17 15:51:12
this one should be used instead of the one on line
felipeg
2013/04/17 16:00:51
Done.
| |
279 SimpleIndexFile::IndexMetadata index_metadata(entries_set_.size(), | 325 SimpleIndexFile::IndexMetadata index_metadata(entries_set_.size(), |
280 cache_size_); | 326 cache_size_); |
281 scoped_ptr<Pickle> pickle = SimpleIndexFile::Serialize(index_metadata, | 327 scoped_ptr<Pickle> pickle = SimpleIndexFile::Serialize(index_metadata, |
282 entries_set_); | 328 entries_set_); |
283 cache_thread_->PostTask(FROM_HERE, base::Bind( | 329 cache_thread_->PostTask(FROM_HERE, base::Bind( |
284 &SimpleIndex::WriteToDiskInternal, | 330 &SimpleIndex::WriteToDiskInternal, |
285 index_filename_, | 331 index_filename_, |
286 base::Passed(&pickle))); | 332 base::Passed(&pickle))); |
287 } | 333 } |
288 | 334 |
289 } // namespace disk_cache | 335 } // namespace disk_cache |
OLD | NEW |