Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: net/disk_cache/simple/simple_index.cc

Issue 14362009: Receive app notifications in SimpleCache, so we save our index file (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
15 #include "base/pickle.h" 15 #include "base/pickle.h"
16 #include "base/sys_info.h" 16 #include "base/sys_info.h"
17 #include "base/task_runner.h" 17 #include "base/task_runner.h"
18 #include "base/threading/worker_pool.h" 18 #include "base/threading/worker_pool.h"
19 #include "net/base/net_errors.h" 19 #include "net/base/net_errors.h"
20 #include "net/disk_cache/backend_impl.h" 20 #include "net/disk_cache/backend_impl.h"
21 #include "net/disk_cache/simple/simple_entry_format.h" 21 #include "net/disk_cache/simple/simple_entry_format.h"
22 #include "net/disk_cache/simple/simple_index_file.h" 22 #include "net/disk_cache/simple/simple_index_file.h"
23 #include "net/disk_cache/simple/simple_synchronous_entry.h" 23 #include "net/disk_cache/simple/simple_synchronous_entry.h"
24 #include "net/disk_cache/simple/simple_util.h" 24 #include "net/disk_cache/simple/simple_util.h"
25 25
26 namespace { 26 namespace {
27 27
28 // How many seconds we delay writing the index to disk since the last cache 28 // How many seconds we delay writing the index to disk since the last cache
29 // operation has happened. 29 // operation has happened.
30 const int kWriteToDiskDelaySecs = 20; 30 const int kWriteToDiskDelayMSecs = 20000;
31 31 const int kWriteToDiskOnBackgroundDelayMSecs = 100;
32 // WriteToDisk at lest every 5 minutes.
33 const int kMaxWriteToDiskDelaySecs = 300;
34 32
35 // Cache size when all other size heuristics failed. 33 // Cache size when all other size heuristics failed.
36 const uint64 kDefaultCacheSize = 80 * 1024 * 1024; 34 const uint64 kDefaultCacheSize = 80 * 1024 * 1024;
37 35
38 // Divides the cache space into this amount of parts to evict when only one part 36 // Divides the cache space into this amount of parts to evict when only one part
39 // is left. 37 // is left.
40 const uint32 kEvictionMarginDivisor = 20; 38 const uint32 kEvictionMarginDivisor = 20;
41 39
42 // Utility class used for timestamp comparisons in entry metadata while sorting. 40 // Utility class used for timestamp comparisons in entry metadata while sorting.
43 class CompareHashesForTimestamp { 41 class CompareHashesForTimestamp {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 const base::FilePath& path, 117 const base::FilePath& path,
120 int max_size) 118 int max_size)
121 : cache_size_(0), 119 : cache_size_(0),
122 max_size_(max_size), 120 max_size_(max_size),
123 high_watermark_(0), 121 high_watermark_(0),
124 low_watermark_(0), 122 low_watermark_(0),
125 eviction_in_progress_(false), 123 eviction_in_progress_(false),
126 initialized_(false), 124 initialized_(false),
127 index_filename_(path.AppendASCII("simple-index")), 125 index_filename_(path.AppendASCII("simple-index")),
128 cache_thread_(cache_thread), 126 cache_thread_(cache_thread),
129 io_thread_(io_thread) { 127 io_thread_(io_thread),
128 #if defined(OS_ANDROID)
129 activity_status_notifier_(
130 base::Bind(&SimpleIndex::ActivityStatusChanged, AsWeakPtr())),
131 #endif
132 app_on_background_(false) {
130 } 133 }
131 134
132 SimpleIndex::~SimpleIndex() { 135 SimpleIndex::~SimpleIndex() {
133 DCHECK(io_thread_checker_.CalledOnValidThread()); 136 DCHECK(io_thread_checker_.CalledOnValidThread());
134 137
135 // Fail all callbacks waiting for the index to come up. 138 // Fail all callbacks waiting for the index to come up.
136 for (CallbackList::iterator it = to_run_when_initialized_.begin(), 139 for (CallbackList::iterator it = to_run_when_initialized_.begin(),
137 end = to_run_when_initialized_.end(); it != end; ++it) { 140 end = to_run_when_initialized_.end(); it != end; ++it) {
138 it->Run(net::ERR_ABORTED); 141 it->Run(net::ERR_ABORTED);
139 } 142 }
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 const disk_cache::EntryMetadata& entry_metadata, 331 const disk_cache::EntryMetadata& entry_metadata,
329 EntrySet* entry_set) { 332 EntrySet* entry_set) {
330 DCHECK(entry_set); 333 DCHECK(entry_set);
331 entry_set->insert( 334 entry_set->insert(
332 std::make_pair(entry_metadata.GetHashKey(), entry_metadata)); 335 std::make_pair(entry_metadata.GetHashKey(), entry_metadata));
333 } 336 }
334 337
335 void SimpleIndex::PostponeWritingToDisk() { 338 void SimpleIndex::PostponeWritingToDisk() {
336 if (!initialized_) 339 if (!initialized_)
337 return; 340 return;
338 const base::TimeDelta file_age = base::Time::Now() - last_write_to_disk_; 341 int delay = kWriteToDiskDelayMSecs;
339 if (file_age > base::TimeDelta::FromSeconds(kMaxWriteToDiskDelaySecs) && 342 if (app_on_background_) {
340 write_to_disk_timer_.IsRunning()) { 343 // When the app is in the background we can write the index much more
341 // If the index file is too old and there is a timer programmed to run a 344 // frequently. We could even write it to disk on every operation if we
342 // WriteToDisk soon, we don't postpone it, so we always WriteToDisk 345 // wanted to.
343 // approximately every kMaxWriteToDiskDelaySecs. 346 delay = kWriteToDiskOnBackgroundDelayMSecs;
344 return;
345 } 347 }
346
347 // If the timer is already active, Start() will just Reset it, postponing it. 348 // If the timer is already active, Start() will just Reset it, postponing it.
348 write_to_disk_timer_.Start( 349 write_to_disk_timer_.Start(
349 FROM_HERE, 350 FROM_HERE,
350 base::TimeDelta::FromSeconds(kWriteToDiskDelaySecs), 351 base::TimeDelta::FromMilliseconds(delay),
351 base::Bind(&SimpleIndex::WriteToDisk, AsWeakPtr())); 352 base::Bind(&SimpleIndex::WriteToDisk, AsWeakPtr()));
352 } 353 }
353 354
354 // static 355 // static
355 bool SimpleIndex::IsIndexFileStale(const base::FilePath& index_filename) { 356 bool SimpleIndex::IsIndexFileStale(const base::FilePath& index_filename) {
356 base::PlatformFileInfo dir_info; 357 base::PlatformFileInfo dir_info;
357 base::PlatformFileInfo index_info; 358 base::PlatformFileInfo index_info;
358 if (!file_util::GetFileInfo(index_filename.DirName(), &dir_info)) 359 if (!file_util::GetFileInfo(index_filename.DirName(), &dir_info))
359 return false; 360 return false;
360 DCHECK(dir_info.is_directory); 361 DCHECK(dir_info.is_directory);
(...skipping 30 matching lines...) Expand all
391 base::Bind(completion_callback, 392 base::Bind(completion_callback,
392 base::Passed(&index_file_entries), 393 base::Passed(&index_file_entries),
393 force_index_flush)); 394 force_index_flush));
394 } 395 }
395 396
396 // static 397 // static
397 scoped_ptr<SimpleIndex::EntrySet> SimpleIndex::RestoreFromDisk( 398 scoped_ptr<SimpleIndex::EntrySet> SimpleIndex::RestoreFromDisk(
398 const base::FilePath& index_filename) { 399 const base::FilePath& index_filename) {
399 using file_util::FileEnumerator; 400 using file_util::FileEnumerator;
400 LOG(INFO) << "Simple Cache Index is being restored from disk."; 401 LOG(INFO) << "Simple Cache Index is being restored from disk.";
401
402 file_util::Delete(index_filename, /* recursive = */ false);
403 scoped_ptr<EntrySet> index_file_entries(new EntrySet()); 402 scoped_ptr<EntrySet> index_file_entries(new EntrySet());
404 403
405 // TODO(felipeg,gavinp): Fix this once we have a one-file per entry format. 404 // TODO(felipeg,gavinp): Fix this once we have a one-file per entry format.
406 COMPILE_ASSERT(kSimpleEntryFileCount == 3, 405 COMPILE_ASSERT(kSimpleEntryFileCount == 3,
407 file_pattern_must_match_file_count); 406 file_pattern_must_match_file_count);
408 407
409 const int kFileSuffixLenght = std::string("_0").size(); 408 const int kFileSuffixLenght = std::string("_0").size();
410 const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*_[0-2]"); 409 const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*_[0-2]");
411 FileEnumerator enumerator(index_filename.DirName(), 410 FileEnumerator enumerator(index_filename.DirName(),
412 false /* recursive */, 411 false /* recursive */,
413 FileEnumerator::FILES, 412 FileEnumerator::FILES,
414 file_pattern); 413 file_pattern);
415 for (base::FilePath file_path = enumerator.Next(); !file_path.empty(); 414 for (base::FilePath file_path = enumerator.Next(); !file_path.empty();
416 file_path = enumerator.Next()) { 415 file_path = enumerator.Next()) {
417 const base::FilePath::StringType base_name = file_path.BaseName().value(); 416 const base::FilePath::StringType base_name = file_path.BaseName().value();
418 // Converting to std::string is OK since we never use UTF8 wide chars in our 417 // Converting to std::string is OK since we never use UTF8 wide chars in our
419 // file names. 418 // file names.
420 const std::string hash_name(base_name.begin(), base_name.end()); 419 const std::string hash_name(base_name.begin(), base_name.end());
421 const std::string hash_key_string = 420 const std::string hash_key_string =
422 hash_name.substr(0, hash_name.size() - kFileSuffixLenght); 421 hash_name.substr(0, hash_name.size() - kFileSuffixLenght);
423 uint64 hash_key = 0; 422 uint64 hash_key = 0;
424 if (!simple_util::GetEntryHashKeyFromHexString( 423 if (!simple_util::GetEntryHashKeyFromHexString(
425 hash_key_string, &hash_key)) { 424 hash_key_string, &hash_key)) {
426 LOG(WARNING) << "Invalid Entry Hash Key filename while restoring " 425 LOG(WARNING) << "Invalid Entry Hash Key filename while restoring "
427 << "Simple Index from disk: " << hash_name; 426 << "Simple Index from disk: " << hash_name;
428 // TODO(felipeg): Should we delete the invalid file here ?
429 continue; 427 continue;
430 } 428 }
431 429
432 FileEnumerator::FindInfo find_info = {}; 430 FileEnumerator::FindInfo find_info = {};
433 enumerator.GetFindInfo(&find_info); 431 enumerator.GetFindInfo(&find_info);
434 base::Time last_used_time; 432 base::Time last_used_time;
435 #if defined(OS_POSIX) 433 #if defined(OS_POSIX)
436 // For POSIX systems, a last access time is available. However, it's not 434 // For POSIX systems, a last access time is available. However, it's not
437 // guaranteed to be more accurate than mtime. It is no worse though. 435 // guaranteed to be more accurate than mtime. It is no worse though.
438 last_used_time = base::Time::FromTimeT(find_info.stat.st_atime); 436 last_used_time = base::Time::FromTimeT(find_info.stat.st_atime);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 EntrySet::iterator current_entry = entries_set_.find(it->first); 479 EntrySet::iterator current_entry = entries_set_.find(it->first);
482 if (current_entry != entries_set_.end()) { 480 if (current_entry != entries_set_.end()) {
483 // When Merging, existing valid data in the |current_entry| will prevail. 481 // When Merging, existing valid data in the |current_entry| will prevail.
484 current_entry->second.MergeWith(it->second); 482 current_entry->second.MergeWith(it->second);
485 cache_size_ += current_entry->second.GetEntrySize(); 483 cache_size_ += current_entry->second.GetEntrySize();
486 } else { 484 } else {
487 InsertInEntrySet(it->second, &entries_set_); 485 InsertInEntrySet(it->second, &entries_set_);
488 cache_size_ += it->second.GetEntrySize(); 486 cache_size_ += it->second.GetEntrySize();
489 } 487 }
490 } 488 }
491 last_write_to_disk_ = base::Time::Now();
492 initialized_ = true; 489 initialized_ = true;
493 removed_entries_.clear(); 490 removed_entries_.clear();
494 491
495 // The actual IO is asynchronous, so calling WriteToDisk() shouldn't slow down 492 // The actual IO is asynchronous, so calling WriteToDisk() shouldn't slow down
496 // much the merge. 493 // much the merge.
497 if (force_index_flush) 494 if (force_index_flush)
498 WriteToDisk(); 495 WriteToDisk();
499 496
500 // Run all callbacks waiting for the index to come up. 497 // Run all callbacks waiting for the index to come up.
501 for (CallbackList::iterator it = to_run_when_initialized_.begin(), 498 for (CallbackList::iterator it = to_run_when_initialized_.begin(),
502 end = to_run_when_initialized_.end(); it != end; ++it) { 499 end = to_run_when_initialized_.end(); it != end; ++it) {
503 io_thread_->PostTask(FROM_HERE, base::Bind((*it), net::OK)); 500 io_thread_->PostTask(FROM_HERE, base::Bind((*it), net::OK));
504 } 501 }
505 to_run_when_initialized_.clear(); 502 to_run_when_initialized_.clear();
506 } 503 }
507 504
505 #if defined(OS_ANDROID)
506 void SimpleIndex::ActivityStatusChanged(
507 net::SimpleCacheActivityStatusNotifier::ActivityStatus activity_status) {
508 DCHECK(io_thread_checker_.CalledOnValidThread());
509 // For more info about android activities, see:
510 // developer.android.com/training/basics/activity-lifecycle/pausing.html
511 // These values are defined in the file ActivityStatus.java
512 if (activity_status == net::SimpleCacheActivityStatusNotifier::RESUMED) {
513 app_on_background_ = false;
514 } else if (activity_status ==
515 net::SimpleCacheActivityStatusNotifier::STOPPED) {
516 app_on_background_ = true;
517 WriteToDisk();
518 }
519 }
520 #endif
521
508 void SimpleIndex::WriteToDisk() { 522 void SimpleIndex::WriteToDisk() {
509 DCHECK(io_thread_checker_.CalledOnValidThread()); 523 DCHECK(io_thread_checker_.CalledOnValidThread());
510 if (!initialized_) 524 if (!initialized_)
511 return; 525 return;
512 last_write_to_disk_ = base::Time::Now();
513 SimpleIndexFile::IndexMetadata index_metadata(entries_set_.size(), 526 SimpleIndexFile::IndexMetadata index_metadata(entries_set_.size(),
514 cache_size_); 527 cache_size_);
515 scoped_ptr<Pickle> pickle = SimpleIndexFile::Serialize(index_metadata, 528 scoped_ptr<Pickle> pickle = SimpleIndexFile::Serialize(index_metadata,
516 entries_set_); 529 entries_set_);
517 cache_thread_->PostTask(FROM_HERE, base::Bind( 530 cache_thread_->PostTask(FROM_HERE, base::Bind(
518 &SimpleIndex::WriteToDiskInternal, 531 &SimpleIndex::WriteToDiskInternal,
519 index_filename_, 532 index_filename_,
520 base::Passed(&pickle))); 533 base::Passed(&pickle)));
521 } 534 }
522 535
523 } // namespace disk_cache 536 } // namespace disk_cache
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698