| Index: third_party/WebKit/Source/core/fetch/MemoryCache.cpp
|
| diff --git a/third_party/WebKit/Source/core/fetch/MemoryCache.cpp b/third_party/WebKit/Source/core/fetch/MemoryCache.cpp
|
| deleted file mode 100644
|
| index d1205da9f06e5047b5c981bad2ebee40a0b58212..0000000000000000000000000000000000000000
|
| --- a/third_party/WebKit/Source/core/fetch/MemoryCache.cpp
|
| +++ /dev/null
|
| @@ -1,467 +0,0 @@
|
| -/*
|
| - Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
|
| - Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
|
| - Copyright (C) 2002 Waldo Bastian (bastian@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.
|
| -*/
|
| -
|
| -#include "core/fetch/MemoryCache.h"
|
| -
|
| -#include "core/fetch/ResourceLoadingLog.h"
|
| -#include "platform/instrumentation/tracing/TraceEvent.h"
|
| -#include "platform/weborigin/SecurityOrigin.h"
|
| -#include "platform/weborigin/SecurityOriginHash.h"
|
| -#include "public/platform/Platform.h"
|
| -#include "wtf/Assertions.h"
|
| -#include "wtf/AutoReset.h"
|
| -#include "wtf/CurrentTime.h"
|
| -#include "wtf/MathExtras.h"
|
| -#include "wtf/text/CString.h"
|
| -
|
| -namespace blink {
|
| -
|
| -static Persistent<MemoryCache>* gMemoryCache;
|
| -
|
| -static const unsigned cDefaultCacheCapacity = 8192 * 1024;
|
| -static const int cMinDelayBeforeLiveDecodedPrune = 1; // Seconds.
|
| -static const double cMaxPruneDeferralDelay = 0.5; // Seconds.
|
| -
|
| -// Percentage of capacity toward which we prune, to avoid immediately pruning
|
| -// again.
|
| -static const float cTargetPrunePercentage = .95f;
|
| -
|
| -MemoryCache* memoryCache() {
|
| - DCHECK(WTF::isMainThread());
|
| - if (!gMemoryCache)
|
| - gMemoryCache = new Persistent<MemoryCache>(MemoryCache::create());
|
| - return gMemoryCache->get();
|
| -}
|
| -
|
| -MemoryCache* replaceMemoryCacheForTesting(MemoryCache* cache) {
|
| - memoryCache();
|
| - MemoryCache* oldCache = gMemoryCache->release();
|
| - *gMemoryCache = cache;
|
| - MemoryCacheDumpProvider::instance()->setMemoryCache(cache);
|
| - return oldCache;
|
| -}
|
| -
|
| -DEFINE_TRACE(MemoryCacheEntry) {
|
| - visitor->template registerWeakMembers<MemoryCacheEntry,
|
| - &MemoryCacheEntry::clearResourceWeak>(
|
| - this);
|
| -}
|
| -
|
| -void MemoryCacheEntry::clearResourceWeak(Visitor* visitor) {
|
| - if (!m_resource || ThreadHeap::isHeapObjectAlive(m_resource))
|
| - return;
|
| - memoryCache()->remove(m_resource.get());
|
| - m_resource.clear();
|
| -}
|
| -
|
| -inline MemoryCache::MemoryCache()
|
| - : m_inPruneResources(false),
|
| - m_prunePending(false),
|
| - m_maxPruneDeferralDelay(cMaxPruneDeferralDelay),
|
| - m_pruneTimeStamp(0.0),
|
| - m_pruneFrameTimeStamp(0.0),
|
| - m_lastFramePaintTimeStamp(0.0),
|
| - m_capacity(cDefaultCacheCapacity),
|
| - m_delayBeforeLiveDecodedPrune(cMinDelayBeforeLiveDecodedPrune),
|
| - m_size(0) {
|
| - MemoryCacheDumpProvider::instance()->setMemoryCache(this);
|
| - if (MemoryCoordinator::isLowEndDevice())
|
| - MemoryCoordinator::instance().registerClient(this);
|
| -}
|
| -
|
| -MemoryCache* MemoryCache::create() {
|
| - return new MemoryCache;
|
| -}
|
| -
|
| -MemoryCache::~MemoryCache() {
|
| - if (m_prunePending)
|
| - Platform::current()->currentThread()->removeTaskObserver(this);
|
| -}
|
| -
|
| -DEFINE_TRACE(MemoryCache) {
|
| - visitor->trace(m_resourceMaps);
|
| - MemoryCacheDumpClient::trace(visitor);
|
| - MemoryCoordinatorClient::trace(visitor);
|
| -}
|
| -
|
| -KURL MemoryCache::removeFragmentIdentifierIfNeeded(const KURL& originalURL) {
|
| - if (!originalURL.hasFragmentIdentifier())
|
| - return originalURL;
|
| - // Strip away fragment identifier from HTTP URLs. Data URLs must be
|
| - // unmodified. For file and custom URLs clients may expect resources to be
|
| - // unique even when they differ by the fragment identifier only.
|
| - if (!originalURL.protocolIsInHTTPFamily())
|
| - return originalURL;
|
| - KURL url = originalURL;
|
| - url.removeFragmentIdentifier();
|
| - return url;
|
| -}
|
| -
|
| -String MemoryCache::defaultCacheIdentifier() {
|
| - return emptyString();
|
| -}
|
| -
|
| -MemoryCache::ResourceMap* MemoryCache::ensureResourceMap(
|
| - const String& cacheIdentifier) {
|
| - if (!m_resourceMaps.contains(cacheIdentifier)) {
|
| - ResourceMapIndex::AddResult result =
|
| - m_resourceMaps.add(cacheIdentifier, new ResourceMap);
|
| - CHECK(result.isNewEntry);
|
| - }
|
| - return m_resourceMaps.get(cacheIdentifier);
|
| -}
|
| -
|
| -void MemoryCache::add(Resource* resource) {
|
| - DCHECK(resource);
|
| - ResourceMap* resources = ensureResourceMap(resource->cacheIdentifier());
|
| - addInternal(resources, MemoryCacheEntry::create(resource));
|
| - RESOURCE_LOADING_DVLOG(1) << "MemoryCache::add Added "
|
| - << resource->url().getString() << ", resource "
|
| - << resource;
|
| -}
|
| -
|
| -void MemoryCache::addInternal(ResourceMap* resourceMap,
|
| - MemoryCacheEntry* entry) {
|
| - DCHECK(WTF::isMainThread());
|
| - DCHECK(resourceMap);
|
| -
|
| - Resource* resource = entry->resource();
|
| - if (!resource)
|
| - return;
|
| - DCHECK(resource->url().isValid());
|
| -
|
| - KURL url = removeFragmentIdentifierIfNeeded(resource->url());
|
| - ResourceMap::iterator it = resourceMap->find(url);
|
| - if (it != resourceMap->end()) {
|
| - Resource* oldResource = it->value->resource();
|
| - CHECK_NE(oldResource, resource);
|
| - update(oldResource, oldResource->size(), 0);
|
| - }
|
| - resourceMap->set(url, entry);
|
| - update(resource, 0, resource->size());
|
| -}
|
| -
|
| -void MemoryCache::remove(Resource* resource) {
|
| - DCHECK(WTF::isMainThread());
|
| - DCHECK(resource);
|
| - RESOURCE_LOADING_DVLOG(1) << "Evicting resource " << resource << " for "
|
| - << resource->url().getString() << " from cache";
|
| - TRACE_EVENT1("blink", "MemoryCache::evict", "resource",
|
| - resource->url().getString().utf8());
|
| -
|
| - ResourceMap* resources = m_resourceMaps.get(resource->cacheIdentifier());
|
| - if (!resources)
|
| - return;
|
| -
|
| - KURL url = removeFragmentIdentifierIfNeeded(resource->url());
|
| - ResourceMap::iterator it = resources->find(url);
|
| - if (it == resources->end() || it->value->resource() != resource)
|
| - return;
|
| - removeInternal(resources, it);
|
| -}
|
| -
|
| -void MemoryCache::removeInternal(ResourceMap* resourceMap,
|
| - const ResourceMap::iterator& it) {
|
| - DCHECK(WTF::isMainThread());
|
| - DCHECK(resourceMap);
|
| -
|
| - Resource* resource = it->value->resource();
|
| - DCHECK(resource);
|
| -
|
| - update(resource, resource->size(), 0);
|
| - resourceMap->remove(it);
|
| -}
|
| -
|
| -bool MemoryCache::contains(const Resource* resource) const {
|
| - if (!resource || resource->url().isEmpty())
|
| - return false;
|
| - const ResourceMap* resources =
|
| - m_resourceMaps.get(resource->cacheIdentifier());
|
| - if (!resources)
|
| - return false;
|
| - KURL url = removeFragmentIdentifierIfNeeded(resource->url());
|
| - MemoryCacheEntry* entry = resources->get(url);
|
| - return entry && resource == entry->resource();
|
| -}
|
| -
|
| -Resource* MemoryCache::resourceForURL(const KURL& resourceURL) const {
|
| - return resourceForURL(resourceURL, defaultCacheIdentifier());
|
| -}
|
| -
|
| -Resource* MemoryCache::resourceForURL(const KURL& resourceURL,
|
| - const String& cacheIdentifier) const {
|
| - DCHECK(WTF::isMainThread());
|
| - if (!resourceURL.isValid() || resourceURL.isNull())
|
| - return nullptr;
|
| - DCHECK(!cacheIdentifier.isNull());
|
| - const ResourceMap* resources = m_resourceMaps.get(cacheIdentifier);
|
| - if (!resources)
|
| - return nullptr;
|
| - MemoryCacheEntry* entry =
|
| - resources->get(removeFragmentIdentifierIfNeeded(resourceURL));
|
| - if (!entry)
|
| - return nullptr;
|
| - return entry->resource();
|
| -}
|
| -
|
| -HeapVector<Member<Resource>> MemoryCache::resourcesForURL(
|
| - const KURL& resourceURL) const {
|
| - DCHECK(WTF::isMainThread());
|
| - KURL url = removeFragmentIdentifierIfNeeded(resourceURL);
|
| - HeapVector<Member<Resource>> results;
|
| - for (const auto& resourceMapIter : m_resourceMaps) {
|
| - if (MemoryCacheEntry* entry = resourceMapIter.value->get(url)) {
|
| - Resource* resource = entry->resource();
|
| - DCHECK(resource);
|
| - results.push_back(resource);
|
| - }
|
| - }
|
| - return results;
|
| -}
|
| -
|
| -void MemoryCache::pruneResources(PruneStrategy strategy) {
|
| - DCHECK(!m_prunePending);
|
| - const size_t sizeLimit = (strategy == MaximalPrune) ? 0 : capacity();
|
| - if (m_size <= sizeLimit)
|
| - return;
|
| -
|
| - // Cut by a percentage to avoid immediately pruning again.
|
| - size_t targetSize = static_cast<size_t>(sizeLimit * cTargetPrunePercentage);
|
| -
|
| - for (const auto& resourceMapIter : m_resourceMaps) {
|
| - for (const auto& resourceIter : *resourceMapIter.value) {
|
| - Resource* resource = resourceIter.value->resource();
|
| - DCHECK(resource);
|
| - if (resource->isLoaded() && resource->decodedSize()) {
|
| - // Check to see if the remaining resources are too new to prune.
|
| - double elapsedTime =
|
| - m_pruneFrameTimeStamp - resourceIter.value->m_lastDecodedAccessTime;
|
| - if (strategy == AutomaticPrune &&
|
| - elapsedTime < m_delayBeforeLiveDecodedPrune)
|
| - continue;
|
| - resource->prune();
|
| - if (m_size <= targetSize)
|
| - return;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -void MemoryCache::setCapacity(size_t totalBytes) {
|
| - m_capacity = totalBytes;
|
| - prune();
|
| -}
|
| -
|
| -void MemoryCache::update(Resource* resource, size_t oldSize, size_t newSize) {
|
| - if (!contains(resource))
|
| - return;
|
| - ptrdiff_t delta = newSize - oldSize;
|
| - DCHECK(delta >= 0 || m_size >= static_cast<size_t>(-delta));
|
| - m_size += delta;
|
| -}
|
| -
|
| -void MemoryCache::removeURLFromCache(const KURL& url) {
|
| - HeapVector<Member<Resource>> resources = resourcesForURL(url);
|
| - for (Resource* resource : resources)
|
| - remove(resource);
|
| -}
|
| -
|
| -void MemoryCache::TypeStatistic::addResource(Resource* o) {
|
| - count++;
|
| - size += o->size();
|
| - decodedSize += o->decodedSize();
|
| - encodedSize += o->encodedSize();
|
| - overheadSize += o->overheadSize();
|
| - encodedSizeDuplicatedInDataURLs +=
|
| - o->url().protocolIsData() ? o->encodedSize() : 0;
|
| -}
|
| -
|
| -MemoryCache::Statistics MemoryCache::getStatistics() const {
|
| - Statistics stats;
|
| - for (const auto& resourceMapIter : m_resourceMaps) {
|
| - for (const auto& resourceIter : *resourceMapIter.value) {
|
| - Resource* resource = resourceIter.value->resource();
|
| - DCHECK(resource);
|
| - switch (resource->getType()) {
|
| - case Resource::Image:
|
| - stats.images.addResource(resource);
|
| - break;
|
| - case Resource::CSSStyleSheet:
|
| - stats.cssStyleSheets.addResource(resource);
|
| - break;
|
| - case Resource::Script:
|
| - stats.scripts.addResource(resource);
|
| - break;
|
| - case Resource::XSLStyleSheet:
|
| - stats.xslStyleSheets.addResource(resource);
|
| - break;
|
| - case Resource::Font:
|
| - stats.fonts.addResource(resource);
|
| - break;
|
| - default:
|
| - stats.other.addResource(resource);
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - return stats;
|
| -}
|
| -
|
| -void MemoryCache::evictResources(EvictResourcePolicy policy) {
|
| - for (auto resourceMapIter = m_resourceMaps.begin();
|
| - resourceMapIter != m_resourceMaps.end();) {
|
| - ResourceMap* resources = resourceMapIter->value.get();
|
| - HeapVector<Member<MemoryCacheEntry>> unusedPreloads;
|
| - for (auto resourceIter = resources->begin();
|
| - resourceIter != resources->end(); resourceIter = resources->begin()) {
|
| - DCHECK(resourceIter.get());
|
| - DCHECK(resourceIter->value.get());
|
| - DCHECK(resourceIter->value->resource());
|
| - Resource* resource = resourceIter->value->resource();
|
| - DCHECK(resource);
|
| - if (policy != EvictAllResources && resource->isUnusedPreload()) {
|
| - // Store unused preloads aside, so they could be added back later.
|
| - // That is in order to avoid the performance impact of iterating over
|
| - // the same resource multiple times.
|
| - unusedPreloads.push_back(resourceIter->value.get());
|
| - }
|
| - removeInternal(resources, resourceIter);
|
| - }
|
| - for (const auto& unusedPreload : unusedPreloads) {
|
| - addInternal(resources, unusedPreload);
|
| - }
|
| - // We may iterate multiple times over resourceMaps with unused preloads.
|
| - // That's extremely unlikely to have any real-life performance impact.
|
| - if (!resources->size()) {
|
| - m_resourceMaps.remove(resourceMapIter);
|
| - resourceMapIter = m_resourceMaps.begin();
|
| - } else {
|
| - ++resourceMapIter;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void MemoryCache::prune() {
|
| - TRACE_EVENT0("renderer", "MemoryCache::prune()");
|
| -
|
| - if (m_inPruneResources)
|
| - return;
|
| - if (m_size <= m_capacity) // Fast path.
|
| - return;
|
| -
|
| - // To avoid burdening the current thread with repetitive pruning jobs, pruning
|
| - // is postponed until the end of the current task. If it has been more than
|
| - // m_maxPruneDeferralDelay since the last prune, then we prune immediately. If
|
| - // the current thread's run loop is not active, then pruning will happen
|
| - // immediately only if it has been over m_maxPruneDeferralDelay since the last
|
| - // prune.
|
| - double currentTime = WTF::currentTime();
|
| - if (m_prunePending) {
|
| - if (currentTime - m_pruneTimeStamp >= m_maxPruneDeferralDelay) {
|
| - pruneNow(currentTime, AutomaticPrune);
|
| - }
|
| - } else {
|
| - if (currentTime - m_pruneTimeStamp >= m_maxPruneDeferralDelay) {
|
| - pruneNow(currentTime, AutomaticPrune); // Delay exceeded, prune now.
|
| - } else {
|
| - // Defer.
|
| - Platform::current()->currentThread()->addTaskObserver(this);
|
| - m_prunePending = true;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void MemoryCache::willProcessTask() {}
|
| -
|
| -void MemoryCache::didProcessTask() {
|
| - // Perform deferred pruning
|
| - DCHECK(m_prunePending);
|
| - pruneNow(WTF::currentTime(), AutomaticPrune);
|
| -}
|
| -
|
| -void MemoryCache::pruneAll() {
|
| - double currentTime = WTF::currentTime();
|
| - pruneNow(currentTime, MaximalPrune);
|
| -}
|
| -
|
| -void MemoryCache::pruneNow(double currentTime, PruneStrategy strategy) {
|
| - if (m_prunePending) {
|
| - m_prunePending = false;
|
| - Platform::current()->currentThread()->removeTaskObserver(this);
|
| - }
|
| -
|
| - AutoReset<bool> reentrancyProtector(&m_inPruneResources, true);
|
| -
|
| - pruneResources(strategy);
|
| - m_pruneFrameTimeStamp = m_lastFramePaintTimeStamp;
|
| - m_pruneTimeStamp = currentTime;
|
| -}
|
| -
|
| -void MemoryCache::updateFramePaintTimestamp() {
|
| - m_lastFramePaintTimeStamp = currentTime();
|
| -}
|
| -
|
| -bool MemoryCache::onMemoryDump(WebMemoryDumpLevelOfDetail levelOfDetail,
|
| - WebProcessMemoryDump* memoryDump) {
|
| - if (levelOfDetail == WebMemoryDumpLevelOfDetail::Background) {
|
| - Statistics stats = getStatistics();
|
| - WebMemoryAllocatorDump* dump1 =
|
| - memoryDump->createMemoryAllocatorDump("web_cache/Image_resources");
|
| - dump1->addScalar("size", "bytes",
|
| - stats.images.encodedSize + stats.images.overheadSize);
|
| - WebMemoryAllocatorDump* dump2 = memoryDump->createMemoryAllocatorDump(
|
| - "web_cache/CSS stylesheet_resources");
|
| - dump2->addScalar("size", "bytes", stats.cssStyleSheets.encodedSize +
|
| - stats.cssStyleSheets.overheadSize);
|
| - WebMemoryAllocatorDump* dump3 =
|
| - memoryDump->createMemoryAllocatorDump("web_cache/Script_resources");
|
| - dump3->addScalar("size", "bytes",
|
| - stats.scripts.encodedSize + stats.scripts.overheadSize);
|
| - WebMemoryAllocatorDump* dump4 = memoryDump->createMemoryAllocatorDump(
|
| - "web_cache/XSL stylesheet_resources");
|
| - dump4->addScalar("size", "bytes", stats.xslStyleSheets.encodedSize +
|
| - stats.xslStyleSheets.overheadSize);
|
| - WebMemoryAllocatorDump* dump5 =
|
| - memoryDump->createMemoryAllocatorDump("web_cache/Font_resources");
|
| - dump5->addScalar("size", "bytes",
|
| - stats.fonts.encodedSize + stats.fonts.overheadSize);
|
| - WebMemoryAllocatorDump* dump6 =
|
| - memoryDump->createMemoryAllocatorDump("web_cache/Other_resources");
|
| - dump6->addScalar("size", "bytes",
|
| - stats.other.encodedSize + stats.other.overheadSize);
|
| - return true;
|
| - }
|
| -
|
| - for (const auto& resourceMapIter : m_resourceMaps) {
|
| - for (const auto& resourceIter : *resourceMapIter.value) {
|
| - Resource* resource = resourceIter.value->resource();
|
| - resource->onMemoryDump(levelOfDetail, memoryDump);
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void MemoryCache::onMemoryPressure(WebMemoryPressureLevel level) {
|
| - pruneAll();
|
| -}
|
| -
|
| -} // namespace blink
|
|
|