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

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

Issue 6292011: Disk cache: Prevent obscure file corruption and deal... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 11 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) 2006-2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2010 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 backend_ = backend; 75 backend_ = backend;
76 rankings_ = &backend->rankings_; 76 rankings_ = &backend->rankings_;
77 header_ = &backend_->data_->header; 77 header_ = &backend_->data_->header;
78 max_size_ = LowWaterAdjust(backend_->max_size_); 78 max_size_ = LowWaterAdjust(backend_->max_size_);
79 new_eviction_ = backend->new_eviction_; 79 new_eviction_ = backend->new_eviction_;
80 first_trim_ = true; 80 first_trim_ = true;
81 trimming_ = false; 81 trimming_ = false;
82 delay_trim_ = false; 82 delay_trim_ = false;
83 trim_delays_ = 0; 83 trim_delays_ = 0;
84 init_ = true; 84 init_ = true;
85 test_mode_ = false;
85 in_experiment_ = (header_->experiment == EXPERIMENT_DELETED_LIST_IN); 86 in_experiment_ = (header_->experiment == EXPERIMENT_DELETED_LIST_IN);
86 } 87 }
87 88
88 void Eviction::Stop() { 89 void Eviction::Stop() {
89 // It is possible for the backend initialization to fail, in which case this 90 // It is possible for the backend initialization to fail, in which case this
90 // object was never initialized... and there is nothing to do. 91 // object was never initialized... and there is nothing to do.
91 if (!init_) 92 if (!init_)
92 return; 93 return;
93 94
94 // We want to stop further evictions, so let's pretend that we are busy from 95 // We want to stop further evictions, so let's pretend that we are busy from
(...skipping 23 matching lines...) Expand all
118 while (header_->num_bytes > target_size && next.get()) { 119 while (header_->num_bytes > target_size && next.get()) {
119 // The iterator could be invalidated within EvictEntry(). 120 // The iterator could be invalidated within EvictEntry().
120 if (!next->HasData()) 121 if (!next->HasData())
121 break; 122 break;
122 node.reset(next.release()); 123 node.reset(next.release());
123 next.reset(rankings_->GetPrev(node.get(), Rankings::NO_USE)); 124 next.reset(rankings_->GetPrev(node.get(), Rankings::NO_USE));
124 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { 125 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) {
125 // This entry is not being used by anybody. 126 // This entry is not being used by anybody.
126 // Do NOT use node as an iterator after this point. 127 // Do NOT use node as an iterator after this point.
127 rankings_->TrackRankingsBlock(node.get(), false); 128 rankings_->TrackRankingsBlock(node.get(), false);
128 if (!EvictEntry(node.get(), empty)) 129 if (!EvictEntry(node.get(), empty) && !test_mode_)
129 continue; 130 continue;
130 131
131 if (!empty) { 132 if (!empty) {
132 backend_->OnEvent(Stats::TRIM_ENTRY); 133 backend_->OnEvent(Stats::TRIM_ENTRY);
134 if (test_mode_)
135 break;
133 136
134 if ((TimeTicks::Now() - start).InMilliseconds() > 20) { 137 if ((TimeTicks::Now() - start).InMilliseconds() > 20) {
135 MessageLoop::current()->PostTask(FROM_HERE, 138 MessageLoop::current()->PostTask(FROM_HERE,
136 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); 139 factory_.NewRunnableMethod(&Eviction::TrimCache, false));
137 break; 140 break;
138 } 141 }
139 } 142 }
140 } 143 }
141 } 144 }
142 145
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 return OnDoomEntryV2(entry); 178 return OnDoomEntryV2(entry);
176 179
177 rankings_->Remove(entry->rankings(), GetListForEntry(entry)); 180 rankings_->Remove(entry->rankings(), GetListForEntry(entry));
178 } 181 }
179 182
180 void Eviction::OnDestroyEntry(EntryImpl* entry) { 183 void Eviction::OnDestroyEntry(EntryImpl* entry) {
181 if (new_eviction_) 184 if (new_eviction_)
182 return OnDestroyEntryV2(entry); 185 return OnDestroyEntryV2(entry);
183 } 186 }
184 187
188 void Eviction::SetTestMode() {
189 test_mode_ = true;
190 }
191
192 void Eviction::TrimDeletedList(bool empty) {
193 DCHECK(test_mode_ && new_eviction_);
194 TrimDeleted(empty);
195 }
196
185 void Eviction::PostDelayedTrim() { 197 void Eviction::PostDelayedTrim() {
186 // Prevent posting multiple tasks. 198 // Prevent posting multiple tasks.
187 if (delay_trim_) 199 if (delay_trim_)
188 return; 200 return;
189 delay_trim_ = true; 201 delay_trim_ = true;
190 trim_delays_++; 202 trim_delays_++;
191 MessageLoop::current()->PostDelayedTask(FROM_HERE, 203 MessageLoop::current()->PostDelayedTask(FROM_HERE,
192 factory_.NewRunnableMethod(&Eviction::DelayedTrim), 1000); 204 factory_.NewRunnableMethod(&Eviction::DelayedTrim), 1000);
193 } 205 }
194 206
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 header_->create_time = Time::FromLocalExploded(old).ToInternalValue(); 247 header_->create_time = Time::FromLocalExploded(old).ToInternalValue();
236 } 248 }
237 } 249 }
238 } 250 }
239 251
240 Rankings::List Eviction::GetListForEntry(EntryImpl* entry) { 252 Rankings::List Eviction::GetListForEntry(EntryImpl* entry) {
241 return Rankings::NO_USE; 253 return Rankings::NO_USE;
242 } 254 }
243 255
244 bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty) { 256 bool Eviction::EvictEntry(CacheRankingsBlock* node, bool empty) {
245 EntryImpl* entry = backend_->GetEnumeratedEntry(node, true); 257 EntryImpl* entry = backend_->GetEnumeratedEntry(node);
246 if (!entry) { 258 if (!entry) {
247 Trace("NewEntry failed on Trim 0x%x", node->address().value()); 259 Trace("NewEntry failed on Trim 0x%x", node->address().value());
248 return false; 260 return false;
249 } 261 }
250 262
251 ReportTrimTimes(entry); 263 ReportTrimTimes(entry);
252 if (empty || !new_eviction_) { 264 if (empty || !new_eviction_) {
253 entry->DoomImpl(); 265 entry->DoomImpl();
254 } else { 266 } else {
255 entry->DeleteEntryData(false); 267 entry->DeleteEntryData(false);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 // The iterator could be invalidated within EvictEntry(). 325 // The iterator could be invalidated within EvictEntry().
314 if (!next[list]->HasData()) 326 if (!next[list]->HasData())
315 break; 327 break;
316 node.reset(next[list].release()); 328 node.reset(next[list].release());
317 next[list].reset(rankings_->GetPrev(node.get(), 329 next[list].reset(rankings_->GetPrev(node.get(),
318 static_cast<Rankings::List>(list))); 330 static_cast<Rankings::List>(list)));
319 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) { 331 if (node->Data()->dirty != backend_->GetCurrentEntryId() || empty) {
320 // This entry is not being used by anybody. 332 // This entry is not being used by anybody.
321 // Do NOT use node as an iterator after this point. 333 // Do NOT use node as an iterator after this point.
322 rankings_->TrackRankingsBlock(node.get(), false); 334 rankings_->TrackRankingsBlock(node.get(), false);
323 if (!EvictEntry(node.get(), empty)) 335 if (!EvictEntry(node.get(), empty) && !test_mode_)
324 continue; 336 continue;
325 337
338 if (!empty && test_mode_)
339 break;
340
326 if (!empty && (TimeTicks::Now() - start).InMilliseconds() > 20) { 341 if (!empty && (TimeTicks::Now() - start).InMilliseconds() > 20) {
327 MessageLoop::current()->PostTask(FROM_HERE, 342 MessageLoop::current()->PostTask(FROM_HERE,
328 factory_.NewRunnableMethod(&Eviction::TrimCache, false)); 343 factory_.NewRunnableMethod(&Eviction::TrimCache, false));
329 break; 344 break;
330 } 345 }
331 } 346 }
332 } 347 }
333 if (!empty) 348 if (!empty)
334 list = kListsToSearch; 349 list = kListsToSearch;
335 } 350 }
336 351
337 if (empty) { 352 if (empty) {
338 TrimDeleted(true); 353 TrimDeleted(true);
339 } else if (header_->lru.sizes[Rankings::DELETED] > header_->num_entries / 4) { 354 } else if (header_->lru.sizes[Rankings::DELETED] > header_->num_entries / 4 &&
355 !test_mode_) {
340 MessageLoop::current()->PostTask(FROM_HERE, 356 MessageLoop::current()->PostTask(FROM_HERE,
341 factory_.NewRunnableMethod(&Eviction::TrimDeleted, empty)); 357 factory_.NewRunnableMethod(&Eviction::TrimDeleted, empty));
342 } 358 }
343 359
344 if (empty) { 360 if (empty) {
345 CACHE_UMA(AGE_MS, "TotalClearTimeV2", 0, start); 361 CACHE_UMA(AGE_MS, "TotalClearTimeV2", 0, start);
346 } else { 362 } else {
347 CACHE_UMA(AGE_MS, "TotalTrimTimeV2", backend_->GetSizeGroup(), start); 363 CACHE_UMA(AGE_MS, "TotalTrimTimeV2", backend_->GetSizeGroup(), start);
348 } 364 }
349 365
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 460
445 TimeTicks start = TimeTicks::Now(); 461 TimeTicks start = TimeTicks::Now();
446 Rankings::ScopedRankingsBlock node(rankings_); 462 Rankings::ScopedRankingsBlock node(rankings_);
447 Rankings::ScopedRankingsBlock next(rankings_, 463 Rankings::ScopedRankingsBlock next(rankings_,
448 rankings_->GetPrev(node.get(), Rankings::DELETED)); 464 rankings_->GetPrev(node.get(), Rankings::DELETED));
449 bool deleted = false; 465 bool deleted = false;
450 for (int i = 0; (i < 4 || empty) && next.get(); i++) { 466 for (int i = 0; (i < 4 || empty) && next.get(); i++) {
451 node.reset(next.release()); 467 node.reset(next.release());
452 next.reset(rankings_->GetPrev(node.get(), Rankings::DELETED)); 468 next.reset(rankings_->GetPrev(node.get(), Rankings::DELETED));
453 deleted |= RemoveDeletedNode(node.get()); 469 deleted |= RemoveDeletedNode(node.get());
470 if (test_mode_)
471 break;
454 } 472 }
455 473
456 // Normally we use 25% for each list. The experiment doubles the number of 474 // Normally we use 25% for each list. The experiment doubles the number of
457 // deleted entries, so the total number of entries increases by 25%. Using 475 // deleted entries, so the total number of entries increases by 25%. Using
458 // 40% of that value for deleted entries leaves the size of the other three 476 // 40% of that value for deleted entries leaves the size of the other three
459 // lists intact. 477 // lists intact.
460 int max_length = in_experiment_ ? header_->num_entries * 2 / 5 : 478 int max_length = in_experiment_ ? header_->num_entries * 2 / 5 :
461 header_->num_entries / 4; 479 header_->num_entries / 4;
462 if (deleted && !empty && 480 if (deleted && !empty && !test_mode_ &&
463 header_->lru.sizes[Rankings::DELETED] > max_length) 481 header_->lru.sizes[Rankings::DELETED] > max_length) {
464 MessageLoop::current()->PostTask(FROM_HERE, 482 MessageLoop::current()->PostTask(FROM_HERE,
465 factory_.NewRunnableMethod(&Eviction::TrimDeleted, false)); 483 factory_.NewRunnableMethod(&Eviction::TrimDeleted, false));
484 }
466 485
467 CACHE_UMA(AGE_MS, "TotalTrimDeletedTime", 0, start); 486 CACHE_UMA(AGE_MS, "TotalTrimDeletedTime", 0, start);
468 Trace("*** Trim Deleted end ***"); 487 Trace("*** Trim Deleted end ***");
469 return; 488 return;
470 } 489 }
471 490
472 bool Eviction::RemoveDeletedNode(CacheRankingsBlock* node) { 491 bool Eviction::RemoveDeletedNode(CacheRankingsBlock* node) {
473 EntryImpl* entry; 492 EntryImpl* entry = backend_->GetEnumeratedEntry(node);
474 bool dirty; 493 if (!entry) {
475 if (backend_->NewEntry(Addr(node->Data()->contents), &entry, &dirty)) {
476 Trace("NewEntry failed on Trim 0x%x", node->address().value()); 494 Trace("NewEntry failed on Trim 0x%x", node->address().value());
477 return false; 495 return false;
478 } 496 }
479 497
480 // TODO(rvargas): figure out how to deal with corruption at this point (dirty
481 // entries that live in this list).
gavinp 2011/01/25 20:23:51 Awesome! I'm always happy to see TODOs go.
482 if (node->Data()->dirty) {
483 // We ignore the failure; we're removing the entry anyway.
484 entry->Update();
485 }
486 bool doomed = (entry->entry()->Data()->state == ENTRY_DOOMED); 498 bool doomed = (entry->entry()->Data()->state == ENTRY_DOOMED);
487 entry->entry()->Data()->state = ENTRY_DOOMED; 499 entry->entry()->Data()->state = ENTRY_DOOMED;
488 entry->DoomImpl(); 500 entry->DoomImpl();
489 entry->Release(); 501 entry->Release();
490 return !doomed; 502 return !doomed;
491 } 503 }
492 504
493 bool Eviction::NodeIsOldEnough(CacheRankingsBlock* node, int list) { 505 bool Eviction::NodeIsOldEnough(CacheRankingsBlock* node, int list) {
494 if (!node) 506 if (!node)
495 return false; 507 return false;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 Time::FromInternalValue(last2.get()->Data()->last_used)); 546 Time::FromInternalValue(last2.get()->Data()->last_used));
535 if (last3.get()) 547 if (last3.get())
536 CACHE_UMA(AGE, "HighUseAge", 0, 548 CACHE_UMA(AGE, "HighUseAge", 0,
537 Time::FromInternalValue(last3.get()->Data()->last_used)); 549 Time::FromInternalValue(last3.get()->Data()->last_used));
538 if (last4.get()) 550 if (last4.get())
539 CACHE_UMA(AGE, "DeletedAge", 0, 551 CACHE_UMA(AGE, "DeletedAge", 0,
540 Time::FromInternalValue(last4.get()->Data()->last_used)); 552 Time::FromInternalValue(last4.get()->Data()->last_used));
541 } 553 }
542 554
543 } // namespace disk_cache 555 } // namespace disk_cache
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698