void MemoryCache::pruneDeadResourcesToSize(unsigned targetSize) { if (m_inPruneResources) return; TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true); int size = m_allResources.size(); // See if we have any purged resources we can evict. for (int i = 0; i < size; i++) { CachedResource* current = m_allResources[i].m_tail; while (current) { CachedResource* prev = current->m_prevInAllResourcesList; if (current->wasPurged()) { ASSERT(!current->hasClients()); ASSERT(!current->isPreloaded()); evict(current); } current = prev; } } if (targetSize && m_deadSize <= targetSize) return; bool canShrinkLRULists = true; for (int i = size - 1; i >= 0; i--) { // Remove from the tail, since this is the least frequently accessed of the objects. CachedResource* current = m_allResources[i].m_tail; // First flush all the decoded data in this queue. while (current) { // Protect 'previous' so it can't get deleted during destroyDecodedData(). CachedResourceHandle<CachedResource> previous = current->m_prevInAllResourcesList; ASSERT(!previous || previous->inCache()); if (!current->hasClients() && !current->isPreloaded() && current->isLoaded()) { // Destroy our decoded data. This will remove us from // m_liveDecodedResources, and possibly move us to a different // LRU list in m_allResources. current->destroyDecodedData(); if (targetSize && m_deadSize <= targetSize) return; } // Decoded data may reference other resources. Stop iterating if 'previous' somehow got // kicked out of cache during destroyDecodedData(). if (previous && !previous->inCache()) break; current = previous.get(); } // Now evict objects from this queue. current = m_allResources[i].m_tail; while (current) { CachedResourceHandle<CachedResource> previous = current->m_prevInAllResourcesList; ASSERT(!previous || previous->inCache()); if (!current->hasClients() && !current->isPreloaded() && !current->isCacheValidator()) { if (!makeResourcePurgeable(current)) evict(current); if (targetSize && m_deadSize <= targetSize) return; } if (previous && !previous->inCache()) break; current = previous.get(); } // Shrink the vector back down so we don't waste time inspecting // empty LRU lists on future prunes. if (m_allResources[i].m_head) canShrinkLRULists = false; else if (canShrinkLRULists) m_allResources.resize(i); } }
void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response) { RefPtr<Host> protector(this); Request* request = m_requestsLoading.get(loader); // FIXME: This is a workaround for <rdar://problem/5236843> // If a load starts while the frame is still in the provisional state // (this can be the case when loading the user style sheet), committing the load then causes all // requests to be removed from the m_requestsLoading map. This means that request might be null here. // In that case we just return early. // ASSERT(request); if (!request) return; CachedResource* resource = request->cachedResource(); if (resource->isCacheValidator()) { if (response.httpStatusCode() == 304) { // 304 Not modified / Use local copy m_requestsLoading.remove(loader); loader->clearClient(); request->docLoader()->decrementRequestCount(); // Existing resource is ok, just use it updating the expiration time. cache()->revalidationSucceeded(resource, response); if (request->docLoader()->frame()) request->docLoader()->frame()->loader()->checkCompleted(); delete request; servePendingRequests(); return; } // Did not get 304 response, continue as a regular resource load. cache()->revalidationFailed(resource); } resource->setResponse(response); String encoding = response.textEncodingName(); if (!encoding.isNull()) resource->setEncoding(encoding); if (request->isMultipart()) { ASSERT(resource->isImage()); static_cast<CachedImage*>(resource)->clear(); if (request->docLoader()->frame()) request->docLoader()->frame()->loader()->checkCompleted(); } else if (response.isMultipart()) { request->setIsMultipart(true); // We don't count multiParts in a DocLoader's request count request->docLoader()->decrementRequestCount(); // If we get a multipart response, we must have a handle ASSERT(loader->handle()); if (!resource->isImage()) loader->handle()->cancel(); } }