Commit 22e5436c authored by japhet@chromium.org's avatar japhet@chromium.org

2010-11-08 Nate Chapin <japhet@chromium.org>

        Reviewed by Alexey Proskuryakov.

        Move connection-per-host counting and request prioritization out
        of Loader and down to the ResourceLoader level.

        https://bugs.webkit.org/show_bug.cgi?id=27165

        Refactor only, so no new tests.

        * CMakeLists.txt:
        * GNUmakefile.am:
        * WebCore.exp.in:
        * WebCore.gypi:
        * WebCore.pro:
        * WebCore.vcproj/WebCore.vcproj:
        * WebCore.xcodeproj/project.pbxproj:
        * dom/ContainerNode.cpp:
        (WebCore::ContainerNode::suspendPostAttachCallbacks):
        (WebCore::ContainerNode::resumePostAttachCallbacks):
        * loader/DocumentThreadableLoader.cpp:
        (WebCore::DocumentThreadableLoader::loadRequest):
        * loader/MainResourceLoader.cpp:
        (WebCore::MainResourceLoader::loadNow):
        * loader/NetscapePlugInStreamLoader.cpp:
        (WebCore::NetscapePlugInStreamLoader::create):
        * loader/NetscapePlugInStreamLoader.h:
        * loader/ResourceLoadScheduler.cpp: Added.
        (WebCore::ResourceLoadScheduler::hostForURL):
        (WebCore::resourceLoadScheduler): Returns the single ResourceLoadScheduler instance
        (WebCore::ResourceLoadScheduler::ResourceLoadScheduler):
        (WebCore::ResourceLoadScheduler::scheduleSubresourceLoad):
        (WebCore::ResourceLoadScheduler::schedulePluginStreamLoad):
        (WebCore::ResourceLoadScheduler::addMainResourceLoad):
        (WebCore::ResourceLoadScheduler::scheduleLoad):
        (WebCore::ResourceLoadScheduler::remove):
        (WebCore::ResourceLoadScheduler::crossOriginRedirectReceived):
        (WebCore::ResourceLoadScheduler::servePendingRequests):
        (WebCore::ResourceLoadScheduler::suspendPendingRequests):
        (WebCore::ResourceLoadScheduler::resumePendingRequests):
        (WebCore::ResourceLoadScheduler::scheduleServePendingRequests):
        (WebCore::ResourceLoadScheduler::requestTimerFired):
        (WebCore::ResourceLoadScheduler::assertLoaderBeingCounted):
        (WebCore::ResourceLoadScheduler::HostInformation::assertLoaderBeingCounted):
        (WebCore::ResourceLoadScheduler::HostInformation::HostInformation):
        (WebCore::ResourceLoadScheduler::HostInformation::~HostInformation):
        (WebCore::ResourceLoadScheduler::HostInformation::schedule):
        (WebCore::ResourceLoadScheduler::HostInformation::addLoadInProgress):
        (WebCore::ResourceLoadScheduler::HostInformation::remove):
        (WebCore::ResourceLoadScheduler::HostInformation::hasRequests):
        * loader/ResourceLoadScheduler.h: Added.
        (WebCore::ResourceLoadScheduler::HostInformation::name):
        (WebCore::ResourceLoadScheduler::HostInformation::limitRequests):
        (WebCore::ResourceLoadScheduler::HostInformation::requestsPending):
        * loader/ResourceLoader.cpp:
        (WebCore::ResourceLoader::releaseResources): Remove this from ResourceLoadScheduler's counting.
        (WebCore::ResourceLoader::load):
        (WebCore::ResourceLoader::start): Create the ResourceHandle, called by ResourceLoadScheduler.
        (WebCore::ResourceLoader::willSendRequest): Ensure ResourceLoadScheduler counts redirects
            correctly.
        * loader/ResourceLoader.h:
        (WebCore::ResourceLoader::url):
        * loader/icon/IconLoader.cpp:
        (WebCore::IconLoader::startLoading):
        * loader/loader.cpp: Move scheduling to ResourceLoadScheduler, remove Host subclass
            and make Loader the SubresourceLoaderClient instead.
        (WebCore::determinePriority):
        (WebCore::Loader::load): Schedule the creation of the ResourceHandle, rather than
            doing it immediately.
        (WebCore::Loader::cancelRequests):
        (WebCore::Loader::didFinishLoading):
        (WebCore::Loader::didFail):
        (WebCore::Loader::didReceiveResponse):
        (WebCore::Loader::didReceiveData):
        (WebCore::Loader::didReceiveCachedMetadata):
        * loader/loader.h:
        * page/EventSource.cpp:
        (WebCore::EventSource::connect):
        (WebCore::EventSource::endRequest):
        * plugins/PluginStream.cpp:
        (WebCore::PluginStream::start):
        * xml/XMLHttpRequest.cpp:
        (WebCore::XMLHttpRequest::XMLHttpRequest):
        (WebCore::XMLHttpRequest::~XMLHttpRequest):
        (WebCore::XMLHttpRequest::createRequest):
        (WebCore::XMLHttpRequest::didFail):
        (WebCore::XMLHttpRequest::didFinishLoading):
        * xml/XMLHttpRequest.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@71562 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent fa2bd348
