Home | History | Annotate | Download | only in fetch
      1 /*
      2     Copyright (C) 1998 Lars Knoll (knoll (at) mpi-hd.mpg.de)
      3     Copyright (C) 2001 Dirk Mueller <mueller (at) 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 MemoryCache_h
     26 #define MemoryCache_h
     27 
     28 #include "core/fetch/Resource.h"
     29 #include "core/fetch/ResourcePtr.h"
     30 #include "public/platform/WebThread.h"
     31 #include "wtf/HashMap.h"
     32 #include "wtf/Noncopyable.h"
     33 #include "wtf/Vector.h"
     34 #include "wtf/text/StringHash.h"
     35 #include "wtf/text/WTFString.h"
     36 
     37 namespace WebCore  {
     38 
     39 class CSSStyleSheetResource;
     40 class Resource;
     41 class ResourceFetcher;
     42 class KURL;
     43 class ExecutionContext;
     44 class SecurityOrigin;
     45 struct SecurityOriginHash;
     46 
     47 // This cache holds subresources used by Web pages: images, scripts, stylesheets, etc.
     48 
     49 // The cache keeps a flexible but bounded window of dead resources that grows/shrinks
     50 // depending on the live resource load. Here's an example of cache growth over time,
     51 // with a min dead resource capacity of 25% and a max dead resource capacity of 50%:
     52 
     53 //        |-----|                              Dead: -
     54 //        |----------|                         Live: +
     55 //      --|----------|                         Cache boundary: | (objects outside this mark have been evicted)
     56 //      --|----------++++++++++|
     57 // -------|-----+++++++++++++++|
     58 // -------|-----+++++++++++++++|+++++
     59 
     60 // Enable this macro to periodically log information about the memory cache.
     61 #undef MEMORY_CACHE_STATS
     62 
     63 // Determines the order in which CachedResources are evicted
     64 // from the decoded resources cache.
     65 enum MemoryCacheLiveResourcePriority {
     66     MemoryCacheLiveResourcePriorityLow = 0,
     67     MemoryCacheLiveResourcePriorityHigh,
     68     MemoryCacheLiveResourcePriorityUnknown
     69 };
     70 
     71 enum UpdateReason {
     72     UpdateForAccess,
     73     UpdateForPropertyChange
     74 };
     75 
     76 class MemoryCache FINAL : public blink::WebThread::TaskObserver {
     77     WTF_MAKE_NONCOPYABLE(MemoryCache); WTF_MAKE_FAST_ALLOCATED;
     78 public:
     79     MemoryCache();
     80     virtual ~MemoryCache();
     81 
     82     class MemoryCacheEntry {
     83     public:
     84         static PassOwnPtr<MemoryCacheEntry> create(Resource* resource) { return adoptPtr(new MemoryCacheEntry(resource)); }
     85 
     86         ResourcePtr<Resource> m_resource;
     87         bool m_inLiveDecodedResourcesList;
     88         unsigned m_accessCount;
     89         MemoryCacheLiveResourcePriority m_liveResourcePriority;
     90         double m_lastDecodedAccessTime; // Used as a thrash guard
     91 
     92         MemoryCacheEntry* m_previousInLiveResourcesList;
     93         MemoryCacheEntry* m_nextInLiveResourcesList;
     94         MemoryCacheEntry* m_previousInAllResourcesList;
     95         MemoryCacheEntry* m_nextInAllResourcesList;
     96 
     97     private:
     98         MemoryCacheEntry(Resource* resource)
     99             : m_resource(resource)
    100             , m_inLiveDecodedResourcesList(false)
    101             , m_accessCount(0)
    102             , m_liveResourcePriority(MemoryCacheLiveResourcePriorityLow)
    103             , m_lastDecodedAccessTime(0.0)
    104             , m_previousInLiveResourcesList(0)
    105             , m_nextInLiveResourcesList(0)
    106             , m_previousInAllResourcesList(0)
    107             , m_nextInAllResourcesList(0)
    108         {
    109         }
    110     };
    111 
    112     struct LRUList {
    113         MemoryCacheEntry* m_head;
    114         MemoryCacheEntry* m_tail;
    115         LRUList() : m_head(0), m_tail(0) { }
    116     };
    117 
    118     struct TypeStatistic {
    119         int count;
    120         int size;
    121         int liveSize;
    122         int decodedSize;
    123         int encodedSize;
    124         int encodedSizeDuplicatedInDataURLs;
    125         int purgeableSize;
    126         int purgedSize;
    127 
    128         TypeStatistic()
    129             : count(0)
    130             , size(0)
    131             , liveSize(0)
    132             , decodedSize(0)
    133             , encodedSize(0)
    134             , encodedSizeDuplicatedInDataURLs(0)
    135             , purgeableSize(0)
    136             , purgedSize(0)
    137         {
    138         }
    139 
    140         void addResource(Resource*);
    141     };
    142 
    143     struct Statistics {
    144         TypeStatistic images;
    145         TypeStatistic cssStyleSheets;
    146         TypeStatistic scripts;
    147         TypeStatistic xslStyleSheets;
    148         TypeStatistic fonts;
    149         TypeStatistic other;
    150     };
    151 
    152     Resource* resourceForURL(const KURL&);
    153 
    154     void add(Resource*);
    155     void replace(Resource* newResource, Resource* oldResource);
    156     void remove(Resource*);
    157     bool contains(const Resource*) const;
    158 
    159     static KURL removeFragmentIdentifierIfNeeded(const KURL& originalURL);
    160 
    161     // Sets the cache's memory capacities, in bytes. These will hold only approximately,
    162     // since the decoded cost of resources like scripts and stylesheets is not known.
    163     //  - minDeadBytes: The maximum number of bytes that dead resources should consume when the cache is under pressure.
    164     //  - maxDeadBytes: The maximum number of bytes that dead resources should consume when the cache is not under pressure.
    165     //  - totalBytes: The maximum number of bytes that the cache should consume overall.
    166     void setCapacities(size_t minDeadBytes, size_t maxDeadBytes, size_t totalBytes);
    167     void setDelayBeforeLiveDecodedPrune(double seconds) { m_delayBeforeLiveDecodedPrune = seconds; }
    168     void setMaxPruneDeferralDelay(double seconds) { m_maxPruneDeferralDelay = seconds; }
    169 
    170     void evictResources();
    171 
    172     void prune(Resource* justReleasedResource = 0);
    173 
    174     // Called to adjust a resource's size, lru list position, and access count.
    175     void update(Resource*, size_t oldSize, size_t newSize, bool wasAccessed = false);
    176     void updateForAccess(Resource* resource) { update(resource, resource->size(), resource->size(), true); }
    177     void updateDecodedResource(Resource*, UpdateReason, MemoryCacheLiveResourcePriority = MemoryCacheLiveResourcePriorityUnknown);
    178 
    179     void makeLive(Resource*);
    180     void makeDead(Resource*);
    181 
    182     static void removeURLFromCache(ExecutionContext*, const KURL&);
    183 
    184     Statistics getStatistics();
    185 
    186     size_t minDeadCapacity() const { return m_minDeadCapacity; }
    187     size_t maxDeadCapacity() const { return m_maxDeadCapacity; }
    188     size_t capacity() const { return m_capacity; }
    189     size_t liveSize() const { return m_liveSize; }
    190     size_t deadSize() const { return m_deadSize; }
    191 
    192     // Exposed for testing
    193     MemoryCacheLiveResourcePriority priority(Resource*) const;
    194 
    195     // TaskObserver implementation
    196     virtual void willProcessTask() OVERRIDE;
    197     virtual void didProcessTask() OVERRIDE;
    198 
    199 private:
    200     LRUList* lruListFor(unsigned accessCount, size_t);
    201 
    202 #ifdef MEMORY_CACHE_STATS
    203     void dumpStats(Timer<MemoryCache>*);
    204     void dumpLRULists(bool includeLive) const;
    205 #endif
    206 
    207     // Calls to put the cached resource into and out of LRU lists.
    208     void insertInLRUList(MemoryCacheEntry*, LRUList*);
    209     void removeFromLRUList(MemoryCacheEntry*, LRUList*);
    210 
    211     // Track decoded resources that are in the cache and referenced by a Web page.
    212     void insertInLiveDecodedResourcesList(MemoryCacheEntry*);
    213     void removeFromLiveDecodedResourcesList(MemoryCacheEntry*);
    214 
    215     size_t liveCapacity() const;
    216     size_t deadCapacity() const;
    217 
    218     // pruneDeadResources() - Flush decoded and encoded data from resources not referenced by Web pages.
    219     // pruneLiveResources() - Flush decoded data from resources still referenced by Web pages.
    220     void pruneDeadResources(); // Automatically decide how much to prune.
    221     void pruneLiveResources();
    222     void pruneNow(double currentTime);
    223 
    224     bool evict(MemoryCacheEntry*);
    225 
    226     static void removeURLFromCacheInternal(ExecutionContext*, const KURL&);
    227 
    228     bool m_inPruneResources;
    229     bool m_prunePending;
    230     double m_maxPruneDeferralDelay;
    231     double m_pruneTimeStamp;
    232     double m_pruneFrameTimeStamp;
    233 
    234     size_t m_capacity;
    235     size_t m_minDeadCapacity;
    236     size_t m_maxDeadCapacity;
    237     size_t m_maxDeferredPruneDeadCapacity;
    238     double m_delayBeforeLiveDecodedPrune;
    239 
    240     size_t m_liveSize; // The number of bytes currently consumed by "live" resources in the cache.
    241     size_t m_deadSize; // The number of bytes currently consumed by "dead" resources in the cache.
    242 
    243     // Size-adjusted and popularity-aware LRU list collection for cache objects. This collection can hold
    244     // more resources than the cached resource map, since it can also hold "stale" multiple versions of objects that are
    245     // waiting to die when the clients referencing them go away.
    246     Vector<LRUList, 32> m_allResources;
    247 
    248     // Lists just for live resources with decoded data. Access to this list is based off of painting the resource.
    249     // The lists are ordered by decode priority, with higher indices having higher priorities.
    250     LRUList m_liveDecodedResources[MemoryCacheLiveResourcePriorityHigh + 1];
    251 
    252     // A URL-based map of all resources that are in the cache (including the freshest version of objects that are currently being
    253     // referenced by a Web page).
    254     typedef HashMap<String, OwnPtr<MemoryCacheEntry> > ResourceMap;
    255     ResourceMap m_resources;
    256 
    257     friend class MemoryCacheTest;
    258 #ifdef MEMORY_CACHE_STATS
    259     Timer<MemoryCache> m_statsTimer;
    260 #endif
    261 };
    262 
    263 // Returns the global cache.
    264 MemoryCache* memoryCache();
    265 
    266 // Sets the global cache, used to swap in a test instance.
    267 void setMemoryCacheForTesting(MemoryCache*);
    268 
    269 }
    270 
    271 #endif
    272