Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: net/disk_cache/backend_impl.cc

Issue 6292011: Disk cache: Prevent obscure file corruption and deal... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/disk_cache/backend_impl.h" 5 #include "net/disk_cache/backend_impl.h"
6 6
7 #include "base/file_path.h" 7 #include "base/file_path.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/metrics/field_trial.h" 10 #include "base/metrics/field_trial.h"
(...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 } 671 }
672 672
673 EntryImpl* BackendImpl::OpenEntryImpl(const std::string& key) { 673 EntryImpl* BackendImpl::OpenEntryImpl(const std::string& key) {
674 if (disabled_) 674 if (disabled_)
675 return NULL; 675 return NULL;
676 676
677 TimeTicks start = TimeTicks::Now(); 677 TimeTicks start = TimeTicks::Now();
678 uint32 hash = Hash(key); 678 uint32 hash = Hash(key);
679 Trace("Open hash 0x%x", hash); 679 Trace("Open hash 0x%x", hash);
680 680
681 EntryImpl* cache_entry = MatchEntry(key, hash, false); 681 bool error;
682 EntryImpl* cache_entry = MatchEntry(key, hash, false, Addr(), &error);
682 if (!cache_entry) { 683 if (!cache_entry) {
683 stats_.OnEvent(Stats::OPEN_MISS); 684 stats_.OnEvent(Stats::OPEN_MISS);
684 return NULL; 685 return NULL;
685 } 686 }
686 687
687 if (ENTRY_NORMAL != cache_entry->entry()->Data()->state) { 688 if (ENTRY_NORMAL != cache_entry->entry()->Data()->state) {
688 // The entry was already evicted. 689 // The entry was already evicted.
689 cache_entry->Release(); 690 cache_entry->Release();
690 stats_.OnEvent(Stats::OPEN_MISS); 691 stats_.OnEvent(Stats::OPEN_MISS);
691 return NULL; 692 return NULL;
(...skipping 13 matching lines...) Expand all
705 706
706 TimeTicks start = TimeTicks::Now(); 707 TimeTicks start = TimeTicks::Now();
707 uint32 hash = Hash(key); 708 uint32 hash = Hash(key);
708 Trace("Create hash 0x%x", hash); 709 Trace("Create hash 0x%x", hash);
709 710
710 scoped_refptr<EntryImpl> parent; 711 scoped_refptr<EntryImpl> parent;
711 Addr entry_address(data_->table[hash & mask_]); 712 Addr entry_address(data_->table[hash & mask_]);
712 if (entry_address.is_initialized()) { 713 if (entry_address.is_initialized()) {
713 // We have an entry already. It could be the one we are looking for, or just 714 // We have an entry already. It could be the one we are looking for, or just
714 // a hash conflict. 715 // a hash conflict.
715 EntryImpl* old_entry = MatchEntry(key, hash, false); 716 bool error;
717 EntryImpl* old_entry = MatchEntry(key, hash, false, Addr(), &error);
716 if (old_entry) 718 if (old_entry)
717 return ResurrectEntry(old_entry); 719 return ResurrectEntry(old_entry);
718 720
719 EntryImpl* parent_entry = MatchEntry(key, hash, true); 721 EntryImpl* parent_entry = MatchEntry(key, hash, true, Addr(), &error);
722 DCHECK(!error);
720 if (parent_entry) { 723 if (parent_entry) {
721 parent.swap(&parent_entry); 724 parent.swap(&parent_entry);
722 } else if (data_->table[hash & mask_]) { 725 } else if (data_->table[hash & mask_]) {
723 // We should have corrected the problem. 726 // We should have corrected the problem.
724 NOTREACHED(); 727 NOTREACHED();
725 return NULL; 728 return NULL;
726 } 729 }
727 } 730 }
728 731
729 int num_blocks; 732 int num_blocks;
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
894 // Anything on the table means that this entry is there. 897 // Anything on the table means that this entry is there.
895 if (data_->table[hash & mask_]) 898 if (data_->table[hash & mask_])
896 return; 899 return;
897 900
898 data_->table[hash & mask_] = address.value(); 901 data_->table[hash & mask_] = address.value();
899 } 902 }
900 903
901 void BackendImpl::InternalDoomEntry(EntryImpl* entry) { 904 void BackendImpl::InternalDoomEntry(EntryImpl* entry) {
902 uint32 hash = entry->GetHash(); 905 uint32 hash = entry->GetHash();
903 std::string key = entry->GetKey(); 906 std::string key = entry->GetKey();
904 EntryImpl* parent_entry = MatchEntry(key, hash, true); 907 Addr entry_addr = entry->entry()->address();
908 bool error;
909 EntryImpl* parent_entry = MatchEntry(key, hash, true, entry_addr, &error);
905 CacheAddr child(entry->GetNextAddress()); 910 CacheAddr child(entry->GetNextAddress());
906 911
907 Trace("Doom entry 0x%p", entry); 912 Trace("Doom entry 0x%p", entry);
908 913
909 eviction_.OnDoomEntry(entry); 914 eviction_.OnDoomEntry(entry);
910 entry->InternalDoom(); 915 entry->InternalDoom();
911 916
912 if (parent_entry) { 917 if (parent_entry) {
913 parent_entry->SetNextAddress(Addr(child)); 918 parent_entry->SetNextAddress(Addr(child));
914 parent_entry->Release(); 919 parent_entry->Release();
915 } else { 920 } else if (!error) {
916 data_->table[hash & mask_] = child; 921 data_->table[hash & mask_] = child;
917 } 922 }
918 923
919 if (!new_eviction_) { 924 if (!new_eviction_) {
920 DecreaseNumEntries(); 925 DecreaseNumEntries();
921 } 926 }
922 927
923 stats_.OnEvent(Stats::DOOM_ENTRY); 928 stats_.OnEvent(Stats::DOOM_ENTRY);
924 } 929 }
925 930
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
1230 return net::ERR_IO_PENDING; 1235 return net::ERR_IO_PENDING;
1231 } 1236 }
1232 1237
1233 void BackendImpl::ThrottleRequestsForTest(bool throttle) { 1238 void BackendImpl::ThrottleRequestsForTest(bool throttle) {
1234 if (throttle) 1239 if (throttle)
1235 background_queue_.StartQueingOperations(); 1240 background_queue_.StartQueingOperations();
1236 else 1241 else
1237 background_queue_.StopQueingOperations(); 1242 background_queue_.StopQueingOperations();
1238 } 1243 }
1239 1244
1245 void BackendImpl::TrimForTest(bool empty) {
1246 eviction_.SetTestMode();
1247 eviction_.TrimCache(empty);
1248 }
1249
1250 void BackendImpl::TrimDeletedListForTest(bool empty) {
1251 eviction_.SetTestMode();
1252 eviction_.TrimDeletedList(empty);
1253 }
1254
1240 int BackendImpl::SelfCheck() { 1255 int BackendImpl::SelfCheck() {
1241 if (!init_) { 1256 if (!init_) {
1242 LOG(ERROR) << "Init failed"; 1257 LOG(ERROR) << "Init failed";
1243 return ERR_INIT_FAILED; 1258 return ERR_INIT_FAILED;
1244 } 1259 }
1245 1260
1246 int num_entries = rankings_.SelfCheck(); 1261 int num_entries = rankings_.SelfCheck();
1247 if (num_entries < 0) { 1262 if (num_entries < 0) {
1248 LOG(ERROR) << "Invalid rankings list, error " << num_entries; 1263 LOG(ERROR) << "Invalid rankings list, error " << num_entries;
1249 return num_entries; 1264 return num_entries;
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after
1546 // We only add clean entries to the map. 1561 // We only add clean entries to the map.
1547 open_entries_[address.value()] = cache_entry; 1562 open_entries_[address.value()] = cache_entry;
1548 } 1563 }
1549 1564
1550 cache_entry->BeginLogging(net_log_, false); 1565 cache_entry->BeginLogging(net_log_, false);
1551 cache_entry.swap(entry); 1566 cache_entry.swap(entry);
1552 return 0; 1567 return 0;
1553 } 1568 }
1554 1569
1555 EntryImpl* BackendImpl::MatchEntry(const std::string& key, uint32 hash, 1570 EntryImpl* BackendImpl::MatchEntry(const std::string& key, uint32 hash,
1556 bool find_parent) { 1571 bool find_parent, Addr entry_addr,
1572 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
1557 Addr address(data_->table[hash & mask_]); 1573 Addr address(data_->table[hash & mask_]);
1558 scoped_refptr<EntryImpl> cache_entry, parent_entry; 1574 scoped_refptr<EntryImpl> cache_entry, parent_entry;
1559 EntryImpl* tmp = NULL; 1575 EntryImpl* tmp = NULL;
1560 bool found = false; 1576 bool found = false;
1577 std::set<CacheAddr> visited;
1578 *match_error = false;
1561 1579
1562 for (;;) { 1580 for (;;) {
1563 if (disabled_) 1581 if (disabled_)
1564 break; 1582 break;
1565 1583
1584 if (visited.find(address.value()) != visited.end()) {
1585 // It's possible for a buggy version of the code to write a loop. Just
1586 // break it.
1587 Trace("Hash collision loop 0x%x", address.value());
1588 address.set_value(0);
1589 parent_entry->SetNextAddress(address);
1590 }
1591 visited.insert(address.value());
1592
1566 if (!address.is_initialized()) { 1593 if (!address.is_initialized()) {
1567 if (find_parent) 1594 if (find_parent)
1568 found = true; 1595 found = true;
1569 break; 1596 break;
1570 } 1597 }
1571 1598
1572 bool dirty; 1599 bool dirty;
1573 int error = NewEntry(address, &tmp, &dirty); 1600 int error = NewEntry(address, &tmp, &dirty);
1574 cache_entry.swap(&tmp); 1601 cache_entry.swap(&tmp);
1575 1602
(...skipping 15 matching lines...) Expand all
1591 // It is important to call DestroyInvalidEntry after removing this 1618 // It is important to call DestroyInvalidEntry after removing this
1592 // entry from the table. 1619 // entry from the table.
1593 DestroyInvalidEntry(cache_entry); 1620 DestroyInvalidEntry(cache_entry);
1594 cache_entry = NULL; 1621 cache_entry = NULL;
1595 } else { 1622 } else {
1596 Trace("NewEntry failed on MatchEntry 0x%x", address.value()); 1623 Trace("NewEntry failed on MatchEntry 0x%x", address.value());
1597 } 1624 }
1598 1625
1599 // Restart the search. 1626 // Restart the search.
1600 address.set_value(data_->table[hash & mask_]); 1627 address.set_value(data_->table[hash & mask_]);
1628 visited.clear();
1601 continue; 1629 continue;
1602 } 1630 }
1603 1631
1604 DCHECK_EQ(hash & mask_, cache_entry->entry()->Data()->hash & mask_); 1632 DCHECK_EQ(hash & mask_, cache_entry->entry()->Data()->hash & mask_);
1605 if (cache_entry->IsSameEntry(key, hash)) { 1633 if (cache_entry->IsSameEntry(key, hash)) {
1606 if (!cache_entry->Update()) 1634 if (!cache_entry->Update())
1607 cache_entry = NULL; 1635 cache_entry = NULL;
1608 found = true; 1636 found = true;
1637 if (find_parent && entry_addr.value() != address.value()) {
1638 Trace("Entry not on the index 0x%x", address.value());
1639 *match_error = true;
1640 parent_entry = NULL;
1641 }
1609 break; 1642 break;
1610 } 1643 }
1611 if (!cache_entry->Update()) 1644 if (!cache_entry->Update())
1612 cache_entry = NULL; 1645 cache_entry = NULL;
1613 parent_entry = cache_entry; 1646 parent_entry = cache_entry;
1614 cache_entry = NULL; 1647 cache_entry = NULL;
1615 if (!parent_entry) 1648 if (!parent_entry)
1616 break; 1649 break;
1617 1650
1618 address.set_value(parent_entry->GetNextAddress()); 1651 address.set_value(parent_entry->GetNextAddress());
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1656 return NULL; 1689 return NULL;
1657 } else { 1690 } else {
1658 // Get the next entry from the last list, and the actual entries for the 1691 // Get the next entry from the last list, and the actual entries for the
1659 // elements on the other lists. 1692 // elements on the other lists.
1660 for (int i = 0; i < kListsToSearch; i++) { 1693 for (int i = 0; i < kListsToSearch; i++) {
1661 EntryImpl* temp = NULL; 1694 EntryImpl* temp = NULL;
1662 if (iterator->list == i) { 1695 if (iterator->list == i) {
1663 OpenFollowingEntryFromList(forward, iterator->list, 1696 OpenFollowingEntryFromList(forward, iterator->list,
1664 &iterator->nodes[i], &temp); 1697 &iterator->nodes[i], &temp);
1665 } else { 1698 } else {
1666 temp = GetEnumeratedEntry(iterator->nodes[i], false); 1699 temp = GetEnumeratedEntry(iterator->nodes[i]);
1667 } 1700 }
1668 1701
1669 entries[i].swap(&temp); // The entry was already addref'd. 1702 entries[i].swap(&temp); // The entry was already addref'd.
1670 } 1703 }
1671 } 1704 }
1672 1705
1673 int newest = -1; 1706 int newest = -1;
1674 int oldest = -1; 1707 int oldest = -1;
1675 Time access_times[kListsToSearch]; 1708 Time access_times[kListsToSearch];
1676 for (int i = 0; i < kListsToSearch; i++) { 1709 for (int i = 0; i < kListsToSearch; i++) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1713 if (!new_eviction_ && Rankings::NO_USE != list) 1746 if (!new_eviction_ && Rankings::NO_USE != list)
1714 return false; 1747 return false;
1715 1748
1716 Rankings::ScopedRankingsBlock rankings(&rankings_, *from_entry); 1749 Rankings::ScopedRankingsBlock rankings(&rankings_, *from_entry);
1717 CacheRankingsBlock* next_block = forward ? 1750 CacheRankingsBlock* next_block = forward ?
1718 rankings_.GetNext(rankings.get(), list) : 1751 rankings_.GetNext(rankings.get(), list) :
1719 rankings_.GetPrev(rankings.get(), list); 1752 rankings_.GetPrev(rankings.get(), list);
1720 Rankings::ScopedRankingsBlock next(&rankings_, next_block); 1753 Rankings::ScopedRankingsBlock next(&rankings_, next_block);
1721 *from_entry = NULL; 1754 *from_entry = NULL;
1722 1755
1723 *next_entry = GetEnumeratedEntry(next.get(), false); 1756 *next_entry = GetEnumeratedEntry(next.get());
1724 if (!*next_entry) 1757 if (!*next_entry)
1725 return false; 1758 return false;
1726 1759
1727 *from_entry = next.release(); 1760 *from_entry = next.release();
1728 return true; 1761 return true;
1729 } 1762 }
1730 1763
1731 EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next, 1764 EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next) {
1732 bool to_evict) {
1733 if (!next || disabled_) 1765 if (!next || disabled_)
1734 return NULL; 1766 return NULL;
1735 1767
1736 EntryImpl* entry; 1768 EntryImpl* entry;
1737 bool dirty; 1769 bool dirty;
1738 if (NewEntry(Addr(next->Data()->contents), &entry, &dirty)) 1770 if (NewEntry(Addr(next->Data()->contents), &entry, &dirty))
1739 return NULL; 1771 return NULL;
1740 1772
1741 if (dirty) { 1773 if (dirty) {
1742 // We cannot trust this entry. This code also releases the reference. 1774 // We cannot trust this entry. This code also releases the reference.
1743 DestroyInvalidEntryFromEnumeration(entry); 1775 DestroyInvalidEntryFromEnumeration(entry);
1744 return NULL; 1776 return NULL;
1745 } 1777 }
1746 1778
1747 // There is no need to store the entry to disk if we want to delete it. 1779 if (!entry->Update()) {
1748 if (!to_evict && !entry->Update()) {
1749 entry->Release(); 1780 entry->Release();
1750 return NULL; 1781 return NULL;
1751 } 1782 }
1752 1783
1784 // Note that it is unfortunate (but possible) for this entry to be clean, but
1785 // not actually the real entry. In other words, we could have lost this entry
1786 // from the index, and it could have been replaced with a newer one. It's not
1787 // worth checking that this entry is "the real one", so we just return it and
1788 // let the enumeration continue; this entry will be evicted at some point, and
1789 // the regular path will work with the real entry. With time, this problem
1790 // will disasappear because this scenario is just a bug.
1791
1753 // Make sure that we save the key for later. 1792 // Make sure that we save the key for later.
1754 entry->GetKey(); 1793 entry->GetKey();
1755 1794
1756 return entry; 1795 return entry;
1757 } 1796 }
1758 1797
1759 EntryImpl* BackendImpl::ResurrectEntry(EntryImpl* deleted_entry) { 1798 EntryImpl* BackendImpl::ResurrectEntry(EntryImpl* deleted_entry) {
1760 if (ENTRY_NORMAL == deleted_entry->entry()->Data()->state) { 1799 if (ENTRY_NORMAL == deleted_entry->entry()->Data()->state) {
1761 deleted_entry->Release(); 1800 deleted_entry->Release();
1762 stats_.OnEvent(Stats::CREATE_MISS); 1801 stats_.OnEvent(Stats::CREATE_MISS);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1794 // deleting it twice (if all fields are right, and when looking up the parent of 1833 // deleting it twice (if all fields are right, and when looking up the parent of
1795 // chained entries wee see this one... and we delete it because it is dirty). If 1834 // chained entries wee see this one... and we delete it because it is dirty). If
1796 // we ignore it, we may leave it here forever. So we're going to attempt to 1835 // we ignore it, we may leave it here forever. So we're going to attempt to
1797 // delete it through the provided object, without touching the index table 1836 // delete it through the provided object, without touching the index table
1798 // (because we cannot jus call MatchEntry()), and also attempt to delete it from 1837 // (because we cannot jus call MatchEntry()), and also attempt to delete it from
1799 // the table through the key: this may find a new entry (too bad), or an entry 1838 // the table through the key: this may find a new entry (too bad), or an entry
1800 // that was just deleted and consider it a very corrupt entry. 1839 // that was just deleted and consider it a very corrupt entry.
1801 void BackendImpl::DestroyInvalidEntryFromEnumeration(EntryImpl* entry) { 1840 void BackendImpl::DestroyInvalidEntryFromEnumeration(EntryImpl* entry) {
1802 std::string key = entry->GetKey(); 1841 std::string key = entry->GetKey();
1803 entry->SetPointerForInvalidEntry(GetCurrentEntryId()); 1842 entry->SetPointerForInvalidEntry(GetCurrentEntryId());
1804 CacheAddr next_entry = entry->entry()->Data()->next; 1843 CacheAddr next_entry = entry->GetNextAddress();
1805 if (!next_entry) { 1844 if (!next_entry) {
1806 DestroyInvalidEntry(entry); 1845 DestroyInvalidEntry(entry);
1807 entry->Release(); 1846 entry->Release();
1808 } 1847 }
1809 SyncDoomEntry(key); 1848 SyncDoomEntry(key);
1810 1849
1811 if (!next_entry) 1850 if (!next_entry)
1812 return; 1851 return;
1813 1852
1814 // We have a chained entry so instead of destroying first this entry and then 1853 // We have a chained entry so instead of destroying first this entry and then
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
2095 if (total_memory > kMaxBuffersSize || total_memory <= 0) 2134 if (total_memory > kMaxBuffersSize || total_memory <= 0)
2096 total_memory = kMaxBuffersSize; 2135 total_memory = kMaxBuffersSize;
2097 2136
2098 done = true; 2137 done = true;
2099 } 2138 }
2100 2139
2101 return static_cast<int>(total_memory); 2140 return static_cast<int>(total_memory);
2102 } 2141 }
2103 2142
2104 } // namespace disk_cache 2143 } // namespace disk_cache
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698