Chromium Code Reviews| 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 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 202 if (done) | 202 if (done) |
| 203 continue; | 203 continue; |
| 204 next[i].reset(rankings_->GetPrev(NULL, static_cast<Rankings::List>(i))); | 204 next[i].reset(rankings_->GetPrev(NULL, static_cast<Rankings::List>(i))); |
| 205 if (!empty && NodeIsOldEnough(next[i].get(), i)) { | 205 if (!empty && NodeIsOldEnough(next[i].get(), i)) { |
| 206 list = static_cast<Rankings::List>(i); | 206 list = static_cast<Rankings::List>(i); |
| 207 done = true; | 207 done = true; |
| 208 } | 208 } |
| 209 } | 209 } |
| 210 | 210 |
| 211 // If we are not meeting the time targets lets move on to list length. | 211 // If we are not meeting the time targets lets move on to list length. |
| 212 if (!empty && Rankings::LAST_ELEMENT == list) | 212 if (!empty && Rankings::LAST_ELEMENT == list) { |
| 213 list = SelectListByLenght(); | 213 list = SelectListByLenght(); |
| 214 // Make sure that frequently used items are kept for a minimum time. | |
| 215 if (Rankings::HIGH_USE == list && | |
| 216 !NodeIsOldEnough(next[Rankings::HIGH_USE].get(), 0)) | |
|
Nicolas Sylvain
2009/03/18 17:17:35
the zero here, it should not be "list" ?
rvargas (doing something else)
2009/03/18 17:32:13
no 'cause NodeIsOldEnough(next[2], 2) was already
| |
| 217 list = 0; | |
| 218 } | |
| 214 | 219 |
| 215 if (empty) | 220 if (empty) |
| 216 list = 0; | 221 list = 0; |
| 217 | 222 |
| 218 Rankings::ScopedRankingsBlock node(rankings_); | 223 Rankings::ScopedRankingsBlock node(rankings_); |
| 219 | 224 |
| 220 int target_size = empty ? 0 : max_size_; | 225 int target_size = empty ? 0 : max_size_; |
| 221 int deleted = 0; | 226 int deleted = 0; |
| 222 for (; list < kListsToSearch; list++) { | 227 for (; list < kListsToSearch; list++) { |
| 223 while (header_->num_bytes > target_size && next[list].get()) { | 228 while (header_->num_bytes > target_size && next[list].get()) { |
| 224 node.reset(next[list].release()); | 229 node.reset(next[list].release()); |
| 225 next[list].reset(rankings_->GetPrev(node.get(), | 230 next[list].reset(rankings_->GetPrev(node.get(), |
| 226 static_cast<Rankings::List>(list))); | 231 static_cast<Rankings::List>(list))); |
| 227 if (!node->Data()->pointer || empty) { | 232 if (!node->Data()->pointer || empty) { |
| 228 // This entry is not being used by anybody. | 233 // This entry is not being used by anybody. |
| 229 if (!EvictEntry(node.get(), empty)) | 234 if (!EvictEntry(node.get(), empty)) |
| 230 continue; | 235 continue; |
| 231 | 236 |
| 232 if (++deleted == 4 && !empty) { | 237 if (++deleted == 4 && !empty) { |
| 233 MessageLoop::current()->PostTask(FROM_HERE, | 238 MessageLoop::current()->PostTask(FROM_HERE, |
| 234 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); | 239 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); |
| 235 break; | 240 break; |
| 236 } | 241 } |
| 237 } | 242 } |
| 238 } | 243 } |
| 239 if (!empty) | 244 if (!empty) |
| 240 list = kListsToSearch; | 245 list = kListsToSearch; |
| 241 } | 246 } |
| 242 | 247 |
| 243 if (empty || header_->lru.sizes[Rankings::DELETED] > header_->num_entries / 4) | 248 if (empty) { |
| 249 TrimDeleted(true); | |
| 250 } else if (header_->lru.sizes[Rankings::DELETED] > header_->num_entries / 4) { | |
| 244 MessageLoop::current()->PostTask(FROM_HERE, | 251 MessageLoop::current()->PostTask(FROM_HERE, |
| 245 factory_.NewRunnableMethod(&Eviction::TrimDeleted, empty)); | 252 factory_.NewRunnableMethod(&Eviction::TrimDeleted, empty)); |
| 253 } | |
| 246 | 254 |
| 247 UMA_HISTOGRAM_TIMES("DiskCache.TotalTrimTime", Time::Now() - start); | 255 UMA_HISTOGRAM_TIMES("DiskCache.TotalTrimTime", Time::Now() - start); |
| 248 Trace("*** Trim Cache end ***"); | 256 Trace("*** Trim Cache end ***"); |
| 249 return; | 257 return; |
| 250 } | 258 } |
| 251 | 259 |
| 252 void Eviction::UpdateRankV2(EntryImpl* entry, bool modified) { | 260 void Eviction::UpdateRankV2(EntryImpl* entry, bool modified) { |
| 253 rankings_->UpdateRank(entry->rankings(), modified, GetListForEntryV2(entry)); | 261 rankings_->UpdateRank(entry->rankings(), modified, GetListForEntryV2(entry)); |
| 254 } | 262 } |
| 255 | 263 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 | 333 |
| 326 if (!info->reuse_count) | 334 if (!info->reuse_count) |
| 327 return Rankings::NO_USE; | 335 return Rankings::NO_USE; |
| 328 | 336 |
| 329 if (info->reuse_count < kHighUse) | 337 if (info->reuse_count < kHighUse) |
| 330 return Rankings::LOW_USE; | 338 return Rankings::LOW_USE; |
| 331 | 339 |
| 332 return Rankings::HIGH_USE; | 340 return Rankings::HIGH_USE; |
| 333 } | 341 } |
| 334 | 342 |
| 343 // This is a minimal implementation that just discards the oldest nodes. | |
| 344 // TODO(rvargas): Do something better here. | |
| 335 void Eviction::TrimDeleted(bool empty) { | 345 void Eviction::TrimDeleted(bool empty) { |
| 346 Trace("*** Trim Deleted ***"); | |
| 347 if (backend_->disabled_) | |
| 348 return; | |
| 349 | |
| 350 Time start = Time::Now(); | |
| 351 Rankings::ScopedRankingsBlock node(rankings_); | |
| 352 Rankings::ScopedRankingsBlock next(rankings_, | |
| 353 rankings_->GetPrev(node.get(), Rankings::DELETED)); | |
| 354 DCHECK(next.get()); | |
| 355 for (int i = 0; (i < 4 || empty) && next.get(); i++) { | |
| 356 node.reset(next.release()); | |
| 357 next.reset(rankings_->GetPrev(node.get(), Rankings::DELETED)); | |
| 358 RemoveDeletedNode(node.get()); | |
| 359 } | |
| 360 | |
| 361 if (header_->lru.sizes[Rankings::DELETED] > header_->num_entries / 4) | |
| 362 MessageLoop::current()->PostTask(FROM_HERE, | |
| 363 factory_.NewRunnableMethod(&Eviction::TrimDeleted, false)); | |
| 364 | |
| 365 UMA_HISTOGRAM_TIMES("DiskCache.TotalTrimDeletedTime", Time::Now() - start); | |
| 366 Trace("*** Trim Deleted end ***"); | |
| 367 return; | |
| 368 } | |
| 369 | |
| 370 bool Eviction::RemoveDeletedNode(CacheRankingsBlock* node) { | |
| 371 EntryImpl* entry; | |
| 372 bool dirty; | |
| 373 if (backend_->NewEntry(Addr(node->Data()->contents), &entry, &dirty)) { | |
| 374 Trace("NewEntry failed on Trim 0x%x", node->address().value()); | |
| 375 return false; | |
| 376 } | |
| 377 | |
| 378 if (node->Data()->pointer) { | |
| 379 entry = EntryImpl::Update(entry); | |
| 380 } | |
| 381 entry->entry()->Data()->state = ENTRY_DOOMED; | |
| 382 entry->Doom(); | |
| 383 entry->Release(); | |
| 384 return true; | |
| 336 } | 385 } |
| 337 | 386 |
| 338 bool Eviction::NodeIsOldEnough(CacheRankingsBlock* node, int list) { | 387 bool Eviction::NodeIsOldEnough(CacheRankingsBlock* node, int list) { |
| 339 if (!node) | 388 if (!node) |
| 340 return false; | 389 return false; |
| 341 | 390 |
| 342 // If possible, we want to keep entries on each list at least kTargetTime | 391 // If possible, we want to keep entries on each list at least kTargetTime |
| 343 // hours. Each successive list on the enumeration has 2x the target time of | 392 // hours. Each successive list on the enumeration has 2x the target time of |
| 344 // the previous list. | 393 // the previous list. |
| 345 Time used = Time::FromInternalValue(node->Data()->last_used); | 394 Time used = Time::FromInternalValue(node->Data()->last_used); |
| 346 int multiplier = 1 << list; | 395 int multiplier = 1 << list; |
| 347 return (Time::Now() - used).InHours() > kTargetTime * multiplier; | 396 return (Time::Now() - used).InHours() > kTargetTime * multiplier; |
| 348 } | 397 } |
| 349 | 398 |
| 350 int Eviction::SelectListByLenght() { | 399 int Eviction::SelectListByLenght() { |
| 400 int data_entries = header_->num_entries - | |
| 401 header_->lru.sizes[Rankings::DELETED]; | |
| 351 // Start by having each list to be roughly the same size. | 402 // Start by having each list to be roughly the same size. |
| 352 if (header_->lru.sizes[0] > header_->num_entries / 4) | 403 if (header_->lru.sizes[0] > data_entries / 3) |
| 353 return 0; | 404 return 0; |
| 354 if (header_->lru.sizes[1] > header_->num_entries / 4) | 405 if (header_->lru.sizes[1] > data_entries / 3) |
| 355 return 1; | 406 return 1; |
| 356 return 2; | 407 return 2; |
| 357 } | 408 } |
| 358 | 409 |
| 359 } // namespace disk_cache | 410 } // namespace disk_cache |
| OLD | NEW |