| 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 <set> | 5 #include <set> |
| 6 | 6 |
| 7 #include "content/browser/loader/resource_scheduler.h" | 7 #include "content/browser/loader/resource_scheduler.h" |
| 8 | 8 |
| 9 #include "base/metrics/field_trial.h" | 9 #include "base/metrics/field_trial.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/string_piece.h" | 13 #include "base/strings/string_piece.h" |
| 14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "content/common/resource_messages.h" | 15 #include "content/common/resource_messages.h" |
| 16 #include "content/browser/loader/resource_message_delegate.h" | |
| 17 #include "content/public/browser/resource_controller.h" | 16 #include "content/public/browser/resource_controller.h" |
| 18 #include "content/public/browser/resource_request_info.h" | 17 #include "content/public/browser/resource_request_info.h" |
| 19 #include "content/public/browser/resource_throttle.h" | 18 #include "content/public/browser/resource_throttle.h" |
| 20 #include "ipc/ipc_message_macros.h" | |
| 21 #include "net/base/host_port_pair.h" | 19 #include "net/base/host_port_pair.h" |
| 22 #include "net/base/load_flags.h" | 20 #include "net/base/load_flags.h" |
| 23 #include "net/base/request_priority.h" | 21 #include "net/base/request_priority.h" |
| 24 #include "net/http/http_server_properties.h" | 22 #include "net/http/http_server_properties.h" |
| 25 #include "net/url_request/url_request.h" | 23 #include "net/url_request/url_request.h" |
| 26 #include "net/url_request/url_request_context.h" | 24 #include "net/url_request/url_request_context.h" |
| 27 | 25 |
| 28 namespace content { | 26 namespace content { |
| 29 | 27 |
| 30 namespace { | 28 namespace { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 return "Over30Clients"; | 69 return "Over30Clients"; |
| 72 } | 70 } |
| 73 | 71 |
| 74 } // namespace | 72 } // namespace |
| 75 | 73 |
| 76 static const size_t kCoalescedTimerPeriod = 5000; | 74 static const size_t kCoalescedTimerPeriod = 5000; |
| 77 static const size_t kMaxNumDelayableRequestsPerClient = 10; | 75 static const size_t kMaxNumDelayableRequestsPerClient = 10; |
| 78 static const size_t kMaxNumDelayableRequestsPerHost = 6; | 76 static const size_t kMaxNumDelayableRequestsPerHost = 6; |
| 79 static const size_t kMaxNumThrottledRequestsPerClient = 1; | 77 static const size_t kMaxNumThrottledRequestsPerClient = 1; |
| 80 | 78 |
| 79 ScheduledResourceRequest::ScheduledResourceRequest() {} |
| 80 ScheduledResourceRequest::~ScheduledResourceRequest() {} |
| 81 |
| 81 struct ResourceScheduler::RequestPriorityParams { | 82 struct ResourceScheduler::RequestPriorityParams { |
| 82 RequestPriorityParams() | 83 RequestPriorityParams() |
| 83 : priority(net::DEFAULT_PRIORITY), | 84 : priority(net::DEFAULT_PRIORITY), |
| 84 intra_priority(0) { | 85 intra_priority(0) { |
| 85 } | 86 } |
| 86 | 87 |
| 87 RequestPriorityParams(net::RequestPriority priority, int intra_priority) | 88 RequestPriorityParams(net::RequestPriority priority, int intra_priority) |
| 88 : priority(priority), | 89 : priority(priority), |
| 89 intra_priority(intra_priority) { | 90 intra_priority(intra_priority) { |
| 90 } | 91 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 103 return priority > other.priority; | 104 return priority > other.priority; |
| 104 return intra_priority > other.intra_priority; | 105 return intra_priority > other.intra_priority; |
| 105 } | 106 } |
| 106 | 107 |
| 107 net::RequestPriority priority; | 108 net::RequestPriority priority; |
| 108 int intra_priority; | 109 int intra_priority; |
| 109 }; | 110 }; |
| 110 | 111 |
| 111 class ResourceScheduler::RequestQueue { | 112 class ResourceScheduler::RequestQueue { |
| 112 public: | 113 public: |
| 113 typedef std::multiset<ScheduledResourceRequest*, ScheduledResourceSorter> | 114 typedef std::multiset<ScheduledResourceRequestImpl*, ScheduledResourceSorter> |
| 114 NetQueue; | 115 NetQueue; |
| 115 | 116 |
| 116 RequestQueue() : fifo_ordering_ids_(0) {} | 117 RequestQueue() : fifo_ordering_ids_(0) {} |
| 117 ~RequestQueue() {} | 118 ~RequestQueue() {} |
| 118 | 119 |
| 119 // Adds |request| to the queue with given |priority|. | 120 // Adds |request| to the queue with given |priority|. |
| 120 void Insert(ScheduledResourceRequest* request); | 121 void Insert(ScheduledResourceRequestImpl* request); |
| 121 | 122 |
| 122 // Removes |request| from the queue. | 123 // Removes |request| from the queue. |
| 123 void Erase(ScheduledResourceRequest* request) { | 124 void Erase(ScheduledResourceRequestImpl* request) { |
| 124 PointerMap::iterator it = pointers_.find(request); | 125 PointerMap::iterator it = pointers_.find(request); |
| 125 DCHECK(it != pointers_.end()); | 126 DCHECK(it != pointers_.end()); |
| 126 if (it == pointers_.end()) | 127 if (it == pointers_.end()) |
| 127 return; | 128 return; |
| 128 queue_.erase(it->second); | 129 queue_.erase(it->second); |
| 129 pointers_.erase(it); | 130 pointers_.erase(it); |
| 130 } | 131 } |
| 131 | 132 |
| 132 NetQueue::iterator GetNextHighestIterator() { | 133 NetQueue::iterator GetNextHighestIterator() { |
| 133 return queue_.begin(); | 134 return queue_.begin(); |
| 134 } | 135 } |
| 135 | 136 |
| 136 NetQueue::iterator End() { | 137 NetQueue::iterator End() { |
| 137 return queue_.end(); | 138 return queue_.end(); |
| 138 } | 139 } |
| 139 | 140 |
| 140 // Returns true if |request| is queued. | 141 // Returns true if |request| is queued. |
| 141 bool IsQueued(ScheduledResourceRequest* request) const { | 142 bool IsQueued(ScheduledResourceRequestImpl* request) const { |
| 142 return ContainsKey(pointers_, request); | 143 return ContainsKey(pointers_, request); |
| 143 } | 144 } |
| 144 | 145 |
| 145 // Returns true if no requests are queued. | 146 // Returns true if no requests are queued. |
| 146 bool IsEmpty() const { return queue_.size() == 0; } | 147 bool IsEmpty() const { return queue_.size() == 0; } |
| 147 | 148 |
| 148 private: | 149 private: |
| 149 typedef std::map<ScheduledResourceRequest*, NetQueue::iterator> PointerMap; | 150 typedef std::map<ScheduledResourceRequestImpl*, NetQueue::iterator> |
| 151 PointerMap; |
| 150 | 152 |
| 151 uint32 MakeFifoOrderingId() { | 153 uint32 MakeFifoOrderingId() { |
| 152 fifo_ordering_ids_ += 1; | 154 fifo_ordering_ids_ += 1; |
| 153 return fifo_ordering_ids_; | 155 return fifo_ordering_ids_; |
| 154 } | 156 } |
| 155 | 157 |
| 156 // Used to create an ordering ID for scheduled resources so that resources | 158 // Used to create an ordering ID for scheduled resources so that resources |
| 157 // with same priority/intra_priority stay in fifo order. | 159 // with same priority/intra_priority stay in fifo order. |
| 158 uint32 fifo_ordering_ids_; | 160 uint32 fifo_ordering_ids_; |
| 159 | 161 |
| 160 NetQueue queue_; | 162 NetQueue queue_; |
| 161 PointerMap pointers_; | 163 PointerMap pointers_; |
| 162 }; | 164 }; |
| 163 | 165 |
| 164 // This is the handle we return to the ResourceDispatcherHostImpl so it can | 166 // This is the handle we return to the ResourceDispatcherHostImpl so it can |
| 165 // interact with the request. | 167 // interact with the request. |
| 166 class ResourceScheduler::ScheduledResourceRequest | 168 class ResourceScheduler::ScheduledResourceRequestImpl |
| 167 : public ResourceMessageDelegate, | 169 : public ScheduledResourceRequest { |
| 168 public ResourceThrottle { | |
| 169 public: | 170 public: |
| 170 ScheduledResourceRequest(const ClientId& client_id, | 171 ScheduledResourceRequestImpl(const ClientId& client_id, |
| 171 net::URLRequest* request, | 172 net::URLRequest* request, |
| 172 ResourceScheduler* scheduler, | 173 ResourceScheduler* scheduler, |
| 173 const RequestPriorityParams& priority) | 174 const RequestPriorityParams& priority, |
| 174 : ResourceMessageDelegate(request), | 175 bool is_async) |
| 175 client_id_(client_id), | 176 : client_id_(client_id), |
| 176 client_state_on_creation_(scheduler->GetClientState(client_id_)), | 177 client_state_on_creation_(scheduler->GetClientState(client_id_)), |
| 177 request_(request), | 178 request_(request), |
| 178 ready_(false), | 179 ready_(false), |
| 179 deferred_(false), | 180 deferred_(false), |
| 181 is_async_(is_async), |
| 180 classification_(NORMAL_REQUEST), | 182 classification_(NORMAL_REQUEST), |
| 181 scheduler_(scheduler), | 183 scheduler_(scheduler), |
| 182 priority_(priority), | 184 priority_(priority), |
| 183 fifo_ordering_(0) { | 185 fifo_ordering_(0) {} |
| 186 |
| 187 ~ScheduledResourceRequestImpl() override { scheduler_->RemoveRequest(this); } |
| 188 |
| 189 void ChangePriority(net::RequestPriority new_priority, |
| 190 int intra_priority_value) override { |
| 191 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); |
| 184 } | 192 } |
| 185 | 193 |
| 186 ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); } | |
| 187 | |
| 188 void Start() { | 194 void Start() { |
| 189 ready_ = true; | 195 ready_ = true; |
| 190 if (!request_->status().is_success()) | 196 if (!request_->status().is_success()) |
| 191 return; | 197 return; |
| 192 base::TimeTicks time = base::TimeTicks::Now(); | 198 base::TimeTicks time = base::TimeTicks::Now(); |
| 193 ClientState current_state = scheduler_->GetClientState(client_id_); | 199 ClientState current_state = scheduler_->GetClientState(client_id_); |
| 194 // Note: the client state isn't perfectly accurate since it won't capture | 200 // Note: the client state isn't perfectly accurate since it won't capture |
| 195 // tabs which have switched between active and background multiple times. | 201 // tabs which have switched between active and background multiple times. |
| 196 // Ex: A tab with the following transitions Active -> Background -> Active | 202 // Ex: A tab with the following transitions Active -> Background -> Active |
| 197 // will be recorded as Active. | 203 // will be recorded as Active. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 219 | 225 |
| 220 void set_request_priority_params(const RequestPriorityParams& priority) { | 226 void set_request_priority_params(const RequestPriorityParams& priority) { |
| 221 priority_ = priority; | 227 priority_ = priority; |
| 222 } | 228 } |
| 223 const RequestPriorityParams& get_request_priority_params() const { | 229 const RequestPriorityParams& get_request_priority_params() const { |
| 224 return priority_; | 230 return priority_; |
| 225 } | 231 } |
| 226 const ClientId& client_id() const { return client_id_; } | 232 const ClientId& client_id() const { return client_id_; } |
| 227 net::URLRequest* url_request() { return request_; } | 233 net::URLRequest* url_request() { return request_; } |
| 228 const net::URLRequest* url_request() const { return request_; } | 234 const net::URLRequest* url_request() const { return request_; } |
| 235 bool is_async() const { return is_async_; } |
| 229 uint32 fifo_ordering() const { return fifo_ordering_; } | 236 uint32 fifo_ordering() const { return fifo_ordering_; } |
| 230 void set_fifo_ordering(uint32 fifo_ordering) { | 237 void set_fifo_ordering(uint32 fifo_ordering) { |
| 231 fifo_ordering_ = fifo_ordering; | 238 fifo_ordering_ = fifo_ordering; |
| 232 } | 239 } |
| 233 RequestClassification classification() const { | 240 RequestClassification classification() const { |
| 234 return classification_; | 241 return classification_; |
| 235 } | 242 } |
| 236 void set_classification(RequestClassification classification) { | 243 void set_classification(RequestClassification classification) { |
| 237 classification_ = classification; | 244 classification_ = classification; |
| 238 } | 245 } |
| 239 | 246 |
| 240 private: | 247 private: |
| 241 // ResourceMessageDelegate interface: | |
| 242 bool OnMessageReceived(const IPC::Message& message) override { | |
| 243 bool handled = true; | |
| 244 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message) | |
| 245 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) | |
| 246 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 247 IPC_END_MESSAGE_MAP() | |
| 248 return handled; | |
| 249 } | |
| 250 | |
| 251 // ResourceThrottle interface: | 248 // ResourceThrottle interface: |
| 252 void WillStartRequest(bool* defer) override { | 249 void WillStartRequest(bool* defer) override { |
| 253 deferred_ = *defer = !ready_; | 250 deferred_ = *defer = !ready_; |
| 254 time_deferred_ = base::TimeTicks::Now(); | 251 time_deferred_ = base::TimeTicks::Now(); |
| 255 } | 252 } |
| 256 | 253 |
| 257 const char* GetNameForLogging() const override { return "ResourceScheduler"; } | 254 const char* GetNameForLogging() const override { return "ResourceScheduler"; } |
| 258 | 255 |
| 259 void DidChangePriority(int request_id, net::RequestPriority new_priority, | |
| 260 int intra_priority_value) { | |
| 261 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); | |
| 262 } | |
| 263 | |
| 264 const ClientId client_id_; | 256 const ClientId client_id_; |
| 265 const ResourceScheduler::ClientState client_state_on_creation_; | 257 const ResourceScheduler::ClientState client_state_on_creation_; |
| 266 net::URLRequest* request_; | 258 net::URLRequest* request_; |
| 267 bool ready_; | 259 bool ready_; |
| 268 bool deferred_; | 260 bool deferred_; |
| 261 bool is_async_; |
| 269 RequestClassification classification_; | 262 RequestClassification classification_; |
| 270 ResourceScheduler* scheduler_; | 263 ResourceScheduler* scheduler_; |
| 271 RequestPriorityParams priority_; | 264 RequestPriorityParams priority_; |
| 272 uint32 fifo_ordering_; | 265 uint32 fifo_ordering_; |
| 273 base::TimeTicks time_deferred_; | 266 base::TimeTicks time_deferred_; |
| 274 | 267 |
| 275 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); | 268 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequestImpl); |
| 276 }; | 269 }; |
| 277 | 270 |
| 278 bool ResourceScheduler::ScheduledResourceSorter::operator()( | 271 bool ResourceScheduler::ScheduledResourceSorter::operator()( |
| 279 const ScheduledResourceRequest* a, | 272 const ScheduledResourceRequestImpl* a, |
| 280 const ScheduledResourceRequest* b) const { | 273 const ScheduledResourceRequestImpl* b) const { |
| 281 // Want the set to be ordered first by decreasing priority, then by | 274 // Want the set to be ordered first by decreasing priority, then by |
| 282 // decreasing intra_priority. | 275 // decreasing intra_priority. |
| 283 // ie. with (priority, intra_priority) | 276 // ie. with (priority, intra_priority) |
| 284 // [(1, 0), (1, 0), (0, 100), (0, 0)] | 277 // [(1, 0), (1, 0), (0, 100), (0, 0)] |
| 285 if (a->get_request_priority_params() != b->get_request_priority_params()) | 278 if (a->get_request_priority_params() != b->get_request_priority_params()) |
| 286 return a->get_request_priority_params().GreaterThan( | 279 return a->get_request_priority_params().GreaterThan( |
| 287 b->get_request_priority_params()); | 280 b->get_request_priority_params()); |
| 288 | 281 |
| 289 // If priority/intra_priority is the same, fall back to fifo ordering. | 282 // If priority/intra_priority is the same, fall back to fifo ordering. |
| 290 // std::multiset doesn't guarantee this until c++11. | 283 // std::multiset doesn't guarantee this until c++11. |
| 291 return a->fifo_ordering() < b->fifo_ordering(); | 284 return a->fifo_ordering() < b->fifo_ordering(); |
| 292 } | 285 } |
| 293 | 286 |
| 294 void ResourceScheduler::RequestQueue::Insert( | 287 void ResourceScheduler::RequestQueue::Insert( |
| 295 ScheduledResourceRequest* request) { | 288 ScheduledResourceRequestImpl* request) { |
| 296 DCHECK(!ContainsKey(pointers_, request)); | 289 DCHECK(!ContainsKey(pointers_, request)); |
| 297 request->set_fifo_ordering(MakeFifoOrderingId()); | 290 request->set_fifo_ordering(MakeFifoOrderingId()); |
| 298 pointers_[request] = queue_.insert(request); | 291 pointers_[request] = queue_.insert(request); |
| 299 } | 292 } |
| 300 | 293 |
| 301 // Each client represents a tab. | 294 // Each client represents a tab. |
| 302 class ResourceScheduler::Client { | 295 class ResourceScheduler::Client { |
| 303 public: | 296 public: |
| 304 explicit Client(ResourceScheduler* scheduler, | 297 explicit Client(ResourceScheduler* scheduler, |
| 305 bool is_visible, | 298 bool is_visible, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 318 | 311 |
| 319 ~Client() { | 312 ~Client() { |
| 320 // Update to default state and pause to ensure the scheduler has a | 313 // Update to default state and pause to ensure the scheduler has a |
| 321 // correct count of relevant types of clients. | 314 // correct count of relevant types of clients. |
| 322 is_visible_ = false; | 315 is_visible_ = false; |
| 323 is_audible_ = false; | 316 is_audible_ = false; |
| 324 is_paused_ = true; | 317 is_paused_ = true; |
| 325 UpdateThrottleState(); | 318 UpdateThrottleState(); |
| 326 } | 319 } |
| 327 | 320 |
| 328 void ScheduleRequest( | 321 void ScheduleRequest(net::URLRequest* url_request, |
| 329 net::URLRequest* url_request, | 322 ScheduledResourceRequestImpl* request) { |
| 330 ScheduledResourceRequest* request) { | |
| 331 if (ShouldStartRequest(request) == START_REQUEST) | 323 if (ShouldStartRequest(request) == START_REQUEST) |
| 332 StartRequest(request); | 324 StartRequest(request); |
| 333 else | 325 else |
| 334 pending_requests_.Insert(request); | 326 pending_requests_.Insert(request); |
| 335 SetRequestClassification(request, ClassifyRequest(request)); | 327 SetRequestClassification(request, ClassifyRequest(request)); |
| 336 } | 328 } |
| 337 | 329 |
| 338 void RemoveRequest(ScheduledResourceRequest* request) { | 330 void RemoveRequest(ScheduledResourceRequestImpl* request) { |
| 339 if (pending_requests_.IsQueued(request)) { | 331 if (pending_requests_.IsQueued(request)) { |
| 340 pending_requests_.Erase(request); | 332 pending_requests_.Erase(request); |
| 341 DCHECK(!ContainsKey(in_flight_requests_, request)); | 333 DCHECK(!ContainsKey(in_flight_requests_, request)); |
| 342 } else { | 334 } else { |
| 343 EraseInFlightRequest(request); | 335 EraseInFlightRequest(request); |
| 344 | 336 |
| 345 // Removing this request may have freed up another to load. | 337 // Removing this request may have freed up another to load. |
| 346 LoadAnyStartablePendingRequests(); | 338 LoadAnyStartablePendingRequests(); |
| 347 } | 339 } |
| 348 } | 340 } |
| 349 | 341 |
| 350 RequestSet StartAndRemoveAllRequests() { | 342 RequestSet StartAndRemoveAllRequests() { |
| 351 // First start any pending requests so that they will be moved into | 343 // First start any pending requests so that they will be moved into |
| 352 // in_flight_requests_. This may exceed the limits | 344 // in_flight_requests_. This may exceed the limits |
| 353 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and | 345 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and |
| 354 // kMaxNumThrottledRequestsPerClient, so this method must not do anything | 346 // kMaxNumThrottledRequestsPerClient, so this method must not do anything |
| 355 // that depends on those limits before calling ClearInFlightRequests() | 347 // that depends on those limits before calling ClearInFlightRequests() |
| 356 // below. | 348 // below. |
| 357 while (!pending_requests_.IsEmpty()) { | 349 while (!pending_requests_.IsEmpty()) { |
| 358 ScheduledResourceRequest* request = | 350 ScheduledResourceRequestImpl* request = |
| 359 *pending_requests_.GetNextHighestIterator(); | 351 *pending_requests_.GetNextHighestIterator(); |
| 360 pending_requests_.Erase(request); | 352 pending_requests_.Erase(request); |
| 361 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? | 353 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? |
| 362 StartRequest(request); | 354 StartRequest(request); |
| 363 } | 355 } |
| 364 RequestSet unowned_requests; | 356 RequestSet unowned_requests; |
| 365 for (RequestSet::iterator it = in_flight_requests_.begin(); | 357 for (RequestSet::iterator it = in_flight_requests_.begin(); |
| 366 it != in_flight_requests_.end(); ++it) { | 358 it != in_flight_requests_.end(); ++it) { |
| 367 unowned_requests.insert(*it); | 359 unowned_requests.insert(*it); |
| 368 (*it)->set_classification(NORMAL_REQUEST); | 360 (*it)->set_classification(NORMAL_REQUEST); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 LoadAnyStartablePendingRequests(); | 471 LoadAnyStartablePendingRequests(); |
| 480 } | 472 } |
| 481 | 473 |
| 482 void OnReceivedSpdyProxiedHttpResponse() { | 474 void OnReceivedSpdyProxiedHttpResponse() { |
| 483 if (!using_spdy_proxy_) { | 475 if (!using_spdy_proxy_) { |
| 484 using_spdy_proxy_ = true; | 476 using_spdy_proxy_ = true; |
| 485 LoadAnyStartablePendingRequests(); | 477 LoadAnyStartablePendingRequests(); |
| 486 } | 478 } |
| 487 } | 479 } |
| 488 | 480 |
| 489 void ReprioritizeRequest(ScheduledResourceRequest* request, | 481 void ReprioritizeRequest(ScheduledResourceRequestImpl* request, |
| 490 RequestPriorityParams old_priority_params, | 482 RequestPriorityParams old_priority_params, |
| 491 RequestPriorityParams new_priority_params) { | 483 RequestPriorityParams new_priority_params) { |
| 492 request->url_request()->SetPriority(new_priority_params.priority); | 484 request->url_request()->SetPriority(new_priority_params.priority); |
| 493 request->set_request_priority_params(new_priority_params); | 485 request->set_request_priority_params(new_priority_params); |
| 494 if (!pending_requests_.IsQueued(request)) { | 486 if (!pending_requests_.IsQueued(request)) { |
| 495 DCHECK(ContainsKey(in_flight_requests_, request)); | 487 DCHECK(ContainsKey(in_flight_requests_, request)); |
| 496 // The priority of the request and priority support of the server may | 488 // The priority of the request and priority support of the server may |
| 497 // have changed, so update the delayable count. | 489 // have changed, so update the delayable count. |
| 498 SetRequestClassification(request, ClassifyRequest(request)); | 490 SetRequestClassification(request, ClassifyRequest(request)); |
| 499 // Request has already started. | 491 // Request has already started. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 SetThrottleState(COALESCED); | 545 SetThrottleState(COALESCED); |
| 554 } | 546 } |
| 555 | 547 |
| 556 private: | 548 private: |
| 557 enum ShouldStartReqResult { | 549 enum ShouldStartReqResult { |
| 558 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, | 550 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, |
| 559 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, | 551 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, |
| 560 START_REQUEST, | 552 START_REQUEST, |
| 561 }; | 553 }; |
| 562 | 554 |
| 563 void InsertInFlightRequest(ScheduledResourceRequest* request) { | 555 void InsertInFlightRequest(ScheduledResourceRequestImpl* request) { |
| 564 in_flight_requests_.insert(request); | 556 in_flight_requests_.insert(request); |
| 565 SetRequestClassification(request, ClassifyRequest(request)); | 557 SetRequestClassification(request, ClassifyRequest(request)); |
| 566 } | 558 } |
| 567 | 559 |
| 568 void EraseInFlightRequest(ScheduledResourceRequest* request) { | 560 void EraseInFlightRequest(ScheduledResourceRequestImpl* request) { |
| 569 size_t erased = in_flight_requests_.erase(request); | 561 size_t erased = in_flight_requests_.erase(request); |
| 570 DCHECK_EQ(1u, erased); | 562 DCHECK_EQ(1u, erased); |
| 571 // Clear any special state that we were tracking for this request. | 563 // Clear any special state that we were tracking for this request. |
| 572 SetRequestClassification(request, NORMAL_REQUEST); | 564 SetRequestClassification(request, NORMAL_REQUEST); |
| 573 } | 565 } |
| 574 | 566 |
| 575 void ClearInFlightRequests() { | 567 void ClearInFlightRequests() { |
| 576 in_flight_requests_.clear(); | 568 in_flight_requests_.clear(); |
| 577 in_flight_delayable_count_ = 0; | 569 in_flight_delayable_count_ = 0; |
| 578 total_layout_blocking_count_ = 0; | 570 total_layout_blocking_count_ = 0; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 590 for (RequestQueue::NetQueue::const_iterator | 582 for (RequestQueue::NetQueue::const_iterator |
| 591 it = pending_requests_.GetNextHighestIterator(); | 583 it = pending_requests_.GetNextHighestIterator(); |
| 592 it != pending_requests_.End(); ++it) { | 584 it != pending_requests_.End(); ++it) { |
| 593 if ((*it)->classification() == classification) | 585 if ((*it)->classification() == classification) |
| 594 classification_request_count++; | 586 classification_request_count++; |
| 595 } | 587 } |
| 596 } | 588 } |
| 597 return classification_request_count; | 589 return classification_request_count; |
| 598 } | 590 } |
| 599 | 591 |
| 600 void SetRequestClassification(ScheduledResourceRequest* request, | 592 void SetRequestClassification(ScheduledResourceRequestImpl* request, |
| 601 RequestClassification classification) { | 593 RequestClassification classification) { |
| 602 RequestClassification old_classification = request->classification(); | 594 RequestClassification old_classification = request->classification(); |
| 603 if (old_classification == classification) | 595 if (old_classification == classification) |
| 604 return; | 596 return; |
| 605 | 597 |
| 606 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) | 598 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) |
| 607 in_flight_delayable_count_--; | 599 in_flight_delayable_count_--; |
| 608 if (old_classification == LAYOUT_BLOCKING_REQUEST) | 600 if (old_classification == LAYOUT_BLOCKING_REQUEST) |
| 609 total_layout_blocking_count_--; | 601 total_layout_blocking_count_--; |
| 610 | 602 |
| 611 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) | 603 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) |
| 612 in_flight_delayable_count_++; | 604 in_flight_delayable_count_++; |
| 613 if (classification == LAYOUT_BLOCKING_REQUEST) | 605 if (classification == LAYOUT_BLOCKING_REQUEST) |
| 614 total_layout_blocking_count_++; | 606 total_layout_blocking_count_++; |
| 615 | 607 |
| 616 request->set_classification(classification); | 608 request->set_classification(classification); |
| 617 DCHECK_EQ( | 609 DCHECK_EQ( |
| 618 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), | 610 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), |
| 619 in_flight_delayable_count_); | 611 in_flight_delayable_count_); |
| 620 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), | 612 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), |
| 621 total_layout_blocking_count_); | 613 total_layout_blocking_count_); |
| 622 } | 614 } |
| 623 | 615 |
| 624 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) { | 616 RequestClassification ClassifyRequest(ScheduledResourceRequestImpl* request) { |
| 625 // If a request is already marked as layout-blocking make sure to keep the | 617 // If a request is already marked as layout-blocking make sure to keep the |
| 626 // classification across redirects unless the priority was lowered. | 618 // classification across redirects unless the priority was lowered. |
| 627 if (request->classification() == LAYOUT_BLOCKING_REQUEST && | 619 if (request->classification() == LAYOUT_BLOCKING_REQUEST && |
| 628 request->url_request()->priority() > net::LOW) { | 620 request->url_request()->priority() > net::LOW) { |
| 629 return LAYOUT_BLOCKING_REQUEST; | 621 return LAYOUT_BLOCKING_REQUEST; |
| 630 } | 622 } |
| 631 | 623 |
| 632 if (!has_body_ && request->url_request()->priority() > net::LOW) | 624 if (!has_body_ && request->url_request()->priority() > net::LOW) |
| 633 return LAYOUT_BLOCKING_REQUEST; | 625 return LAYOUT_BLOCKING_REQUEST; |
| 634 | 626 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 654 net::HostPortPair::FromURL((*it)->url_request()->url()); | 646 net::HostPortPair::FromURL((*it)->url_request()->url()); |
| 655 if (active_request_host.Equals(host_port_pair)) { | 647 if (active_request_host.Equals(host_port_pair)) { |
| 656 same_host_count++; | 648 same_host_count++; |
| 657 if (same_host_count >= kMaxNumDelayableRequestsPerHost) | 649 if (same_host_count >= kMaxNumDelayableRequestsPerHost) |
| 658 return true; | 650 return true; |
| 659 } | 651 } |
| 660 } | 652 } |
| 661 return false; | 653 return false; |
| 662 } | 654 } |
| 663 | 655 |
| 664 void StartRequest(ScheduledResourceRequest* request) { | 656 void StartRequest(ScheduledResourceRequestImpl* request) { |
| 665 InsertInFlightRequest(request); | 657 InsertInFlightRequest(request); |
| 666 request->Start(); | 658 request->Start(); |
| 667 } | 659 } |
| 668 | 660 |
| 669 // ShouldStartRequest is the main scheduling algorithm. | 661 // ShouldStartRequest is the main scheduling algorithm. |
| 670 // | 662 // |
| 671 // Requests are evaluated on five attributes: | 663 // Requests are evaluated on five attributes: |
| 672 // | 664 // |
| 673 // 1. Non-delayable requests: | 665 // 1. Non-delayable requests: |
| 674 // * Synchronous requests. | 666 // * Synchronous requests. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 // * If no high priority requests are in flight, start loading low priority | 704 // * If no high priority requests are in flight, start loading low priority |
| 713 // requests. | 705 // requests. |
| 714 // | 706 // |
| 715 // COALESCED Clients never load requests, with the following exceptions: | 707 // COALESCED Clients never load requests, with the following exceptions: |
| 716 // * Non-delayable requests are issued imediately. | 708 // * Non-delayable requests are issued imediately. |
| 717 // * On a (currently 5 second) heart beat, they load all requests as an | 709 // * On a (currently 5 second) heart beat, they load all requests as an |
| 718 // UNTHROTTLED Client, and then return to the COALESCED state. | 710 // UNTHROTTLED Client, and then return to the COALESCED state. |
| 719 // * When an active Client makes a request, they are THROTTLED until the | 711 // * When an active Client makes a request, they are THROTTLED until the |
| 720 // active Client finishes loading. | 712 // active Client finishes loading. |
| 721 ShouldStartReqResult ShouldStartRequest( | 713 ShouldStartReqResult ShouldStartRequest( |
| 722 ScheduledResourceRequest* request) const { | 714 ScheduledResourceRequestImpl* request) const { |
| 723 const net::URLRequest& url_request = *request->url_request(); | 715 const net::URLRequest& url_request = *request->url_request(); |
| 724 // Syncronous requests could block the entire render, which could impact | 716 // Syncronous requests could block the entire render, which could impact |
| 725 // user-observable Clients. | 717 // user-observable Clients. |
| 726 if (!ResourceRequestInfo::ForRequest(&url_request)->IsAsync()) { | 718 if (!request->is_async()) { |
| 727 return START_REQUEST; | 719 return START_REQUEST; |
| 728 } | 720 } |
| 729 | 721 |
| 730 // TODO(simonjam): This may end up causing disk contention. We should | 722 // TODO(simonjam): This may end up causing disk contention. We should |
| 731 // experiment with throttling if that happens. | 723 // experiment with throttling if that happens. |
| 732 // TODO(aiolos): We probably want to Coalesce these as well to avoid | 724 // TODO(aiolos): We probably want to Coalesce these as well to avoid |
| 733 // waking the disk. | 725 // waking the disk. |
| 734 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { | 726 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { |
| 735 return START_REQUEST; | 727 return START_REQUEST; |
| 736 } | 728 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 803 // 1) We start the request, remove it from the list, and keep checking. | 795 // 1) We start the request, remove it from the list, and keep checking. |
| 804 // 2) We do NOT start the request, but ShouldStartRequest() signals us that | 796 // 2) We do NOT start the request, but ShouldStartRequest() signals us that |
| 805 // there may be room for other requests, so we keep checking and leave | 797 // there may be room for other requests, so we keep checking and leave |
| 806 // the previous request still in the list. | 798 // the previous request still in the list. |
| 807 // 3) We do not start the request, same as above, but StartRequest() tells | 799 // 3) We do not start the request, same as above, but StartRequest() tells |
| 808 // us there's no point in checking any further requests. | 800 // us there's no point in checking any further requests. |
| 809 RequestQueue::NetQueue::iterator request_iter = | 801 RequestQueue::NetQueue::iterator request_iter = |
| 810 pending_requests_.GetNextHighestIterator(); | 802 pending_requests_.GetNextHighestIterator(); |
| 811 | 803 |
| 812 while (request_iter != pending_requests_.End()) { | 804 while (request_iter != pending_requests_.End()) { |
| 813 ScheduledResourceRequest* request = *request_iter; | 805 ScheduledResourceRequestImpl* request = *request_iter; |
| 814 ShouldStartReqResult query_result = ShouldStartRequest(request); | 806 ShouldStartReqResult query_result = ShouldStartRequest(request); |
| 815 | 807 |
| 816 if (query_result == START_REQUEST) { | 808 if (query_result == START_REQUEST) { |
| 817 pending_requests_.Erase(request); | 809 pending_requests_.Erase(request); |
| 818 StartRequest(request); | 810 StartRequest(request); |
| 819 | 811 |
| 820 // StartRequest can modify the pending list, so we (re)start evaluation | 812 // StartRequest can modify the pending list, so we (re)start evaluation |
| 821 // from the currently highest priority request. Avoid copying a singular | 813 // from the currently highest priority request. Avoid copying a singular |
| 822 // iterator, which would trigger undefined behavior. | 814 // iterator, which would trigger undefined behavior. |
| 823 if (pending_requests_.GetNextHighestIterator() == | 815 if (pending_requests_.GetNextHighestIterator() == |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 898 OnLoadingActiveClientsStateChangedForAllClients(); | 890 OnLoadingActiveClientsStateChangedForAllClients(); |
| 899 } | 891 } |
| 900 | 892 |
| 901 ResourceScheduler::ClientThrottleState | 893 ResourceScheduler::ClientThrottleState |
| 902 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { | 894 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { |
| 903 Client* client = GetClient(child_id, route_id); | 895 Client* client = GetClient(child_id, route_id); |
| 904 DCHECK(client); | 896 DCHECK(client); |
| 905 return client->throttle_state(); | 897 return client->throttle_state(); |
| 906 } | 898 } |
| 907 | 899 |
| 908 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( | 900 scoped_ptr<ScheduledResourceRequest> ResourceScheduler::ScheduleRequest( |
| 909 int child_id, | 901 int child_id, |
| 910 int route_id, | 902 int route_id, |
| 903 bool is_async, |
| 911 net::URLRequest* url_request) { | 904 net::URLRequest* url_request) { |
| 912 DCHECK(CalledOnValidThread()); | 905 DCHECK(CalledOnValidThread()); |
| 913 ClientId client_id = MakeClientId(child_id, route_id); | 906 ClientId client_id = MakeClientId(child_id, route_id); |
| 914 scoped_ptr<ScheduledResourceRequest> request(new ScheduledResourceRequest( | 907 scoped_ptr<ScheduledResourceRequestImpl> request( |
| 915 client_id, | 908 new ScheduledResourceRequestImpl( |
| 916 url_request, | 909 client_id, url_request, this, |
| 917 this, | 910 RequestPriorityParams(url_request->priority(), 0), is_async)); |
| 918 RequestPriorityParams(url_request->priority(), 0))); | |
| 919 | 911 |
| 920 ClientMap::iterator it = client_map_.find(client_id); | 912 ClientMap::iterator it = client_map_.find(client_id); |
| 921 if (it == client_map_.end()) { | 913 if (it == client_map_.end()) { |
| 922 // There are several ways this could happen: | 914 // There are several ways this could happen: |
| 923 // 1. <a ping> requests don't have a route_id. | 915 // 1. <a ping> requests don't have a route_id. |
| 924 // 2. Most unittests don't send the IPCs needed to register Clients. | 916 // 2. Most unittests don't send the IPCs needed to register Clients. |
| 925 // 3. The tab is closed while a RequestResource IPC is in flight. | 917 // 3. The tab is closed while a RequestResource IPC is in flight. |
| 926 unowned_requests_.insert(request.get()); | 918 unowned_requests_.insert(request.get()); |
| 927 request->Start(); | 919 request->Start(); |
| 928 return request.Pass(); | 920 return request.Pass(); |
| 929 } | 921 } |
| 930 | 922 |
| 931 Client* client = it->second; | 923 Client* client = it->second; |
| 932 client->ScheduleRequest(url_request, request.get()); | 924 client->ScheduleRequest(url_request, request.get()); |
| 933 return request.Pass(); | 925 return request.Pass(); |
| 934 } | 926 } |
| 935 | 927 |
| 936 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { | 928 void ResourceScheduler::RemoveRequest(ScheduledResourceRequestImpl* request) { |
| 937 DCHECK(CalledOnValidThread()); | 929 DCHECK(CalledOnValidThread()); |
| 938 if (ContainsKey(unowned_requests_, request)) { | 930 if (ContainsKey(unowned_requests_, request)) { |
| 939 unowned_requests_.erase(request); | 931 unowned_requests_.erase(request); |
| 940 return; | 932 return; |
| 941 } | 933 } |
| 942 | 934 |
| 943 ClientMap::iterator client_it = client_map_.find(request->client_id()); | 935 ClientMap::iterator client_it = client_map_.find(request->client_id()); |
| 944 if (client_it == client_map_.end()) { | 936 if (client_it == client_map_.end()) { |
| 945 return; | 937 return; |
| 946 } | 938 } |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1164 } | 1156 } |
| 1165 | 1157 |
| 1166 ResourceScheduler::ClientState ResourceScheduler::GetClientState( | 1158 ResourceScheduler::ClientState ResourceScheduler::GetClientState( |
| 1167 ClientId client_id) const { | 1159 ClientId client_id) const { |
| 1168 ClientMap::const_iterator client_it = client_map_.find(client_id); | 1160 ClientMap::const_iterator client_it = client_map_.find(client_id); |
| 1169 if (client_it == client_map_.end()) | 1161 if (client_it == client_map_.end()) |
| 1170 return UNKNOWN; | 1162 return UNKNOWN; |
| 1171 return client_it->second->is_active() ? ACTIVE : BACKGROUND; | 1163 return client_it->second->is_active() ? ACTIVE : BACKGROUND; |
| 1172 } | 1164 } |
| 1173 | 1165 |
| 1174 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, | 1166 void ResourceScheduler::ReprioritizeRequest( |
| 1175 net::RequestPriority new_priority, | 1167 ScheduledResourceRequestImpl* request, |
| 1176 int new_intra_priority_value) { | 1168 net::RequestPriority new_priority, |
| 1169 int new_intra_priority_value) { |
| 1177 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { | 1170 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { |
| 1178 // We should not be re-prioritizing requests with the | 1171 // We should not be re-prioritizing requests with the |
| 1179 // IGNORE_LIMITS flag. | 1172 // IGNORE_LIMITS flag. |
| 1180 NOTREACHED(); | 1173 NOTREACHED(); |
| 1181 return; | 1174 return; |
| 1182 } | 1175 } |
| 1183 RequestPriorityParams new_priority_params(new_priority, | 1176 RequestPriorityParams new_priority_params(new_priority, |
| 1184 new_intra_priority_value); | 1177 new_intra_priority_value); |
| 1185 RequestPriorityParams old_priority_params = | 1178 RequestPriorityParams old_priority_params = |
| 1186 request->get_request_priority_params(); | 1179 request->get_request_priority_params(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1202 client->ReprioritizeRequest( | 1195 client->ReprioritizeRequest( |
| 1203 request, old_priority_params, new_priority_params); | 1196 request, old_priority_params, new_priority_params); |
| 1204 } | 1197 } |
| 1205 | 1198 |
| 1206 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 1199 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
| 1207 int child_id, int route_id) { | 1200 int child_id, int route_id) { |
| 1208 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 1201 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
| 1209 } | 1202 } |
| 1210 | 1203 |
| 1211 } // namespace content | 1204 } // namespace content |
| OLD | NEW |