Chromium Code Reviews| 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 <stdint.h> | 7 #include <stdint.h> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 347 | 347 |
| 348 // Each client represents a tab. | 348 // Each client represents a tab. |
| 349 class ResourceScheduler::Client { | 349 class ResourceScheduler::Client { |
| 350 public: | 350 public: |
| 351 explicit Client(bool priority_requests_delayable) | 351 explicit Client(bool priority_requests_delayable) |
| 352 : is_loaded_(false), | 352 : is_loaded_(false), |
| 353 has_html_body_(false), | 353 has_html_body_(false), |
| 354 using_spdy_proxy_(false), | 354 using_spdy_proxy_(false), |
| 355 in_flight_delayable_count_(0), | 355 in_flight_delayable_count_(0), |
| 356 total_layout_blocking_count_(0), | 356 total_layout_blocking_count_(0), |
| 357 priority_requests_delayable_(priority_requests_delayable) {} | 357 priority_requests_delayable_(priority_requests_delayable), |
| 358 has_pending_start_task_(false), | |
| 359 weak_ptr_factory_(this) {} | |
| 358 | 360 |
| 359 ~Client() {} | 361 ~Client() {} |
| 360 | 362 |
| 361 void ScheduleRequest(net::URLRequest* url_request, | 363 void ScheduleRequest(net::URLRequest* url_request, |
| 362 ScheduledResourceRequest* request) { | 364 ScheduledResourceRequest* request) { |
| 363 SetRequestAttributes(request, DetermineRequestAttributes(request)); | 365 SetRequestAttributes(request, DetermineRequestAttributes(request)); |
| 364 if (ShouldStartRequest(request) == START_REQUEST) { | 366 if (ShouldStartRequest(request) == START_REQUEST) { |
| 365 // New requests can be started synchronously without issue. | 367 // New requests can be started synchronously without issue. |
| 366 StartRequest(request, START_SYNC, RequestStartTrigger::NONE); | 368 StartRequest(request, START_SYNC, RequestStartTrigger::NONE); |
| 367 } else { | 369 } else { |
| 368 pending_requests_.Insert(request); | 370 pending_requests_.Insert(request); |
| 369 } | 371 } |
| 370 } | 372 } |
| 371 | 373 |
| 372 void RemoveRequest(ScheduledResourceRequest* request) { | 374 void RemoveRequest(ScheduledResourceRequest* request) { |
| 373 if (pending_requests_.IsQueued(request)) { | 375 if (pending_requests_.IsQueued(request)) { |
| 374 pending_requests_.Erase(request); | 376 pending_requests_.Erase(request); |
| 375 DCHECK(!base::ContainsKey(in_flight_requests_, request)); | 377 DCHECK(!base::ContainsKey(in_flight_requests_, request)); |
| 376 } else { | 378 } else { |
| 377 EraseInFlightRequest(request); | 379 EraseInFlightRequest(request); |
| 378 | 380 |
| 379 // Removing this request may have freed up another to load. | 381 // Removing this request may have freed up another to load. |
| 380 LoadAnyStartablePendingRequests( | 382 ScheduleLoadAnyStartablePendingRequests( |
| 381 has_html_body_ | 383 has_html_body_ ? RequestStartTrigger::COMPLETION_POST_BODY |
| 382 ? RequestStartTrigger::COMPLETION_POST_BODY | 384 : RequestStartTrigger::COMPLETION_PRE_BODY); |
| 383 : RequestStartTrigger::COMPLETION_PRE_BODY); | |
| 384 } | 385 } |
| 385 } | 386 } |
| 386 | 387 |
| 387 RequestSet StartAndRemoveAllRequests() { | 388 RequestSet StartAndRemoveAllRequests() { |
| 388 // First start any pending requests so that they will be moved into | 389 // First start any pending requests so that they will be moved into |
| 389 // in_flight_requests_. This may exceed the limits | 390 // in_flight_requests_. This may exceed the limits |
| 390 // kDefaultMaxNumDelayableRequestsPerClient and | 391 // kDefaultMaxNumDelayableRequestsPerClient and |
| 391 // kMaxNumDelayableRequestsPerHostPerClient, so this method must not do | 392 // kMaxNumDelayableRequestsPerHostPerClient, so this method must not do |
| 392 // anything that depends on those limits before calling | 393 // anything that depends on those limits before calling |
| 393 // ClearInFlightRequests() below. | 394 // ClearInFlightRequests() below. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 446 DCHECK(base::ContainsKey(in_flight_requests_, request)); | 447 DCHECK(base::ContainsKey(in_flight_requests_, request)); |
| 447 // Request has already started. | 448 // Request has already started. |
| 448 return; | 449 return; |
| 449 } | 450 } |
| 450 | 451 |
| 451 pending_requests_.Erase(request); | 452 pending_requests_.Erase(request); |
| 452 pending_requests_.Insert(request); | 453 pending_requests_.Insert(request); |
| 453 | 454 |
| 454 if (new_priority_params.priority > old_priority_params.priority) { | 455 if (new_priority_params.priority > old_priority_params.priority) { |
| 455 // Check if this request is now able to load at its new priority. | 456 // Check if this request is now able to load at its new priority. |
| 456 LoadAnyStartablePendingRequests( | 457 ScheduleLoadAnyStartablePendingRequests( |
| 457 RequestStartTrigger::REQUEST_REPRIORITIZED); | 458 RequestStartTrigger::REQUEST_REPRIORITIZED); |
| 458 } | 459 } |
| 459 } | 460 } |
| 460 | 461 |
| 461 private: | 462 private: |
| 462 enum ShouldStartReqResult { | 463 enum ShouldStartReqResult { |
| 463 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, | 464 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, |
| 464 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, | 465 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, |
| 465 START_REQUEST, | 466 START_REQUEST, |
| 466 }; | 467 }; |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 712 // Block the request if at least one request is in flight and the | 713 // Block the request if at least one request is in flight and the |
| 713 // number of in-flight delayable requests has hit the configured | 714 // number of in-flight delayable requests has hit the configured |
| 714 // limit. | 715 // limit. |
| 715 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | 716 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; |
| 716 } | 717 } |
| 717 } | 718 } |
| 718 | 719 |
| 719 return START_REQUEST; | 720 return START_REQUEST; |
| 720 } | 721 } |
| 721 | 722 |
| 723 // It is common for a burst of messages to come from the renderer which | |
| 724 // trigger starting pending requests. Naively, this would result in O(n*m) | |
| 725 // behavior for n pending requests and m <= n messages, as | |
| 726 // LoadAnyStartablePendingRequest is O(n) for n pending requests. To solve | |
| 727 // this, just post a task to the end of the queue to call the method, | |
| 728 // coalescing the m messages into a single call to | |
| 729 // LoadAnyStartablePendingRequests. | |
| 730 // TODO(csharrison): Reconsider this if IPC batching becomes an easy to use | |
| 731 // pattern. | |
| 732 void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) { | |
| 733 if (has_pending_start_task_) | |
| 734 return; | |
| 735 has_pending_start_task_ = true; | |
| 736 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 737 FROM_HERE, base::Bind(&Client::LoadAnyStartablePendingRequests, | |
| 738 weak_ptr_factory_.GetWeakPtr(), trigger)); | |
|
kinuko
2017/02/06 20:57:14
This changes when we actually triggers startable r
Charlie Harrison
2017/02/06 21:24:29
This is a valid concern. We currently "schedule" t
| |
| 739 } | |
| 740 | |
| 722 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) { | 741 void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) { |
| 723 // We iterate through all the pending requests, starting with the highest | 742 // We iterate through all the pending requests, starting with the highest |
| 724 // priority one. For each entry, one of three things can happen: | 743 // priority one. For each entry, one of three things can happen: |
| 725 // 1) We start the request, remove it from the list, and keep checking. | 744 // 1) We start the request, remove it from the list, and keep checking. |
| 726 // 2) We do NOT start the request, but ShouldStartRequest() signals us that | 745 // 2) We do NOT start the request, but ShouldStartRequest() signals us that |
| 727 // there may be room for other requests, so we keep checking and leave | 746 // there may be room for other requests, so we keep checking and leave |
| 728 // the previous request still in the list. | 747 // the previous request still in the list. |
| 729 // 3) We do not start the request, same as above, but StartRequest() tells | 748 // 3) We do not start the request, same as above, but StartRequest() tells |
| 730 // us there's no point in checking any further requests. | 749 // us there's no point in checking any further requests. |
| 750 has_pending_start_task_ = false; | |
| 731 RequestQueue::NetQueue::iterator request_iter = | 751 RequestQueue::NetQueue::iterator request_iter = |
| 732 pending_requests_.GetNextHighestIterator(); | 752 pending_requests_.GetNextHighestIterator(); |
| 733 | 753 |
| 734 while (request_iter != pending_requests_.End()) { | 754 while (request_iter != pending_requests_.End()) { |
| 735 ScheduledResourceRequest* request = *request_iter; | 755 ScheduledResourceRequest* request = *request_iter; |
| 736 ShouldStartReqResult query_result = ShouldStartRequest(request); | 756 ShouldStartReqResult query_result = ShouldStartRequest(request); |
| 737 | 757 |
| 738 if (query_result == START_REQUEST) { | 758 if (query_result == START_REQUEST) { |
| 739 pending_requests_.Erase(request); | 759 pending_requests_.Erase(request); |
| 740 StartRequest(request, START_ASYNC, trigger); | 760 StartRequest(request, START_ASYNC, trigger); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 764 RequestQueue pending_requests_; | 784 RequestQueue pending_requests_; |
| 765 RequestSet in_flight_requests_; | 785 RequestSet in_flight_requests_; |
| 766 // The number of delayable in-flight requests. | 786 // The number of delayable in-flight requests. |
| 767 size_t in_flight_delayable_count_; | 787 size_t in_flight_delayable_count_; |
| 768 // The number of layout-blocking in-flight requests. | 788 // The number of layout-blocking in-flight requests. |
| 769 size_t total_layout_blocking_count_; | 789 size_t total_layout_blocking_count_; |
| 770 | 790 |
| 771 // True if requests to servers that support priorities (e.g., H2/QUIC) can | 791 // True if requests to servers that support priorities (e.g., H2/QUIC) can |
| 772 // be delayed. | 792 // be delayed. |
| 773 bool priority_requests_delayable_; | 793 bool priority_requests_delayable_; |
| 794 | |
| 795 bool has_pending_start_task_; | |
| 796 | |
| 797 base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_; | |
| 774 }; | 798 }; |
| 775 | 799 |
| 776 ResourceScheduler::ResourceScheduler() | 800 ResourceScheduler::ResourceScheduler() |
| 777 : priority_requests_delayable_( | 801 : priority_requests_delayable_( |
| 778 base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {} | 802 base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {} |
| 779 | 803 |
| 780 ResourceScheduler::~ResourceScheduler() { | 804 ResourceScheduler::~ResourceScheduler() { |
| 781 DCHECK(unowned_requests_.empty()); | 805 DCHECK(unowned_requests_.empty()); |
| 782 DCHECK(client_map_.empty()); | 806 DCHECK(client_map_.empty()); |
| 783 } | 807 } |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 964 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, | 988 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, |
| 965 new_priority_params); | 989 new_priority_params); |
| 966 } | 990 } |
| 967 | 991 |
| 968 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 992 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
| 969 int child_id, int route_id) { | 993 int child_id, int route_id) { |
| 970 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 994 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
| 971 } | 995 } |
| 972 | 996 |
| 973 } // namespace content | 997 } // namespace content |
| OLD | NEW |