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