| 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 |