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 <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/supports_user_data.h" | |
| 14 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 15 #include "content/common/resource_messages.h" | 16 #include "content/common/resource_messages.h" |
| 16 #include "content/browser/loader/resource_message_delegate.h" | |
| 17 #include "content/public/browser/resource_controller.h" | 17 #include "content/public/browser/resource_controller.h" |
| 18 #include "content/public/browser/resource_request_info.h" | 18 #include "content/public/browser/resource_request_info.h" |
| 19 #include "content/public/browser/resource_throttle.h" | 19 #include "content/public/browser/resource_throttle.h" |
| 20 #include "ipc/ipc_message_macros.h" | |
| 21 #include "net/base/host_port_pair.h" | 20 #include "net/base/host_port_pair.h" |
| 22 #include "net/base/load_flags.h" | 21 #include "net/base/load_flags.h" |
| 23 #include "net/base/request_priority.h" | 22 #include "net/base/request_priority.h" |
| 24 #include "net/http/http_server_properties.h" | 23 #include "net/http/http_server_properties.h" |
| 25 #include "net/url_request/url_request.h" | 24 #include "net/url_request/url_request.h" |
| 26 #include "net/url_request/url_request_context.h" | 25 #include "net/url_request/url_request_context.h" |
| 27 | 26 |
| 28 namespace content { | 27 namespace content { |
| 29 | 28 |
| 30 namespace { | 29 namespace { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 103 return priority > other.priority; | 102 return priority > other.priority; |
| 104 return intra_priority > other.intra_priority; | 103 return intra_priority > other.intra_priority; |
| 105 } | 104 } |
| 106 | 105 |
| 107 net::RequestPriority priority; | 106 net::RequestPriority priority; |
| 108 int intra_priority; | 107 int intra_priority; |
| 109 }; | 108 }; |
| 110 | 109 |
| 111 class ResourceScheduler::RequestQueue { | 110 class ResourceScheduler::RequestQueue { |
| 112 public: | 111 public: |
| 113 typedef std::multiset<ScheduledResourceRequest*, ScheduledResourceSorter> | 112 typedef std::multiset<ScheduledResourceRequestImpl*, ScheduledResourceSorter> |
| 114 NetQueue; | 113 NetQueue; |
| 115 | 114 |
| 116 RequestQueue() : fifo_ordering_ids_(0) {} | 115 RequestQueue() : fifo_ordering_ids_(0) {} |
| 117 ~RequestQueue() {} | 116 ~RequestQueue() {} |
| 118 | 117 |
| 119 // Adds |request| to the queue with given |priority|. | 118 // Adds |request| to the queue with given |priority|. |
| 120 void Insert(ScheduledResourceRequest* request); | 119 void Insert(ScheduledResourceRequestImpl* request); |
| 121 | 120 |
| 122 // Removes |request| from the queue. | 121 // Removes |request| from the queue. |
| 123 void Erase(ScheduledResourceRequest* request) { | 122 void Erase(ScheduledResourceRequestImpl* request) { |
| 124 PointerMap::iterator it = pointers_.find(request); | 123 PointerMap::iterator it = pointers_.find(request); |
| 125 DCHECK(it != pointers_.end()); | 124 DCHECK(it != pointers_.end()); |
| 126 if (it == pointers_.end()) | 125 if (it == pointers_.end()) |
| 127 return; | 126 return; |
| 128 queue_.erase(it->second); | 127 queue_.erase(it->second); |
| 129 pointers_.erase(it); | 128 pointers_.erase(it); |
| 130 } | 129 } |
| 131 | 130 |
| 132 NetQueue::iterator GetNextHighestIterator() { | 131 NetQueue::iterator GetNextHighestIterator() { |
| 133 return queue_.begin(); | 132 return queue_.begin(); |
| 134 } | 133 } |
| 135 | 134 |
| 136 NetQueue::iterator End() { | 135 NetQueue::iterator End() { |
| 137 return queue_.end(); | 136 return queue_.end(); |
| 138 } | 137 } |
| 139 | 138 |
| 140 // Returns true if |request| is queued. | 139 // Returns true if |request| is queued. |
| 141 bool IsQueued(ScheduledResourceRequest* request) const { | 140 bool IsQueued(ScheduledResourceRequestImpl* request) const { |
| 142 return ContainsKey(pointers_, request); | 141 return ContainsKey(pointers_, request); |
| 143 } | 142 } |
| 144 | 143 |
| 145 // Returns true if no requests are queued. | 144 // Returns true if no requests are queued. |
| 146 bool IsEmpty() const { return queue_.size() == 0; } | 145 bool IsEmpty() const { return queue_.size() == 0; } |
| 147 | 146 |
| 148 private: | 147 private: |
| 149 typedef std::map<ScheduledResourceRequest*, NetQueue::iterator> PointerMap; | 148 typedef std::map<ScheduledResourceRequestImpl*, NetQueue::iterator> |
| 149 PointerMap; | |
| 150 | 150 |
| 151 uint32 MakeFifoOrderingId() { | 151 uint32 MakeFifoOrderingId() { |
| 152 fifo_ordering_ids_ += 1; | 152 fifo_ordering_ids_ += 1; |
| 153 return fifo_ordering_ids_; | 153 return fifo_ordering_ids_; |
| 154 } | 154 } |
| 155 | 155 |
| 156 // Used to create an ordering ID for scheduled resources so that resources | 156 // Used to create an ordering ID for scheduled resources so that resources |
| 157 // with same priority/intra_priority stay in fifo order. | 157 // with same priority/intra_priority stay in fifo order. |
| 158 uint32 fifo_ordering_ids_; | 158 uint32 fifo_ordering_ids_; |
| 159 | 159 |
| 160 NetQueue queue_; | 160 NetQueue queue_; |
| 161 PointerMap pointers_; | 161 PointerMap pointers_; |
| 162 }; | 162 }; |
| 163 | 163 |
| 164 // This is the handle we return to the ResourceDispatcherHostImpl so it can | 164 // This is the handle we return to the ResourceDispatcherHostImpl so it can |
| 165 // interact with the request. | 165 // interact with the request. |
| 166 class ResourceScheduler::ScheduledResourceRequest | 166 class ResourceScheduler::ScheduledResourceRequestImpl |
| 167 : public ResourceMessageDelegate, | 167 : public ScheduledResourceRequest { |
| 168 public ResourceThrottle { | |
| 169 public: | 168 public: |
| 170 ScheduledResourceRequest(const ClientId& client_id, | 169 ScheduledResourceRequestImpl(const ClientId& client_id, |
| 171 net::URLRequest* request, | 170 net::URLRequest* request, |
| 172 ResourceScheduler* scheduler, | 171 ResourceScheduler* scheduler, |
| 173 const RequestPriorityParams& priority) | 172 const RequestPriorityParams& priority, |
| 174 : ResourceMessageDelegate(request), | 173 bool is_async) |
| 175 client_id_(client_id), | 174 : client_id_(client_id), |
| 176 client_state_on_creation_(scheduler->GetClientState(client_id_)), | 175 client_state_on_creation_(scheduler->GetClientState(client_id_)), |
| 177 request_(request), | 176 request_(request), |
| 178 ready_(false), | 177 ready_(false), |
| 179 deferred_(false), | 178 deferred_(false), |
| 179 is_async_(is_async), | |
| 180 classification_(NORMAL_REQUEST), | 180 classification_(NORMAL_REQUEST), |
| 181 scheduler_(scheduler), | 181 scheduler_(scheduler), |
| 182 priority_(priority), | 182 priority_(priority), |
| 183 fifo_ordering_(0) { | 183 fifo_ordering_(0) { |
| 184 request_->SetUserData(kUserDataKey, new UnownedPointer(this)); | |
| 184 } | 185 } |
| 185 | 186 |
| 186 ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); } | 187 ~ScheduledResourceRequestImpl() override { |
| 188 request_->RemoveUserData(kUserDataKey); | |
| 189 scheduler_->RemoveRequest(this); | |
| 190 } | |
| 191 | |
| 192 void ChangePriority(net::RequestPriority new_priority, | |
| 193 int intra_priority_value) override { | |
| 194 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); | |
| 195 } | |
| 196 | |
| 197 static ScheduledResourceRequest* ForRequest(net::URLRequest* request) { | |
| 198 return static_cast<UnownedPointer*>(request->GetUserData(kUserDataKey)) | |
| 199 ->pointer; | |
| 200 } | |
| 187 | 201 |
| 188 void Start() { | 202 void Start() { |
| 189 ready_ = true; | 203 ready_ = true; |
| 190 if (!request_->status().is_success()) | 204 if (!request_->status().is_success()) |
| 191 return; | 205 return; |
| 192 base::TimeTicks time = base::TimeTicks::Now(); | 206 base::TimeTicks time = base::TimeTicks::Now(); |
| 193 ClientState current_state = scheduler_->GetClientState(client_id_); | 207 ClientState current_state = scheduler_->GetClientState(client_id_); |
| 194 // Note: the client state isn't perfectly accurate since it won't capture | 208 // Note: the client state isn't perfectly accurate since it won't capture |
| 195 // tabs which have switched between active and background multiple times. | 209 // tabs which have switched between active and background multiple times. |
| 196 // Ex: A tab with the following transitions Active -> Background -> Active | 210 // Ex: A tab with the following transitions Active -> Background -> Active |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 219 | 233 |
| 220 void set_request_priority_params(const RequestPriorityParams& priority) { | 234 void set_request_priority_params(const RequestPriorityParams& priority) { |
| 221 priority_ = priority; | 235 priority_ = priority; |
| 222 } | 236 } |
| 223 const RequestPriorityParams& get_request_priority_params() const { | 237 const RequestPriorityParams& get_request_priority_params() const { |
| 224 return priority_; | 238 return priority_; |
| 225 } | 239 } |
| 226 const ClientId& client_id() const { return client_id_; } | 240 const ClientId& client_id() const { return client_id_; } |
| 227 net::URLRequest* url_request() { return request_; } | 241 net::URLRequest* url_request() { return request_; } |
| 228 const net::URLRequest* url_request() const { return request_; } | 242 const net::URLRequest* url_request() const { return request_; } |
| 243 bool is_async() const { return is_async_; } | |
| 229 uint32 fifo_ordering() const { return fifo_ordering_; } | 244 uint32 fifo_ordering() const { return fifo_ordering_; } |
| 230 void set_fifo_ordering(uint32 fifo_ordering) { | 245 void set_fifo_ordering(uint32 fifo_ordering) { |
| 231 fifo_ordering_ = fifo_ordering; | 246 fifo_ordering_ = fifo_ordering; |
| 232 } | 247 } |
| 233 RequestClassification classification() const { | 248 RequestClassification classification() const { |
| 234 return classification_; | 249 return classification_; |
| 235 } | 250 } |
| 236 void set_classification(RequestClassification classification) { | 251 void set_classification(RequestClassification classification) { |
| 237 classification_ = classification; | 252 classification_ = classification; |
| 238 } | 253 } |
| 239 | 254 |
| 240 private: | 255 private: |
| 241 // ResourceMessageDelegate interface: | 256 class UnownedPointer : public base::SupportsUserData::Data { |
| 242 bool OnMessageReceived(const IPC::Message& message) override { | 257 public: |
| 243 bool handled = true; | 258 UnownedPointer(ScheduledResourceRequestImpl* pointer) : pointer(pointer) {} |
|
mmenke
2015/08/14 15:23:14
explicit
Adam Rice
2015/08/14 17:17:22
Done.
| |
| 244 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message) | 259 |
| 245 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) | 260 ScheduledResourceRequestImpl* const pointer; |
|
mmenke
2015/08/14 15:23:15
This should be private, with an accessor, per Goog
Adam Rice
2015/08/14 17:17:23
Done.
| |
| 246 IPC_MESSAGE_UNHANDLED(handled = false) | 261 |
| 247 IPC_END_MESSAGE_MAP() | 262 private: |
| 248 return handled; | 263 DISALLOW_COPY_AND_ASSIGN(UnownedPointer); |
| 249 } | 264 }; |
| 265 | |
| 266 static const void* const kUserDataKey; | |
| 250 | 267 |
| 251 // ResourceThrottle interface: | 268 // ResourceThrottle interface: |
| 252 void WillStartRequest(bool* defer) override { | 269 void WillStartRequest(bool* defer) override { |
| 253 deferred_ = *defer = !ready_; | 270 deferred_ = *defer = !ready_; |
| 254 time_deferred_ = base::TimeTicks::Now(); | 271 time_deferred_ = base::TimeTicks::Now(); |
| 255 } | 272 } |
| 256 | 273 |
| 257 const char* GetNameForLogging() const override { return "ResourceScheduler"; } | 274 const char* GetNameForLogging() const override { return "ResourceScheduler"; } |
| 258 | 275 |
| 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_; | 276 const ClientId client_id_; |
| 265 const ResourceScheduler::ClientState client_state_on_creation_; | 277 const ResourceScheduler::ClientState client_state_on_creation_; |
| 266 net::URLRequest* request_; | 278 net::URLRequest* request_; |
| 267 bool ready_; | 279 bool ready_; |
| 268 bool deferred_; | 280 bool deferred_; |
| 281 bool is_async_; | |
| 269 RequestClassification classification_; | 282 RequestClassification classification_; |
| 270 ResourceScheduler* scheduler_; | 283 ResourceScheduler* scheduler_; |
| 271 RequestPriorityParams priority_; | 284 RequestPriorityParams priority_; |
| 272 uint32 fifo_ordering_; | 285 uint32 fifo_ordering_; |
| 273 base::TimeTicks time_deferred_; | 286 base::TimeTicks time_deferred_; |
| 274 | 287 |
| 275 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); | 288 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequestImpl); |
| 276 }; | 289 }; |
| 277 | 290 |
| 291 const void* const | |
| 292 ResourceScheduler::ScheduledResourceRequestImpl::kUserDataKey = | |
| 293 &ResourceScheduler::ScheduledResourceRequestImpl::kUserDataKey; | |
| 294 | |
| 295 ResourceScheduler::ScheduledResourceRequest::ScheduledResourceRequest() {} | |
| 296 ResourceScheduler::ScheduledResourceRequest::~ScheduledResourceRequest() {} | |
| 297 ResourceScheduler::ScheduledResourceRequest* | |
| 298 ResourceScheduler::ScheduledResourceRequest::ForRequest( | |
| 299 net::URLRequest* request) { | |
| 300 return ResourceScheduler::ScheduledResourceRequestImpl::ForRequest(request); | |
| 301 } | |
|
mmenke
2015/08/14 15:23:14
nit: believe there should be a blank line between
Adam Rice
2015/08/14 17:17:23
Removed.
| |
| 302 | |
| 278 bool ResourceScheduler::ScheduledResourceSorter::operator()( | 303 bool ResourceScheduler::ScheduledResourceSorter::operator()( |
| 279 const ScheduledResourceRequest* a, | 304 const ScheduledResourceRequestImpl* a, |
| 280 const ScheduledResourceRequest* b) const { | 305 const ScheduledResourceRequestImpl* b) const { |
| 281 // Want the set to be ordered first by decreasing priority, then by | 306 // Want the set to be ordered first by decreasing priority, then by |
| 282 // decreasing intra_priority. | 307 // decreasing intra_priority. |
| 283 // ie. with (priority, intra_priority) | 308 // ie. with (priority, intra_priority) |
| 284 // [(1, 0), (1, 0), (0, 100), (0, 0)] | 309 // [(1, 0), (1, 0), (0, 100), (0, 0)] |
| 285 if (a->get_request_priority_params() != b->get_request_priority_params()) | 310 if (a->get_request_priority_params() != b->get_request_priority_params()) |
| 286 return a->get_request_priority_params().GreaterThan( | 311 return a->get_request_priority_params().GreaterThan( |
| 287 b->get_request_priority_params()); | 312 b->get_request_priority_params()); |
| 288 | 313 |
| 289 // If priority/intra_priority is the same, fall back to fifo ordering. | 314 // If priority/intra_priority is the same, fall back to fifo ordering. |
| 290 // std::multiset doesn't guarantee this until c++11. | 315 // std::multiset doesn't guarantee this until c++11. |
| 291 return a->fifo_ordering() < b->fifo_ordering(); | 316 return a->fifo_ordering() < b->fifo_ordering(); |
| 292 } | 317 } |
| 293 | 318 |
| 294 void ResourceScheduler::RequestQueue::Insert( | 319 void ResourceScheduler::RequestQueue::Insert( |
| 295 ScheduledResourceRequest* request) { | 320 ScheduledResourceRequestImpl* request) { |
| 296 DCHECK(!ContainsKey(pointers_, request)); | 321 DCHECK(!ContainsKey(pointers_, request)); |
| 297 request->set_fifo_ordering(MakeFifoOrderingId()); | 322 request->set_fifo_ordering(MakeFifoOrderingId()); |
| 298 pointers_[request] = queue_.insert(request); | 323 pointers_[request] = queue_.insert(request); |
| 299 } | 324 } |
| 300 | 325 |
| 301 // Each client represents a tab. | 326 // Each client represents a tab. |
| 302 class ResourceScheduler::Client { | 327 class ResourceScheduler::Client { |
| 303 public: | 328 public: |
| 304 explicit Client(ResourceScheduler* scheduler, | 329 explicit Client(ResourceScheduler* scheduler, |
| 305 bool is_visible, | 330 bool is_visible, |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 318 | 343 |
| 319 ~Client() { | 344 ~Client() { |
| 320 // Update to default state and pause to ensure the scheduler has a | 345 // Update to default state and pause to ensure the scheduler has a |
| 321 // correct count of relevant types of clients. | 346 // correct count of relevant types of clients. |
| 322 is_visible_ = false; | 347 is_visible_ = false; |
| 323 is_audible_ = false; | 348 is_audible_ = false; |
| 324 is_paused_ = true; | 349 is_paused_ = true; |
| 325 UpdateThrottleState(); | 350 UpdateThrottleState(); |
| 326 } | 351 } |
| 327 | 352 |
| 328 void ScheduleRequest( | 353 void ScheduleRequest(net::URLRequest* url_request, |
| 329 net::URLRequest* url_request, | 354 ScheduledResourceRequestImpl* request) { |
| 330 ScheduledResourceRequest* request) { | |
| 331 if (ShouldStartRequest(request) == START_REQUEST) | 355 if (ShouldStartRequest(request) == START_REQUEST) |
| 332 StartRequest(request); | 356 StartRequest(request); |
| 333 else | 357 else |
| 334 pending_requests_.Insert(request); | 358 pending_requests_.Insert(request); |
| 335 SetRequestClassification(request, ClassifyRequest(request)); | 359 SetRequestClassification(request, ClassifyRequest(request)); |
| 336 } | 360 } |
| 337 | 361 |
| 338 void RemoveRequest(ScheduledResourceRequest* request) { | 362 void RemoveRequest(ScheduledResourceRequestImpl* request) { |
| 339 if (pending_requests_.IsQueued(request)) { | 363 if (pending_requests_.IsQueued(request)) { |
| 340 pending_requests_.Erase(request); | 364 pending_requests_.Erase(request); |
| 341 DCHECK(!ContainsKey(in_flight_requests_, request)); | 365 DCHECK(!ContainsKey(in_flight_requests_, request)); |
| 342 } else { | 366 } else { |
| 343 EraseInFlightRequest(request); | 367 EraseInFlightRequest(request); |
| 344 | 368 |
| 345 // Removing this request may have freed up another to load. | 369 // Removing this request may have freed up another to load. |
| 346 LoadAnyStartablePendingRequests(); | 370 LoadAnyStartablePendingRequests(); |
| 347 } | 371 } |
| 348 } | 372 } |
| 349 | 373 |
| 350 RequestSet StartAndRemoveAllRequests() { | 374 RequestSet StartAndRemoveAllRequests() { |
| 351 // First start any pending requests so that they will be moved into | 375 // First start any pending requests so that they will be moved into |
| 352 // in_flight_requests_. This may exceed the limits | 376 // in_flight_requests_. This may exceed the limits |
| 353 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and | 377 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and |
| 354 // kMaxNumThrottledRequestsPerClient, so this method must not do anything | 378 // kMaxNumThrottledRequestsPerClient, so this method must not do anything |
| 355 // that depends on those limits before calling ClearInFlightRequests() | 379 // that depends on those limits before calling ClearInFlightRequests() |
| 356 // below. | 380 // below. |
| 357 while (!pending_requests_.IsEmpty()) { | 381 while (!pending_requests_.IsEmpty()) { |
| 358 ScheduledResourceRequest* request = | 382 ScheduledResourceRequestImpl* request = |
| 359 *pending_requests_.GetNextHighestIterator(); | 383 *pending_requests_.GetNextHighestIterator(); |
| 360 pending_requests_.Erase(request); | 384 pending_requests_.Erase(request); |
| 361 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? | 385 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? |
| 362 StartRequest(request); | 386 StartRequest(request); |
| 363 } | 387 } |
| 364 RequestSet unowned_requests; | 388 RequestSet unowned_requests; |
| 365 for (RequestSet::iterator it = in_flight_requests_.begin(); | 389 for (RequestSet::iterator it = in_flight_requests_.begin(); |
| 366 it != in_flight_requests_.end(); ++it) { | 390 it != in_flight_requests_.end(); ++it) { |
| 367 unowned_requests.insert(*it); | 391 unowned_requests.insert(*it); |
| 368 (*it)->set_classification(NORMAL_REQUEST); | 392 (*it)->set_classification(NORMAL_REQUEST); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 LoadAnyStartablePendingRequests(); | 503 LoadAnyStartablePendingRequests(); |
| 480 } | 504 } |
| 481 | 505 |
| 482 void OnReceivedSpdyProxiedHttpResponse() { | 506 void OnReceivedSpdyProxiedHttpResponse() { |
| 483 if (!using_spdy_proxy_) { | 507 if (!using_spdy_proxy_) { |
| 484 using_spdy_proxy_ = true; | 508 using_spdy_proxy_ = true; |
| 485 LoadAnyStartablePendingRequests(); | 509 LoadAnyStartablePendingRequests(); |
| 486 } | 510 } |
| 487 } | 511 } |
| 488 | 512 |
| 489 void ReprioritizeRequest(ScheduledResourceRequest* request, | 513 void ReprioritizeRequest(ScheduledResourceRequestImpl* request, |
| 490 RequestPriorityParams old_priority_params, | 514 RequestPriorityParams old_priority_params, |
| 491 RequestPriorityParams new_priority_params) { | 515 RequestPriorityParams new_priority_params) { |
| 492 request->url_request()->SetPriority(new_priority_params.priority); | 516 request->url_request()->SetPriority(new_priority_params.priority); |
| 493 request->set_request_priority_params(new_priority_params); | 517 request->set_request_priority_params(new_priority_params); |
| 494 if (!pending_requests_.IsQueued(request)) { | 518 if (!pending_requests_.IsQueued(request)) { |
| 495 DCHECK(ContainsKey(in_flight_requests_, request)); | 519 DCHECK(ContainsKey(in_flight_requests_, request)); |
| 496 // The priority of the request and priority support of the server may | 520 // The priority of the request and priority support of the server may |
| 497 // have changed, so update the delayable count. | 521 // have changed, so update the delayable count. |
| 498 SetRequestClassification(request, ClassifyRequest(request)); | 522 SetRequestClassification(request, ClassifyRequest(request)); |
| 499 // Request has already started. | 523 // Request has already started. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 553 SetThrottleState(COALESCED); | 577 SetThrottleState(COALESCED); |
| 554 } | 578 } |
| 555 | 579 |
| 556 private: | 580 private: |
| 557 enum ShouldStartReqResult { | 581 enum ShouldStartReqResult { |
| 558 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, | 582 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, |
| 559 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, | 583 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, |
| 560 START_REQUEST, | 584 START_REQUEST, |
| 561 }; | 585 }; |
| 562 | 586 |
| 563 void InsertInFlightRequest(ScheduledResourceRequest* request) { | 587 void InsertInFlightRequest(ScheduledResourceRequestImpl* request) { |
| 564 in_flight_requests_.insert(request); | 588 in_flight_requests_.insert(request); |
| 565 SetRequestClassification(request, ClassifyRequest(request)); | 589 SetRequestClassification(request, ClassifyRequest(request)); |
| 566 } | 590 } |
| 567 | 591 |
| 568 void EraseInFlightRequest(ScheduledResourceRequest* request) { | 592 void EraseInFlightRequest(ScheduledResourceRequestImpl* request) { |
| 569 size_t erased = in_flight_requests_.erase(request); | 593 size_t erased = in_flight_requests_.erase(request); |
| 570 DCHECK_EQ(1u, erased); | 594 DCHECK_EQ(1u, erased); |
| 571 // Clear any special state that we were tracking for this request. | 595 // Clear any special state that we were tracking for this request. |
| 572 SetRequestClassification(request, NORMAL_REQUEST); | 596 SetRequestClassification(request, NORMAL_REQUEST); |
| 573 } | 597 } |
| 574 | 598 |
| 575 void ClearInFlightRequests() { | 599 void ClearInFlightRequests() { |
| 576 in_flight_requests_.clear(); | 600 in_flight_requests_.clear(); |
| 577 in_flight_delayable_count_ = 0; | 601 in_flight_delayable_count_ = 0; |
| 578 total_layout_blocking_count_ = 0; | 602 total_layout_blocking_count_ = 0; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 590 for (RequestQueue::NetQueue::const_iterator | 614 for (RequestQueue::NetQueue::const_iterator |
| 591 it = pending_requests_.GetNextHighestIterator(); | 615 it = pending_requests_.GetNextHighestIterator(); |
| 592 it != pending_requests_.End(); ++it) { | 616 it != pending_requests_.End(); ++it) { |
| 593 if ((*it)->classification() == classification) | 617 if ((*it)->classification() == classification) |
| 594 classification_request_count++; | 618 classification_request_count++; |
| 595 } | 619 } |
| 596 } | 620 } |
| 597 return classification_request_count; | 621 return classification_request_count; |
| 598 } | 622 } |
| 599 | 623 |
| 600 void SetRequestClassification(ScheduledResourceRequest* request, | 624 void SetRequestClassification(ScheduledResourceRequestImpl* request, |
| 601 RequestClassification classification) { | 625 RequestClassification classification) { |
| 602 RequestClassification old_classification = request->classification(); | 626 RequestClassification old_classification = request->classification(); |
| 603 if (old_classification == classification) | 627 if (old_classification == classification) |
| 604 return; | 628 return; |
| 605 | 629 |
| 606 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) | 630 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) |
| 607 in_flight_delayable_count_--; | 631 in_flight_delayable_count_--; |
| 608 if (old_classification == LAYOUT_BLOCKING_REQUEST) | 632 if (old_classification == LAYOUT_BLOCKING_REQUEST) |
| 609 total_layout_blocking_count_--; | 633 total_layout_blocking_count_--; |
| 610 | 634 |
| 611 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) | 635 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) |
| 612 in_flight_delayable_count_++; | 636 in_flight_delayable_count_++; |
| 613 if (classification == LAYOUT_BLOCKING_REQUEST) | 637 if (classification == LAYOUT_BLOCKING_REQUEST) |
| 614 total_layout_blocking_count_++; | 638 total_layout_blocking_count_++; |
| 615 | 639 |
| 616 request->set_classification(classification); | 640 request->set_classification(classification); |
| 617 DCHECK_EQ( | 641 DCHECK_EQ( |
| 618 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), | 642 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), |
| 619 in_flight_delayable_count_); | 643 in_flight_delayable_count_); |
| 620 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), | 644 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), |
| 621 total_layout_blocking_count_); | 645 total_layout_blocking_count_); |
| 622 } | 646 } |
| 623 | 647 |
| 624 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) { | 648 RequestClassification ClassifyRequest(ScheduledResourceRequestImpl* request) { |
| 625 // If a request is already marked as layout-blocking make sure to keep the | 649 // If a request is already marked as layout-blocking make sure to keep the |
| 626 // classification across redirects unless the priority was lowered. | 650 // classification across redirects unless the priority was lowered. |
| 627 if (request->classification() == LAYOUT_BLOCKING_REQUEST && | 651 if (request->classification() == LAYOUT_BLOCKING_REQUEST && |
| 628 request->url_request()->priority() > net::LOW) { | 652 request->url_request()->priority() > net::LOW) { |
| 629 return LAYOUT_BLOCKING_REQUEST; | 653 return LAYOUT_BLOCKING_REQUEST; |
| 630 } | 654 } |
| 631 | 655 |
| 632 if (!has_body_ && request->url_request()->priority() > net::LOW) | 656 if (!has_body_ && request->url_request()->priority() > net::LOW) |
| 633 return LAYOUT_BLOCKING_REQUEST; | 657 return LAYOUT_BLOCKING_REQUEST; |
| 634 | 658 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 654 net::HostPortPair::FromURL((*it)->url_request()->url()); | 678 net::HostPortPair::FromURL((*it)->url_request()->url()); |
| 655 if (active_request_host.Equals(host_port_pair)) { | 679 if (active_request_host.Equals(host_port_pair)) { |
| 656 same_host_count++; | 680 same_host_count++; |
| 657 if (same_host_count >= kMaxNumDelayableRequestsPerHost) | 681 if (same_host_count >= kMaxNumDelayableRequestsPerHost) |
| 658 return true; | 682 return true; |
| 659 } | 683 } |
| 660 } | 684 } |
| 661 return false; | 685 return false; |
| 662 } | 686 } |
| 663 | 687 |
| 664 void StartRequest(ScheduledResourceRequest* request) { | 688 void StartRequest(ScheduledResourceRequestImpl* request) { |
| 665 InsertInFlightRequest(request); | 689 InsertInFlightRequest(request); |
| 666 request->Start(); | 690 request->Start(); |
| 667 } | 691 } |
| 668 | 692 |
| 669 // ShouldStartRequest is the main scheduling algorithm. | 693 // ShouldStartRequest is the main scheduling algorithm. |
| 670 // | 694 // |
| 671 // Requests are evaluated on five attributes: | 695 // Requests are evaluated on five attributes: |
| 672 // | 696 // |
| 673 // 1. Non-delayable requests: | 697 // 1. Non-delayable requests: |
| 674 // * Synchronous requests. | 698 // * 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 | 736 // * If no high priority requests are in flight, start loading low priority |
| 713 // requests. | 737 // requests. |
| 714 // | 738 // |
| 715 // COALESCED Clients never load requests, with the following exceptions: | 739 // COALESCED Clients never load requests, with the following exceptions: |
| 716 // * Non-delayable requests are issued imediately. | 740 // * Non-delayable requests are issued imediately. |
| 717 // * On a (currently 5 second) heart beat, they load all requests as an | 741 // * On a (currently 5 second) heart beat, they load all requests as an |
| 718 // UNTHROTTLED Client, and then return to the COALESCED state. | 742 // UNTHROTTLED Client, and then return to the COALESCED state. |
| 719 // * When an active Client makes a request, they are THROTTLED until the | 743 // * When an active Client makes a request, they are THROTTLED until the |
| 720 // active Client finishes loading. | 744 // active Client finishes loading. |
| 721 ShouldStartReqResult ShouldStartRequest( | 745 ShouldStartReqResult ShouldStartRequest( |
| 722 ScheduledResourceRequest* request) const { | 746 ScheduledResourceRequestImpl* request) const { |
| 723 const net::URLRequest& url_request = *request->url_request(); | 747 const net::URLRequest& url_request = *request->url_request(); |
| 724 // Syncronous requests could block the entire render, which could impact | 748 // Syncronous requests could block the entire render, which could impact |
| 725 // user-observable Clients. | 749 // user-observable Clients. |
| 726 if (!ResourceRequestInfo::ForRequest(&url_request)->IsAsync()) { | 750 if (!request->is_async()) { |
| 727 return START_REQUEST; | 751 return START_REQUEST; |
| 728 } | 752 } |
| 729 | 753 |
| 730 // TODO(simonjam): This may end up causing disk contention. We should | 754 // TODO(simonjam): This may end up causing disk contention. We should |
| 731 // experiment with throttling if that happens. | 755 // experiment with throttling if that happens. |
| 732 // TODO(aiolos): We probably want to Coalesce these as well to avoid | 756 // TODO(aiolos): We probably want to Coalesce these as well to avoid |
| 733 // waking the disk. | 757 // waking the disk. |
| 734 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { | 758 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { |
| 735 return START_REQUEST; | 759 return START_REQUEST; |
| 736 } | 760 } |
| (...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. | 827 // 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 | 828 // 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 | 829 // there may be room for other requests, so we keep checking and leave |
| 806 // the previous request still in the list. | 830 // the previous request still in the list. |
| 807 // 3) We do not start the request, same as above, but StartRequest() tells | 831 // 3) We do not start the request, same as above, but StartRequest() tells |
| 808 // us there's no point in checking any further requests. | 832 // us there's no point in checking any further requests. |
| 809 RequestQueue::NetQueue::iterator request_iter = | 833 RequestQueue::NetQueue::iterator request_iter = |
| 810 pending_requests_.GetNextHighestIterator(); | 834 pending_requests_.GetNextHighestIterator(); |
| 811 | 835 |
| 812 while (request_iter != pending_requests_.End()) { | 836 while (request_iter != pending_requests_.End()) { |
| 813 ScheduledResourceRequest* request = *request_iter; | 837 ScheduledResourceRequestImpl* request = *request_iter; |
| 814 ShouldStartReqResult query_result = ShouldStartRequest(request); | 838 ShouldStartReqResult query_result = ShouldStartRequest(request); |
| 815 | 839 |
| 816 if (query_result == START_REQUEST) { | 840 if (query_result == START_REQUEST) { |
| 817 pending_requests_.Erase(request); | 841 pending_requests_.Erase(request); |
| 818 StartRequest(request); | 842 StartRequest(request); |
| 819 | 843 |
| 820 // StartRequest can modify the pending list, so we (re)start evaluation | 844 // StartRequest can modify the pending list, so we (re)start evaluation |
| 821 // from the currently highest priority request. Avoid copying a singular | 845 // from the currently highest priority request. Avoid copying a singular |
| 822 // iterator, which would trigger undefined behavior. | 846 // iterator, which would trigger undefined behavior. |
| 823 if (pending_requests_.GetNextHighestIterator() == | 847 if (pending_requests_.GetNextHighestIterator() == |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 898 OnLoadingActiveClientsStateChangedForAllClients(); | 922 OnLoadingActiveClientsStateChangedForAllClients(); |
| 899 } | 923 } |
| 900 | 924 |
| 901 ResourceScheduler::ClientThrottleState | 925 ResourceScheduler::ClientThrottleState |
| 902 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { | 926 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { |
| 903 Client* client = GetClient(child_id, route_id); | 927 Client* client = GetClient(child_id, route_id); |
| 904 DCHECK(client); | 928 DCHECK(client); |
| 905 return client->throttle_state(); | 929 return client->throttle_state(); |
| 906 } | 930 } |
| 907 | 931 |
| 908 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( | 932 scoped_ptr<ResourceScheduler::ScheduledResourceRequest> |
| 909 int child_id, | 933 ResourceScheduler::ScheduleRequest(int child_id, |
| 910 int route_id, | 934 int route_id, |
| 911 net::URLRequest* url_request) { | 935 bool is_async, |
| 936 net::URLRequest* url_request) { | |
| 912 DCHECK(CalledOnValidThread()); | 937 DCHECK(CalledOnValidThread()); |
| 913 ClientId client_id = MakeClientId(child_id, route_id); | 938 ClientId client_id = MakeClientId(child_id, route_id); |
| 914 scoped_ptr<ScheduledResourceRequest> request(new ScheduledResourceRequest( | 939 scoped_ptr<ScheduledResourceRequestImpl> request( |
| 915 client_id, | 940 new ScheduledResourceRequestImpl( |
| 916 url_request, | 941 client_id, url_request, this, |
| 917 this, | 942 RequestPriorityParams(url_request->priority(), 0), is_async)); |
| 918 RequestPriorityParams(url_request->priority(), 0))); | |
| 919 | 943 |
| 920 ClientMap::iterator it = client_map_.find(client_id); | 944 ClientMap::iterator it = client_map_.find(client_id); |
| 921 if (it == client_map_.end()) { | 945 if (it == client_map_.end()) { |
| 922 // There are several ways this could happen: | 946 // There are several ways this could happen: |
| 923 // 1. <a ping> requests don't have a route_id. | 947 // 1. <a ping> requests don't have a route_id. |
| 924 // 2. Most unittests don't send the IPCs needed to register Clients. | 948 // 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. | 949 // 3. The tab is closed while a RequestResource IPC is in flight. |
| 926 unowned_requests_.insert(request.get()); | 950 unowned_requests_.insert(request.get()); |
| 927 request->Start(); | 951 request->Start(); |
| 928 return request.Pass(); | 952 return request.Pass(); |
| 929 } | 953 } |
| 930 | 954 |
| 931 Client* client = it->second; | 955 Client* client = it->second; |
| 932 client->ScheduleRequest(url_request, request.get()); | 956 client->ScheduleRequest(url_request, request.get()); |
| 933 return request.Pass(); | 957 return request.Pass(); |
| 934 } | 958 } |
| 935 | 959 |
| 936 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { | 960 void ResourceScheduler::RemoveRequest(ScheduledResourceRequestImpl* request) { |
| 937 DCHECK(CalledOnValidThread()); | 961 DCHECK(CalledOnValidThread()); |
| 938 if (ContainsKey(unowned_requests_, request)) { | 962 if (ContainsKey(unowned_requests_, request)) { |
| 939 unowned_requests_.erase(request); | 963 unowned_requests_.erase(request); |
| 940 return; | 964 return; |
| 941 } | 965 } |
| 942 | 966 |
| 943 ClientMap::iterator client_it = client_map_.find(request->client_id()); | 967 ClientMap::iterator client_it = client_map_.find(request->client_id()); |
| 944 if (client_it == client_map_.end()) { | 968 if (client_it == client_map_.end()) { |
| 945 return; | 969 return; |
| 946 } | 970 } |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1164 } | 1188 } |
| 1165 | 1189 |
| 1166 ResourceScheduler::ClientState ResourceScheduler::GetClientState( | 1190 ResourceScheduler::ClientState ResourceScheduler::GetClientState( |
| 1167 ClientId client_id) const { | 1191 ClientId client_id) const { |
| 1168 ClientMap::const_iterator client_it = client_map_.find(client_id); | 1192 ClientMap::const_iterator client_it = client_map_.find(client_id); |
| 1169 if (client_it == client_map_.end()) | 1193 if (client_it == client_map_.end()) |
| 1170 return UNKNOWN; | 1194 return UNKNOWN; |
| 1171 return client_it->second->is_active() ? ACTIVE : BACKGROUND; | 1195 return client_it->second->is_active() ? ACTIVE : BACKGROUND; |
| 1172 } | 1196 } |
| 1173 | 1197 |
| 1174 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, | 1198 void ResourceScheduler::ReprioritizeRequest( |
| 1175 net::RequestPriority new_priority, | 1199 ScheduledResourceRequestImpl* request, |
| 1176 int new_intra_priority_value) { | 1200 net::RequestPriority new_priority, |
| 1201 int new_intra_priority_value) { | |
|
mmenke
2015/08/14 15:23:14
Why not have the RDH call this method with the URL
Adam Rice
2015/08/14 17:17:22
Oh. Thank you. Done.
| |
| 1177 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { | 1202 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { |
| 1178 // We should not be re-prioritizing requests with the | 1203 // We should not be re-prioritizing requests with the |
| 1179 // IGNORE_LIMITS flag. | 1204 // IGNORE_LIMITS flag. |
| 1180 NOTREACHED(); | 1205 NOTREACHED(); |
| 1181 return; | 1206 return; |
| 1182 } | 1207 } |
| 1183 RequestPriorityParams new_priority_params(new_priority, | 1208 RequestPriorityParams new_priority_params(new_priority, |
| 1184 new_intra_priority_value); | 1209 new_intra_priority_value); |
| 1185 RequestPriorityParams old_priority_params = | 1210 RequestPriorityParams old_priority_params = |
| 1186 request->get_request_priority_params(); | 1211 request->get_request_priority_params(); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1202 client->ReprioritizeRequest( | 1227 client->ReprioritizeRequest( |
| 1203 request, old_priority_params, new_priority_params); | 1228 request, old_priority_params, new_priority_params); |
| 1204 } | 1229 } |
| 1205 | 1230 |
| 1206 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 1231 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
| 1207 int child_id, int route_id) { | 1232 int child_id, int route_id) { |
| 1208 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 1233 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
| 1209 } | 1234 } |
| 1210 | 1235 |
| 1211 } // namespace content | 1236 } // namespace content |
| OLD | NEW |