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) {} |
|
davidben
2015/08/13 23:08:52
Nit: Maybe a newline here? Not sure. Was a bit har
Adam Rice
2015/08/13 23:42:28
Done.
| |
| 244 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message) | 259 ScheduledResourceRequestImpl* const pointer; |
| 245 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) | 260 |
| 246 IPC_MESSAGE_UNHANDLED(handled = false) | 261 private: |
| 247 IPC_END_MESSAGE_MAP() | 262 DISALLOW_COPY_AND_ASSIGN(UnownedPointer); |
| 248 return handled; | 263 }; |
| 249 } | 264 |
| 265 static const void* const kUserDataKey; | |
| 250 | 266 |
| 251 // ResourceThrottle interface: | 267 // ResourceThrottle interface: |
| 252 void WillStartRequest(bool* defer) override { | 268 void WillStartRequest(bool* defer) override { |
| 253 deferred_ = *defer = !ready_; | 269 deferred_ = *defer = !ready_; |
| 254 time_deferred_ = base::TimeTicks::Now(); | 270 time_deferred_ = base::TimeTicks::Now(); |
| 255 } | 271 } |
| 256 | 272 |
| 257 const char* GetNameForLogging() const override { return "ResourceScheduler"; } | 273 const char* GetNameForLogging() const override { return "ResourceScheduler"; } |
| 258 | 274 |
| 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_; | 275 const ClientId client_id_; |
| 265 const ResourceScheduler::ClientState client_state_on_creation_; | 276 const ResourceScheduler::ClientState client_state_on_creation_; |
| 266 net::URLRequest* request_; | 277 net::URLRequest* request_; |
| 267 bool ready_; | 278 bool ready_; |
| 268 bool deferred_; | 279 bool deferred_; |
| 280 bool is_async_; | |
| 269 RequestClassification classification_; | 281 RequestClassification classification_; |
| 270 ResourceScheduler* scheduler_; | 282 ResourceScheduler* scheduler_; |
| 271 RequestPriorityParams priority_; | 283 RequestPriorityParams priority_; |
| 272 uint32 fifo_ordering_; | 284 uint32 fifo_ordering_; |
| 273 base::TimeTicks time_deferred_; | 285 base::TimeTicks time_deferred_; |
| 274 | 286 |
| 275 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); | 287 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequestImpl); |
| 276 }; | 288 }; |
| 277 | 289 |
| 290 const void* const | |
| 291 ResourceScheduler::ScheduledResourceRequestImpl::kUserDataKey = | |
| 292 &ResourceScheduler::ScheduledResourceRequestImpl::kUserDataKey; | |
|
davidben
2015/08/13 23:08:53
[Ah the sweet music of C++. You can tell it's musi
Adam Rice
2015/08/13 23:42:28
I have to admit I borrowed this trick from someone
| |
| 293 | |
| 294 ResourceScheduler::ScheduledResourceRequest::ScheduledResourceRequest() {} | |
| 295 ResourceScheduler::ScheduledResourceRequest::~ScheduledResourceRequest() {} | |
| 296 ResourceScheduler::ScheduledResourceRequest* | |
| 297 ResourceScheduler::ScheduledResourceRequest::ForRequest( | |
| 298 net::URLRequest* request) { | |
| 299 return ResourceScheduler::ScheduledResourceRequestImpl::ForRequest(request); | |
| 300 } | |
| 301 | |
| 278 bool ResourceScheduler::ScheduledResourceSorter::operator()( | 302 bool ResourceScheduler::ScheduledResourceSorter::operator()( |
| 279 const ScheduledResourceRequest* a, | 303 const ScheduledResourceRequestImpl* a, |
| 280 const ScheduledResourceRequest* b) const { | 304 const ScheduledResourceRequestImpl* b) const { |
| 281 // Want the set to be ordered first by decreasing priority, then by | 305 // Want the set to be ordered first by decreasing priority, then by |
| 282 // decreasing intra_priority. | 306 // decreasing intra_priority. |
| 283 // ie. with (priority, intra_priority) | 307 // ie. with (priority, intra_priority) |
| 284 // [(1, 0), (1, 0), (0, 100), (0, 0)] | 308 // [(1, 0), (1, 0), (0, 100), (0, 0)] |
| 285 if (a->get_request_priority_params() != b->get_request_priority_params()) | 309 if (a->get_request_priority_params() != b->get_request_priority_params()) |
| 286 return a->get_request_priority_params().GreaterThan( | 310 return a->get_request_priority_params().GreaterThan( |
| 287 b->get_request_priority_params()); | 311 b->get_request_priority_params()); |
| 288 | 312 |
| 289 // If priority/intra_priority is the same, fall back to fifo ordering. | 313 // If priority/intra_priority is the same, fall back to fifo ordering. |
| 290 // std::multiset doesn't guarantee this until c++11. | 314 // std::multiset doesn't guarantee this until c++11. |
| 291 return a->fifo_ordering() < b->fifo_ordering(); | 315 return a->fifo_ordering() < b->fifo_ordering(); |
| 292 } | 316 } |
| 293 | 317 |
| 294 void ResourceScheduler::RequestQueue::Insert( | 318 void ResourceScheduler::RequestQueue::Insert( |
| 295 ScheduledResourceRequest* request) { | 319 ScheduledResourceRequestImpl* request) { |
| 296 DCHECK(!ContainsKey(pointers_, request)); | 320 DCHECK(!ContainsKey(pointers_, request)); |
| 297 request->set_fifo_ordering(MakeFifoOrderingId()); | 321 request->set_fifo_ordering(MakeFifoOrderingId()); |
| 298 pointers_[request] = queue_.insert(request); | 322 pointers_[request] = queue_.insert(request); |
| 299 } | 323 } |
| 300 | 324 |
| 301 // Each client represents a tab. | 325 // Each client represents a tab. |
| 302 class ResourceScheduler::Client { | 326 class ResourceScheduler::Client { |
| 303 public: | 327 public: |
| 304 explicit Client(ResourceScheduler* scheduler, | 328 explicit Client(ResourceScheduler* scheduler, |
| 305 bool is_visible, | 329 bool is_visible, |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 318 | 342 |
| 319 ~Client() { | 343 ~Client() { |
| 320 // Update to default state and pause to ensure the scheduler has a | 344 // Update to default state and pause to ensure the scheduler has a |
| 321 // correct count of relevant types of clients. | 345 // correct count of relevant types of clients. |
| 322 is_visible_ = false; | 346 is_visible_ = false; |
| 323 is_audible_ = false; | 347 is_audible_ = false; |
| 324 is_paused_ = true; | 348 is_paused_ = true; |
| 325 UpdateThrottleState(); | 349 UpdateThrottleState(); |
| 326 } | 350 } |
| 327 | 351 |
| 328 void ScheduleRequest( | 352 void ScheduleRequest(net::URLRequest* url_request, |
| 329 net::URLRequest* url_request, | 353 ScheduledResourceRequestImpl* request) { |
| 330 ScheduledResourceRequest* request) { | |
| 331 if (ShouldStartRequest(request) == START_REQUEST) | 354 if (ShouldStartRequest(request) == START_REQUEST) |
| 332 StartRequest(request); | 355 StartRequest(request); |
| 333 else | 356 else |
| 334 pending_requests_.Insert(request); | 357 pending_requests_.Insert(request); |
| 335 SetRequestClassification(request, ClassifyRequest(request)); | 358 SetRequestClassification(request, ClassifyRequest(request)); |
| 336 } | 359 } |
| 337 | 360 |
| 338 void RemoveRequest(ScheduledResourceRequest* request) { | 361 void RemoveRequest(ScheduledResourceRequestImpl* request) { |
| 339 if (pending_requests_.IsQueued(request)) { | 362 if (pending_requests_.IsQueued(request)) { |
| 340 pending_requests_.Erase(request); | 363 pending_requests_.Erase(request); |
| 341 DCHECK(!ContainsKey(in_flight_requests_, request)); | 364 DCHECK(!ContainsKey(in_flight_requests_, request)); |
| 342 } else { | 365 } else { |
| 343 EraseInFlightRequest(request); | 366 EraseInFlightRequest(request); |
| 344 | 367 |
| 345 // Removing this request may have freed up another to load. | 368 // Removing this request may have freed up another to load. |
| 346 LoadAnyStartablePendingRequests(); | 369 LoadAnyStartablePendingRequests(); |
| 347 } | 370 } |
| 348 } | 371 } |
| 349 | 372 |
| 350 RequestSet StartAndRemoveAllRequests() { | 373 RequestSet StartAndRemoveAllRequests() { |
| 351 // First start any pending requests so that they will be moved into | 374 // First start any pending requests so that they will be moved into |
| 352 // in_flight_requests_. This may exceed the limits | 375 // in_flight_requests_. This may exceed the limits |
| 353 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and | 376 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and |
| 354 // kMaxNumThrottledRequestsPerClient, so this method must not do anything | 377 // kMaxNumThrottledRequestsPerClient, so this method must not do anything |
| 355 // that depends on those limits before calling ClearInFlightRequests() | 378 // that depends on those limits before calling ClearInFlightRequests() |
| 356 // below. | 379 // below. |
| 357 while (!pending_requests_.IsEmpty()) { | 380 while (!pending_requests_.IsEmpty()) { |
| 358 ScheduledResourceRequest* request = | 381 ScheduledResourceRequestImpl* request = |
| 359 *pending_requests_.GetNextHighestIterator(); | 382 *pending_requests_.GetNextHighestIterator(); |
| 360 pending_requests_.Erase(request); | 383 pending_requests_.Erase(request); |
| 361 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? | 384 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? |
| 362 StartRequest(request); | 385 StartRequest(request); |
| 363 } | 386 } |
| 364 RequestSet unowned_requests; | 387 RequestSet unowned_requests; |
| 365 for (RequestSet::iterator it = in_flight_requests_.begin(); | 388 for (RequestSet::iterator it = in_flight_requests_.begin(); |
| 366 it != in_flight_requests_.end(); ++it) { | 389 it != in_flight_requests_.end(); ++it) { |
| 367 unowned_requests.insert(*it); | 390 unowned_requests.insert(*it); |
| 368 (*it)->set_classification(NORMAL_REQUEST); | 391 (*it)->set_classification(NORMAL_REQUEST); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 LoadAnyStartablePendingRequests(); | 502 LoadAnyStartablePendingRequests(); |
| 480 } | 503 } |
| 481 | 504 |
| 482 void OnReceivedSpdyProxiedHttpResponse() { | 505 void OnReceivedSpdyProxiedHttpResponse() { |
| 483 if (!using_spdy_proxy_) { | 506 if (!using_spdy_proxy_) { |
| 484 using_spdy_proxy_ = true; | 507 using_spdy_proxy_ = true; |
| 485 LoadAnyStartablePendingRequests(); | 508 LoadAnyStartablePendingRequests(); |
| 486 } | 509 } |
| 487 } | 510 } |
| 488 | 511 |
| 489 void ReprioritizeRequest(ScheduledResourceRequest* request, | 512 void ReprioritizeRequest(ScheduledResourceRequestImpl* request, |
| 490 RequestPriorityParams old_priority_params, | 513 RequestPriorityParams old_priority_params, |
| 491 RequestPriorityParams new_priority_params) { | 514 RequestPriorityParams new_priority_params) { |
| 492 request->url_request()->SetPriority(new_priority_params.priority); | 515 request->url_request()->SetPriority(new_priority_params.priority); |
| 493 request->set_request_priority_params(new_priority_params); | 516 request->set_request_priority_params(new_priority_params); |
| 494 if (!pending_requests_.IsQueued(request)) { | 517 if (!pending_requests_.IsQueued(request)) { |
| 495 DCHECK(ContainsKey(in_flight_requests_, request)); | 518 DCHECK(ContainsKey(in_flight_requests_, request)); |
| 496 // The priority of the request and priority support of the server may | 519 // The priority of the request and priority support of the server may |
| 497 // have changed, so update the delayable count. | 520 // have changed, so update the delayable count. |
| 498 SetRequestClassification(request, ClassifyRequest(request)); | 521 SetRequestClassification(request, ClassifyRequest(request)); |
| 499 // Request has already started. | 522 // Request has already started. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 553 SetThrottleState(COALESCED); | 576 SetThrottleState(COALESCED); |
| 554 } | 577 } |
| 555 | 578 |
| 556 private: | 579 private: |
| 557 enum ShouldStartReqResult { | 580 enum ShouldStartReqResult { |
| 558 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, | 581 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, |
| 559 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, | 582 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, |
| 560 START_REQUEST, | 583 START_REQUEST, |
| 561 }; | 584 }; |
| 562 | 585 |
| 563 void InsertInFlightRequest(ScheduledResourceRequest* request) { | 586 void InsertInFlightRequest(ScheduledResourceRequestImpl* request) { |
| 564 in_flight_requests_.insert(request); | 587 in_flight_requests_.insert(request); |
| 565 SetRequestClassification(request, ClassifyRequest(request)); | 588 SetRequestClassification(request, ClassifyRequest(request)); |
| 566 } | 589 } |
| 567 | 590 |
| 568 void EraseInFlightRequest(ScheduledResourceRequest* request) { | 591 void EraseInFlightRequest(ScheduledResourceRequestImpl* request) { |
| 569 size_t erased = in_flight_requests_.erase(request); | 592 size_t erased = in_flight_requests_.erase(request); |
| 570 DCHECK_EQ(1u, erased); | 593 DCHECK_EQ(1u, erased); |
| 571 // Clear any special state that we were tracking for this request. | 594 // Clear any special state that we were tracking for this request. |
| 572 SetRequestClassification(request, NORMAL_REQUEST); | 595 SetRequestClassification(request, NORMAL_REQUEST); |
| 573 } | 596 } |
| 574 | 597 |
| 575 void ClearInFlightRequests() { | 598 void ClearInFlightRequests() { |
| 576 in_flight_requests_.clear(); | 599 in_flight_requests_.clear(); |
| 577 in_flight_delayable_count_ = 0; | 600 in_flight_delayable_count_ = 0; |
| 578 total_layout_blocking_count_ = 0; | 601 total_layout_blocking_count_ = 0; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 590 for (RequestQueue::NetQueue::const_iterator | 613 for (RequestQueue::NetQueue::const_iterator |
| 591 it = pending_requests_.GetNextHighestIterator(); | 614 it = pending_requests_.GetNextHighestIterator(); |
| 592 it != pending_requests_.End(); ++it) { | 615 it != pending_requests_.End(); ++it) { |
| 593 if ((*it)->classification() == classification) | 616 if ((*it)->classification() == classification) |
| 594 classification_request_count++; | 617 classification_request_count++; |
| 595 } | 618 } |
| 596 } | 619 } |
| 597 return classification_request_count; | 620 return classification_request_count; |
| 598 } | 621 } |
| 599 | 622 |
| 600 void SetRequestClassification(ScheduledResourceRequest* request, | 623 void SetRequestClassification(ScheduledResourceRequestImpl* request, |
| 601 RequestClassification classification) { | 624 RequestClassification classification) { |
| 602 RequestClassification old_classification = request->classification(); | 625 RequestClassification old_classification = request->classification(); |
| 603 if (old_classification == classification) | 626 if (old_classification == classification) |
| 604 return; | 627 return; |
| 605 | 628 |
| 606 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) | 629 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) |
| 607 in_flight_delayable_count_--; | 630 in_flight_delayable_count_--; |
| 608 if (old_classification == LAYOUT_BLOCKING_REQUEST) | 631 if (old_classification == LAYOUT_BLOCKING_REQUEST) |
| 609 total_layout_blocking_count_--; | 632 total_layout_blocking_count_--; |
| 610 | 633 |
| 611 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) | 634 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) |
| 612 in_flight_delayable_count_++; | 635 in_flight_delayable_count_++; |
| 613 if (classification == LAYOUT_BLOCKING_REQUEST) | 636 if (classification == LAYOUT_BLOCKING_REQUEST) |
| 614 total_layout_blocking_count_++; | 637 total_layout_blocking_count_++; |
| 615 | 638 |
| 616 request->set_classification(classification); | 639 request->set_classification(classification); |
| 617 DCHECK_EQ( | 640 DCHECK_EQ( |
| 618 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), | 641 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), |
| 619 in_flight_delayable_count_); | 642 in_flight_delayable_count_); |
| 620 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), | 643 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), |
| 621 total_layout_blocking_count_); | 644 total_layout_blocking_count_); |
| 622 } | 645 } |
| 623 | 646 |
| 624 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) { | 647 RequestClassification ClassifyRequest(ScheduledResourceRequestImpl* request) { |
| 625 // If a request is already marked as layout-blocking make sure to keep the | 648 // If a request is already marked as layout-blocking make sure to keep the |
| 626 // classification across redirects unless the priority was lowered. | 649 // classification across redirects unless the priority was lowered. |
| 627 if (request->classification() == LAYOUT_BLOCKING_REQUEST && | 650 if (request->classification() == LAYOUT_BLOCKING_REQUEST && |
| 628 request->url_request()->priority() > net::LOW) { | 651 request->url_request()->priority() > net::LOW) { |
| 629 return LAYOUT_BLOCKING_REQUEST; | 652 return LAYOUT_BLOCKING_REQUEST; |
| 630 } | 653 } |
| 631 | 654 |
| 632 if (!has_body_ && request->url_request()->priority() > net::LOW) | 655 if (!has_body_ && request->url_request()->priority() > net::LOW) |
| 633 return LAYOUT_BLOCKING_REQUEST; | 656 return LAYOUT_BLOCKING_REQUEST; |
| 634 | 657 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 654 net::HostPortPair::FromURL((*it)->url_request()->url()); | 677 net::HostPortPair::FromURL((*it)->url_request()->url()); |
| 655 if (active_request_host.Equals(host_port_pair)) { | 678 if (active_request_host.Equals(host_port_pair)) { |
| 656 same_host_count++; | 679 same_host_count++; |
| 657 if (same_host_count >= kMaxNumDelayableRequestsPerHost) | 680 if (same_host_count >= kMaxNumDelayableRequestsPerHost) |
| 658 return true; | 681 return true; |
| 659 } | 682 } |
| 660 } | 683 } |
| 661 return false; | 684 return false; |
| 662 } | 685 } |
| 663 | 686 |
| 664 void StartRequest(ScheduledResourceRequest* request) { | 687 void StartRequest(ScheduledResourceRequestImpl* request) { |
| 665 InsertInFlightRequest(request); | 688 InsertInFlightRequest(request); |
| 666 request->Start(); | 689 request->Start(); |
| 667 } | 690 } |
| 668 | 691 |
| 669 // ShouldStartRequest is the main scheduling algorithm. | 692 // ShouldStartRequest is the main scheduling algorithm. |
| 670 // | 693 // |
| 671 // Requests are evaluated on five attributes: | 694 // Requests are evaluated on five attributes: |
| 672 // | 695 // |
| 673 // 1. Non-delayable requests: | 696 // 1. Non-delayable requests: |
| 674 // * Synchronous requests. | 697 // * 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 | 735 // * If no high priority requests are in flight, start loading low priority |
| 713 // requests. | 736 // requests. |
| 714 // | 737 // |
| 715 // COALESCED Clients never load requests, with the following exceptions: | 738 // COALESCED Clients never load requests, with the following exceptions: |
| 716 // * Non-delayable requests are issued imediately. | 739 // * Non-delayable requests are issued imediately. |
| 717 // * On a (currently 5 second) heart beat, they load all requests as an | 740 // * On a (currently 5 second) heart beat, they load all requests as an |
| 718 // UNTHROTTLED Client, and then return to the COALESCED state. | 741 // UNTHROTTLED Client, and then return to the COALESCED state. |
| 719 // * When an active Client makes a request, they are THROTTLED until the | 742 // * When an active Client makes a request, they are THROTTLED until the |
| 720 // active Client finishes loading. | 743 // active Client finishes loading. |
| 721 ShouldStartReqResult ShouldStartRequest( | 744 ShouldStartReqResult ShouldStartRequest( |
| 722 ScheduledResourceRequest* request) const { | 745 ScheduledResourceRequestImpl* request) const { |
| 723 const net::URLRequest& url_request = *request->url_request(); | 746 const net::URLRequest& url_request = *request->url_request(); |
| 724 // Syncronous requests could block the entire render, which could impact | 747 // Syncronous requests could block the entire render, which could impact |
| 725 // user-observable Clients. | 748 // user-observable Clients. |
| 726 if (!ResourceRequestInfo::ForRequest(&url_request)->IsAsync()) { | 749 if (!request->is_async()) { |
| 727 return START_REQUEST; | 750 return START_REQUEST; |
| 728 } | 751 } |
| 729 | 752 |
| 730 // TODO(simonjam): This may end up causing disk contention. We should | 753 // TODO(simonjam): This may end up causing disk contention. We should |
| 731 // experiment with throttling if that happens. | 754 // experiment with throttling if that happens. |
| 732 // TODO(aiolos): We probably want to Coalesce these as well to avoid | 755 // TODO(aiolos): We probably want to Coalesce these as well to avoid |
| 733 // waking the disk. | 756 // waking the disk. |
| 734 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { | 757 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { |
| 735 return START_REQUEST; | 758 return START_REQUEST; |
| 736 } | 759 } |
| (...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. | 826 // 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 | 827 // 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 | 828 // there may be room for other requests, so we keep checking and leave |
| 806 // the previous request still in the list. | 829 // the previous request still in the list. |
| 807 // 3) We do not start the request, same as above, but StartRequest() tells | 830 // 3) We do not start the request, same as above, but StartRequest() tells |
| 808 // us there's no point in checking any further requests. | 831 // us there's no point in checking any further requests. |
| 809 RequestQueue::NetQueue::iterator request_iter = | 832 RequestQueue::NetQueue::iterator request_iter = |
| 810 pending_requests_.GetNextHighestIterator(); | 833 pending_requests_.GetNextHighestIterator(); |
| 811 | 834 |
| 812 while (request_iter != pending_requests_.End()) { | 835 while (request_iter != pending_requests_.End()) { |
| 813 ScheduledResourceRequest* request = *request_iter; | 836 ScheduledResourceRequestImpl* request = *request_iter; |
| 814 ShouldStartReqResult query_result = ShouldStartRequest(request); | 837 ShouldStartReqResult query_result = ShouldStartRequest(request); |
| 815 | 838 |
| 816 if (query_result == START_REQUEST) { | 839 if (query_result == START_REQUEST) { |
| 817 pending_requests_.Erase(request); | 840 pending_requests_.Erase(request); |
| 818 StartRequest(request); | 841 StartRequest(request); |
| 819 | 842 |
| 820 // StartRequest can modify the pending list, so we (re)start evaluation | 843 // StartRequest can modify the pending list, so we (re)start evaluation |
| 821 // from the currently highest priority request. Avoid copying a singular | 844 // from the currently highest priority request. Avoid copying a singular |
| 822 // iterator, which would trigger undefined behavior. | 845 // iterator, which would trigger undefined behavior. |
| 823 if (pending_requests_.GetNextHighestIterator() == | 846 if (pending_requests_.GetNextHighestIterator() == |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 898 OnLoadingActiveClientsStateChangedForAllClients(); | 921 OnLoadingActiveClientsStateChangedForAllClients(); |
| 899 } | 922 } |
| 900 | 923 |
| 901 ResourceScheduler::ClientThrottleState | 924 ResourceScheduler::ClientThrottleState |
| 902 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { | 925 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { |
| 903 Client* client = GetClient(child_id, route_id); | 926 Client* client = GetClient(child_id, route_id); |
| 904 DCHECK(client); | 927 DCHECK(client); |
| 905 return client->throttle_state(); | 928 return client->throttle_state(); |
| 906 } | 929 } |
| 907 | 930 |
| 908 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( | 931 scoped_ptr<ResourceScheduler::ScheduledResourceRequest> |
| 909 int child_id, | 932 ResourceScheduler::ScheduleRequest(int child_id, |
| 910 int route_id, | 933 int route_id, |
| 911 net::URLRequest* url_request) { | 934 bool is_async, |
| 935 net::URLRequest* url_request) { | |
| 912 DCHECK(CalledOnValidThread()); | 936 DCHECK(CalledOnValidThread()); |
| 913 ClientId client_id = MakeClientId(child_id, route_id); | 937 ClientId client_id = MakeClientId(child_id, route_id); |
| 914 scoped_ptr<ScheduledResourceRequest> request(new ScheduledResourceRequest( | 938 scoped_ptr<ScheduledResourceRequestImpl> request( |
| 915 client_id, | 939 new ScheduledResourceRequestImpl( |
| 916 url_request, | 940 client_id, url_request, this, |
| 917 this, | 941 RequestPriorityParams(url_request->priority(), 0), is_async)); |
| 918 RequestPriorityParams(url_request->priority(), 0))); | |
| 919 | 942 |
| 920 ClientMap::iterator it = client_map_.find(client_id); | 943 ClientMap::iterator it = client_map_.find(client_id); |
| 921 if (it == client_map_.end()) { | 944 if (it == client_map_.end()) { |
| 922 // There are several ways this could happen: | 945 // There are several ways this could happen: |
| 923 // 1. <a ping> requests don't have a route_id. | 946 // 1. <a ping> requests don't have a route_id. |
| 924 // 2. Most unittests don't send the IPCs needed to register Clients. | 947 // 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. | 948 // 3. The tab is closed while a RequestResource IPC is in flight. |
| 926 unowned_requests_.insert(request.get()); | 949 unowned_requests_.insert(request.get()); |
| 927 request->Start(); | 950 request->Start(); |
| 928 return request.Pass(); | 951 return request.Pass(); |
| 929 } | 952 } |
| 930 | 953 |
| 931 Client* client = it->second; | 954 Client* client = it->second; |
| 932 client->ScheduleRequest(url_request, request.get()); | 955 client->ScheduleRequest(url_request, request.get()); |
| 933 return request.Pass(); | 956 return request.Pass(); |
| 934 } | 957 } |
| 935 | 958 |
| 936 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { | 959 void ResourceScheduler::RemoveRequest(ScheduledResourceRequestImpl* request) { |
| 937 DCHECK(CalledOnValidThread()); | 960 DCHECK(CalledOnValidThread()); |
| 938 if (ContainsKey(unowned_requests_, request)) { | 961 if (ContainsKey(unowned_requests_, request)) { |
| 939 unowned_requests_.erase(request); | 962 unowned_requests_.erase(request); |
| 940 return; | 963 return; |
| 941 } | 964 } |
| 942 | 965 |
| 943 ClientMap::iterator client_it = client_map_.find(request->client_id()); | 966 ClientMap::iterator client_it = client_map_.find(request->client_id()); |
| 944 if (client_it == client_map_.end()) { | 967 if (client_it == client_map_.end()) { |
| 945 return; | 968 return; |
| 946 } | 969 } |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1164 } | 1187 } |
| 1165 | 1188 |
| 1166 ResourceScheduler::ClientState ResourceScheduler::GetClientState( | 1189 ResourceScheduler::ClientState ResourceScheduler::GetClientState( |
| 1167 ClientId client_id) const { | 1190 ClientId client_id) const { |
| 1168 ClientMap::const_iterator client_it = client_map_.find(client_id); | 1191 ClientMap::const_iterator client_it = client_map_.find(client_id); |
| 1169 if (client_it == client_map_.end()) | 1192 if (client_it == client_map_.end()) |
| 1170 return UNKNOWN; | 1193 return UNKNOWN; |
| 1171 return client_it->second->is_active() ? ACTIVE : BACKGROUND; | 1194 return client_it->second->is_active() ? ACTIVE : BACKGROUND; |
| 1172 } | 1195 } |
| 1173 | 1196 |
| 1174 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, | 1197 void ResourceScheduler::ReprioritizeRequest( |
| 1175 net::RequestPriority new_priority, | 1198 ScheduledResourceRequestImpl* request, |
| 1176 int new_intra_priority_value) { | 1199 net::RequestPriority new_priority, |
| 1200 int new_intra_priority_value) { | |
| 1177 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { | 1201 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { |
| 1178 // We should not be re-prioritizing requests with the | 1202 // We should not be re-prioritizing requests with the |
| 1179 // IGNORE_LIMITS flag. | 1203 // IGNORE_LIMITS flag. |
| 1180 NOTREACHED(); | 1204 NOTREACHED(); |
| 1181 return; | 1205 return; |
| 1182 } | 1206 } |
| 1183 RequestPriorityParams new_priority_params(new_priority, | 1207 RequestPriorityParams new_priority_params(new_priority, |
| 1184 new_intra_priority_value); | 1208 new_intra_priority_value); |
| 1185 RequestPriorityParams old_priority_params = | 1209 RequestPriorityParams old_priority_params = |
| 1186 request->get_request_priority_params(); | 1210 request->get_request_priority_params(); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1202 client->ReprioritizeRequest( | 1226 client->ReprioritizeRequest( |
| 1203 request, old_priority_params, new_priority_params); | 1227 request, old_priority_params, new_priority_params); |
| 1204 } | 1228 } |
| 1205 | 1229 |
| 1206 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 1230 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
| 1207 int child_id, int route_id) { | 1231 int child_id, int route_id) { |
| 1208 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 1232 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
| 1209 } | 1233 } |
| 1210 | 1234 |
| 1211 } // namespace content | 1235 } // namespace content |
| OLD | NEW |