| 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 |