1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
|
/*
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
This class provides all functionality needed for loading images, style sheets and html
pages from the web. It has a memory cache for these objects.
*/
#ifndef MemoryCache_h
#define MemoryCache_h
#include "core/fetch/Resource.h"
#include "core/fetch/ResourcePtr.h"
#include "public/platform/WebThread.h"
#include "wtf/HashMap.h"
#include "wtf/Noncopyable.h"
#include "wtf/Vector.h"
#include "wtf/text/StringHash.h"
#include "wtf/text/WTFString.h"
namespace blink {
class Resource;
class KURL;
class ExecutionContext;
// This cache holds subresources used by Web pages: images, scripts, stylesheets, etc.
// The cache keeps a flexible but bounded window of dead resources that grows/shrinks
// depending on the live resource load. Here's an example of cache growth over time,
// with a min dead resource capacity of 25% and a max dead resource capacity of 50%:
// |-----| Dead: -
// |----------| Live: +
// --|----------| Cache boundary: | (objects outside this mark have been evicted)
// --|----------++++++++++|
// -------|-----+++++++++++++++|
// -------|-----+++++++++++++++|+++++
// Enable this macro to periodically log information about the memory cache.
#undef MEMORY_CACHE_STATS
// Determines the order in which CachedResources are evicted
// from the decoded resources cache.
enum MemoryCacheLiveResourcePriority {
MemoryCacheLiveResourcePriorityLow = 0,
MemoryCacheLiveResourcePriorityHigh,
MemoryCacheLiveResourcePriorityUnknown
};
enum UpdateReason {
UpdateForAccess,
UpdateForPropertyChange
};
// MemoryCacheEntry class is used only in MemoryCache class, but we don't make
// MemoryCacheEntry class an inner class of MemoryCache because of dependency
// from MemoryCacheLRUList.
class MemoryCacheEntry final : public NoBaseWillBeGarbageCollectedFinalized<MemoryCacheEntry> {
public:
static PassOwnPtrWillBeRawPtr<MemoryCacheEntry> create(Resource* resource)
{
return adoptPtrWillBeNoop(new MemoryCacheEntry(resource));
}
void trace(Visitor*);
#if ENABLE(OILPAN)
void dispose();
#endif
ResourcePtr<Resource> m_resource;
bool m_inLiveDecodedResourcesList;
unsigned m_accessCount;
MemoryCacheLiveResourcePriority m_liveResourcePriority;
double m_lastDecodedAccessTime; // Used as a thrash guard
RawPtrWillBeMember<MemoryCacheEntry> m_previousInLiveResourcesList;
RawPtrWillBeMember<MemoryCacheEntry> m_nextInLiveResourcesList;
RawPtrWillBeMember<MemoryCacheEntry> m_previousInAllResourcesList;
RawPtrWillBeMember<MemoryCacheEntry> m_nextInAllResourcesList;
private:
explicit MemoryCacheEntry(Resource* resource)
: m_resource(resource)
, m_inLiveDecodedResourcesList(false)
, m_accessCount(0)
, m_liveResourcePriority(MemoryCacheLiveResourcePriorityLow)
, m_lastDecodedAccessTime(0.0)
, m_previousInLiveResourcesList(nullptr)
, m_nextInLiveResourcesList(nullptr)
, m_previousInAllResourcesList(nullptr)
, m_nextInAllResourcesList(nullptr)
{
}
};
WILL_NOT_BE_EAGERLY_TRACED_CLASS(MemoryCacheEntry);
// MemoryCacheLRUList is used only in MemoryCache class, but we don't make
// MemoryCacheLRUList an inner struct of MemoryCache because we can't define
// VectorTraits for inner structs.
struct MemoryCacheLRUList final {
ALLOW_ONLY_INLINE_ALLOCATION();
public:
RawPtrWillBeMember<MemoryCacheEntry> m_head;
RawPtrWillBeMember<MemoryCacheEntry> m_tail;
MemoryCacheLRUList() : m_head(nullptr), m_tail(nullptr) { }
void trace(Visitor*);
};
}
WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::MemoryCacheLRUList);
namespace blink {
class MemoryCache final : public NoBaseWillBeGarbageCollectedFinalized<MemoryCache>, public WebThread::TaskObserver {
WTF_MAKE_NONCOPYABLE(MemoryCache); WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
public:
static PassOwnPtrWillBeRawPtr<MemoryCache> create();
~MemoryCache();
void trace(Visitor*);
struct TypeStatistic {
int count;
int size;
int liveSize;
int decodedSize;
int encodedSize;
int encodedSizeDuplicatedInDataURLs;
int purgeableSize;
int purgedSize;
TypeStatistic()
: count(0)
, size(0)
, liveSize(0)
, decodedSize(0)
, encodedSize(0)
, encodedSizeDuplicatedInDataURLs(0)
, purgeableSize(0)
, purgedSize(0)
{
}
void addResource(Resource*);
};
struct Statistics {
TypeStatistic images;
TypeStatistic cssStyleSheets;
TypeStatistic scripts;
TypeStatistic xslStyleSheets;
TypeStatistic fonts;
TypeStatistic other;
};
Resource* resourceForURL(const KURL&);
Resource* resourceForURL(const KURL&, const String& cacheIdentifier);
WillBeHeapVector<Member<Resource>> resourcesForURL(const KURL&);
void add(Resource*);
void replace(Resource* newResource, Resource* oldResource);
void remove(Resource*);
bool contains(const Resource*) const;
static KURL removeFragmentIdentifierIfNeeded(const KURL& originalURL);
static String defaultCacheIdentifier();
// Sets the cache's memory capacities, in bytes. These will hold only approximately,
// since the decoded cost of resources like scripts and stylesheets is not known.
// - minDeadBytes: The maximum number of bytes that dead resources should consume when the cache is under pressure.
// - maxDeadBytes: The maximum number of bytes that dead resources should consume when the cache is not under pressure.
// - totalBytes: The maximum number of bytes that the cache should consume overall.
void setCapacities(size_t minDeadBytes, size_t maxDeadBytes, size_t totalBytes);
void setDelayBeforeLiveDecodedPrune(double seconds) { m_delayBeforeLiveDecodedPrune = seconds; }
void setMaxPruneDeferralDelay(double seconds) { m_maxPruneDeferralDelay = seconds; }
void evictResources();
void prune(Resource* justReleasedResource = 0);
// Called to adjust a resource's size, lru list position, and access count.
void update(Resource*, size_t oldSize, size_t newSize, bool wasAccessed = false);
void updateForAccess(Resource* resource) { update(resource, resource->size(), resource->size(), true); }
void updateDecodedResource(Resource*, UpdateReason, MemoryCacheLiveResourcePriority = MemoryCacheLiveResourcePriorityUnknown);
void makeLive(Resource*);
void makeDead(Resource*);
// This should be called when a Resource object is created.
void registerLiveResource(Resource&);
// This should be called when a Resource object becomes unnecesarry.
void unregisterLiveResource(Resource&);
static void removeURLFromCache(ExecutionContext*, const KURL&);
Statistics getStatistics();
size_t minDeadCapacity() const { return m_minDeadCapacity; }
size_t maxDeadCapacity() const { return m_maxDeadCapacity; }
size_t capacity() const { return m_capacity; }
size_t liveSize() const { return m_liveSize; }
size_t deadSize() const { return m_deadSize; }
// Exposed for testing
MemoryCacheLiveResourcePriority priority(Resource*) const;
// TaskObserver implementation
virtual void willProcessTask() override;
virtual void didProcessTask() override;
void pruneAll();
private:
enum PruneStrategy {
// Automatically decide how much to prune.
AutomaticPrune,
// Maximally prune resources.
MaximalPrune
};
MemoryCache();
MemoryCacheLRUList* lruListFor(unsigned accessCount, size_t);
#ifdef MEMORY_CACHE_STATS
void dumpStats(Timer<MemoryCache>*);
void dumpLRULists(bool includeLive) const;
#endif
// Calls to put the cached resource into and out of LRU lists.
void insertInLRUList(MemoryCacheEntry*, MemoryCacheLRUList*);
void removeFromLRUList(MemoryCacheEntry*, MemoryCacheLRUList*);
bool containedInLRUList(MemoryCacheEntry*, MemoryCacheLRUList*);
// Track decoded resources that are in the cache and referenced by a Web page.
void insertInLiveDecodedResourcesList(MemoryCacheEntry*);
void removeFromLiveDecodedResourcesList(MemoryCacheEntry*);
bool containedInLiveDecodedResourcesList(MemoryCacheEntry*);
size_t liveCapacity() const;
size_t deadCapacity() const;
// pruneDeadResources() - Flush decoded and encoded data from resources not referenced by Web pages.
// pruneLiveResources() - Flush decoded data from resources still referenced by Web pages.
void pruneDeadResources(PruneStrategy);
void pruneLiveResources(PruneStrategy);
void pruneNow(double currentTime, PruneStrategy);
bool evict(MemoryCacheEntry*);
MemoryCacheEntry* getEntryForResource(const Resource*) const;
static void removeURLFromCacheInternal(ExecutionContext*, const KURL&);
bool m_inPruneResources;
bool m_prunePending;
double m_maxPruneDeferralDelay;
double m_pruneTimeStamp;
double m_pruneFrameTimeStamp;
size_t m_capacity;
size_t m_minDeadCapacity;
size_t m_maxDeadCapacity;
size_t m_maxDeferredPruneDeadCapacity;
double m_delayBeforeLiveDecodedPrune;
size_t m_liveSize; // The number of bytes currently consumed by "live" resources in the cache.
size_t m_deadSize; // The number of bytes currently consumed by "dead" resources in the cache.
// Size-adjusted and popularity-aware LRU list collection for cache objects. This collection can hold
// more resources than the cached resource map, since it can also hold "stale" multiple versions of objects that are
// waiting to die when the clients referencing them go away.
WillBeHeapVector<MemoryCacheLRUList, 32> m_allResources;
// Lists just for live resources with decoded data. Access to this list is based off of painting the resource.
// The lists are ordered by decode priority, with higher indices having higher priorities.
MemoryCacheLRUList m_liveDecodedResources[MemoryCacheLiveResourcePriorityHigh + 1];
// A URL-based map of all resources that are in the cache (including the freshest version of objects that are currently being
// referenced by a Web page).
using ResourceMap = WillBeHeapHashMap<String, OwnPtrWillBeMember<MemoryCacheEntry>>;
using ResourceMapIndex = WillBeHeapHashMap<String, OwnPtrWillBeMember<ResourceMap>>;
ResourceMap* ensureResourceMap(const String& cacheIdentifier);
ResourceMapIndex m_resourceMaps;
#if ENABLE(OILPAN)
// Unlike m_allResources, m_liveResources is a set of Resource objects which
// should not be deleted. m_allResources only contains on-cache Resource
// objects.
// FIXME: Can we remove manual lifetime management of Resource and this?
HeapHashSet<Member<Resource>> m_liveResources;
friend RawPtr<MemoryCache> replaceMemoryCacheForTesting(RawPtr<MemoryCache>);
#endif
friend class MemoryCacheTest;
#ifdef MEMORY_CACHE_STATS
Timer<MemoryCache> m_statsTimer;
#endif
};
// Returns the global cache.
MemoryCache* memoryCache();
// Sets the global cache, used to swap in a test instance. Returns the old
// MemoryCache object.
PassOwnPtrWillBeRawPtr<MemoryCache> replaceMemoryCacheForTesting(PassOwnPtrWillBeRawPtr<MemoryCache>);
}
#endif
|