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