Index: Source/core/fetch/MemoryCache.cpp |
diff --git a/Source/core/fetch/MemoryCache.cpp b/Source/core/fetch/MemoryCache.cpp |
index 4aa2a5aca2024e0ee814717db0681b78b05a0111..52603e3d0eb16583fbb3502fa2953b7c7017b3be 100644 |
--- a/Source/core/fetch/MemoryCache.cpp |
+++ b/Source/core/fetch/MemoryCache.cpp |
@@ -134,7 +134,7 @@ void MemoryCache::trace(Visitor* visitor) |
visitor->trace(m_allResources); |
for (size_t i = 0; i < WTF_ARRAY_LENGTH(m_liveDecodedResources); ++i) |
visitor->trace(m_liveDecodedResources[i]); |
- visitor->trace(m_resources); |
+ visitor->trace(m_resourceMaps); |
visitor->trace(m_liveResources); |
#endif |
} |
@@ -153,12 +153,27 @@ KURL MemoryCache::removeFragmentIdentifierIfNeeded(const KURL& originalURL) |
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, adoptPtrWillBeNoop(new ResourceMap())); |
+ RELEASE_ASSERT(result.isNewEntry); |
+ } |
+ return m_resourceMaps.get(cacheIdentifier); |
+} |
+ |
void MemoryCache::add(Resource* resource) |
{ |
ASSERT(WTF::isMainThread()); |
ASSERT(resource->url().isValid()); |
- RELEASE_ASSERT(!m_resources.contains(resource->url())); |
- m_resources.set(resource->url().string(), MemoryCacheEntry::create(resource)); |
+ ResourceMap* resources = ensureResourceMap(resource->cacheIdentifier()); |
+ RELEASE_ASSERT(!resources->contains(resource->url())); |
+ resources->set(resource->url(), MemoryCacheEntry::create(resource)); |
update(resource, 0, resource->size(), true); |
WTF_LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resource->url().string().latin1().data(), resource); |
@@ -166,47 +181,65 @@ void MemoryCache::add(Resource* resource) |
void MemoryCache::replace(Resource* newResource, Resource* oldResource) |
{ |
- if (MemoryCacheEntry* oldEntry = m_resources.get(oldResource->url())) |
+ ASSERT(newResource->cacheIdentifier() == oldResource->cacheIdentifier()); |
+ ResourceMap* resources = ensureResourceMap(oldResource->cacheIdentifier()); |
+ if (MemoryCacheEntry* oldEntry = resources->get(oldResource->url())) |
evict(oldEntry); |
add(newResource); |
if (newResource->decodedSize() && newResource->hasClients()) |
- insertInLiveDecodedResourcesList(m_resources.get(newResource->url())); |
+ insertInLiveDecodedResourcesList(resources->get(newResource->url())); |
} |
void MemoryCache::remove(Resource* resource) |
{ |
// The resource may have already been removed by someone other than our caller, |
// who needed a fresh copy for a reload. |
- if (!contains(resource)) |
- return; |
- evict(m_resources.get(resource->url())); |
+ if (MemoryCacheEntry* entry = getEntryForResource(resource)) |
+ evict(entry); |
} |
bool MemoryCache::contains(const Resource* resource) const |
{ |
- if (resource->url().isNull()) |
- return false; |
- const MemoryCacheEntry* entry = m_resources.get(resource->url()); |
- return entry && entry->m_resource == resource; |
+ return getEntryForResource(resource); |
} |
Resource* MemoryCache::resourceForURL(const KURL& resourceURL) |
{ |
+ return resourceForURL(resourceURL, defaultCacheIdentifier()); |
+} |
+ |
+Resource* MemoryCache::resourceForURL(const KURL& resourceURL, const String& cacheIdentifier) |
+{ |
ASSERT(WTF::isMainThread()); |
+ ResourceMap* resources = m_resourceMaps.get(cacheIdentifier); |
+ if (!resources) |
+ return nullptr; |
KURL url = removeFragmentIdentifierIfNeeded(resourceURL); |
- MemoryCacheEntry* entry = m_resources.get(url); |
+ MemoryCacheEntry* entry = resources->get(url); |
if (!entry) |
- return 0; |
+ return nullptr; |
Resource* resource = entry->m_resource.get(); |
if (resource && !resource->lock()) { |
ASSERT(!resource->hasClients()); |
bool didEvict = evict(entry); |
ASSERT_UNUSED(didEvict, didEvict); |
- return 0; |
+ return nullptr; |
} |
return resource; |
} |
+WillBeHeapVector<Member<Resource>> MemoryCache::resourcesForURL(const KURL& resourceURL) |
+{ |
+ ASSERT(WTF::isMainThread()); |
+ KURL url = removeFragmentIdentifierIfNeeded(resourceURL); |
+ WillBeHeapVector<Member<Resource>> results; |
+ for (const auto& resourceMapIter : m_resourceMaps) { |
+ if (MemoryCacheEntry* entry = resourceMapIter.value->get(url)) |
+ results.append(entry->m_resource.get()); |
+ } |
+ return results; |
+} |
+ |
size_t MemoryCache::deadCapacity() const |
{ |
// Dead resource capacity is whatever space is not occupied by live resources, bounded by an independent minimum and maximum. |
@@ -374,15 +407,17 @@ bool MemoryCache::evict(MemoryCacheEntry* entry) |
update(resource, resource->size(), 0, false); |
removeFromLiveDecodedResourcesList(entry); |
- ResourceMap::iterator it = m_resources.find(resource->url()); |
- ASSERT(it != m_resources.end()); |
+ ResourceMap* resources = m_resourceMaps.get(resource->cacheIdentifier()); |
+ ASSERT(resources); |
+ ResourceMap::iterator it = resources->find(resource->url()); |
+ ASSERT(it != resources->end()); |
#if ENABLE(OILPAN) |
MemoryCacheEntry* entryPtr = it->value; |
#else |
OwnPtr<MemoryCacheEntry> entryPtr; |
entryPtr.swap(it->value); |
#endif |
- m_resources.remove(it); |
+ resources->remove(it); |
#if ENABLE(OILPAN) |
if (entryPtr) |
entryPtr->dispose(); |
@@ -390,6 +425,19 @@ bool MemoryCache::evict(MemoryCacheEntry* entry) |
return canDelete; |
} |
+MemoryCacheEntry* MemoryCache::getEntryForResource(const Resource* resource) const |
+{ |
+ if (resource->url().isNull() || resource->url().isEmpty()) |
+ return nullptr; |
+ ResourceMap* resources = m_resourceMaps.get(resource->cacheIdentifier()); |
+ if (!resources) |
+ return nullptr; |
+ MemoryCacheEntry* entry = resources->get(resource->url()); |
+ if (!entry || entry->m_resource != resource) |
+ return nullptr; |
+ return entry; |
+} |
+ |
MemoryCacheLRUList* MemoryCache::lruListFor(unsigned accessCount, size_t size) |
{ |
ASSERT(accessCount > 0); |
@@ -522,14 +570,14 @@ void MemoryCache::makeDead(Resource* resource) |
return; |
m_liveSize -= resource->size(); |
m_deadSize += resource->size(); |
- removeFromLiveDecodedResourcesList(m_resources.get(resource->url())); |
+ removeFromLiveDecodedResourcesList(getEntryForResource(resource)); |
} |
void MemoryCache::update(Resource* resource, size_t oldSize, size_t newSize, bool wasAccessed) |
{ |
- if (!contains(resource)) |
+ MemoryCacheEntry* entry = getEntryForResource(resource); |
+ if (!entry) |
return; |
- MemoryCacheEntry* entry = m_resources.get(resource->url()); |
// The object must now be moved to a different queue, since either its size or its accessCount has been changed, |
// and both of those are used to determine which LRU queue the resource should be in. |
@@ -552,9 +600,9 @@ void MemoryCache::update(Resource* resource, size_t oldSize, size_t newSize, boo |
void MemoryCache::updateDecodedResource(Resource* resource, UpdateReason reason, MemoryCacheLiveResourcePriority priority) |
{ |
- if (!contains(resource)) |
+ MemoryCacheEntry* entry = getEntryForResource(resource); |
+ if (!entry) |
return; |
- MemoryCacheEntry* entry = m_resources.get(resource->url()); |
removeFromLiveDecodedResourcesList(entry); |
if (priority != MemoryCacheLiveResourcePriorityUnknown && priority != entry->m_liveResourcePriority) |
@@ -573,9 +621,9 @@ void MemoryCache::updateDecodedResource(Resource* resource, UpdateReason reason, |
MemoryCacheLiveResourcePriority MemoryCache::priority(Resource* resource) const |
{ |
- if (!contains(resource)) |
+ MemoryCacheEntry* entry = getEntryForResource(resource); |
+ if (!entry) |
return MemoryCacheLiveResourcePriorityUnknown; |
- MemoryCacheEntry* entry = m_resources.get(resource->url()); |
return entry->m_liveResourcePriority; |
} |
@@ -591,7 +639,8 @@ void MemoryCache::removeURLFromCache(ExecutionContext* context, const KURL& url) |
void MemoryCache::removeURLFromCacheInternal(ExecutionContext*, const KURL& url) |
{ |
- if (Resource* resource = memoryCache()->resourceForURL(url)) |
+ WillBeHeapVector<Member<Resource>> resources = memoryCache()->resourcesForURL(url); |
+ for (Resource* resource : resources) |
memoryCache()->remove(resource); |
} |
@@ -613,27 +662,29 @@ void MemoryCache::TypeStatistic::addResource(Resource* o) |
MemoryCache::Statistics MemoryCache::getStatistics() |
{ |
Statistics stats; |
- for (const auto& resourceIter : m_resources) { |
- Resource* resource = resourceIter.value->m_resource.get(); |
- switch (resource->type()) { |
- 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; |
+ for (const auto& resourceMapIter : m_resourceMaps) { |
+ for (const auto& resourceIter : *resourceMapIter.value) { |
+ Resource* resource = resourceIter.value->m_resource.get(); |
+ switch (resource->type()) { |
+ 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; |
@@ -641,11 +692,18 @@ MemoryCache::Statistics MemoryCache::getStatistics() |
void MemoryCache::evictResources() |
{ |
- for (;;) { |
- ResourceMap::iterator i = m_resources.begin(); |
- if (i == m_resources.end()) |
+ while (true) { |
+ ResourceMapIndex::iterator resourceMapIter = m_resourceMaps.begin(); |
+ if (resourceMapIter == m_resourceMaps.end()) |
break; |
- evict(i->value.get()); |
+ ResourceMap* resources = resourceMapIter->value.get(); |
+ while (true) { |
+ ResourceMap::iterator resourceIter = resources->begin(); |
+ if (resourceIter == resources->end()) |
+ break; |
+ evict(resourceIter->value.get()); |
+ } |
+ m_resourceMaps.remove(resourceMapIter); |
} |
} |
@@ -689,8 +747,10 @@ void MemoryCache::prune(Resource* justReleasedResource) |
// while a prune is pending. |
// Main Resources in the cache are only substitue data that was |
// precached and should not be evicted. |
- if (contains(justReleasedResource) && justReleasedResource->type() != Resource::MainResource) |
- evict(m_resources.get(justReleasedResource->url())); |
+ if (justReleasedResource->type() != Resource::MainResource) { |
+ if (MemoryCacheEntry* entry = getEntryForResource(justReleasedResource)) |
+ evict(entry); |
+ } |
// As a last resort, prune immediately |
if (m_deadSize > m_maxDeferredPruneDeadCapacity) |