| OLD | NEW |
| 1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // The eviction policy is a very simple pure LRU, so the elements at the end of | 5 // The eviction policy is a very simple pure LRU, so the elements at the end of |
| 6 // the list are evicted until kCleanUpMargin free space is available. There is | 6 // the list are evicted until kCleanUpMargin free space is available. There is |
| 7 // only one list in use (Rankings::NO_USE), and elements are sent to the front | 7 // only one list in use (Rankings::NO_USE), and elements are sent to the front |
| 8 // of the list whenever they are accessed. | 8 // of the list whenever they are accessed. |
| 9 | 9 |
| 10 // The new (in-development) eviction policy adds re-use as a factor to evict | 10 // The new (in-development) eviction policy adds re-use as a factor to evict |
| 11 // an entry. The story so far: | 11 // an entry. The story so far: |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 if (new_eviction_) | 109 if (new_eviction_) |
| 110 return TrimCacheV2(empty); | 110 return TrimCacheV2(empty); |
| 111 | 111 |
| 112 Trace("*** Trim Cache ***"); | 112 Trace("*** Trim Cache ***"); |
| 113 trimming_ = true; | 113 trimming_ = true; |
| 114 TimeTicks start = TimeTicks::Now(); | 114 TimeTicks start = TimeTicks::Now(); |
| 115 Rankings::ScopedRankingsBlock node(rankings_); | 115 Rankings::ScopedRankingsBlock node(rankings_); |
| 116 Rankings::ScopedRankingsBlock next(rankings_, | 116 Rankings::ScopedRankingsBlock next(rankings_, |
| 117 rankings_->GetPrev(node.get(), Rankings::NO_USE)); | 117 rankings_->GetPrev(node.get(), Rankings::NO_USE)); |
| 118 int target_size = empty ? 0 : max_size_; | 118 int target_size = empty ? 0 : max_size_; |
| 119 while (header_->num_bytes > target_size && next.get()) { | 119 while ((header_->num_bytes > target_size && next.get()) || test_mode_) { |
| 120 // The iterator could be invalidated within EvictEntry(). | 120 // The iterator could be invalidated within EvictEntry(). |
| 121 if (!next->HasData()) | 121 if (!next->HasData()) |
| 122 break; | 122 break; |
| 123 node.reset(next.release()); | 123 node.reset(next.release()); |
| 124 next.reset(rankings_->GetPrev(node.get(), Rankings::NO_USE)); | 124 next.reset(rankings_->GetPrev(node.get(), Rankings::NO_USE)); |
| 125 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { | 125 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { |
| 126 // This entry is not being used by anybody. | 126 // This entry is not being used by anybody. |
| 127 // Do NOT use node as an iterator after this point. | 127 // Do NOT use node as an iterator after this point. |
| 128 rankings_->TrackRankingsBlock(node.get(), false); | 128 rankings_->TrackRankingsBlock(node.get(), false); |
| 129 if (!EvictEntry(node.get(), empty) && !test_mode_) | 129 if (!EvictEntry(node.get(), empty) && !test_mode_) |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 if (done) | 297 if (done) |
| 298 continue; | 298 continue; |
| 299 next[i].reset(rankings_->GetPrev(NULL, static_cast<Rankings::List>(i))); | 299 next[i].reset(rankings_->GetPrev(NULL, static_cast<Rankings::List>(i))); |
| 300 if (!empty && NodeIsOldEnough(next[i].get(), i)) { | 300 if (!empty && NodeIsOldEnough(next[i].get(), i)) { |
| 301 list = static_cast<Rankings::List>(i); | 301 list = static_cast<Rankings::List>(i); |
| 302 done = true; | 302 done = true; |
| 303 } | 303 } |
| 304 } | 304 } |
| 305 | 305 |
| 306 // If we are not meeting the time targets lets move on to list length. | 306 // If we are not meeting the time targets lets move on to list length. |
| 307 if (!empty && Rankings::LAST_ELEMENT == list) { | 307 if (!empty && Rankings::LAST_ELEMENT == list) |
| 308 list = SelectListByLenght(); | 308 list = SelectListByLenght(next); |
| 309 // Make sure that frequently used items are kept for a minimum time; we know | |
| 310 // that this entry is not older than its current target, but it must be at | |
| 311 // least older than the target for list 0 (kTargetTime). | |
| 312 if ((Rankings::HIGH_USE == list || Rankings::LOW_USE == list) && | |
| 313 !NodeIsOldEnough(next[list].get(), 0)) | |
| 314 list = 0; | |
| 315 } | |
| 316 | 309 |
| 317 if (empty) | 310 if (empty) |
| 318 list = 0; | 311 list = 0; |
| 319 | 312 |
| 320 Rankings::ScopedRankingsBlock node(rankings_); | 313 Rankings::ScopedRankingsBlock node(rankings_); |
| 321 | 314 |
| 322 int target_size = empty ? 0 : max_size_; | 315 int target_size = empty ? 0 : max_size_; |
| 323 for (; list < kListsToSearch; list++) { | 316 for (; list < kListsToSearch; list++) { |
| 324 while (header_->num_bytes > target_size && next[list].get()) { | 317 while ((header_->num_bytes > target_size && next[list].get()) || |
| 318 test_mode_) { |
| 325 // The iterator could be invalidated within EvictEntry(). | 319 // The iterator could be invalidated within EvictEntry(). |
| 326 if (!next[list]->HasData()) | 320 if (!next[list]->HasData()) |
| 327 break; | 321 break; |
| 328 node.reset(next[list].release()); | 322 node.reset(next[list].release()); |
| 329 next[list].reset(rankings_->GetPrev(node.get(), | 323 next[list].reset(rankings_->GetPrev(node.get(), |
| 330 static_cast<Rankings::List>(list))); | 324 static_cast<Rankings::List>(list))); |
| 331 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { | 325 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { |
| 332 // This entry is not being used by anybody. | 326 // This entry is not being used by anybody. |
| 333 // Do NOT use node as an iterator after this point. | 327 // Do NOT use node as an iterator after this point. |
| 334 rankings_->TrackRankingsBlock(node.get(), false); | 328 rankings_->TrackRankingsBlock(node.get(), false); |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 return false; | 501 return false; |
| 508 | 502 |
| 509 // If possible, we want to keep entries on each list at least kTargetTime | 503 // If possible, we want to keep entries on each list at least kTargetTime |
| 510 // hours. Each successive list on the enumeration has 2x the target time of | 504 // hours. Each successive list on the enumeration has 2x the target time of |
| 511 // the previous list. | 505 // the previous list. |
| 512 Time used = Time::FromInternalValue(node->Data()->last_used); | 506 Time used = Time::FromInternalValue(node->Data()->last_used); |
| 513 int multiplier = 1 << list; | 507 int multiplier = 1 << list; |
| 514 return (Time::Now() - used).InHours() > kTargetTime * multiplier; | 508 return (Time::Now() - used).InHours() > kTargetTime * multiplier; |
| 515 } | 509 } |
| 516 | 510 |
| 517 int Eviction::SelectListByLenght() { | 511 int Eviction::SelectListByLenght(Rankings::ScopedRankingsBlock* next) { |
| 518 int data_entries = header_->num_entries - | 512 int data_entries = header_->num_entries - |
| 519 header_->lru.sizes[Rankings::DELETED]; | 513 header_->lru.sizes[Rankings::DELETED]; |
| 520 // Start by having each list to be roughly the same size. | 514 // Start by having each list to be roughly the same size. |
| 521 if (header_->lru.sizes[0] > data_entries / 3) | 515 if (header_->lru.sizes[0] > data_entries / 3) |
| 522 return 0; | 516 return 0; |
| 523 if (header_->lru.sizes[1] > data_entries / 3) | 517 |
| 524 return 1; | 518 int list = (header_->lru.sizes[1] > data_entries / 3) ? 1 : 2; |
| 525 return 2; | 519 |
| 520 // Make sure that frequently used items are kept for a minimum time; we know |
| 521 // that this entry is not older than its current target, but it must be at |
| 522 // least older than the target for list 0 (kTargetTime), as long as we don't |
| 523 // exhaust list 0. |
| 524 if (!NodeIsOldEnough(next[list].get(), 0) && |
| 525 header_->lru.sizes[0] > data_entries / 10) |
| 526 list = 0; |
| 527 |
| 528 return list; |
| 526 } | 529 } |
| 527 | 530 |
| 528 void Eviction::ReportListStats() { | 531 void Eviction::ReportListStats() { |
| 529 if (!new_eviction_) | 532 if (!new_eviction_) |
| 530 return; | 533 return; |
| 531 | 534 |
| 532 Rankings::ScopedRankingsBlock last1(rankings_, | 535 Rankings::ScopedRankingsBlock last1(rankings_, |
| 533 rankings_->GetPrev(NULL, Rankings::NO_USE)); | 536 rankings_->GetPrev(NULL, Rankings::NO_USE)); |
| 534 Rankings::ScopedRankingsBlock last2(rankings_, | 537 Rankings::ScopedRankingsBlock last2(rankings_, |
| 535 rankings_->GetPrev(NULL, Rankings::LOW_USE)); | 538 rankings_->GetPrev(NULL, Rankings::LOW_USE)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 546 Time::FromInternalValue(last2.get()->Data()->last_used)); | 549 Time::FromInternalValue(last2.get()->Data()->last_used)); |
| 547 if (last3.get()) | 550 if (last3.get()) |
| 548 CACHE_UMA(AGE, "HighUseAge", 0, | 551 CACHE_UMA(AGE, "HighUseAge", 0, |
| 549 Time::FromInternalValue(last3.get()->Data()->last_used)); | 552 Time::FromInternalValue(last3.get()->Data()->last_used)); |
| 550 if (last4.get()) | 553 if (last4.get()) |
| 551 CACHE_UMA(AGE, "DeletedAge", 0, | 554 CACHE_UMA(AGE, "DeletedAge", 0, |
| 552 Time::FromInternalValue(last4.get()->Data()->last_used)); | 555 Time::FromInternalValue(last4.get()->Data()->last_used)); |
| 553 } | 556 } |
| 554 | 557 |
| 555 } // namespace disk_cache | 558 } // namespace disk_cache |
| OLD | NEW |