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

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

Powered by Google App Engine
This is Rietveld 408576698