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 |