Chromium Code Reviews| 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 |