Chromium Code Reviews| Index: content/browser/loader/resource_scheduler.cc |
| diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc |
| index ef95f2a34f9cb79b962246ed847e81e70f2ef110..8d510f34849a8d4049523f2cdf6f7bd42566a3af 100644 |
| --- a/content/browser/loader/resource_scheduler.cc |
| +++ b/content/browser/loader/resource_scheduler.cc |
| @@ -16,6 +16,8 @@ |
| namespace content { |
| +static const int kMaxNumLowPriorityRequestsPerClient = 10; |
| + |
| class ResourceScheduler::ScheduledResourceRequest |
| : public ResourceMessageDelegate, |
| public ResourceThrottle { |
| @@ -43,6 +45,18 @@ class ResourceScheduler::ScheduledResourceRequest |
| } |
| } |
| + // |queue_pointer| keeps track of the position of |this| in its client's |
| + // |pending_requests| queue. |
| + ResourceScheduler::RequestQueue::Pointer queue_pointer() { |
| + return queue_pointer_; |
| + } |
| + void set_queue_pointer(ResourceScheduler::RequestQueue::Pointer pointer) { |
| + queue_pointer_ = pointer; |
| + } |
| + void clear_queue_pointer() { |
| + queue_pointer_.Reset(); |
| + } |
| + |
| const ClientId& client_id() const { return client_id_; } |
| const net::URLRequest& url_request() const { return *request_; } |
| @@ -65,9 +79,9 @@ class ResourceScheduler::ScheduledResourceRequest |
| void DidChangePriority(int request_id, net::RequestPriority new_priority) { |
| net::RequestPriority old_priority = request_->priority(); |
| - request_->set_priority(new_priority); |
| - if (new_priority > old_priority) { |
| - Start(); |
| + if (new_priority != old_priority) { |
|
willchan no longer on Chromium
2013/03/18 07:30:33
When is this ever false? Sounds like a renderer bu
James Simonsen
2013/03/18 23:50:13
Agreed. Done.
|
| + request_->set_priority(new_priority); |
| + scheduler_->ReprioritizeRequest(this); |
| } |
| } |
| @@ -76,6 +90,7 @@ class ResourceScheduler::ScheduledResourceRequest |
| bool ready_; |
| bool deferred_; |
| ResourceScheduler* scheduler_; |
| + ResourceScheduler::RequestQueue::Pointer queue_pointer_; |
| DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); |
| }; |
| @@ -86,7 +101,7 @@ ResourceScheduler::ResourceScheduler() { |
| ResourceScheduler::~ResourceScheduler() { |
| for (ClientMap::iterator it ALLOW_UNUSED = client_map_.begin(); |
| it != client_map_.end(); ++it) { |
| - DCHECK(it->second->pending_requests.empty()); |
| + DCHECK(!it->second->pending_requests.size()); |
| DCHECK(it->second->in_flight_requests.empty()); |
| } |
| DCHECK(unowned_requests_.empty()); |
| @@ -114,17 +129,12 @@ scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( |
| } |
| Client* client = it->second; |
| - |
| - bool is_synchronous = (url_request->load_flags() & net::LOAD_IGNORE_LIMITS) == |
| - net::LOAD_IGNORE_LIMITS; |
| - bool is_low_priority = |
| - url_request->priority() < net::LOW && !is_synchronous; |
| - |
| - if (is_low_priority && !client->in_flight_requests.empty() && |
| - !client->has_body) { |
| - client->pending_requests.push_back(request.get()); |
| - } else { |
| + if (ShouldStartRequest(request.get(), client)) { |
| StartRequest(request.get(), client); |
| + } else { |
| + RequestQueue::Pointer pointer = client->pending_requests.Insert( |
| + request.get(), url_request->priority()); |
| + request->set_queue_pointer(pointer); |
| } |
| return request.PassAs<ResourceThrottle>(); |
| } |
| @@ -142,30 +152,18 @@ void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { |
| } |
| Client* client = client_it->second; |
| - RequestSet::iterator request_it = client->in_flight_requests.find(request); |
| - if (request_it == client->in_flight_requests.end()) { |
| - bool removed = false; |
| - RequestQueue::iterator queue_it; |
| - for (queue_it = client->pending_requests.begin(); |
| - queue_it != client->pending_requests.end(); ++queue_it) { |
| - if (*queue_it == request) { |
| - client->pending_requests.erase(queue_it); |
| - removed = true; |
| - break; |
| - } |
| - } |
| - DCHECK(removed); |
| - DCHECK(!ContainsKey(client->in_flight_requests, request)); |
| - } else { |
| + |
| + if (request->queue_pointer().is_null()) { |
| size_t erased = client->in_flight_requests.erase(request); |
| DCHECK(erased); |
| + } else { |
| + client->pending_requests.Erase(request->queue_pointer()); |
| + request->clear_queue_pointer(); |
| + DCHECK(!ContainsKey(client->in_flight_requests, request)); |
| } |
| - if (client->in_flight_requests.empty()) { |
| - // Since the network is now idle, we may as well load some of the low |
| - // priority requests. |
| - LoadPendingRequests(client); |
| - } |
| + // Removing this request may have freed up another to load. |
|
willchan no longer on Chromium
2013/03/18 07:30:33
Isn't this only true if we remove an in flight req
James Simonsen
2013/03/18 23:50:13
Done.
|
| + LoadPendingRequests(client); |
| } |
| void ResourceScheduler::OnClientCreated(int child_id, int route_id) { |
| @@ -233,26 +231,93 @@ void ResourceScheduler::StartRequest(ScheduledResourceRequest* request, |
| request->Start(); |
| } |
| +void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request) { |
| + ClientMap::iterator client_it = client_map_.find(request->client_id()); |
| + if (client_it == client_map_.end()) { |
| + // The client was likely deleted shortly before we received this IPC. |
|
willchan no longer on Chromium
2013/03/18 07:30:33
How? The comment for OnClientDeleted() says it hap
James Simonsen
2013/03/18 23:50:13
RenderViewHosts can be deleted by user action on t
willchan no longer on Chromium
2013/03/19 20:53:52
Why are we listening for the signal that the Rende
|
| + return; |
| + } |
| + |
| + Client *client = client_it->second; |
| + if (request->queue_pointer().is_null()) { |
| + DCHECK(ContainsKey(client->in_flight_requests, request)); |
| + // Request has already started. |
|
willchan no longer on Chromium
2013/03/18 07:30:33
But don't we need to call set_priority()? OH, I se
James Simonsen
2013/03/18 23:50:13
Done.
|
| + return; |
| + } |
| + |
| + client->pending_requests.Erase(request->queue_pointer()); |
|
willchan no longer on Chromium
2013/03/18 07:30:33
When I see stuff like this where the caller needs
James Simonsen
2013/03/18 23:50:13
Done.
|
| + RequestQueue::Pointer pointer = client->pending_requests.Insert( |
| + request, request->url_request().priority()); |
| + request->set_queue_pointer(pointer); |
| + |
| + // Check if this request is now able to load at its new priority. |
|
willchan no longer on Chromium
2013/03/18 07:30:33
We only want to do this if the new priority is hig
James Simonsen
2013/03/18 23:50:13
Done.
|
| + LoadPendingRequests(client); |
| +} |
| + |
| void ResourceScheduler::LoadPendingRequests(Client* client) { |
| - while (!client->pending_requests.empty()) { |
| - ScheduledResourceRequest* request = client->pending_requests.front(); |
| - client->pending_requests.erase(client->pending_requests.begin()); |
| - StartRequest(request, client); |
| + while (client->pending_requests.size()) { |
| + ScheduledResourceRequest* request = |
| + client->pending_requests.FirstMax().value(); |
| + if (ShouldStartRequest(request, client)) { |
| + client->pending_requests.Erase(request->queue_pointer()); |
| + request->clear_queue_pointer(); |
| + StartRequest(request, client); |
| + } else { |
| + break; |
| + } |
| } |
| } |
| +int ResourceScheduler::GetNumLowPriorityRequestsInFlight(Client* client) { |
| + int count = 0; |
| + for (RequestSet::iterator it = client->in_flight_requests.begin(); |
| + it != client->in_flight_requests.end(); ++it) { |
| + if ((*it)->url_request().priority() < net::LOW) { |
| + ++count; |
| + } |
| + } |
| + return count; |
| +} |
| + |
| +bool ResourceScheduler::ShouldStartRequest(ScheduledResourceRequest* request, |
|
willchan no longer on Chromium
2013/03/18 07:30:33
Please add a comment here explaining in plain Engl
James Simonsen
2013/03/18 23:50:13
Done.
|
| + Client* client) { |
| + bool is_synchronous = |
|
willchan no longer on Chromium
2013/03/18 07:30:33
I know you're just moving this, but this caught my
James Simonsen
2013/03/18 23:50:13
Done.
|
| + (request->url_request().load_flags() & net::LOAD_IGNORE_LIMITS) == |
| + net::LOAD_IGNORE_LIMITS; |
| + bool is_low_priority = |
|
willchan no longer on Chromium
2013/03/18 07:30:33
Sorry again for nitting you when you're just movin
James Simonsen
2013/03/18 23:50:13
Done.
|
| + request->url_request().priority() < net::LOW && !is_synchronous; |
| + if (!is_low_priority) |
| + return true; |
| + |
| + int num_low_priority_requests_in_flight = |
| + GetNumLowPriorityRequestsInFlight(client); |
| + if (num_low_priority_requests_in_flight >= |
| + kMaxNumLowPriorityRequestsPerClient) { |
| + return false; |
| + } |
| + |
| + int num_high_priority_requests_in_flight = |
|
willchan no longer on Chromium
2013/03/18 07:30:33
You don't need the number, you just need to know i
James Simonsen
2013/03/18 23:50:13
Done.
|
| + client->in_flight_requests.size() - num_low_priority_requests_in_flight; |
| + if (num_high_priority_requests_in_flight && !client->has_body) { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
| int child_id, int route_id) { |
| return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
| } |
| ResourceScheduler::Client::Client() |
| - : has_body(false) { |
| + : has_body(false), |
| + pending_requests(net::NUM_PRIORITIES) { |
| } |
| ResourceScheduler::Client::~Client() { |
| DCHECK(in_flight_requests.empty()); |
| - DCHECK(pending_requests.empty()); |
| + DCHECK(!pending_requests.size()); |
| } |
| } // namespace content |