OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/backend_impl.h" | 5 #include "net/disk_cache/backend_impl.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/histogram.h" | 8 #include "base/histogram.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
11 #include "base/sys_info.h" | 11 #include "base/sys_info.h" |
12 #include "base/timer.h" | 12 #include "base/timer.h" |
13 #include "base/worker_pool.h" | 13 #include "base/worker_pool.h" |
14 #include "net/disk_cache/cache_util.h" | 14 #include "net/disk_cache/cache_util.h" |
15 #include "net/disk_cache/entry_impl.h" | 15 #include "net/disk_cache/entry_impl.h" |
16 #include "net/disk_cache/errors.h" | 16 #include "net/disk_cache/errors.h" |
17 #include "net/disk_cache/hash.h" | 17 #include "net/disk_cache/hash.h" |
18 #include "net/disk_cache/file.h" | 18 #include "net/disk_cache/file.h" |
19 | 19 |
20 using base::Time; | 20 using base::Time; |
21 using base::TimeDelta; | 21 using base::TimeDelta; |
22 | 22 |
23 namespace { | 23 namespace { |
24 | 24 |
25 const wchar_t* kIndexName = L"index"; | 25 const wchar_t* kIndexName = L"index"; |
26 const int kCleanUpMargin = 1024 * 1024; | |
27 const int kMaxOldFolders = 100; | 26 const int kMaxOldFolders = 100; |
28 | 27 |
29 // Seems like ~240 MB correspond to less than 50k entries for 99% of the people. | 28 // Seems like ~240 MB correspond to less than 50k entries for 99% of the people. |
30 const int k64kEntriesStore = 240 * 1000 * 1000; | 29 const int k64kEntriesStore = 240 * 1000 * 1000; |
31 const int kBaseTableLen = 64 * 1024; | 30 const int kBaseTableLen = 64 * 1024; |
32 const int kDefaultCacheSize = 80 * 1024 * 1024; | 31 const int kDefaultCacheSize = 80 * 1024 * 1024; |
33 | 32 |
34 int DesiredIndexTableLen(int32 storage_size) { | 33 int DesiredIndexTableLen(int32 storage_size) { |
35 if (storage_size <= k64kEntriesStore) | 34 if (storage_size <= k64kEntriesStore) |
36 return kBaseTableLen; | 35 return kBaseTableLen; |
(...skipping 10 matching lines...) Expand all Loading... |
47 | 46 |
48 int MaxStorageSizeForTable(int table_len) { | 47 int MaxStorageSizeForTable(int table_len) { |
49 return table_len * (k64kEntriesStore / kBaseTableLen); | 48 return table_len * (k64kEntriesStore / kBaseTableLen); |
50 } | 49 } |
51 | 50 |
52 size_t GetIndexSize(int table_len) { | 51 size_t GetIndexSize(int table_len) { |
53 size_t table_size = sizeof(disk_cache::CacheAddr) * table_len; | 52 size_t table_size = sizeof(disk_cache::CacheAddr) * table_len; |
54 return sizeof(disk_cache::IndexHeader) + table_size; | 53 return sizeof(disk_cache::IndexHeader) + table_size; |
55 } | 54 } |
56 | 55 |
57 int LowWaterAdjust(int high_water) { | |
58 if (high_water < kCleanUpMargin) | |
59 return 0; | |
60 | |
61 return high_water - kCleanUpMargin; | |
62 } | |
63 | |
64 // ------------------------------------------------------------------------ | 56 // ------------------------------------------------------------------------ |
65 | 57 |
66 // Returns a fully qualified name from path and name, using a given name prefix | 58 // Returns a fully qualified name from path and name, using a given name prefix |
67 // and index number. For instance, if the arguments are "/foo", "bar" and 5, it | 59 // and index number. For instance, if the arguments are "/foo", "bar" and 5, it |
68 // will return "/foo/old_bar_005". | 60 // will return "/foo/old_bar_005". |
69 std::wstring GetPrefixedName(const std::wstring& path, const std::wstring& name, | 61 std::wstring GetPrefixedName(const std::wstring& path, const std::wstring& name, |
70 int index) { | 62 int index) { |
71 std::wstring prefixed(path); | 63 std::wstring prefixed(path); |
72 std::wstring tmp = StringPrintf(L"%ls%ls_%03d", L"old_", name.c_str(), index); | 64 std::wstring tmp = StringPrintf(L"%ls%ls_%03d", L"old_", name.c_str(), index); |
73 file_util::AppendToPath(&prefixed, tmp); | 65 file_util::AppendToPath(&prefixed, tmp); |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 | 233 |
242 if (!block_files_.Init(create_files)) | 234 if (!block_files_.Init(create_files)) |
243 return false; | 235 return false; |
244 | 236 |
245 // stats_ and rankings_ may end up calling back to us so we better be enabled. | 237 // stats_ and rankings_ may end up calling back to us so we better be enabled. |
246 disabled_ = false; | 238 disabled_ = false; |
247 if (!stats_.Init(this, &data_->header.stats)) | 239 if (!stats_.Init(this, &data_->header.stats)) |
248 return false; | 240 return false; |
249 | 241 |
250 disabled_ = !rankings_.Init(this); | 242 disabled_ = !rankings_.Init(this); |
| 243 eviction_.Init(this); |
251 | 244 |
252 return !disabled_; | 245 return !disabled_; |
253 } | 246 } |
254 | 247 |
255 BackendImpl::~BackendImpl() { | 248 BackendImpl::~BackendImpl() { |
256 Trace("Backend destructor"); | 249 Trace("Backend destructor"); |
257 if (!init_) | 250 if (!init_) |
258 return; | 251 return; |
259 | 252 |
260 if (data_) | 253 if (data_) |
(...skipping 19 matching lines...) Expand all Loading... |
280 | 273 |
281 Time start = Time::Now(); | 274 Time start = Time::Now(); |
282 uint32 hash = Hash(key); | 275 uint32 hash = Hash(key); |
283 | 276 |
284 EntryImpl* cache_entry = MatchEntry(key, hash, false); | 277 EntryImpl* cache_entry = MatchEntry(key, hash, false); |
285 if (!cache_entry) { | 278 if (!cache_entry) { |
286 stats_.OnEvent(Stats::OPEN_MISS); | 279 stats_.OnEvent(Stats::OPEN_MISS); |
287 return false; | 280 return false; |
288 } | 281 } |
289 | 282 |
| 283 eviction_.OnOpenEntry(cache_entry); |
290 DCHECK(entry); | 284 DCHECK(entry); |
291 *entry = cache_entry; | 285 *entry = cache_entry; |
292 | 286 |
293 UMA_HISTOGRAM_TIMES(L"DiskCache.OpenTime", Time::Now() - start); | 287 UMA_HISTOGRAM_TIMES(L"DiskCache.OpenTime", Time::Now() - start); |
294 stats_.OnEvent(Stats::OPEN_HIT); | 288 stats_.OnEvent(Stats::OPEN_HIT); |
295 return true; | 289 return true; |
296 } | 290 } |
297 | 291 |
298 bool BackendImpl::CreateEntry(const std::string& key, Entry** entry) { | 292 bool BackendImpl::CreateEntry(const std::string& key, Entry** entry) { |
299 if (disabled_ || key.empty()) | 293 if (disabled_ || key.empty()) |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 } | 342 } |
349 | 343 |
350 if (parent.get()) | 344 if (parent.get()) |
351 parent->SetNextAddress(entry_address); | 345 parent->SetNextAddress(entry_address); |
352 | 346 |
353 block_files_.GetFile(entry_address)->Store(cache_entry->entry()); | 347 block_files_.GetFile(entry_address)->Store(cache_entry->entry()); |
354 block_files_.GetFile(node_address)->Store(cache_entry->rankings()); | 348 block_files_.GetFile(node_address)->Store(cache_entry->rankings()); |
355 | 349 |
356 data_->header.num_entries++; | 350 data_->header.num_entries++; |
357 DCHECK(data_->header.num_entries > 0); | 351 DCHECK(data_->header.num_entries > 0); |
358 rankings_.Insert(cache_entry->rankings(), true, Rankings::NO_USE); | 352 eviction_.OnCreateEntry(cache_entry); |
359 if (!parent.get()) | 353 if (!parent.get()) |
360 data_->table[hash & mask_] = entry_address.value(); | 354 data_->table[hash & mask_] = entry_address.value(); |
361 | 355 |
362 DCHECK(entry); | 356 DCHECK(entry); |
363 *entry = NULL; | 357 *entry = NULL; |
364 cache_entry.swap(reinterpret_cast<EntryImpl**>(entry)); | 358 cache_entry.swap(reinterpret_cast<EntryImpl**>(entry)); |
365 | 359 |
366 UMA_HISTOGRAM_TIMES(L"DiskCache.CreateTime", Time::Now() - start); | 360 UMA_HISTOGRAM_TIMES(L"DiskCache.CreateTime", Time::Now() - start); |
367 stats_.OnEvent(Stats::CREATE_HIT); | 361 stats_.OnEvent(Stats::CREATE_HIT); |
368 Trace("create entry hit "); | 362 Trace("create entry hit "); |
(...skipping 18 matching lines...) Expand all Loading... |
387 | 381 |
388 bool BackendImpl::DoomAllEntries() { | 382 bool BackendImpl::DoomAllEntries() { |
389 if (!num_refs_) { | 383 if (!num_refs_) { |
390 PrepareForRestart(); | 384 PrepareForRestart(); |
391 DeleteCache(path_.c_str(), false); | 385 DeleteCache(path_.c_str(), false); |
392 return Init(); | 386 return Init(); |
393 } else { | 387 } else { |
394 if (disabled_) | 388 if (disabled_) |
395 return false; | 389 return false; |
396 | 390 |
397 TrimCache(true); | 391 eviction_.TrimCache(true); |
398 stats_.OnEvent(Stats::DOOM_CACHE); | 392 stats_.OnEvent(Stats::DOOM_CACHE); |
399 return true; | 393 return true; |
400 } | 394 } |
401 } | 395 } |
402 | 396 |
403 bool BackendImpl::DoomEntriesBetween(const Time initial_time, | 397 bool BackendImpl::DoomEntriesBetween(const Time initial_time, |
404 const Time end_time) { | 398 const Time end_time) { |
405 if (end_time.is_null()) | 399 if (end_time.is_null()) |
406 return DoomEntriesSince(initial_time); | 400 return DoomEntriesSince(initial_time); |
407 | 401 |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
568 void BackendImpl::DeleteBlock(Addr block_address, bool deep) { | 562 void BackendImpl::DeleteBlock(Addr block_address, bool deep) { |
569 block_files_.DeleteBlock(block_address, deep); | 563 block_files_.DeleteBlock(block_address, deep); |
570 } | 564 } |
571 | 565 |
572 LruData* BackendImpl::GetLruData() { | 566 LruData* BackendImpl::GetLruData() { |
573 return &data_->header.lru; | 567 return &data_->header.lru; |
574 } | 568 } |
575 | 569 |
576 void BackendImpl::UpdateRank(EntryImpl* entry, bool modified) { | 570 void BackendImpl::UpdateRank(EntryImpl* entry, bool modified) { |
577 if (!read_only_) { | 571 if (!read_only_) { |
578 rankings_.UpdateRank(entry->rankings(), modified, Rankings::NO_USE); | 572 eviction_.UpdateRank(entry, modified); |
579 } | 573 } |
580 } | 574 } |
581 | 575 |
582 void BackendImpl::RecoveredEntry(CacheRankingsBlock* rankings) { | 576 void BackendImpl::RecoveredEntry(CacheRankingsBlock* rankings) { |
583 Addr address(rankings->Data()->contents); | 577 Addr address(rankings->Data()->contents); |
584 EntryImpl* cache_entry = NULL; | 578 EntryImpl* cache_entry = NULL; |
585 bool dirty; | 579 bool dirty; |
586 if (NewEntry(address, &cache_entry, &dirty)) | 580 if (NewEntry(address, &cache_entry, &dirty)) |
587 return; | 581 return; |
588 | 582 |
589 uint32 hash = cache_entry->GetHash(); | 583 uint32 hash = cache_entry->GetHash(); |
590 cache_entry->Release(); | 584 cache_entry->Release(); |
591 | 585 |
592 // Anything on the table means that this entry is there. | 586 // Anything on the table means that this entry is there. |
593 if (data_->table[hash & mask_]) | 587 if (data_->table[hash & mask_]) |
594 return; | 588 return; |
595 | 589 |
596 data_->table[hash & mask_] = address.value(); | 590 data_->table[hash & mask_] = address.value(); |
597 } | 591 } |
598 | 592 |
599 void BackendImpl::InternalDoomEntry(EntryImpl* entry) { | 593 void BackendImpl::InternalDoomEntry(EntryImpl* entry) { |
600 uint32 hash = entry->GetHash(); | 594 uint32 hash = entry->GetHash(); |
601 std::string key = entry->GetKey(); | 595 std::string key = entry->GetKey(); |
602 EntryImpl* parent_entry = MatchEntry(key, hash, true); | 596 EntryImpl* parent_entry = MatchEntry(key, hash, true); |
603 CacheAddr child(entry->GetNextAddress()); | 597 CacheAddr child(entry->GetNextAddress()); |
604 | 598 |
605 Trace("Doom entry 0x%p", entry); | 599 Trace("Doom entry 0x%p", entry); |
606 | 600 |
607 rankings_.Remove(entry->rankings(), Rankings::NO_USE); | 601 eviction_.OnDoomEntry(entry); |
608 | |
609 entry->InternalDoom(); | 602 entry->InternalDoom(); |
610 | 603 |
611 if (parent_entry) { | 604 if (parent_entry) { |
612 parent_entry->SetNextAddress(Addr(child)); | 605 parent_entry->SetNextAddress(Addr(child)); |
613 parent_entry->Release(); | 606 parent_entry->Release(); |
614 } else { | 607 } else { |
615 data_->table[hash & mask_] = child; | 608 data_->table[hash & mask_] = child; |
616 } | 609 } |
617 | 610 |
618 data_->header.num_entries--; | 611 data_->header.num_entries--; |
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1013 | 1006 |
1014 entry.swap(reinterpret_cast<EntryImpl**>(next_entry)); | 1007 entry.swap(reinterpret_cast<EntryImpl**>(next_entry)); |
1015 *iter = next.release(); | 1008 *iter = next.release(); |
1016 return true; | 1009 return true; |
1017 } | 1010 } |
1018 | 1011 |
1019 void BackendImpl::DestroyInvalidEntry(Addr address, EntryImpl* entry) { | 1012 void BackendImpl::DestroyInvalidEntry(Addr address, EntryImpl* entry) { |
1020 LOG(WARNING) << "Destroying invalid entry."; | 1013 LOG(WARNING) << "Destroying invalid entry."; |
1021 Trace("Destroying invalid entry 0x%p", entry); | 1014 Trace("Destroying invalid entry 0x%p", entry); |
1022 | 1015 |
1023 rankings_.Remove(entry->rankings(), Rankings::NO_USE); | |
1024 entry->SetPointerForInvalidEntry(GetCurrentEntryId()); | 1016 entry->SetPointerForInvalidEntry(GetCurrentEntryId()); |
1025 | 1017 |
| 1018 eviction_.OnDoomEntry(entry); |
1026 entry->InternalDoom(); | 1019 entry->InternalDoom(); |
1027 | 1020 |
1028 data_->header.num_entries--; | 1021 data_->header.num_entries--; |
1029 DCHECK(data_->header.num_entries >= 0); | 1022 DCHECK(data_->header.num_entries >= 0); |
1030 stats_.OnEvent(Stats::INVALID_ENTRY); | 1023 stats_.OnEvent(Stats::INVALID_ENTRY); |
1031 } | 1024 } |
1032 | 1025 |
1033 void BackendImpl::TrimCache(bool empty) { | |
1034 Trace("*** Trim Cache ***"); | |
1035 if (disabled_) | |
1036 return; | |
1037 | |
1038 Time start = Time::Now(); | |
1039 Rankings::ScopedRankingsBlock node(&rankings_); | |
1040 Rankings::ScopedRankingsBlock next(&rankings_, | |
1041 rankings_.GetPrev(node.get(), Rankings::NO_USE)); | |
1042 DCHECK(next.get()); | |
1043 int target_size = empty ? 0 : LowWaterAdjust(max_size_); | |
1044 int deleted = 0; | |
1045 while (data_->header.num_bytes > target_size && next.get()) { | |
1046 node.reset(next.release()); | |
1047 next.reset(rankings_.GetPrev(node.get(), Rankings::NO_USE)); | |
1048 if (!node->Data()->pointer || empty) { | |
1049 // This entry is not being used by anybody. | |
1050 EntryImpl* entry; | |
1051 bool dirty; | |
1052 if (NewEntry(Addr(node->Data()->contents), &entry, &dirty)) { | |
1053 Trace("NewEntry failed on Trim 0x%x", node->address().value()); | |
1054 continue; | |
1055 } | |
1056 | |
1057 if (node->Data()->pointer) { | |
1058 entry = EntryImpl::Update(entry); | |
1059 } | |
1060 ReportTrimTimes(entry); | |
1061 entry->Doom(); | |
1062 entry->Release(); | |
1063 if (!empty) | |
1064 stats_.OnEvent(Stats::TRIM_ENTRY); | |
1065 if (++deleted == 4 && !empty) { | |
1066 #if defined(OS_WIN) | |
1067 MessageLoop::current()->PostTask(FROM_HERE, | |
1068 factory_.NewRunnableMethod(&BackendImpl::TrimCache, false)); | |
1069 break; | |
1070 #endif | |
1071 } | |
1072 } | |
1073 } | |
1074 | |
1075 UMA_HISTOGRAM_TIMES(L"DiskCache.TotalTrimTime", Time::Now() - start); | |
1076 Trace("*** Trim Cache end ***"); | |
1077 return; | |
1078 } | |
1079 | |
1080 void BackendImpl::ReportTrimTimes(EntryImpl* entry) { | |
1081 static bool first_time = true; | |
1082 if (first_time) { | |
1083 first_time = false; | |
1084 std::wstring name(StringPrintf(L"DiskCache.TrimAge_%d", | |
1085 data_->header.experiment)); | |
1086 static Histogram counter(name.c_str(), 1, 10000, 50); | |
1087 counter.SetFlags(kUmaTargetedHistogramFlag); | |
1088 counter.Add((Time::Now() - entry->GetLastUsed()).InHours()); | |
1089 } | |
1090 } | |
1091 | |
1092 void BackendImpl::AddStorageSize(int32 bytes) { | 1026 void BackendImpl::AddStorageSize(int32 bytes) { |
1093 data_->header.num_bytes += bytes; | 1027 data_->header.num_bytes += bytes; |
1094 DCHECK(data_->header.num_bytes >= 0); | 1028 DCHECK(data_->header.num_bytes >= 0); |
1095 | 1029 |
1096 if (data_->header.num_bytes > max_size_) | 1030 if (data_->header.num_bytes > max_size_) |
1097 TrimCache(false); | 1031 eviction_.TrimCache(false); |
1098 } | 1032 } |
1099 | 1033 |
1100 void BackendImpl::SubstractStorageSize(int32 bytes) { | 1034 void BackendImpl::SubstractStorageSize(int32 bytes) { |
1101 data_->header.num_bytes -= bytes; | 1035 data_->header.num_bytes -= bytes; |
1102 DCHECK(data_->header.num_bytes >= 0); | 1036 DCHECK(data_->header.num_bytes >= 0); |
1103 } | 1037 } |
1104 | 1038 |
1105 void BackendImpl::IncreaseNumRefs() { | 1039 void BackendImpl::IncreaseNumRefs() { |
1106 num_refs_++; | 1040 num_refs_++; |
1107 if (max_refs_ < num_refs_) | 1041 if (max_refs_ < num_refs_) |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1211 | 1145 |
1212 return num_dirty; | 1146 return num_dirty; |
1213 } | 1147 } |
1214 | 1148 |
1215 bool BackendImpl::CheckEntry(EntryImpl* cache_entry) { | 1149 bool BackendImpl::CheckEntry(EntryImpl* cache_entry) { |
1216 RankingsNode* rankings = cache_entry->rankings()->Data(); | 1150 RankingsNode* rankings = cache_entry->rankings()->Data(); |
1217 return !rankings->pointer; | 1151 return !rankings->pointer; |
1218 } | 1152 } |
1219 | 1153 |
1220 } // namespace disk_cache | 1154 } // namespace disk_cache |
OLD | NEW |