OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/loader/resource_scheduler.h" | 5 #include "content/browser/loader/resource_scheduler.h" |
6 | 6 |
7 #include "base/stl_util.h" | 7 #include "base/stl_util.h" |
8 #include "content/common/resource_messages.h" | 8 #include "content/common/resource_messages.h" |
9 #include "content/browser/loader/resource_message_delegate.h" | 9 #include "content/browser/loader/resource_message_delegate.h" |
10 #include "content/public/browser/resource_controller.h" | 10 #include "content/public/browser/resource_controller.h" |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
170 ClientId client_id_; | 170 ClientId client_id_; |
171 net::URLRequest* request_; | 171 net::URLRequest* request_; |
172 bool ready_; | 172 bool ready_; |
173 bool deferred_; | 173 bool deferred_; |
174 ResourceScheduler* scheduler_; | 174 ResourceScheduler* scheduler_; |
175 | 175 |
176 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); | 176 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); |
177 }; | 177 }; |
178 | 178 |
179 // Each client represents a tab. | 179 // Each client represents a tab. |
180 struct ResourceScheduler::Client { | 180 struct ResourceScheduler::Client { |
James Simonsen
2014/03/05 02:30:59
This isn't a struct anymore. To keep these methods
| |
181 Client() : has_body(false), using_spdy_proxy(false) {} | 181 Client() |
182 : has_body(false), | |
183 using_spdy_proxy(false), | |
184 total_delayable_count(0) {} | |
182 ~Client() {} | 185 ~Client() {} |
183 | 186 |
184 bool has_body; | 187 bool has_body; |
185 bool using_spdy_proxy; | 188 bool using_spdy_proxy; |
186 RequestQueue pending_requests; | 189 RequestQueue pending_requests; |
187 RequestSet in_flight_requests; | 190 RequestSet in_flight_requests; |
191 size_t total_delayable_count; | |
192 | |
193 bool IsDelayableRequest(ScheduledResourceRequest* request) { | |
194 if (request->url_request()->priority() < net::LOW) { | |
195 net::HostPortPair host_port_pair = | |
196 net::HostPortPair::FromURL(request->url_request()->url()); | |
197 const net::HttpServerProperties& http_server_properties = | |
198 *request->url_request()->context()->http_server_properties(); | |
199 if (!http_server_properties.SupportsSpdy(host_port_pair)) { | |
200 return true; | |
201 } | |
202 } | |
203 return false; | |
204 } | |
205 | |
206 void InsertFlightRequests(ScheduledResourceRequest* request) { | |
James Simonsen
2014/03/05 02:30:59
This should be InsertInFlightRequest().
| |
207 in_flight_requests.insert(request); | |
208 if (IsDelayableRequest(request)) | |
209 total_delayable_count++; | |
210 } | |
211 | |
212 size_t EraseFlightRequests(ScheduledResourceRequest* request) { | |
James Simonsen
2014/03/05 02:30:59
And EraseInFlightRequest().
| |
213 size_t erased = in_flight_requests.erase(request); | |
214 if (in_flight_requests.size() == 0) { | |
215 total_delayable_count = 0; | |
216 } else if (IsDelayableRequest(request)) { | |
217 total_delayable_count--; | |
218 } | |
219 return erased; | |
220 } | |
221 | |
222 void ClearFlightRequests() { | |
James Simonsen
2014/03/05 02:30:59
ClearInFlightRequests()
| |
223 in_flight_requests.clear(); | |
224 total_delayable_count = 0; | |
225 } | |
188 }; | 226 }; |
189 | 227 |
190 ResourceScheduler::ResourceScheduler() { | 228 ResourceScheduler::ResourceScheduler() { |
191 } | 229 } |
192 | 230 |
193 ResourceScheduler::~ResourceScheduler() { | 231 ResourceScheduler::~ResourceScheduler() { |
194 DCHECK(unowned_requests_.empty()); | 232 DCHECK(unowned_requests_.empty()); |
195 DCHECK(client_map_.empty()); | 233 DCHECK(client_map_.empty()); |
196 } | 234 } |
197 | 235 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
235 if (client_it == client_map_.end()) { | 273 if (client_it == client_map_.end()) { |
236 return; | 274 return; |
237 } | 275 } |
238 | 276 |
239 Client* client = client_it->second; | 277 Client* client = client_it->second; |
240 | 278 |
241 if (client->pending_requests.IsQueued(request)) { | 279 if (client->pending_requests.IsQueued(request)) { |
242 client->pending_requests.Erase(request); | 280 client->pending_requests.Erase(request); |
243 DCHECK(!ContainsKey(client->in_flight_requests, request)); | 281 DCHECK(!ContainsKey(client->in_flight_requests, request)); |
244 } else { | 282 } else { |
245 size_t erased = client->in_flight_requests.erase(request); | 283 size_t erased = client->EraseFlightRequests(request); |
246 DCHECK(erased); | 284 DCHECK(erased); |
247 | 285 |
248 // Removing this request may have freed up another to load. | 286 // Removing this request may have freed up another to load. |
249 LoadAnyStartablePendingRequests(client); | 287 LoadAnyStartablePendingRequests(client); |
250 } | 288 } |
251 } | 289 } |
252 | 290 |
253 void ResourceScheduler::OnClientCreated(int child_id, int route_id) { | 291 void ResourceScheduler::OnClientCreated(int child_id, int route_id) { |
254 DCHECK(CalledOnValidThread()); | 292 DCHECK(CalledOnValidThread()); |
255 ClientId client_id = MakeClientId(child_id, route_id); | 293 ClientId client_id = MakeClientId(child_id, route_id); |
(...skipping 12 matching lines...) Expand all Loading... | |
268 | 306 |
269 Client* client = it->second; | 307 Client* client = it->second; |
270 | 308 |
271 // FYI, ResourceDispatcherHost cancels all of the requests after this function | 309 // FYI, ResourceDispatcherHost cancels all of the requests after this function |
272 // is called. It should end up canceling all of the requests except for a | 310 // is called. It should end up canceling all of the requests except for a |
273 // cross-renderer navigation. | 311 // cross-renderer navigation. |
274 for (RequestSet::iterator it = client->in_flight_requests.begin(); | 312 for (RequestSet::iterator it = client->in_flight_requests.begin(); |
275 it != client->in_flight_requests.end(); ++it) { | 313 it != client->in_flight_requests.end(); ++it) { |
276 unowned_requests_.insert(*it); | 314 unowned_requests_.insert(*it); |
277 } | 315 } |
278 client->in_flight_requests.clear(); | 316 client->ClearFlightRequests(); |
279 | 317 |
280 delete client; | 318 delete client; |
281 client_map_.erase(it); | 319 client_map_.erase(it); |
282 } | 320 } |
283 | 321 |
284 void ResourceScheduler::OnNavigate(int child_id, int route_id) { | 322 void ResourceScheduler::OnNavigate(int child_id, int route_id) { |
285 DCHECK(CalledOnValidThread()); | 323 DCHECK(CalledOnValidThread()); |
286 ClientId client_id = MakeClientId(child_id, route_id); | 324 ClientId client_id = MakeClientId(child_id, route_id); |
287 | 325 |
288 ClientMap::iterator it = client_map_.find(client_id); | 326 ClientMap::iterator it = client_map_.find(client_id); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
324 Client* client = client_it->second; | 362 Client* client = client_it->second; |
325 | 363 |
326 if (!client->using_spdy_proxy) { | 364 if (!client->using_spdy_proxy) { |
327 client->using_spdy_proxy = true; | 365 client->using_spdy_proxy = true; |
328 LoadAnyStartablePendingRequests(client); | 366 LoadAnyStartablePendingRequests(client); |
329 } | 367 } |
330 } | 368 } |
331 | 369 |
332 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request, | 370 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request, |
333 Client* client) { | 371 Client* client) { |
334 client->in_flight_requests.insert(request); | 372 client->InsertFlightRequests(request); |
335 request->Start(); | 373 request->Start(); |
336 } | 374 } |
337 | 375 |
338 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, | 376 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, |
339 net::RequestPriority new_priority) { | 377 net::RequestPriority new_priority) { |
340 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { | 378 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { |
341 // We should not be re-prioritizing requests with the | 379 // We should not be re-prioritizing requests with the |
342 // IGNORE_LIMITS flag. | 380 // IGNORE_LIMITS flag. |
343 NOTREACHED(); | 381 NOTREACHED(); |
344 return; | 382 return; |
345 } | 383 } |
346 net::RequestPriority old_priority = request->url_request()->priority(); | 384 net::RequestPriority old_priority = request->url_request()->priority(); |
347 DCHECK_NE(new_priority, old_priority); | 385 DCHECK_NE(new_priority, old_priority); |
348 request->url_request()->SetPriority(new_priority); | 386 request->url_request()->SetPriority(new_priority); |
349 ClientMap::iterator client_it = client_map_.find(request->client_id()); | 387 ClientMap::iterator client_it = client_map_.find(request->client_id()); |
350 if (client_it == client_map_.end()) { | 388 if (client_it == client_map_.end()) { |
351 // The client was likely deleted shortly before we received this IPC. | 389 // The client was likely deleted shortly before we received this IPC. |
352 return; | 390 return; |
353 } | 391 } |
354 | 392 |
355 Client *client = client_it->second; | 393 Client *client = client_it->second; |
356 if (!client->pending_requests.IsQueued(request)) { | 394 if (!client->pending_requests.IsQueued(request)) { |
357 DCHECK(ContainsKey(client->in_flight_requests, request)); | 395 DCHECK(ContainsKey(client->in_flight_requests, request)); |
396 if (new_priority >= net::LOW) { | |
397 if (client->IsDelayableRequest(request)) | |
398 client->total_delayable_count--; | |
James Simonsen
2014/03/05 02:30:59
Please add a unit test that shows the old code was
James Simonsen
2014/03/05 02:30:59
I don't like that total_delayable_count is sometim
| |
399 } | |
358 // Request has already started. | 400 // Request has already started. |
359 return; | 401 return; |
360 } | 402 } |
361 | 403 |
362 client->pending_requests.Erase(request); | 404 client->pending_requests.Erase(request); |
363 client->pending_requests.Insert(request, | 405 client->pending_requests.Insert(request, |
364 request->url_request()->priority()); | 406 request->url_request()->priority()); |
365 | 407 |
366 if (new_priority > old_priority) { | 408 if (new_priority > old_priority) { |
367 // Check if this request is now able to load at its new priority. | 409 // Check if this request is now able to load at its new priority. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
399 } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) { | 441 } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) { |
400 ++request_iter; | 442 ++request_iter; |
401 continue; | 443 continue; |
402 } else { | 444 } else { |
403 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); | 445 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); |
404 break; | 446 break; |
405 } | 447 } |
406 } | 448 } |
407 } | 449 } |
408 | 450 |
409 void ResourceScheduler::GetNumDelayableRequestsInFlight( | 451 size_t ResourceScheduler::GetNumSameHostRequestsInFlight( |
410 Client* client, | 452 Client* client, |
411 const net::HostPortPair& active_request_host, | 453 const net::HostPortPair& active_request_host) const { |
412 size_t* total_delayable, | 454 DCHECK(client != NULL); |
413 size_t* total_for_active_host) const { | |
414 DCHECK(client != NULL && total_delayable != NULL && | |
415 total_for_active_host != NULL); | |
416 | 455 |
417 size_t total_delayable_count = 0; | |
418 size_t same_host_count = 0; | 456 size_t same_host_count = 0; |
419 for (RequestSet::iterator it = client->in_flight_requests.begin(); | 457 for (RequestSet::iterator it = client->in_flight_requests.begin(); |
420 it != client->in_flight_requests.end(); ++it) { | 458 it != client->in_flight_requests.end(); ++it) { |
421 net::HostPortPair host_port_pair = | 459 net::HostPortPair host_port_pair = |
422 net::HostPortPair::FromURL((*it)->url_request()->url()); | 460 net::HostPortPair::FromURL((*it)->url_request()->url()); |
423 | 461 |
424 if (active_request_host.Equals(host_port_pair)) { | 462 if (active_request_host.Equals(host_port_pair)) { |
425 same_host_count++; | 463 same_host_count++; |
426 } | 464 } |
427 | |
428 if ((*it)->url_request()->priority() < net::LOW) { | |
429 const net::HttpServerProperties& http_server_properties = | |
430 *(*it)->url_request()->context()->http_server_properties(); | |
431 | |
432 if (!http_server_properties.SupportsSpdy(host_port_pair)) { | |
433 ++total_delayable_count; | |
434 } | |
435 } | |
436 } | 465 } |
437 *total_delayable = total_delayable_count; | 466 return same_host_count; |
438 *total_for_active_host = same_host_count; | |
439 } | 467 } |
440 | 468 |
441 // ShouldStartRequest is the main scheduling algorithm. | 469 // ShouldStartRequest is the main scheduling algorithm. |
442 // | 470 // |
443 // Requests are categorized into two categories: | 471 // Requests are categorized into two categories: |
444 // | 472 // |
445 // 1. Immediately issued requests, which are: | 473 // 1. Immediately issued requests, which are: |
446 // | 474 // |
447 // * Higher priority requests (>= net::LOW). | 475 // * Higher priority requests (>= net::LOW). |
448 // * Synchronous requests. | 476 // * Synchronous requests. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
483 net::HostPortPair host_port_pair = | 511 net::HostPortPair host_port_pair = |
484 net::HostPortPair::FromURL(url_request.url()); | 512 net::HostPortPair::FromURL(url_request.url()); |
485 | 513 |
486 // TODO(willchan): We should really improve this algorithm as described in | 514 // TODO(willchan): We should really improve this algorithm as described in |
487 // crbug.com/164101. Also, theoretically we should not count a SPDY request | 515 // crbug.com/164101. Also, theoretically we should not count a SPDY request |
488 // against the delayable requests limit. | 516 // against the delayable requests limit. |
489 if (http_server_properties.SupportsSpdy(host_port_pair)) { | 517 if (http_server_properties.SupportsSpdy(host_port_pair)) { |
490 return START_REQUEST; | 518 return START_REQUEST; |
491 } | 519 } |
492 | 520 |
493 size_t num_delayable_requests_in_flight = 0; | 521 size_t num_delayable_requests_in_flight = client->total_delayable_count; |
494 size_t num_requests_in_flight_for_host = 0; | 522 size_t num_requests_in_flight_for_host = |
495 GetNumDelayableRequestsInFlight(client, host_port_pair, | 523 GetNumSameHostRequestsInFlight(client, host_port_pair); |
496 &num_delayable_requests_in_flight, | |
497 &num_requests_in_flight_for_host); | |
498 | 524 |
499 if (num_delayable_requests_in_flight >= kMaxNumDelayableRequestsPerClient) { | 525 if (num_delayable_requests_in_flight >= kMaxNumDelayableRequestsPerClient) { |
500 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | 526 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; |
501 } | 527 } |
502 | 528 |
503 if (num_requests_in_flight_for_host >= kMaxNumDelayableRequestsPerHost) { | 529 if (num_requests_in_flight_for_host >= kMaxNumDelayableRequestsPerHost) { |
504 // There may be other requests for other hosts we'd allow, so keep checking. | 530 // There may be other requests for other hosts we'd allow, so keep checking. |
505 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; | 531 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; |
506 } | 532 } |
507 | 533 |
508 bool have_immediate_requests_in_flight = | 534 bool have_immediate_requests_in_flight = |
509 client->in_flight_requests.size() > num_delayable_requests_in_flight; | 535 client->in_flight_requests.size() > num_delayable_requests_in_flight; |
510 if (have_immediate_requests_in_flight && !client->has_body && | 536 if (have_immediate_requests_in_flight && !client->has_body && |
511 num_delayable_requests_in_flight != 0) { | 537 num_delayable_requests_in_flight != 0) { |
512 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | 538 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; |
513 } | 539 } |
514 | 540 |
515 return START_REQUEST; | 541 return START_REQUEST; |
516 } | 542 } |
517 | 543 |
518 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 544 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
519 int child_id, int route_id) { | 545 int child_id, int route_id) { |
520 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 546 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
521 } | 547 } |
522 | 548 |
523 } // namespace content | 549 } // namespace content |
OLD | NEW |