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 |