Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |