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 |