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