| 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 // 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 ads re-use as a factor to evict | 10 // The new (in-development) eviction policy ads re-use as a factor to evict |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 new_eviction_ = backend->new_eviction_; | 66 new_eviction_ = backend->new_eviction_; |
| 67 first_trim_ = true; | 67 first_trim_ = true; |
| 68 trimming_ = false; | 68 trimming_ = false; |
| 69 delay_trim_ = false; | 69 delay_trim_ = false; |
| 70 } | 70 } |
| 71 | 71 |
| 72 void Eviction::TrimCache(bool empty) { | 72 void Eviction::TrimCache(bool empty) { |
| 73 if (new_eviction_) | 73 if (new_eviction_) |
| 74 return TrimCacheV2(empty); | 74 return TrimCacheV2(empty); |
| 75 | 75 |
| 76 Trace("*** Trim Cache ***"); | |
| 77 if (backend_->disabled_ || trimming_) | 76 if (backend_->disabled_ || trimming_) |
| 78 return; | 77 return; |
| 79 | 78 |
| 80 if (!empty && backend_->IsLoaded()) | 79 if (!empty && backend_->IsLoaded()) |
| 81 return PostDelayedTrim(); | 80 return PostDelayedTrim(); |
| 82 | 81 |
| 82 Trace("*** Trim Cache ***"); |
| 83 trimming_ = true; | 83 trimming_ = true; |
| 84 Time start = Time::Now(); | 84 Time start = Time::Now(); |
| 85 Rankings::ScopedRankingsBlock node(rankings_); | 85 Rankings::ScopedRankingsBlock node(rankings_); |
| 86 Rankings::ScopedRankingsBlock next(rankings_, | 86 Rankings::ScopedRankingsBlock next(rankings_, |
| 87 rankings_->GetPrev(node.get(), Rankings::NO_USE)); | 87 rankings_->GetPrev(node.get(), Rankings::NO_USE)); |
| 88 DCHECK(next.get()); | |
| 89 int target_size = empty ? 0 : max_size_; | 88 int target_size = empty ? 0 : max_size_; |
| 90 while (header_->num_bytes > target_size && next.get()) { | 89 while (header_->num_bytes > target_size && next.get()) { |
| 90 // The iterator could be invalidated within EvictEntry(). |
| 91 if (!next->HasData()) |
| 92 break; |
| 91 node.reset(next.release()); | 93 node.reset(next.release()); |
| 92 next.reset(rankings_->GetPrev(node.get(), Rankings::NO_USE)); | 94 next.reset(rankings_->GetPrev(node.get(), Rankings::NO_USE)); |
| 93 if (!node->Data()->pointer || empty) { | 95 if (!node->Data()->pointer || empty) { |
| 94 // This entry is not being used by anybody. | 96 // This entry is not being used by anybody. |
| 97 // Do NOT use node as an iterator after this point. |
| 98 rankings_->TrackRankingsBlock(node.get(), false); |
| 95 if (!EvictEntry(node.get(), empty)) | 99 if (!EvictEntry(node.get(), empty)) |
| 96 continue; | 100 continue; |
| 97 | 101 |
| 98 if (!empty) { | 102 if (!empty) { |
| 99 backend_->OnEvent(Stats::TRIM_ENTRY); | 103 backend_->OnEvent(Stats::TRIM_ENTRY); |
| 100 | 104 |
| 101 if ((Time::Now() - start).InMilliseconds() > 20) { | 105 if ((Time::Now() - start).InMilliseconds() > 20) { |
| 102 MessageLoop::current()->PostTask(FROM_HERE, | 106 MessageLoop::current()->PostTask(FROM_HERE, |
| 103 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); | 107 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); |
| 104 break; | 108 break; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 header_->create_time = Time::FromLocalExploded(old).ToInternalValue(); | 188 header_->create_time = Time::FromLocalExploded(old).ToInternalValue(); |
| 185 } | 189 } |
| 186 } | 190 } |
| 187 } | 191 } |
| 188 | 192 |
| 189 Rankings::List Eviction::GetListForEntry(EntryImpl* entry) { | 193 Rankings::List Eviction::GetListForEntry(EntryImpl* entry) { |
| 190 return Rankings::NO_USE; | 194 return Rankings::NO_USE; |
| 191 } | 195 } |
| 192 | 196 |
| 193 bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty) { | 197 bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty) { |
| 194 EntryImpl* entry; | 198 EntryImpl* entry = backend_->GetEnumeratedEntry(node, true); |
| 195 bool dirty; | 199 if (!entry) { |
| 196 if (backend_->NewEntry(Addr(node->Data()->contents), &entry, &dirty)) { | |
| 197 Trace("NewEntry failed on Trim 0x%x", node->address().value()); | 200 Trace("NewEntry failed on Trim 0x%x", node->address().value()); |
| 198 return false; | 201 return false; |
| 199 } | 202 } |
| 200 | 203 |
| 201 if (node->Data()->pointer) { | |
| 202 // We ignore the failure; we're removing the entry anyway. | |
| 203 entry->Update(); | |
| 204 } | |
| 205 ReportTrimTimes(entry); | 204 ReportTrimTimes(entry); |
| 206 if (empty || !new_eviction_) { | 205 if (empty || !new_eviction_) { |
| 207 entry->Doom(); | 206 entry->Doom(); |
| 208 } else { | 207 } else { |
| 209 entry->DeleteEntryData(false); | 208 entry->DeleteEntryData(false); |
| 210 EntryStore* info = entry->entry()->Data(); | 209 EntryStore* info = entry->entry()->Data(); |
| 211 DCHECK(ENTRY_NORMAL == info->state); | 210 DCHECK(ENTRY_NORMAL == info->state); |
| 212 | 211 |
| 213 rankings_->Remove(entry->rankings(), GetListForEntryV2(entry)); | 212 rankings_->Remove(entry->rankings(), GetListForEntryV2(entry)); |
| 214 info->state = ENTRY_EVICTED; | 213 info->state = ENTRY_EVICTED; |
| 215 entry->entry()->Store(); | 214 entry->entry()->Store(); |
| 216 rankings_->Insert(entry->rankings(), true, Rankings::DELETED); | 215 rankings_->Insert(entry->rankings(), true, Rankings::DELETED); |
| 217 backend_->OnEvent(Stats::TRIM_ENTRY); | 216 backend_->OnEvent(Stats::TRIM_ENTRY); |
| 218 } | 217 } |
| 219 entry->Release(); | 218 entry->Release(); |
| 220 | 219 |
| 221 return true; | 220 return true; |
| 222 } | 221 } |
| 223 | 222 |
| 224 // ----------------------------------------------------------------------- | 223 // ----------------------------------------------------------------------- |
| 225 | 224 |
| 226 void Eviction::TrimCacheV2(bool empty) { | 225 void Eviction::TrimCacheV2(bool empty) { |
| 227 Trace("*** Trim Cache ***"); | |
| 228 if (backend_->disabled_ || trimming_) | 226 if (backend_->disabled_ || trimming_) |
| 229 return; | 227 return; |
| 230 | 228 |
| 231 if (!empty && backend_->IsLoaded()) | 229 if (!empty && backend_->IsLoaded()) |
| 232 return PostDelayedTrim(); | 230 return PostDelayedTrim(); |
| 233 | 231 |
| 232 Trace("*** Trim Cache ***"); |
| 234 trimming_ = true; | 233 trimming_ = true; |
| 235 Time start = Time::Now(); | 234 Time start = Time::Now(); |
| 236 | 235 |
| 237 const int kListsToSearch = 3; | 236 const int kListsToSearch = 3; |
| 238 Rankings::ScopedRankingsBlock next[kListsToSearch]; | 237 Rankings::ScopedRankingsBlock next[kListsToSearch]; |
| 239 int list = Rankings::LAST_ELEMENT; | 238 int list = Rankings::LAST_ELEMENT; |
| 240 | 239 |
| 241 // Get a node from each list. | 240 // Get a node from each list. |
| 242 for (int i = 0; i < kListsToSearch; i++) { | 241 for (int i = 0; i < kListsToSearch; i++) { |
| 243 bool done = false; | 242 bool done = false; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 263 } | 262 } |
| 264 | 263 |
| 265 if (empty) | 264 if (empty) |
| 266 list = 0; | 265 list = 0; |
| 267 | 266 |
| 268 Rankings::ScopedRankingsBlock node(rankings_); | 267 Rankings::ScopedRankingsBlock node(rankings_); |
| 269 | 268 |
| 270 int target_size = empty ? 0 : max_size_; | 269 int target_size = empty ? 0 : max_size_; |
| 271 for (; list < kListsToSearch; list++) { | 270 for (; list < kListsToSearch; list++) { |
| 272 while (header_->num_bytes > target_size && next[list].get()) { | 271 while (header_->num_bytes > target_size && next[list].get()) { |
| 272 // The iterator could be invalidated within EvictEntry(). |
| 273 if (!next[list]->HasData()) |
| 274 break; |
| 273 node.reset(next[list].release()); | 275 node.reset(next[list].release()); |
| 274 next[list].reset(rankings_->GetPrev(node.get(), | 276 next[list].reset(rankings_->GetPrev(node.get(), |
| 275 static_cast<Rankings::List>(list))); | 277 static_cast<Rankings::List>(list))); |
| 276 if (!node->Data()->pointer || empty) { | 278 if (!node->Data()->pointer || empty) { |
| 277 // This entry is not being used by anybody. | 279 // This entry is not being used by anybody. |
| 280 // Do NOT use node as an iterator after this point. |
| 281 rankings_->TrackRankingsBlock(node.get(), false); |
| 278 if (!EvictEntry(node.get(), empty)) | 282 if (!EvictEntry(node.get(), empty)) |
| 279 continue; | 283 continue; |
| 280 | 284 |
| 281 if (!empty && (Time::Now() - start).InMilliseconds() > 20) { | 285 if (!empty && (Time::Now() - start).InMilliseconds() > 20) { |
| 282 MessageLoop::current()->PostTask(FROM_HERE, | 286 MessageLoop::current()->PostTask(FROM_HERE, |
| 283 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); | 287 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); |
| 284 break; | 288 break; |
| 285 } | 289 } |
| 286 } | 290 } |
| 287 } | 291 } |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 } | 416 } |
| 413 | 417 |
| 414 bool Eviction::RemoveDeletedNode(CacheRankingsBlock* node) { | 418 bool Eviction::RemoveDeletedNode(CacheRankingsBlock* node) { |
| 415 EntryImpl* entry; | 419 EntryImpl* entry; |
| 416 bool dirty; | 420 bool dirty; |
| 417 if (backend_->NewEntry(Addr(node->Data()->contents), &entry, &dirty)) { | 421 if (backend_->NewEntry(Addr(node->Data()->contents), &entry, &dirty)) { |
| 418 Trace("NewEntry failed on Trim 0x%x", node->address().value()); | 422 Trace("NewEntry failed on Trim 0x%x", node->address().value()); |
| 419 return false; | 423 return false; |
| 420 } | 424 } |
| 421 | 425 |
| 426 // TODO(rvargas): figure out how to deal with corruption at this point (dirty |
| 427 // entries that live in this list). |
| 422 if (node->Data()->pointer) { | 428 if (node->Data()->pointer) { |
| 423 // We ignore the failure; we're removing the entry anyway. | 429 // We ignore the failure; we're removing the entry anyway. |
| 424 entry->Update(); | 430 entry->Update(); |
| 425 } | 431 } |
| 426 entry->entry()->Data()->state = ENTRY_DOOMED; | 432 entry->entry()->Data()->state = ENTRY_DOOMED; |
| 427 entry->Doom(); | 433 entry->Doom(); |
| 428 entry->Release(); | 434 entry->Release(); |
| 429 return true; | 435 return true; |
| 430 } | 436 } |
| 431 | 437 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 Time::FromInternalValue(last2.get()->Data()->last_used)); | 479 Time::FromInternalValue(last2.get()->Data()->last_used)); |
| 474 if (last3.get()) | 480 if (last3.get()) |
| 475 CACHE_UMA(AGE, "HighUseAge", header_->experiment, | 481 CACHE_UMA(AGE, "HighUseAge", header_->experiment, |
| 476 Time::FromInternalValue(last3.get()->Data()->last_used)); | 482 Time::FromInternalValue(last3.get()->Data()->last_used)); |
| 477 if (last4.get()) | 483 if (last4.get()) |
| 478 CACHE_UMA(AGE, "DeletedAge", header_->experiment, | 484 CACHE_UMA(AGE, "DeletedAge", header_->experiment, |
| 479 Time::FromInternalValue(last4.get()->Data()->last_used)); | 485 Time::FromInternalValue(last4.get()->Data()->last_used)); |
| 480 } | 486 } |
| 481 | 487 |
| 482 } // namespace disk_cache | 488 } // namespace disk_cache |
| OLD | NEW |