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 |