| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 #define CACHE_UMA_BACKEND_IMPL_OBJ backend_ | 43 #define CACHE_UMA_BACKEND_IMPL_OBJ backend_ |
| 44 | 44 |
| 45 using base::Time; | 45 using base::Time; |
| 46 using base::TimeTicks; | 46 using base::TimeTicks; |
| 47 | 47 |
| 48 namespace { | 48 namespace { |
| 49 | 49 |
| 50 const int kCleanUpMargin = 1024 * 1024; | 50 const int kCleanUpMargin = 1024 * 1024; |
| 51 | 51 |
| 52 #if defined(V3_NOT_JUST_YET_READY) | 52 #if defined(V3_NOT_JUST_YET_READY) |
| 53 const int kHighUse = 10; // Reuse count to be on the HIGH_USE list. | 53 const int kHighUse = 10; // Reuse count to be on the HIGH_USE list. |
| 54 const int kTargetTime = 24 * 7; // Time to be evicted (hours since last use). | 54 const int kTargetTime = 24 * 7; // Time to be evicted (hours since last use). |
| 55 const int kMaxDelayedTrims = 60; | 55 const int kMaxDelayedTrims = 60; |
| 56 #endif // defined(V3_NOT_JUST_YET_READY). | 56 #endif // defined(V3_NOT_JUST_YET_READY). |
| 57 | 57 |
| 58 int LowWaterAdjust(int high_water) { | 58 int LowWaterAdjust(int high_water) { |
| 59 if (high_water < kCleanUpMargin) | 59 if (high_water < kCleanUpMargin) |
| 60 return 0; | 60 return 0; |
| 61 | 61 |
| 62 return high_water - kCleanUpMargin; | 62 return high_water - kCleanUpMargin; |
| 63 } | 63 } |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 trim_delays_ = 0; | 261 trim_delays_ = 0; |
| 262 return true; | 262 return true; |
| 263 } | 263 } |
| 264 | 264 |
| 265 bool EvictionV3::ShouldTrimDeleted() { | 265 bool EvictionV3::ShouldTrimDeleted() { |
| 266 int index_load = header_->num_entries * 100 / index_size_; | 266 int index_load = header_->num_entries * 100 / index_size_; |
| 267 | 267 |
| 268 // If the index is not loaded, the deleted list will tend to double the size | 268 // If the index is not loaded, the deleted list will tend to double the size |
| 269 // of the other lists 3 lists (40% of the total). Otherwise, all lists will be | 269 // of the other lists 3 lists (40% of the total). Otherwise, all lists will be |
| 270 // about the same size. | 270 // about the same size. |
| 271 int max_length = (index_load < 25) ? header_->num_entries * 2 / 5 : | 271 int max_length = (index_load < 25) ? header_->num_entries * 2 / 5 |
| 272 header_->num_entries / 4; | 272 : header_->num_entries / 4; |
| 273 return (!test_mode_ && header_->lru.sizes[Rankings::DELETED] > max_length); | 273 return (!test_mode_ && header_->lru.sizes[Rankings::DELETED] > max_length); |
| 274 } | 274 } |
| 275 | 275 |
| 276 bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty, | 276 bool Eviction::EvictEntry(CacheRankingsBlock* node, |
| 277 bool empty, |
| 277 Rankings::List list) { | 278 Rankings::List list) { |
| 278 EntryImplV3* entry = backend_->GetEnumeratedEntry(node, list); | 279 EntryImplV3* entry = backend_->GetEnumeratedEntry(node, list); |
| 279 if (!entry) { | 280 if (!entry) { |
| 280 Trace("NewEntry failed on Trim 0x%x", node->address().value()); | 281 Trace("NewEntry failed on Trim 0x%x", node->address().value()); |
| 281 return false; | 282 return false; |
| 282 } | 283 } |
| 283 | 284 |
| 284 ReportTrimTimes(entry); | 285 ReportTrimTimes(entry); |
| 285 if (empty || !new_eviction_) { | 286 if (empty || !new_eviction_) { |
| 286 entry->DoomImpl(); | 287 entry->DoomImpl(); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 int deleted_entries = 0; | 336 int deleted_entries = 0; |
| 336 int target_size = empty ? 0 : max_size_; | 337 int target_size = empty ? 0 : max_size_; |
| 337 | 338 |
| 338 for (; list < kListsToSearch; list++) { | 339 for (; list < kListsToSearch; list++) { |
| 339 while ((header_->num_bytes > target_size || test_mode_) && | 340 while ((header_->num_bytes > target_size || test_mode_) && |
| 340 next[list].get()) { | 341 next[list].get()) { |
| 341 // The iterator could be invalidated within EvictEntry(). | 342 // The iterator could be invalidated within EvictEntry(). |
| 342 if (!next[list]->HasData()) | 343 if (!next[list]->HasData()) |
| 343 break; | 344 break; |
| 344 node.reset(next[list].release()); | 345 node.reset(next[list].release()); |
| 345 next[list].reset(rankings_->GetPrev(node.get(), | 346 next[list].reset( |
| 346 static_cast<Rankings::List>(list))); | 347 rankings_->GetPrev(node.get(), static_cast<Rankings::List>(list))); |
| 347 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { | 348 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { |
| 348 // This entry is not being used by anybody. | 349 // This entry is not being used by anybody. |
| 349 // Do NOT use node as an iterator after this point. | 350 // Do NOT use node as an iterator after this point. |
| 350 rankings_->TrackRankingsBlock(node.get(), false); | 351 rankings_->TrackRankingsBlock(node.get(), false); |
| 351 if (EvictEntry(node.get(), empty, static_cast<Rankings::List>(list))) | 352 if (EvictEntry(node.get(), empty, static_cast<Rankings::List>(list))) |
| 352 deleted_entries++; | 353 deleted_entries++; |
| 353 | 354 |
| 354 if (!empty && test_mode_) | 355 if (!empty && test_mode_) |
| 355 break; | 356 break; |
| 356 } | 357 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 // This is a minimal implementation that just discards the oldest nodes. | 390 // This is a minimal implementation that just discards the oldest nodes. |
| 390 // TODO(rvargas): Do something better here. | 391 // TODO(rvargas): Do something better here. |
| 391 void EvictionV3::TrimDeleted(bool empty) { | 392 void EvictionV3::TrimDeleted(bool empty) { |
| 392 Trace("*** Trim Deleted ***"); | 393 Trace("*** Trim Deleted ***"); |
| 393 if (backend_->disabled_) | 394 if (backend_->disabled_) |
| 394 return; | 395 return; |
| 395 | 396 |
| 396 TimeTicks start = TimeTicks::Now(); | 397 TimeTicks start = TimeTicks::Now(); |
| 397 Rankings::ScopedRankingsBlock node(rankings_); | 398 Rankings::ScopedRankingsBlock node(rankings_); |
| 398 Rankings::ScopedRankingsBlock next( | 399 Rankings::ScopedRankingsBlock next( |
| 399 rankings_, rankings_->GetPrev(node.get(), Rankings::DELETED)); | 400 rankings_, rankings_->GetPrev(node.get(), Rankings::DELETED)); |
| 400 int deleted_entries = 0; | 401 int deleted_entries = 0; |
| 401 while (next.get() && | 402 while (next.get() && |
| 402 (empty || (deleted_entries < 20 && | 403 (empty || (deleted_entries < 20 && |
| 403 (TimeTicks::Now() - start).InMilliseconds() < 20))) { | 404 (TimeTicks::Now() - start).InMilliseconds() < 20))) { |
| 404 node.reset(next.release()); | 405 node.reset(next.release()); |
| 405 next.reset(rankings_->GetPrev(node.get(), Rankings::DELETED)); | 406 next.reset(rankings_->GetPrev(node.get(), Rankings::DELETED)); |
| 406 if (RemoveDeletedNode(node.get())) | 407 if (RemoveDeletedNode(node.get())) |
| 407 deleted_entries++; | 408 deleted_entries++; |
| 408 if (test_mode_) | 409 if (test_mode_) |
| 409 break; | 410 break; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 | 456 |
| 456 // If possible, we want to keep entries on each list at least kTargetTime | 457 // If possible, we want to keep entries on each list at least kTargetTime |
| 457 // hours. Each successive list on the enumeration has 2x the target time of | 458 // hours. Each successive list on the enumeration has 2x the target time of |
| 458 // the previous list. | 459 // the previous list. |
| 459 Time used = Time::FromInternalValue(node->Data()->last_used); | 460 Time used = Time::FromInternalValue(node->Data()->last_used); |
| 460 int multiplier = 1 << list; | 461 int multiplier = 1 << list; |
| 461 return (Time::Now() - used).InHours() > kTargetTime * multiplier; | 462 return (Time::Now() - used).InHours() > kTargetTime * multiplier; |
| 462 } | 463 } |
| 463 | 464 |
| 464 int EvictionV3::SelectListByLength(Rankings::ScopedRankingsBlock* next) { | 465 int EvictionV3::SelectListByLength(Rankings::ScopedRankingsBlock* next) { |
| 465 int data_entries = header_->num_entries - | 466 int data_entries = |
| 466 header_->lru.sizes[Rankings::DELETED]; | 467 header_->num_entries - header_->lru.sizes[Rankings::DELETED]; |
| 467 // Start by having each list to be roughly the same size. | 468 // Start by having each list to be roughly the same size. |
| 468 if (header_->lru.sizes[0] > data_entries / 3) | 469 if (header_->lru.sizes[0] > data_entries / 3) |
| 469 return 0; | 470 return 0; |
| 470 | 471 |
| 471 int list = (header_->lru.sizes[1] > data_entries / 3) ? 1 : 2; | 472 int list = (header_->lru.sizes[1] > data_entries / 3) ? 1 : 2; |
| 472 | 473 |
| 473 // Make sure that frequently used items are kept for a minimum time; we know | 474 // Make sure that frequently used items are kept for a minimum time; we know |
| 474 // that this entry is not older than its current target, but it must be at | 475 // that this entry is not older than its current target, but it must be at |
| 475 // least older than the target for list 0 (kTargetTime), as long as we don't | 476 // least older than the target for list 0 (kTargetTime), as long as we don't |
| 476 // exhaust list 0. | 477 // exhaust list 0. |
| 477 if (!NodeIsOldEnough(next[list].get(), 0) && | 478 if (!NodeIsOldEnough(next[list].get(), 0) && |
| 478 header_->lru.sizes[0] > data_entries / 10) | 479 header_->lru.sizes[0] > data_entries / 10) |
| 479 list = 0; | 480 list = 0; |
| 480 | 481 |
| 481 return list; | 482 return list; |
| 482 } | 483 } |
| 483 | 484 |
| 484 void EvictionV3::ReportListStats() { | 485 void EvictionV3::ReportListStats() { |
| 485 if (!new_eviction_) | 486 if (!new_eviction_) |
| 486 return; | 487 return; |
| 487 | 488 |
| 488 Rankings::ScopedRankingsBlock last1(rankings_, | 489 Rankings::ScopedRankingsBlock last1( |
| 489 rankings_->GetPrev(NULL, Rankings::NO_USE)); | 490 rankings_, rankings_->GetPrev(NULL, Rankings::NO_USE)); |
| 490 Rankings::ScopedRankingsBlock last2(rankings_, | 491 Rankings::ScopedRankingsBlock last2( |
| 491 rankings_->GetPrev(NULL, Rankings::LOW_USE)); | 492 rankings_, rankings_->GetPrev(NULL, Rankings::LOW_USE)); |
| 492 Rankings::ScopedRankingsBlock last3(rankings_, | 493 Rankings::ScopedRankingsBlock last3( |
| 493 rankings_->GetPrev(NULL, Rankings::HIGH_USE)); | 494 rankings_, rankings_->GetPrev(NULL, Rankings::HIGH_USE)); |
| 494 Rankings::ScopedRankingsBlock last4(rankings_, | 495 Rankings::ScopedRankingsBlock last4( |
| 495 rankings_->GetPrev(NULL, Rankings::DELETED)); | 496 rankings_, rankings_->GetPrev(NULL, Rankings::DELETED)); |
| 496 | 497 |
| 497 if (last1.get()) | 498 if (last1.get()) |
| 498 CACHE_UMA(AGE, "NoUseAge", 0, | 499 CACHE_UMA(AGE, |
| 500 "NoUseAge", |
| 501 0, |
| 499 Time::FromInternalValue(last1.get()->Data()->last_used)); | 502 Time::FromInternalValue(last1.get()->Data()->last_used)); |
| 500 if (last2.get()) | 503 if (last2.get()) |
| 501 CACHE_UMA(AGE, "LowUseAge", 0, | 504 CACHE_UMA(AGE, |
| 505 "LowUseAge", |
| 506 0, |
| 502 Time::FromInternalValue(last2.get()->Data()->last_used)); | 507 Time::FromInternalValue(last2.get()->Data()->last_used)); |
| 503 if (last3.get()) | 508 if (last3.get()) |
| 504 CACHE_UMA(AGE, "HighUseAge", 0, | 509 CACHE_UMA(AGE, |
| 510 "HighUseAge", |
| 511 0, |
| 505 Time::FromInternalValue(last3.get()->Data()->last_used)); | 512 Time::FromInternalValue(last3.get()->Data()->last_used)); |
| 506 if (last4.get()) | 513 if (last4.get()) |
| 507 CACHE_UMA(AGE, "DeletedAge", 0, | 514 CACHE_UMA(AGE, |
| 515 "DeletedAge", |
| 516 0, |
| 508 Time::FromInternalValue(last4.get()->Data()->last_used)); | 517 Time::FromInternalValue(last4.get()->Data()->last_used)); |
| 509 } | 518 } |
| 510 #endif // defined(V3_NOT_JUST_YET_READY). | 519 #endif // defined(V3_NOT_JUST_YET_READY). |
| 511 | 520 |
| 512 } // namespace disk_cache | 521 } // namespace disk_cache |
| OLD | NEW |