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 { | 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |