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 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 NetQueue::iterator GetNextHighestIterator() { | 129 NetQueue::iterator GetNextHighestIterator() { |
130 return queue_.begin(); | 130 return queue_.begin(); |
131 } | 131 } |
132 | 132 |
133 NetQueue::iterator End() { | 133 NetQueue::iterator End() { |
134 return queue_.end(); | 134 return queue_.end(); |
135 } | 135 } |
136 | 136 |
137 // Returns true if |request| is queued. | 137 // Returns true if |request| is queued. |
138 bool IsQueued(ScheduledResourceRequest* request) const { | 138 bool IsQueued(ScheduledResourceRequest* request) const { |
139 return ContainsKey(pointers_, request); | 139 return base::ContainsKey(pointers_, request); |
140 } | 140 } |
141 | 141 |
142 // Returns true if no requests are queued. | 142 // Returns true if no requests are queued. |
143 bool IsEmpty() const { return queue_.size() == 0; } | 143 bool IsEmpty() const { return queue_.size() == 0; } |
144 | 144 |
145 private: | 145 private: |
146 typedef std::map<ScheduledResourceRequest*, NetQueue::iterator> PointerMap; | 146 typedef std::map<ScheduledResourceRequest*, NetQueue::iterator> PointerMap; |
147 | 147 |
148 uint32_t MakeFifoOrderingId() { | 148 uint32_t MakeFifoOrderingId() { |
149 fifo_ordering_ids_ += 1; | 149 fifo_ordering_ids_ += 1; |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 return a->get_request_priority_params().GreaterThan( | 295 return a->get_request_priority_params().GreaterThan( |
296 b->get_request_priority_params()); | 296 b->get_request_priority_params()); |
297 | 297 |
298 // If priority/intra_priority is the same, fall back to fifo ordering. | 298 // If priority/intra_priority is the same, fall back to fifo ordering. |
299 // std::multiset doesn't guarantee this until c++11. | 299 // std::multiset doesn't guarantee this until c++11. |
300 return a->fifo_ordering() < b->fifo_ordering(); | 300 return a->fifo_ordering() < b->fifo_ordering(); |
301 } | 301 } |
302 | 302 |
303 void ResourceScheduler::RequestQueue::Insert( | 303 void ResourceScheduler::RequestQueue::Insert( |
304 ScheduledResourceRequest* request) { | 304 ScheduledResourceRequest* request) { |
305 DCHECK(!ContainsKey(pointers_, request)); | 305 DCHECK(!base::ContainsKey(pointers_, request)); |
306 request->set_fifo_ordering(MakeFifoOrderingId()); | 306 request->set_fifo_ordering(MakeFifoOrderingId()); |
307 pointers_[request] = queue_.insert(request); | 307 pointers_[request] = queue_.insert(request); |
308 } | 308 } |
309 | 309 |
310 // Each client represents a tab. | 310 // Each client represents a tab. |
311 class ResourceScheduler::Client { | 311 class ResourceScheduler::Client { |
312 public: | 312 public: |
313 explicit Client(ResourceScheduler* scheduler) | 313 explicit Client(ResourceScheduler* scheduler) |
314 : is_loaded_(false), | 314 : is_loaded_(false), |
315 has_html_body_(false), | 315 has_html_body_(false), |
(...skipping 11 matching lines...) Expand all Loading... |
327 // New requests can be started synchronously without issue. | 327 // New requests can be started synchronously without issue. |
328 StartRequest(request, START_SYNC); | 328 StartRequest(request, START_SYNC); |
329 } else { | 329 } else { |
330 pending_requests_.Insert(request); | 330 pending_requests_.Insert(request); |
331 } | 331 } |
332 } | 332 } |
333 | 333 |
334 void RemoveRequest(ScheduledResourceRequest* request) { | 334 void RemoveRequest(ScheduledResourceRequest* request) { |
335 if (pending_requests_.IsQueued(request)) { | 335 if (pending_requests_.IsQueued(request)) { |
336 pending_requests_.Erase(request); | 336 pending_requests_.Erase(request); |
337 DCHECK(!ContainsKey(in_flight_requests_, request)); | 337 DCHECK(!base::ContainsKey(in_flight_requests_, request)); |
338 } else { | 338 } else { |
339 EraseInFlightRequest(request); | 339 EraseInFlightRequest(request); |
340 | 340 |
341 // Removing this request may have freed up another to load. | 341 // Removing this request may have freed up another to load. |
342 LoadAnyStartablePendingRequests(); | 342 LoadAnyStartablePendingRequests(); |
343 } | 343 } |
344 } | 344 } |
345 | 345 |
346 RequestSet StartAndRemoveAllRequests() { | 346 RequestSet StartAndRemoveAllRequests() { |
347 // First start any pending requests so that they will be moved into | 347 // First start any pending requests so that they will be moved into |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 } | 391 } |
392 } | 392 } |
393 | 393 |
394 void ReprioritizeRequest(ScheduledResourceRequest* request, | 394 void ReprioritizeRequest(ScheduledResourceRequest* request, |
395 RequestPriorityParams old_priority_params, | 395 RequestPriorityParams old_priority_params, |
396 RequestPriorityParams new_priority_params) { | 396 RequestPriorityParams new_priority_params) { |
397 request->url_request()->SetPriority(new_priority_params.priority); | 397 request->url_request()->SetPriority(new_priority_params.priority); |
398 request->set_request_priority_params(new_priority_params); | 398 request->set_request_priority_params(new_priority_params); |
399 SetRequestAttributes(request, DetermineRequestAttributes(request)); | 399 SetRequestAttributes(request, DetermineRequestAttributes(request)); |
400 if (!pending_requests_.IsQueued(request)) { | 400 if (!pending_requests_.IsQueued(request)) { |
401 DCHECK(ContainsKey(in_flight_requests_, request)); | 401 DCHECK(base::ContainsKey(in_flight_requests_, request)); |
402 // Request has already started. | 402 // Request has already started. |
403 return; | 403 return; |
404 } | 404 } |
405 | 405 |
406 pending_requests_.Erase(request); | 406 pending_requests_.Erase(request); |
407 pending_requests_.Insert(request); | 407 pending_requests_.Insert(request); |
408 | 408 |
409 if (new_priority_params.priority > old_priority_params.priority) { | 409 if (new_priority_params.priority > old_priority_params.priority) { |
410 // Check if this request is now able to load at its new priority. | 410 // Check if this request is now able to load at its new priority. |
411 LoadAnyStartablePendingRequests(); | 411 LoadAnyStartablePendingRequests(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 for (RequestQueue::NetQueue::const_iterator | 451 for (RequestQueue::NetQueue::const_iterator |
452 it = pending_requests_.GetNextHighestIterator(); | 452 it = pending_requests_.GetNextHighestIterator(); |
453 it != pending_requests_.End(); ++it) { | 453 it != pending_requests_.End(); ++it) { |
454 if (RequestAttributesAreSet((*it)->attributes(), attributes)) | 454 if (RequestAttributesAreSet((*it)->attributes(), attributes)) |
455 matching_request_count++; | 455 matching_request_count++; |
456 if (*it == current_request) | 456 if (*it == current_request) |
457 current_request_is_pending = true; | 457 current_request_is_pending = true; |
458 } | 458 } |
459 // Account for the current request if it is not in one of the lists yet. | 459 // Account for the current request if it is not in one of the lists yet. |
460 if (current_request && | 460 if (current_request && |
461 !ContainsKey(in_flight_requests_, current_request) && | 461 !base::ContainsKey(in_flight_requests_, current_request) && |
462 !current_request_is_pending) { | 462 !current_request_is_pending) { |
463 if (RequestAttributesAreSet(current_request->attributes(), attributes)) | 463 if (RequestAttributesAreSet(current_request->attributes(), attributes)) |
464 matching_request_count++; | 464 matching_request_count++; |
465 } | 465 } |
466 } | 466 } |
467 return matching_request_count; | 467 return matching_request_count; |
468 } | 468 } |
469 | 469 |
470 bool RequestAttributesAreSet(RequestAttributes request_attributes, | 470 bool RequestAttributesAreSet(RequestAttributes request_attributes, |
471 RequestAttributes matching_attributes) const { | 471 RequestAttributes matching_attributes) const { |
(...skipping 25 matching lines...) Expand all Loading... |
497 kAttributeInFlight | kAttributeDelayable, request), | 497 kAttributeInFlight | kAttributeDelayable, request), |
498 in_flight_delayable_count_); | 498 in_flight_delayable_count_); |
499 DCHECK_EQ(CountRequestsWithAttributes(kAttributeLayoutBlocking, request), | 499 DCHECK_EQ(CountRequestsWithAttributes(kAttributeLayoutBlocking, request), |
500 total_layout_blocking_count_); | 500 total_layout_blocking_count_); |
501 } | 501 } |
502 | 502 |
503 RequestAttributes DetermineRequestAttributes( | 503 RequestAttributes DetermineRequestAttributes( |
504 ScheduledResourceRequest* request) { | 504 ScheduledResourceRequest* request) { |
505 RequestAttributes attributes = kAttributeNone; | 505 RequestAttributes attributes = kAttributeNone; |
506 | 506 |
507 if (ContainsKey(in_flight_requests_, request)) | 507 if (base::ContainsKey(in_flight_requests_, request)) |
508 attributes |= kAttributeInFlight; | 508 attributes |= kAttributeInFlight; |
509 | 509 |
510 if (RequestAttributesAreSet(request->attributes(), | 510 if (RequestAttributesAreSet(request->attributes(), |
511 kAttributeLayoutBlocking)) { | 511 kAttributeLayoutBlocking)) { |
512 // If a request is already marked as layout-blocking make sure to keep the | 512 // If a request is already marked as layout-blocking make sure to keep the |
513 // attribute across redirects. | 513 // attribute across redirects. |
514 attributes |= kAttributeLayoutBlocking; | 514 attributes |= kAttributeLayoutBlocking; |
515 } else if (!has_html_body_ && | 515 } else if (!has_html_body_ && |
516 request->url_request()->priority() > | 516 request->url_request()->priority() > |
517 kLayoutBlockingPriorityThreshold) { | 517 kLayoutBlockingPriorityThreshold) { |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 return std::move(request); | 764 return std::move(request); |
765 } | 765 } |
766 | 766 |
767 Client* client = it->second; | 767 Client* client = it->second; |
768 client->ScheduleRequest(url_request, request.get()); | 768 client->ScheduleRequest(url_request, request.get()); |
769 return std::move(request); | 769 return std::move(request); |
770 } | 770 } |
771 | 771 |
772 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { | 772 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { |
773 DCHECK(CalledOnValidThread()); | 773 DCHECK(CalledOnValidThread()); |
774 if (ContainsKey(unowned_requests_, request)) { | 774 if (base::ContainsKey(unowned_requests_, request)) { |
775 unowned_requests_.erase(request); | 775 unowned_requests_.erase(request); |
776 return; | 776 return; |
777 } | 777 } |
778 | 778 |
779 ClientMap::iterator client_it = client_map_.find(request->client_id()); | 779 ClientMap::iterator client_it = client_map_.find(request->client_id()); |
780 if (client_it == client_map_.end()) { | 780 if (client_it == client_map_.end()) { |
781 return; | 781 return; |
782 } | 782 } |
783 | 783 |
784 Client* client = client_it->second; | 784 Client* client = client_it->second; |
785 client->RemoveRequest(request); | 785 client->RemoveRequest(request); |
786 } | 786 } |
787 | 787 |
788 void ResourceScheduler::OnClientCreated(int child_id, | 788 void ResourceScheduler::OnClientCreated(int child_id, |
789 int route_id) { | 789 int route_id) { |
790 DCHECK(CalledOnValidThread()); | 790 DCHECK(CalledOnValidThread()); |
791 ClientId client_id = MakeClientId(child_id, route_id); | 791 ClientId client_id = MakeClientId(child_id, route_id); |
792 DCHECK(!ContainsKey(client_map_, client_id)); | 792 DCHECK(!base::ContainsKey(client_map_, client_id)); |
793 | 793 |
794 Client* client = new Client(this); | 794 Client* client = new Client(this); |
795 client_map_[client_id] = client; | 795 client_map_[client_id] = client; |
796 } | 796 } |
797 | 797 |
798 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) { | 798 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) { |
799 DCHECK(CalledOnValidThread()); | 799 DCHECK(CalledOnValidThread()); |
800 ClientId client_id = MakeClientId(child_id, route_id); | 800 ClientId client_id = MakeClientId(child_id, route_id); |
801 ClientMap::iterator it = client_map_.find(client_id); | 801 ClientMap::iterator it = client_map_.find(client_id); |
802 DCHECK(it != client_map_.end()); | 802 DCHECK(it != client_map_.end()); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
923 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, | 923 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, |
924 new_priority_params); | 924 new_priority_params); |
925 } | 925 } |
926 | 926 |
927 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 927 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
928 int child_id, int route_id) { | 928 int child_id, int route_id) { |
929 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 929 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
930 } | 930 } |
931 | 931 |
932 } // namespace content | 932 } // namespace content |
OLD | NEW |