Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: net/disk_cache/eviction.cc

Issue 8065015: Disk Cache: Improve handling of dirty entries. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 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
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
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()) || test_mode_) { 119 while ((header_->num_bytes > target_size || test_mode_) && next.get()) {
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, Rankings::NO_USE) && !test_mode_)
130 continue; 130 continue;
131 131
132 if (!empty) { 132 if (!empty) {
133 backend_->OnEvent(Stats::TRIM_ENTRY); 133 backend_->OnEvent(Stats::TRIM_ENTRY);
134 if (test_mode_) 134 if (test_mode_)
135 break; 135 break;
136 136
137 if ((TimeTicks::Now() - start).InMilliseconds() > 20) { 137 if ((TimeTicks::Now() - start).InMilliseconds() > 20) {
138 MessageLoop::current()->PostTask(FROM_HERE, 138 MessageLoop::current()->PostTask(FROM_HERE,
139 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); 139 factory_.NewRunnableMethod(&Eviction::TrimCache, false));
(...skipping 30 matching lines...) Expand all
170 if (new_eviction_) 170 if (new_eviction_)
171 return OnCreateEntryV2(entry); 171 return OnCreateEntryV2(entry);
172 172
173 rankings_->Insert(entry->rankings(), true, GetListForEntry(entry)); 173 rankings_->Insert(entry->rankings(), true, GetListForEntry(entry));
174 } 174 }
175 175
176 void Eviction::OnDoomEntry(EntryImpl* entry) { 176 void Eviction::OnDoomEntry(EntryImpl* entry) {
177 if (new_eviction_) 177 if (new_eviction_)
178 return OnDoomEntryV2(entry); 178 return OnDoomEntryV2(entry);
179 179
180 rankings_->Remove(entry->rankings(), GetListForEntry(entry)); 180 if (entry->LeaveRankingsBehind())
181 return;
182
183 rankings_->Remove(entry->rankings(), GetListForEntry(entry), true);
181 } 184 }
182 185
183 void Eviction::OnDestroyEntry(EntryImpl* entry) { 186 void Eviction::OnDestroyEntry(EntryImpl* entry) {
184 if (new_eviction_) 187 if (new_eviction_)
185 return OnDestroyEntryV2(entry); 188 return OnDestroyEntryV2(entry);
186 } 189 }
187 190
188 void Eviction::SetTestMode() { 191 void Eviction::SetTestMode() {
189 test_mode_ = true; 192 test_mode_ = true;
190 } 193 }
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 old.day_of_month = 1; 250 old.day_of_month = 1;
248 header_->create_time = Time::FromLocalExploded(old).ToInternalValue(); 251 header_->create_time = Time::FromLocalExploded(old).ToInternalValue();
249 } 252 }
250 } 253 }
251 } 254 }
252 255
253 Rankings::List Eviction::GetListForEntry(EntryImpl* entry) { 256 Rankings::List Eviction::GetListForEntry(EntryImpl* entry) {
254 return Rankings::NO_USE; 257 return Rankings::NO_USE;
255 } 258 }
256 259
257 bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty) { 260 bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty,
258 EntryImpl* entry = backend_->GetEnumeratedEntry(node); 261 Rankings::List list) {
262 EntryImpl* entry = backend_->GetEnumeratedEntry(node, list);
259 if (!entry) { 263 if (!entry) {
260 Trace("NewEntry failed on Trim 0x%x", node->address().value()); 264 Trace("NewEntry failed on Trim 0x%x", node->address().value());
261 return false; 265 return false;
262 } 266 }
263 267
264 ReportTrimTimes(entry); 268 ReportTrimTimes(entry);
265 if (empty || !new_eviction_) { 269 if (empty || !new_eviction_) {
266 entry->DoomImpl(); 270 entry->DoomImpl();
267 } else { 271 } else {
268 entry->DeleteEntryData(false); 272 entry->DeleteEntryData(false);
269 EntryStore* info = entry->entry()->Data(); 273 EntryStore* info = entry->entry()->Data();
270 DCHECK_EQ(ENTRY_NORMAL, info->state); 274 DCHECK_EQ(ENTRY_NORMAL, info->state);
271 275
272 rankings_->Remove(entry->rankings(), GetListForEntryV2(entry)); 276 rankings_->Remove(entry->rankings(), GetListForEntryV2(entry), true);
273 info->state = ENTRY_EVICTED; 277 info->state = ENTRY_EVICTED;
274 entry->entry()->Store(); 278 entry->entry()->Store();
275 rankings_->Insert(entry->rankings(), true, Rankings::DELETED); 279 rankings_->Insert(entry->rankings(), true, Rankings::DELETED);
276 backend_->OnEvent(Stats::TRIM_ENTRY); 280 backend_->OnEvent(Stats::TRIM_ENTRY);
277 } 281 }
278 entry->Release(); 282 entry->Release();
279 283
280 return true; 284 return true;
281 } 285 }
282 286
(...skipping 25 matching lines...) Expand all
308 if (!empty && Rankings::LAST_ELEMENT == list) 312 if (!empty && Rankings::LAST_ELEMENT == list)
309 list = SelectListByLength(next); 313 list = SelectListByLength(next);
310 314
311 if (empty) 315 if (empty)
312 list = 0; 316 list = 0;
313 317
314 Rankings::ScopedRankingsBlock node(rankings_); 318 Rankings::ScopedRankingsBlock node(rankings_);
315 319
316 int target_size = empty ? 0 : max_size_; 320 int target_size = empty ? 0 : max_size_;
317 for (; list < kListsToSearch; list++) { 321 for (; list < kListsToSearch; list++) {
318 while ((header_->num_bytes > target_size && next[list].get()) || 322 while ((header_->num_bytes > target_size || test_mode_) &&
319 test_mode_) { 323 next[list].get()) {
320 // The iterator could be invalidated within EvictEntry(). 324 // The iterator could be invalidated within EvictEntry().
321 if (!next[list]->HasData()) 325 if (!next[list]->HasData())
322 break; 326 break;
323 node.reset(next[list].release()); 327 node.reset(next[list].release());
324 next[list].reset(rankings_->GetPrev(node.get(), 328 next[list].reset(rankings_->GetPrev(node.get(),
325 static_cast<Rankings::List>(list))); 329 static_cast<Rankings::List>(list)));
326 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { 330 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) {
327 // This entry is not being used by anybody. 331 // This entry is not being used by anybody.
328 // Do NOT use node as an iterator after this point. 332 // Do NOT use node as an iterator after this point.
329 rankings_->TrackRankingsBlock(node.get(), false); 333 rankings_->TrackRankingsBlock(node.get(), false);
330 if (!EvictEntry(node.get(), empty) && !test_mode_) 334 if (!EvictEntry(node.get(), empty, static_cast<Rankings::List>(list)) &&
335 !test_mode_)
331 continue; 336 continue;
332 337
333 if (!empty && test_mode_) 338 if (!empty && test_mode_)
334 break; 339 break;
335 340
336 if (!empty && (TimeTicks::Now() - start).InMilliseconds() > 20) { 341 if (!empty && (TimeTicks::Now() - start).InMilliseconds() > 20) {
337 MessageLoop::current()->PostTask(FROM_HERE, 342 MessageLoop::current()->PostTask(FROM_HERE,
338 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); 343 factory_.NewRunnableMethod(&Eviction::TrimCache, false));
339 break; 344 break;
340 } 345 }
(...skipping 29 matching lines...) Expand all
370 void Eviction::OnOpenEntryV2(EntryImpl* entry) { 375 void Eviction::OnOpenEntryV2(EntryImpl* entry) {
371 EntryStore* info = entry->entry()->Data(); 376 EntryStore* info = entry->entry()->Data();
372 DCHECK_EQ(ENTRY_NORMAL, info->state); 377 DCHECK_EQ(ENTRY_NORMAL, info->state);
373 378
374 if (info->reuse_count < kint32max) { 379 if (info->reuse_count < kint32max) {
375 info->reuse_count++; 380 info->reuse_count++;
376 entry->entry()->set_modified(); 381 entry->entry()->set_modified();
377 382
378 // We may need to move this to a new list. 383 // We may need to move this to a new list.
379 if (1 == info->reuse_count) { 384 if (1 == info->reuse_count) {
380 rankings_->Remove(entry->rankings(), Rankings::NO_USE); 385 rankings_->Remove(entry->rankings(), Rankings::NO_USE, true);
381 rankings_->Insert(entry->rankings(), false, Rankings::LOW_USE); 386 rankings_->Insert(entry->rankings(), false, Rankings::LOW_USE);
382 entry->entry()->Store(); 387 entry->entry()->Store();
383 } else if (kHighUse == info->reuse_count) { 388 } else if (kHighUse == info->reuse_count) {
384 rankings_->Remove(entry->rankings(), Rankings::LOW_USE); 389 rankings_->Remove(entry->rankings(), Rankings::LOW_USE, true);
385 rankings_->Insert(entry->rankings(), false, Rankings::HIGH_USE); 390 rankings_->Insert(entry->rankings(), false, Rankings::HIGH_USE);
386 entry->entry()->Store(); 391 entry->entry()->Store();
387 } 392 }
388 } 393 }
389 } 394 }
390 395
391 void Eviction::OnCreateEntryV2(EntryImpl* entry) { 396 void Eviction::OnCreateEntryV2(EntryImpl* entry) {
392 EntryStore* info = entry->entry()->Data(); 397 EntryStore* info = entry->entry()->Data();
393 switch (info->state) { 398 switch (info->state) {
394 case ENTRY_NORMAL: { 399 case ENTRY_NORMAL: {
395 DCHECK(!info->reuse_count); 400 DCHECK(!info->reuse_count);
396 DCHECK(!info->refetch_count); 401 DCHECK(!info->refetch_count);
397 break; 402 break;
398 }; 403 };
399 case ENTRY_EVICTED: { 404 case ENTRY_EVICTED: {
400 if (info->refetch_count < kint32max) 405 if (info->refetch_count < kint32max)
401 info->refetch_count++; 406 info->refetch_count++;
402 407
403 if (info->refetch_count > kHighUse && info->reuse_count < kHighUse) { 408 if (info->refetch_count > kHighUse && info->reuse_count < kHighUse) {
404 info->reuse_count = kHighUse; 409 info->reuse_count = kHighUse;
405 } else { 410 } else {
406 info->reuse_count++; 411 info->reuse_count++;
407 } 412 }
408 info->state = ENTRY_NORMAL; 413 info->state = ENTRY_NORMAL;
409 entry->entry()->Store(); 414 entry->entry()->Store();
410 rankings_->Remove(entry->rankings(), Rankings::DELETED); 415 rankings_->Remove(entry->rankings(), Rankings::DELETED, true);
411 break; 416 break;
412 }; 417 };
413 default: 418 default:
414 NOTREACHED(); 419 NOTREACHED();
415 } 420 }
416 421
417 rankings_->Insert(entry->rankings(), true, GetListForEntryV2(entry)); 422 rankings_->Insert(entry->rankings(), true, GetListForEntryV2(entry));
418 } 423 }
419 424
420 void Eviction::OnDoomEntryV2(EntryImpl* entry) { 425 void Eviction::OnDoomEntryV2(EntryImpl* entry) {
421 EntryStore* info = entry->entry()->Data(); 426 EntryStore* info = entry->entry()->Data();
422 if (ENTRY_NORMAL != info->state) 427 if (ENTRY_NORMAL != info->state)
423 return; 428 return;
424 429
425 rankings_->Remove(entry->rankings(), GetListForEntryV2(entry)); 430 if (entry->LeaveRankingsBehind()) {
431 info->state = ENTRY_DOOMED;
432 entry->entry()->Store();
433 return;
434 }
435
436 rankings_->Remove(entry->rankings(), GetListForEntryV2(entry), true);
426 437
427 info->state = ENTRY_DOOMED; 438 info->state = ENTRY_DOOMED;
428 entry->entry()->Store(); 439 entry->entry()->Store();
429 rankings_->Insert(entry->rankings(), true, Rankings::DELETED); 440 rankings_->Insert(entry->rankings(), true, Rankings::DELETED);
430 } 441 }
431 442
432 void Eviction::OnDestroyEntryV2(EntryImpl* entry) { 443 void Eviction::OnDestroyEntryV2(EntryImpl* entry) {
433 rankings_->Remove(entry->rankings(), Rankings::DELETED); 444 if (entry->LeaveRankingsBehind())
445 return;
446
447 rankings_->Remove(entry->rankings(), Rankings::DELETED, true);
434 } 448 }
435 449
436 Rankings::List Eviction::GetListForEntryV2(EntryImpl* entry) { 450 Rankings::List Eviction::GetListForEntryV2(EntryImpl* entry) {
437 EntryStore* info = entry->entry()->Data(); 451 EntryStore* info = entry->entry()->Data();
438 DCHECK_EQ(ENTRY_NORMAL, info->state); 452 DCHECK_EQ(ENTRY_NORMAL, info->state);
439 453
440 if (!info->reuse_count) 454 if (!info->reuse_count)
441 return Rankings::NO_USE; 455 return Rankings::NO_USE;
442 456
443 if (info->reuse_count < kHighUse) 457 if (info->reuse_count < kHighUse)
444 return Rankings::LOW_USE; 458 return Rankings::LOW_USE;
445 459
446 return Rankings::HIGH_USE; 460 return Rankings::HIGH_USE;
447 } 461 }
448 462
449 // This is a minimal implementation that just discards the oldest nodes. 463 // This is a minimal implementation that just discards the oldest nodes.
450 // TODO(rvargas): Do something better here. 464 // TODO(rvargas): Do something better here.
451 void Eviction::TrimDeleted(bool empty) { 465 void Eviction::TrimDeleted(bool empty) {
452 Trace("*** Trim Deleted ***"); 466 Trace("*** Trim Deleted ***");
453 if (backend_->disabled_) 467 if (backend_->disabled_)
454 return; 468 return;
455 469
456 TimeTicks start = TimeTicks::Now(); 470 TimeTicks start = TimeTicks::Now();
457 Rankings::ScopedRankingsBlock node(rankings_); 471 Rankings::ScopedRankingsBlock node(rankings_);
458 Rankings::ScopedRankingsBlock next(rankings_, 472 Rankings::ScopedRankingsBlock next(rankings_,
459 rankings_->GetPrev(node.get(), Rankings::DELETED)); 473 rankings_->GetPrev(node.get(), Rankings::DELETED));
460 bool deleted = false; 474 bool deleted = false;
461 for (int i = 0; (i < 4 || empty) && next.get(); i++) { 475 while (next.get() &&
476 (empty || (TimeTicks::Now() - start).InMilliseconds() < 20)) {
462 node.reset(next.release()); 477 node.reset(next.release());
463 next.reset(rankings_->GetPrev(node.get(), Rankings::DELETED)); 478 next.reset(rankings_->GetPrev(node.get(), Rankings::DELETED));
464 deleted |= RemoveDeletedNode(node.get()); 479 deleted |= RemoveDeletedNode(node.get());
465 if (test_mode_) 480 if (test_mode_)
466 break; 481 break;
467 } 482 }
468 483
469 // Normally we use 25% for each list. The experiment doubles the number of 484 // Normally we use 25% for each list. The experiment doubles the number of
470 // deleted entries, so the total number of entries increases by 25%. Using 485 // deleted entries, so the total number of entries increases by 25%. Using
471 // 40% of that value for deleted entries leaves the size of the other three 486 // 40% of that value for deleted entries leaves the size of the other three
472 // lists intact. 487 // lists intact.
473 int max_length = in_experiment_ ? header_->num_entries * 2 / 5 : 488 int max_length = in_experiment_ ? header_->num_entries * 2 / 5 :
474 header_->num_entries / 4; 489 header_->num_entries / 4;
475 if (deleted && !empty && !test_mode_ && 490 if (deleted && !empty && !test_mode_ &&
476 header_->lru.sizes[Rankings::DELETED] > max_length) { 491 header_->lru.sizes[Rankings::DELETED] > max_length) {
477 MessageLoop::current()->PostTask(FROM_HERE, 492 MessageLoop::current()->PostTask(FROM_HERE,
478 factory_.NewRunnableMethod(&Eviction::TrimDeleted, false)); 493 factory_.NewRunnableMethod(&Eviction::TrimDeleted, false));
479 } 494 }
480 495
481 CACHE_UMA(AGE_MS, "TotalTrimDeletedTime", 0, start); 496 CACHE_UMA(AGE_MS, "TotalTrimDeletedTime", 0, start);
482 Trace("*** Trim Deleted end ***"); 497 Trace("*** Trim Deleted end ***");
483 return; 498 return;
484 } 499 }
485 500
486 bool Eviction::RemoveDeletedNode(CacheRankingsBlock* node) { 501 bool Eviction::RemoveDeletedNode(CacheRankingsBlock* node) {
487 EntryImpl* entry = backend_->GetEnumeratedEntry(node); 502 EntryImpl* entry = backend_->GetEnumeratedEntry(node, Rankings::DELETED);
488 if (!entry) { 503 if (!entry) {
489 Trace("NewEntry failed on Trim 0x%x", node->address().value()); 504 Trace("NewEntry failed on Trim 0x%x", node->address().value());
490 return false; 505 return false;
491 } 506 }
492 507
493 bool doomed = (entry->entry()->Data()->state == ENTRY_DOOMED); 508 bool doomed = (entry->entry()->Data()->state == ENTRY_DOOMED);
494 entry->entry()->Data()->state = ENTRY_DOOMED; 509 entry->entry()->Data()->state = ENTRY_DOOMED;
495 entry->DoomImpl(); 510 entry->DoomImpl();
496 entry->Release(); 511 entry->Release();
497 return !doomed; 512 return !doomed;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
550 Time::FromInternalValue(last2.get()->Data()->last_used)); 565 Time::FromInternalValue(last2.get()->Data()->last_used));
551 if (last3.get()) 566 if (last3.get())
552 CACHE_UMA(AGE, "HighUseAge", 0, 567 CACHE_UMA(AGE, "HighUseAge", 0,
553 Time::FromInternalValue(last3.get()->Data()->last_used)); 568 Time::FromInternalValue(last3.get()->Data()->last_used));
554 if (last4.get()) 569 if (last4.get())
555 CACHE_UMA(AGE, "DeletedAge", 0, 570 CACHE_UMA(AGE, "DeletedAge", 0,
556 Time::FromInternalValue(last4.get()->Data()->last_used)); 571 Time::FromInternalValue(last4.get()->Data()->last_used));
557 } 572 }
558 573
559 } // namespace disk_cache 574 } // namespace disk_cache
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698