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 #include "net/disk_cache/rankings.h" | 5 #include "net/disk_cache/rankings.h" |
6 | 6 |
7 #include "base/histogram.h" | 7 #include "base/histogram.h" |
8 #include "net/disk_cache/backend_impl.h" | 8 #include "net/disk_cache/backend_impl.h" |
9 #include "net/disk_cache/entry_impl.h" | 9 #include "net/disk_cache/entry_impl.h" |
10 #include "net/disk_cache/errors.h" | 10 #include "net/disk_cache/errors.h" |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 void Rankings::Reset() { | 197 void Rankings::Reset() { |
198 init_ = false; | 198 init_ = false; |
199 for (int i = 0; i < LAST_ELEMENT; i++) { | 199 for (int i = 0; i < LAST_ELEMENT; i++) { |
200 heads_[i].set_value(0); | 200 heads_[i].set_value(0); |
201 tails_[i].set_value(0); | 201 tails_[i].set_value(0); |
202 } | 202 } |
203 control_data_ = NULL; | 203 control_data_ = NULL; |
204 } | 204 } |
205 | 205 |
206 bool Rankings::GetRanking(CacheRankingsBlock* rankings) { | 206 bool Rankings::GetRanking(CacheRankingsBlock* rankings) { |
207 Time start = Time::Now(); | |
208 if (!rankings->address().is_initialized()) | 207 if (!rankings->address().is_initialized()) |
209 return false; | 208 return false; |
210 | 209 |
| 210 Time start = Time::Now(); |
211 if (!rankings->Load()) | 211 if (!rankings->Load()) |
212 return false; | 212 return false; |
213 | 213 |
214 if (!SanityCheck(rankings, true)) { | 214 if (!SanityCheck(rankings, true)) { |
215 backend_->CriticalError(ERR_INVALID_LINKS); | 215 backend_->CriticalError(ERR_INVALID_LINKS); |
216 return false; | 216 return false; |
217 } | 217 } |
218 | 218 |
219 if (!rankings->Data()->pointer) { | |
220 backend_->OnEvent(Stats::GET_RANKINGS); | |
221 return true; | |
222 } | |
223 | |
224 backend_->OnEvent(Stats::OPEN_RANKINGS); | 219 backend_->OnEvent(Stats::OPEN_RANKINGS); |
225 | 220 |
226 if (backend_->GetCurrentEntryId() != rankings->Data()->dirty || | 221 // "dummy" is the old "pointer" value, so it has to be 0. |
227 !backend_->IsOpen(rankings)) { | 222 if (!rankings->Data()->dirty && !rankings->Data()->dummy) |
| 223 return true; |
| 224 |
| 225 EntryImpl* entry = backend_->GetOpenEntry(rankings); |
| 226 if (backend_->GetCurrentEntryId() != rankings->Data()->dirty || !entry) { |
228 // We cannot trust this entry, but we cannot initiate a cleanup from this | 227 // We cannot trust this entry, but we cannot initiate a cleanup from this |
229 // point (we may be in the middle of a cleanup already). Just get rid of | 228 // point (we may be in the middle of a cleanup already). Just get rid of |
230 // the invalid pointer and continue; the entry will be deleted when detected | 229 // the invalid pointer and continue; the entry will be deleted when detected |
231 // from a regular open/create path. | 230 // from a regular open/create path. |
232 rankings->Data()->pointer = NULL; | 231 rankings->Data()->dummy = 0; |
233 rankings->Data()->dirty = backend_->GetCurrentEntryId() - 1; | 232 rankings->Data()->dirty = backend_->GetCurrentEntryId() - 1; |
234 if (!rankings->Data()->dirty) | 233 if (!rankings->Data()->dirty) |
235 rankings->Data()->dirty--; | 234 rankings->Data()->dirty--; |
236 return true; | 235 return true; |
237 } | 236 } |
238 | 237 |
239 EntryImpl* cache_entry = | 238 // Note that we should not leave this module without deleting rankings first. |
240 reinterpret_cast<EntryImpl*>(rankings->Data()->pointer); | 239 rankings->SetData(entry->rankings()->Data()); |
241 rankings->SetData(cache_entry->rankings()->Data()); | 240 |
242 CACHE_UMA(AGE_MS, "GetRankings", 0, start); | 241 CACHE_UMA(AGE_MS, "GetRankings", 0, start); |
243 return true; | 242 return true; |
244 } | 243 } |
245 | 244 |
| 245 void Rankings::ConvertToLongLived(CacheRankingsBlock* rankings) { |
| 246 if (rankings->own_data()) |
| 247 return; |
| 248 |
| 249 // We cannot return a shared node because we are not keeping a reference |
| 250 // to the entry that owns the buffer. Make this node a copy of the one that |
| 251 // we have, and let the iterator logic update it when the entry changes. |
| 252 CacheRankingsBlock temp(NULL, Addr(0)); |
| 253 *temp.Data() = *rankings->Data(); |
| 254 rankings->StopSharingData(); |
| 255 *rankings->Data() = *temp.Data(); |
| 256 } |
| 257 |
246 void Rankings::Insert(CacheRankingsBlock* node, bool modified, List list) { | 258 void Rankings::Insert(CacheRankingsBlock* node, bool modified, List list) { |
247 Trace("Insert 0x%x", node->address().value()); | 259 Trace("Insert 0x%x", node->address().value()); |
248 DCHECK(node->HasData()); | 260 DCHECK(node->HasData()); |
249 Addr& my_head = heads_[list]; | 261 Addr& my_head = heads_[list]; |
250 Addr& my_tail = tails_[list]; | 262 Addr& my_tail = tails_[list]; |
251 Transaction lock(control_data_, node->address(), INSERT, list); | 263 Transaction lock(control_data_, node->address(), INSERT, list); |
252 CacheRankingsBlock head(backend_->File(my_head), my_head); | 264 CacheRankingsBlock head(backend_->File(my_head), my_head); |
253 if (my_head.is_initialized()) { | 265 if (my_head.is_initialized()) { |
254 if (!GetRanking(&head)) | 266 if (!GetRanking(&head)) |
255 return; | 267 return; |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 LOG(ERROR) << "Invalid rankings info."; | 419 LOG(ERROR) << "Invalid rankings info."; |
408 return; | 420 return; |
409 } | 421 } |
410 | 422 |
411 Trace("CompleteTransaction 0x%x", node_addr.value()); | 423 Trace("CompleteTransaction 0x%x", node_addr.value()); |
412 | 424 |
413 CacheRankingsBlock node(backend_->File(node_addr), node_addr); | 425 CacheRankingsBlock node(backend_->File(node_addr), node_addr); |
414 if (!node.Load()) | 426 if (!node.Load()) |
415 return; | 427 return; |
416 | 428 |
417 node.Data()->pointer = NULL; | 429 node.Data()->dummy = 0; |
418 node.Store(); | 430 node.Store(); |
419 | 431 |
420 Addr& my_head = heads_[control_data_->operation_list]; | 432 Addr& my_head = heads_[control_data_->operation_list]; |
421 Addr& my_tail = tails_[control_data_->operation_list]; | 433 Addr& my_tail = tails_[control_data_->operation_list]; |
422 | 434 |
423 // We want to leave the node inside the list. The entry must me marked as | 435 // We want to leave the node inside the list. The entry must me marked as |
424 // dirty, and will be removed later. Otherwise, we'll get assertions when | 436 // dirty, and will be removed later. Otherwise, we'll get assertions when |
425 // attempting to remove the dirty entry. | 437 // attempting to remove the dirty entry. |
426 if (INSERT == control_data_->operation) { | 438 if (INSERT == control_data_->operation) { |
427 Trace("FinishInsert h:0x%x t:0x%x", my_head.value(), my_tail.value()); | 439 Trace("FinishInsert h:0x%x t:0x%x", my_head.value(), my_tail.value()); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 } | 523 } |
512 | 524 |
513 CacheRankingsBlock* Rankings::GetNext(CacheRankingsBlock* node, List list) { | 525 CacheRankingsBlock* Rankings::GetNext(CacheRankingsBlock* node, List list) { |
514 ScopedRankingsBlock next(this); | 526 ScopedRankingsBlock next(this); |
515 if (!node) { | 527 if (!node) { |
516 Addr& my_head = heads_[list]; | 528 Addr& my_head = heads_[list]; |
517 if (!my_head.is_initialized()) | 529 if (!my_head.is_initialized()) |
518 return NULL; | 530 return NULL; |
519 next.reset(new CacheRankingsBlock(backend_->File(my_head), my_head)); | 531 next.reset(new CacheRankingsBlock(backend_->File(my_head), my_head)); |
520 } else { | 532 } else { |
| 533 if (!node->HasData()) |
| 534 node->Load(); |
521 Addr& my_tail = tails_[list]; | 535 Addr& my_tail = tails_[list]; |
522 if (!my_tail.is_initialized()) | 536 if (!my_tail.is_initialized()) |
523 return NULL; | 537 return NULL; |
524 if (my_tail.value() == node->address().value()) | 538 if (my_tail.value() == node->address().value()) |
525 return NULL; | 539 return NULL; |
526 Addr address(node->Data()->next); | 540 Addr address(node->Data()->next); |
527 if (address.value() == node->address().value()) | 541 if (address.value() == node->address().value()) |
528 return NULL; // Another tail? fail it. | 542 return NULL; // Another tail? fail it. |
529 next.reset(new CacheRankingsBlock(backend_->File(address), address)); | 543 next.reset(new CacheRankingsBlock(backend_->File(address), address)); |
530 } | 544 } |
531 | 545 |
532 TrackRankingsBlock(next.get(), true); | 546 TrackRankingsBlock(next.get(), true); |
533 | 547 |
534 if (!GetRanking(next.get())) | 548 if (!GetRanking(next.get())) |
535 return NULL; | 549 return NULL; |
536 | 550 |
| 551 ConvertToLongLived(next.get()); |
537 if (node && !CheckSingleLink(node, next.get())) | 552 if (node && !CheckSingleLink(node, next.get())) |
538 return NULL; | 553 return NULL; |
539 | 554 |
540 return next.release(); | 555 return next.release(); |
541 } | 556 } |
542 | 557 |
543 CacheRankingsBlock* Rankings::GetPrev(CacheRankingsBlock* node, List list) { | 558 CacheRankingsBlock* Rankings::GetPrev(CacheRankingsBlock* node, List list) { |
544 ScopedRankingsBlock prev(this); | 559 ScopedRankingsBlock prev(this); |
545 if (!node) { | 560 if (!node) { |
546 Addr& my_tail = tails_[list]; | 561 Addr& my_tail = tails_[list]; |
547 if (!my_tail.is_initialized()) | 562 if (!my_tail.is_initialized()) |
548 return NULL; | 563 return NULL; |
549 prev.reset(new CacheRankingsBlock(backend_->File(my_tail), my_tail)); | 564 prev.reset(new CacheRankingsBlock(backend_->File(my_tail), my_tail)); |
550 } else { | 565 } else { |
| 566 if (!node->HasData()) |
| 567 node->Load(); |
551 Addr& my_head = heads_[list]; | 568 Addr& my_head = heads_[list]; |
552 if (!my_head.is_initialized()) | 569 if (!my_head.is_initialized()) |
553 return NULL; | 570 return NULL; |
554 if (my_head.value() == node->address().value()) | 571 if (my_head.value() == node->address().value()) |
555 return NULL; | 572 return NULL; |
556 Addr address(node->Data()->prev); | 573 Addr address(node->Data()->prev); |
557 if (address.value() == node->address().value()) | 574 if (address.value() == node->address().value()) |
558 return NULL; // Another head? fail it. | 575 return NULL; // Another head? fail it. |
559 prev.reset(new CacheRankingsBlock(backend_->File(address), address)); | 576 prev.reset(new CacheRankingsBlock(backend_->File(address), address)); |
560 } | 577 } |
561 | 578 |
562 TrackRankingsBlock(prev.get(), true); | 579 TrackRankingsBlock(prev.get(), true); |
563 | 580 |
564 if (!GetRanking(prev.get())) | 581 if (!GetRanking(prev.get())) |
565 return NULL; | 582 return NULL; |
566 | 583 |
| 584 ConvertToLongLived(prev.get()); |
567 if (node && !CheckSingleLink(prev.get(), node)) | 585 if (node && !CheckSingleLink(prev.get(), node)) |
568 return NULL; | 586 return NULL; |
569 | 587 |
570 return prev.release(); | 588 return prev.release(); |
571 } | 589 } |
572 | 590 |
573 void Rankings::FreeRankingsBlock(CacheRankingsBlock* node) { | 591 void Rankings::FreeRankingsBlock(CacheRankingsBlock* node) { |
574 TrackRankingsBlock(node, false); | 592 TrackRankingsBlock(node, false); |
575 } | 593 } |
576 | 594 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
635 | 653 |
636 void Rankings::WriteHead(List list) { | 654 void Rankings::WriteHead(List list) { |
637 control_data_->heads[list] = heads_[list].value(); | 655 control_data_->heads[list] = heads_[list].value(); |
638 } | 656 } |
639 | 657 |
640 void Rankings::WriteTail(List list) { | 658 void Rankings::WriteTail(List list) { |
641 control_data_->tails[list] = tails_[list].value(); | 659 control_data_->tails[list] = tails_[list].value(); |
642 } | 660 } |
643 | 661 |
644 bool Rankings::CheckEntry(CacheRankingsBlock* rankings) { | 662 bool Rankings::CheckEntry(CacheRankingsBlock* rankings) { |
645 if (!rankings->Data()->pointer) | 663 if (!rankings->Data()->dummy) |
646 return true; | 664 return true; |
647 | 665 |
648 // If this entry is not dirty, it is a serious problem. | 666 // If this entry is not dirty, it is a serious problem. |
649 return backend_->GetCurrentEntryId() != rankings->Data()->dirty; | 667 return backend_->GetCurrentEntryId() != rankings->Data()->dirty; |
650 } | 668 } |
651 | 669 |
652 bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev, | 670 bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev, |
653 CacheRankingsBlock* next, List list) { | 671 CacheRankingsBlock* next, List list) { |
654 if ((prev->Data()->next != node->address().value() && | 672 if ((prev->Data()->next != node->address().value() && |
655 heads_[list].value() != node->address().value()) || | 673 heads_[list].value() != node->address().value()) || |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
742 | 760 |
743 // We expect to have just a few iterators at any given time, maybe two or three, | 761 // We expect to have just a few iterators at any given time, maybe two or three, |
744 // But we could have more than one pointing at the same mode. We walk the list | 762 // But we could have more than one pointing at the same mode. We walk the list |
745 // of cache iterators and update all that are pointing to the given node. | 763 // of cache iterators and update all that are pointing to the given node. |
746 void Rankings::UpdateIterators(CacheRankingsBlock* node) { | 764 void Rankings::UpdateIterators(CacheRankingsBlock* node) { |
747 CacheAddr address = node->address().value(); | 765 CacheAddr address = node->address().value(); |
748 for (IteratorList::iterator it = iterators_.begin(); it != iterators_.end(); | 766 for (IteratorList::iterator it = iterators_.begin(); it != iterators_.end(); |
749 ++it) { | 767 ++it) { |
750 if (it->first == address && it->second->HasData()) { | 768 if (it->first == address && it->second->HasData()) { |
751 CacheRankingsBlock* other = it->second; | 769 CacheRankingsBlock* other = it->second; |
752 other->Data()->next = node->Data()->next; | 770 *other->Data() = *node->Data(); |
753 other->Data()->prev = node->Data()->prev; | |
754 } | 771 } |
755 } | 772 } |
756 } | 773 } |
757 | 774 |
758 void Rankings::InvalidateIterators(CacheRankingsBlock* node) { | 775 void Rankings::InvalidateIterators(CacheRankingsBlock* node) { |
759 CacheAddr address = node->address().value(); | 776 CacheAddr address = node->address().value(); |
760 for (IteratorList::iterator it = iterators_.begin(); it != iterators_.end(); | 777 for (IteratorList::iterator it = iterators_.begin(); it != iterators_.end(); |
761 ++it) { | 778 ++it) { |
762 if (it->first == address) { | 779 if (it->first == address) { |
763 LOG(WARNING) << "Invalidating iterator at 0x" << std::hex << address; | 780 LOG(WARNING) << "Invalidating iterator at 0x" << std::hex << address; |
(...skipping 14 matching lines...) Expand all Loading... |
778 void Rankings::DecrementCounter(List list) { | 795 void Rankings::DecrementCounter(List list) { |
779 if (!count_lists_) | 796 if (!count_lists_) |
780 return; | 797 return; |
781 | 798 |
782 DCHECK(control_data_->sizes[list] > 0); | 799 DCHECK(control_data_->sizes[list] > 0); |
783 if (control_data_->sizes[list] > 0) | 800 if (control_data_->sizes[list] > 0) |
784 control_data_->sizes[list]--; | 801 control_data_->sizes[list]--; |
785 } | 802 } |
786 | 803 |
787 } // namespace disk_cache | 804 } // namespace disk_cache |
OLD | NEW |