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

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

Powered by Google App Engine
This is Rietveld 408576698