summaryrefslogtreecommitdiffstats
path: root/net/disk_cache/backend_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/disk_cache/backend_impl.cc')
-rw-r--r--net/disk_cache/backend_impl.cc65
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();