1/* 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) 3 Copyright (C) 2001 Dirk Mueller <mueller@kde.org> 4 Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Library General Public 8 License as published by the Free Software Foundation; either 9 version 2 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Library General Public License for more details. 15 16 You should have received a copy of the GNU Library General Public License 17 along with this library; see the file COPYING.LIB. If not, write to 18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20 21 This class provides all functionality needed for loading images, style sheets and html 22 pages from the web. It has a memory cache for these objects. 23*/ 24 25#ifndef Cache_h 26#define Cache_h 27 28#include "NativeImagePtr.h" 29#include "SecurityOriginHash.h" 30#include "SessionIDHash.h" 31#include <wtf/HashMap.h> 32#include <wtf/HashSet.h> 33#include <wtf/Noncopyable.h> 34#include <wtf/Vector.h> 35#include <wtf/text/StringHash.h> 36#include <wtf/text/WTFString.h> 37 38namespace WebCore { 39 40class CachedCSSStyleSheet; 41class CachedResource; 42class CachedResourceLoader; 43class URL; 44class ResourceRequest; 45class ResourceResponse; 46class ScriptExecutionContext; 47class SecurityOrigin; 48struct CrossThreadResourceRequestData; 49struct SecurityOriginHash; 50 51// This cache holds subresources used by Web pages: images, scripts, stylesheets, etc. 52 53// The cache keeps a flexible but bounded window of dead resources that grows/shrinks 54// depending on the live resource load. Here's an example of cache growth over time, 55// with a min dead resource capacity of 25% and a max dead resource capacity of 50%: 56 57// |-----| Dead: - 58// |----------| Live: + 59// --|----------| Cache boundary: | (objects outside this mark have been evicted) 60// --|----------++++++++++| 61// -------|-----+++++++++++++++| 62// -------|-----+++++++++++++++|+++++ 63 64// The behavior of the cache changes in the following way if shouldMakeResourcePurgeableOnEviction 65// returns true. 66// 67// 1. Dead resources in the cache are kept in non-purgeable memory. 68// 2. When we prune dead resources, instead of freeing them, we mark their memory as purgeable and 69// keep the resources until the kernel reclaims the purgeable memory. 70// 71// By leaving the in-cache dead resources in dirty resident memory, we decrease the likelihood of 72// the kernel claiming that memory and forcing us to refetch the resource (for example when a user 73// presses back). 74// 75// And by having an unbounded number of resource objects using purgeable memory, we can use as much 76// memory as is available on the machine. The trade-off here is that the CachedResource object (and 77// its member variables) are allocated in non-purgeable TC-malloc'd memory so we would see slightly 78// more memory use due to this. 79 80class MemoryCache { 81 WTF_MAKE_NONCOPYABLE(MemoryCache); WTF_MAKE_FAST_ALLOCATED; 82public: 83 friend MemoryCache* memoryCache(); 84 85#if ENABLE(CACHE_PARTITIONING) 86 typedef HashMap<String, CachedResource*> CachedResourceItem; 87 typedef HashMap<String, OwnPtr<CachedResourceItem>> CachedResourceMap; 88#else 89 typedef HashMap<String, CachedResource*> CachedResourceMap; 90#endif 91 typedef HashMap<SessionID, std::unique_ptr<CachedResourceMap>> SessionCachedResourceMap; 92 93 struct LRUList { 94 CachedResource* m_head; 95 CachedResource* m_tail; 96 LRUList() : m_head(0), m_tail(0) { } 97 }; 98 99 struct TypeStatistic { 100 int count; 101 int size; 102 int liveSize; 103 int decodedSize; 104 int purgeableSize; 105 int purgedSize; 106#if ENABLE(DISK_IMAGE_CACHE) 107 int mappedSize; 108 TypeStatistic() : count(0), size(0), liveSize(0), decodedSize(0), purgeableSize(0), purgedSize(0), mappedSize(0) { } 109#else 110 TypeStatistic() : count(0), size(0), liveSize(0), decodedSize(0), purgeableSize(0), purgedSize(0) { } 111#endif 112 void addResource(CachedResource*); 113 }; 114 115 struct Statistics { 116 TypeStatistic images; 117 TypeStatistic cssStyleSheets; 118 TypeStatistic scripts; 119 TypeStatistic xslStyleSheets; 120 TypeStatistic fonts; 121 }; 122 123 CachedResource* resourceForURL(const URL&); 124 CachedResource* resourceForURL(const URL&, SessionID); 125 CachedResource* resourceForRequest(const ResourceRequest&, SessionID); 126 127 bool add(CachedResource*); 128 void remove(CachedResource* resource) { evict(resource); } 129 130 static URL removeFragmentIdentifierIfNeeded(const URL& originalURL); 131 132 void revalidationSucceeded(CachedResource* revalidatingResource, const ResourceResponse&); 133 void revalidationFailed(CachedResource* revalidatingResource); 134 135 // Sets the cache's memory capacities, in bytes. These will hold only approximately, 136 // since the decoded cost of resources like scripts and stylesheets is not known. 137 // - minDeadBytes: The maximum number of bytes that dead resources should consume when the cache is under pressure. 138 // - maxDeadBytes: The maximum number of bytes that dead resources should consume when the cache is not under pressure. 139 // - totalBytes: The maximum number of bytes that the cache should consume overall. 140 void setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes); 141 142 // Turn the cache on and off. Disabling the cache will remove all resources from the cache. They may 143 // still live on if they are referenced by some Web page though. 144 void setDisabled(bool); 145 bool disabled() const { return m_disabled; } 146 147 void evictResources(); 148 149 void setPruneEnabled(bool enabled) { m_pruneEnabled = enabled; } 150 void prune(); 151 void pruneToPercentage(float targetPercentLive); 152 153 void setDeadDecodedDataDeletionInterval(std::chrono::milliseconds interval) { m_deadDecodedDataDeletionInterval = interval; } 154 std::chrono::milliseconds deadDecodedDataDeletionInterval() const { return m_deadDecodedDataDeletionInterval; } 155 156 // Calls to put the cached resource into and out of LRU lists. 157 void insertInLRUList(CachedResource*); 158 void removeFromLRUList(CachedResource*); 159 160 // Called to adjust the cache totals when a resource changes size. 161 void adjustSize(bool live, int delta); 162 163 // Track decoded resources that are in the cache and referenced by a Web page. 164 void insertInLiveDecodedResourcesList(CachedResource*); 165 void removeFromLiveDecodedResourcesList(CachedResource*); 166 167 void addToLiveResourcesSize(CachedResource*); 168 void removeFromLiveResourcesSize(CachedResource*); 169 170 static bool shouldMakeResourcePurgeableOnEviction(); 171 172#if ENABLE(DISK_IMAGE_CACHE) 173 void flushCachedImagesToDisk(); // Flush encoded data from resources still referenced by web pages. 174#endif 175 176 static void removeUrlFromCache(ScriptExecutionContext*, const String& urlString, SessionID); 177 static void removeRequestFromCache(ScriptExecutionContext*, const ResourceRequest&, SessionID); 178 static void removeRequestFromSessionCaches(ScriptExecutionContext*, const ResourceRequest&); 179 180 // Function to collect cache statistics for the caches window in the Safari Debug menu. 181 Statistics getStatistics(); 182 183 void resourceAccessed(CachedResource*); 184 185 typedef HashSet<RefPtr<SecurityOrigin>> SecurityOriginSet; 186 void removeResourcesWithOrigin(SecurityOrigin*); 187 void getOriginsWithCache(SecurityOriginSet& origins); 188 189 unsigned minDeadCapacity() const { return m_minDeadCapacity; } 190 unsigned maxDeadCapacity() const { return m_maxDeadCapacity; } 191 unsigned capacity() const { return m_capacity; } 192 unsigned liveSize() const { return m_liveSize; } 193 unsigned deadSize() const { return m_deadSize; } 194 195#if USE(CG) 196 // FIXME: Remove the USE(CG) once we either make NativeImagePtr a smart pointer on all platforms or 197 // remove the usage of CFRetain() in MemoryCache::addImageToCache() so as to make the code platform-independent. 198 bool addImageToCache(NativeImagePtr, const URL&, const String& cachePartition); 199 void removeImageFromCache(const URL&, const String& cachePartition); 200#endif 201 202 // pruneDead*() - Flush decoded and encoded data from resources not referenced by Web pages. 203 // pruneLive*() - Flush decoded data from resources still referenced by Web pages. 204 void pruneDeadResources(); // Automatically decide how much to prune. 205 void pruneLiveResources(bool shouldDestroyDecodedDataForAllLiveResources = false); 206 207private: 208 void pruneDeadResourcesToPercentage(float prunePercentage); // Prune to % current size 209 void pruneLiveResourcesToPercentage(float prunePercentage); 210 void pruneDeadResourcesToSize(unsigned targetSize); 211 void pruneLiveResourcesToSize(unsigned targetSize, bool shouldDestroyDecodedDataForAllLiveResources = false); 212 213 MemoryCache(); 214 ~MemoryCache(); // Not implemented to make sure nobody accidentally calls delete -- WebCore does not delete singletons. 215 216 LRUList* lruListFor(CachedResource*); 217#ifndef NDEBUG 218 void dumpStats(); 219 void dumpLRULists(bool includeLive) const; 220#endif 221 222 unsigned liveCapacity() const; 223 unsigned deadCapacity() const; 224 225 bool makeResourcePurgeable(CachedResource*); 226 void evict(CachedResource*); 227 228 CachedResource* resourceForRequestImpl(const ResourceRequest&, CachedResourceMap&); 229 static void removeRequestFromCacheImpl(ScriptExecutionContext*, const ResourceRequest&, SessionID); 230 static void removeRequestFromSessionCachesImpl(ScriptExecutionContext*, const ResourceRequest&); 231 static void crossThreadRemoveRequestFromCache(ScriptExecutionContext&, PassOwnPtr<CrossThreadResourceRequestData>, SessionID); 232 static void crossThreadRemoveRequestFromSessionCaches(ScriptExecutionContext&, PassOwnPtr<CrossThreadResourceRequestData>); 233 234 CachedResourceMap& getSessionMap(SessionID); 235 236 bool m_disabled; // Whether or not the cache is enabled. 237 bool m_pruneEnabled; 238 bool m_inPruneResources; 239 240 unsigned m_capacity; 241 unsigned m_minDeadCapacity; 242 unsigned m_maxDeadCapacity; 243 std::chrono::milliseconds m_deadDecodedDataDeletionInterval; 244 245 unsigned m_liveSize; // The number of bytes currently consumed by "live" resources in the cache. 246 unsigned m_deadSize; // The number of bytes currently consumed by "dead" resources in the cache. 247 248 // Size-adjusted and popularity-aware LRU list collection for cache objects. This collection can hold 249 // more resources than the cached resource map, since it can also hold "stale" multiple versions of objects that are 250 // waiting to die when the clients referencing them go away. 251 Vector<LRUList, 32> m_allResources; 252 253 // List just for live resources with decoded data. Access to this list is based off of painting the resource. 254 LRUList m_liveDecodedResources; 255 256 // A URL-based map of all resources that are in the cache (including the freshest version of objects that are currently being 257 // referenced by a Web page). 258 SessionCachedResourceMap m_sessionResources; 259}; 260 261inline bool MemoryCache::shouldMakeResourcePurgeableOnEviction() 262{ 263#if PLATFORM(IOS) 264 return true; 265#else 266 return false; 267#endif 268} 269 270// Function to obtain the global cache. 271MemoryCache* memoryCache(); 272 273} 274 275#endif 276