12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/resource_scheduler.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/common/resource_messages.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/resource_message_delegate.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/resource_controller.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/resource_request_info.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/resource_throttle.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_message_macros.h" 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/base/host_port_pair.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/load_flags.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/request_priority.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/http/http_server_properties.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_request.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/url_request/url_request_context.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content { 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const size_t kMaxNumDelayableRequestsPerClient = 10; 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A thin wrapper around net::PriorityQueue that deals with 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ScheduledResourceRequests instead of PriorityQueue::Pointers. 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ResourceScheduler::RequestQueue { 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RequestQueue() : queue_(net::NUM_PRIORITIES) {} 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~RequestQueue() {} 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Adds |request| to the queue with given |priority|. 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Insert(ScheduledResourceRequest* request, 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::RequestPriority priority) { 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!ContainsKey(pointers_, request)); 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NetQueue::Pointer pointer = queue_.Insert(request, priority); 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pointers_[request] = pointer; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Removes |request| from the queue. 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Erase(ScheduledResourceRequest* request) { 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PointerMap::iterator it = pointers_.find(request); 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(it != pointers_.end()); 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) queue_.Erase(it->second); 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pointers_.erase(it); 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Returns the highest priority request that's queued, or NULL if none are. 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScheduledResourceRequest* FirstMax() { 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return queue_.FirstMax().value(); 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Returns true if |request| is queued. 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool IsQueued(ScheduledResourceRequest* request) const { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ContainsKey(pointers_, request); 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Returns true if no requests are queued. 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool IsEmpty() const { return queue_.size() == 0; } 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typedef net::PriorityQueue<ScheduledResourceRequest*> NetQueue; 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typedef std::map<ScheduledResourceRequest*, NetQueue::Pointer> PointerMap; 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NetQueue queue_; 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PointerMap pointers_; 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is the handle we return to the ResourceDispatcherHostImpl so it can 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// interact with the request. 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ResourceScheduler::ScheduledResourceRequest 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : public ResourceMessageDelegate, 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public ResourceThrottle { 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScheduledResourceRequest(const ClientId& client_id, 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLRequest* request, 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ResourceScheduler* scheduler) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : ResourceMessageDelegate(request), 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client_id_(client_id), 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_(request), 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ready_(false), 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) deferred_(false), 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scheduler_(scheduler) { 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~ScheduledResourceRequest() { 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scheduler_->RemoveRequest(this); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Start() { 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ready_ = true; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (deferred_ && request_->status().is_success()) { 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) deferred_ = false; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) controller()->Resume(); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ClientId& client_id() const { return client_id_; } 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLRequest* url_request() { return request_; } 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const net::URLRequest* url_request() const { return request_; } 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // ResourceMessageDelegate interface: 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool OnMessageReceived(const IPC::Message& message, 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool* message_was_ok) OVERRIDE { 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool handled = true; 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_BEGIN_MESSAGE_MAP_EX(ScheduledResourceRequest, message, *message_was_ok) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC_END_MESSAGE_MAP_EX() 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return handled; 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // ResourceThrottle interface: 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void WillStartRequest(bool* defer) OVERRIDE { 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) deferred_ = *defer = !ready_; 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void DidChangePriority(int request_id, net::RequestPriority new_priority) { 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scheduler_->ReprioritizeRequest(this, new_priority); 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientId client_id_; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLRequest* request_; 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool ready_; 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool deferred_; 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ResourceScheduler* scheduler_; 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Each client represents a tab. 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct ResourceScheduler::Client { 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client() : has_body(false) {} 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~Client() {} 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool has_body; 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RequestQueue pending_requests; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RequestSet in_flight_requests; 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourceScheduler::ResourceScheduler() { 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourceScheduler::~ResourceScheduler() { 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(unowned_requests_.empty()); 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(client_map_.empty()); 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int child_id, 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int route_id, 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::URLRequest* url_request) { 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientId client_id = MakeClientId(child_id, route_id); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<ScheduledResourceRequest> request( 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new ScheduledResourceRequest(client_id, url_request, this)); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientMap::iterator it = client_map_.find(client_id); 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (it == client_map_.end()) { 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // There are several ways this could happen: 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 1. <a ping> requests don't have a route_id. 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 2. Most unittests don't send the IPCs needed to register Clients. 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 3. The tab is closed while a RequestResource IPC is in flight. 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unowned_requests_.insert(request.get()); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request->Start(); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return request.PassAs<ResourceThrottle>(); 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client* client = it->second; 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ShouldStartRequest(request.get(), client)) { 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StartRequest(request.get(), client); 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->pending_requests.Insert(request.get(), url_request->priority()); 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return request.PassAs<ResourceThrottle>(); 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ContainsKey(unowned_requests_, request)) { 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unowned_requests_.erase(request); 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientMap::iterator client_it = client_map_.find(request->client_id()); 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (client_it == client_map_.end()) { 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client* client = client_it->second; 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (client->pending_requests.IsQueued(request)) { 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->pending_requests.Erase(request); 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!ContainsKey(client->in_flight_requests, request)); 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t erased = client->in_flight_requests.erase(request); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(erased); 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Removing this request may have freed up another to load. 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LoadAnyStartablePendingRequests(client); 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::OnClientCreated(int child_id, int route_id) { 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientId client_id = MakeClientId(child_id, route_id); 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!ContainsKey(client_map_, client_id)); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client_map_[client_id] = new Client; 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::OnClientDeleted(int child_id, int route_id) { 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientId client_id = MakeClientId(child_id, route_id); 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ContainsKey(client_map_, client_id)); 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientMap::iterator it = client_map_.find(client_id); 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client* client = it->second; 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // FYI, ResourceDispatcherHost cancels all of the requests after this function 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // is called. It should end up canceling all of the requests except for a 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // cross-renderer navigation. 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (RequestSet::iterator it = client->in_flight_requests.begin(); 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != client->in_flight_requests.end(); ++it) { 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unowned_requests_.insert(*it); 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->in_flight_requests.clear(); 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete client; 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client_map_.erase(it); 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::OnNavigate(int child_id, int route_id) { 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientId client_id = MakeClientId(child_id, route_id); 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientMap::iterator it = client_map_.find(client_id); 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (it == client_map_.end()) { 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The client was likely deleted shortly before we received this IPC. 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client* client = it->second; 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->has_body = false; 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::OnWillInsertBody(int child_id, int route_id) { 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientId client_id = MakeClientId(child_id, route_id); 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientMap::iterator it = client_map_.find(client_id); 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (it == client_map_.end()) { 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The client was likely deleted shortly before we received this IPC. 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client* client = it->second; 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->has_body = false; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!client->has_body) { 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->has_body = true; 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LoadAnyStartablePendingRequests(client); 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::StartRequest(ScheduledResourceRequest* request, 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client* client) { 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->in_flight_requests.insert(request); 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request->Start(); 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::RequestPriority new_priority) { 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::RequestPriority old_priority = request->url_request()->priority(); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_NE(new_priority, old_priority); 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request->url_request()->SetPriority(new_priority); 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientMap::iterator client_it = client_map_.find(request->client_id()); 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (client_it == client_map_.end()) { 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The client was likely deleted shortly before we received this IPC. 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client *client = client_it->second; 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!client->pending_requests.IsQueued(request)) { 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ContainsKey(client->in_flight_requests, request)); 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Request has already started. 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->pending_requests.Erase(request); 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->pending_requests.Insert(request, request->url_request()->priority()); 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (new_priority > old_priority) { 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check if this request is now able to load at its new priority. 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LoadAnyStartablePendingRequests(client); 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceScheduler::LoadAnyStartablePendingRequests(Client* client) { 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (!client->pending_requests.IsEmpty()) { 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScheduledResourceRequest* request = client->pending_requests.FirstMax(); 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ShouldStartRequest(request, client)) { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->pending_requests.Erase(request); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StartRequest(request, client); 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)size_t ResourceScheduler::GetNumDelayableRequestsInFlight( 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client* client) const { 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t count = 0; 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (RequestSet::iterator it = client->in_flight_requests.begin(); 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != client->in_flight_requests.end(); ++it) { 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((*it)->url_request()->priority() < net::LOW) { 316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::HttpServerProperties& http_server_properties = 317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *(*it)->url_request()->context()->http_server_properties(); 318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!http_server_properties.SupportsSpdy( 319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::HostPortPair::FromURL((*it)->url_request()->url()))) { 320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ++count; 321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return count; 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ShouldStartRequest is the main scheduling algorithm. 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Requests are categorized into two categories: 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 1. Immediately issued requests, which are: 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// * Higher priority requests (>= net::LOW). 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// * Synchronous requests. 335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// * Requests to SPDY-capable origin servers. 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 2. The remainder are delayable requests, which follow these rules: 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// * If no high priority requests are in flight, start loading low priority 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// requests. 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// * Once the renderer has a <body>, start loading delayable requests. 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// * Never exceed 10 delayable requests in flight per client. 343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// * Prior to <body>, allow one delayable request to load at a time. 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ResourceScheduler::ShouldStartRequest(ScheduledResourceRequest* request, 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Client* client) const { 346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const net::URLRequest& url_request = *request->url_request(); 347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const net::HttpServerProperties& http_server_properties = 348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *url_request.context()->http_server_properties(); 349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(willchan): We should really improve this algorithm as described in 351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // crbug.com/164101. Also, theoretically we should not count a SPDY request 352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // against the delayable requests limit. 353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool origin_supports_spdy = http_server_properties.SupportsSpdy( 354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) net::HostPortPair::FromURL(url_request.url())); 355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (url_request.priority() >= net::LOW || 357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) !ResourceRequestInfo::ForRequest(&url_request)->IsAsync() || 358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) origin_supports_spdy) { 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t num_delayable_requests_in_flight = 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetNumDelayableRequestsInFlight(client); 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (num_delayable_requests_in_flight >= kMaxNumDelayableRequestsPerClient) { 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool have_immediate_requests_in_flight = 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client->in_flight_requests.size() > num_delayable_requests_in_flight; 370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (have_immediate_requests_in_flight && !client->has_body && 371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch num_delayable_requests_in_flight != 0) { 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int child_id, int route_id) { 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace content 384