| 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 |