Chromium Code Reviews| Index: net/disk_cache/backend_impl.cc |
| =================================================================== |
| --- net/disk_cache/backend_impl.cc (revision 71365) |
| +++ net/disk_cache/backend_impl.cc (working copy) |
| @@ -678,7 +678,8 @@ |
| uint32 hash = Hash(key); |
| Trace("Open hash 0x%x", hash); |
| - EntryImpl* cache_entry = MatchEntry(key, hash, false); |
| + bool error; |
| + EntryImpl* cache_entry = MatchEntry(key, hash, false, Addr(), &error); |
| if (!cache_entry) { |
| stats_.OnEvent(Stats::OPEN_MISS); |
| return NULL; |
| @@ -712,11 +713,13 @@ |
| if (entry_address.is_initialized()) { |
| // We have an entry already. It could be the one we are looking for, or just |
| // a hash conflict. |
| - EntryImpl* old_entry = MatchEntry(key, hash, false); |
| + bool error; |
| + EntryImpl* old_entry = MatchEntry(key, hash, false, Addr(), &error); |
| if (old_entry) |
| return ResurrectEntry(old_entry); |
| - EntryImpl* parent_entry = MatchEntry(key, hash, true); |
| + EntryImpl* parent_entry = MatchEntry(key, hash, true, Addr(), &error); |
| + DCHECK(!error); |
| if (parent_entry) { |
| parent.swap(&parent_entry); |
| } else if (data_->table[hash & mask_]) { |
| @@ -901,7 +904,9 @@ |
| void BackendImpl::InternalDoomEntry(EntryImpl* entry) { |
| uint32 hash = entry->GetHash(); |
| std::string key = entry->GetKey(); |
| - EntryImpl* parent_entry = MatchEntry(key, hash, true); |
| + Addr entry_addr = entry->entry()->address(); |
| + bool error; |
| + EntryImpl* parent_entry = MatchEntry(key, hash, true, entry_addr, &error); |
| CacheAddr child(entry->GetNextAddress()); |
| Trace("Doom entry 0x%p", entry); |
| @@ -912,7 +917,7 @@ |
| if (parent_entry) { |
| parent_entry->SetNextAddress(Addr(child)); |
| parent_entry->Release(); |
| - } else { |
| + } else if (!error) { |
| data_->table[hash & mask_] = child; |
| } |
| @@ -1237,6 +1242,16 @@ |
| background_queue_.StopQueingOperations(); |
| } |
| +void BackendImpl::TrimForTest(bool empty) { |
| + eviction_.SetTestMode(); |
| + eviction_.TrimCache(empty); |
| +} |
| + |
| +void BackendImpl::TrimDeletedListForTest(bool empty) { |
| + eviction_.SetTestMode(); |
| + eviction_.TrimDeletedList(empty); |
| +} |
| + |
| int BackendImpl::SelfCheck() { |
| if (!init_) { |
| LOG(ERROR) << "Init failed"; |
| @@ -1553,16 +1568,28 @@ |
| } |
| EntryImpl* BackendImpl::MatchEntry(const std::string& key, uint32 hash, |
| - bool find_parent) { |
| + bool find_parent, Addr entry_addr, |
| + bool* match_error) { |
|
gavinp
2011/01/25 20:23:51
I'm concerned this function is doing too much. Th
rvargas (doing something else)
2011/01/25 20:47:53
Yeah, I thought about that too. In fact, I initial
|
| Addr address(data_->table[hash & mask_]); |
| scoped_refptr<EntryImpl> cache_entry, parent_entry; |
| EntryImpl* tmp = NULL; |
| bool found = false; |
| + std::set<CacheAddr> visited; |
| + *match_error = false; |
| for (;;) { |
| if (disabled_) |
| break; |
| + if (visited.find(address.value()) != visited.end()) { |
| + // It's possible for a buggy version of the code to write a loop. Just |
| + // break it. |
| + Trace("Hash collision loop 0x%x", address.value()); |
| + address.set_value(0); |
| + parent_entry->SetNextAddress(address); |
| + } |
| + visited.insert(address.value()); |
| + |
| if (!address.is_initialized()) { |
| if (find_parent) |
| found = true; |
| @@ -1598,6 +1625,7 @@ |
| // Restart the search. |
| address.set_value(data_->table[hash & mask_]); |
| + visited.clear(); |
| continue; |
| } |
| @@ -1606,6 +1634,11 @@ |
| if (!cache_entry->Update()) |
| cache_entry = NULL; |
| found = true; |
| + if (find_parent && entry_addr.value() != address.value()) { |
| + Trace("Entry not on the index 0x%x", address.value()); |
| + *match_error = true; |
| + parent_entry = NULL; |
| + } |
| break; |
| } |
| if (!cache_entry->Update()) |
| @@ -1663,7 +1696,7 @@ |
| OpenFollowingEntryFromList(forward, iterator->list, |
| &iterator->nodes[i], &temp); |
| } else { |
| - temp = GetEnumeratedEntry(iterator->nodes[i], false); |
| + temp = GetEnumeratedEntry(iterator->nodes[i]); |
| } |
| entries[i].swap(&temp); // The entry was already addref'd. |
| @@ -1720,7 +1753,7 @@ |
| Rankings::ScopedRankingsBlock next(&rankings_, next_block); |
| *from_entry = NULL; |
| - *next_entry = GetEnumeratedEntry(next.get(), false); |
| + *next_entry = GetEnumeratedEntry(next.get()); |
| if (!*next_entry) |
| return false; |
| @@ -1728,8 +1761,7 @@ |
| return true; |
| } |
| -EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next, |
| - bool to_evict) { |
| +EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next) { |
| if (!next || disabled_) |
| return NULL; |
| @@ -1744,12 +1776,19 @@ |
| return NULL; |
| } |
| - // There is no need to store the entry to disk if we want to delete it. |
| - if (!to_evict && !entry->Update()) { |
| + if (!entry->Update()) { |
| entry->Release(); |
| return NULL; |
| } |
| + // Note that it is unfortunate (but possible) for this entry to be clean, but |
| + // not actually the real entry. In other words, we could have lost this entry |
| + // from the index, and it could have been replaced with a newer one. It's not |
| + // worth checking that this entry is "the real one", so we just return it and |
| + // let the enumeration continue; this entry will be evicted at some point, and |
| + // the regular path will work with the real entry. With time, this problem |
| + // will disasappear because this scenario is just a bug. |
| + |
| // Make sure that we save the key for later. |
| entry->GetKey(); |
| @@ -1801,7 +1840,7 @@ |
| void BackendImpl::DestroyInvalidEntryFromEnumeration(EntryImpl* entry) { |
| std::string key = entry->GetKey(); |
| entry->SetPointerForInvalidEntry(GetCurrentEntryId()); |
| - CacheAddr next_entry = entry->entry()->Data()->next; |
| + CacheAddr next_entry = entry->GetNextAddress(); |
| if (!next_entry) { |
| DestroyInvalidEntry(entry); |
| entry->Release(); |