NetworkResourceLoadScheduler.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #include "config.h"
  2. #include "NetworkResourceLoadScheduler.h"
  3. #include "HostRecord.h"
  4. #include "Logging.h"
  5. #include "NetworkProcess.h"
  6. #include "NetworkResourceLoadParameters.h"
  7. #include "NetworkResourceLoader.h"
  8. #include <wtf/MainThread.h>
  9. #include <wtf/text/CString.h>
  10. #if ENABLE(NETWORK_PROCESS)
  11. using namespace WebCore;
  12. namespace WebKit {
  13. static const unsigned maxRequestsInFlightForNonHTTPProtocols = 20;
  14. NetworkResourceLoadScheduler::NetworkResourceLoadScheduler()
  15. : m_nonHTTPProtocolHost(HostRecord::create(String(), maxRequestsInFlightForNonHTTPProtocols))
  16. , m_requestTimer(this, &NetworkResourceLoadScheduler::requestTimerFired)
  17. {
  18. platformInitializeMaximumHTTPConnectionCountPerHost();
  19. }
  20. void NetworkResourceLoadScheduler::scheduleServePendingRequests()
  21. {
  22. if (!m_requestTimer.isActive())
  23. m_requestTimer.startOneShot(0);
  24. }
  25. void NetworkResourceLoadScheduler::requestTimerFired(WebCore::Timer<NetworkResourceLoadScheduler>*)
  26. {
  27. servePendingRequests();
  28. }
  29. void NetworkResourceLoadScheduler::scheduleLoader(PassRefPtr<NetworkResourceLoader> loader)
  30. {
  31. ResourceLoadPriority priority = loader->priority();
  32. const ResourceRequest& resourceRequest = loader->request();
  33. LOG(NetworkScheduling, "(NetworkProcess) NetworkResourceLoadScheduler::scheduleLoader resource '%s'", resourceRequest.url().string().utf8().data());
  34. HostRecord* host = hostForURL(resourceRequest.url(), CreateIfNotFound);
  35. bool hadRequests = host->hasRequests();
  36. host->scheduleResourceLoader(loader);
  37. if (priority > ResourceLoadPriorityLow || !resourceRequest.url().protocolIsInHTTPFamily() || (priority == ResourceLoadPriorityLow && !hadRequests)) {
  38. // Try to request important resources immediately.
  39. host->servePendingRequests(priority);
  40. return;
  41. }
  42. // Handle asynchronously so early low priority requests don't get scheduled before later high priority ones.
  43. scheduleServePendingRequests();
  44. }
  45. HostRecord* NetworkResourceLoadScheduler::hostForURL(const WebCore::KURL& url, CreateHostPolicy createHostPolicy)
  46. {
  47. if (!url.protocolIsInHTTPFamily())
  48. return m_nonHTTPProtocolHost.get();
  49. m_hosts.checkConsistency();
  50. String hostName = url.host();
  51. HostRecord* host = m_hosts.get(hostName);
  52. if (!host && createHostPolicy == CreateIfNotFound) {
  53. RefPtr<HostRecord> newHost = HostRecord::create(hostName, m_maxRequestsInFlightPerHost);
  54. host = newHost.get();
  55. m_hosts.add(hostName, newHost.release());
  56. }
  57. return host;
  58. }
  59. void NetworkResourceLoadScheduler::removeLoader(NetworkResourceLoader* loader)
  60. {
  61. ASSERT(isMainThread());
  62. ASSERT(loader);
  63. LOG(NetworkScheduling, "(NetworkProcess) NetworkResourceLoadScheduler::removeLoadIdentifier removing loader %s", loader->request().url().string().utf8().data());
  64. HostRecord* host = loader->hostRecord();
  65. // Due to a race condition the WebProcess might have messaged the NetworkProcess to remove this identifier
  66. // after the NetworkProcess has already removed it internally.
  67. // In this situation we might not have a HostRecord to clean up.
  68. if (host)
  69. host->removeLoader(loader);
  70. scheduleServePendingRequests();
  71. }
  72. void NetworkResourceLoadScheduler::receivedRedirect(NetworkResourceLoader* loader, const WebCore::KURL& redirectURL)
  73. {
  74. ASSERT(isMainThread());
  75. LOG(NetworkScheduling, "(NetworkProcess) NetworkResourceLoadScheduler::receivedRedirect loader originally for '%s' redirected to '%s'", loader->request().url().string().utf8().data(), redirectURL.string().utf8().data());
  76. HostRecord* oldHost = loader->hostRecord();
  77. // The load may have been cancelled while the message was in flight from network thread to main thread.
  78. if (!oldHost)
  79. return;
  80. HostRecord* newHost = hostForURL(redirectURL, CreateIfNotFound);
  81. if (oldHost->name() == newHost->name())
  82. return;
  83. oldHost->removeLoader(loader);
  84. newHost->addLoaderInProgress(loader);
  85. }
  86. void NetworkResourceLoadScheduler::servePendingRequests(ResourceLoadPriority minimumPriority)
  87. {
  88. LOG(NetworkScheduling, "(NetworkProcess) NetworkResourceLoadScheduler::servePendingRequests Serving requests for up to %i hosts with minimum priority %i", m_hosts.size(), minimumPriority);
  89. m_requestTimer.stop();
  90. m_nonHTTPProtocolHost->servePendingRequests(minimumPriority);
  91. m_hosts.checkConsistency();
  92. Vector<RefPtr<HostRecord>> hostsToServe;
  93. copyValuesToVector(m_hosts, hostsToServe);
  94. size_t size = hostsToServe.size();
  95. for (size_t i = 0; i < size; ++i) {
  96. HostRecord* host = hostsToServe[i].get();
  97. if (host->hasRequests())
  98. host->servePendingRequests(minimumPriority);
  99. else
  100. m_hosts.remove(host->name());
  101. }
  102. }
  103. static bool removeScheduledLoadersCalled = false;
  104. void NetworkResourceLoadScheduler::removeScheduledLoaders(void* context)
  105. {
  106. ASSERT(isMainThread());
  107. ASSERT(removeScheduledLoadersCalled);
  108. NetworkResourceLoadScheduler* scheduler = static_cast<NetworkResourceLoadScheduler*>(context);
  109. scheduler->removeScheduledLoaders();
  110. }
  111. void NetworkResourceLoadScheduler::removeScheduledLoaders()
  112. {
  113. Vector<RefPtr<NetworkResourceLoader>> loadersToRemove;
  114. {
  115. MutexLocker locker(m_loadersToRemoveMutex);
  116. loadersToRemove = m_loadersToRemove;
  117. m_loadersToRemove.clear();
  118. removeScheduledLoadersCalled = false;
  119. }
  120. for (size_t i = 0; i < loadersToRemove.size(); ++i)
  121. removeLoader(loadersToRemove[i].get());
  122. }
  123. void NetworkResourceLoadScheduler::scheduleRemoveLoader(NetworkResourceLoader* loader)
  124. {
  125. MutexLocker locker(m_loadersToRemoveMutex);
  126. m_loadersToRemove.append(loader);
  127. if (!removeScheduledLoadersCalled) {
  128. removeScheduledLoadersCalled = true;
  129. callOnMainThread(NetworkResourceLoadScheduler::removeScheduledLoaders, this);
  130. }
  131. }
  132. uint64_t NetworkResourceLoadScheduler::hostsPendingCount() const
  133. {
  134. uint64_t count = m_nonHTTPProtocolHost->pendingRequestCount() ? 1 : 0;
  135. HostMap::const_iterator end = m_hosts.end();
  136. for (HostMap::const_iterator i = m_hosts.begin(); i != end; ++i) {
  137. if (i->value->pendingRequestCount())
  138. ++count;
  139. }
  140. return count;
  141. }
  142. uint64_t NetworkResourceLoadScheduler::loadsPendingCount() const
  143. {
  144. uint64_t count = m_nonHTTPProtocolHost->pendingRequestCount();
  145. HostMap::const_iterator end = m_hosts.end();
  146. for (HostMap::const_iterator i = m_hosts.begin(); i != end; ++i)
  147. count += i->value->pendingRequestCount();
  148. return count;
  149. }
  150. uint64_t NetworkResourceLoadScheduler::hostsActiveCount() const
  151. {
  152. uint64_t count = 0;
  153. if (m_nonHTTPProtocolHost->activeLoadCount())
  154. count = 1;
  155. HostMap::const_iterator end = m_hosts.end();
  156. for (HostMap::const_iterator i = m_hosts.begin(); i != end; ++i) {
  157. if (i->value->activeLoadCount())
  158. ++count;
  159. }
  160. return count;
  161. }
  162. uint64_t NetworkResourceLoadScheduler::loadsActiveCount() const
  163. {
  164. uint64_t count = m_nonHTTPProtocolHost->activeLoadCount();
  165. HostMap::const_iterator end = m_hosts.end();
  166. for (HostMap::const_iterator i = m_hosts.begin(); i != end; ++i)
  167. count += i->value->activeLoadCount();
  168. return count;
  169. }
  170. } // namespace WebKit
  171. #endif // ENABLE(NETWORK_PROCESS)