| 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 // Uncomment this to use the new eviction algorithm. |
| 21 // #define USE_NEW_EVICTION |
| 22 |
| 20 using base::Time; | 23 using base::Time; |
| 21 using base::TimeDelta; | 24 using base::TimeDelta; |
| 22 | 25 |
| 23 namespace { | 26 namespace { |
| 24 | 27 |
| 25 const wchar_t* kIndexName = L"index"; | 28 const wchar_t* kIndexName = L"index"; |
| 26 const int kMaxOldFolders = 100; | 29 const int kMaxOldFolders = 100; |
| 27 | 30 |
| 28 // Seems like ~240 MB correspond to less than 50k entries for 99% of the people. | 31 // Seems like ~240 MB correspond to less than 50k entries for 99% of the people. |
| 29 const int k64kEntriesStore = 240 * 1000 * 1000; | 32 const int k64kEntriesStore = 240 * 1000 * 1000; |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 return NULL; | 180 return NULL; |
| 178 } | 181 } |
| 179 | 182 |
| 180 // ------------------------------------------------------------------------ | 183 // ------------------------------------------------------------------------ |
| 181 | 184 |
| 182 bool BackendImpl::Init() { | 185 bool BackendImpl::Init() { |
| 183 DCHECK(!init_); | 186 DCHECK(!init_); |
| 184 if (init_) | 187 if (init_) |
| 185 return false; | 188 return false; |
| 186 | 189 |
| 190 #ifdef USE_NEW_EVICTION |
| 191 new_eviction_ = true; |
| 192 #endif |
| 193 |
| 187 bool create_files = false; | 194 bool create_files = false; |
| 188 if (!InitBackingStore(&create_files)) { | 195 if (!InitBackingStore(&create_files)) { |
| 189 ReportError(ERR_STORAGE_ERROR); | 196 ReportError(ERR_STORAGE_ERROR); |
| 190 return false; | 197 return false; |
| 191 } | 198 } |
| 192 | 199 |
| 193 num_refs_ = num_pending_io_ = max_refs_ = 0; | 200 num_refs_ = num_pending_io_ = max_refs_ = 0; |
| 194 | 201 |
| 195 if (!restarted_) { | 202 if (!restarted_) { |
| 196 // Create a recurrent timer of 30 secs. | 203 // Create a recurrent timer of 30 secs. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 224 } | 231 } |
| 225 | 232 |
| 226 if (!block_files_.Init(create_files)) | 233 if (!block_files_.Init(create_files)) |
| 227 return false; | 234 return false; |
| 228 | 235 |
| 229 // stats_ and rankings_ may end up calling back to us so we better be enabled. | 236 // stats_ and rankings_ may end up calling back to us so we better be enabled. |
| 230 disabled_ = false; | 237 disabled_ = false; |
| 231 if (!stats_.Init(this, &data_->header.stats)) | 238 if (!stats_.Init(this, &data_->header.stats)) |
| 232 return false; | 239 return false; |
| 233 | 240 |
| 234 disabled_ = !rankings_.Init(this); | 241 disabled_ = !rankings_.Init(this, new_eviction_); |
| 235 eviction_.Init(this); | 242 eviction_.Init(this); |
| 236 | 243 |
| 237 return !disabled_; | 244 return !disabled_; |
| 238 } | 245 } |
| 239 | 246 |
| 240 BackendImpl::~BackendImpl() { | 247 BackendImpl::~BackendImpl() { |
| 241 Trace("Backend destructor"); | 248 Trace("Backend destructor"); |
| 242 if (!init_) | 249 if (!init_) |
| 243 return; | 250 return; |
| 244 | 251 |
| 245 if (data_) | 252 if (data_) |
| 246 data_->header.crash = 0; | 253 data_->header.crash = 0; |
| 247 | 254 |
| 248 timer_.Stop(); | 255 timer_.Stop(); |
| 249 | 256 |
| 250 WaitForPendingIO(&num_pending_io_); | 257 WaitForPendingIO(&num_pending_io_); |
| 251 DCHECK(!num_refs_); | 258 DCHECK(!num_refs_); |
| 252 } | 259 } |
| 253 | 260 |
| 254 // ------------------------------------------------------------------------ | 261 // ------------------------------------------------------------------------ |
| 255 | 262 |
| 256 int32 BackendImpl::GetEntryCount() const { | 263 int32 BackendImpl::GetEntryCount() const { |
| 257 if (!index_) | 264 if (!index_) |
| 258 return 0; | 265 return 0; |
| 259 return data_->header.num_entries; | 266 // num_entries includes entries already evicted. |
| 267 int32 not_deleted = data_->header.num_entries - |
| 268 data_->header.lru.sizes[Rankings::DELETED]; |
| 269 |
| 270 if (not_deleted < 0) { |
| 271 NOTREACHED(); |
| 272 not_deleted = 0; |
| 273 } |
| 274 |
| 275 return not_deleted; |
| 260 } | 276 } |
| 261 | 277 |
| 262 bool BackendImpl::OpenEntry(const std::string& key, Entry** entry) { | 278 bool BackendImpl::OpenEntry(const std::string& key, Entry** entry) { |
| 263 if (disabled_) | 279 if (disabled_) |
| 264 return false; | 280 return false; |
| 265 | 281 |
| 266 Time start = Time::Now(); | 282 Time start = Time::Now(); |
| 267 uint32 hash = Hash(key); | 283 uint32 hash = Hash(key); |
| 268 | 284 |
| 269 EntryImpl* cache_entry = MatchEntry(key, hash, false); | 285 EntryImpl* cache_entry = MatchEntry(key, hash, false); |
| 270 if (!cache_entry) { | 286 if (!cache_entry) { |
| 271 stats_.OnEvent(Stats::OPEN_MISS); | 287 stats_.OnEvent(Stats::OPEN_MISS); |
| 272 return false; | 288 return false; |
| 273 } | 289 } |
| 274 | 290 |
| 291 if (ENTRY_NORMAL != cache_entry->entry()->Data()->state) { |
| 292 // The entry was already evicted. |
| 293 cache_entry->Release(); |
| 294 stats_.OnEvent(Stats::OPEN_MISS); |
| 295 return false; |
| 296 } |
| 297 |
| 275 eviction_.OnOpenEntry(cache_entry); | 298 eviction_.OnOpenEntry(cache_entry); |
| 276 DCHECK(entry); | 299 DCHECK(entry); |
| 277 *entry = cache_entry; | 300 *entry = cache_entry; |
| 278 | 301 |
| 279 UMA_HISTOGRAM_TIMES("DiskCache.OpenTime", Time::Now() - start); | 302 UMA_HISTOGRAM_TIMES("DiskCache.OpenTime", Time::Now() - start); |
| 280 stats_.OnEvent(Stats::OPEN_HIT); | 303 stats_.OnEvent(Stats::OPEN_HIT); |
| 281 return true; | 304 return true; |
| 282 } | 305 } |
| 283 | 306 |
| 284 bool BackendImpl::CreateEntry(const std::string& key, Entry** entry) { | 307 bool BackendImpl::CreateEntry(const std::string& key, Entry** entry) { |
| 285 if (disabled_ || key.empty()) | 308 if (disabled_ || key.empty()) |
| 286 return false; | 309 return false; |
| 287 | 310 |
| 311 DCHECK(entry); |
| 312 *entry = NULL; |
| 313 |
| 288 Time start = Time::Now(); | 314 Time start = Time::Now(); |
| 289 uint32 hash = Hash(key); | 315 uint32 hash = Hash(key); |
| 290 | 316 |
| 291 scoped_refptr<EntryImpl> parent; | 317 scoped_refptr<EntryImpl> parent; |
| 292 Addr entry_address(data_->table[hash & mask_]); | 318 Addr entry_address(data_->table[hash & mask_]); |
| 293 if (entry_address.is_initialized()) { | 319 if (entry_address.is_initialized()) { |
| 320 // We have an entry already. It could be the one we are looking for, or just |
| 321 // a hash conflict. |
| 322 EntryImpl* old_entry = MatchEntry(key, hash, false); |
| 323 if (old_entry) |
| 324 return ResurrectEntry(old_entry, entry); |
| 325 |
| 294 EntryImpl* parent_entry = MatchEntry(key, hash, true); | 326 EntryImpl* parent_entry = MatchEntry(key, hash, true); |
| 295 if (!parent_entry) { | 327 if (!parent_entry) { |
| 296 stats_.OnEvent(Stats::CREATE_MISS); | 328 NOTREACHED(); |
| 297 Trace("create entry miss "); | |
| 298 return false; | 329 return false; |
| 299 } | 330 } |
| 300 parent.swap(&parent_entry); | 331 parent.swap(&parent_entry); |
| 301 } | 332 } |
| 302 | 333 |
| 303 int num_blocks; | 334 int num_blocks; |
| 304 size_t key1_len = sizeof(EntryStore) - offsetof(EntryStore, key); | 335 size_t key1_len = sizeof(EntryStore) - offsetof(EntryStore, key); |
| 305 if (key.size() < key1_len || | 336 if (key.size() < key1_len || |
| 306 key.size() > static_cast<size_t>(kMaxInternalKeyLength)) | 337 key.size() > static_cast<size_t>(kMaxInternalKeyLength)) |
| 307 num_blocks = 1; | 338 num_blocks = 1; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 332 stats_.OnEvent(Stats::CREATE_ERROR); | 363 stats_.OnEvent(Stats::CREATE_ERROR); |
| 333 return false; | 364 return false; |
| 334 } | 365 } |
| 335 | 366 |
| 336 if (parent.get()) | 367 if (parent.get()) |
| 337 parent->SetNextAddress(entry_address); | 368 parent->SetNextAddress(entry_address); |
| 338 | 369 |
| 339 block_files_.GetFile(entry_address)->Store(cache_entry->entry()); | 370 block_files_.GetFile(entry_address)->Store(cache_entry->entry()); |
| 340 block_files_.GetFile(node_address)->Store(cache_entry->rankings()); | 371 block_files_.GetFile(node_address)->Store(cache_entry->rankings()); |
| 341 | 372 |
| 342 data_->header.num_entries++; | 373 IncreaseNumEntries(); |
| 343 DCHECK(data_->header.num_entries > 0); | |
| 344 eviction_.OnCreateEntry(cache_entry); | 374 eviction_.OnCreateEntry(cache_entry); |
| 345 if (!parent.get()) | 375 if (!parent.get()) |
| 346 data_->table[hash & mask_] = entry_address.value(); | 376 data_->table[hash & mask_] = entry_address.value(); |
| 347 | 377 |
| 348 DCHECK(entry); | |
| 349 *entry = NULL; | |
| 350 cache_entry.swap(reinterpret_cast<EntryImpl**>(entry)); | 378 cache_entry.swap(reinterpret_cast<EntryImpl**>(entry)); |
| 351 | 379 |
| 352 UMA_HISTOGRAM_TIMES("DiskCache.CreateTime", Time::Now() - start); | 380 UMA_HISTOGRAM_TIMES("DiskCache.CreateTime", Time::Now() - start); |
| 353 stats_.OnEvent(Stats::CREATE_HIT); | 381 stats_.OnEvent(Stats::CREATE_HIT); |
| 354 Trace("create entry hit "); | 382 Trace("create entry hit "); |
| 355 return true; | 383 return true; |
| 356 } | 384 } |
| 357 | 385 |
| 358 bool BackendImpl::DoomEntry(const std::string& key) { | 386 bool BackendImpl::DoomEntry(const std::string& key) { |
| 359 if (disabled_) | 387 if (disabled_) |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 entry->Close(); | 472 entry->Close(); |
| 445 EndEnumeration(&iter); // Dooming the entry invalidates the iterator. | 473 EndEnumeration(&iter); // Dooming the entry invalidates the iterator. |
| 446 } | 474 } |
| 447 } | 475 } |
| 448 | 476 |
| 449 bool BackendImpl::OpenNextEntry(void** iter, Entry** next_entry) { | 477 bool BackendImpl::OpenNextEntry(void** iter, Entry** next_entry) { |
| 450 return OpenFollowingEntry(true, iter, next_entry); | 478 return OpenFollowingEntry(true, iter, next_entry); |
| 451 } | 479 } |
| 452 | 480 |
| 453 void BackendImpl::EndEnumeration(void** iter) { | 481 void BackendImpl::EndEnumeration(void** iter) { |
| 454 Rankings::ScopedRankingsBlock rankings(&rankings_, | 482 scoped_ptr<Rankings::Iterator> iterator( |
| 455 reinterpret_cast<CacheRankingsBlock*>(*iter)); | 483 reinterpret_cast<Rankings::Iterator*>(*iter)); |
| 456 *iter = NULL; | 484 *iter = NULL; |
| 457 } | 485 } |
| 458 | 486 |
| 459 void BackendImpl::GetStats(StatsItems* stats) { | 487 void BackendImpl::GetStats(StatsItems* stats) { |
| 460 if (disabled_) | 488 if (disabled_) |
| 461 return; | 489 return; |
| 462 | 490 |
| 463 std::pair<std::string, std::string> item; | 491 std::pair<std::string, std::string> item; |
| 464 | 492 |
| 465 item.first = "Entries"; | 493 item.first = "Entries"; |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 593 eviction_.OnDoomEntry(entry); | 621 eviction_.OnDoomEntry(entry); |
| 594 entry->InternalDoom(); | 622 entry->InternalDoom(); |
| 595 | 623 |
| 596 if (parent_entry) { | 624 if (parent_entry) { |
| 597 parent_entry->SetNextAddress(Addr(child)); | 625 parent_entry->SetNextAddress(Addr(child)); |
| 598 parent_entry->Release(); | 626 parent_entry->Release(); |
| 599 } else { | 627 } else { |
| 600 data_->table[hash & mask_] = child; | 628 data_->table[hash & mask_] = child; |
| 601 } | 629 } |
| 602 | 630 |
| 603 data_->header.num_entries--; | 631 if (!new_eviction_) { |
| 604 DCHECK(data_->header.num_entries >= 0); | 632 DecreaseNumEntries(); |
| 633 } |
| 634 |
| 605 stats_.OnEvent(Stats::DOOM_ENTRY); | 635 stats_.OnEvent(Stats::DOOM_ENTRY); |
| 606 } | 636 } |
| 607 | 637 |
| 638 // An entry may be linked on the DELETED list for a while after being doomed. |
| 639 // This function is called when we want to remove it. |
| 640 void BackendImpl::RemoveEntry(EntryImpl* entry) { |
| 641 if (!new_eviction_) |
| 642 return; |
| 643 |
| 644 DCHECK(ENTRY_DOOMED == entry->entry()->Data()->state); |
| 645 |
| 646 Trace("Remove entry 0x%p", entry); |
| 647 eviction_.OnDestroyEntry(entry); |
| 648 DecreaseNumEntries(); |
| 649 } |
| 650 |
| 608 void BackendImpl::CacheEntryDestroyed() { | 651 void BackendImpl::CacheEntryDestroyed() { |
| 609 DecreaseNumRefs(); | 652 DecreaseNumRefs(); |
| 610 } | 653 } |
| 611 | 654 |
| 612 int32 BackendImpl::GetCurrentEntryId() { | 655 int32 BackendImpl::GetCurrentEntryId() { |
| 613 return data_->header.this_id; | 656 return data_->header.this_id; |
| 614 } | 657 } |
| 615 | 658 |
| 616 int BackendImpl::MaxFileSize() const { | 659 int BackendImpl::MaxFileSize() const { |
| 617 return max_size_ / 8; | 660 return max_size_ / 8; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 // ------------------------------------------------------------------------ | 778 // ------------------------------------------------------------------------ |
| 736 | 779 |
| 737 // We just created a new file so we're going to write the header and set the | 780 // We just created a new file so we're going to write the header and set the |
| 738 // file length to include the hash table (zero filled). | 781 // file length to include the hash table (zero filled). |
| 739 bool BackendImpl::CreateBackingStore(disk_cache::File* file) { | 782 bool BackendImpl::CreateBackingStore(disk_cache::File* file) { |
| 740 AdjustMaxCacheSize(0); | 783 AdjustMaxCacheSize(0); |
| 741 | 784 |
| 742 IndexHeader header; | 785 IndexHeader header; |
| 743 header.table_len = DesiredIndexTableLen(max_size_); | 786 header.table_len = DesiredIndexTableLen(max_size_); |
| 744 | 787 |
| 788 // We need file version 2.1 for the new eviction algorithm. |
| 789 if (new_eviction_) |
| 790 header.version = 0x20001; |
| 791 |
| 745 if (!file->Write(&header, sizeof(header), 0)) | 792 if (!file->Write(&header, sizeof(header), 0)) |
| 746 return false; | 793 return false; |
| 747 | 794 |
| 748 return file->SetLength(GetIndexSize(header.table_len)); | 795 return file->SetLength(GetIndexSize(header.table_len)); |
| 749 } | 796 } |
| 750 | 797 |
| 751 bool BackendImpl::InitBackingStore(bool* file_created) { | 798 bool BackendImpl::InitBackingStore(bool* file_created) { |
| 752 file_util::CreateDirectory(path_); | 799 file_util::CreateDirectory(path_); |
| 753 | 800 |
| 754 std::wstring index_name(path_); | 801 std::wstring index_name(path_); |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 955 | 1002 |
| 956 return find_parent ? parent_entry : cache_entry; | 1003 return find_parent ? parent_entry : cache_entry; |
| 957 } | 1004 } |
| 958 | 1005 |
| 959 // This is the actual implementation for OpenNextEntry and OpenPrevEntry. | 1006 // This is the actual implementation for OpenNextEntry and OpenPrevEntry. |
| 960 bool BackendImpl::OpenFollowingEntry(bool forward, void** iter, | 1007 bool BackendImpl::OpenFollowingEntry(bool forward, void** iter, |
| 961 Entry** next_entry) { | 1008 Entry** next_entry) { |
| 962 if (disabled_) | 1009 if (disabled_) |
| 963 return false; | 1010 return false; |
| 964 | 1011 |
| 965 Rankings::ScopedRankingsBlock rankings(&rankings_, | 1012 DCHECK(iter); |
| 966 reinterpret_cast<CacheRankingsBlock*>(*iter)); | 1013 DCHECK(next_entry); |
| 967 CacheRankingsBlock* next_block = forward ? | |
| 968 rankings_.GetNext(rankings.get(), Rankings::NO_USE) : | |
| 969 rankings_.GetPrev(rankings.get(), Rankings::NO_USE); | |
| 970 Rankings::ScopedRankingsBlock next(&rankings_, next_block); | |
| 971 *next_entry = NULL; | 1014 *next_entry = NULL; |
| 1015 |
| 1016 const int kListsToSearch = 3; |
| 1017 scoped_refptr<EntryImpl> entries[kListsToSearch]; |
| 1018 scoped_ptr<Rankings::Iterator> iterator( |
| 1019 reinterpret_cast<Rankings::Iterator*>(*iter)); |
| 972 *iter = NULL; | 1020 *iter = NULL; |
| 973 if (!next.get()) | 1021 |
| 1022 if (!iterator.get()) { |
| 1023 iterator.reset(new Rankings::Iterator(&rankings_)); |
| 1024 bool ret = false; |
| 1025 |
| 1026 // Get an entry from each list. |
| 1027 for (int i = 0; i < kListsToSearch; i++) { |
| 1028 EntryImpl* temp = NULL; |
| 1029 ret |= OpenFollowingEntryFromList(forward, static_cast<Rankings::List>(i), |
| 1030 &iterator->nodes[i], &temp); |
| 1031 entries[i].swap(&temp); // The entry was already addref'd. |
| 1032 } |
| 1033 if (!ret) |
| 1034 return false; |
| 1035 } else { |
| 1036 // Get the next entry from the last list, and the actual entries for the |
| 1037 // elements on the other lists. |
| 1038 for (int i = 0; i < kListsToSearch; i++) { |
| 1039 EntryImpl* temp = NULL; |
| 1040 if (iterator->list == i) { |
| 1041 OpenFollowingEntryFromList(forward, iterator->list, |
| 1042 &iterator->nodes[i], &temp); |
| 1043 } else { |
| 1044 temp = GetEnumeratedEntry(iterator->nodes[i]); |
| 1045 } |
| 1046 |
| 1047 entries[i].swap(&temp); // The entry was already addref'd. |
| 1048 } |
| 1049 } |
| 1050 |
| 1051 int newest = -1; |
| 1052 int oldest = -1; |
| 1053 Time access_times[kListsToSearch]; |
| 1054 for (int i = 0; i < kListsToSearch; i++) { |
| 1055 if (entries[i].get()) { |
| 1056 access_times[i] = entries[i]->GetLastUsed(); |
| 1057 if (newest < 0) { |
| 1058 DCHECK(oldest < 0); |
| 1059 newest = oldest = i; |
| 1060 continue; |
| 1061 } |
| 1062 if (access_times[i] > access_times[newest]) |
| 1063 newest = i; |
| 1064 if (access_times[i] < access_times[oldest]) |
| 1065 oldest = i; |
| 1066 } |
| 1067 } |
| 1068 |
| 1069 if (newest < 0 || oldest < 0) |
| 974 return false; | 1070 return false; |
| 975 | 1071 |
| 976 scoped_refptr<EntryImpl> entry; | 1072 if (forward) { |
| 977 if (next->Data()->pointer) { | 1073 entries[newest].swap(reinterpret_cast<EntryImpl**>(next_entry)); |
| 978 entry = reinterpret_cast<EntryImpl*>(next->Data()->pointer); | 1074 iterator->list = static_cast<Rankings::List>(newest); |
| 979 } else { | 1075 } else { |
| 980 bool dirty; | 1076 entries[oldest].swap(reinterpret_cast<EntryImpl**>(next_entry)); |
| 981 EntryImpl* temp = NULL; | 1077 iterator->list = static_cast<Rankings::List>(oldest); |
| 982 if (NewEntry(Addr(next->Data()->contents), &temp, &dirty)) | |
| 983 return false; | |
| 984 entry.swap(&temp); | |
| 985 | |
| 986 if (dirty) { | |
| 987 // We cannot trust this entry. Call MatchEntry to go through the regular | |
| 988 // path and take the appropriate action. | |
| 989 std::string key = entry->GetKey(); | |
| 990 uint32 hash = entry->GetHash(); | |
| 991 entry = NULL; // Release the entry. | |
| 992 temp = MatchEntry(key, hash, false); | |
| 993 if (temp) | |
| 994 temp->Release(); | |
| 995 | |
| 996 return false; | |
| 997 } | |
| 998 | |
| 999 entry.swap(&temp); | |
| 1000 temp = EntryImpl::Update(temp); // Update returns an adref'd entry. | |
| 1001 entry.swap(&temp); | |
| 1002 if (!entry.get()) | |
| 1003 return false; | |
| 1004 } | 1078 } |
| 1005 | 1079 |
| 1006 entry.swap(reinterpret_cast<EntryImpl**>(next_entry)); | 1080 *iter = iterator.release(); |
| 1007 *iter = next.release(); | |
| 1008 return true; | 1081 return true; |
| 1009 } | 1082 } |
| 1010 | 1083 |
| 1084 bool BackendImpl::OpenFollowingEntryFromList(bool forward, Rankings::List list, |
| 1085 CacheRankingsBlock** from_entry, |
| 1086 EntryImpl** next_entry) { |
| 1087 if (disabled_) |
| 1088 return false; |
| 1089 |
| 1090 if (!new_eviction_ && Rankings::NO_USE != list) |
| 1091 return false; |
| 1092 |
| 1093 Rankings::ScopedRankingsBlock rankings(&rankings_, *from_entry); |
| 1094 CacheRankingsBlock* next_block = forward ? |
| 1095 rankings_.GetNext(rankings.get(), list) : |
| 1096 rankings_.GetPrev(rankings.get(), list); |
| 1097 Rankings::ScopedRankingsBlock next(&rankings_, next_block); |
| 1098 *from_entry = NULL; |
| 1099 |
| 1100 *next_entry = GetEnumeratedEntry(next.get()); |
| 1101 if (!*next_entry) |
| 1102 return false; |
| 1103 |
| 1104 *from_entry = next.release(); |
| 1105 return true; |
| 1106 } |
| 1107 |
| 1108 EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next) { |
| 1109 if (!next) |
| 1110 return NULL; |
| 1111 |
| 1112 scoped_refptr<EntryImpl> entry; |
| 1113 EntryImpl* temp = NULL; |
| 1114 |
| 1115 if (next->Data()->pointer) { |
| 1116 entry = reinterpret_cast<EntryImpl*>(next->Data()->pointer); |
| 1117 entry.swap(&temp); |
| 1118 return temp; |
| 1119 } |
| 1120 |
| 1121 bool dirty; |
| 1122 if (NewEntry(Addr(next->Data()->contents), &temp, &dirty)) |
| 1123 return NULL; |
| 1124 entry.swap(&temp); |
| 1125 |
| 1126 if (dirty) { |
| 1127 // We cannot trust this entry. Call MatchEntry to go through the regular |
| 1128 // path and take the appropriate action. |
| 1129 std::string key = entry->GetKey(); |
| 1130 uint32 hash = entry->GetHash(); |
| 1131 entry = NULL; // Release the entry. |
| 1132 temp = MatchEntry(key, hash, false); |
| 1133 if (temp) |
| 1134 temp->Release(); |
| 1135 |
| 1136 return NULL; |
| 1137 } |
| 1138 |
| 1139 entry.swap(&temp); |
| 1140 return EntryImpl::Update(temp); // Update returns an adref'd entry. |
| 1141 } |
| 1142 |
| 1143 bool BackendImpl::ResurrectEntry(EntryImpl* deleted_entry, Entry** entry) { |
| 1144 if (ENTRY_NORMAL == deleted_entry->entry()->Data()->state) { |
| 1145 deleted_entry->Release(); |
| 1146 stats_.OnEvent(Stats::CREATE_MISS); |
| 1147 Trace("create entry miss "); |
| 1148 return false; |
| 1149 } |
| 1150 |
| 1151 // We are attempting to create an entry and found out that the entry was |
| 1152 // previously deleted. |
| 1153 |
| 1154 eviction_.OnCreateEntry(deleted_entry); |
| 1155 *entry = deleted_entry; |
| 1156 |
| 1157 stats_.OnEvent(Stats::CREATE_HIT); |
| 1158 Trace("Resurrect entry hit "); |
| 1159 return true; |
| 1160 } |
| 1161 |
| 1011 void BackendImpl::DestroyInvalidEntry(Addr address, EntryImpl* entry) { | 1162 void BackendImpl::DestroyInvalidEntry(Addr address, EntryImpl* entry) { |
| 1012 LOG(WARNING) << "Destroying invalid entry."; | 1163 LOG(WARNING) << "Destroying invalid entry."; |
| 1013 Trace("Destroying invalid entry 0x%p", entry); | 1164 Trace("Destroying invalid entry 0x%p", entry); |
| 1014 | 1165 |
| 1015 entry->SetPointerForInvalidEntry(GetCurrentEntryId()); | 1166 entry->SetPointerForInvalidEntry(GetCurrentEntryId()); |
| 1016 | 1167 |
| 1017 eviction_.OnDoomEntry(entry); | 1168 eviction_.OnDoomEntry(entry); |
| 1018 entry->InternalDoom(); | 1169 entry->InternalDoom(); |
| 1019 | 1170 |
| 1020 data_->header.num_entries--; | 1171 if (!new_eviction_) |
| 1021 DCHECK(data_->header.num_entries >= 0); | 1172 DecreaseNumEntries(); |
| 1022 stats_.OnEvent(Stats::INVALID_ENTRY); | 1173 stats_.OnEvent(Stats::INVALID_ENTRY); |
| 1023 } | 1174 } |
| 1024 | 1175 |
| 1025 void BackendImpl::AddStorageSize(int32 bytes) { | 1176 void BackendImpl::AddStorageSize(int32 bytes) { |
| 1026 data_->header.num_bytes += bytes; | 1177 data_->header.num_bytes += bytes; |
| 1027 DCHECK(data_->header.num_bytes >= 0); | 1178 DCHECK(data_->header.num_bytes >= 0); |
| 1028 | 1179 |
| 1029 if (data_->header.num_bytes > max_size_) | 1180 if (data_->header.num_bytes > max_size_) |
| 1030 eviction_.TrimCache(false); | 1181 eviction_.TrimCache(false); |
| 1031 } | 1182 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1042 } | 1193 } |
| 1043 | 1194 |
| 1044 void BackendImpl::DecreaseNumRefs() { | 1195 void BackendImpl::DecreaseNumRefs() { |
| 1045 DCHECK(num_refs_); | 1196 DCHECK(num_refs_); |
| 1046 num_refs_--; | 1197 num_refs_--; |
| 1047 | 1198 |
| 1048 if (!num_refs_ && disabled_) | 1199 if (!num_refs_ && disabled_) |
| 1049 RestartCache(); | 1200 RestartCache(); |
| 1050 } | 1201 } |
| 1051 | 1202 |
| 1203 void BackendImpl::IncreaseNumEntries() { |
| 1204 data_->header.num_entries++; |
| 1205 DCHECK(data_->header.num_entries > 0); |
| 1206 } |
| 1207 |
| 1208 void BackendImpl::DecreaseNumEntries() { |
| 1209 data_->header.num_entries--; |
| 1210 if (data_->header.num_entries < 0) { |
| 1211 NOTREACHED(); |
| 1212 data_->header.num_entries = 0; |
| 1213 } |
| 1214 } |
| 1215 |
| 1052 void BackendImpl::LogStats() { | 1216 void BackendImpl::LogStats() { |
| 1053 StatsItems stats; | 1217 StatsItems stats; |
| 1054 GetStats(&stats); | 1218 GetStats(&stats); |
| 1055 | 1219 |
| 1056 for (size_t index = 0; index < stats.size(); index++) { | 1220 for (size_t index = 0; index < stats.size(); index++) { |
| 1057 LOG(INFO) << stats[index].first << ": " << stats[index].second; | 1221 LOG(INFO) << stats[index].first << ": " << stats[index].second; |
| 1058 } | 1222 } |
| 1059 } | 1223 } |
| 1060 | 1224 |
| 1225 void BackendImpl::UpgradeTo2_1() { |
| 1226 // 2.1 is basically the same as 2.0, except that new fields are actually |
| 1227 // updated by the new eviction algorithm. |
| 1228 DCHECK(0x20000 == data_->header.version); |
| 1229 data_->header.version = 0x20001; |
| 1230 data_->header.lru.sizes[Rankings::NO_USE] = data_->header.num_entries; |
| 1231 } |
| 1232 |
| 1061 bool BackendImpl::CheckIndex() { | 1233 bool BackendImpl::CheckIndex() { |
| 1062 if (!data_) { | 1234 if (!data_) { |
| 1063 LOG(ERROR) << "Unable to map Index file"; | 1235 LOG(ERROR) << "Unable to map Index file"; |
| 1064 return false; | 1236 return false; |
| 1065 } | 1237 } |
| 1066 | 1238 |
| 1067 size_t current_size = index_->GetLength(); | 1239 size_t current_size = index_->GetLength(); |
| 1068 if (current_size < sizeof(Index)) { | 1240 if (current_size < sizeof(Index)) { |
| 1069 LOG(ERROR) << "Corrupt Index file"; | 1241 LOG(ERROR) << "Corrupt Index file"; |
| 1070 return false; | 1242 return false; |
| 1071 } | 1243 } |
| 1072 | 1244 |
| 1073 if (kIndexMagic != data_->header.magic || | 1245 if (new_eviction_) { |
| 1074 kCurrentVersion != data_->header.version) { | 1246 // We support versions 2.0 and 2.1, upgrading 2.0 to 2.1. |
| 1075 LOG(ERROR) << "Invalid file version or magic"; | 1247 if (kIndexMagic != data_->header.magic || |
| 1076 return false; | 1248 kCurrentVersion >> 16 != data_->header.version >> 16) { |
| 1249 LOG(ERROR) << "Invalid file version or magic"; |
| 1250 return false; |
| 1251 } |
| 1252 if (kCurrentVersion == data_->header.version) { |
| 1253 // We need file version 2.1 for the new eviction algorithm. |
| 1254 UpgradeTo2_1(); |
| 1255 } |
| 1256 } else { |
| 1257 if (kIndexMagic != data_->header.magic || |
| 1258 kCurrentVersion != data_->header.version) { |
| 1259 LOG(ERROR) << "Invalid file version or magic"; |
| 1260 return false; |
| 1261 } |
| 1077 } | 1262 } |
| 1078 | 1263 |
| 1079 if (!data_->header.table_len) { | 1264 if (!data_->header.table_len) { |
| 1080 LOG(ERROR) << "Invalid table size"; | 1265 LOG(ERROR) << "Invalid table size"; |
| 1081 return false; | 1266 return false; |
| 1082 } | 1267 } |
| 1083 | 1268 |
| 1084 if (current_size < GetIndexSize(data_->header.table_len) || | 1269 if (current_size < GetIndexSize(data_->header.table_len) || |
| 1085 data_->header.table_len & (kBaseTableLen - 1)) { | 1270 data_->header.table_len & (kBaseTableLen - 1)) { |
| 1086 LOG(ERROR) << "Corrupt Index file"; | 1271 LOG(ERROR) << "Corrupt Index file"; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1153 | 1338 |
| 1154 return num_dirty; | 1339 return num_dirty; |
| 1155 } | 1340 } |
| 1156 | 1341 |
| 1157 bool BackendImpl::CheckEntry(EntryImpl* cache_entry) { | 1342 bool BackendImpl::CheckEntry(EntryImpl* cache_entry) { |
| 1158 RankingsNode* rankings = cache_entry->rankings()->Data(); | 1343 RankingsNode* rankings = cache_entry->rankings()->Data(); |
| 1159 return !rankings->pointer; | 1344 return !rankings->pointer; |
| 1160 } | 1345 } |
| 1161 | 1346 |
| 1162 } // namespace disk_cache | 1347 } // namespace disk_cache |
| OLD | NEW |