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 | |
|
Philippe
2013/04/22 11:35:48
Nit: change not needed.
felipeg
2013/04/22 16:14:32
Done.
| |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 // How many seconds we delay writing the index to disk since the last cache | 25 // How many seconds we delay writing the index to disk since the last cache |
| 25 // operation has happened. | 26 // operation has happened. |
| 26 const int kWriteToDiskDelaySecs = 20; | 27 const int kWriteToDiskDelay_ms = 20000; |
|
Philippe
2013/04/22 11:35:48
Nit: s/_ms/MSecs here and below.
felipeg
2013/04/22 16:14:32
Done.
| |
| 27 | 28 const int kWriteToDiskOnBackgroundDelay_ms = 100; |
| 28 // WriteToDisk at lest every 5 minutes. | |
| 29 const int kMaxWriteToDiskDelaySecs = 300; | |
| 30 | 29 |
| 31 } // namespace | 30 } // namespace |
| 32 | 31 |
| 33 namespace disk_cache { | 32 namespace disk_cache { |
| 34 | 33 |
| 35 EntryMetadata::EntryMetadata() : hash_key_(0), | 34 EntryMetadata::EntryMetadata() : hash_key_(0), |
| 36 last_used_time_(0), | 35 last_used_time_(0), |
| 37 entry_size_(0) { | 36 entry_size_(0) { |
| 38 } | 37 } |
| 39 | 38 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 } | 78 } |
| 80 | 79 |
| 81 SimpleIndex::SimpleIndex( | 80 SimpleIndex::SimpleIndex( |
| 82 base::SingleThreadTaskRunner* cache_thread, | 81 base::SingleThreadTaskRunner* cache_thread, |
| 83 base::SingleThreadTaskRunner* io_thread, | 82 base::SingleThreadTaskRunner* io_thread, |
| 84 const base::FilePath& path) | 83 const base::FilePath& path) |
| 85 : cache_size_(0), | 84 : cache_size_(0), |
| 86 initialized_(false), | 85 initialized_(false), |
| 87 index_filename_(path.AppendASCII("simple-index")), | 86 index_filename_(path.AppendASCII("simple-index")), |
| 88 cache_thread_(cache_thread), | 87 cache_thread_(cache_thread), |
| 89 io_thread_(io_thread) { | 88 io_thread_(io_thread), |
| 89 #if defined(OS_ANDROID) | |
| 90 activity_status_notifier_( | |
| 91 io_thread, | |
| 92 base::Bind(&SimpleIndex::ActivityStatusChanged, AsWeakPtr())), | |
| 93 #endif | |
| 94 app_on_background_(false) { | |
| 90 } | 95 } |
| 91 | 96 |
| 92 SimpleIndex::~SimpleIndex() { | 97 SimpleIndex::~SimpleIndex() { |
| 93 DCHECK(io_thread_checker_.CalledOnValidThread()); | 98 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 94 | 99 |
| 95 // Fail all callbacks waiting for the index to come up. | 100 // Fail all callbacks waiting for the index to come up. |
| 96 for (CallbackList::iterator it = to_run_when_initialized_.begin(), | 101 for (CallbackList::iterator it = to_run_when_initialized_.begin(), |
| 97 end = to_run_when_initialized_.end(); it != end; ++it) { | 102 end = to_run_when_initialized_.end(); it != end; ++it) { |
| 98 it->Run(net::ERR_ABORTED); | 103 it->Run(net::ERR_ABORTED); |
| 99 } | 104 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 207 // static | 212 // static |
| 208 void SimpleIndex::InsertInEntrySet( | 213 void SimpleIndex::InsertInEntrySet( |
| 209 const disk_cache::EntryMetadata& entry_metadata, | 214 const disk_cache::EntryMetadata& entry_metadata, |
| 210 EntrySet* entry_set) { | 215 EntrySet* entry_set) { |
| 211 DCHECK(entry_set); | 216 DCHECK(entry_set); |
| 212 entry_set->insert( | 217 entry_set->insert( |
| 213 std::make_pair(entry_metadata.GetHashKey(), entry_metadata)); | 218 std::make_pair(entry_metadata.GetHashKey(), entry_metadata)); |
| 214 } | 219 } |
| 215 | 220 |
| 216 void SimpleIndex::PostponeWritingToDisk() { | 221 void SimpleIndex::PostponeWritingToDisk() { |
| 217 const base::TimeDelta file_age = base::Time::Now() - last_write_to_disk_; | 222 if (!initialized_) |
| 218 if (file_age > base::TimeDelta::FromSeconds(kMaxWriteToDiskDelaySecs) && | |
| 219 write_to_disk_timer_.IsRunning()) { | |
| 220 // If the index file is too old and there is a timer programmed to run a | |
| 221 // WriteToDisk soon, we don't postpone it, so we always WriteToDisk | |
| 222 // approximately every kMaxWriteToDiskDelaySecs. | |
| 223 return; | 223 return; |
| 224 int delay = kWriteToDiskDelay_ms; | |
| 225 if (app_on_background_) { | |
| 226 // When the app is in the background we can write the index much more | |
| 227 // frequently. We could even write it to disk on every operation if we | |
| 228 // wanted to. | |
| 229 delay = kWriteToDiskOnBackgroundDelay_ms; | |
| 224 } | 230 } |
| 225 | |
| 226 // If the timer is already active, Start() will just Reset it, postponing it. | 231 // If the timer is already active, Start() will just Reset it, postponing it. |
| 227 write_to_disk_timer_.Start( | 232 write_to_disk_timer_.Start( |
| 228 FROM_HERE, | 233 FROM_HERE, |
| 229 base::TimeDelta::FromSeconds(kWriteToDiskDelaySecs), | 234 base::TimeDelta::FromMilliseconds(delay), |
| 230 base::Bind(&SimpleIndex::WriteToDisk, AsWeakPtr())); | 235 base::Bind(&SimpleIndex::WriteToDisk, AsWeakPtr())); |
| 231 } | 236 } |
| 232 | 237 |
| 233 // static | 238 // static |
| 234 void SimpleIndex::LoadFromDisk( | 239 void SimpleIndex::LoadFromDisk( |
| 235 const base::FilePath& index_filename, | 240 const base::FilePath& index_filename, |
| 236 base::SingleThreadTaskRunner* io_thread, | 241 base::SingleThreadTaskRunner* io_thread, |
| 237 const IndexCompletionCallback& completion_callback) { | 242 const IndexCompletionCallback& completion_callback) { |
| 238 scoped_ptr<EntrySet> index_file_entries = | 243 scoped_ptr<EntrySet> index_file_entries = |
| 239 SimpleIndexFile::LoadFromDisk(index_filename); | 244 SimpleIndexFile::LoadFromDisk(index_filename); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 250 base::Bind(completion_callback, | 255 base::Bind(completion_callback, |
| 251 base::Passed(&index_file_entries), | 256 base::Passed(&index_file_entries), |
| 252 force_index_flush)); | 257 force_index_flush)); |
| 253 } | 258 } |
| 254 | 259 |
| 255 // static | 260 // static |
| 256 scoped_ptr<SimpleIndex::EntrySet> SimpleIndex::RestoreFromDisk( | 261 scoped_ptr<SimpleIndex::EntrySet> SimpleIndex::RestoreFromDisk( |
| 257 const base::FilePath& index_filename) { | 262 const base::FilePath& index_filename) { |
| 258 using file_util::FileEnumerator; | 263 using file_util::FileEnumerator; |
| 259 LOG(INFO) << "Simple Cache Index is being restored from disk."; | 264 LOG(INFO) << "Simple Cache Index is being restored from disk."; |
| 260 | |
| 261 file_util::Delete(index_filename, /* recursive = */ false); | |
| 262 scoped_ptr<EntrySet> index_file_entries(new EntrySet()); | 265 scoped_ptr<EntrySet> index_file_entries(new EntrySet()); |
| 263 | 266 |
| 264 // TODO(felipeg,gavinp): Fix this once we have a one-file per entry format. | 267 // TODO(felipeg,gavinp): Fix this once we have a one-file per entry format. |
| 265 COMPILE_ASSERT(kSimpleEntryFileCount == 3, | 268 COMPILE_ASSERT(kSimpleEntryFileCount == 3, |
| 266 file_pattern_must_match_file_count); | 269 file_pattern_must_match_file_count); |
| 267 | 270 |
| 268 const int kFileSuffixLenght = std::string("_0").size(); | 271 const int kFileSuffixLenght = std::string("_0").size(); |
| 269 const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*_[0-2]"); | 272 const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*_[0-2]"); |
| 270 FileEnumerator enumerator(index_filename.DirName(), | 273 FileEnumerator enumerator(index_filename.DirName(), |
| 271 false /* recursive */, | 274 false /* recursive */, |
| 272 FileEnumerator::FILES, | 275 FileEnumerator::FILES, |
| 273 file_pattern); | 276 file_pattern); |
| 274 for (base::FilePath file_path = enumerator.Next(); !file_path.empty(); | 277 for (base::FilePath file_path = enumerator.Next(); !file_path.empty(); |
| 275 file_path = enumerator.Next()) { | 278 file_path = enumerator.Next()) { |
| 276 const base::FilePath::StringType base_name = file_path.BaseName().value(); | 279 const base::FilePath::StringType base_name = file_path.BaseName().value(); |
| 277 // Converting to std::string is OK since we never use UTF8 wide chars in our | 280 // Converting to std::string is OK since we never use UTF8 wide chars in our |
| 278 // file names. | 281 // file names. |
| 279 const std::string hash_name(base_name.begin(), base_name.end()); | 282 const std::string hash_name(base_name.begin(), base_name.end()); |
| 280 const std::string hash_key_string = | 283 const std::string hash_key_string = |
| 281 hash_name.substr(0, hash_name.size() - kFileSuffixLenght); | 284 hash_name.substr(0, hash_name.size() - kFileSuffixLenght); |
| 282 uint64 hash_key = 0; | 285 uint64 hash_key = 0; |
| 283 if (!simple_util::GetEntryHashKeyFromHexString( | 286 if (!simple_util::GetEntryHashKeyFromHexString( |
| 284 hash_key_string, &hash_key)) { | 287 hash_key_string, &hash_key)) { |
| 285 LOG(WARNING) << "Invalid Entry Hash Key filename while restoring " | 288 LOG(WARNING) << "Invalid Entry Hash Key filename while restoring " |
| 286 << "Simple Index from disk: " << hash_name; | 289 << "Simple Index from disk: " << hash_name; |
| 287 // TODO(felipeg): Should we delete the invalid file here ? | |
| 288 continue; | 290 continue; |
| 289 } | 291 } |
| 290 | 292 |
| 291 FileEnumerator::FindInfo find_info = {}; | 293 FileEnumerator::FindInfo find_info = {}; |
| 292 enumerator.GetFindInfo(&find_info); | 294 enumerator.GetFindInfo(&find_info); |
| 293 base::Time last_used_time; | 295 base::Time last_used_time; |
| 294 #if defined(OS_POSIX) | 296 #if defined(OS_POSIX) |
| 295 // For POSIX systems, a last access time is available. However, it's not | 297 // For POSIX systems, a last access time is available. However, it's not |
| 296 // guaranteed to be more accurate than mtime. It is no worse though. | 298 // guaranteed to be more accurate than mtime. It is no worse though. |
| 297 last_used_time = base::Time::FromTimeT(find_info.stat.st_atime); | 299 last_used_time = base::Time::FromTimeT(find_info.stat.st_atime); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 339 EntrySet::iterator current_entry = entries_set_.find(it->first); | 341 EntrySet::iterator current_entry = entries_set_.find(it->first); |
| 340 if (current_entry != entries_set_.end()) { | 342 if (current_entry != entries_set_.end()) { |
| 341 // When Merging, existing valid data in the |current_entry| will prevail. | 343 // When Merging, existing valid data in the |current_entry| will prevail. |
| 342 current_entry->second.MergeWith(it->second); | 344 current_entry->second.MergeWith(it->second); |
| 343 cache_size_ += current_entry->second.GetEntrySize(); | 345 cache_size_ += current_entry->second.GetEntrySize(); |
| 344 } else { | 346 } else { |
| 345 InsertInEntrySet(it->second, &entries_set_); | 347 InsertInEntrySet(it->second, &entries_set_); |
| 346 cache_size_ += it->second.GetEntrySize(); | 348 cache_size_ += it->second.GetEntrySize(); |
| 347 } | 349 } |
| 348 } | 350 } |
| 349 last_write_to_disk_ = base::Time::Now(); | |
| 350 initialized_ = true; | 351 initialized_ = true; |
| 351 removed_entries_.clear(); | 352 removed_entries_.clear(); |
| 352 | 353 |
| 353 // The actual IO is asynchronous, so calling WriteToDisk() shouldn't slow down | 354 // The actual IO is asynchronous, so calling WriteToDisk() shouldn't slow down |
| 354 // much the merge. | 355 // much the merge. |
| 355 if (force_index_flush) | 356 if (force_index_flush) |
| 356 WriteToDisk(); | 357 WriteToDisk(); |
| 357 | 358 |
| 358 // Run all callbacks waiting for the index to come up. | 359 // Run all callbacks waiting for the index to come up. |
| 359 for (CallbackList::iterator it = to_run_when_initialized_.begin(), | 360 for (CallbackList::iterator it = to_run_when_initialized_.begin(), |
| 360 end = to_run_when_initialized_.end(); it != end; ++it) { | 361 end = to_run_when_initialized_.end(); it != end; ++it) { |
| 361 io_thread_->PostTask(FROM_HERE, base::Bind((*it), net::OK)); | 362 io_thread_->PostTask(FROM_HERE, base::Bind((*it), net::OK)); |
| 362 } | 363 } |
| 363 to_run_when_initialized_.clear(); | 364 to_run_when_initialized_.clear(); |
| 364 } | 365 } |
| 365 | 366 |
| 367 #if defined(OS_ANDROID) | |
| 368 void SimpleIndex::ActivityStatusChanged( | |
| 369 net::SimpleCacheActivityStatusNotifier::ActivityStatus activity_status) { | |
| 370 DCHECK(io_thread_checker_.CalledOnValidThread()); | |
| 371 // These values are defined in the file ActivityStatus.java | |
| 372 if (activity_status == net::SimpleCacheActivityStatusNotifier::RESUMED) { | |
| 373 app_on_background_ = false; | |
| 374 } else if (activity_status == | |
| 375 net::SimpleCacheActivityStatusNotifier::PAUSED) { | |
| 376 app_on_background_ = true; | |
| 377 WriteToDisk(); | |
| 378 } else if (activity_status == | |
| 379 net::SimpleCacheActivityStatusNotifier::STOPPED) { | |
| 380 WriteToDisk(); | |
| 381 } else if (activity_status == | |
| 382 net::SimpleCacheActivityStatusNotifier::DESTROYED) { | |
| 383 WriteToDisk(); | |
| 384 } | |
| 385 } | |
| 386 #endif | |
| 387 | |
| 366 void SimpleIndex::WriteToDisk() { | 388 void SimpleIndex::WriteToDisk() { |
| 367 DCHECK(io_thread_checker_.CalledOnValidThread()); | 389 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 368 if (!initialized_) | 390 if (!initialized_) |
| 369 return; | 391 return; |
| 370 last_write_to_disk_ = base::Time::Now(); | |
| 371 SimpleIndexFile::IndexMetadata index_metadata(entries_set_.size(), | 392 SimpleIndexFile::IndexMetadata index_metadata(entries_set_.size(), |
| 372 cache_size_); | 393 cache_size_); |
| 373 scoped_ptr<Pickle> pickle = SimpleIndexFile::Serialize(index_metadata, | 394 scoped_ptr<Pickle> pickle = SimpleIndexFile::Serialize(index_metadata, |
| 374 entries_set_); | 395 entries_set_); |
| 375 cache_thread_->PostTask(FROM_HERE, base::Bind( | 396 cache_thread_->PostTask(FROM_HERE, base::Bind( |
| 376 &SimpleIndex::WriteToDiskInternal, | 397 &SimpleIndex::WriteToDiskInternal, |
| 377 index_filename_, | 398 index_filename_, |
| 378 base::Passed(&pickle))); | 399 base::Passed(&pickle))); |
| 379 } | 400 } |
| 380 | 401 |
| 381 } // namespace disk_cache | 402 } // namespace disk_cache |
| OLD | NEW |