diff options
Diffstat (limited to 'net/disk_cache/backend_impl.cc')
-rw-r--r-- | net/disk_cache/backend_impl.cc | 65 |
1 files changed, 52 insertions, 13 deletions
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc index 3d0e403..89890e9 100644 --- a/net/disk_cache/backend_impl.cc +++ b/net/disk_cache/backend_impl.cc @@ -681,7 +681,8 @@ EntryImpl* BackendImpl::OpenEntryImpl(const std::string& key) { 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; @@ -715,11 +716,13 @@ EntryImpl* BackendImpl::CreateEntryImpl(const std::string& key) { 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_]) { @@ -904,7 +907,9 @@ void BackendImpl::RecoveredEntry(CacheRankingsBlock* rankings) { 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); @@ -915,7 +920,7 @@ void BackendImpl::InternalDoomEntry(EntryImpl* entry) { if (parent_entry) { parent_entry->SetNextAddress(Addr(child)); parent_entry->Release(); - } else { + } else if (!error) { data_->table[hash & mask_] = child; } @@ -1240,6 +1245,16 @@ void BackendImpl::ThrottleRequestsForTest(bool throttle) { 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"; @@ -1556,16 +1571,28 @@ int BackendImpl::NewEntry(Addr address, EntryImpl** entry, bool* dirty) { } EntryImpl* BackendImpl::MatchEntry(const std::string& key, uint32 hash, - bool find_parent) { + bool find_parent, Addr entry_addr, + bool* match_error) { 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; @@ -1601,6 +1628,7 @@ EntryImpl* BackendImpl::MatchEntry(const std::string& key, uint32 hash, // Restart the search. address.set_value(data_->table[hash & mask_]); + visited.clear(); continue; } @@ -1609,6 +1637,11 @@ EntryImpl* BackendImpl::MatchEntry(const std::string& key, uint32 hash, 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()) @@ -1666,7 +1699,7 @@ EntryImpl* BackendImpl::OpenFollowingEntry(bool forward, void** iter) { 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. @@ -1723,7 +1756,7 @@ bool BackendImpl::OpenFollowingEntryFromList(bool forward, Rankings::List list, 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; @@ -1731,8 +1764,7 @@ bool BackendImpl::OpenFollowingEntryFromList(bool forward, Rankings::List list, return true; } -EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next, - bool to_evict) { +EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next) { if (!next || disabled_) return NULL; @@ -1747,12 +1779,19 @@ EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next, 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(); @@ -1804,7 +1843,7 @@ void BackendImpl::DestroyInvalidEntry(EntryImpl* entry) { 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(); |