......@@ -1172,6 +1172,7 @@ SET(WebCore_SOURCES
loader/NavigationScheduler.cpp
loader/Request.cpp
loader/ResourceLoadNotifier.cpp
loader/ResourceLoadScheduler.cpp
loader/ResourceLoader.cpp
loader/SinkDocument.cpp
loader/SubframeLoader.cpp
......
2010-11-08 Nate Chapin <japhet@chromium.org>
Reviewed by Alexey Proskuryakov.
Move connection-per-host counting and request prioritization out
of Loader and down to the ResourceLoader level.
https://bugs.webkit.org/show_bug.cgi?id=27165
Refactor only, so no new tests.
* CMakeLists.txt:
* GNUmakefile.am:
* WebCore.exp.in:
* WebCore.gypi:
* WebCore.pro:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* dom/ContainerNode.cpp:
(WebCore::ContainerNode::suspendPostAttachCallbacks):
(WebCore::ContainerNode::resumePostAttachCallbacks):
* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::loadRequest):
* loader/MainResourceLoader.cpp:
(WebCore::MainResourceLoader::loadNow):
* loader/NetscapePlugInStreamLoader.cpp:
(WebCore::NetscapePlugInStreamLoader::create):
* loader/NetscapePlugInStreamLoader.h:
* loader/ResourceLoadScheduler.cpp: Added.
(WebCore::ResourceLoadScheduler::hostForURL):
(WebCore::resourceLoadScheduler): Returns the single ResourceLoadScheduler instance
(WebCore::ResourceLoadScheduler::ResourceLoadScheduler):
(WebCore::ResourceLoadScheduler::scheduleSubresourceLoad):
(WebCore::ResourceLoadScheduler::schedulePluginStreamLoad):
(WebCore::ResourceLoadScheduler::addMainResourceLoad):
(WebCore::ResourceLoadScheduler::scheduleLoad):
(WebCore::ResourceLoadScheduler::remove):
(WebCore::ResourceLoadScheduler::crossOriginRedirectReceived):
(WebCore::ResourceLoadScheduler::servePendingRequests):
(WebCore::ResourceLoadScheduler::suspendPendingRequests):
(WebCore::ResourceLoadScheduler::resumePendingRequests):
(WebCore::ResourceLoadScheduler::scheduleServePendingRequests):
(WebCore::ResourceLoadScheduler::requestTimerFired):
(WebCore::ResourceLoadScheduler::assertLoaderBeingCounted):
(WebCore::ResourceLoadScheduler::HostInformation::assertLoaderBeingCounted):
(WebCore::ResourceLoadScheduler::HostInformation::HostInformation):
(WebCore::ResourceLoadScheduler::HostInformation::~HostInformation):
(WebCore::ResourceLoadScheduler::HostInformation::schedule):
(WebCore::ResourceLoadScheduler::HostInformation::addLoadInProgress):
(WebCore::ResourceLoadScheduler::HostInformation::remove):
(WebCore::ResourceLoadScheduler::HostInformation::hasRequests):
* loader/ResourceLoadScheduler.h: Added.
(WebCore::ResourceLoadScheduler::HostInformation::name):
(WebCore::ResourceLoadScheduler::HostInformation::limitRequests):
(WebCore::ResourceLoadScheduler::HostInformation::requestsPending):
* loader/ResourceLoader.cpp:
(WebCore::ResourceLoader::releaseResources): Remove this from ResourceLoadScheduler's counting.
(WebCore::ResourceLoader::load):
(WebCore::ResourceLoader::start): Create the ResourceHandle, called by ResourceLoadScheduler.
(WebCore::ResourceLoader::willSendRequest): Ensure ResourceLoadScheduler counts redirects
correctly.
* loader/ResourceLoader.h:
(WebCore::ResourceLoader::url):
* loader/icon/IconLoader.cpp:
(WebCore::IconLoader::startLoading):
* loader/loader.cpp: Move scheduling to ResourceLoadScheduler, remove Host subclass
and make Loader the SubresourceLoaderClient instead.
(WebCore::determinePriority):
(WebCore::Loader::load): Schedule the creation of the ResourceHandle, rather than
doing it immediately.
(WebCore::Loader::cancelRequests):
(WebCore::Loader::didFinishLoading):
(WebCore::Loader::didFail):
(WebCore::Loader::didReceiveResponse):
(WebCore::Loader::didReceiveData):
(WebCore::Loader::didReceiveCachedMetadata):
* loader/loader.h:
* page/EventSource.cpp:
(WebCore::EventSource::connect):
(WebCore::EventSource::endRequest):
* plugins/PluginStream.cpp:
(WebCore::PluginStream::start):
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::XMLHttpRequest):
(WebCore::XMLHttpRequest::~XMLHttpRequest):
(WebCore::XMLHttpRequest::createRequest):
(WebCore::XMLHttpRequest::didFail):
(WebCore::XMLHttpRequest::didFinishLoading):
* xml/XMLHttpRequest.h:
2010-11-08 Ryosuke Niwa <rniwa@webkit.org>
Reviewed by Darin Adler.
......@@ -1999,6 +1999,8 @@ webcore_sources += \
WebCore/loader/ResourceLoader.h \
WebCore/loader/ResourceLoadNotifier.cpp \
WebCore/loader/ResourceLoadNotifier.h \
WebCore/loader/ResourceLoadScheduler.cpp \
WebCore/loader/ResourceLoadScheduler.h \
WebCore/loader/SinkDocument.cpp \
WebCore/loader/SinkDocument.h \
WebCore/loader/SubframeLoader.cpp \
......
......@@ -479,6 +479,8 @@ __ZN7WebCore20ResourceResponseBaseC2Ev
__ZN7WebCore20SpaceSplitStringData12createVectorEv
__ZN7WebCore20protocolIsJavaScriptERKN3WTF6StringE
__ZN7WebCore21BackForwardController11itemAtIndexEi
__ZN7WebCore21ResourceLoadScheduler20servePendingRequestsENS0_8PriorityE
__ZN7WebCore21ResourceLoadScheduler24schedulePluginStreamLoadEPNS_5FrameEPNS_32NetscapePlugInStreamLoaderClientERKNS_15ResourceRequestE
__ZN7WebCore21PlatformKeyboardEvent24disambiguateKeyDownEventENS0_4TypeEb
__ZN7WebCore21PlatformKeyboardEventC1EP7NSEvent
__ZN7WebCore21SVGDocumentExtensions21sampleAnimationAtTimeERKN3WTF6StringEPNS_14SVGSMILElementEd
......@@ -493,6 +495,7 @@ __ZN7WebCore21isBackForwardLoadTypeENS_13FrameLoadTypeE
__ZN7WebCore21mainThreadNormalWorldEv
__ZN7WebCore21markerTextForListItemEPNS_7ElementE
__ZN7WebCore21reportThreadViolationEPKcNS_20ThreadViolationRoundE
__ZN7WebCore21resourceLoadSchedulerEv
__ZN7WebCore21setPlatformStrategiesEPNS_18PlatformStrategiesE
__ZN7WebCore22ScriptExecutionContext26canSuspendActiveDOMObjectsEv
__ZN7WebCore22applicationIsAppleMailEv
......@@ -525,7 +528,6 @@ __ZN7WebCore25PluginMainThreadScheduler9schedulerEv
__ZN7WebCore25addLanguageChangeObserverEPvPFvS0_E
__ZN7WebCore25contextMenuItemTagOutlineEv
__ZN7WebCore26CSSMutableStyleDeclarationC1Ev
__ZN7WebCore26NetscapePlugInStreamLoader6createEPNS_5FrameEPNS_32NetscapePlugInStreamLoaderClientE
__ZN7WebCore26UserTypingGestureIndicator27processingUserTypingGestureEv
__ZN7WebCore26UserTypingGestureIndicator28focusedElementAtGestureStartEv
__ZN7WebCore26contextMenuItemTagFontMenuEv
......@@ -699,7 +701,6 @@ __ZN7WebCore6Editor6indentEv
__ZN7WebCore6Editor7CommandC1Ev
__ZN7WebCore6Editor7commandERKN3WTF6StringE
__ZN7WebCore6Editor7outdentEv
__ZN7WebCore6Loader20servePendingRequestsENS0_8PriorityE
__ZN7WebCore6Widget12setFrameRectERKNS_7IntRectE
__ZN7WebCore6Widget16removeFromParentEv
__ZN7WebCore6Widget17frameRectsChangedEv
......
......@@ -2102,6 +2102,8 @@
'loader/ResourceLoader.h',
'loader/ResourceLoadNotifier.cpp',
'loader/ResourceLoadNotifier.h',
'loader/ResourceLoadScheduler.cpp',
'loader/ResourceLoadScheduler.h',
'loader/SinkDocument.cpp',
'loader/SinkDocument.h',
'loader/SubframeLoader.cpp',
......
......@@ -1069,6 +1069,7 @@ SOURCES += \
loader/Request.cpp \
loader/ResourceLoader.cpp \
loader/ResourceLoadNotifier.cpp \
loader/ResourceLoadScheduler.cpp \
loader/SinkDocument.cpp \
loader/SubframeLoader.cpp \
loader/SubresourceLoader.cpp \
......
......@@ -23947,6 +23947,14 @@
RelativePath="..\loader\ResourceLoadNotifier.h"
>
</File>
<File
RelativePath="..\loader\ResourceLoadScheduler.cpp"
>
</File>
<File
RelativePath="..\loader\ ResourceLoadScheduler.h"
>
</File>
<File
RelativePath="..\loader\SinkDocument.cpp"
>
......@@ -5327,6 +5327,8 @@
D086FE9909D53AAB005BC74D /* UnlinkCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D086FE9709D53AAB005BC74D /* UnlinkCommand.cpp */; };
D0B0556809C6700100307E43 /* CreateLinkCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B0556609C6700100307E43 /* CreateLinkCommand.h */; };
D0B0556909C6700100307E43 /* CreateLinkCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0B0556709C6700100307E43 /* CreateLinkCommand.cpp */; };
D0CE58F8125E4CC200F3F199 /* ResourceLoadScheduler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0CE58F6125E4CC200F3F199 /* ResourceLoadScheduler.cpp */; };
D0CE58F9125E4CC200F3F199 /* ResourceLoadScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D0CE58F7125E4CC200F3F199 /* ResourceLoadScheduler.h */; settings = {ATTRIBUTES = (Private, ); }; };
D0FF2A5D11F8C45A007E74E0 /* PingLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0FF2A5B11F8C45A007E74E0 /* PingLoader.cpp */; };
D0FF2A5E11F8C45A007E74E0 /* PingLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = D0FF2A5C11F8C45A007E74E0 /* PingLoader.h */; };
D23CA55D0AB0EAAE005108A5 /* JSRangeException.h in Headers */ = {isa = PBXBuildFile; fileRef = D23CA55C0AB0EAAE005108A5 /* JSRangeException.h */; };
......@@ -11389,6 +11391,8 @@
D086FE9709D53AAB005BC74D /* UnlinkCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnlinkCommand.cpp; sourceTree = "<group>"; };
D0B0556609C6700100307E43 /* CreateLinkCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CreateLinkCommand.h; sourceTree = "<group>"; };
D0B0556709C6700100307E43 /* CreateLinkCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CreateLinkCommand.cpp; sourceTree = "<group>"; };
D0CE58F6125E4CC200F3F199 /* ResourceLoadScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResourceLoadScheduler.cpp; sourceTree = "<group>"; };
D0CE58F7125E4CC200F3F199 /* ResourceLoadScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceLoadScheduler.h; sourceTree = "<group>"; };
D0FF2A5B11F8C45A007E74E0 /* PingLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PingLoader.cpp; sourceTree = "<group>"; };
D0FF2A5C11F8C45A007E74E0 /* PingLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PingLoader.h; sourceTree = "<group>"; };
D23CA5480AB0E983005108A5 /* RangeException.idl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = RangeException.idl; sourceTree = "<group>"; };
......@@ -17333,6 +17337,8 @@
656D37270ADBA5DE00A4554D /* ResourceLoader.h */,
973E325410883B7C005BC493 /* ResourceLoadNotifier.cpp */,
973E325510883B7C005BC493 /* ResourceLoadNotifier.h */,
D0CE58F6125E4CC200F3F199 /* ResourceLoadScheduler.cpp */,
D0CE58F7125E4CC200F3F199 /* ResourceLoadScheduler.h */,
51327D5F11A33A2B004F9D65 /* SinkDocument.cpp */,
51327D5E11A33A2B004F9D65 /* SinkDocument.h */,
D000ED2511C1B9CD00C47726 /* SubframeLoader.cpp */,
......@@ -20709,6 +20715,7 @@
514C767B0CE923A1007EF3CD /* ResourceHandleInternal.h in Headers */,
656D373F0ADBA5DE00A4554D /* ResourceLoader.h in Headers */,
973E325710883B7C005BC493 /* ResourceLoadNotifier.h in Headers */,
D0CE58F9125E4CC200F3F199 /* ResourceLoadScheduler.h in Headers */,
8A81BF8511DCFD9000DA2B98 /* ResourceLoadTiming.h in Headers */,
492863991253B8FC00F792D6 /* ResourceRawHeaders.h in Headers */,
514C76520CE9234E007EF3CD /* ResourceRequest.h in Headers */,
......@@ -23896,6 +23903,7 @@
93F19B0508245E59001E9ABC /* XSLTProcessorLibxslt.cpp in Sources */,
E1BE512D0CF6C512002EA959 /* XSLTUnicodeSort.cpp in Sources */,
97DD4D860FDF4D6E00ECF9A4 /* XSSAuditor.cpp in Sources */,
D0CE58F8125E4CC200F3F199 /* ResourceLoadScheduler.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -35,11 +35,11 @@
#include "InlineTextBox.h"
#include "InspectorInstrumentation.h"
#include "MutationEvent.h"
#include "ResourceLoadScheduler.h"
#include "Page.h"
#include "RenderBox.h"
#include "RenderTheme.h"
#include "RootInlineBox.h"
#include "loader.h"
#include <wtf/CurrentTime.h>
#include <wtf/Vector.h>
......@@ -655,7 +655,7 @@ void ContainerNode::suspendPostAttachCallbacks()
s_shouldReEnableMemoryCacheCallsAfterAttach = true;
}
}
cache()->loader()->suspendPendingRequests();
resourceLoadScheduler()->suspendPendingRequests();
}
++s_attachDepth;
}
......@@ -670,7 +670,7 @@ void ContainerNode::resumePostAttachCallbacks()
if (Page* page = document()->page())
page->setMemoryCacheClientCallsEnabled(true);
}
cache()->loader()->resumePendingRequests();
resourceLoadScheduler()->resumePendingRequests();
}
--s_attachDepth;
}
......
......@@ -38,6 +38,7 @@
#include "Frame.h"
#include "FrameLoader.h"
#include "ResourceHandle.h"
#include "ResourceLoadScheduler.h"
#include "ResourceRequest.h"
#include "SecurityOrigin.h"
#include "SubresourceLoader.h"
......@@ -319,7 +320,7 @@ void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Secur
// Clear the loader so that any callbacks from SubresourceLoader::create will not have the old loader.
m_loader = 0;
m_loader = SubresourceLoader::create(m_document->frame(), this, request, securityCheck, sendLoadCallbacks, sniffContent);
m_loader = resourceLoadScheduler()->scheduleSubresourceLoad(m_document->frame(), this, request, ResourceLoadScheduler::Medium, securityCheck, sendLoadCallbacks, sniffContent);
return;
}
......
......@@ -44,6 +44,7 @@
#endif
#include "ResourceError.h"
#include "ResourceHandle.h"
#include "ResourceLoadScheduler.h"
#include "SchemeRegistry.h"
#include "Settings.h"
#include <wtf/CurrentTime.h>
......@@ -548,6 +549,7 @@ bool MainResourceLoader::loadNow(ResourceRequest& r)
if (shouldLoadEmptyBeforeRedirect && !shouldLoadEmpty && defersLoading())
return true;
resourceLoadScheduler()->addMainResourceLoad(this);
if (m_substituteData.isValid())
handleDataLoadSoon(r);
else if (shouldLoadEmpty || frameLoader()->representationExistsForURLScheme(url.protocol()))
......
......@@ -44,9 +44,12 @@ NetscapePlugInStreamLoader::~NetscapePlugInStreamLoader()
{
}
PassRefPtr<NetscapePlugInStreamLoader> NetscapePlugInStreamLoader::create(Frame* frame, NetscapePlugInStreamLoaderClient* client)
PassRefPtr<NetscapePlugInStreamLoader> NetscapePlugInStreamLoader::create(Frame* frame, NetscapePlugInStreamLoaderClient* client, const ResourceRequest& request)
{
return adoptRef(new NetscapePlugInStreamLoader(frame, client));
RefPtr<NetscapePlugInStreamLoader> loader(adoptRef(new NetscapePlugInStreamLoader(frame, client)));
loader->setShouldBufferData(false);
loader->documentLoader()->addPlugInStreamLoader(loader.get());
return loader->load(request) ? loader.release() : 0;
}
bool NetscapePlugInStreamLoader::isDone() const
......
......@@ -47,7 +47,7 @@ namespace WebCore {
class NetscapePlugInStreamLoader : public ResourceLoader {
public:
static PassRefPtr<NetscapePlugInStreamLoader> create(Frame*, NetscapePlugInStreamLoaderClient*);
static PassRefPtr<NetscapePlugInStreamLoader> create(Frame*, NetscapePlugInStreamLoaderClient*, const ResourceRequest&);
virtual ~NetscapePlugInStreamLoader();
bool isDone() const;
......
/*
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) 2006 Samuel Weinig (sam.weinig@gmail.com)
Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
Copyright (C) 2010 Google 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 "config.h"
#include "ResourceLoadScheduler.h"
#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "InspectorInstrumentation.h"
#include "KURL.h"
#include "Logging.h"
#include "NetscapePlugInStreamLoader.h"
#include "ResourceLoader.h"
#include "ResourceRequest.h"
#include "SubresourceLoader.h"
#define REQUEST_MANAGEMENT_ENABLED 1
namespace WebCore {
#if REQUEST_MANAGEMENT_ENABLED
static const unsigned maxRequestsInFlightForNonHTTPProtocols = 20;
// Match the parallel connection count used by the networking layer.
static unsigned maxRequestsInFlightPerHost;
#else
static const unsigned maxRequestsInFlightForNonHTTPProtocols = 10000;
static const unsigned maxRequestsInFlightPerHost = 10000;
#endif
ResourceLoadScheduler::HostInformation* ResourceLoadScheduler::hostForURL(const KURL& url, CreateHostPolicy createHostPolicy)
{
if (!url.protocolInHTTPFamily())
return m_nonHTTPProtocolHost;
m_hosts.checkConsistency();
String hostName = url.host();
HostInformation* host = m_hosts.get(hostName);
if (!host && createHostPolicy == CreateIfNotFound) {
host = new HostInformation(hostName, maxRequestsInFlightPerHost);
m_hosts.add(hostName, host);
}
return host;
}
ResourceLoadScheduler* resourceLoadScheduler()
{
ASSERT(isMainThread());
DEFINE_STATIC_LOCAL(ResourceLoadScheduler, resourceLoadScheduler, ());
return &resourceLoadScheduler;
}
ResourceLoadScheduler::ResourceLoadScheduler()
: m_nonHTTPProtocolHost(new HostInformation(String(), maxRequestsInFlightForNonHTTPProtocols))
, m_requestTimer(this, &ResourceLoadScheduler::requestTimerFired)
, m_isSuspendingPendingRequests(false)
{
#if REQUEST_MANAGEMENT_ENABLED
maxRequestsInFlightPerHost = initializeMaximumHTTPConnectionCountPerHost();
#endif
}
PassRefPtr<SubresourceLoader> ResourceLoadScheduler::scheduleSubresourceLoad(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, Priority priority, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff)
{
PassRefPtr<SubresourceLoader> loader = SubresourceLoader::create(frame, client, request, securityCheck, sendResourceLoadCallbacks, shouldContentSniff);
if (loader)
scheduleLoad(loader.get(), priority);
return loader;
}
PassRefPtr<NetscapePlugInStreamLoader> ResourceLoadScheduler::schedulePluginStreamLoad(Frame* frame, NetscapePlugInStreamLoaderClient* client, const ResourceRequest& request)
{
PassRefPtr<NetscapePlugInStreamLoader> loader = NetscapePlugInStreamLoader::create(frame, client, request);
if (loader)
scheduleLoad(loader.get(), Low);
return loader;
}
void ResourceLoadScheduler::addMainResourceLoad(ResourceLoader* resourceLoader)
{
hostForURL(resourceLoader->url(), CreateIfNotFound)->addLoadInProgress(resourceLoader);
}
void ResourceLoadScheduler::scheduleLoad(ResourceLoader* resourceLoader, Priority priority)
{
ASSERT(resourceLoader);
#if !REQUEST_MANAGEMENT_ENABLED
priority = High;
#endif
LOG(ResourceLoading, "ResourceLoadScheduler::load resource %p '%s'", resourceLoader, resourceLoader->url().string().latin1().data());
HostInformation* host = hostForURL(resourceLoader->url(), CreateIfNotFound);
bool hadRequests = host->hasRequests();
host->schedule(resourceLoader, priority);
if (priority > Low || !resourceLoader->url().protocolInHTTPFamily() || (priority == Low && !hadRequests)) {
// Try to request important resources immediately.
servePendingRequests(host, priority);
} else {
// Handle asynchronously so early low priority requests don't get scheduled before later high priority ones.
InspectorInstrumentation::didScheduleResourceRequest(resourceLoader->frameLoader() ? resourceLoader->frameLoader()->frame()->document() : 0, resourceLoader->url());
scheduleServePendingRequests();
}
}
void ResourceLoadScheduler::remove(ResourceLoader* resourceLoader)
{
ASSERT(resourceLoader);
HostInformation* host = hostForURL(resourceLoader->url());
if (host)
host->remove(resourceLoader);
scheduleServePendingRequests();
}
void ResourceLoadScheduler::crossOriginRedirectReceived(ResourceLoader* resourceLoader, const KURL& redirectURL)
{
HostInformation* oldHost = hostForURL(resourceLoader->url());
ASSERT(oldHost);
HostInformation* newHost = hostForURL(redirectURL, CreateIfNotFound);
if (oldHost->name() == newHost->name())
return;
newHost->addLoadInProgress(resourceLoader);
oldHost->remove(resourceLoader);
}
void ResourceLoadScheduler::servePendingRequests(Priority minimumPriority)
{
LOG(ResourceLoading, "ResourceLoadScheduler::servePendingRequests. m_isSuspendingPendingRequests=%d", m_isSuspendingPendingRequests);
if (m_isSuspendingPendingRequests)
return;
m_requestTimer.stop();
servePendingRequests(m_nonHTTPProtocolHost, minimumPriority);
Vector<HostInformation*> hostsToServe;
m_hosts.checkConsistency();
HostMap::iterator end = m_hosts.end();
for (HostMap::iterator iter = m_hosts.begin(); iter != end; ++iter)
hostsToServe.append(iter->second);
int size = hostsToServe.size();
for (int i = 0; i < size; ++i) {
HostInformation* host = hostsToServe[i];
if (host->hasRequests())
servePendingRequests(host, minimumPriority);
else
delete m_hosts.take(host->name());
}
}
void ResourceLoadScheduler::servePendingRequests(HostInformation* host, Priority minimumPriority)
{
LOG(ResourceLoading, "ResourceLoadScheduler::servePendingRequests HostInformation.m_name='%s'", host->name().latin1().data());
for (int priority = High; priority >= minimumPriority; --priority) {
HostInformation::RequestQueue& requestsPending = host->requestsPending((Priority) priority);
HostInformation::RequestQueue deferredRequests;
while (!requestsPending.isEmpty()) {
RefPtr<ResourceLoader> resourceLoader = requestsPending.first();
// For named hosts - which are only http(s) hosts - we should always enforce the connection limit.
// For non-named hosts - everything but http(s) - we should only enforce the limit if the document isn't done parsing
// and we don't know all stylesheets yet.
Document* document = resourceLoader->frameLoader() ? resourceLoader->frameLoader()->frame()->document() : 0;
bool shouldLimitRequests = !host->name().isNull() || (document && (document->parsing() || !document->haveStylesheetsLoaded()));
if (shouldLimitRequests && host->limitRequests()) {
while (!deferredRequests.isEmpty())
requestsPending.append(deferredRequests.takeFirst());
return;
}
if (resourceLoader->start())
host->addLoadInProgress(resourceLoader.get());
else
deferredRequests.append(resourceLoader);
requestsPending.removeFirst();
}
requestsPending.swap(deferredRequests);
}
}
void ResourceLoadScheduler::suspendPendingRequests()
{
ASSERT(!m_isSuspendingPendingRequests);
m_isSuspendingPendingRequests = true;
}
void ResourceLoadScheduler::resumePendingRequests()
{
ASSERT(m_isSuspendingPendingRequests);
m_isSuspendingPendingRequests = false;
if (!m_hosts.isEmpty() || m_nonHTTPProtocolHost->hasRequests())
scheduleServePendingRequests();
}
void ResourceLoadScheduler::scheduleServePendingRequests()
{
LOG(ResourceLoading, "ResourceLoadScheduler::scheduleServePendingRequests, m_requestTimer.isActive()=%u", m_requestTimer.isActive());
if (!m_requestTimer.isActive())
m_requestTimer.startOneShot(0);
}
void ResourceLoadScheduler::requestTimerFired(Timer<ResourceLoadScheduler>*)
{
LOG(ResourceLoading, "ResourceLoadScheduler::requestTimerFired\n");
servePendingRequests();
}
#ifndef NDEBUG
void ResourceLoadScheduler::assertLoaderBeingCounted(ResourceLoader* resourceLoader)
{
HostInformation* host = hostForURL(resourceLoader->url());
ASSERT(host);
host->assertLoaderBeingCounted(resourceLoader);
}
void ResourceLoadScheduler::HostInformation::assertLoaderBeingCounted(ResourceLoader* resourceLoader)
{
// If a load is being started, it should be at the front of the highest priority queue
// that actually contains a request.
for (int priority = High; priority >= VeryLow; --priority) {
if (!m_requestsPending[priority].isEmpty()) {
ASSERT(m_requestsPending[priority].first().get() == resourceLoader);
return;
}
}
ASSERT_NOT_REACHED();
}
#endif
ResourceLoadScheduler::HostInformation::HostInformation(const String& name, unsigned maxRequestsInFlight)
: m_name(name)
, m_maxRequestsInFlight(maxRequestsInFlight)
{
}
ResourceLoadScheduler::HostInformation::~HostInformation()
{
ASSERT(m_requestsLoading.isEmpty());
for (unsigned p = 0; p <= High; p++)
ASSERT(m_requestsPending[p].isEmpty());
}
void ResourceLoadScheduler::HostInformation::schedule(ResourceLoader* resourceLoader, Priority priority)
{
m_requestsPending[priority].append(resourceLoader);
}
void ResourceLoadScheduler::HostInformation::addLoadInProgress(ResourceLoader* resourceLoader)
{
LOG(ResourceLoading, "HostInformation '%s' loading '%s'. Current count %d", m_name.latin1().data(), resourceLoader->url().string().latin1().data(), m_requestsLoading.size());
m_requestsLoading.add(resourceLoader);
}
void ResourceLoadScheduler::HostInformation::remove(ResourceLoader* resourceLoader)
{
if (m_requestsLoading.contains(resourceLoader)) {
m_requestsLoading.remove(resourceLoader);
return;
}
for (int priority = High; priority >= VeryLow; --priority) {
RequestQueue::iterator end = m_requestsPending[priority].end();
for (RequestQueue::iterator it = m_requestsPending[priority].begin(); it != end; ++it) {
if (*it == resourceLoader) {
m_requestsPending[priority].remove(it);
return;
}
}
}
}
bool ResourceLoadScheduler::HostInformation::hasRequests() const
{
if (!m_requestsLoading.isEmpty())
return true;
for (unsigned p = 0; p <= High; p++) {
if (!m_requestsPending[p].isEmpty())
return true;
}
return false;
}
} // namespace WebCore
/*
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved.
Copyright (C) 2010 Google Inc. All rights reserved.