Chromium Code Reviews| Index: net/disk_cache/rankings.cc |
| =================================================================== |
| --- net/disk_cache/rankings.cc (revision 133063) |
| +++ net/disk_cache/rankings.cc (working copy) |
| @@ -724,14 +724,6 @@ |
| control_data_->operation = 0; |
| } |
| -bool Rankings::CheckEntry(CacheRankingsBlock* rankings) { |
| - if (rankings->VerifyHash()) |
| - return true; |
| - |
| - // If this entry is not dirty, it is a serious problem. |
| - return backend_->GetCurrentEntryId() != rankings->Data()->dirty; |
| -} |
| - |
| bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev, |
| CacheRankingsBlock* next, List* list) { |
| CacheAddr node_addr = node->address().value(); |
| @@ -787,44 +779,119 @@ |
| } |
| int Rankings::CheckList(List list) { |
| - Addr& my_head = heads_[list]; |
| - Addr& my_tail = tails_[list]; |
| - if (!my_head.is_initialized()) { |
| - if (!my_tail.is_initialized()) |
| - return 0; |
| - // If there is no head, having a tail is an error. |
| - return ERR_INVALID_TAIL; |
| + Addr last1, last2; |
| + int num_items; |
| + int rv = CheckListSection(list, last1, last2, FORWARD, |
| + &last1, &last2, &num_items); |
| + if (rv == 0) |
| + return num_items; |
| + |
| + 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
|
| + int num_items2; |
|
gavinp
2012/04/26 15:46:54
num_items_backwards ?
|
| + int rv2 = CheckListSection(list, last1, last2, BACKWARD, |
| + &last3, &last4, &num_items2); |
| + |
| + if (!num_items && rv != ERR_INVALID_NEXT) |
| + rv = ERR_INVALID_HEAD; |
| + |
| + if (!num_items2 && rv2 != ERR_INVALID_NEXT) |
| + rv2 = ERR_INVALID_HEAD; |
| + |
| + int expected = control_data_->sizes[list]; |
| + int total_items = num_items + num_items2; |
| + |
| + if (!count_lists_) { |
| + // 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
|
| + if (last3 == last1 || last3 == last2 || last4 == last1 || last4 == last2) |
| + expected = total_items + 1; |
| } |
| - // If there is no tail, having a head is an error. |
| - if (!my_tail.is_initialized()) |
| - return ERR_INVALID_HEAD; |
| - if (my_tail.is_separate_file()) |
| - return ERR_INVALID_TAIL; |
| + if (expected) { |
| + // This histogram has an offset so that we can see small negative values. In |
| + // practice, it is linear from -9 to +8. |
| + 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
|
| + expected - total_items + 10, 0, 2000, 75); |
| + } |
| - if (my_head.is_separate_file()) |
| + const int kInvalidHead = 1; |
| + const int kInvalidTail = 2; |
| + const int kInvalidHeadAndTail = 3; |
| + const int kOneInvalidEntry = 4; |
| + const int kTwoInvalidEntries = 5; |
| + const int kOneInvalidLink = 6; |
| + const int kTwoInvalidLinks = 7; |
| + const int kOneInvalidEntryOneInvalidLink = 8; |
| + |
| + 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
|
| + if (rv == ERR_INVALID_HEAD && rv2 != ERR_INVALID_HEAD) { |
| + error += kInvalidHead; |
| + } else if (rv == ERR_INVALID_HEAD && rv2 == ERR_INVALID_HEAD) { |
| + error += kInvalidHeadAndTail; |
| + } else if (rv != ERR_INVALID_HEAD && rv2 == ERR_INVALID_HEAD) { |
| + error += kInvalidTail; |
| + } else if (rv == ERR_INVALID_ENTRY && rv2 == ERR_INVALID_ENTRY) { |
| + error += kTwoInvalidEntries; |
| + } else if (rv == ERR_INVALID_ENTRY && rv2 == 0) { |
| + error += kOneInvalidEntry; |
| + } else if (rv == ERR_INVALID_ENTRY || rv2 == ERR_INVALID_ENTRY) { |
| + error += kOneInvalidEntryOneInvalidLink; |
| + } else if (rv2 != 0) { |
| + error += kTwoInvalidLinks; |
| + } else { |
| + error += kOneInvalidLink; |
| + } |
| + 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
|
| + |
| + return rv; |
| +} |
| + |
| +// Note that the returned error codes assume a forward walk (from head to tail) |
| +// so they have to be adjusted accordingly by the caller. We use two stop values |
| +// to be able to detect a corrupt node at the end that is not linked going back. |
| +int Rankings::CheckListSection(List list, Addr stop1, Addr stop2, |
| + ListDirection dir, |
| + Addr* last1, Addr* last2, int* num_items) { |
| + Addr current = (dir == FORWARD) ? heads_[list] : tails_[list]; |
| + *last1 = *last2 = current; |
| + *num_items = 0; |
| + if (!current.is_initialized()) |
| + return 0; |
| + |
| + if (!current.SanityCheckForRankings()) |
| return ERR_INVALID_HEAD; |
| - int num_items = 0; |
| - Addr address(my_head.value()); |
| - Addr prev(my_head.value()); |
| scoped_ptr<CacheRankingsBlock> node; |
| + Addr prev_addr(current); |
| do { |
| - node.reset(new CacheRankingsBlock(backend_->File(address), address)); |
| + node.reset(new CacheRankingsBlock(backend_->File(current), current)); |
| node->Load(); |
| - if (node->Data()->prev != prev.value()) |
| - return ERR_INVALID_PREV; |
| - if (!CheckEntry(node.get())) |
| + if (!SanityCheck(node.get(), true)) |
| return ERR_INVALID_ENTRY; |
| - prev.set_value(address.value()); |
| - address.set_value(node->Data()->next); |
| - if (!address.is_initialized() || address.is_separate_file()) |
| + 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
|
| + CacheAddr prev = (dir == FORWARD) ? node->Data()->prev : node->Data()->next; |
| + |
| + if (prev != prev_addr.value()) |
| + return ERR_INVALID_PREV; |
| + |
| + Addr next_addr(next); |
| + if (!next_addr.SanityCheckForRankings()) |
| return ERR_INVALID_NEXT; |
| - num_items++; |
| - } while (node->address().value() != address.value()); |
| - return num_items; |
| + prev_addr = current; |
| + current = next_addr; |
| + *last2 = *last1; |
| + *last1 = current; |
| + (*num_items)++; |
| + |
| + if (next_addr == prev_addr) { |
| + Addr last = (dir == FORWARD) ? tails_[list] : heads_[list]; |
| + if (next_addr == last) |
| + return 0; |
| + return ERR_INVALID_TAIL; |
| + } |
| + } while (current != stop1 && current != stop2); |
| + return 0; |
|
gavinp
2012/04/26 15:46:54
return OK;
|
| } |
| bool Rankings::IsHead(CacheAddr addr, List* list) const { |