Index: net/disk_cache/backend_impl.cc |
=================================================================== |
--- net/disk_cache/backend_impl.cc (revision 102424) |
+++ net/disk_cache/backend_impl.cc (working copy) |
@@ -760,6 +760,19 @@ |
} |
} |
+ // The general flow is to allocate disk space and initialize the entry data, |
+ // followed by saving that to disk, then linking the entry though the index |
+ // and finally thorugh the lists. If there is a crash in this process, we may |
gavinp
2011/09/29 13:25:34
typo: thorugh -> through
|
+ // end up with: |
+ // a. Used, unreferenced empty blocks on disk (basically just garbage). |
+ // b. Used, unreferenced but meaningful data on disk (more garbage). |
+ // c. A fully formed entry, reachable only through the index. |
+ // d. A fully formed entry, also reachable through the lists, but still dirty. |
+ // |
+ // Anything after (b) can be automatically cleaned up. We may consider saving |
+ // the current operation (as we do while manipulating the lists) so that we |
+ // can detect and cleanup (a) and (b). |
+ |
int num_blocks = EntryImpl::NumBlocksForEntry(key.size()); |
if (!block_files_.CreateBlock(BLOCK_256, num_blocks, &entry_address)) { |
LOG(ERROR) << "Create entry failed " << key.c_str(); |
@@ -792,18 +805,22 @@ |
// We are not failing the operation; let's add this to the map. |
open_entries_[entry_address.value()] = cache_entry; |
- if (parent.get()) |
- parent->SetNextAddress(entry_address); |
- |
+ // Save the entry. |
block_files_.GetFile(entry_address)->Store(cache_entry->entry()); |
block_files_.GetFile(node_address)->Store(cache_entry->rankings()); |
- |
IncreaseNumEntries(); |
- eviction_.OnCreateEntry(cache_entry); |
entry_count_++; |
- if (!parent.get()) |
+ |
+ // Link this entry through the index. |
+ if (parent.get()) { |
+ parent->SetNextAddress(entry_address); |
+ } else { |
data_->table[hash & mask_] = entry_address.value(); |
+ } |
+ // Link this entry through the lists. |
+ eviction_.OnCreateEntry(cache_entry); |
+ |
CACHE_UMA(AGE_MS, "CreateTime", GetSizeGroup(), start); |
stats_.OnEvent(Stats::CREATE_HIT); |
SIMPLE_STATS_COUNTER("disk_cache.miss"); |
@@ -1562,9 +1579,23 @@ |
// Prevent overwriting the dirty flag on the destructor. |
cache_entry->SetDirtyFlag(GetCurrentEntryId()); |
- if (!rankings_.SanityCheck(cache_entry->rankings(), false)) |
- return ERR_INVALID_LINKS; |
+ if (!rankings_.SanityCheck(cache_entry->rankings(), false)) { |
+ cache_entry->SetDirtyFlag(0); |
+ // Don't remove this from the list (it is not linked properly). Instead, |
+ // break the link back to the entry because it is going away, and leave the |
+ // rankings node to be deleted if we find it through a list. |
+ rankings_.SetContents(cache_entry->rankings(), 0); |
+ } else if (!rankings_.DataSanityCheck(cache_entry->rankings(), false)) { |
+ cache_entry->SetDirtyFlag(0); |
+ rankings_.SetContents(cache_entry->rankings(), address.value()); |
+ } |
+ if (!cache_entry->DataSanityCheck()) { |
+ LOG(WARNING) << "Messed up entry found."; |
+ cache_entry->SetDirtyFlag(0); |
+ cache_entry->FixForDelete(); |
+ } |
+ |
if (cache_entry->dirty()) { |
Trace("Dirty entry 0x%p 0x%x", reinterpret_cast<void*>(cache_entry.get()), |
address.value()); |
@@ -1713,7 +1744,8 @@ |
OpenFollowingEntryFromList(forward, iterator->list, |
&iterator->nodes[i], &temp); |
} else { |
- temp = GetEnumeratedEntry(iterator->nodes[i]); |
+ temp = GetEnumeratedEntry(iterator->nodes[i], |
+ static_cast<Rankings::List>(i)); |
} |
entries[i].swap(&temp); // The entry was already addref'd. |
@@ -1770,7 +1802,7 @@ |
Rankings::ScopedRankingsBlock next(&rankings_, next_block); |
*from_entry = NULL; |
- *next_entry = GetEnumeratedEntry(next.get()); |
+ *next_entry = GetEnumeratedEntry(next.get(), list); |
if (!*next_entry) |
return false; |
@@ -1778,14 +1810,19 @@ |
return true; |
} |
-EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next) { |
+EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next, |
+ Rankings::List list) { |
if (!next || disabled_) |
return NULL; |
EntryImpl* entry; |
- if (NewEntry(Addr(next->Data()->contents), &entry)) { |
- // TODO(rvargas) bug 73102: We should remove this node from the list, and |
- // maybe do a better cleanup. |
+ int rv = NewEntry(Addr(next->Data()->contents), &entry); |
+ if (rv) { |
+ rankings_.Remove(next, list, false); |
+ if (rv == ERR_INVALID_ADDRESS) { |
+ // There is nothing linked from the index. Delete the rankings node. |
+ DeleteBlock(next->address(), true); |
+ } |
return NULL; |
} |