OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/metrics/histogram.h" | 7 #include "base/metrics/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 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
717 next.Data()->prev = prev.address().value(); | 717 next.Data()->prev = prev.address().value(); |
718 WriteTail(my_list); | 718 WriteTail(my_list); |
719 } | 719 } |
720 | 720 |
721 next.Store(); | 721 next.Store(); |
722 prev.Store(); | 722 prev.Store(); |
723 control_data_->transaction = 0; | 723 control_data_->transaction = 0; |
724 control_data_->operation = 0; | 724 control_data_->operation = 0; |
725 } | 725 } |
726 | 726 |
727 bool Rankings::CheckEntry(CacheRankingsBlock* rankings) { | |
728 if (rankings->VerifyHash()) | |
729 return true; | |
730 | |
731 // If this entry is not dirty, it is a serious problem. | |
732 return backend_->GetCurrentEntryId() != rankings->Data()->dirty; | |
733 } | |
734 | |
735 bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev, | 727 bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev, |
736 CacheRankingsBlock* next, List* list) { | 728 CacheRankingsBlock* next, List* list) { |
737 CacheAddr node_addr = node->address().value(); | 729 CacheAddr node_addr = node->address().value(); |
738 if (prev->Data()->next == node_addr && | 730 if (prev->Data()->next == node_addr && |
739 next->Data()->prev == node_addr) { | 731 next->Data()->prev == node_addr) { |
740 // A regular linked node. | 732 // A regular linked node. |
741 return true; | 733 return true; |
742 } | 734 } |
743 | 735 |
744 Trace("CheckLinks 0x%x (0x%x 0x%x)", node_addr, | 736 Trace("CheckLinks 0x%x (0x%x 0x%x)", node_addr, |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
780 LOG(ERROR) << "Inconsistent LRU."; | 772 LOG(ERROR) << "Inconsistent LRU."; |
781 | 773 |
782 backend_->CriticalError(ERR_INVALID_LINKS); | 774 backend_->CriticalError(ERR_INVALID_LINKS); |
783 return false; | 775 return false; |
784 } | 776 } |
785 | 777 |
786 return true; | 778 return true; |
787 } | 779 } |
788 | 780 |
789 int Rankings::CheckList(List list) { | 781 int Rankings::CheckList(List list) { |
790 Addr& my_head = heads_[list]; | 782 Addr last1, last2; |
791 Addr& my_tail = tails_[list]; | 783 int num_items; |
792 if (!my_head.is_initialized()) { | 784 int rv = CheckListSection(list, last1, last2, FORWARD, |
793 if (!my_tail.is_initialized()) | 785 &last1, &last2, &num_items); |
794 return 0; | 786 if (rv == 0) |
795 // If there is no head, having a tail is an error. | 787 return num_items; |
796 return ERR_INVALID_TAIL; | 788 |
789 Addr last3, last4; | |
gavinp
2012/04/26 15:46:54
Don't we mean "first" and "second" here?
rvargas (doing something else)
2012/04/27 00:18:10
I'm sorry I don't follow you here. What is first a
gavinp
2012/04/30 18:57:15
If I'm moving backwards, then when I reach the end
rvargas (doing something else)
2012/04/30 22:03:00
sort of... but that would confuse me. The returned
| |
790 int num_items2; | |
gavinp
2012/04/26 15:46:54
num_items_backwards ?
| |
791 int rv2 = CheckListSection(list, last1, last2, BACKWARD, | |
792 &last3, &last4, &num_items2); | |
793 | |
794 if (!num_items && rv != ERR_INVALID_NEXT) | |
795 rv = ERR_INVALID_HEAD; | |
796 | |
797 if (!num_items2 && rv2 != ERR_INVALID_NEXT) | |
798 rv2 = ERR_INVALID_HEAD; | |
799 | |
800 int expected = control_data_->sizes[list]; | |
801 int total_items = num_items + num_items2; | |
802 | |
803 if (!count_lists_) { | |
804 // There's no expected value, so we'll use something else. | |
gavinp
2012/04/26 15:46:54
So, if the second element is the last element or t
rvargas (doing something else)
2012/04/27 00:18:10
Not an exact science, but if the two searches over
| |
805 if (last3 == last1 || last3 == last2 || last4 == last1 || last4 == last2) | |
806 expected = total_items + 1; | |
797 } | 807 } |
798 // If there is no tail, having a head is an error. | 808 |
799 if (!my_tail.is_initialized()) | 809 if (expected) { |
810 // This histogram has an offset so that we can see small negative values. In | |
811 // practice, it is linear from -9 to +8. | |
812 UMA_HISTOGRAM_CUSTOM_COUNTS("DiskCache.LostItems", | |
gavinp
2012/04/26 15:46:54
So if I understand the comment, the range is -9 t
rvargas (doing something else)
2012/04/27 00:18:10
Nope. IMO, the histogram ranges (log ones) are kin
gavinp
2012/04/30 18:57:15
Aha! This is right on the cusp (so it's probably
rvargas (doing something else)
2012/04/30 22:03:00
Note that I'm actually happy with the usual 50 buc
| |
813 expected - total_items + 10, 0, 2000, 75); | |
814 } | |
815 | |
816 const int kInvalidHead = 1; | |
817 const int kInvalidTail = 2; | |
818 const int kInvalidHeadAndTail = 3; | |
819 const int kOneInvalidEntry = 4; | |
820 const int kTwoInvalidEntries = 5; | |
821 const int kOneInvalidLink = 6; | |
822 const int kTwoInvalidLinks = 7; | |
823 const int kOneInvalidEntryOneInvalidLink = 8; | |
824 | |
825 int error = list * 10; | |
gavinp
2012/04/26 15:46:54
10? And not 9?
rvargas (doing something else)
2012/04/27 00:18:10
I'm going for something that is easier to read (wh
gavinp
2012/04/30 18:57:15
Yeah, I thought as much. It's a shame we can't pu
rvargas (doing something else)
2012/04/30 22:03:00
I was thinking over lunch.. sure, ...ErrorWithList
| |
826 if (rv == ERR_INVALID_HEAD && rv2 != ERR_INVALID_HEAD) { | |
827 error += kInvalidHead; | |
828 } else if (rv == ERR_INVALID_HEAD && rv2 == ERR_INVALID_HEAD) { | |
829 error += kInvalidHeadAndTail; | |
830 } else if (rv != ERR_INVALID_HEAD && rv2 == ERR_INVALID_HEAD) { | |
831 error += kInvalidTail; | |
832 } else if (rv == ERR_INVALID_ENTRY && rv2 == ERR_INVALID_ENTRY) { | |
833 error += kTwoInvalidEntries; | |
834 } else if (rv == ERR_INVALID_ENTRY && rv2 == 0) { | |
835 error += kOneInvalidEntry; | |
836 } else if (rv == ERR_INVALID_ENTRY || rv2 == ERR_INVALID_ENTRY) { | |
837 error += kOneInvalidEntryOneInvalidLink; | |
838 } else if (rv2 != 0) { | |
839 error += kTwoInvalidLinks; | |
840 } else { | |
841 error += kOneInvalidLink; | |
842 } | |
843 CACHE_UMA(CACHE_ERROR, "ListError", 0, error); | |
gavinp
2012/04/26 15:46:54
"ListTypeAndError" ??
rvargas (doing something else)
2012/04/27 00:18:10
ListType sounds unrelated to ListError, so ListTyp
| |
844 | |
845 return rv; | |
846 } | |
847 | |
848 // Note that the returned error codes assume a forward walk (from head to tail) | |
849 // so they have to be adjusted accordingly by the caller. We use two stop values | |
850 // to be able to detect a corrupt node at the end that is not linked going back. | |
851 int Rankings::CheckListSection(List list, Addr stop1, Addr stop2, | |
852 ListDirection dir, | |
853 Addr* last1, Addr* last2, int* num_items) { | |
854 Addr current = (dir == FORWARD) ? heads_[list] : tails_[list]; | |
855 *last1 = *last2 = current; | |
856 *num_items = 0; | |
857 if (!current.is_initialized()) | |
858 return 0; | |
859 | |
860 if (!current.SanityCheckForRankings()) | |
800 return ERR_INVALID_HEAD; | 861 return ERR_INVALID_HEAD; |
801 | 862 |
802 if (my_tail.is_separate_file()) | |
803 return ERR_INVALID_TAIL; | |
804 | |
805 if (my_head.is_separate_file()) | |
806 return ERR_INVALID_HEAD; | |
807 | |
808 int num_items = 0; | |
809 Addr address(my_head.value()); | |
810 Addr prev(my_head.value()); | |
811 scoped_ptr<CacheRankingsBlock> node; | 863 scoped_ptr<CacheRankingsBlock> node; |
864 Addr prev_addr(current); | |
812 do { | 865 do { |
813 node.reset(new CacheRankingsBlock(backend_->File(address), address)); | 866 node.reset(new CacheRankingsBlock(backend_->File(current), current)); |
814 node->Load(); | 867 node->Load(); |
815 if (node->Data()->prev != prev.value()) | 868 if (!SanityCheck(node.get(), true)) |
816 return ERR_INVALID_PREV; | |
817 if (!CheckEntry(node.get())) | |
818 return ERR_INVALID_ENTRY; | 869 return ERR_INVALID_ENTRY; |
819 | 870 |
820 prev.set_value(address.value()); | 871 CacheAddr next = (dir == FORWARD) ? node->Data()->next : node->Data()->prev; |
gavinp
2012/04/26 15:46:54
This is really pessimal, including dir == FORWARD
rvargas (doing something else)
2012/04/27 00:18:10
This is getting ridiculous. The natural value is b
gavinp
2012/04/30 18:57:15
OK, so what motivates me on this is that I want ca
rvargas (doing something else)
2012/04/30 22:03:00
as you wish.
On 2012/04/30 18:57:15, gavinp wrote
| |
821 address.set_value(node->Data()->next); | 872 CacheAddr prev = (dir == FORWARD) ? node->Data()->prev : node->Data()->next; |
822 if (!address.is_initialized() || address.is_separate_file()) | 873 |
874 if (prev != prev_addr.value()) | |
875 return ERR_INVALID_PREV; | |
876 | |
877 Addr next_addr(next); | |
878 if (!next_addr.SanityCheckForRankings()) | |
823 return ERR_INVALID_NEXT; | 879 return ERR_INVALID_NEXT; |
824 | 880 |
825 num_items++; | 881 prev_addr = current; |
826 } while (node->address().value() != address.value()); | 882 current = next_addr; |
827 return num_items; | 883 *last2 = *last1; |
884 *last1 = current; | |
885 (*num_items)++; | |
886 | |
887 if (next_addr == prev_addr) { | |
888 Addr last = (dir == FORWARD) ? tails_[list] : heads_[list]; | |
889 if (next_addr == last) | |
890 return 0; | |
891 return ERR_INVALID_TAIL; | |
892 } | |
893 } while (current != stop1 && current != stop2); | |
894 return 0; | |
gavinp
2012/04/26 15:46:54
return OK;
| |
828 } | 895 } |
829 | 896 |
830 bool Rankings::IsHead(CacheAddr addr, List* list) const { | 897 bool Rankings::IsHead(CacheAddr addr, List* list) const { |
831 for (int i = 0; i < LAST_ELEMENT; i++) { | 898 for (int i = 0; i < LAST_ELEMENT; i++) { |
832 if (addr == heads_[i].value()) { | 899 if (addr == heads_[i].value()) { |
833 if (*list != i) | 900 if (*list != i) |
834 Trace("Changing list %d to %d", *list, i); | 901 Trace("Changing list %d to %d", *list, i); |
835 *list = static_cast<List>(i); | 902 *list = static_cast<List>(i); |
836 return true; | 903 return true; |
837 } | 904 } |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
888 void Rankings::DecrementCounter(List list) { | 955 void Rankings::DecrementCounter(List list) { |
889 if (!count_lists_) | 956 if (!count_lists_) |
890 return; | 957 return; |
891 | 958 |
892 DCHECK(control_data_->sizes[list] > 0); | 959 DCHECK(control_data_->sizes[list] > 0); |
893 if (control_data_->sizes[list] > 0) | 960 if (control_data_->sizes[list] > 0) |
894 control_data_->sizes[list]--; | 961 control_data_->sizes[list]--; |
895 } | 962 } |
896 | 963 |
897 } // namespace disk_cache | 964 } // namespace disk_cache |
OLD | NEW |